This diagram details the end-to-end search flow from user input through to rendered results, including how the search execution layer orchestrates multiple suppliers in parallel via streaming.
---
config:
layout: elk
htmlLabels: true
markdownAutoWrap: true
look: neo
theme: dark
elk:
mergeEdges: true
nodePlacementStrategy: BRANDES_KOEPF
flowchart:
curve: basis
---
flowchart TB
linkStyle default stroke-width:4px;
subgraph Entry["Entry Points"]
direction LR
SP["SearchPage\n(Web App)"]
SPH["SearchPanelHome\n(Chrome Extension)"]
end
SP -->|"onSearch(query)"| SF["SearchForm"]
SPH -->|"onSearch(query)"| SF
subgraph InputLayer["UI Input Layer"]
SF
SI["SearchInput\n(alternative input)"]
USI["useSearchInput Hook\nmanages input state and\nchrome.storage.session persistence"]
SI --- USI
end
SF -->|"query string"| ES
SI -->|"query string"| ES
subgraph Execution["Search Execution Layer"]
ES["executeSearch(query)\nuseSearch hook"]
ES -->|"startTransition"| PS["performSearch()"]
PS -->|"1. Instantiate"| SFACT["SupplierFactory\nnew SupplierFactory(query, limit, controller, suppliers?)"]
SFACT -->|"2. Stream results"| STREAM["executeAllStream(concurrency=3)\nAsyncGenerator - yields products\nas they arrive from any supplier"]
STREAM -->|"for await (product)"| PROCESS["Process Each Result\nupdate resultCount\nappend to searchResults\nsave to IndexedDB"]
end
IDB[("IndexedDB\nsearchResults store\ncurrent result set")]
CHROME[("chrome.storage.session\nquery, isNewSearch flag")]
SPH -.->|"save query + isNewSearch flag"| CHROME
CHROME -.->|"load on mount\nif isNewSearch then performSearch"| ES
PROCESS -.->|"save incrementally"| IDB
IDB -.->|"load on mount\nrestore results"| ES
subgraph Factory["SupplierFactory"]
direction TB
SFACT2["Instantiate selected suppliers\nfrom supplier index module"]
QUEUE["async-await-queue\nparallel execution with\nconcurrency limit"]
CHAN["Channel array\ncollect yielded products\nfrom all suppliers"]
SFACT2 --> QUEUE --> CHAN
end
STREAM -.-> Factory
CHAN -->|"per supplier"| EXEC
subgraph SupplierPipeline["SupplierBase.execute - AsyncGenerator Pipeline"]
direction TB
EXEC["execute()\nload excluded-product list;\nover-fetch by excluded count"]
SETUP["setup()\nsupplier-specific init\nauth tokens, headers, etc."]
QPC["queryProductsWithCache()\ncheck IndexedDB cache\nfallback to queryProductsResolved()"]
QPR["queryProductsResolved()\nplain / native-advanced: 1 query\nkeyword-only advanced: 1 search per\nOR-group term, unioned + deduped"]
QP["queryProducts()\nfetch search results\nsupplier-specific"]
FUZZ["fuzzyFilterAst()\nAST-aware (AND/OR/NOT, phrases)\nscore titleSelector() with active\nfuzz scorer (default ratio); rank-only"]
IPB["initProductBuilders()\nparse raw data into\nProductBuilder instances"]
EXCL["drop excluded products\n(Ignore Product list),\nslice back to limit"]
EXEC --> SETUP --> QPC
QPC -->|"cache miss"| QPR
QPR --> QP
QP --> FUZZ --> IPB --> EXCL
subgraph DetailFetch["Product Detail Fetching - concurrent via async-await-queue"]
direction TB
GPDC["getProductDataWithCache()\nper product"]
GPD["getProductData()\nfetch individual product page\nsupplier-specific"]
FP["finishProduct()\nvalidate, set country/shipping,\ncall product.build()"]
GPDC -->|"cache miss"| GPD --> FP
end
EXCL -->|"for each product builder"| DetailFetch
FP -->|"yield product"| YIELD(("yield"))
end
subgraph Strategies["Supplier Data Strategies"]
direction TB
subgraph JSONOnly["JSON Only - e.g. Wix Suppliers"]
direction TB
WS["setup: fetch Wix access token\nGET /_api/v1/access-tokens"]
WQ["queryProducts: GraphQL API call\nPOST /ecom query\ngetFilteredProductsWithHasDiscount"]
WI["initProductBuilders:\nparse JSON product nodes\nitems, variants, prices\nselections, quantities/sizes\nextract CAS numbers"]
WG["getProductData: no-op\nall data already available\nfrom search response"]
WS --> WQ --> WI --> WG
end
subgraph HTMLOnly["HTML Only - e.g. Loudwolf"]
direction TB
LQ["queryProducts: fetch search page\nGET /storefront/?search=..."]
LF["fuzzHtmlResponse:\nDOMParser then querySelectorAll\ndiv.product-layout.product-list\nfuzzy filter by title"]
LI["initProductBuilders:\nscrape .caption p.price\nand .caption h4 a for URL/ID"]
LG["getProductData: fetch product page\nparse MsoTableGrid for\nCAS, quantity, grade\nchunk-based key/value extraction"]
LQ --> LF --> LI --> LG
end
subgraph Hybrid["Hybrid JSON + HTML - e.g. AsesChem"]
direction TB
OQ["queryProducts: Shopify GraphQL\nPOST /api/{version}/graphql.json"]
OF["fuzzyFilterAst:\nfilter JSON nodes by title"]
OI["initProductBuilders:\nmap GraphQL nodes to builders\ntitle, handle, variants, price"]
OG["getProductData: fetch product page HTML\nDOMParser scrape for the\nSDS and CoA document links"]
OQ --> OF --> OI --> OG
end
end
QP -.->|"JSON path"| JSONOnly
QP -.->|"HTML path"| HTMLOnly
QP -.->|"Hybrid path"| Hybrid
YIELD -->|"streamed back through\nexecuteAllStream"| PROCESS
PROCESS --> RT["ResultsTable\nSearchPanel renders table\nwith column filters"]
PROCESS -->|"if no results"| PUBCHEM["PubChem API\nsuggest alternative\nsearch terms"]
classDef entry fill:#4A90D9,stroke:#2C5F8A,color:#fff,font-weight:bold
classDef input fill:#5BA3CF,stroke:#3A7CA5,color:#fff
classDef exec fill:#4A90D9,stroke:#2C5F8A,color:#fff
classDef factory fill:#6B8E9B,stroke:#4A6B78,color:#fff
classDef pipeline fill:#5A7D8B,stroke:#3E5A66,color:#fff
classDef json fill:#2EAD6B,stroke:#1F7A4A,color:#fff
classDef html fill:#D97B2A,stroke:#A35D1F,color:#fff
classDef hybrid fill:#9B59B6,stroke:#6F3D8A,color:#fff
classDef storage fill:#E8A838,stroke:#B8841F,color:#fff
classDef output fill:#3498DB,stroke:#2176AC,color:#fff
classDef fallback fill:#95A5A6,stroke:#6E7B7C,color:#fff
classDef yieldNode fill:#27AE60,stroke:#1E8449,color:#fff
class SP,SPH entry
class SF,SI,USI input
class ES,PS,SFACT,STREAM,PROCESS exec
class SFACT2,QUEUE,CHAN factory
class EXEC,SETUP,QPC,QPR,QP,FUZZ,IPB,EXCL,GPDC,GPD,FP pipeline
class WS,WQ,WI,WG json
class LQ,LF,LI,LG html
class OQ,OF,OI,OG hybrid
class IDB,CHROME storage
class RT output
class PUBCHEM fallback
class YIELD yieldNode