@nuskin/react-search-sdk 1.0.1-code-cleanup.2 → 1.1.0-pa-1255.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config/configurationSdk.ts","../src/constants.ts","../src/config/commerceSearchConfig.ts","../src/hooks/useCommerceSearchConfig.ts","../src/copy/searchPanelCopy.ts","../src/copy/fetchSearchPanelCopy.ts","../src/copy/loadSearchPanelCopy.ts","../src/hooks/useSearchPanelCopy.ts","../src/services/localeParts.ts","../src/services/catalogRequest.ts","../src/services/recentSearches.ts","../src/services/searchPaths.ts","../src/services/suggestionsPayload.ts","../src/services/SearchApiService.ts","../src/services/marketConfig.ts","../src/utils/gtmConstants.ts","../src/utils/navigationTarget.ts","../src/utils/productEnvironment.ts","../src/components/CommerceSearch/CommerceSearchUnavailable.tsx","../src/utils/nuiSearchGate.ts","../src/hooks/useNuiAgentGate.ts","../src/hooks/useRecentSearches.ts","../src/utils/catalogStatus.ts","../src/utils/catalogHelpers.ts","../src/hooks/useSearchSuggestions.ts","../src/utils/commonUtils.ts","../src/utils/gtmTracking.ts","../src/utils/searchRouting.ts","../src/hooks/useSubmitRouting.ts","../src/utils/cachedProductClient.ts","../src/components/CommerceSearch/NuiAgentPanel.styled.tsx","../src/components/CommerceSearch/NuiAgentPanel.tsx","../src/components/CommerceSearch/CommerceSearchView.tsx","../src/components/CommerceSearch/CommerceSearch.tsx"],"names":["useState","useEffect","resolveTotalResultsCount","useCallback","useRef","jsx","SearchPanel","useMemo"],"mappings":"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","file":"index.mjs","sourcesContent":["import configurationSdk from '@nuskin/configuration-sdk';\n\n/**\n * `@nuskin/configuration-sdk` is CommonJS. Node's ESM loader cannot see all of its named exports\n * (`getEnvironmentCode` is missed), so import the default and read the functions off it.\n */\nexport const { getConfiguration, getEnvironmentCode } = configurationSdk;\n","/** Constants for the search SDK. */\n\n/** API shopping-context segment used when resolving the Equinox gateway URL. */\nexport const STOREFRONT_SHOPPING_CONTEXT = 'storefront';\n\n/** Catalog suggestions path appended when the market gateway is not already\n * under the storefront shopping context. */\nexport const CATALOG_SUGGESTIONS_PATH =\n '/storefront/catalogs/search/suggestions';\n\n/** Prefix for the `sessionStorage` key that persists recent searches.\n * Full key format: `${RECENT_SEARCHES_PREFIX}:{locale}:{COUNTRY}:{lang}`.\n * Must not change — existing sessions rely on this key. */\nexport const RECENT_SEARCHES_PREFIX = 'nuskin:header:recentSearches';\n\n/** Maximum number of recent searches persisted per locale bucket. */\nexport const RECENT_SEARCHES_DEFAULT_LIMIT = 10;\n\n/** Equinox suggestion pagination — page is 1-indexed. */\nexport const DEFAULT_SUGGESTION_PAGE = 1;\n\n/** Number of suggestion rows requested from the Equinox catalog per call. */\nexport const DEFAULT_SUGGESTION_SIZE = 6;\n\n/** Segment used when building the fallback search-results URL. */\nexport const DEFAULT_SEARCH_PATH = '/search';\n\n/** Debounce for typeahead input → API dispatch. */\nexport const DEBOUNCE_MS = 220;\n\n/** Terms shorter than this are not sent to the suggestions API. */\nexport const MINIMUM_SEARCH_CHAR_LENGTH = 2;\n\n/** Cap on suggestions rendered in the dropdown, regardless of API response size. */\nexport const MAX_VISIBLE_SUGGESTIONS = 6;\n\n/** The configuration map holding each market's API gateway and store. */\nexport const EQUINOX_MARKETS_MAP = 'Equinox_Markets';\n\n/**\n * TODO: PA-1255 moves this client id into the configuration store with the other values read per\n * environment.\n */\nexport const DEFAULT_EQUINOX_CLIENT_ID = '63056848d7532f9923f3d08cb48c423b';\n","import { getEnvironmentCode } from './configurationSdk';\nimport { MINIMUM_SEARCH_CHAR_LENGTH } from '../constants';\n\n/**\n * Everything about the product search that is meant to be configuration, in one place, behind\n * one async reader. `fetchCommerceSearchConfig` is the only function that knows where the values\n * come from, so moving them to a configuration store changes that function and nothing else.\n */\n\n/** The NUi app the search can hand off to. */\nexport interface CommerceSearchAgentConfig {\n appKey: string;\n apiBaseUrl: string;\n /** UI language, taken from the market the config was read for. */\n language?: string;\n}\n\n/**\n * The contract the configuration store entry has to satisfy:\n * - `minimumSearchLength`: characters a term needs before the typeahead looks it up\n * - `agent`: the NUi app to hand off to; absent means plain search only\n * - `allowGuestAgent`: lets visitors who are not signed in reach the agent too; absent means the\n * agent is for signed-in visitors only\n */\nexport interface CommerceSearchConfig {\n minimumSearchLength: number;\n agent?: CommerceSearchAgentConfig;\n allowGuestAgent?: boolean;\n}\n\nexport interface FetchCommerceSearchConfigOptions {\n country?: string;\n language?: string;\n}\n\nexport const COMMERCE_SEARCH_CONFIG_DEFAULTS: Readonly<CommerceSearchConfig> =\n Object.freeze({\n minimumSearchLength: MINIMUM_SEARCH_CHAR_LENGTH,\n });\n\n/**\n * TODO: PA-1255 replaces this with a configuration store (Contentstack, read through the Configuration\n * SDK) that holds these values per environment, then delete the values below.\n *\n * TEMPORARY: values for the test environment, used only when the page is served from a test\n * host or localhost (`getEnvironmentCode()` is `test`). Every other environment gets the\n * defaults, so search stays plain search.\n */\nconst TEST_ENVIRONMENT_VALUES = {\n agent: {\n appKey: 'pk_commerce_product_advisor_624aea4305b09240e8c8f41d0f6527b2',\n apiBaseUrl: 'https://nui.tst.nuskin.ai/',\n },\n // Open to visitors who are not signed in, so the handoff can be tried where signing in is not\n // possible (for example local development). Sign-in stays required everywhere else.\n allowGuestAgent: true,\n};\n\nfunction nonEmptyString(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\n/**\n * Turns whatever the store returned into a safe configuration: anything missing or malformed\n * falls back to the default, and the agent is dropped unless it is complete.\n */\nexport function normalizeCommerceSearchConfig(\n raw?: {\n minimumSearchLength?: unknown;\n agent?: { appKey?: unknown; apiBaseUrl?: unknown };\n allowGuestAgent?: unknown;\n } | null,\n { language }: { language?: string } = {},\n): CommerceSearchConfig {\n const minimumSearchLength = Number(raw?.minimumSearchLength);\n const appKey = nonEmptyString(raw?.agent?.appKey);\n const apiBaseUrl = nonEmptyString(raw?.agent?.apiBaseUrl);\n\n return {\n minimumSearchLength:\n Number.isInteger(minimumSearchLength) && minimumSearchLength >= 1\n ? minimumSearchLength\n : COMMERCE_SEARCH_CONFIG_DEFAULTS.minimumSearchLength,\n ...(appKey && apiBaseUrl\n ? {\n agent: {\n appKey,\n apiBaseUrl,\n ...(language ? { language } : {}),\n },\n }\n : {}),\n ...(raw?.allowGuestAgent === true ? { allowGuestAgent: true } : {}),\n };\n}\n\n/** Reads the product search configuration for a market and host. */\nexport async function fetchCommerceSearchConfig({\n language,\n}: FetchCommerceSearchConfigOptions = {}): Promise<CommerceSearchConfig> {\n const raw = getEnvironmentCode() === 'test' ? TEST_ENVIRONMENT_VALUES : {};\n\n return normalizeCommerceSearchConfig(raw, language ? { language } : {});\n}\n","import { useEffect, useState } from 'react';\nimport {\n COMMERCE_SEARCH_CONFIG_DEFAULTS,\n fetchCommerceSearchConfig,\n} from '../config/commerceSearchConfig';\nimport type { CommerceSearchConfig } from '../config/commerceSearchConfig';\n\nexport interface UseCommerceSearchConfigOptions {\n country?: string;\n language?: string;\n /** Nothing is read until this is true (for example, until the panel first opens). */\n enabled: boolean;\n}\n\n/**\n * The product search configuration for a market: the defaults until the read finishes, and\n * again if it fails. A read that finishes after the market changed is ignored.\n */\nexport function useCommerceSearchConfig({\n country,\n language,\n enabled,\n}: UseCommerceSearchConfigOptions): CommerceSearchConfig {\n const [config, setConfig] = useState<CommerceSearchConfig>(\n COMMERCE_SEARCH_CONFIG_DEFAULTS,\n );\n\n useEffect(() => {\n if (!enabled) return undefined;\n let isStale = false;\n\n fetchCommerceSearchConfig({\n ...(country ? { country } : {}),\n ...(language ? { language } : {}),\n })\n .then((next) => {\n if (!isStale) setConfig(next);\n })\n .catch((error: unknown) => {\n console.warn(\n '[search] Could not load the product search configuration:',\n error,\n );\n });\n\n return () => {\n isStale = true;\n };\n }, [enabled, country, language]);\n\n return config;\n}\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\n\n/**\n * The search panel's text, in English. This file is where the text comes from for now, for every\n * language. The configuration store will replace it, and only `fetchSearchPanelCopy` reads it.\n *\n * The functions word a string around a number or a product name.\n */\nexport const SEARCH_PANEL_COPY_EN: SearchPanelCopy = {\n cancel: 'Cancel',\n searchPlaceholder: 'Search',\n didYouMean: 'Did You Mean?',\n noSuggestions: 'No suggestions',\n seeMoreResults: 'See More Results',\n recentSearches: 'Recent searches',\n clearRecentSearches: 'Clear all',\n moreRecentSearches: (count) => `+${count} More`,\n searchLabel: 'Search',\n submitSearch: 'Submit search',\n clearInput: 'Clear search',\n suggestionsLabel: 'Suggestions',\n addToCart: (productName) => `Add ${productName} to cart`,\n openBundle: (productName) => `Open bundle action for ${productName}`,\n suggestionsLoading: 'Loading suggestions',\n suggestionsCount: (count) => `${count} suggestions available`,\n};\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { SEARCH_PANEL_COPY_EN } from './searchPanelCopy';\n\nexport interface FetchSearchPanelCopyOptions {\n language?: string;\n}\n\n/**\n * Reads the search panel's text for a language. It is the only function that knows where the text\n * comes from, so moving it to the configuration store changes this function and nothing else.\n *\n * For now there is one English file, and every language gets it.\n */\nexport async function fetchSearchPanelCopy(\n _options: FetchSearchPanelCopyOptions = {},\n): Promise<SearchPanelCopy> {\n return SEARCH_PANEL_COPY_EN;\n}\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { fetchSearchPanelCopy } from './fetchSearchPanelCopy';\n\nconst copyByLanguage = new Map<string, Promise<SearchPanelCopy>>();\nconst loadedByLanguage = new Map<string, SearchPanelCopy>();\n\nfunction cacheKey(language?: string): string {\n return (language ?? '').toLowerCase();\n}\n\n/**\n * The search panel's text for a language, read once and shared by every caller, so that\n * remounting the search (or StrictMode running an effect twice) does not read it again.\n * A read that fails is not kept, so the next caller tries again.\n */\nexport function loadSearchPanelCopy(\n language?: string,\n): Promise<SearchPanelCopy> {\n const key = cacheKey(language);\n const cached = copyByLanguage.get(key);\n if (cached) return cached;\n\n const pending = fetchSearchPanelCopy(language ? { language } : {});\n copyByLanguage.set(key, pending);\n // Registered before any caller's own handlers, so the text can be peeked at by the time they run.\n pending.then(\n (copy) => {\n if (copyByLanguage.get(key) === pending) {\n loadedByLanguage.set(key, copy);\n }\n },\n () => {\n if (copyByLanguage.get(key) === pending) {\n copyByLanguage.delete(key);\n }\n },\n );\n\n return pending;\n}\n\n/**\n * The text for a language if it has already loaded, otherwise `undefined`. It never starts a\n * read, and it answers straight away, which a promise cannot.\n */\nexport function peekSearchPanelCopy(\n language?: string,\n): SearchPanelCopy | undefined {\n return loadedByLanguage.get(cacheKey(language));\n}\n\n/** Forgets what was read, so a test starts from nothing. */\nexport function clearSearchPanelCopyCache(): void {\n copyByLanguage.clear();\n loadedByLanguage.clear();\n}\n","import { useEffect, useState } from 'react';\nimport type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport {\n loadSearchPanelCopy,\n peekSearchPanelCopy,\n} from '../copy/loadSearchPanelCopy';\n\n/**\n * The search panel's text for a language, or nothing until it has loaded. It starts loading as\n * soon as it is used, not when the panel opens, so the text is ready by then. A read that\n * finishes after the language changed is ignored.\n *\n * A mount that finds the text already loaded has it on its first render, so the panel does not\n * wait a tick for text that is already in memory. The server renders nothing here, so a root that\n * hydrates after another root has loaded the text would render the panel where the server did\n * not. A single root cannot: loading starts in an effect, after hydration has finished.\n */\nexport function useSearchPanelCopy({\n language,\n}: {\n language?: string;\n}): SearchPanelCopy | undefined {\n const [copy, setCopy] = useState<SearchPanelCopy | undefined>(() =>\n peekSearchPanelCopy(language),\n );\n\n useEffect(() => {\n let isStale = false;\n\n loadSearchPanelCopy(language)\n .then((next) => {\n if (!isStale) setCopy(next);\n })\n .catch((error: unknown) => {\n // The panel stays unrendered until the text loads.\n console.warn(\n '[search] Could not load the search panel text:',\n error,\n );\n });\n\n return () => {\n isStale = true;\n };\n }, [language]);\n\n return copy;\n}\n","import type { LocaleParts } from '../types';\n\n/**\n * A market is a country and a language, two letters each, as the storefront's own URLs and locale\n * parsing require (`/us/en/`). Nothing else is a market, and nothing stands in for one.\n */\nconst TWO_LETTERS = /^[A-Za-z]{2}$/;\n\n/** What is wrong with a market, or `undefined` when it is valid. */\nexport function marketProblem(\n country: unknown,\n language: unknown,\n): string | undefined {\n const countryText = String(country ?? '').trim();\n const languageText = String(language ?? '').trim();\n if (TWO_LETTERS.test(countryText) && TWO_LETTERS.test(languageText)) {\n return undefined;\n }\n return `the market is not valid (country ${JSON.stringify(countryText)}, language ${JSON.stringify(languageText)}): each must be two letters, for example US and en`;\n}\n\nexport function isValidMarket(country: unknown, language: unknown): boolean {\n return marketProblem(country, language) === undefined;\n}\n\n/**\n * The market in the shape the SDK stores it: an upper-case country, a lower-case language and the\n * two joined (`US-en`). Throws for a market that is not valid, so that nothing ever falls back to\n * another market.\n */\nexport function createLocaleParts({\n country,\n language,\n}: {\n country: string;\n language: string;\n}): LocaleParts {\n const problem = marketProblem(country, language);\n if (problem) throw new Error(problem);\n\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedLanguage = language.trim().toLowerCase();\n return {\n country: normalizedCountry,\n language: normalizedLanguage,\n locale: `${normalizedCountry}-${normalizedLanguage}`,\n };\n}\n\n/** The market as the catalog API names it: `en_US`. */\nexport function toCatalogLocale({ country, language }: LocaleParts): string {\n return `${language}_${country}`;\n}\n\n/** The market as the storefront's paths start: `/us/en`. */\nexport function toPathPrefix({ country, language }: LocaleParts): string {\n return `/${country.toLowerCase()}/${language}`;\n}\n","import {\n CATALOG_SUGGESTIONS_PATH,\n DEFAULT_SUGGESTION_PAGE,\n DEFAULT_SUGGESTION_SIZE,\n STOREFRONT_SHOPPING_CONTEXT,\n} from '../constants';\nimport type {\n GetMarketConfig,\n LocaleParts,\n LocationLike,\n MarketConfig,\n} from '../types';\nimport { toCatalogLocale } from './localeParts';\n\n/* -------------------------------------------------------------------------- */\n/* Market-config → URL/storeId resolution */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Replaces `{api_name}` in a market-config gateway path with the given API\n * name, then trims a single trailing slash.\n */\nexport function resolveApiGatewayPath(\n apiGatewayPath: string | undefined | null,\n apiName: string = STOREFRONT_SHOPPING_CONTEXT,\n): string {\n const apiGateway = String(apiGatewayPath ?? '').trim();\n if (!apiGateway) return '';\n return apiGateway.replace(/\\{api_name\\}/gi, apiName).replace(/\\/$/, '');\n}\n\nfunction resolveCatalogApiBaseUrl(\n marketConfig: MarketConfig | null | undefined,\n): string {\n return resolveApiGatewayPath(marketConfig?.api_gateway_path);\n}\n\nfunction resolveCatalogStoreId(\n marketConfig: MarketConfig | null | undefined,\n): string {\n return String(marketConfig?.store_id ?? '').trim();\n}\n\nfunction buildCatalogSuggestionsUrl(apiBaseUrl: string): string {\n const normalizedBase = String(apiBaseUrl ?? '')\n .trim()\n .replace(/\\/$/, '');\n if (!normalizedBase) return '';\n\n const suggestionsPath = normalizedBase.endsWith(\n `/${STOREFRONT_SHOPPING_CONTEXT}`,\n )\n ? '/catalogs/search/suggestions'\n : CATALOG_SUGGESTIONS_PATH;\n\n return `${normalizedBase}${suggestionsPath}`;\n}\n\n/** The URL of one suggestions request. */\nexport function buildSuggestionsRequestUrl({\n suggestionsUrl,\n searchTerm,\n storeId,\n localeParts,\n}: {\n suggestionsUrl: string;\n searchTerm: string;\n storeId: string;\n localeParts: LocaleParts;\n}): string {\n const queryParams = new URLSearchParams({\n searchTerm,\n page: String(DEFAULT_SUGGESTION_PAGE),\n size: String(DEFAULT_SUGGESTION_SIZE),\n locale: toCatalogLocale(localeParts),\n storeId,\n });\n return `${suggestionsUrl}?${queryParams.toString()}`;\n}\n\n/**\n * Where the market's suggestions live and which store they are for. Throws when the market has no\n * gateway or no store, so that it counts as a failed lookup and is not remembered, and never reads\n * as \"the catalog has no products\".\n */\nexport async function resolveCatalogRequestConfig({\n locationLike,\n country,\n getMarketConfig,\n}: {\n locationLike: LocationLike | null;\n country: string;\n getMarketConfig: GetMarketConfig | undefined;\n}): Promise<{ suggestionsUrl: string; storeId: string }> {\n const marketConfig = getMarketConfig\n ? ((await getMarketConfig({ locationLike, country })) ?? null)\n : null;\n\n const suggestionsUrl = buildCatalogSuggestionsUrl(\n resolveCatalogApiBaseUrl(marketConfig),\n );\n if (!suggestionsUrl) {\n throw new Error(\n `no suggestions API for market ${country}: the market configuration has no gateway`,\n );\n }\n const storeId = resolveCatalogStoreId(marketConfig);\n if (!storeId) {\n throw new Error(\n `no suggestions API for market ${country}: the market configuration has no store`,\n );\n }\n\n return { suggestionsUrl, storeId };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Fetch helper */\n/* -------------------------------------------------------------------------- */\n\n/** The `X-Customer-Type` header for a request, or none when there is no customer type to send. */\nexport function resolveCustomerTypeHeaders(\n getCustomerType: (() => string | undefined) | undefined,\n): Record<string, string> | undefined {\n const customerType = getCustomerType?.()?.trim();\n return customerType ? { 'X-Customer-Type': customerType } : undefined;\n}\n\n/**\n * The suggestions API answers a term that matches nothing with a 404 whose body carries this code\n * (`{ code: 'SFOSER002', message: 'No Results Found for Search Term …' }`). That is an answer,\n * not an outage: treating it as a failure would also keep the NUi agent from ever taking over.\n */\nconst NO_RESULTS_ERROR_CODE = 'SFOSER002';\n\nasync function isNoResultsResponse(response: Response): Promise<boolean> {\n if (response.status !== 404) return false;\n try {\n const body = (await response.json()) as { code?: unknown } | null;\n return body?.code === NO_RESULTS_ERROR_CODE;\n } catch {\n return false;\n }\n}\n\n/** Resolves to the response's JSON, or `null` when the API says nothing matched. */\nexport async function fetchJson(\n fetchImpl: typeof fetch,\n requestUrl: string,\n requestHeaders: Record<string, string> = {},\n): Promise<unknown> {\n const response = await fetchImpl(requestUrl, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json', ...requestHeaders },\n });\n\n if (!response.ok) {\n if (await isNoResultsResponse(response)) return null;\n throw new Error(`Request failed with status ${response.status}`);\n }\n\n return response.json();\n}\n","import {\n RECENT_SEARCHES_DEFAULT_LIMIT,\n RECENT_SEARCHES_PREFIX,\n} from '../constants';\nimport type { LocaleParts } from '../types';\n\n/* -------------------------------------------------------------------------- */\n/* Storage guards */\n/* -------------------------------------------------------------------------- */\n\nfunction canUseStorage(\n storage: Storage | null | undefined,\n): storage is Storage {\n return (\n Boolean(storage) && typeof (storage as Storage).getItem === 'function'\n );\n}\n\nexport function getSessionStorage(\n providedStorage: Storage | null | undefined,\n): Storage | null {\n if (providedStorage) return providedStorage;\n\n if (typeof window !== 'undefined') {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\nfunction getRecentHeaderSearchesStorageKey(localeParts: LocaleParts): string {\n const { country, language, locale } = localeParts;\n return `${RECENT_SEARCHES_PREFIX}:${locale}:${country}:${language}`;\n}\n\nexport function getRecentHeaderSearches(\n localeParts: LocaleParts,\n storage: Storage | null,\n): string[] {\n if (!canUseStorage(storage)) {\n return [];\n }\n\n try {\n const rawValue = storage.getItem(\n getRecentHeaderSearchesStorageKey(localeParts),\n );\n if (!rawValue) {\n return [];\n }\n\n const parsedValue: unknown = JSON.parse(rawValue);\n if (!Array.isArray(parsedValue)) {\n return [];\n }\n\n return parsedValue\n .map((item) => String(item ?? '').trim())\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function addRecentHeaderSearch(\n localeParts: LocaleParts,\n query: string,\n storage: Storage | null,\n limit: number = RECENT_SEARCHES_DEFAULT_LIMIT,\n): string[] {\n const normalizedQuery = String(query ?? '').trim();\n if (!normalizedQuery || !canUseStorage(storage)) {\n return [];\n }\n\n try {\n const existingValues = getRecentHeaderSearches(\n localeParts,\n storage,\n ).filter(\n (item) => item.toLowerCase() !== normalizedQuery.toLowerCase(),\n );\n const nextValues = [normalizedQuery, ...existingValues].slice(0, limit);\n storage.setItem(\n getRecentHeaderSearchesStorageKey(localeParts),\n JSON.stringify(nextValues),\n );\n return nextValues;\n } catch {\n return [];\n }\n}\n\nexport function clearRecentHeaderSearches(\n localeParts: LocaleParts,\n storage: Storage | null,\n): void {\n if (!canUseStorage(storage)) {\n return;\n }\n\n try {\n storage.removeItem(getRecentHeaderSearchesStorageKey(localeParts));\n } catch {\n // intentionally quiet when storage is blocked/unavailable\n }\n}\n","import { DEFAULT_SEARCH_PATH } from '../constants';\nimport type { LocaleParts, SuggestionOption } from '../types';\nimport { toPathPrefix } from './localeParts';\n\n/* -------------------------------------------------------------------------- */\n/* Path + slug helpers */\n/* -------------------------------------------------------------------------- */\n\nexport function buildSearchResultsPath(\n query: string,\n localeParts: LocaleParts,\n): string {\n const trimmedQuery = String(query ?? '').trim();\n const hyphenatedQuery = trimmedQuery.replace(/\\s+/g, '-');\n const encodedQuery = encodeURIComponent(hyphenatedQuery).replace(\n /%2D/gi,\n '-',\n );\n return `${toPathPrefix(localeParts)}${DEFAULT_SEARCH_PATH}/${encodedQuery}`;\n}\n\n/** Starts with a scheme, such as `javascript:`, `mailto:` or `https:`. */\nconst SCHEME = /^[a-z][a-z0-9+.-]*:/i;\n\n/**\n * An authored link can leave out its leading slash (`search/serum`). Put it back, unless the value\n * starts with a scheme or is already a path or protocol-relative (it then starts with a slash):\n * `isNavigableUrl` accepts or refuses those as they are.\n */\nfunction normalizeOptionUrl(rawValue: unknown): string {\n if (typeof rawValue !== 'string') return '';\n const value = rawValue.trim();\n if (!value || value.startsWith('/') || SCHEME.test(value)) return value;\n return `/${value}`;\n}\n\nfunction safeDecodeURIComponent(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction trimEdgeHyphens(value: string): string {\n let normalizedValue = value;\n while (normalizedValue.startsWith('-')) {\n normalizedValue = normalizedValue.slice(1);\n }\n while (normalizedValue.endsWith('-')) {\n normalizedValue = normalizedValue.slice(0, -1);\n }\n return normalizedValue;\n}\n\nfunction slugifyPathSegment(value: string | undefined | null): string {\n const decoded = safeDecodeURIComponent(String(value ?? '')).replace(\n /\\+/g,\n ' ',\n );\n const normalized = decoded\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/-{2,}/g, '-')\n .toLowerCase();\n return trimEdgeHyphens(normalized);\n}\n\nfunction buildProductSlugPath(\n slugValue: string | undefined | null,\n localeParts: LocaleParts,\n): string {\n const slug = slugifyPathSegment(slugValue);\n if (!slug) return '';\n return `${toPathPrefix(localeParts)}/product/${slug}`;\n}\n\nfunction isNavigableUrl(value: string): boolean {\n if (!value) return false;\n return value.startsWith('/') || /^https?:\\/\\//i.test(value);\n}\n\nexport function stripLocalePrefix(\n path: string,\n localeParts: LocaleParts,\n): string {\n const prefix = toPathPrefix(localeParts);\n return path.startsWith(prefix) ? path.slice(prefix.length) || '/' : path;\n}\n\nexport function resolveOptionHref(\n option: SuggestionOption | null | undefined,\n localeParts: LocaleParts,\n): string {\n const productSlugPath = buildProductSlugPath(\n option?.slug ?? option?.productSlug ?? option?.product_slug ?? null,\n localeParts,\n );\n if (productSlugPath) {\n return productSlugPath;\n }\n\n const directUrl = normalizeOptionUrl(option?.href ?? option?.url);\n if (isNavigableUrl(directUrl) && !directUrl.includes('/chr/')) {\n return directUrl;\n }\n return '';\n}\n","import type { SuggestionsResponse } from '../types';\n\n/** The answer when there is nothing to look up, or nowhere to look it up. */\nexport function emptySuggestions(): SuggestionsResponse {\n return { suggestions: [], didYouMean: [], totalResultsCount: 0 };\n}\n\n/** The total the API reports: `totalResultsCount`, else the pageable total, else `fallback`. */\nfunction resolveTotalResultsCount(\n payload: SuggestionsResponse | null | undefined,\n fallback: number,\n): number {\n if (typeof payload?.totalResultsCount === 'number') {\n return payload.totalResultsCount;\n }\n const pageableTotal = Number(\n payload?.pageableInfo?.totalCount ?? Number.NaN,\n );\n return Number.isNaN(pageableTotal) ? fallback : pageableTotal;\n}\n\n/**\n * The API's answer with `suggestions` and `didYouMean` always arrays and `totalResultsCount`\n * always a number. Everything else the API sent (the `product` array, for one) is kept.\n */\nexport function normalizeSuggestionsPayload(\n payload: SuggestionsResponse | null | undefined,\n): SuggestionsResponse {\n const suggestions = Array.isArray(payload?.suggestions)\n ? payload.suggestions\n : [];\n const products = Array.isArray(payload?.product)\n ? (payload.product as unknown[])\n : null;\n const rawDidYouMean = payload?.didYouMean ?? payload?.did_you_mean;\n const didYouMean = Array.isArray(rawDidYouMean)\n ? (rawDidYouMean as unknown[])\n : [];\n\n return {\n ...(payload ?? {}),\n suggestions,\n didYouMean,\n totalResultsCount: resolveTotalResultsCount(\n payload,\n products?.length ?? suggestions.length,\n ),\n };\n}\n","/**\n * SearchApiService: the suggestions request and the paths a search leads to. Navigation is left\n * to the host's router.\n *\n * Two things stay outside it:\n * 1. Market-config resolution, which depends on `@nuskin/configuration-sdk`. The caller\n * injects a `getMarketConfig` callback to resolve the gateway URL and store id.\n * 2. The market itself. The caller passes `country` and `language` explicitly.\n */\n\nimport { MINIMUM_SEARCH_CHAR_LENGTH } from '../constants';\nimport type {\n LocationLike,\n SearchServiceOptions,\n SuggestionOption,\n SuggestionsResponse,\n} from '../types';\nimport {\n buildSuggestionsRequestUrl,\n fetchJson,\n resolveCatalogRequestConfig,\n resolveCustomerTypeHeaders,\n} from './catalogRequest';\nimport { createLocaleParts } from './localeParts';\nimport {\n addRecentHeaderSearch,\n clearRecentHeaderSearches,\n getRecentHeaderSearches,\n getSessionStorage,\n} from './recentSearches';\nimport {\n buildSearchResultsPath,\n resolveOptionHref,\n stripLocalePrefix,\n} from './searchPaths';\nimport {\n emptySuggestions,\n normalizeSuggestionsPayload,\n} from './suggestionsPayload';\n\n/** Returned by `createSearchService`. Internal to the package. */\nexport interface SearchService {\n /** Fetches typeahead suggestions from the Equinox catalog. */\n fetchSuggestions: (searchTerm: string) => Promise<SuggestionsResponse>;\n /**\n * Records the query in recent searches, then returns the option URL or the\n * fallback search-results path for the consuming router to navigate.\n */\n submitProductSearch: (\n query: string,\n option?: SuggestionOption,\n ) => string | undefined;\n /**\n * Returns the suggestion's URL if one is resolvable; otherwise submits the\n * suggestion's textual value as a product search.\n */\n activateSuggestionAction: (option: SuggestionOption) => string | undefined;\n /** Returns the navigable URL for a suggestion option (or `\"\"`). */\n getSuggestionHref: (option: SuggestionOption) => string;\n /** Returns the search-results page path for `query`. */\n viewMoreResults: (input: { query: string }) => string | undefined;\n /** Returns the persisted recent searches for the current locale bucket. */\n getRecentSearches: () => string[];\n /** Removes all persisted recent searches for the current locale bucket. */\n clearRecentSearches: () => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Location helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction getBrowserLocation(\n providedLocation: LocationLike | null | undefined,\n): LocationLike | null {\n if (providedLocation) return providedLocation;\n if (typeof window !== 'undefined' && window.location)\n return window.location;\n return null;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Factory */\n/* -------------------------------------------------------------------------- */\n\n/**\n * What `createSearchService` accepts. Internal: `CommerceSearch` adds the minimum search length\n * from its configuration, so hosts never set it.\n */\ninterface ResolvedSearchServiceOptions extends SearchServiceOptions {\n /**\n * The visitor's account type, sent as `X-Customer-Type` on every suggestions request. Read\n * when the request is made, because it can change after the visitor signs in.\n */\n getCustomerType?: () => string | undefined;\n /**\n * Terms shorter than this are not sent to the suggestions API. Defaults to\n * `MINIMUM_SEARCH_CHAR_LENGTH`.\n */\n minimumSearchLength?: number;\n}\n\n/**\n * Creates a search service instance. All options are optional; sensible\n * fallbacks are used when the browser environment is absent (SSR).\n */\nexport function createSearchService(\n options: ResolvedSearchServiceOptions,\n): SearchService {\n const {\n fetchImpl: fetchImplOption,\n location: providedLocation,\n storage: providedStorage,\n country,\n language,\n getMarketConfig,\n getCustomerType,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n } = options;\n\n const locationLike = getBrowserLocation(providedLocation);\n const storage = getSessionStorage(providedStorage);\n const localeParts = createLocaleParts({ country, language });\n\n let catalogRequestConfigPromise: Promise<{\n suggestionsUrl: string;\n storeId: string;\n }> | null = null;\n\n function loadCatalogRequestConfig() {\n if (!catalogRequestConfigPromise) {\n catalogRequestConfigPromise = resolveCatalogRequestConfig({\n locationLike,\n country: localeParts.country,\n getMarketConfig,\n }).catch((error: unknown) => {\n // Do not remember a failure: the next search tries again. And say so, because a\n // search that quietly returns nothing is very hard to diagnose.\n catalogRequestConfigPromise = null;\n console.warn(\n '[search] Could not load the market configuration for the suggestions:',\n error,\n );\n throw error;\n });\n }\n return catalogRequestConfigPromise;\n }\n\n const service: SearchService = {\n async fetchSuggestions(\n searchTerm: string,\n ): Promise<SuggestionsResponse> {\n const trimmedSearchTerm = String(searchTerm ?? '').trim();\n if (\n !trimmedSearchTerm ||\n trimmedSearchTerm.length < minimumSearchLength\n ) {\n return emptySuggestions();\n }\n\n const { suggestionsUrl, storeId } =\n await loadCatalogRequestConfig();\n\n const responsePayload = (await fetchJson(\n fetchImplOption ?? fetch.bind(globalThis),\n buildSuggestionsRequestUrl({\n suggestionsUrl,\n searchTerm: trimmedSearchTerm,\n storeId,\n localeParts,\n }),\n resolveCustomerTypeHeaders(getCustomerType),\n )) as SuggestionsResponse | null | undefined;\n\n return normalizeSuggestionsPayload(responsePayload);\n },\n\n submitProductSearch(\n query: string,\n option?: SuggestionOption,\n ): string | undefined {\n const trimmedQuery = String(query ?? '').trim();\n if (!trimmedQuery) return undefined;\n\n addRecentHeaderSearch(localeParts, trimmedQuery, storage);\n\n const optionHref = resolveOptionHref(option, localeParts);\n if (optionHref) {\n return stripLocalePrefix(optionHref, localeParts);\n }\n\n const targetPath = buildSearchResultsPath(\n trimmedQuery,\n localeParts,\n );\n\n return stripLocalePrefix(targetPath, localeParts);\n },\n\n activateSuggestionAction(option: SuggestionOption): string | undefined {\n // The suggestion's page, or a search for its text.\n const optionHref = resolveOptionHref(option, localeParts);\n if (optionHref) {\n return stripLocalePrefix(optionHref, localeParts);\n }\n\n const optionQuery =\n option?.value ?? option?.label ?? option?.identifier ?? '';\n return service.submitProductSearch(String(optionQuery));\n },\n\n getSuggestionHref(option: SuggestionOption): string {\n return stripLocalePrefix(\n resolveOptionHref(option, localeParts),\n localeParts,\n );\n },\n\n viewMoreResults({ query }: { query: string }): string | undefined {\n return service.submitProductSearch(query);\n },\n\n getRecentSearches(): string[] {\n return getRecentHeaderSearches(localeParts, storage);\n },\n\n clearRecentSearches(): void {\n clearRecentHeaderSearches(localeParts, storage);\n },\n };\n\n return service;\n}\n","import {\n getConfiguration,\n getEnvironmentCode,\n} from '../config/configurationSdk';\nimport {\n DEFAULT_EQUINOX_CLIENT_ID,\n EQUINOX_MARKETS_MAP,\n STOREFRONT_SHOPPING_CONTEXT,\n} from '../constants';\nimport type { GetMarketConfig, MarketConfig } from '../types';\n\n/**\n * Reads the market's API gateway and store from the `Equinox_Markets` configuration, for the\n * environment the page is served from.\n */\nexport const fetchMarketConfig: GetMarketConfig = async ({ country }) => {\n const countryCode = country.trim().toUpperCase();\n const configuration = await getConfiguration([EQUINOX_MARKETS_MAP], {\n country: countryCode,\n ...(getEnvironmentCode()\n ? { environment: getEnvironmentCode() as string }\n : {}),\n clientId: DEFAULT_EQUINOX_CLIENT_ID,\n shoppingContext: STOREFRONT_SHOPPING_CONTEXT,\n });\n\n return (\n (configuration?.[EQUINOX_MARKETS_MAP] as MarketConfig | undefined) ??\n null\n );\n};\n","/**\n * GTM constants — event names, storage keys, and enum-like value maps.\n * Types are declared in `./gtmTypes` and imported here only for `satisfies`.\n */\n\nimport type { SearchGtmSearchType, SearchGtmUserStatus } from './gtmTypes';\n\n/* -------------------------------------------------------------------------- */\n/* Event names (COMX-3277) */\n/* -------------------------------------------------------------------------- */\n\nexport const SEARCH_GTM_EVENTS = {\n CHAT_ENTRY_POINT: 'Begin_chat',\n SEARCH_TYPE: 'Search_Type',\n PRODUCT_SEARCH: 'ProductSearch',\n ERROR_POPUP: 'Error_popup',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Enum-like value maps */\n/* -------------------------------------------------------------------------- */\n\nexport const SEARCH_GTM_SEARCH_TYPES = {\n SEMANTIC: 'semantic search',\n AI_AGENT: 'AI agent',\n} as const satisfies Record<string, SearchGtmSearchType>;\n\nexport const SEARCH_GTM_USER_STATUS = {\n GUEST: 'guest',\n LOGGED_IN: 'logged_in',\n} as const satisfies Record<string, SearchGtmUserStatus>;\n\n/* -------------------------------------------------------------------------- */\n/* Storage keys the SDK reads from the host storefront */\n/* -------------------------------------------------------------------------- */\n\n/** Fallback string used for the GTM `id` and `Chat_ID` fields when unknown. */\nexport const GTM_FALLBACK_NA = 'NA';\n","/**\n * Where `CommerceSearch` wants the host to take the shopper: a page inside the app (a path for\n * the host's router, with the market prefix already removed), or somewhere that needs a full\n * page load.\n */\nexport type NavigationTarget =\n { type: 'internal'; path: string } | { type: 'external'; url: string };\n\nconst EXTERNAL_URL = /^https?:\\/\\//i;\n\n/**\n * A path inside the app starts with exactly one slash. `//host` and `/\\host` are another site to a\n * browser, and a browser drops a tab or a newline anywhere in a URL, so `/<tab>/host` is `//host`.\n */\nconst INTERNAL_PATH = /^\\/(?![/\\\\])[^\\t\\n\\r]*$/;\n\n/**\n * Classifies a path from the search service as internal or external. Anything that is neither an\n * `http(s)` URL nor a path inside the app (`javascript:`, `data:`, `//host` and the like) is\n * refused with `undefined`, so it never reaches the host.\n */\nexport function toNavigationTarget(path: string): NavigationTarget | undefined {\n if (EXTERNAL_URL.test(path)) return { type: 'external', url: path };\n if (INTERNAL_PATH.test(path)) return { type: 'internal', path };\n return undefined;\n}\n","import type { ProductEnvironment } from '@nuskin/react-product-sdk';\nimport { getEnvironmentCode } from '../config/configurationSdk';\n\n/**\n * Every environment the product SDK knows. A record, so that a change to the SDK's list is a\n * compile error here and not a silent mismatch: each environment must appear exactly once.\n */\nconst PRODUCT_ENVIRONMENTS: Readonly<Record<ProductEnvironment, true>> = {\n dev: true,\n test: true,\n prod: true,\n};\n\nfunction isProductEnvironment(code: string): code is ProductEnvironment {\n // Compares against the keys: `in` would take `constructor` and `toString` for environments.\n return Object.keys(PRODUCT_ENVIRONMENTS).includes(code);\n}\n\n/**\n * The product SDK's environment for the configuration SDK's environment code, or `undefined` when\n * the product SDK has none (for example `stage`): the agent's product cards then stay the widget's own.\n */\nexport function toProductEnvironment(\n environmentCode: string | undefined,\n): ProductEnvironment | undefined {\n return environmentCode !== undefined &&\n isProductEnvironment(environmentCode)\n ? environmentCode\n : undefined;\n}\n\n/**\n * The product SDK's environment for the page, or `undefined` when it cannot be told. The product\n * cards are an enhancement: not knowing the environment must never break the search.\n */\nexport function getProductEnvironment(): ProductEnvironment | undefined {\n try {\n return toProductEnvironment(getEnvironmentCode());\n } catch {\n return undefined;\n }\n}\n","import { useEffect } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchPanel } from '@nuskin/react-search-components';\nimport { SEARCH_PANEL_COPY_EN } from '../../copy/searchPanelCopy';\nimport { marketProblem } from '../../services/localeParts';\n\nexport interface CommerceSearchUnavailableProps {\n isOpen: boolean;\n onClose: () => void;\n country: string;\n language: string;\n logo?: ReactNode;\n}\n\nconst NOTHING = () => undefined;\n\n/**\n * What the shopper sees when the host gave the search a market it cannot search in. The search\n * makes no request and shows no other market's results; the problem is logged once for the\n * market, so the host's mistake is found early.\n */\nexport function CommerceSearchUnavailable({\n isOpen,\n onClose,\n country,\n language,\n logo,\n}: Readonly<CommerceSearchUnavailableProps>): ReactElement {\n useEffect(() => {\n console.error(\n `[search] Search is unavailable: ${marketProblem(country, language)}`,\n );\n }, [country, language]);\n\n return (\n <SearchPanel\n isOpen={isOpen}\n onClose={onClose}\n copy={SEARCH_PANEL_COPY_EN}\n logo={logo}\n input={{ value: '', onChange: NOTHING, onSubmit: NOTHING }}\n suggestions={{\n items: [],\n loading: false,\n showNoResults: false,\n showDidYouMean: false,\n hasMore: false,\n query: '',\n onSelect: NOTHING,\n onRunAction: NOTHING,\n onSeeMore: NOTHING,\n }}\n recentSearches={{\n items: [],\n onSelect: NOTHING,\n onClear: NOTHING,\n }}\n agentPanel={<p role=\"alert\">Search is unavailable right now.</p>}\n />\n );\n}\n","/**\n * The enable gate for NUi search.\n *\n * NUi search is on only for visitors who have switched it on with the\n * `enableNuiSearch` flag, either as a URL query parameter\n * (`?enableNuiSearch=true` or `=false`) or as a cookie of the same name. The\n * library only ever reads them: the query parameter is never copied into the\n * cookie, so the cookie is something a person sets by hand, and the parameter\n * applies only to the page whose URL carries it. When both are present the\n * parameter wins, so `?enableNuiSearch=false` switches it off for that page.\n * Off by default. Visitors must also be signed in, unless the configuration\n * allows guests.\n *\n * The flag is a client-side feature toggle, not a security control. Real\n * per-market and per-locale switching is a later step.\n */\n\n/** Name shared by the cookie and the URL query parameter. */\nexport const NUI_SEARCH_FLAG = 'enableNuiSearch';\n\nfunction parseFlagValue(raw: string | null | undefined): boolean | undefined {\n const value = raw?.trim().toLowerCase();\n if (value === 'true' || value === '1') return true;\n if (value === 'false' || value === '0') return false;\n return undefined;\n}\n\nfunction readCookieFlag(cookie: string): boolean | undefined {\n for (const part of cookie.split(';')) {\n const separator = part.indexOf('=');\n if (separator < 0) continue;\n if (part.slice(0, separator).trim() !== NUI_SEARCH_FLAG) continue;\n try {\n return parseFlagValue(\n decodeURIComponent(part.slice(separator + 1)),\n );\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\n/** Where the flag is read from. Each defaults to the browser's. */\nexport interface NuiSearchFlagEnv {\n /** Query string, with or without the leading `?`. */\n search?: string;\n /** Cookie string, as in `document.cookie`. */\n cookie?: string;\n}\n\n/**\n * Reads the flag. A recognized query parameter wins; otherwise the cookie\n * decides. `undefined` means neither is set to a recognized value. Never writes\n * a cookie or any storage, and is safe to call during server rendering (there\n * is no URL or cookie there, so it is `undefined`).\n */\nexport function resolveNuiSearchFlag(\n env: NuiSearchFlagEnv = {},\n): boolean | undefined {\n const inBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n const search = env.search ?? (inBrowser ? window.location.search : '');\n const cookie = env.cookie ?? (inBrowser ? document.cookie : '');\n\n return (\n parseFlagValue(new URLSearchParams(search).get(NUI_SEARCH_FLAG)) ??\n readCookieFlag(cookie)\n );\n}\n\nexport interface IsNuiSearchEnabledInput {\n /** From the host (the storefront's `customerData.isAuthenticated`). */\n isAuthenticated: boolean | undefined;\n /** The resolved flag; see `resolveNuiSearchFlag`. */\n flag: boolean | undefined;\n /** From the configuration: lets a visitor who is not signed in through. Defaults to false. */\n allowGuests?: boolean;\n}\n\n/**\n * On only when the flag is explicitly on and the visitor is signed in (or guests are allowed).\n */\nexport function isNuiSearchEnabled({\n isAuthenticated,\n flag,\n allowGuests = false,\n}: IsNuiSearchEnabledInput): boolean {\n return flag === true && (isAuthenticated === true || allowGuests);\n}\n","import { useEffect, useState } from 'react';\nimport {\n isNuiSearchEnabled,\n resolveNuiSearchFlag,\n} from '../utils/nuiSearchGate';\n\nexport interface UseNuiAgentGateOptions {\n /** Whether an agent is configured at all. Without one the agent is never on. */\n hasAgent: boolean;\n /** The `enableNuiSearch` flag is read each time the panel opens. */\n isOpen: boolean;\n isAuthenticated: boolean;\n /** Lets a visitor who is not signed in through. */\n allowGuestAgent: boolean;\n}\n\n/**\n * Whether a search may reach the NUi agent: an agent is configured, the shopper switched it on\n * with the `enableNuiSearch` flag, and the shopper is signed in (or guests are allowed).\n */\nexport function useNuiAgentGate({\n hasAgent,\n isOpen,\n isAuthenticated,\n allowGuestAgent,\n}: UseNuiAgentGateOptions): boolean {\n const [flag, setFlag] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n if (isOpen) setFlag(resolveNuiSearchFlag());\n }, [isOpen]);\n\n return (\n hasAgent &&\n isNuiSearchEnabled({\n isAuthenticated,\n flag,\n allowGuests: allowGuestAgent,\n })\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { SearchService } from '../services/SearchApiService';\n\nexport interface UseRecentSearchesOptions {\n service: SearchService;\n /** Recent searches are read when the panel opens. */\n isOpen: boolean;\n /** Read them again when this changes, for example when an agent conversation ends. */\n refreshKey?: unknown;\n}\n\n/** The recent searches without blanks or repeats (compared ignoring case), newest first. */\nfunction uniqueRecentSearches(queries: ReadonlyArray<string>): string[] {\n const seen = new Set<string>();\n return queries.filter((query) => {\n const key = query.trim().toLowerCase();\n if (!key || seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** The shopper's recent searches for the panel, and a way to clear them. */\nexport function useRecentSearches({\n service,\n isOpen,\n refreshKey,\n}: UseRecentSearchesOptions): {\n recentSearches: string[];\n clearRecentSearches: () => void;\n} {\n const [recentSearches, setRecentSearches] = useState<string[]>([]);\n\n useEffect(() => {\n if (isOpen) {\n setRecentSearches(\n uniqueRecentSearches(service.getRecentSearches()),\n );\n }\n }, [isOpen, service, refreshKey]);\n\n const clearRecentSearches = useCallback(() => {\n service.clearRecentSearches();\n setRecentSearches([]);\n }, [service]);\n\n return { recentSearches, clearRecentSearches };\n}\n","/* -------------------------------------------------------------------------- */\n/* Product-status helpers */\n/* -------------------------------------------------------------------------- */\n\nconst CART_DISABLED_PRODUCT_STATUSES = new Set([\n 'discontinued',\n 'preview',\n 'previewproduct',\n 'test',\n 'stopped',\n 'replacement',\n 'bundleonly',\n 'inactive',\n 'notavailable',\n]);\n\nfunction normalizeProductStatusValue(value: unknown): string {\n return String(value ?? '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '');\n}\n\n/** Returns `true` when `productStatus` is `\"sellable\"`. */\nexport function isSellableProductStatus(productStatus: unknown): boolean {\n return normalizeProductStatusValue(productStatus) === 'sellable';\n}\n\nfunction resolveSkuStatusValues(\n suggestionOption: Record<string, unknown>,\n): string[] {\n return [\n suggestionOption['productStatus'],\n suggestionOption['product_status'],\n suggestionOption['status'],\n suggestionOption['sku_status'],\n ]\n .map(normalizeProductStatusValue)\n .filter(Boolean);\n}\n\nfunction isNonSellableStatusValue(statusValue: string): boolean {\n if (CART_DISABLED_PRODUCT_STATUSES.has(statusValue)) {\n return true;\n }\n return statusValue !== 'sellable' && statusValue !== 'active';\n}\n\n/**\n * Returns `true` when the suggestion option should not allow add-to-cart\n * (out of stock, discontinued, inactive, etc.).\n */\nexport function isCartActionDisabled(\n suggestionOption: Record<string, unknown> | null | undefined,\n): boolean {\n if (!suggestionOption) {\n return true;\n }\n\n const outOfStock =\n suggestionOption['out_of_stock'] ?? suggestionOption['outOfStock'];\n if (outOfStock) {\n return true;\n }\n\n const statusValues = resolveSkuStatusValues(suggestionOption);\n if (statusValues.length === 0) {\n return false;\n }\n\n return statusValues.some(isNonSellableStatusValue);\n}\n\n/**\n * Returns `true` when the suggestion row should be displayed as\n * non-interactive (out-of-stock only — a subset of `isCartActionDisabled`).\n */\nexport function isSuggestionDisabled(\n suggestionOption: Record<string, unknown> | null | undefined,\n): boolean {\n return Boolean(\n !suggestionOption ||\n suggestionOption['out_of_stock'] ||\n suggestionOption['outOfStock'],\n );\n}\n","/**\n * Catalog-product normalization helpers: the data processing for the suggestions list.\n * UI-specific helpers (keyboard handling, ARIA attributes, display data) live in\n * `react-search-components`, because they depend on DOM refs and component props.\n *\n * `resolveSuggestionImageSrc` returns `\"\"` when the source is absent, not a bundled\n * placeholder. Components apply their own `<img onError>` / CSS placeholder; the SDK must not\n * bundle assets.\n */\n\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n ProductType,\n} from '../types';\nimport { isCartActionDisabled } from './catalogStatus';\n\n/* -------------------------------------------------------------------------- */\n/* Image helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Reads the first non-empty image URL from a Contentstack / catalog property\n * bag. Returns `\"\"` when no image is found.\n */\nexport function getImageFromProperty(\n properties: Record<string, unknown> = {},\n): string {\n let image =\n String(properties['primaryimage'] ?? '').trim() ||\n String(properties['imageURL'] ?? '').trim();\n\n if (!image) {\n try {\n const parsed: unknown = JSON.parse(\n String(properties['productImages'] ?? '{}'),\n );\n if (\n Array.isArray(parsed) &&\n parsed[0] &&\n typeof parsed[0] === 'object'\n ) {\n image = String(\n (parsed[0] as Record<string, unknown>)['url'] ?? '',\n ).trim();\n }\n } catch {\n image = '';\n }\n }\n\n return image;\n}\n\n/**\n * Normalizes an image source value. Returns `\"\"` when the source is absent or\n * blank. Components are responsible for applying a fallback placeholder image.\n */\nexport function resolveSuggestionImageSrc(imageSrc: unknown): string {\n const trimmed =\n typeof imageSrc === 'string'\n ? imageSrc.trim()\n : String(imageSrc ?? '').trim();\n return trimmed;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Ingredient terms */\n/* -------------------------------------------------------------------------- */\n\nfunction safeParseJsonArray(value: unknown): unknown[] {\n if (Array.isArray(value)) {\n return value;\n }\n\n if (typeof value !== 'string' || !value.trim()) {\n return [];\n }\n\n try {\n const parsed: unknown = JSON.parse(value);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Extracts a flat list of ingredient terms from a Contentstack ingredient\n * structure. Used to populate `CatalogSuggestionItem.ingredientTerms`.\n */\nexport function getIngredientTerms(rawIngredients: unknown): string[] {\n const ingredientGroups = safeParseJsonArray(rawIngredients);\n\n return ingredientGroups\n .flatMap((ingredientGroup) => {\n if (!ingredientGroup || typeof ingredientGroup !== 'object') {\n return [];\n }\n const group = ingredientGroup as Record<string, unknown>;\n const keyIngredients = Array.isArray(group['keyIngredients'])\n ? (\n group['keyIngredients'] as Array<Record<string, unknown>>\n ).map((ingredient) => ingredient['name'])\n : [];\n\n return [\n group['productName'],\n group['activeIngredients'],\n group['inactiveIngredients'],\n group['allIngredients'],\n group['otherIngredients'],\n ...keyIngredients,\n ];\n })\n .filter(Boolean)\n .map((term) => String(term).trim())\n .filter(Boolean);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Catalog product → suggestion mapping */\n/* -------------------------------------------------------------------------- */\n\nfunction getSkuProperties(product: Record<string, unknown>): {\n defaultSku: Record<string, unknown> | null;\n skuProperties: Record<string, unknown>;\n} {\n const skuList = Array.isArray(product['sku'])\n ? (product['sku'] as Array<Record<string, unknown>>)\n : [];\n const defaultSku =\n skuList.find((skuEntry) => skuEntry?.['default'] === true) ??\n skuList[0] ??\n null;\n return {\n defaultSku: defaultSku ?? null,\n skuProperties:\n ((defaultSku as Record<string, unknown> | null)?.[\n 'properties'\n ] as Record<string, unknown>) ?? {},\n };\n}\n\nfunction getIdentifier(\n product: Record<string, unknown>,\n defaultSku: Record<string, unknown> | null,\n index: number,\n): string {\n return String(\n defaultSku?.['identifier'] ??\n product['identifier'] ??\n `catalog-product-${index}`,\n ).trim();\n}\n\nfunction getDisplayLabel(\n identifier: string,\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): string {\n return String(\n skuProperties['title'] ??\n productProperties['name'] ??\n productProperties['title'] ??\n skuProperties['name'] ??\n identifier,\n );\n}\n\nfunction getTypeData(\n product: Record<string, unknown>,\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): { customProductType: string; isBundle: boolean } {\n const customProductType = String(\n productProperties['customProductType'] ??\n skuProperties['customProductType'] ??\n '',\n ).trim();\n const normalizedType = String(\n product['type'] ??\n productProperties['producttype'] ??\n skuProperties['producttype'] ??\n '',\n )\n .trim()\n .toLowerCase();\n return {\n customProductType,\n isBundle:\n normalizedType === 'bundle' ||\n customProductType.toLowerCase().includes('bundle'),\n };\n}\n\nfunction getNavigationUrls(\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): { navigableUrl: string | null; slug: string | null } {\n const slug =\n String(\n skuProperties['slug'] ?? productProperties['slug'] ?? '',\n ).trim() || null;\n const navigableUrl =\n String(\n skuProperties['url'] ??\n skuProperties['href'] ??\n productProperties['url'] ??\n productProperties['href'] ??\n '',\n ).trim() || null;\n return { navigableUrl, slug };\n}\n\nfunction isOutOfStock(inventoryStatus: unknown): boolean {\n return String(inventoryStatus).toUpperCase() === 'OUT OF STOCK';\n}\n\nfunction getCatalogStatusFields(\n skuProperties: Record<string, unknown>,\n productProperties: Record<string, unknown>,\n): {\n normalizedProductStatus: string;\n normalizedSkuStatus: string;\n outOfStock: boolean;\n cartActionDisabled: boolean;\n} {\n const inventoryStatus =\n skuProperties['inventoryStatus'] ??\n productProperties['inventoryStatus'] ??\n '';\n const productStatus =\n skuProperties['productStatus'] ??\n productProperties['productStatus'] ??\n '';\n const skuStatus =\n skuProperties['status'] ?? productProperties['status'] ?? '';\n const normalizedProductStatus = String(productStatus).trim();\n const normalizedSkuStatus = String(skuStatus).trim();\n const outOfStock = isOutOfStock(inventoryStatus);\n\n return {\n normalizedProductStatus,\n normalizedSkuStatus,\n outOfStock,\n cartActionDisabled: isCartActionDisabled({\n outOfStock,\n productStatus: normalizedProductStatus || undefined,\n status: normalizedSkuStatus || undefined,\n }),\n };\n}\n\nfunction optionalNonEmptyString(value: string): string | undefined {\n const normalized = String(value ?? '').trim();\n return normalized || undefined;\n}\n\nfunction getProductImageSrc(opts: {\n product: Record<string, unknown>;\n productProperties: Record<string, unknown>;\n skuProperties: Record<string, unknown>;\n}): string {\n const normalizedType = String(opts.product['type'] ?? '')\n .trim()\n .toLowerCase();\n\n if (normalizedType === 'kit' || normalizedType === 'bundle') {\n return getImageFromProperty(opts.productProperties);\n }\n\n return getImageFromProperty(opts.skuProperties);\n}\n\n/**\n * Maps a raw Equinox catalog product object to the normalized\n * `CatalogSuggestionItem` shape consumed by the UI components.\n * Returns `null` for invalid input so callers can `.filter(Boolean)`.\n */\nexport function mapCatalogProductToSuggestion(\n product: unknown,\n index: number = 0,\n): CatalogSuggestionItem | null {\n if (!product || typeof product !== 'object') {\n return null;\n }\n\n const p = product as Record<string, unknown>;\n const productProperties =\n (p['properties'] as Record<string, unknown>) ?? {};\n const { defaultSku, skuProperties } = getSkuProperties(p);\n const identifier = getIdentifier(p, defaultSku, index);\n const { customProductType, isBundle } = getTypeData(\n p,\n productProperties,\n skuProperties,\n );\n const { navigableUrl, slug } = getNavigationUrls(\n productProperties,\n skuProperties,\n );\n const statusFields = getCatalogStatusFields(\n skuProperties,\n productProperties,\n );\n const imageSrc = resolveSuggestionImageSrc(\n getProductImageSrc({ product: p, productProperties, skuProperties }),\n );\n const mappedProductType: ProductType = isBundle ? 'bundle' : 'single';\n\n return {\n id: identifier,\n identifier,\n sku: identifier,\n label: getDisplayLabel(identifier, productProperties, skuProperties),\n value: getDisplayLabel(identifier, productProperties, skuProperties),\n imageURL: imageSrc,\n thumbnail: imageSrc,\n productType: mappedProductType,\n product_type: mappedProductType,\n outOfStock: statusFields.outOfStock,\n productStatus: optionalNonEmptyString(\n statusFields.normalizedProductStatus,\n ),\n status: optionalNonEmptyString(statusFields.normalizedSkuStatus),\n cartActionDisabled: statusFields.cartActionDisabled,\n customProductType,\n slug,\n productSlug: slug,\n url: navigableUrl,\n href: navigableUrl,\n keywords: String(\n (productProperties['keyword'] as unknown) ??\n (skuProperties['keyword'] as unknown) ??\n '',\n ),\n ingredientTerms: getIngredientTerms(\n skuProperties['ingredients'] ?? productProperties['ingredients'],\n ),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Did-you-mean normalization */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Normalizes the raw `didYouMean` / `did_you_mean` array from the Equinox\n * API into a consistent shape consumed by `useSearchSuggestions`.\n */\nexport function normalizeDidYouMean(didYouMean: unknown): DidYouMeanItem[] {\n if (!Array.isArray(didYouMean)) {\n return [];\n }\n\n return didYouMean\n .map((item: unknown, index: number): DidYouMeanItem | null => {\n if (typeof item === 'string') {\n return {\n id: `did-you-mean-${index}-${item}`,\n value: item,\n suggestionType: 'did-you-mean',\n };\n }\n\n if (item && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n return {\n ...obj,\n id: String(\n obj['id'] ??\n `did-you-mean-${index}-${obj['value'] ?? obj['label'] ?? ''}`,\n ),\n value: String(obj['value'] ?? ''),\n suggestionType: 'did-you-mean',\n };\n }\n\n return null;\n })\n .filter((item): item is DidYouMeanItem => item !== null);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Suggestion list helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Returns the items that should actually be rendered in the suggestions list.\n * When \"Did You Mean?\" results are present they take precedence over product\n * suggestions.\n */\nexport function getVisibleSuggestions(opts: {\n didYouMean: DidYouMeanItem[];\n suggestions: CatalogSuggestionItem[];\n}): DidYouMeanItem[] | CatalogSuggestionItem[] {\n if (opts.didYouMean.length > 0) {\n return opts.didYouMean;\n }\n return opts.suggestions;\n}\n\n/**\n * Builds the analytics payload emitted when the user clicks \"See More Results\".\n */\nexport function getSeeMoreResultsPayload(\n query: string,\n totalResultsCount: number,\n suggestions: CatalogSuggestionItem[],\n): {\n query: string;\n source: string;\n totalResultsCount: number;\n visibleResultsCount: number;\n} {\n return {\n query,\n source: 'autocomplete-footer',\n totalResultsCount,\n visibleResultsCount: suggestions.length,\n };\n}\n","/**\n * useSearchSuggestions: the typeahead's state.\n * - Requests are debounced by `DEBOUNCE_MS`, and a response that is no longer the latest\n * request is ignored\n * - `MAX_VISIBLE_SUGGESTIONS` caps the products shown\n * - `didYouMean` items take precedence: when present, `suggestions` is `[]`\n * - `emptyFetched` is `true` only when both lists are empty after a fetch, and a failed fetch\n * sets `suggestionFetchFailed` as well\n * - `enabled = false` clears state without calling the API\n *\n * Keyboard navigation and the display-data helpers live in `react-search-components`, because\n * they depend on DOM refs and component props.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { DEBOUNCE_MS, MAX_VISIBLE_SUGGESTIONS } from '../constants';\nimport {\n mapCatalogProductToSuggestion,\n normalizeDidYouMean,\n} from '../utils/catalogHelpers';\nimport type { SearchService } from '../services/SearchApiService';\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n SuggestionsResponse,\n} from '../types';\n\n/** Options accepted by `useSearchSuggestions`. */\nexport interface UseSearchSuggestionsOptions {\n /** The search service `CommerceSearch` creates. */\n service: SearchService;\n /**\n * When `false` the hook clears state and skips all API calls.\n * Useful for suppressing suggestions while the user is typing a question.\n * Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/** State and actions returned by `useSearchSuggestions`. */\nexport interface UseSearchSuggestionsResult {\n /**\n * Resets the query to `\"\"` and clears all suggestions state.\n * Call when the user clicks the Clear button.\n */\n clearQuery: () => void;\n /**\n * `true` after a fetch completes with an empty result set.\n * Use this to show a \"No suggestions\" message.\n */\n emptyFetched: boolean;\n /** `true` when the server has more matches than `MAX_VISIBLE_SUGGESTIONS`. */\n hasMoreResults: boolean;\n /** `true` when the latest suggestions request failed. */\n suggestionFetchFailed: boolean;\n /** Normalized \"Did You Mean?\" items from the API. */\n didYouMean: DidYouMeanItem[];\n /** `true` while a debounced fetch is in flight. */\n loading: boolean;\n /** The current query string (unmodified, as typed by the user). */\n query: string;\n /**\n * The trimmed query the current results (or failure) belong to; `\"\"` until a\n * fetch has finished. Compare with `query.trim()` to know whether the\n * results on screen are for the term the user has typed.\n */\n settledQuery: string;\n /** Normalized product suggestion items from the catalog API. */\n suggestions: CatalogSuggestionItem[];\n /**\n * Preferred setter — updates `query`, optimistically sets `loading`, and\n * clears `emptyFetched` before the debounce fires.\n */\n updateQuery: (query: string) => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Internal normalization */\n/* -------------------------------------------------------------------------- */\n\ninterface NormalizedSuggestions {\n suggestions: CatalogSuggestionItem[];\n didYouMean: DidYouMeanItem[];\n}\n\nfunction normalizeSuggestionsResponse(\n response: SuggestionsResponse | unknown,\n): NormalizedSuggestions {\n // Raw array fallback (some API variants return an array directly)\n if (Array.isArray(response)) {\n return {\n suggestions: response as CatalogSuggestionItem[],\n didYouMean: [],\n };\n }\n\n if (!response || typeof response !== 'object') {\n return { suggestions: [], didYouMean: [] };\n }\n\n const r = response as SuggestionsResponse;\n\n // Equinox catalog API returns a `product` array\n if (Array.isArray(r.product)) {\n return {\n suggestions: (r.product as unknown[])\n .map((product, index) =>\n mapCatalogProductToSuggestion(product, index),\n )\n .filter((item): item is CatalogSuggestionItem => item !== null),\n didYouMean: normalizeDidYouMean(r.didYouMean ?? r.did_you_mean),\n };\n }\n\n // Generic suggestions array fallback\n return {\n suggestions: Array.isArray(r.suggestions)\n ? (r.suggestions as CatalogSuggestionItem[])\n : [],\n didYouMean: normalizeDidYouMean(r.didYouMean),\n };\n}\n\n/** The total the API reports: `totalResultsCount`, else the pageable total, else what came back. */\nfunction resolveTotalResultsCount(\n response: SuggestionsResponse,\n fallback: number,\n): number {\n if (typeof response.totalResultsCount === 'number') {\n return response.totalResultsCount;\n }\n if (typeof response.pageableInfo?.totalCount === 'number') {\n return response.pageableInfo.totalCount;\n }\n return fallback;\n}\n\n/** What the panel shows once a request has finished. */\ninterface SettledResults {\n suggestions: CatalogSuggestionItem[];\n didYouMean: DidYouMeanItem[];\n hasMoreResults: boolean;\n emptyFetched: boolean;\n failed: boolean;\n}\n\n/** A request that failed looks like no results, but says it failed, so a caller can tell. */\nconst FETCH_FAILED: SettledResults = {\n suggestions: [],\n didYouMean: [],\n hasMoreResults: false,\n emptyFetched: true,\n failed: true,\n};\n\n/**\n * What to show for the API's answer. \"Did you mean\" terms replace the products. At most\n * `MAX_VISIBLE_SUGGESTIONS` products show, and there are more when the API says so.\n */\nfunction toSettledResults(response: SuggestionsResponse): SettledResults {\n const { suggestions: allSuggestions, didYouMean } =\n normalizeSuggestionsResponse(response);\n\n if (didYouMean.length > 0) {\n return {\n suggestions: [],\n didYouMean,\n hasMoreResults: false,\n emptyFetched: false,\n failed: false,\n };\n }\n\n const total = Math.max(\n resolveTotalResultsCount(response, allSuggestions.length),\n allSuggestions.length,\n );\n const suggestions = allSuggestions.slice(0, MAX_VISIBLE_SUGGESTIONS);\n return {\n suggestions,\n didYouMean,\n hasMoreResults: total > MAX_VISIBLE_SUGGESTIONS,\n emptyFetched: suggestions.length === 0,\n failed: false,\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Hook */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Manages debounced typeahead suggestions from the Equinox catalog API.\n *\n * @example\n * ```tsx\n * const service = createSearchService({ country, language, getMarketConfig });\n * const { suggestions, didYouMean, loading, updateQuery, clearQuery } =\n * useSearchSuggestions({ service });\n * ```\n */\nexport function useSearchSuggestions({\n service,\n enabled = true,\n}: UseSearchSuggestionsOptions): UseSearchSuggestionsResult {\n const [query, setQuery] = useState('');\n const [suggestions, setSuggestions] = useState<CatalogSuggestionItem[]>([]);\n const [didYouMean, setDidYouMean] = useState<DidYouMeanItem[]>([]);\n const [loading, setLoading] = useState(false);\n const [emptyFetched, setEmptyFetched] = useState(false);\n const [suggestionFetchFailed, setSuggestionFetchFailed] = useState(false);\n const [hasMoreResults, setHasMoreResults] = useState(false);\n const [settledQuery, setSettledQuery] = useState('');\n\n const fetchDebounced = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestRequestId = useRef(0);\n\n const resetSuggestionsState = useCallback(() => {\n setSuggestions([]);\n setDidYouMean([]);\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n setHasMoreResults(false);\n setSettledQuery('');\n setLoading(false);\n }, []);\n\n const updateQuery = useCallback(\n (nextQuery: string) => {\n const hasNextQuery = Boolean(nextQuery.trim());\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n setLoading(enabled && hasNextQuery);\n setQuery(nextQuery);\n },\n [enabled],\n );\n\n const clearQuery = useCallback(() => {\n resetSuggestionsState();\n setQuery('');\n }, [resetSuggestionsState]);\n\n const settle = useCallback((results: SettledResults, term: string) => {\n setDidYouMean(results.didYouMean);\n setSuggestions(results.suggestions);\n setHasMoreResults(results.hasMoreResults);\n setSuggestionFetchFailed(results.failed);\n setSettledQuery(term);\n setEmptyFetched(results.emptyFetched);\n }, []);\n\n const runFetch = useCallback(\n async (nextQuery: string) => {\n const trimmedQuery = nextQuery.trim();\n const requestId = latestRequestId.current;\n\n if (!trimmedQuery || !enabled) {\n resetSuggestionsState();\n return;\n }\n\n setLoading(true);\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n\n let results: SettledResults;\n try {\n results = toSettledResults(\n await service.fetchSuggestions(trimmedQuery),\n );\n } catch (error) {\n console.warn('[search] Could not load suggestions:', error);\n results = FETCH_FAILED;\n }\n\n // Discard a stale answer if a newer request has since been issued.\n if (requestId !== latestRequestId.current) return;\n\n settle(results, trimmedQuery);\n setLoading(false);\n },\n [enabled, service, resetSuggestionsState, settle],\n );\n\n useEffect(() => {\n // Any request still in flight is stale now, whether or not another one follows: when the\n // hook is disabled its late answer must not fill in the results.\n latestRequestId.current += 1;\n\n if (!enabled) {\n resetSuggestionsState();\n return undefined;\n }\n\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n\n fetchDebounced.current = setTimeout(() => {\n void runFetch(query);\n }, DEBOUNCE_MS);\n\n return () => {\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n };\n }, [enabled, query, resetSuggestionsState, runFetch]);\n\n return {\n clearQuery,\n emptyFetched,\n hasMoreResults,\n didYouMean,\n loading,\n query,\n settledQuery,\n suggestionFetchFailed,\n suggestions,\n updateQuery,\n };\n}\n","/**\n * Generic browser helpers shared across SDK utilities.\n * Nothing here should be GTM-specific — keep this file free of tracker logic.\n */\n\nexport const IS_BROWSER = typeof window !== 'undefined';\n\n/**\n * Coerces a value to a trimmed string for use in analytics payloads.\n * Empty / nullish input returns `fallback` (default: single space, matching\n * the placeholder convention the data team specified).\n */\nexport function toEventString(\n value: string | number | undefined | null,\n fallback = ' ',\n): string {\n if (value === undefined || value === null) return fallback;\n const str = String(value).trim();\n return str.length > 0 ? str : fallback;\n}\n","/**\n * GTM (Google Tag Manager) dataLayer tracking for the AI Chat Bot.\n *\n * Implements the events specified in COMX-3277:\n * 1. Begin_chat - user initiates the AI chat from an entry point\n * 2. Search_Type - user submits a query in the AI chat\n * 3. ProductSearch - AI chat returns product results (fires even on 0)\n * 4. Error_popup - API errors / unhandled exceptions during a session\n *\n * The SDK's components call these helpers instead of touching `window.dataLayer` directly, so\n * that payload shape and error handling stay consistent.\n *\n * Types live in `./gtmTypes`, constants in `./gtmConstants`, and generic helpers in\n * `./commonUtils`.\n */\n\nimport { IS_BROWSER, toEventString } from './commonUtils';\nimport {\n GTM_FALLBACK_NA,\n SEARCH_GTM_EVENTS,\n SEARCH_GTM_SEARCH_TYPES,\n SEARCH_GTM_USER_STATUS,\n} from './gtmConstants';\nimport type {\n ErrorPopupEventInput,\n ProductSearchEventInput,\n SearchGtmContext,\n SearchTypeEventInput,\n} from './gtmTypes';\n\n/* -------------------------------------------------------------------------- */\n/* Re-exports so `./gtmTracking` remains the single public entry point */\n/* -------------------------------------------------------------------------- */\n\nexport {\n SEARCH_GTM_EVENTS,\n SEARCH_GTM_SEARCH_TYPES,\n SEARCH_GTM_USER_STATUS,\n} from './gtmConstants';\nexport type {\n ErrorPopupEventInput,\n ProductSearchEventInput,\n SearchGtmContext,\n SearchGtmSearchType,\n SearchGtmUserStatus,\n SearchTypeEventInput,\n} from './gtmTypes';\n\n/** The GTM `id` field: the user id the host supplied, or `'NA'`. */\nfunction resolveUserId(explicit: string | undefined): string {\n return toEventString(explicit, GTM_FALLBACK_NA);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Base payload + dataLayer push */\n/* -------------------------------------------------------------------------- */\n\nfunction baseEventPayload(ctx: SearchGtmContext): Record<string, string> {\n return {\n Chat_ID: toEventString(ctx.chatId, GTM_FALLBACK_NA),\n // TODO: COMX-3277 puts `page_type` in every event but defines no values. Send `NA` until\n // the data team says what it should hold (perhaps the page path).\n page_type: GTM_FALLBACK_NA,\n country_code: toEventString(ctx.countryCode, GTM_FALLBACK_NA),\n language: toEventString(ctx.language, GTM_FALLBACK_NA),\n user_status: toEventString(\n ctx.userStatus ?? SEARCH_GTM_USER_STATUS.GUEST,\n SEARCH_GTM_USER_STATUS.GUEST,\n ),\n account_type: toEventString(ctx.accountType, GTM_FALLBACK_NA),\n };\n}\n\nfunction serializeProductResults(\n productResultsData: unknown,\n productResults?: number,\n): string {\n if (productResultsData !== undefined) {\n try {\n return JSON.stringify(productResultsData);\n } catch {\n return GTM_FALLBACK_NA;\n }\n }\n\n if (productResults === undefined || productResults === null) {\n return GTM_FALLBACK_NA;\n }\n\n return String(productResults);\n}\n\n/**\n * Pushes a raw event object onto `window.dataLayer`.\n *\n * Silently no-ops when `window` is unavailable (SSR) or the dataLayer is\n * missing - GTM tag firing is a best-effort side effect, never a blocker for\n * the search flow.\n */\nexport function pushGtmEvent(event: Record<string, unknown>): void {\n if (!IS_BROWSER) return;\n try {\n const layer = (window.dataLayer ??= []);\n layer.push(event);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.warn('[react-search-sdk] pushGtmEvent failed:', err);\n }\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Event trackers */\n/* -------------------------------------------------------------------------- */\n\n/** Fires `Begin_chat` when the user initiates the AI chat. */\nexport function trackChatEntryPoint(ctx: SearchGtmContext): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.CHAT_ENTRY_POINT,\n ...baseEventPayload(ctx),\n });\n}\n\n/** Fires `Search_Type` when the user submits a query in the AI chat. */\nexport function trackSearchType(input: SearchTypeEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.SEARCH_TYPE,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n search_response: toEventString(input.searchResponse, GTM_FALLBACK_NA),\n });\n}\n\n/**\n * Fires `ProductSearch` when the AI chat returns results.\n * Must be called even when 0 products are returned.\n */\nexport function trackProductSearch(input: ProductSearchEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.PRODUCT_SEARCH,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n search_type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n Product_results: serializeProductResults(\n input.productResultsData,\n input.productResults,\n ),\n });\n}\n\n/** Fires `Error_popup` for API errors and unhandled exceptions during chat. */\nexport function trackErrorPopup(input: ErrorPopupEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.ERROR_POPUP,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n search_type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n });\n}\n","/**\n * Routing between Solr search and the NUi agent.\n *\n * Rule: when the shopper submits a search and the typeahead response for that\n * exact term shows no products, the NUi widget takes over in the same panel.\n * Anything else stays plain search. A pure function, so a smarter intent\n * heuristic can replace it later without touching any UI.\n */\n\nimport type { UseSearchSuggestionsResult } from '../hooks/useSearchSuggestions';\n\n/**\n * - `search` — stay on Solr search (submit behaves as it does today).\n * - `handoff` — hand the query to the NUi agent.\n * - `wait` — the typeahead for this term has not settled yet; ask again when\n * the snapshot changes. Callers should apply their own timeout and\n * fall back to `search`, so a slow request never blocks a submit.\n */\nexport type SearchRoute = 'search' | 'handoff' | 'wait';\n\n/** The slice of `useSearchSuggestions` state the rule reads. */\nexport type RoutingSnapshot = Pick<\n UseSearchSuggestionsResult,\n | 'query'\n | 'loading'\n | 'settledQuery'\n | 'suggestions'\n | 'suggestionFetchFailed'\n>;\n\nexport interface DecideSearchRouteInput {\n /** Whether NUi search is on for this visitor (see `isNuiSearchEnabled`). */\n enabled: boolean;\n snapshot: RoutingSnapshot;\n}\n\n/**\n * Decides what a submitted search does.\n *\n * \"No products\" means the hook has nothing to show for the term. A response\n * that only offers \"did you mean\" terms counts as no products: the hook hides\n * the products in that case, so the shopper sees none either. A failed request\n * is not \"no products\": an outage must not send every shopper to the agent.\n */\nexport function decideSearchRoute({\n enabled,\n snapshot,\n}: DecideSearchRouteInput): SearchRoute {\n const term = snapshot.query.trim();\n if (!enabled || !term) return 'search';\n\n // The results on screen must belong to the term being submitted.\n if (snapshot.loading || snapshot.settledQuery !== term) return 'wait';\n\n if (snapshot.suggestionFetchFailed) return 'search';\n\n return snapshot.suggestions.length > 0 ? 'search' : 'handoff';\n}\n","import { useCallback, useEffect, useRef } from 'react';\nimport { trackChatEntryPoint } from '../utils/gtmTracking';\nimport type { SearchGtmContext } from '../utils/gtmTypes';\nimport { decideSearchRoute } from '../utils/searchRouting';\nimport type { SearchRoute } from '../utils/searchRouting';\nimport type { UseSearchSuggestionsResult } from './useSearchSuggestions';\n\n/** How long a submit waits for the typeahead of that exact term before it stays on search. */\nexport const SUBMIT_WAIT_TIMEOUT_MS = 2000;\n\n/** How the agent starts: what was submitted, and the \"did you mean\" terms Solr offered for it. */\nexport interface AgentHandoff {\n query: string;\n didYouMean: string[];\n}\n\nexport interface UseSubmitRoutingOptions {\n /** Whether a search may reach the agent (see `useNuiAgentGate`). */\n enabled: boolean;\n /** Terms shorter than this were never looked up, so they never hand off to the agent. */\n minimumSearchLength: number;\n /** What the typeahead shows now. */\n search: Pick<\n UseSearchSuggestionsResult,\n | 'didYouMean'\n | 'loading'\n | 'settledQuery'\n | 'suggestionFetchFailed'\n | 'suggestions'\n >;\n gtmContext?: Omit<SearchGtmContext, 'chatId'>;\n /**\n * The term of a submit that is waiting for the typeahead, or `null`. The caller owns it,\n * because it has to forget it when the panel closes.\n */\n pendingTerm: string | null;\n setPendingTerm: (term: string | null) => void;\n /** The search stays plain: take the shopper to the results for `term`. */\n onSearch: (term: string) => void;\n /** The search goes to the agent. */\n onHandoff: (handoff: AgentHandoff) => void;\n}\n\n/**\n * Decides what a submitted search does: plain search, the agent, or wait. A submit that beat the\n * typeahead waits for it to settle and decides again. If it never settles, the shopper gets plain\n * search rather than a stuck panel. Returns the submit handler.\n */\nexport function useSubmitRouting({\n enabled,\n minimumSearchLength,\n search,\n gtmContext,\n pendingTerm,\n setPendingTerm,\n onSearch,\n onHandoff,\n}: UseSubmitRoutingOptions): (value: string) => void {\n const {\n didYouMean,\n loading,\n settledQuery,\n suggestionFetchFailed,\n suggestions,\n } = search;\n\n const decide = useCallback(\n (term: string): SearchRoute =>\n decideSearchRoute({\n enabled,\n snapshot: {\n query: term,\n loading,\n settledQuery,\n suggestions,\n suggestionFetchFailed,\n },\n }),\n [enabled, loading, settledQuery, suggestions, suggestionFetchFailed],\n );\n\n const act = useCallback(\n (term: string, route: SearchRoute) => {\n setPendingTerm(null);\n if (route === 'handoff') {\n trackChatEntryPoint(gtmContext ?? {});\n onHandoff({\n query: term,\n didYouMean: didYouMean.map((item) => item.value),\n });\n return;\n }\n onSearch(term);\n },\n [didYouMean, gtmContext, onHandoff, onSearch, setPendingTerm],\n );\n\n const submit = useCallback(\n (value: string) => {\n const term = value.trim();\n if (!term) return;\n // Too short for the typeahead to have looked: plain search, never the agent.\n if (term.length < minimumSearchLength) {\n onSearch(term);\n return;\n }\n const route = decide(term);\n if (route === 'wait') {\n setPendingTerm(term);\n return;\n }\n act(term, route);\n },\n [act, decide, minimumSearchLength, onSearch, setPendingTerm],\n );\n\n // The waiting effect below runs after this one, in the same commit, so it sees the latest.\n const latest = useRef({ act, decide });\n useEffect(() => {\n latest.current = { act, decide };\n });\n\n useEffect(() => {\n if (pendingTerm === null) return undefined;\n const route = latest.current.decide(pendingTerm);\n if (route !== 'wait') {\n latest.current.act(pendingTerm, route);\n return undefined;\n }\n const timer = setTimeout(\n () => latest.current.act(pendingTerm, 'search'),\n SUBMIT_WAIT_TIMEOUT_MS,\n );\n return () => clearTimeout(timer);\n }, [\n pendingTerm,\n loading,\n settledQuery,\n suggestions,\n suggestionFetchFailed,\n ]);\n\n return submit;\n}\n","import type { ProductClient, ProductData } from '@nuskin/react-product-sdk';\n\n/**\n * Remembers each product lookup for the life of the client, in flight or settled, failures\n * included. The widget re-creates its product cards whenever the conversation re-renders, and a\n * card looks its product up each time it is created: without this, one conversation turns into\n * dozens of identical requests and every card flashes empty while it waits for its own.\n */\nexport function withProductCache(client: ProductClient): ProductClient {\n const lookups = new Map<string, Promise<ProductData | null>>();\n\n return {\n getProductById(productId) {\n let lookup = lookups.get(productId);\n if (!lookup) {\n lookup = client.getProductById(productId);\n lookups.set(productId, lookup);\n }\n return lookup;\n },\n getProductsByIds: (productIds) => client.getProductsByIds(productIds),\n };\n}\n","import styled from '@emotion/styled';\n\n/**\n * The slot every product card sits in: the same width for all of them, so a row looks even\n * whatever the size of its product's image.\n */\nexport const AgentProductSlot = styled.div`\n && {\n flex: 0 0 240px;\n overflow: hidden;\n width: 240px;\n }\n`;\n","import { Component, useEffect, useMemo, useRef } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SalesAIChatWidget } from '@nuskin/react-nui-chat-sdk';\nimport type { SalesAIChatWidgetProps } from '@nuskin/react-nui-chat-sdk';\nimport '@nuskin/react-nui-chat-sdk/styles.css';\nimport {\n ProductCard,\n ProductProvider,\n createProductClient,\n useProductById,\n} from '@nuskin/react-product-sdk';\nimport type { ProductClientConfig } from '@nuskin/react-product-sdk';\nimport { withProductCache } from '../../utils/cachedProductClient';\nimport { AgentProductSlot } from './NuiAgentPanel.styled';\n\n/** How often to look for the widget's `window.SalesAI` handle while it starts. */\nconst HANDLE_POLL_MS = 50;\n/** How long to wait for the widget to register its handle before giving up and falling back to plain search. */\nconst HANDLE_TIMEOUT_MS = 15000;\n\n/** Where the agent's product cards are looked up: the product SDK's environment, market and language. */\nexport type AgentProductsConfig = Pick<\n ProductClientConfig,\n 'environment' | 'market' | 'language'\n>;\n\ninterface AgentWidgetProps {\n widgetProps: SalesAIChatWidgetProps;\n products?: AgentProductsConfig;\n}\n\n/**\n * The product SDK's card in a slot of the same width for every product, whatever the size of its\n * image. A product that cannot be shown (not found, failed, or with nowhere to link to) leaves no\n * gap. Defined once, at module level: the widget remounts a card whose component type changes, and\n * a remounted card would look its product up again.\n */\nfunction AgentProductCard({ sku }: Readonly<{ sku: string }>) {\n const { product, isLoading, error } = useProductById(sku);\n if (!isLoading && (error || !product?.seoInformation?.canonicalURL)) {\n return null;\n }\n return (\n <AgentProductSlot>\n <ProductCard productId={sku} />\n </AgentProductSlot>\n );\n}\n\nconst renderAgentProduct: NonNullable<\n SalesAIChatWidgetProps['renderProduct']\n> = (product) => <AgentProductCard sku={product.sku} />;\n\n/**\n * The NUi widget. With `products`, the product SDK draws the agent's product cards (looked up by\n * the SKU the agent sends) in place of the widget's own.\n */\nfunction AgentWidget({\n widgetProps,\n products,\n}: Readonly<AgentWidgetProps>): ReactElement {\n const environment = products?.environment;\n const market = products?.market;\n const language = products?.language;\n const client = useMemo(\n () =>\n environment && market && language\n ? withProductCache(\n createProductClient({ environment, market, language }),\n )\n : undefined,\n [environment, market, language],\n );\n\n if (!client) {\n return <SalesAIChatWidget {...widgetProps} />;\n }\n return (\n <ProductProvider client={client}>\n <SalesAIChatWidget\n renderProduct={renderAgentProduct}\n {...widgetProps}\n />\n </ProductProvider>\n );\n}\n\n/** The imperative handle the widget registers on `window` (see the widget's `open` options). */\ninterface SalesAIHandle {\n open: (options?: {\n query?: string;\n context?: Record<string, unknown> | null;\n }) => void;\n}\n\nfunction getSalesAIHandle(): SalesAIHandle | undefined {\n return (window as Window & { SalesAI?: SalesAIHandle }).SalesAI;\n}\n\n/** How the host's NUi app is reached and presented. */\nexport interface NuiAgentConfig {\n /** The NUi app key for the search surface. */\n appKey: string;\n /** Origin of the NUi API. */\n apiBaseUrl: string;\n /** UI language, e.g. `en-US`. */\n language?: string;\n /** Widget theme. Defaults to `nui-light`. */\n theme?: SalesAIChatWidgetProps['theme'];\n /** Context sent with every turn of the conversation, under the handoff context. */\n context?: Record<string, unknown>;\n}\n\nexport interface NuiAgentPanelProps {\n agent: NuiAgentConfig;\n /** The search the shopper submitted; sent to the agent as the first message. */\n query: string;\n /** Describes how the conversation started; layered over `agent.context`. */\n handoffContext: Record<string, unknown>;\n /** Draws the agent's product recommendations with the product SDK's cards. Absent: the widget's own. */\n products?: AgentProductsConfig;\n /** Called when the agent cannot be shown, so the host can fall back to plain search. */\n onUnavailable: () => void;\n}\n\ninterface BoundaryProps {\n children: ReactNode;\n onError: () => void;\n}\n\n/** Turns a failure to load or render the widget into a fallback instead of a broken panel. */\nclass AgentErrorBoundary extends Component<BoundaryProps, { failed: boolean }> {\n override state = { failed: false };\n\n static getDerivedStateFromError() {\n return { failed: true };\n }\n\n override componentDidCatch(error: Error) {\n console.warn('[search] The agent could not be shown:', error);\n this.props.onError();\n }\n\n override render() {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/** Hands the submitted query to the widget once its handle is available. */\nfunction useHandoff({\n query,\n handoffContext,\n agentContext,\n onUnavailable,\n}: {\n query: string;\n handoffContext: Record<string, unknown>;\n agentContext: Record<string, unknown> | undefined;\n onUnavailable: () => void;\n}) {\n // The fallback runs up to `HANDLE_TIMEOUT_MS` after the handoff starts: use the latest one.\n const onUnavailableRef = useRef(onUnavailable);\n useEffect(() => {\n onUnavailableRef.current = onUnavailable;\n });\n\n useEffect(() => {\n let canceled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const startedAt = Date.now();\n\n const tryOpen = () => {\n if (canceled) return;\n const handle = getSalesAIHandle();\n if (handle) {\n handle.open({\n query,\n context: { ...agentContext, ...handoffContext },\n });\n return;\n }\n if (Date.now() - startedAt >= HANDLE_TIMEOUT_MS) {\n console.warn(\n `[search] The agent did not start within ${HANDLE_TIMEOUT_MS / 1000} seconds.`,\n );\n onUnavailableRef.current();\n return;\n }\n timer = setTimeout(tryOpen, HANDLE_POLL_MS);\n };\n\n tryOpen();\n return () => {\n canceled = true;\n if (timer !== undefined) clearTimeout(timer);\n };\n // The handoff happens once per submitted query.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [query]);\n}\n\n/** The NUi widget, mounted in the search panel and handed the shopper's query. */\nexport function NuiAgentPanel({\n agent,\n query,\n handoffContext,\n products,\n onUnavailable,\n}: Readonly<NuiAgentPanelProps>): ReactElement {\n useHandoff({\n query,\n handoffContext,\n agentContext: agent.context,\n onUnavailable,\n });\n\n const widgetProps: SalesAIChatWidgetProps = {\n appKey: agent.appKey,\n apiBaseUrl: agent.apiBaseUrl,\n theme: agent.theme ?? 'nui-light',\n defaultOpen: true,\n hideFab: true,\n placement: 'host',\n ...(agent.language === undefined ? {} : { language: agent.language }),\n };\n\n return (\n <AgentErrorBoundary onError={onUnavailable}>\n <AgentWidget\n widgetProps={widgetProps}\n {...(products ? { products } : {})}\n />\n </AgentErrorBoundary>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchPanel } from '@nuskin/react-search-components';\nimport type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { useNuiAgentGate } from '../../hooks/useNuiAgentGate';\nimport { useRecentSearches } from '../../hooks/useRecentSearches';\nimport { useSearchSuggestions } from '../../hooks/useSearchSuggestions';\nimport { useSubmitRouting } from '../../hooks/useSubmitRouting';\nimport type { AgentHandoff } from '../../hooks/useSubmitRouting';\nimport type { SearchService } from '../../services/SearchApiService';\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n SuggestionOption,\n} from '../../types';\nimport { getVisibleSuggestions } from '../../utils/catalogHelpers';\nimport { isSuggestionDisabled } from '../../utils/catalogStatus';\nimport { MINIMUM_SEARCH_CHAR_LENGTH } from '../../constants';\nimport { SEARCH_GTM_SEARCH_TYPES } from '../../utils/gtmConstants';\nimport { trackProductSearch } from '../../utils/gtmTracking';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport { NuiAgentPanel } from './NuiAgentPanel';\nimport type { AgentProductsConfig, NuiAgentConfig } from './NuiAgentPanel';\n\n/** A row the modal shows: a product, or a \"did you mean\" term. */\ntype VisibleSuggestion = CatalogSuggestionItem | DidYouMeanItem;\n\nexport interface CommerceSearchViewProps {\n isOpen: boolean;\n onClose: () => void;\n /** From `createSearchService`. Keep its identity stable (memoize it). */\n service: SearchService;\n /** Takes the shopper to a path, using the host's router. The panel closes afterwards. */\n navigate: (path: string) => void;\n /** Whether the visitor is signed in (the storefront's `customerData.isAuthenticated`). */\n isAuthenticated: boolean;\n /** The NUi app the agent runs on. Without it the agent never shows and search stays plain. */\n agent?: NuiAgentConfig;\n /** Lets a visitor who is not signed in reach the agent. Defaults to false. */\n allowGuestAgent?: boolean;\n /** Draws the agent's product recommendations with the product SDK's cards. Absent: the widget's own. */\n agentProducts?: AgentProductsConfig;\n /** All of the panel's text, already loaded. */\n copy: SearchPanelCopy;\n logo?: ReactNode;\n /**\n * Terms shorter than this never hand off to the agent. Keep it equal to the\n * `minimumSearchLength` the `service` was created with. Defaults to\n * `MINIMUM_SEARCH_CHAR_LENGTH`.\n */\n minimumSearchLength?: number;\n /** Host-known values for the search analytics events. */\n gtmContext?: Omit<SearchGtmContext, 'chatId'>;\n}\n\n/**\n * Product search with an agent fallback, for a `service` and `agent` the caller already has.\n * `CommerceSearch` is the entry point that reads the configuration and builds them.\n *\n * Shows Solr typeahead and recent searches in the library's `SearchPanel`. When a signed-in\n * shopper (or any shopper, if `allowGuestAgent` is set) submits a term whose typeahead shows no\n * products, the NUi agent takes over in the same panel with that term as the first message.\n * Everything else behaves as plain search.\n */\nexport function CommerceSearchView({\n copy,\n isOpen,\n onClose,\n service,\n navigate,\n isAuthenticated,\n agent,\n allowGuestAgent = false,\n agentProducts,\n logo,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n gtmContext,\n}: Readonly<CommerceSearchViewProps>): ReactElement {\n // The view owns these two, not `useSubmitRouting`: the typeahead is switched off during an\n // agent session, so it needs `agentQuery` before routing can read what the typeahead shows.\n const [handoff, setHandoff] = useState<AgentHandoff | null>(null);\n const agentQuery = handoff?.query ?? null;\n const [pendingTerm, setPendingTerm] = useState<string | null>(null);\n\n const search = useSearchSuggestions({\n service,\n enabled: isOpen && agentQuery === null,\n });\n const {\n clearQuery,\n didYouMean,\n emptyFetched,\n hasMoreResults,\n loading,\n query,\n suggestions,\n updateQuery,\n } = search;\n\n const agentEnabled = useNuiAgentGate({\n hasAgent: agent !== undefined,\n isOpen,\n isAuthenticated,\n allowGuestAgent,\n });\n const { recentSearches, clearRecentSearches } = useRecentSearches({\n service,\n isOpen,\n refreshKey: agentQuery,\n });\n const items = getVisibleSuggestions({\n didYouMean,\n suggestions,\n });\n const showDidYouMean = didYouMean.length > 0;\n\n const close = useCallback(() => {\n setHandoff(null);\n setPendingTerm(null);\n clearQuery();\n onClose();\n }, [clearQuery, onClose]);\n\n // The host can also close the panel from outside.\n useEffect(() => {\n if (!isOpen) {\n setHandoff(null);\n setPendingTerm(null);\n clearQuery();\n }\n }, [isOpen, clearQuery]);\n\n /** Navigates and closes. */\n const navigateTo = useCallback(\n (path: string | undefined) => {\n if (!path) return;\n navigate(path);\n close();\n },\n [navigate, close],\n );\n\n const trackSemantic = useCallback(\n (productResultsData: unknown) => {\n trackProductSearch({\n ...gtmContext,\n searchType: SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n productResultsData,\n });\n },\n [gtmContext],\n );\n\n const runSearch = useCallback(\n (term: string) => {\n trackSemantic(items.length > 0 ? items : { query: term });\n navigateTo(service.submitProductSearch(term));\n },\n [items, navigateTo, service, trackSemantic],\n );\n\n const handleSubmit = useSubmitRouting({\n enabled: agentEnabled,\n minimumSearchLength,\n search,\n ...(gtmContext ? { gtmContext } : {}),\n pendingTerm,\n setPendingTerm,\n onSearch: runSearch,\n onHandoff: setHandoff,\n });\n\n const handleSelect = useCallback(\n (option: VisibleSuggestion) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n const term = String(option['value'] ?? option['label'] ?? '');\n if (term.trim()) trackSemantic([option]);\n\n const suggestionOption = option as unknown as SuggestionOption;\n const href = service.getSuggestionHref(suggestionOption);\n navigateTo(\n href || service.submitProductSearch(term, suggestionOption),\n );\n },\n [navigateTo, service, trackSemantic],\n );\n\n const handleRunAction = useCallback(\n (option: VisibleSuggestion) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n navigateTo(\n service.activateSuggestionAction(\n option as unknown as SuggestionOption,\n ),\n );\n },\n [navigateTo, service],\n );\n\n const handleSeeMore = useCallback(() => {\n const term = query.trim();\n if (term) navigateTo(service.viewMoreResults({ query: term }));\n }, [navigateTo, query, service]);\n\n const handleRecentSelect = useCallback(\n (recentQuery: string) => {\n trackSemantic({ query: recentQuery });\n navigateTo(service.submitProductSearch(recentQuery));\n },\n [navigateTo, service, trackSemantic],\n );\n\n // The agent could not be shown: give the shopper the search they asked for.\n const handleAgentUnavailable = useCallback(() => {\n if (agentQuery !== null)\n navigateTo(service.submitProductSearch(agentQuery));\n }, [agentQuery, navigateTo, service]);\n\n // Built here, not inline, so no ternary nests in another (Sonar S3358).\n let agentPanel: ReactElement | undefined;\n if (handoff !== null && agent !== undefined) {\n agentPanel = (\n <NuiAgentPanel\n agent={agent}\n query={handoff.query}\n handoffContext={{\n source: 'storefront_search',\n trigger: 'zero_results',\n query: handoff.query,\n did_you_mean: handoff.didYouMean,\n }}\n {...(agentProducts ? { products: agentProducts } : {})}\n onUnavailable={handleAgentUnavailable}\n />\n );\n }\n\n return (\n <SearchPanel\n isOpen={isOpen}\n onClose={close}\n copy={copy}\n logo={logo}\n input={{\n value: query,\n onChange: updateQuery,\n onSubmit: handleSubmit,\n }}\n suggestions={{\n items,\n loading,\n showNoResults: !loading && emptyFetched && items.length === 0,\n showDidYouMean,\n hasMore: hasMoreResults,\n query,\n onSelect: handleSelect,\n onRunAction: handleRunAction,\n onSeeMore: handleSeeMore,\n }}\n recentSearches={{\n items: recentSearches,\n onSelect: handleRecentSelect,\n onClear: clearRecentSearches,\n }}\n agentPanel={agentPanel}\n />\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { useCommerceSearchConfig } from '../../hooks/useCommerceSearchConfig';\nimport { useSearchPanelCopy } from '../../hooks/useSearchPanelCopy';\nimport { createSearchService } from '../../services/SearchApiService';\nimport { isValidMarket } from '../../services/localeParts';\nimport { fetchMarketConfig } from '../../services/marketConfig';\nimport { SEARCH_GTM_USER_STATUS } from '../../utils/gtmConstants';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport { toNavigationTarget } from '../../utils/navigationTarget';\nimport type { NavigationTarget } from '../../utils/navigationTarget';\nimport { getProductEnvironment } from '../../utils/productEnvironment';\nimport { CommerceSearchUnavailable } from './CommerceSearchUnavailable';\nimport { CommerceSearchView } from './CommerceSearchView';\nimport type { AgentProductsConfig } from './NuiAgentPanel';\n\n/**\n * The account types the suggestions API distinguishes, sent as `X-Customer-Type`.\n *\n * TODO: PA-1254 validates this set, which is a best guess from the values the storefront sends,\n * against the storefront's customer types and what the suggestions API accepts.\n */\nexport type CustomerAccountType =\n | 'guest'\n | 'Brand Affiliate'\n | 'Retail Customer'\n | 'Preferred Customer/Member';\n\n/** Who is searching. */\nexport interface CommerceSearchCustomer {\n /**\n * Whether the visitor is signed in. The NUi agent is for signed-in visitors only, unless the\n * package's configuration allows guests.\n */\n isAuthenticated: boolean;\n /** Defaults to `guest`. Ignored for a visitor who is not signed in. */\n accountType?: CustomerAccountType;\n /** The signed-in visitor's id, for analytics. */\n userId?: string;\n}\n\nexport interface CommerceSearchProps {\n isOpen: boolean;\n onClose: () => void;\n /**\n * Takes the shopper to a destination, using the host's router for an internal path and a\n * full page load for an external URL. The panel closes afterwards.\n */\n navigate: (target: NavigationTarget) => void;\n /** Read on every request, so a change after sign-in is picked up. */\n customer: CommerceSearchCustomer;\n /** ISO 3166-1 alpha-2 market, for example `US`. */\n country: string;\n /** ISO 639-1 language, for example `en`. */\n language: string;\n /** Shown at the top of the panel, for example the brand logo. */\n logo?: ReactNode;\n}\n\nconst GUEST: CustomerAccountType = 'guest';\n\n/**\n * The commerce website's single search entry point: typeahead and recent searches over the\n * product catalog today, with the NUi agent taking over in the same panel when a signed-in\n * shopper (guests too, where the configuration allows it) searches for something with no products. What it can answer is not limited to\n * products — it is the commerce site's search, not a product-only search box.\n *\n * The package works out the rest itself: the market's catalog lookup, the minimum search length,\n * which NUi app to use, the panel's text and the analytics fields.\n */\nexport function CommerceSearch(\n props: Readonly<CommerceSearchProps>,\n): ReactElement | null {\n // Checked before anything starts, so a market that is not valid makes no request and loads no\n // market's configuration.\n if (!isValidMarket(props.country, props.language)) {\n return (\n <CommerceSearchUnavailable\n isOpen={props.isOpen}\n onClose={props.onClose}\n country={props.country}\n language={props.language}\n logo={props.logo}\n />\n );\n }\n return <ValidMarketSearch {...props} />;\n}\n\nfunction ValidMarketSearch({\n isOpen,\n onClose,\n navigate,\n customer,\n country,\n language,\n logo,\n}: Readonly<CommerceSearchProps>): ReactElement | null {\n const [hasOpened, setHasOpened] = useState(false);\n useEffect(() => {\n if (isOpen) setHasOpened(true);\n }, [isOpen]);\n\n // Starts when the host mounts the search, not when the panel opens, so the text is ready by then.\n const copy = useSearchPanelCopy({ language });\n\n const { minimumSearchLength, agent, allowGuestAgent } =\n useCommerceSearchConfig({\n country,\n language,\n enabled: hasOpened,\n });\n\n // Read per request, so a change of customer does not rebuild the service.\n const customerType: CustomerAccountType = customer.isAuthenticated\n ? (customer.accountType ?? GUEST)\n : GUEST;\n const customerTypeRef = useRef<CustomerAccountType>(customerType);\n useEffect(() => {\n customerTypeRef.current = customerType;\n }, [customerType]);\n\n const service = useMemo(\n () =>\n createSearchService({\n country,\n language,\n getMarketConfig: fetchMarketConfig,\n minimumSearchLength,\n getCustomerType: () => customerTypeRef.current,\n }),\n [country, language, minimumSearchLength],\n );\n\n const navigateToPath = useCallback(\n (path: string) => {\n const target = toNavigationTarget(path);\n if (target) {\n navigate(target);\n } else {\n console.warn(\n '[search] Not navigating to a path the SDK does not recognize:',\n path,\n );\n }\n },\n [navigate],\n );\n\n const { isAuthenticated, accountType, userId } = customer;\n const gtmContext = useMemo<Omit<SearchGtmContext, 'chatId'>>(\n () => ({\n countryCode: country,\n language,\n userStatus: isAuthenticated\n ? SEARCH_GTM_USER_STATUS.LOGGED_IN\n : SEARCH_GTM_USER_STATUS.GUEST,\n ...(isAuthenticated && accountType ? { accountType } : {}),\n ...(isAuthenticated && userId ? { userId } : {}),\n }),\n [country, language, isAuthenticated, accountType, userId],\n );\n\n // Where the agent's product cards are looked up. No product environment, no product SDK cards.\n const agentProducts = useMemo<AgentProductsConfig | undefined>(() => {\n const environment = getProductEnvironment();\n return environment\n ? {\n environment,\n market: country.toUpperCase(),\n language: language.toLowerCase(),\n }\n : undefined;\n }, [country, language]);\n\n // The panel has no text of its own, so it waits for the text.\n if (!copy) return null;\n\n return (\n <CommerceSearchView\n isOpen={isOpen}\n onClose={onClose}\n service={service}\n navigate={navigateToPath}\n isAuthenticated={isAuthenticated}\n {...(agent ? { agent } : {})}\n {...(allowGuestAgent ? { allowGuestAgent } : {})}\n {...(agentProducts ? { agentProducts } : {})}\n copy={copy}\n logo={logo}\n minimumSearchLength={minimumSearchLength}\n gtmContext={gtmContext}\n />\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/config/configurationSdk.ts","../src/constants.ts","../src/config/commerceSearchConfig.ts","../src/hooks/useCommerceSearchConfig.ts","../src/copy/searchPanelCopy.ts","../src/copy/fetchSearchPanelCopy.ts","../src/copy/loadSearchPanelCopy.ts","../src/hooks/useSearchPanelCopy.ts","../src/services/localeParts.ts","../src/services/catalogRequest.ts","../src/services/recentSearches.ts","../src/services/searchPaths.ts","../src/services/suggestionsPayload.ts","../src/services/SearchApiService.ts","../src/services/marketConfig.ts","../src/utils/gtmConstants.ts","../src/utils/navigationTarget.ts","../src/utils/productEnvironment.ts","../src/components/CommerceSearch/CommerceSearchUnavailable.tsx","../src/utils/nuiSearchGate.ts","../src/hooks/useNuiAgentGate.ts","../src/hooks/useRecentSearches.ts","../src/utils/catalogStatus.ts","../src/utils/catalogHelpers.ts","../src/hooks/useSearchSuggestions.ts","../src/utils/commonUtils.ts","../src/utils/gtmTracking.ts","../src/utils/searchRouting.ts","../src/hooks/useSubmitRouting.ts","../src/utils/cachedProductClient.ts","../src/components/CommerceSearch/NuiAgentPanel.styled.tsx","../src/components/CommerceSearch/NuiAgentPanel.tsx","../src/components/CommerceSearch/CommerceSearchView.tsx","../src/components/CommerceSearch/CommerceSearch.tsx"],"names":["useState","useEffect","resolveTotalResultsCount","useRef","useCallback","jsx","SearchPanel","useMemo"],"mappings":"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","file":"index.mjs","sourcesContent":["import configurationSdk from '@nuskin/configuration-sdk';\n\n/**\n * `@nuskin/configuration-sdk` is CommonJS. Node's ESM loader cannot see all of its named exports\n * (`getEnvironmentCode` is missed), so import the default and read the functions off it.\n */\nexport const { getConfiguration, getEnvironmentCode } = configurationSdk;\n","/** Constants for the search SDK. */\n\n/** API shopping-context segment used when resolving the Equinox gateway URL. */\nexport const STOREFRONT_SHOPPING_CONTEXT = 'storefront';\n\n/** Catalog suggestions path appended when the market gateway is not already\n * under the storefront shopping context. */\nexport const CATALOG_SUGGESTIONS_PATH =\n '/storefront/catalogs/search/suggestions';\n\n/** Prefix for the `sessionStorage` key that persists recent searches.\n * Full key format: `${RECENT_SEARCHES_PREFIX}:{locale}:{COUNTRY}:{lang}`.\n * Must not change — existing sessions rely on this key. */\nexport const RECENT_SEARCHES_PREFIX = 'nuskin:header:recentSearches';\n\n/** Maximum number of recent searches persisted per locale bucket. */\nexport const RECENT_SEARCHES_DEFAULT_LIMIT = 10;\n\n/** Equinox suggestion pagination — page is 1-indexed. */\nexport const DEFAULT_SUGGESTION_PAGE = 1;\n\n/** Segment used when building the fallback search-results URL. */\nexport const DEFAULT_SEARCH_PATH = '/search';\n\n/** Debounce for typeahead input → API dispatch. */\nexport const DEBOUNCE_MS = 220;\n\n/** Terms shorter than this are not sent to the suggestions API, unless the configuration says otherwise. */\nexport const MINIMUM_SEARCH_CHAR_LENGTH = 2;\n\n/**\n * How many suggestions the typeahead asks the catalog for, and shows, unless the configuration\n * says otherwise.\n */\nexport const DEFAULT_MAX_SUGGESTIONS = 6;\n\n/** The most the suggestions API accepts for one request. A larger configured value is lowered to this. */\nexport const MAX_SUGGESTIONS_CEILING = 20;\n\n/** The configuration map holding each market's API gateway and store. */\nexport const EQUINOX_MARKETS_MAP = 'Equinox_Markets';\n\n/** The configuration map holding the product search's own settings. */\nexport const COMMERCE_SEARCH_MAP = 'Commerce_Search';\n","import { getConfiguration } from './configurationSdk';\nimport {\n COMMERCE_SEARCH_MAP,\n DEFAULT_MAX_SUGGESTIONS,\n MAX_SUGGESTIONS_CEILING,\n MINIMUM_SEARCH_CHAR_LENGTH,\n} from '../constants';\n\n/**\n * Everything about the product search that is meant to be configuration, in one place, behind\n * one async reader. `fetchCommerceSearchConfig` is the only function that knows where the values\n * come from: the `Commerce_Search` configuration map, read through the Configuration SDK, which\n * resolves the environment, shopping context and per-market inheritance itself.\n */\n\n/** The NUi app the search can hand off to. */\nexport interface CommerceSearchAgentConfig {\n appKey: string;\n apiBaseUrl: string;\n /** UI language, taken from the market the config was read for. */\n language?: string;\n}\n\n/** Which kinds of customer the agent is switched on for. All off unless the map says otherwise. */\nexport interface AgentEnabledFor {\n guest: boolean;\n brandAffiliate: boolean;\n preferredCustomer: boolean;\n retailCustomer: boolean;\n}\n\n/**\n * What the search does, as read from the configuration:\n * - `minimumSearchLength`: characters a term needs before the typeahead looks it up\n * - `maxSuggestions`: suggestions asked for and shown, never more than the suggestions API allows\n * - `agent`: the NUi app to hand off to; absent means plain search only\n * - `agentEnabledFor`: which kinds of customer the agent is on for\n */\nexport interface CommerceSearchConfig {\n minimumSearchLength: number;\n maxSuggestions: number;\n agent?: CommerceSearchAgentConfig;\n agentEnabledFor: AgentEnabledFor;\n}\n\nexport interface FetchCommerceSearchConfigOptions {\n country: string;\n language?: string;\n /** The host's client id for the configuration service. Absent: the configuration SDK's own. */\n clientId?: string;\n}\n\n/** Plain search with the package's own settings: what the search does when it has no configuration. */\nexport const COMMERCE_SEARCH_CONFIG_DEFAULTS: Readonly<CommerceSearchConfig> =\n Object.freeze({\n minimumSearchLength: MINIMUM_SEARCH_CHAR_LENGTH,\n maxSuggestions: DEFAULT_MAX_SUGGESTIONS,\n agentEnabledFor: Object.freeze({\n guest: false,\n brandAffiliate: false,\n preferredCustomer: false,\n retailCustomer: false,\n }),\n });\n\n/** The fields of the `Commerce_Search` map. The service returns them flat. */\nconst FIELDS = {\n minimumLength: 'commerceSearchMinimumLength',\n maxSuggestions: 'commerceSearchMaxSuggestions',\n agentAppKey: 'commerceSearchAgentAppKey',\n agentApiBaseUrl: 'commerceSearchAgentApiBaseUrl',\n enabledGuest: 'commerceSearchAgentEnabledGuest',\n enabledBrandAffiliate: 'commerceSearchAgentEnabledBrandAffiliate',\n enabledPreferredCustomer: 'commerceSearchAgentEnabledPreferredCustomer',\n enabledRetailCustomer: 'commerceSearchAgentEnabledRetailCustomer',\n} as const;\n\ntype RawCommerceSearch = Readonly<Record<string, unknown>>;\n\nfunction nonEmptyString(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\n/**\n * A whole number from a number or a numeric string (the service returns numbers as strings), or\n * `undefined` for anything else.\n */\nfunction wholeNumber(value: unknown): number | undefined {\n const number =\n typeof value === 'string' && value.trim() !== ''\n ? Number(value)\n : value;\n return typeof number === 'number' && Number.isInteger(number)\n ? number\n : undefined;\n}\n\n/** Whole and at least 1, or `undefined`. */\nfunction positiveWholeNumber(value: unknown): number | undefined {\n const number = wholeNumber(value);\n return number !== undefined && number >= 1 ? number : undefined;\n}\n\n/**\n * Turns whatever the service returned into a safe configuration: anything missing or malformed\n * falls back to the default, the number of suggestions is held to what the API accepts, a flag\n * is on only when it is exactly `true`, and the agent is dropped unless it is complete.\n */\nexport function normalizeCommerceSearchConfig(\n raw?: RawCommerceSearch | null,\n { language }: { language?: string } = {},\n): CommerceSearchConfig {\n const appKey = nonEmptyString(raw?.[FIELDS.agentAppKey]);\n const apiBaseUrl = nonEmptyString(raw?.[FIELDS.agentApiBaseUrl]);\n const maxSuggestions = positiveWholeNumber(raw?.[FIELDS.maxSuggestions]);\n\n return {\n minimumSearchLength:\n positiveWholeNumber(raw?.[FIELDS.minimumLength]) ??\n COMMERCE_SEARCH_CONFIG_DEFAULTS.minimumSearchLength,\n maxSuggestions:\n maxSuggestions === undefined\n ? COMMERCE_SEARCH_CONFIG_DEFAULTS.maxSuggestions\n : Math.min(maxSuggestions, MAX_SUGGESTIONS_CEILING),\n ...(appKey && apiBaseUrl\n ? {\n agent: {\n appKey,\n apiBaseUrl,\n ...(language ? { language } : {}),\n },\n }\n : {}),\n agentEnabledFor: {\n guest: raw?.[FIELDS.enabledGuest] === true,\n brandAffiliate: raw?.[FIELDS.enabledBrandAffiliate] === true,\n preferredCustomer: raw?.[FIELDS.enabledPreferredCustomer] === true,\n retailCustomer: raw?.[FIELDS.enabledRetailCustomer] === true,\n },\n };\n}\n\n/**\n * Reads the product search configuration for a market. Fails when the read fails and when the\n * service has no `Commerce_Search` map for the market (an unpublished entry), so that the caller\n * can try again later and never mistakes \"nothing configured\" for \"configured to nothing\".\n */\nexport async function fetchCommerceSearchConfig({\n country,\n language,\n clientId,\n}: FetchCommerceSearchConfigOptions): Promise<CommerceSearchConfig> {\n const configuration = await getConfiguration([COMMERCE_SEARCH_MAP], {\n country: country.trim().toUpperCase(),\n ...(clientId ? { clientId } : {}),\n });\n const raw = configuration?.[COMMERCE_SEARCH_MAP] as\n RawCommerceSearch | undefined;\n\n if (!raw || Object.keys(raw).length === 0) {\n throw new Error(\n `the configuration service returned no ${COMMERCE_SEARCH_MAP} for market ${country}`,\n );\n }\n\n const hasKey = nonEmptyString(raw[FIELDS.agentAppKey]) !== '';\n const hasUrl = nonEmptyString(raw[FIELDS.agentApiBaseUrl]) !== '';\n if (hasKey !== hasUrl) {\n console.warn(\n `[search] The agent is half configured: ${FIELDS.agentAppKey} and ${FIELDS.agentApiBaseUrl} must both be set, or both empty. Using plain search.`,\n );\n }\n\n return normalizeCommerceSearchConfig(raw, language ? { language } : {});\n}\n","import { useEffect, useRef, useState } from 'react';\nimport {\n COMMERCE_SEARCH_CONFIG_DEFAULTS,\n fetchCommerceSearchConfig,\n} from '../config/commerceSearchConfig';\nimport type { CommerceSearchConfig } from '../config/commerceSearchConfig';\n\nexport interface UseCommerceSearchConfigOptions {\n country: string;\n language: string;\n /** The host's client id for the configuration service. Absent: the configuration SDK's own. */\n clientId?: string;\n /** Nothing is read until the panel opens, and a failed read is tried again at the next open. */\n isOpen: boolean;\n}\n\n/**\n * The product search configuration for a market: the defaults (plain search) until the read\n * finishes, and again if it fails. A failed read is tried again the next time the panel opens. The\n * configuration of one market is never returned for another, and a read that finishes after the\n * market changed is ignored.\n */\nexport function useCommerceSearchConfig({\n country,\n language,\n clientId,\n isOpen,\n}: UseCommerceSearchConfigOptions): CommerceSearchConfig {\n const market = `${country}|${language}|${clientId ?? ''}`;\n const [loaded, setLoaded] = useState<{\n market: string;\n config: CommerceSearchConfig;\n } | null>(null);\n\n const currentMarket = useRef(market);\n useEffect(() => {\n currentMarket.current = market;\n }, [market]);\n\n // The market being read, so that opening the panel again does not start a second read.\n const reading = useRef<string | null>(null);\n\n useEffect(() => {\n if (\n !isOpen ||\n loaded?.market === market ||\n reading.current === market\n ) {\n return;\n }\n reading.current = market;\n\n fetchCommerceSearchConfig({\n country,\n language,\n ...(clientId ? { clientId } : {}),\n })\n .then((config) => {\n if (currentMarket.current === market) {\n setLoaded({ market, config });\n }\n })\n .catch((error: unknown) => {\n console.warn(\n '[search] Could not load the product search configuration:',\n error,\n );\n })\n .finally(() => {\n if (reading.current === market) reading.current = null;\n });\n }, [isOpen, market, loaded, country, language, clientId]);\n\n return loaded?.market === market\n ? loaded.config\n : COMMERCE_SEARCH_CONFIG_DEFAULTS;\n}\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\n\n/**\n * The search panel's text, in English. This file is where the text comes from for now, for every\n * language. The configuration store will replace it, and only `fetchSearchPanelCopy` reads it.\n *\n * The functions word a string around a number or a product name.\n */\nexport const SEARCH_PANEL_COPY_EN: SearchPanelCopy = {\n cancel: 'Cancel',\n searchPlaceholder: 'Search',\n didYouMean: 'Did You Mean?',\n noSuggestions: 'No suggestions',\n seeMoreResults: 'See More Results',\n recentSearches: 'Recent searches',\n clearRecentSearches: 'Clear all',\n moreRecentSearches: (count) => `+${count} More`,\n searchLabel: 'Search',\n submitSearch: 'Submit search',\n clearInput: 'Clear search',\n suggestionsLabel: 'Suggestions',\n addToCart: (productName) => `Add ${productName} to cart`,\n openBundle: (productName) => `Open bundle action for ${productName}`,\n suggestionsLoading: 'Loading suggestions',\n suggestionsCount: (count) => `${count} suggestions available`,\n};\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { SEARCH_PANEL_COPY_EN } from './searchPanelCopy';\n\nexport interface FetchSearchPanelCopyOptions {\n language?: string;\n}\n\n/**\n * Reads the search panel's text for a language. It is the only function that knows where the text\n * comes from, so moving it to the configuration store changes this function and nothing else.\n *\n * For now there is one English file, and every language gets it.\n */\nexport async function fetchSearchPanelCopy(\n _options: FetchSearchPanelCopyOptions = {},\n): Promise<SearchPanelCopy> {\n return SEARCH_PANEL_COPY_EN;\n}\n","import type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { fetchSearchPanelCopy } from './fetchSearchPanelCopy';\n\nconst copyByLanguage = new Map<string, Promise<SearchPanelCopy>>();\nconst loadedByLanguage = new Map<string, SearchPanelCopy>();\n\nfunction cacheKey(language?: string): string {\n return (language ?? '').toLowerCase();\n}\n\n/**\n * The search panel's text for a language, read once and shared by every caller, so that\n * remounting the search (or StrictMode running an effect twice) does not read it again.\n * A read that fails is not kept, so the next caller tries again.\n */\nexport function loadSearchPanelCopy(\n language?: string,\n): Promise<SearchPanelCopy> {\n const key = cacheKey(language);\n const cached = copyByLanguage.get(key);\n if (cached) return cached;\n\n const pending = fetchSearchPanelCopy(language ? { language } : {});\n copyByLanguage.set(key, pending);\n // Registered before any caller's own handlers, so the text can be peeked at by the time they run.\n pending.then(\n (copy) => {\n if (copyByLanguage.get(key) === pending) {\n loadedByLanguage.set(key, copy);\n }\n },\n () => {\n if (copyByLanguage.get(key) === pending) {\n copyByLanguage.delete(key);\n }\n },\n );\n\n return pending;\n}\n\n/**\n * The text for a language if it has already loaded, otherwise `undefined`. It never starts a\n * read, and it answers straight away, which a promise cannot.\n */\nexport function peekSearchPanelCopy(\n language?: string,\n): SearchPanelCopy | undefined {\n return loadedByLanguage.get(cacheKey(language));\n}\n\n/** Forgets what was read, so a test starts from nothing. */\nexport function clearSearchPanelCopyCache(): void {\n copyByLanguage.clear();\n loadedByLanguage.clear();\n}\n","import { useEffect, useState } from 'react';\nimport type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport {\n loadSearchPanelCopy,\n peekSearchPanelCopy,\n} from '../copy/loadSearchPanelCopy';\n\n/**\n * The search panel's text for a language, or nothing until it has loaded. It starts loading as\n * soon as it is used, not when the panel opens, so the text is ready by then. A read that\n * finishes after the language changed is ignored.\n *\n * A mount that finds the text already loaded has it on its first render, so the panel does not\n * wait a tick for text that is already in memory. The server renders nothing here, so a root that\n * hydrates after another root has loaded the text would render the panel where the server did\n * not. A single root cannot: loading starts in an effect, after hydration has finished.\n */\nexport function useSearchPanelCopy({\n language,\n}: {\n language?: string;\n}): SearchPanelCopy | undefined {\n const [copy, setCopy] = useState<SearchPanelCopy | undefined>(() =>\n peekSearchPanelCopy(language),\n );\n\n useEffect(() => {\n let isStale = false;\n\n loadSearchPanelCopy(language)\n .then((next) => {\n if (!isStale) setCopy(next);\n })\n .catch((error: unknown) => {\n // The panel stays unrendered until the text loads.\n console.warn(\n '[search] Could not load the search panel text:',\n error,\n );\n });\n\n return () => {\n isStale = true;\n };\n }, [language]);\n\n return copy;\n}\n","import type { LocaleParts } from '../types';\n\n/**\n * A market is a country and a language, two letters each, as the storefront's own URLs and locale\n * parsing require (`/us/en/`). Nothing else is a market, and nothing stands in for one.\n */\nconst TWO_LETTERS = /^[A-Za-z]{2}$/;\n\n/** What is wrong with a market, or `undefined` when it is valid. */\nexport function marketProblem(\n country: unknown,\n language: unknown,\n): string | undefined {\n const countryText = String(country ?? '').trim();\n const languageText = String(language ?? '').trim();\n if (TWO_LETTERS.test(countryText) && TWO_LETTERS.test(languageText)) {\n return undefined;\n }\n return `the market is not valid (country ${JSON.stringify(countryText)}, language ${JSON.stringify(languageText)}): each must be two letters, for example US and en`;\n}\n\nexport function isValidMarket(country: unknown, language: unknown): boolean {\n return marketProblem(country, language) === undefined;\n}\n\n/**\n * The market in the shape the SDK stores it: an upper-case country, a lower-case language and the\n * two joined (`US-en`). Throws for a market that is not valid, so that nothing ever falls back to\n * another market.\n */\nexport function createLocaleParts({\n country,\n language,\n}: {\n country: string;\n language: string;\n}): LocaleParts {\n const problem = marketProblem(country, language);\n if (problem) throw new Error(problem);\n\n const normalizedCountry = country.trim().toUpperCase();\n const normalizedLanguage = language.trim().toLowerCase();\n return {\n country: normalizedCountry,\n language: normalizedLanguage,\n locale: `${normalizedCountry}-${normalizedLanguage}`,\n };\n}\n\n/** The market as the catalog API names it: `en_US`. */\nexport function toCatalogLocale({ country, language }: LocaleParts): string {\n return `${language}_${country}`;\n}\n\n/** The market as the storefront's paths start: `/us/en`. */\nexport function toPathPrefix({ country, language }: LocaleParts): string {\n return `/${country.toLowerCase()}/${language}`;\n}\n","import {\n CATALOG_SUGGESTIONS_PATH,\n DEFAULT_SUGGESTION_PAGE,\n STOREFRONT_SHOPPING_CONTEXT,\n} from '../constants';\nimport type {\n GetMarketConfig,\n LocaleParts,\n LocationLike,\n MarketConfig,\n} from '../types';\nimport { toCatalogLocale } from './localeParts';\n\n/* -------------------------------------------------------------------------- */\n/* Market-config → URL/storeId resolution */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Replaces `{api_name}` in a market-config gateway path with the given API\n * name, then trims a single trailing slash.\n */\nexport function resolveApiGatewayPath(\n apiGatewayPath: string | undefined | null,\n apiName: string = STOREFRONT_SHOPPING_CONTEXT,\n): string {\n const apiGateway = String(apiGatewayPath ?? '').trim();\n if (!apiGateway) return '';\n return apiGateway.replace(/\\{api_name\\}/gi, apiName).replace(/\\/$/, '');\n}\n\nfunction resolveCatalogApiBaseUrl(\n marketConfig: MarketConfig | null | undefined,\n): string {\n return resolveApiGatewayPath(marketConfig?.api_gateway_path);\n}\n\nfunction resolveCatalogStoreId(\n marketConfig: MarketConfig | null | undefined,\n): string {\n return String(marketConfig?.store_id ?? '').trim();\n}\n\nfunction buildCatalogSuggestionsUrl(apiBaseUrl: string): string {\n const normalizedBase = String(apiBaseUrl ?? '')\n .trim()\n .replace(/\\/$/, '');\n if (!normalizedBase) return '';\n\n const suggestionsPath = normalizedBase.endsWith(\n `/${STOREFRONT_SHOPPING_CONTEXT}`,\n )\n ? '/catalogs/search/suggestions'\n : CATALOG_SUGGESTIONS_PATH;\n\n return `${normalizedBase}${suggestionsPath}`;\n}\n\n/** The URL of one suggestions request. */\nexport function buildSuggestionsRequestUrl({\n suggestionsUrl,\n searchTerm,\n size,\n storeId,\n localeParts,\n}: {\n suggestionsUrl: string;\n searchTerm: string;\n /** How many suggestions to ask for. */\n size: number;\n storeId: string;\n localeParts: LocaleParts;\n}): string {\n const queryParams = new URLSearchParams({\n searchTerm,\n page: String(DEFAULT_SUGGESTION_PAGE),\n size: String(size),\n locale: toCatalogLocale(localeParts),\n storeId,\n });\n return `${suggestionsUrl}?${queryParams.toString()}`;\n}\n\n/**\n * Where the market's suggestions live and which store they are for. Throws when the market has no\n * gateway or no store, so that it counts as a failed lookup and is not remembered, and never reads\n * as \"the catalog has no products\".\n */\nexport async function resolveCatalogRequestConfig({\n locationLike,\n country,\n getMarketConfig,\n}: {\n locationLike: LocationLike | null;\n country: string;\n getMarketConfig: GetMarketConfig | undefined;\n}): Promise<{ suggestionsUrl: string; storeId: string }> {\n const marketConfig = getMarketConfig\n ? ((await getMarketConfig({ locationLike, country })) ?? null)\n : null;\n\n const suggestionsUrl = buildCatalogSuggestionsUrl(\n resolveCatalogApiBaseUrl(marketConfig),\n );\n if (!suggestionsUrl) {\n throw new Error(\n `no suggestions API for market ${country}: the market configuration has no gateway`,\n );\n }\n const storeId = resolveCatalogStoreId(marketConfig);\n if (!storeId) {\n throw new Error(\n `no suggestions API for market ${country}: the market configuration has no store`,\n );\n }\n\n return { suggestionsUrl, storeId };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Fetch helper */\n/* -------------------------------------------------------------------------- */\n\n/** The `X-Customer-Type` header for a request, or none when there is no customer type to send. */\nexport function resolveCustomerTypeHeaders(\n getCustomerType: (() => string | undefined) | undefined,\n): Record<string, string> | undefined {\n const customerType = getCustomerType?.()?.trim();\n return customerType ? { 'X-Customer-Type': customerType } : undefined;\n}\n\n/**\n * The suggestions API answers a term that matches nothing with a 404 whose body carries this code\n * (`{ code: 'SFOSER002', message: 'No Results Found for Search Term …' }`). That is an answer,\n * not an outage: treating it as a failure would also keep the NUi agent from ever taking over.\n */\nconst NO_RESULTS_ERROR_CODE = 'SFOSER002';\n\nasync function isNoResultsResponse(response: Response): Promise<boolean> {\n if (response.status !== 404) return false;\n try {\n const body = (await response.json()) as { code?: unknown } | null;\n return body?.code === NO_RESULTS_ERROR_CODE;\n } catch {\n return false;\n }\n}\n\n/** Resolves to the response's JSON, or `null` when the API says nothing matched. */\nexport async function fetchJson(\n fetchImpl: typeof fetch,\n requestUrl: string,\n requestHeaders: Record<string, string> = {},\n): Promise<unknown> {\n const response = await fetchImpl(requestUrl, {\n method: 'GET',\n credentials: 'include',\n headers: { Accept: 'application/json', ...requestHeaders },\n });\n\n if (!response.ok) {\n if (await isNoResultsResponse(response)) return null;\n throw new Error(`Request failed with status ${response.status}`);\n }\n\n return response.json();\n}\n","import {\n RECENT_SEARCHES_DEFAULT_LIMIT,\n RECENT_SEARCHES_PREFIX,\n} from '../constants';\nimport type { LocaleParts } from '../types';\n\n/* -------------------------------------------------------------------------- */\n/* Storage guards */\n/* -------------------------------------------------------------------------- */\n\nfunction canUseStorage(\n storage: Storage | null | undefined,\n): storage is Storage {\n return (\n Boolean(storage) && typeof (storage as Storage).getItem === 'function'\n );\n}\n\nexport function getSessionStorage(\n providedStorage: Storage | null | undefined,\n): Storage | null {\n if (providedStorage) return providedStorage;\n\n if (typeof window !== 'undefined') {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\nfunction getRecentHeaderSearchesStorageKey(localeParts: LocaleParts): string {\n const { country, language, locale } = localeParts;\n return `${RECENT_SEARCHES_PREFIX}:${locale}:${country}:${language}`;\n}\n\nexport function getRecentHeaderSearches(\n localeParts: LocaleParts,\n storage: Storage | null,\n): string[] {\n if (!canUseStorage(storage)) {\n return [];\n }\n\n try {\n const rawValue = storage.getItem(\n getRecentHeaderSearchesStorageKey(localeParts),\n );\n if (!rawValue) {\n return [];\n }\n\n const parsedValue: unknown = JSON.parse(rawValue);\n if (!Array.isArray(parsedValue)) {\n return [];\n }\n\n return parsedValue\n .map((item) => String(item ?? '').trim())\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function addRecentHeaderSearch(\n localeParts: LocaleParts,\n query: string,\n storage: Storage | null,\n limit: number = RECENT_SEARCHES_DEFAULT_LIMIT,\n): string[] {\n const normalizedQuery = String(query ?? '').trim();\n if (!normalizedQuery || !canUseStorage(storage)) {\n return [];\n }\n\n try {\n const existingValues = getRecentHeaderSearches(\n localeParts,\n storage,\n ).filter(\n (item) => item.toLowerCase() !== normalizedQuery.toLowerCase(),\n );\n const nextValues = [normalizedQuery, ...existingValues].slice(0, limit);\n storage.setItem(\n getRecentHeaderSearchesStorageKey(localeParts),\n JSON.stringify(nextValues),\n );\n return nextValues;\n } catch {\n return [];\n }\n}\n\nexport function clearRecentHeaderSearches(\n localeParts: LocaleParts,\n storage: Storage | null,\n): void {\n if (!canUseStorage(storage)) {\n return;\n }\n\n try {\n storage.removeItem(getRecentHeaderSearchesStorageKey(localeParts));\n } catch {\n // intentionally quiet when storage is blocked/unavailable\n }\n}\n","import { DEFAULT_SEARCH_PATH } from '../constants';\nimport type { LocaleParts, SuggestionOption } from '../types';\nimport { toPathPrefix } from './localeParts';\n\n/* -------------------------------------------------------------------------- */\n/* Path + slug helpers */\n/* -------------------------------------------------------------------------- */\n\nexport function buildSearchResultsPath(\n query: string,\n localeParts: LocaleParts,\n): string {\n const trimmedQuery = String(query ?? '').trim();\n const hyphenatedQuery = trimmedQuery.replace(/\\s+/g, '-');\n const encodedQuery = encodeURIComponent(hyphenatedQuery).replace(\n /%2D/gi,\n '-',\n );\n return `${toPathPrefix(localeParts)}${DEFAULT_SEARCH_PATH}/${encodedQuery}`;\n}\n\n/** Starts with a scheme, such as `javascript:`, `mailto:` or `https:`. */\nconst SCHEME = /^[a-z][a-z0-9+.-]*:/i;\n\n/**\n * An authored link can leave out its leading slash (`search/serum`). Put it back, unless the value\n * starts with a scheme or is already a path or protocol-relative (it then starts with a slash):\n * `isNavigableUrl` accepts or refuses those as they are.\n */\nfunction normalizeOptionUrl(rawValue: unknown): string {\n if (typeof rawValue !== 'string') return '';\n const value = rawValue.trim();\n if (!value || value.startsWith('/') || SCHEME.test(value)) return value;\n return `/${value}`;\n}\n\nfunction safeDecodeURIComponent(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction trimEdgeHyphens(value: string): string {\n let normalizedValue = value;\n while (normalizedValue.startsWith('-')) {\n normalizedValue = normalizedValue.slice(1);\n }\n while (normalizedValue.endsWith('-')) {\n normalizedValue = normalizedValue.slice(0, -1);\n }\n return normalizedValue;\n}\n\nfunction slugifyPathSegment(value: string | undefined | null): string {\n const decoded = safeDecodeURIComponent(String(value ?? '')).replace(\n /\\+/g,\n ' ',\n );\n const normalized = decoded\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/-{2,}/g, '-')\n .toLowerCase();\n return trimEdgeHyphens(normalized);\n}\n\nfunction buildProductSlugPath(\n slugValue: string | undefined | null,\n localeParts: LocaleParts,\n): string {\n const slug = slugifyPathSegment(slugValue);\n if (!slug) return '';\n return `${toPathPrefix(localeParts)}/product/${slug}`;\n}\n\nfunction isNavigableUrl(value: string): boolean {\n if (!value) return false;\n return value.startsWith('/') || /^https?:\\/\\//i.test(value);\n}\n\nexport function stripLocalePrefix(\n path: string,\n localeParts: LocaleParts,\n): string {\n const prefix = toPathPrefix(localeParts);\n return path.startsWith(prefix) ? path.slice(prefix.length) || '/' : path;\n}\n\nexport function resolveOptionHref(\n option: SuggestionOption | null | undefined,\n localeParts: LocaleParts,\n): string {\n const productSlugPath = buildProductSlugPath(\n option?.slug ?? option?.productSlug ?? option?.product_slug ?? null,\n localeParts,\n );\n if (productSlugPath) {\n return productSlugPath;\n }\n\n const directUrl = normalizeOptionUrl(option?.href ?? option?.url);\n if (isNavigableUrl(directUrl) && !directUrl.includes('/chr/')) {\n return directUrl;\n }\n return '';\n}\n","import type { SuggestionsResponse } from '../types';\n\n/** The answer when there is nothing to look up, or nowhere to look it up. */\nexport function emptySuggestions(): SuggestionsResponse {\n return { suggestions: [], didYouMean: [], totalResultsCount: 0 };\n}\n\n/** The total the API reports: `totalResultsCount`, else the pageable total, else `fallback`. */\nfunction resolveTotalResultsCount(\n payload: SuggestionsResponse | null | undefined,\n fallback: number,\n): number {\n if (typeof payload?.totalResultsCount === 'number') {\n return payload.totalResultsCount;\n }\n const pageableTotal = Number(\n payload?.pageableInfo?.totalCount ?? Number.NaN,\n );\n return Number.isNaN(pageableTotal) ? fallback : pageableTotal;\n}\n\n/**\n * The API's answer with `suggestions` and `didYouMean` always arrays and `totalResultsCount`\n * always a number. Everything else the API sent (the `product` array, for one) is kept.\n */\nexport function normalizeSuggestionsPayload(\n payload: SuggestionsResponse | null | undefined,\n): SuggestionsResponse {\n const suggestions = Array.isArray(payload?.suggestions)\n ? payload.suggestions\n : [];\n const products = Array.isArray(payload?.product)\n ? (payload.product as unknown[])\n : null;\n const rawDidYouMean = payload?.didYouMean ?? payload?.did_you_mean;\n const didYouMean = Array.isArray(rawDidYouMean)\n ? (rawDidYouMean as unknown[])\n : [];\n\n return {\n ...(payload ?? {}),\n suggestions,\n didYouMean,\n totalResultsCount: resolveTotalResultsCount(\n payload,\n products?.length ?? suggestions.length,\n ),\n };\n}\n","/**\n * SearchApiService: the suggestions request and the paths a search leads to. Navigation is left\n * to the host's router.\n *\n * Two things stay outside it:\n * 1. Market-config resolution, which depends on `@nuskin/configuration-sdk`. The caller\n * injects a `getMarketConfig` callback to resolve the gateway URL and store id.\n * 2. The market itself. The caller passes `country` and `language` explicitly.\n */\n\nimport {\n DEFAULT_MAX_SUGGESTIONS,\n MINIMUM_SEARCH_CHAR_LENGTH,\n} from '../constants';\nimport type {\n LocationLike,\n SearchServiceOptions,\n SuggestionOption,\n SuggestionsResponse,\n} from '../types';\nimport {\n buildSuggestionsRequestUrl,\n fetchJson,\n resolveCatalogRequestConfig,\n resolveCustomerTypeHeaders,\n} from './catalogRequest';\nimport { createLocaleParts } from './localeParts';\nimport {\n addRecentHeaderSearch,\n clearRecentHeaderSearches,\n getRecentHeaderSearches,\n getSessionStorage,\n} from './recentSearches';\nimport {\n buildSearchResultsPath,\n resolveOptionHref,\n stripLocalePrefix,\n} from './searchPaths';\nimport {\n emptySuggestions,\n normalizeSuggestionsPayload,\n} from './suggestionsPayload';\n\n/** Returned by `createSearchService`. Internal to the package. */\nexport interface SearchService {\n /** Fetches typeahead suggestions from the Equinox catalog. */\n fetchSuggestions: (searchTerm: string) => Promise<SuggestionsResponse>;\n /**\n * Records the query in recent searches, then returns the option URL or the\n * fallback search-results path for the consuming router to navigate.\n */\n submitProductSearch: (\n query: string,\n option?: SuggestionOption,\n ) => string | undefined;\n /**\n * Returns the suggestion's URL if one is resolvable; otherwise submits the\n * suggestion's textual value as a product search.\n */\n activateSuggestionAction: (option: SuggestionOption) => string | undefined;\n /** Returns the navigable URL for a suggestion option (or `\"\"`). */\n getSuggestionHref: (option: SuggestionOption) => string;\n /** Returns the search-results page path for `query`. */\n viewMoreResults: (input: { query: string }) => string | undefined;\n /** Returns the persisted recent searches for the current locale bucket. */\n getRecentSearches: () => string[];\n /** Removes all persisted recent searches for the current locale bucket. */\n clearRecentSearches: () => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Location helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction getBrowserLocation(\n providedLocation: LocationLike | null | undefined,\n): LocationLike | null {\n if (providedLocation) return providedLocation;\n if (typeof window !== 'undefined' && window.location)\n return window.location;\n return null;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Factory */\n/* -------------------------------------------------------------------------- */\n\n/**\n * What `createSearchService` accepts. Internal: `CommerceSearch` adds the minimum search length\n * and the number of suggestions from its configuration, so hosts never set them.\n */\ninterface ResolvedSearchServiceOptions extends SearchServiceOptions {\n /**\n * The visitor's account type, sent as `X-Customer-Type` on every suggestions request. Read\n * when the request is made, because it can change after the visitor signs in.\n */\n getCustomerType?: () => string | undefined;\n /**\n * Terms shorter than this are not sent to the suggestions API. Defaults to\n * `MINIMUM_SEARCH_CHAR_LENGTH`.\n */\n minimumSearchLength?: number;\n /**\n * How many suggestions to ask the catalog for, which is also how many the typeahead shows.\n * Defaults to `DEFAULT_MAX_SUGGESTIONS`.\n */\n maxSuggestions?: number;\n}\n\n/**\n * Creates a search service instance. All options are optional; sensible\n * fallbacks are used when the browser environment is absent (SSR).\n */\nexport function createSearchService(\n options: ResolvedSearchServiceOptions,\n): SearchService {\n const {\n fetchImpl: fetchImplOption,\n location: providedLocation,\n storage: providedStorage,\n country,\n language,\n getMarketConfig,\n getCustomerType,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n maxSuggestions = DEFAULT_MAX_SUGGESTIONS,\n } = options;\n\n const locationLike = getBrowserLocation(providedLocation);\n const storage = getSessionStorage(providedStorage);\n const localeParts = createLocaleParts({ country, language });\n\n let catalogRequestConfigPromise: Promise<{\n suggestionsUrl: string;\n storeId: string;\n }> | null = null;\n\n function loadCatalogRequestConfig() {\n if (!catalogRequestConfigPromise) {\n catalogRequestConfigPromise = resolveCatalogRequestConfig({\n locationLike,\n country: localeParts.country,\n getMarketConfig,\n }).catch((error: unknown) => {\n // Do not remember a failure: the next search tries again. And say so, because a\n // search that quietly returns nothing is very hard to diagnose.\n catalogRequestConfigPromise = null;\n console.warn(\n '[search] Could not load the market configuration for the suggestions:',\n error,\n );\n throw error;\n });\n }\n return catalogRequestConfigPromise;\n }\n\n const service: SearchService = {\n async fetchSuggestions(\n searchTerm: string,\n ): Promise<SuggestionsResponse> {\n const trimmedSearchTerm = String(searchTerm ?? '').trim();\n if (\n !trimmedSearchTerm ||\n trimmedSearchTerm.length < minimumSearchLength\n ) {\n return emptySuggestions();\n }\n\n const { suggestionsUrl, storeId } =\n await loadCatalogRequestConfig();\n\n const responsePayload = (await fetchJson(\n fetchImplOption ?? fetch.bind(globalThis),\n buildSuggestionsRequestUrl({\n suggestionsUrl,\n searchTerm: trimmedSearchTerm,\n size: maxSuggestions,\n storeId,\n localeParts,\n }),\n resolveCustomerTypeHeaders(getCustomerType),\n )) as SuggestionsResponse | null | undefined;\n\n return normalizeSuggestionsPayload(responsePayload);\n },\n\n submitProductSearch(\n query: string,\n option?: SuggestionOption,\n ): string | undefined {\n const trimmedQuery = String(query ?? '').trim();\n if (!trimmedQuery) return undefined;\n\n addRecentHeaderSearch(localeParts, trimmedQuery, storage);\n\n const optionHref = resolveOptionHref(option, localeParts);\n if (optionHref) {\n return stripLocalePrefix(optionHref, localeParts);\n }\n\n const targetPath = buildSearchResultsPath(\n trimmedQuery,\n localeParts,\n );\n\n return stripLocalePrefix(targetPath, localeParts);\n },\n\n activateSuggestionAction(option: SuggestionOption): string | undefined {\n // The suggestion's page, or a search for its text.\n const optionHref = resolveOptionHref(option, localeParts);\n if (optionHref) {\n return stripLocalePrefix(optionHref, localeParts);\n }\n\n const optionQuery =\n option?.value ?? option?.label ?? option?.identifier ?? '';\n return service.submitProductSearch(String(optionQuery));\n },\n\n getSuggestionHref(option: SuggestionOption): string {\n return stripLocalePrefix(\n resolveOptionHref(option, localeParts),\n localeParts,\n );\n },\n\n viewMoreResults({ query }: { query: string }): string | undefined {\n return service.submitProductSearch(query);\n },\n\n getRecentSearches(): string[] {\n return getRecentHeaderSearches(localeParts, storage);\n },\n\n clearRecentSearches(): void {\n clearRecentHeaderSearches(localeParts, storage);\n },\n };\n\n return service;\n}\n","import {\n getConfiguration,\n getEnvironmentCode,\n} from '../config/configurationSdk';\nimport { EQUINOX_MARKETS_MAP, STOREFRONT_SHOPPING_CONTEXT } from '../constants';\nimport type { GetMarketConfig, MarketConfig } from '../types';\n\n/**\n * Reads the market's API gateway and store from the `Equinox_Markets` configuration, for the\n * environment the page is served from.\n */\nexport const fetchMarketConfig: GetMarketConfig = async ({\n country,\n clientId,\n}) => {\n const countryCode = country.trim().toUpperCase();\n const configuration = await getConfiguration([EQUINOX_MARKETS_MAP], {\n country: countryCode,\n ...(getEnvironmentCode()\n ? { environment: getEnvironmentCode() as string }\n : {}),\n ...(clientId ? { clientId } : {}),\n shoppingContext: STOREFRONT_SHOPPING_CONTEXT,\n });\n\n return (\n (configuration?.[EQUINOX_MARKETS_MAP] as MarketConfig | undefined) ??\n null\n );\n};\n","/**\n * GTM constants — event names, storage keys, and enum-like value maps.\n * Types are declared in `./gtmTypes` and imported here only for `satisfies`.\n */\n\nimport type { SearchGtmSearchType, SearchGtmUserStatus } from './gtmTypes';\n\n/* -------------------------------------------------------------------------- */\n/* Event names (COMX-3277) */\n/* -------------------------------------------------------------------------- */\n\nexport const SEARCH_GTM_EVENTS = {\n CHAT_ENTRY_POINT: 'Begin_chat',\n SEARCH_TYPE: 'Search_Type',\n PRODUCT_SEARCH: 'ProductSearch',\n ERROR_POPUP: 'Error_popup',\n} as const;\n\n/* -------------------------------------------------------------------------- */\n/* Enum-like value maps */\n/* -------------------------------------------------------------------------- */\n\nexport const SEARCH_GTM_SEARCH_TYPES = {\n SEMANTIC: 'semantic search',\n AI_AGENT: 'AI agent',\n} as const satisfies Record<string, SearchGtmSearchType>;\n\nexport const SEARCH_GTM_USER_STATUS = {\n GUEST: 'guest',\n LOGGED_IN: 'logged_in',\n} as const satisfies Record<string, SearchGtmUserStatus>;\n\n/* -------------------------------------------------------------------------- */\n/* Storage keys the SDK reads from the host storefront */\n/* -------------------------------------------------------------------------- */\n\n/** Fallback string used for the GTM `id` and `Chat_ID` fields when unknown. */\nexport const GTM_FALLBACK_NA = 'NA';\n","/**\n * Where `CommerceSearch` wants the host to take the shopper: a page inside the app (a path for\n * the host's router, with the market prefix already removed), or somewhere that needs a full\n * page load.\n */\nexport type NavigationTarget =\n { type: 'internal'; path: string } | { type: 'external'; url: string };\n\nconst EXTERNAL_URL = /^https?:\\/\\//i;\n\n/**\n * A path inside the app starts with exactly one slash. `//host` and `/\\host` are another site to a\n * browser, and a browser drops a tab or a newline anywhere in a URL, so `/<tab>/host` is `//host`.\n */\nconst INTERNAL_PATH = /^\\/(?![/\\\\])[^\\t\\n\\r]*$/;\n\n/**\n * Classifies a path from the search service as internal or external. Anything that is neither an\n * `http(s)` URL nor a path inside the app (`javascript:`, `data:`, `//host` and the like) is\n * refused with `undefined`, so it never reaches the host.\n */\nexport function toNavigationTarget(path: string): NavigationTarget | undefined {\n if (EXTERNAL_URL.test(path)) return { type: 'external', url: path };\n if (INTERNAL_PATH.test(path)) return { type: 'internal', path };\n return undefined;\n}\n","import type { ProductEnvironment } from '@nuskin/react-product-sdk';\nimport { getEnvironmentCode } from '../config/configurationSdk';\n\n/**\n * Every environment the product SDK knows. A record, so that a change to the SDK's list is a\n * compile error here and not a silent mismatch: each environment must appear exactly once.\n */\nconst PRODUCT_ENVIRONMENTS: Readonly<Record<ProductEnvironment, true>> = {\n dev: true,\n test: true,\n prod: true,\n};\n\nfunction isProductEnvironment(code: string): code is ProductEnvironment {\n // Compares against the keys: `in` would take `constructor` and `toString` for environments.\n return Object.keys(PRODUCT_ENVIRONMENTS).includes(code);\n}\n\n/**\n * The product SDK's environment for the configuration SDK's environment code, or `undefined` when\n * the product SDK has none (for example `stage`): the agent's product cards then stay the widget's own.\n */\nexport function toProductEnvironment(\n environmentCode: string | undefined,\n): ProductEnvironment | undefined {\n return environmentCode !== undefined &&\n isProductEnvironment(environmentCode)\n ? environmentCode\n : undefined;\n}\n\n/**\n * The product SDK's environment for the page, or `undefined` when it cannot be told. The product\n * cards are an enhancement: not knowing the environment must never break the search.\n */\nexport function getProductEnvironment(): ProductEnvironment | undefined {\n try {\n return toProductEnvironment(getEnvironmentCode());\n } catch {\n return undefined;\n }\n}\n","import { useEffect } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchPanel } from '@nuskin/react-search-components';\nimport { SEARCH_PANEL_COPY_EN } from '../../copy/searchPanelCopy';\nimport { marketProblem } from '../../services/localeParts';\n\nexport interface CommerceSearchUnavailableProps {\n isOpen: boolean;\n onClose: () => void;\n country: string;\n language: string;\n logo?: ReactNode;\n}\n\nconst NOTHING = () => undefined;\n\n/**\n * What the shopper sees when the host gave the search a market it cannot search in. The search\n * makes no request and shows no other market's results; the problem is logged once for the\n * market, so the host's mistake is found early.\n */\nexport function CommerceSearchUnavailable({\n isOpen,\n onClose,\n country,\n language,\n logo,\n}: Readonly<CommerceSearchUnavailableProps>): ReactElement {\n useEffect(() => {\n console.error(\n `[search] Search is unavailable: ${marketProblem(country, language)}`,\n );\n }, [country, language]);\n\n return (\n <SearchPanel\n isOpen={isOpen}\n onClose={onClose}\n copy={SEARCH_PANEL_COPY_EN}\n logo={logo}\n input={{ value: '', onChange: NOTHING, onSubmit: NOTHING }}\n suggestions={{\n items: [],\n loading: false,\n showNoResults: false,\n showDidYouMean: false,\n hasMore: false,\n query: '',\n onSelect: NOTHING,\n onRunAction: NOTHING,\n onSeeMore: NOTHING,\n }}\n recentSearches={{\n items: [],\n onSelect: NOTHING,\n onClear: NOTHING,\n }}\n agentPanel={<p role=\"alert\">Search is unavailable right now.</p>}\n />\n );\n}\n","/**\n * The enable gate for NUi search.\n *\n * The configuration decides whether the agent is on for a visitor's kind of\n * customer, so no flag is needed where the configuration enables it. A visitor can\n * override that decision with the `enableNuiSearch` flag, either as a URL query\n * parameter (`?enableNuiSearch=true` or `=false`) or as a cookie of the same name:\n * `true` switches the agent on and `false` switches it off, whatever the\n * configuration says (an agent still has to be configured). The library only ever\n * reads them: the query parameter is never copied into the cookie, so the cookie is\n * something a person sets by hand, and the parameter applies only to the page whose\n * URL carries it. When both are present the parameter wins. With neither, the\n * configuration decides (see `isNuiSearchEnabled`).\n *\n * The flag is a client-side feature toggle, not a security control.\n */\n\n/** Name shared by the cookie and the URL query parameter. */\nexport const NUI_SEARCH_FLAG = 'enableNuiSearch';\n\nfunction parseFlagValue(raw: string | null | undefined): boolean | undefined {\n const value = raw?.trim().toLowerCase();\n if (value === 'true' || value === '1') return true;\n if (value === 'false' || value === '0') return false;\n return undefined;\n}\n\nfunction readCookieFlag(cookie: string): boolean | undefined {\n for (const part of cookie.split(';')) {\n const separator = part.indexOf('=');\n if (separator < 0) continue;\n if (part.slice(0, separator).trim() !== NUI_SEARCH_FLAG) continue;\n try {\n return parseFlagValue(\n decodeURIComponent(part.slice(separator + 1)),\n );\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\n/** Where the flag is read from. Each defaults to the browser's. */\nexport interface NuiSearchFlagEnv {\n /** Query string, with or without the leading `?`. */\n search?: string;\n /** Cookie string, as in `document.cookie`. */\n cookie?: string;\n}\n\n/**\n * Reads the flag. A recognized query parameter wins; otherwise the cookie\n * decides. `undefined` means neither is set to a recognized value. Never writes\n * a cookie or any storage, and is safe to call during server rendering (there\n * is no URL or cookie there, so it is `undefined`).\n */\nexport function resolveNuiSearchFlag(\n env: NuiSearchFlagEnv = {},\n): boolean | undefined {\n const inBrowser =\n typeof window !== 'undefined' && typeof document !== 'undefined';\n const search = env.search ?? (inBrowser ? window.location.search : '');\n const cookie = env.cookie ?? (inBrowser ? document.cookie : '');\n\n return (\n parseFlagValue(new URLSearchParams(search).get(NUI_SEARCH_FLAG)) ??\n readCookieFlag(cookie)\n );\n}\n\nexport interface IsNuiSearchEnabledInput {\n /** The resolved flag; see `resolveNuiSearchFlag`. */\n flag: boolean | undefined;\n /** From the configuration: whether the agent is on for this visitor's kind of customer. */\n enabledForCustomer: boolean;\n}\n\n/**\n * The visitor's flag when they set one, otherwise whether the configuration enables the agent for\n * their kind of customer.\n */\nexport function isNuiSearchEnabled({\n flag,\n enabledForCustomer,\n}: IsNuiSearchEnabledInput): boolean {\n return flag ?? enabledForCustomer;\n}\n","import { useEffect, useState } from 'react';\nimport {\n isNuiSearchEnabled,\n resolveNuiSearchFlag,\n} from '../utils/nuiSearchGate';\n\nexport interface UseNuiAgentGateOptions {\n /** Whether an agent is configured at all. Without one the agent is never on. */\n hasAgent: boolean;\n /** The `enableNuiSearch` flag is read each time the panel opens. */\n isOpen: boolean;\n /** Whether the configuration enables the agent for this visitor's kind of customer. */\n enabledForCustomer: boolean;\n}\n\n/**\n * Whether a search may reach the NUi agent: an agent is configured, and either the shopper's\n * `enableNuiSearch` flag says so or, with no flag, the configuration enables the agent for them.\n */\nexport function useNuiAgentGate({\n hasAgent,\n isOpen,\n enabledForCustomer,\n}: UseNuiAgentGateOptions): boolean {\n const [flag, setFlag] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n if (isOpen) setFlag(resolveNuiSearchFlag());\n }, [isOpen]);\n\n return hasAgent && isNuiSearchEnabled({ flag, enabledForCustomer });\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { SearchService } from '../services/SearchApiService';\n\nexport interface UseRecentSearchesOptions {\n service: SearchService;\n /** Recent searches are read when the panel opens. */\n isOpen: boolean;\n /** Read them again when this changes, for example when an agent conversation ends. */\n refreshKey?: unknown;\n}\n\n/** The recent searches without blanks or repeats (compared ignoring case), newest first. */\nfunction uniqueRecentSearches(queries: ReadonlyArray<string>): string[] {\n const seen = new Set<string>();\n return queries.filter((query) => {\n const key = query.trim().toLowerCase();\n if (!key || seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** The shopper's recent searches for the panel, and a way to clear them. */\nexport function useRecentSearches({\n service,\n isOpen,\n refreshKey,\n}: UseRecentSearchesOptions): {\n recentSearches: string[];\n clearRecentSearches: () => void;\n} {\n const [recentSearches, setRecentSearches] = useState<string[]>([]);\n\n useEffect(() => {\n if (isOpen) {\n setRecentSearches(\n uniqueRecentSearches(service.getRecentSearches()),\n );\n }\n }, [isOpen, service, refreshKey]);\n\n const clearRecentSearches = useCallback(() => {\n service.clearRecentSearches();\n setRecentSearches([]);\n }, [service]);\n\n return { recentSearches, clearRecentSearches };\n}\n","/* -------------------------------------------------------------------------- */\n/* Product-status helpers */\n/* -------------------------------------------------------------------------- */\n\nconst CART_DISABLED_PRODUCT_STATUSES = new Set([\n 'discontinued',\n 'preview',\n 'previewproduct',\n 'test',\n 'stopped',\n 'replacement',\n 'bundleonly',\n 'inactive',\n 'notavailable',\n]);\n\nfunction normalizeProductStatusValue(value: unknown): string {\n return String(value ?? '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '');\n}\n\n/** Returns `true` when `productStatus` is `\"sellable\"`. */\nexport function isSellableProductStatus(productStatus: unknown): boolean {\n return normalizeProductStatusValue(productStatus) === 'sellable';\n}\n\nfunction resolveSkuStatusValues(\n suggestionOption: Record<string, unknown>,\n): string[] {\n return [\n suggestionOption['productStatus'],\n suggestionOption['product_status'],\n suggestionOption['status'],\n suggestionOption['sku_status'],\n ]\n .map(normalizeProductStatusValue)\n .filter(Boolean);\n}\n\nfunction isNonSellableStatusValue(statusValue: string): boolean {\n if (CART_DISABLED_PRODUCT_STATUSES.has(statusValue)) {\n return true;\n }\n return statusValue !== 'sellable' && statusValue !== 'active';\n}\n\n/**\n * Returns `true` when the suggestion option should not allow add-to-cart\n * (out of stock, discontinued, inactive, etc.).\n */\nexport function isCartActionDisabled(\n suggestionOption: Record<string, unknown> | null | undefined,\n): boolean {\n if (!suggestionOption) {\n return true;\n }\n\n const outOfStock =\n suggestionOption['out_of_stock'] ?? suggestionOption['outOfStock'];\n if (outOfStock) {\n return true;\n }\n\n const statusValues = resolveSkuStatusValues(suggestionOption);\n if (statusValues.length === 0) {\n return false;\n }\n\n return statusValues.some(isNonSellableStatusValue);\n}\n\n/**\n * Returns `true` when the suggestion row should be displayed as\n * non-interactive (out-of-stock only — a subset of `isCartActionDisabled`).\n */\nexport function isSuggestionDisabled(\n suggestionOption: Record<string, unknown> | null | undefined,\n): boolean {\n return Boolean(\n !suggestionOption ||\n suggestionOption['out_of_stock'] ||\n suggestionOption['outOfStock'],\n );\n}\n","/**\n * Catalog-product normalization helpers: the data processing for the suggestions list.\n * UI-specific helpers (keyboard handling, ARIA attributes, display data) live in\n * `react-search-components`, because they depend on DOM refs and component props.\n *\n * `resolveSuggestionImageSrc` returns `\"\"` when the source is absent, not a bundled\n * placeholder. Components apply their own `<img onError>` / CSS placeholder; the SDK must not\n * bundle assets.\n */\n\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n ProductType,\n} from '../types';\nimport { isCartActionDisabled } from './catalogStatus';\n\n/* -------------------------------------------------------------------------- */\n/* Image helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Reads the first non-empty image URL from a Contentstack / catalog property\n * bag. Returns `\"\"` when no image is found.\n */\nexport function getImageFromProperty(\n properties: Record<string, unknown> = {},\n): string {\n let image =\n String(properties['primaryimage'] ?? '').trim() ||\n String(properties['imageURL'] ?? '').trim();\n\n if (!image) {\n try {\n const parsed: unknown = JSON.parse(\n String(properties['productImages'] ?? '{}'),\n );\n if (\n Array.isArray(parsed) &&\n parsed[0] &&\n typeof parsed[0] === 'object'\n ) {\n image = String(\n (parsed[0] as Record<string, unknown>)['url'] ?? '',\n ).trim();\n }\n } catch {\n image = '';\n }\n }\n\n return image;\n}\n\n/**\n * Normalizes an image source value. Returns `\"\"` when the source is absent or\n * blank. Components are responsible for applying a fallback placeholder image.\n */\nexport function resolveSuggestionImageSrc(imageSrc: unknown): string {\n const trimmed =\n typeof imageSrc === 'string'\n ? imageSrc.trim()\n : String(imageSrc ?? '').trim();\n return trimmed;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Ingredient terms */\n/* -------------------------------------------------------------------------- */\n\nfunction safeParseJsonArray(value: unknown): unknown[] {\n if (Array.isArray(value)) {\n return value;\n }\n\n if (typeof value !== 'string' || !value.trim()) {\n return [];\n }\n\n try {\n const parsed: unknown = JSON.parse(value);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Extracts a flat list of ingredient terms from a Contentstack ingredient\n * structure. Used to populate `CatalogSuggestionItem.ingredientTerms`.\n */\nexport function getIngredientTerms(rawIngredients: unknown): string[] {\n const ingredientGroups = safeParseJsonArray(rawIngredients);\n\n return ingredientGroups\n .flatMap((ingredientGroup) => {\n if (!ingredientGroup || typeof ingredientGroup !== 'object') {\n return [];\n }\n const group = ingredientGroup as Record<string, unknown>;\n const keyIngredients = Array.isArray(group['keyIngredients'])\n ? (\n group['keyIngredients'] as Array<Record<string, unknown>>\n ).map((ingredient) => ingredient['name'])\n : [];\n\n return [\n group['productName'],\n group['activeIngredients'],\n group['inactiveIngredients'],\n group['allIngredients'],\n group['otherIngredients'],\n ...keyIngredients,\n ];\n })\n .filter(Boolean)\n .map((term) => String(term).trim())\n .filter(Boolean);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Catalog product → suggestion mapping */\n/* -------------------------------------------------------------------------- */\n\nfunction getSkuProperties(product: Record<string, unknown>): {\n defaultSku: Record<string, unknown> | null;\n skuProperties: Record<string, unknown>;\n} {\n const skuList = Array.isArray(product['sku'])\n ? (product['sku'] as Array<Record<string, unknown>>)\n : [];\n const defaultSku =\n skuList.find((skuEntry) => skuEntry?.['default'] === true) ??\n skuList[0] ??\n null;\n return {\n defaultSku: defaultSku ?? null,\n skuProperties:\n ((defaultSku as Record<string, unknown> | null)?.[\n 'properties'\n ] as Record<string, unknown>) ?? {},\n };\n}\n\nfunction getIdentifier(\n product: Record<string, unknown>,\n defaultSku: Record<string, unknown> | null,\n index: number,\n): string {\n return String(\n defaultSku?.['identifier'] ??\n product['identifier'] ??\n `catalog-product-${index}`,\n ).trim();\n}\n\nfunction getDisplayLabel(\n identifier: string,\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): string {\n return String(\n skuProperties['title'] ??\n productProperties['name'] ??\n productProperties['title'] ??\n skuProperties['name'] ??\n identifier,\n );\n}\n\nfunction getTypeData(\n product: Record<string, unknown>,\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): { customProductType: string; isBundle: boolean } {\n const customProductType = String(\n productProperties['customProductType'] ??\n skuProperties['customProductType'] ??\n '',\n ).trim();\n const normalizedType = String(\n product['type'] ??\n productProperties['producttype'] ??\n skuProperties['producttype'] ??\n '',\n )\n .trim()\n .toLowerCase();\n return {\n customProductType,\n isBundle:\n normalizedType === 'bundle' ||\n customProductType.toLowerCase().includes('bundle'),\n };\n}\n\nfunction getNavigationUrls(\n productProperties: Record<string, unknown>,\n skuProperties: Record<string, unknown>,\n): { navigableUrl: string | null; slug: string | null } {\n const slug =\n String(\n skuProperties['slug'] ?? productProperties['slug'] ?? '',\n ).trim() || null;\n const navigableUrl =\n String(\n skuProperties['url'] ??\n skuProperties['href'] ??\n productProperties['url'] ??\n productProperties['href'] ??\n '',\n ).trim() || null;\n return { navigableUrl, slug };\n}\n\nfunction isOutOfStock(inventoryStatus: unknown): boolean {\n return String(inventoryStatus).toUpperCase() === 'OUT OF STOCK';\n}\n\nfunction getCatalogStatusFields(\n skuProperties: Record<string, unknown>,\n productProperties: Record<string, unknown>,\n): {\n normalizedProductStatus: string;\n normalizedSkuStatus: string;\n outOfStock: boolean;\n cartActionDisabled: boolean;\n} {\n const inventoryStatus =\n skuProperties['inventoryStatus'] ??\n productProperties['inventoryStatus'] ??\n '';\n const productStatus =\n skuProperties['productStatus'] ??\n productProperties['productStatus'] ??\n '';\n const skuStatus =\n skuProperties['status'] ?? productProperties['status'] ?? '';\n const normalizedProductStatus = String(productStatus).trim();\n const normalizedSkuStatus = String(skuStatus).trim();\n const outOfStock = isOutOfStock(inventoryStatus);\n\n return {\n normalizedProductStatus,\n normalizedSkuStatus,\n outOfStock,\n cartActionDisabled: isCartActionDisabled({\n outOfStock,\n productStatus: normalizedProductStatus || undefined,\n status: normalizedSkuStatus || undefined,\n }),\n };\n}\n\nfunction optionalNonEmptyString(value: string): string | undefined {\n const normalized = String(value ?? '').trim();\n return normalized || undefined;\n}\n\nfunction getProductImageSrc(opts: {\n product: Record<string, unknown>;\n productProperties: Record<string, unknown>;\n skuProperties: Record<string, unknown>;\n}): string {\n const normalizedType = String(opts.product['type'] ?? '')\n .trim()\n .toLowerCase();\n\n if (normalizedType === 'kit' || normalizedType === 'bundle') {\n return getImageFromProperty(opts.productProperties);\n }\n\n return getImageFromProperty(opts.skuProperties);\n}\n\n/**\n * Maps a raw Equinox catalog product object to the normalized\n * `CatalogSuggestionItem` shape consumed by the UI components.\n * Returns `null` for invalid input so callers can `.filter(Boolean)`.\n */\nexport function mapCatalogProductToSuggestion(\n product: unknown,\n index: number = 0,\n): CatalogSuggestionItem | null {\n if (!product || typeof product !== 'object') {\n return null;\n }\n\n const p = product as Record<string, unknown>;\n const productProperties =\n (p['properties'] as Record<string, unknown>) ?? {};\n const { defaultSku, skuProperties } = getSkuProperties(p);\n const identifier = getIdentifier(p, defaultSku, index);\n const { customProductType, isBundle } = getTypeData(\n p,\n productProperties,\n skuProperties,\n );\n const { navigableUrl, slug } = getNavigationUrls(\n productProperties,\n skuProperties,\n );\n const statusFields = getCatalogStatusFields(\n skuProperties,\n productProperties,\n );\n const imageSrc = resolveSuggestionImageSrc(\n getProductImageSrc({ product: p, productProperties, skuProperties }),\n );\n const mappedProductType: ProductType = isBundle ? 'bundle' : 'single';\n\n return {\n id: identifier,\n identifier,\n sku: identifier,\n label: getDisplayLabel(identifier, productProperties, skuProperties),\n value: getDisplayLabel(identifier, productProperties, skuProperties),\n imageURL: imageSrc,\n thumbnail: imageSrc,\n productType: mappedProductType,\n product_type: mappedProductType,\n outOfStock: statusFields.outOfStock,\n productStatus: optionalNonEmptyString(\n statusFields.normalizedProductStatus,\n ),\n status: optionalNonEmptyString(statusFields.normalizedSkuStatus),\n cartActionDisabled: statusFields.cartActionDisabled,\n customProductType,\n slug,\n productSlug: slug,\n url: navigableUrl,\n href: navigableUrl,\n keywords: String(\n (productProperties['keyword'] as unknown) ??\n (skuProperties['keyword'] as unknown) ??\n '',\n ),\n ingredientTerms: getIngredientTerms(\n skuProperties['ingredients'] ?? productProperties['ingredients'],\n ),\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Did-you-mean normalization */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Normalizes the raw `didYouMean` / `did_you_mean` array from the Equinox\n * API into a consistent shape consumed by `useSearchSuggestions`.\n */\nexport function normalizeDidYouMean(didYouMean: unknown): DidYouMeanItem[] {\n if (!Array.isArray(didYouMean)) {\n return [];\n }\n\n return didYouMean\n .map((item: unknown, index: number): DidYouMeanItem | null => {\n if (typeof item === 'string') {\n return {\n id: `did-you-mean-${index}-${item}`,\n value: item,\n suggestionType: 'did-you-mean',\n };\n }\n\n if (item && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n return {\n ...obj,\n id: String(\n obj['id'] ??\n `did-you-mean-${index}-${obj['value'] ?? obj['label'] ?? ''}`,\n ),\n value: String(obj['value'] ?? ''),\n suggestionType: 'did-you-mean',\n };\n }\n\n return null;\n })\n .filter((item): item is DidYouMeanItem => item !== null);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Suggestion list helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Returns the items that should actually be rendered in the suggestions list.\n * When \"Did You Mean?\" results are present they take precedence over product\n * suggestions.\n */\nexport function getVisibleSuggestions(opts: {\n didYouMean: DidYouMeanItem[];\n suggestions: CatalogSuggestionItem[];\n}): DidYouMeanItem[] | CatalogSuggestionItem[] {\n if (opts.didYouMean.length > 0) {\n return opts.didYouMean;\n }\n return opts.suggestions;\n}\n\n/**\n * Builds the analytics payload emitted when the user clicks \"See More Results\".\n */\nexport function getSeeMoreResultsPayload(\n query: string,\n totalResultsCount: number,\n suggestions: CatalogSuggestionItem[],\n): {\n query: string;\n source: string;\n totalResultsCount: number;\n visibleResultsCount: number;\n} {\n return {\n query,\n source: 'autocomplete-footer',\n totalResultsCount,\n visibleResultsCount: suggestions.length,\n };\n}\n","/**\n * useSearchSuggestions: the typeahead's state.\n * - Requests are debounced by `DEBOUNCE_MS`, and a response that is no longer the latest\n * request is ignored\n * - `maxSuggestions` caps the products shown\n * - `didYouMean` items take precedence: when present, `suggestions` is `[]`\n * - `emptyFetched` is `true` only when both lists are empty after a fetch, and a failed fetch\n * sets `suggestionFetchFailed` as well\n * - `enabled = false` clears state without calling the API\n *\n * Keyboard navigation and the display-data helpers live in `react-search-components`, because\n * they depend on DOM refs and component props.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { DEBOUNCE_MS, DEFAULT_MAX_SUGGESTIONS } from '../constants';\nimport {\n mapCatalogProductToSuggestion,\n normalizeDidYouMean,\n} from '../utils/catalogHelpers';\nimport type { SearchService } from '../services/SearchApiService';\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n SuggestionsResponse,\n} from '../types';\n\n/** Options accepted by `useSearchSuggestions`. */\nexport interface UseSearchSuggestionsOptions {\n /** The search service `CommerceSearch` creates. */\n service: SearchService;\n /**\n * When `false` the hook clears state and skips all API calls.\n * Useful for suppressing suggestions while the user is typing a question.\n * Defaults to `true`.\n */\n enabled?: boolean;\n /**\n * How many products show. Keep it equal to the `maxSuggestions` the `service` was created\n * with, which is how many it asks the catalog for. Defaults to `DEFAULT_MAX_SUGGESTIONS`.\n */\n maxSuggestions?: number;\n}\n\n/** State and actions returned by `useSearchSuggestions`. */\nexport interface UseSearchSuggestionsResult {\n /**\n * Resets the query to `\"\"` and clears all suggestions state.\n * Call when the user clicks the Clear button.\n */\n clearQuery: () => void;\n /**\n * `true` after a fetch completes with an empty result set.\n * Use this to show a \"No suggestions\" message.\n */\n emptyFetched: boolean;\n /** `true` when the server has more matches than `maxSuggestions`. */\n hasMoreResults: boolean;\n /** `true` when the latest suggestions request failed. */\n suggestionFetchFailed: boolean;\n /** Normalized \"Did You Mean?\" items from the API. */\n didYouMean: DidYouMeanItem[];\n /** `true` while a debounced fetch is in flight. */\n loading: boolean;\n /** The current query string (unmodified, as typed by the user). */\n query: string;\n /**\n * The trimmed query the current results (or failure) belong to; `\"\"` until a\n * fetch has finished. Compare with `query.trim()` to know whether the\n * results on screen are for the term the user has typed.\n */\n settledQuery: string;\n /** Normalized product suggestion items from the catalog API. */\n suggestions: CatalogSuggestionItem[];\n /**\n * Preferred setter — updates `query`, optimistically sets `loading`, and\n * clears `emptyFetched` before the debounce fires.\n */\n updateQuery: (query: string) => void;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Internal normalization */\n/* -------------------------------------------------------------------------- */\n\ninterface NormalizedSuggestions {\n suggestions: CatalogSuggestionItem[];\n didYouMean: DidYouMeanItem[];\n}\n\nfunction normalizeSuggestionsResponse(\n response: SuggestionsResponse | unknown,\n): NormalizedSuggestions {\n // Raw array fallback (some API variants return an array directly)\n if (Array.isArray(response)) {\n return {\n suggestions: response as CatalogSuggestionItem[],\n didYouMean: [],\n };\n }\n\n if (!response || typeof response !== 'object') {\n return { suggestions: [], didYouMean: [] };\n }\n\n const r = response as SuggestionsResponse;\n\n // Equinox catalog API returns a `product` array\n if (Array.isArray(r.product)) {\n return {\n suggestions: (r.product as unknown[])\n .map((product, index) =>\n mapCatalogProductToSuggestion(product, index),\n )\n .filter((item): item is CatalogSuggestionItem => item !== null),\n didYouMean: normalizeDidYouMean(r.didYouMean ?? r.did_you_mean),\n };\n }\n\n // Generic suggestions array fallback\n return {\n suggestions: Array.isArray(r.suggestions)\n ? (r.suggestions as CatalogSuggestionItem[])\n : [],\n didYouMean: normalizeDidYouMean(r.didYouMean),\n };\n}\n\n/** The total the API reports: `totalResultsCount`, else the pageable total, else what came back. */\nfunction resolveTotalResultsCount(\n response: SuggestionsResponse,\n fallback: number,\n): number {\n if (typeof response.totalResultsCount === 'number') {\n return response.totalResultsCount;\n }\n if (typeof response.pageableInfo?.totalCount === 'number') {\n return response.pageableInfo.totalCount;\n }\n return fallback;\n}\n\n/** What the panel shows once a request has finished. */\ninterface SettledResults {\n suggestions: CatalogSuggestionItem[];\n didYouMean: DidYouMeanItem[];\n hasMoreResults: boolean;\n emptyFetched: boolean;\n failed: boolean;\n}\n\n/** A request that failed looks like no results, but says it failed, so a caller can tell. */\nconst FETCH_FAILED: SettledResults = {\n suggestions: [],\n didYouMean: [],\n hasMoreResults: false,\n emptyFetched: true,\n failed: true,\n};\n\n/**\n * What to show for the API's answer. \"Did you mean\" terms replace the products. At most\n * `maxSuggestions` products show, and there are more when the API says so.\n */\nfunction toSettledResults(\n response: SuggestionsResponse,\n maxSuggestions: number,\n): SettledResults {\n const { suggestions: allSuggestions, didYouMean } =\n normalizeSuggestionsResponse(response);\n\n if (didYouMean.length > 0) {\n return {\n suggestions: [],\n didYouMean,\n hasMoreResults: false,\n emptyFetched: false,\n failed: false,\n };\n }\n\n const total = Math.max(\n resolveTotalResultsCount(response, allSuggestions.length),\n allSuggestions.length,\n );\n const suggestions = allSuggestions.slice(0, maxSuggestions);\n return {\n suggestions,\n didYouMean,\n hasMoreResults: total > maxSuggestions,\n emptyFetched: suggestions.length === 0,\n failed: false,\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Hook */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Manages debounced typeahead suggestions from the Equinox catalog API.\n *\n * @example\n * ```tsx\n * const service = createSearchService({ country, language, getMarketConfig });\n * const { suggestions, didYouMean, loading, updateQuery, clearQuery } =\n * useSearchSuggestions({ service });\n * ```\n */\nexport function useSearchSuggestions({\n service,\n enabled = true,\n maxSuggestions = DEFAULT_MAX_SUGGESTIONS,\n}: UseSearchSuggestionsOptions): UseSearchSuggestionsResult {\n const [query, setQuery] = useState('');\n const [suggestions, setSuggestions] = useState<CatalogSuggestionItem[]>([]);\n const [didYouMean, setDidYouMean] = useState<DidYouMeanItem[]>([]);\n const [loading, setLoading] = useState(false);\n const [emptyFetched, setEmptyFetched] = useState(false);\n const [suggestionFetchFailed, setSuggestionFetchFailed] = useState(false);\n const [hasMoreResults, setHasMoreResults] = useState(false);\n const [settledQuery, setSettledQuery] = useState('');\n\n const fetchDebounced = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestRequestId = useRef(0);\n\n const resetSuggestionsState = useCallback(() => {\n setSuggestions([]);\n setDidYouMean([]);\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n setHasMoreResults(false);\n setSettledQuery('');\n setLoading(false);\n }, []);\n\n const updateQuery = useCallback(\n (nextQuery: string) => {\n const hasNextQuery = Boolean(nextQuery.trim());\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n setLoading(enabled && hasNextQuery);\n setQuery(nextQuery);\n },\n [enabled],\n );\n\n const clearQuery = useCallback(() => {\n resetSuggestionsState();\n setQuery('');\n }, [resetSuggestionsState]);\n\n const settle = useCallback((results: SettledResults, term: string) => {\n setDidYouMean(results.didYouMean);\n setSuggestions(results.suggestions);\n setHasMoreResults(results.hasMoreResults);\n setSuggestionFetchFailed(results.failed);\n setSettledQuery(term);\n setEmptyFetched(results.emptyFetched);\n }, []);\n\n const runFetch = useCallback(\n async (nextQuery: string) => {\n const trimmedQuery = nextQuery.trim();\n const requestId = latestRequestId.current;\n\n if (!trimmedQuery || !enabled) {\n resetSuggestionsState();\n return;\n }\n\n setLoading(true);\n setEmptyFetched(false);\n setSuggestionFetchFailed(false);\n\n let results: SettledResults;\n try {\n results = toSettledResults(\n await service.fetchSuggestions(trimmedQuery),\n maxSuggestions,\n );\n } catch (error) {\n console.warn('[search] Could not load suggestions:', error);\n results = FETCH_FAILED;\n }\n\n // Discard a stale answer if a newer request has since been issued.\n if (requestId !== latestRequestId.current) return;\n\n settle(results, trimmedQuery);\n setLoading(false);\n },\n [enabled, maxSuggestions, service, resetSuggestionsState, settle],\n );\n\n useEffect(() => {\n // Any request still in flight is stale now, whether or not another one follows: when the\n // hook is disabled its late answer must not fill in the results.\n latestRequestId.current += 1;\n\n if (!enabled) {\n resetSuggestionsState();\n return undefined;\n }\n\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n\n fetchDebounced.current = setTimeout(() => {\n void runFetch(query);\n }, DEBOUNCE_MS);\n\n return () => {\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n };\n }, [enabled, query, resetSuggestionsState, runFetch]);\n\n return {\n clearQuery,\n emptyFetched,\n hasMoreResults,\n didYouMean,\n loading,\n query,\n settledQuery,\n suggestionFetchFailed,\n suggestions,\n updateQuery,\n };\n}\n","/**\n * Generic browser helpers shared across SDK utilities.\n * Nothing here should be GTM-specific — keep this file free of tracker logic.\n */\n\nexport const IS_BROWSER = typeof window !== 'undefined';\n\n/**\n * Coerces a value to a trimmed string for use in analytics payloads.\n * Empty / nullish input returns `fallback` (default: single space, matching\n * the placeholder convention the data team specified).\n */\nexport function toEventString(\n value: string | number | undefined | null,\n fallback = ' ',\n): string {\n if (value === undefined || value === null) return fallback;\n const str = String(value).trim();\n return str.length > 0 ? str : fallback;\n}\n","/**\n * GTM (Google Tag Manager) dataLayer tracking for the AI Chat Bot.\n *\n * Implements the events specified in COMX-3277:\n * 1. Begin_chat - user initiates the AI chat from an entry point\n * 2. Search_Type - user submits a query in the AI chat\n * 3. ProductSearch - AI chat returns product results (fires even on 0)\n * 4. Error_popup - API errors / unhandled exceptions during a session\n *\n * The SDK's components call these helpers instead of touching `window.dataLayer` directly, so\n * that payload shape and error handling stay consistent.\n *\n * Types live in `./gtmTypes`, constants in `./gtmConstants`, and generic helpers in\n * `./commonUtils`.\n */\n\nimport { IS_BROWSER, toEventString } from './commonUtils';\nimport {\n GTM_FALLBACK_NA,\n SEARCH_GTM_EVENTS,\n SEARCH_GTM_SEARCH_TYPES,\n SEARCH_GTM_USER_STATUS,\n} from './gtmConstants';\nimport type {\n ErrorPopupEventInput,\n ProductSearchEventInput,\n SearchGtmContext,\n SearchTypeEventInput,\n} from './gtmTypes';\n\n/* -------------------------------------------------------------------------- */\n/* Re-exports so `./gtmTracking` remains the single public entry point */\n/* -------------------------------------------------------------------------- */\n\nexport {\n SEARCH_GTM_EVENTS,\n SEARCH_GTM_SEARCH_TYPES,\n SEARCH_GTM_USER_STATUS,\n} from './gtmConstants';\nexport type {\n ErrorPopupEventInput,\n ProductSearchEventInput,\n SearchGtmContext,\n SearchGtmSearchType,\n SearchGtmUserStatus,\n SearchTypeEventInput,\n} from './gtmTypes';\n\n/** The GTM `id` field: the user id the host supplied, or `'NA'`. */\nfunction resolveUserId(explicit: string | undefined): string {\n return toEventString(explicit, GTM_FALLBACK_NA);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Base payload + dataLayer push */\n/* -------------------------------------------------------------------------- */\n\nfunction baseEventPayload(ctx: SearchGtmContext): Record<string, string> {\n return {\n Chat_ID: toEventString(ctx.chatId, GTM_FALLBACK_NA),\n // TODO: COMX-3277 puts `page_type` in every event but defines no values. Send `NA` until\n // the data team says what it should hold (perhaps the page path).\n page_type: GTM_FALLBACK_NA,\n country_code: toEventString(ctx.countryCode, GTM_FALLBACK_NA),\n language: toEventString(ctx.language, GTM_FALLBACK_NA),\n user_status: toEventString(\n ctx.userStatus ?? SEARCH_GTM_USER_STATUS.GUEST,\n SEARCH_GTM_USER_STATUS.GUEST,\n ),\n account_type: toEventString(ctx.accountType, GTM_FALLBACK_NA),\n };\n}\n\nfunction serializeProductResults(\n productResultsData: unknown,\n productResults?: number,\n): string {\n if (productResultsData !== undefined) {\n try {\n return JSON.stringify(productResultsData);\n } catch {\n return GTM_FALLBACK_NA;\n }\n }\n\n if (productResults === undefined || productResults === null) {\n return GTM_FALLBACK_NA;\n }\n\n return String(productResults);\n}\n\n/**\n * Pushes a raw event object onto `window.dataLayer`.\n *\n * Silently no-ops when `window` is unavailable (SSR) or the dataLayer is\n * missing - GTM tag firing is a best-effort side effect, never a blocker for\n * the search flow.\n */\nexport function pushGtmEvent(event: Record<string, unknown>): void {\n if (!IS_BROWSER) return;\n try {\n const layer = (window.dataLayer ??= []);\n layer.push(event);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.warn('[react-search-sdk] pushGtmEvent failed:', err);\n }\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Event trackers */\n/* -------------------------------------------------------------------------- */\n\n/** Fires `Begin_chat` when the user initiates the AI chat. */\nexport function trackChatEntryPoint(ctx: SearchGtmContext): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.CHAT_ENTRY_POINT,\n ...baseEventPayload(ctx),\n });\n}\n\n/** Fires `Search_Type` when the user submits a query in the AI chat. */\nexport function trackSearchType(input: SearchTypeEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.SEARCH_TYPE,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n search_response: toEventString(input.searchResponse, GTM_FALLBACK_NA),\n });\n}\n\n/**\n * Fires `ProductSearch` when the AI chat returns results.\n * Must be called even when 0 products are returned.\n */\nexport function trackProductSearch(input: ProductSearchEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.PRODUCT_SEARCH,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n search_type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n Product_results: serializeProductResults(\n input.productResultsData,\n input.productResults,\n ),\n });\n}\n\n/** Fires `Error_popup` for API errors and unhandled exceptions during chat. */\nexport function trackErrorPopup(input: ErrorPopupEventInput): void {\n pushGtmEvent({\n event: SEARCH_GTM_EVENTS.ERROR_POPUP,\n ...baseEventPayload(input),\n id: resolveUserId(input.userId),\n search_type: input.searchType ?? SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n });\n}\n","/**\n * Routing between Solr search and the NUi agent.\n *\n * Rule: when the shopper submits a search and the typeahead response for that\n * exact term shows no products, the NUi widget takes over in the same panel.\n * Anything else stays plain search. A pure function, so a smarter intent\n * heuristic can replace it later without touching any UI.\n */\n\nimport type { UseSearchSuggestionsResult } from '../hooks/useSearchSuggestions';\n\n/**\n * - `search` — stay on Solr search (submit behaves as it does today).\n * - `handoff` — hand the query to the NUi agent.\n * - `wait` — the typeahead for this term has not settled yet; ask again when\n * the snapshot changes. Callers should apply their own timeout and\n * fall back to `search`, so a slow request never blocks a submit.\n */\nexport type SearchRoute = 'search' | 'handoff' | 'wait';\n\n/** The slice of `useSearchSuggestions` state the rule reads. */\nexport type RoutingSnapshot = Pick<\n UseSearchSuggestionsResult,\n | 'query'\n | 'loading'\n | 'settledQuery'\n | 'suggestions'\n | 'suggestionFetchFailed'\n>;\n\nexport interface DecideSearchRouteInput {\n /** Whether NUi search is on for this visitor (see `isNuiSearchEnabled`). */\n enabled: boolean;\n snapshot: RoutingSnapshot;\n}\n\n/**\n * Decides what a submitted search does.\n *\n * \"No products\" means the hook has nothing to show for the term. A response\n * that only offers \"did you mean\" terms counts as no products: the hook hides\n * the products in that case, so the shopper sees none either. A failed request\n * is not \"no products\": an outage must not send every shopper to the agent.\n */\nexport function decideSearchRoute({\n enabled,\n snapshot,\n}: DecideSearchRouteInput): SearchRoute {\n const term = snapshot.query.trim();\n if (!enabled || !term) return 'search';\n\n // The results on screen must belong to the term being submitted.\n if (snapshot.loading || snapshot.settledQuery !== term) return 'wait';\n\n if (snapshot.suggestionFetchFailed) return 'search';\n\n return snapshot.suggestions.length > 0 ? 'search' : 'handoff';\n}\n","import { useCallback, useEffect, useRef } from 'react';\nimport { trackChatEntryPoint } from '../utils/gtmTracking';\nimport type { SearchGtmContext } from '../utils/gtmTypes';\nimport { decideSearchRoute } from '../utils/searchRouting';\nimport type { SearchRoute } from '../utils/searchRouting';\nimport type { UseSearchSuggestionsResult } from './useSearchSuggestions';\n\n/** How long a submit waits for the typeahead of that exact term before it stays on search. */\nexport const SUBMIT_WAIT_TIMEOUT_MS = 2000;\n\n/** How the agent starts: what was submitted, and the \"did you mean\" terms Solr offered for it. */\nexport interface AgentHandoff {\n query: string;\n didYouMean: string[];\n}\n\nexport interface UseSubmitRoutingOptions {\n /** Whether a search may reach the agent (see `useNuiAgentGate`). */\n enabled: boolean;\n /** Terms shorter than this were never looked up, so they never hand off to the agent. */\n minimumSearchLength: number;\n /** What the typeahead shows now. */\n search: Pick<\n UseSearchSuggestionsResult,\n | 'didYouMean'\n | 'loading'\n | 'settledQuery'\n | 'suggestionFetchFailed'\n | 'suggestions'\n >;\n gtmContext?: Omit<SearchGtmContext, 'chatId'>;\n /**\n * The term of a submit that is waiting for the typeahead, or `null`. The caller owns it,\n * because it has to forget it when the panel closes.\n */\n pendingTerm: string | null;\n setPendingTerm: (term: string | null) => void;\n /** The search stays plain: take the shopper to the results for `term`. */\n onSearch: (term: string) => void;\n /** The search goes to the agent. */\n onHandoff: (handoff: AgentHandoff) => void;\n}\n\n/**\n * Decides what a submitted search does: plain search, the agent, or wait. A submit that beat the\n * typeahead waits for it to settle and decides again. If it never settles, the shopper gets plain\n * search rather than a stuck panel. Returns the submit handler.\n */\nexport function useSubmitRouting({\n enabled,\n minimumSearchLength,\n search,\n gtmContext,\n pendingTerm,\n setPendingTerm,\n onSearch,\n onHandoff,\n}: UseSubmitRoutingOptions): (value: string) => void {\n const {\n didYouMean,\n loading,\n settledQuery,\n suggestionFetchFailed,\n suggestions,\n } = search;\n\n const decide = useCallback(\n (term: string): SearchRoute =>\n decideSearchRoute({\n enabled,\n snapshot: {\n query: term,\n loading,\n settledQuery,\n suggestions,\n suggestionFetchFailed,\n },\n }),\n [enabled, loading, settledQuery, suggestions, suggestionFetchFailed],\n );\n\n const act = useCallback(\n (term: string, route: SearchRoute) => {\n setPendingTerm(null);\n if (route === 'handoff') {\n trackChatEntryPoint(gtmContext ?? {});\n onHandoff({\n query: term,\n didYouMean: didYouMean.map((item) => item.value),\n });\n return;\n }\n onSearch(term);\n },\n [didYouMean, gtmContext, onHandoff, onSearch, setPendingTerm],\n );\n\n const submit = useCallback(\n (value: string) => {\n const term = value.trim();\n if (!term) return;\n // Too short for the typeahead to have looked: plain search, never the agent.\n if (term.length < minimumSearchLength) {\n onSearch(term);\n return;\n }\n const route = decide(term);\n if (route === 'wait') {\n setPendingTerm(term);\n return;\n }\n act(term, route);\n },\n [act, decide, minimumSearchLength, onSearch, setPendingTerm],\n );\n\n // The waiting effect below runs after this one, in the same commit, so it sees the latest.\n const latest = useRef({ act, decide });\n useEffect(() => {\n latest.current = { act, decide };\n });\n\n useEffect(() => {\n if (pendingTerm === null) return undefined;\n const route = latest.current.decide(pendingTerm);\n if (route !== 'wait') {\n latest.current.act(pendingTerm, route);\n return undefined;\n }\n const timer = setTimeout(\n () => latest.current.act(pendingTerm, 'search'),\n SUBMIT_WAIT_TIMEOUT_MS,\n );\n return () => clearTimeout(timer);\n }, [\n pendingTerm,\n loading,\n settledQuery,\n suggestions,\n suggestionFetchFailed,\n ]);\n\n return submit;\n}\n","import type { ProductClient, ProductData } from '@nuskin/react-product-sdk';\n\n/**\n * Remembers each product lookup for the life of the client, in flight or settled, failures\n * included. The widget re-creates its product cards whenever the conversation re-renders, and a\n * card looks its product up each time it is created: without this, one conversation turns into\n * dozens of identical requests and every card flashes empty while it waits for its own.\n */\nexport function withProductCache(client: ProductClient): ProductClient {\n const lookups = new Map<string, Promise<ProductData | null>>();\n\n return {\n getProductById(productId) {\n let lookup = lookups.get(productId);\n if (!lookup) {\n lookup = client.getProductById(productId);\n lookups.set(productId, lookup);\n }\n return lookup;\n },\n getProductsByIds: (productIds) => client.getProductsByIds(productIds),\n };\n}\n","import styled from '@emotion/styled';\n\n/**\n * The slot every product card sits in: the same width for all of them, so a row looks even\n * whatever the size of its product's image.\n */\nexport const AgentProductSlot = styled.div`\n && {\n flex: 0 0 240px;\n overflow: hidden;\n width: 240px;\n }\n`;\n","import { Component, useEffect, useMemo, useRef } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SalesAIChatWidget } from '@nuskin/react-nui-chat-sdk';\nimport type { SalesAIChatWidgetProps } from '@nuskin/react-nui-chat-sdk';\nimport '@nuskin/react-nui-chat-sdk/styles.css';\nimport {\n ProductCard,\n ProductProvider,\n createProductClient,\n useProductById,\n} from '@nuskin/react-product-sdk';\nimport type { ProductClientConfig } from '@nuskin/react-product-sdk';\nimport { withProductCache } from '../../utils/cachedProductClient';\nimport { AgentProductSlot } from './NuiAgentPanel.styled';\n\n/** How often to look for the widget's `window.SalesAI` handle while it starts. */\nconst HANDLE_POLL_MS = 50;\n/** How long to wait for the widget to register its handle before giving up and falling back to plain search. */\nconst HANDLE_TIMEOUT_MS = 15000;\n\n/** Where the agent's product cards are looked up: the product SDK's environment, market and language. */\nexport type AgentProductsConfig = Pick<\n ProductClientConfig,\n 'environment' | 'market' | 'language'\n>;\n\ninterface AgentWidgetProps {\n widgetProps: SalesAIChatWidgetProps;\n products?: AgentProductsConfig;\n}\n\n/**\n * The product SDK's card in a slot of the same width for every product, whatever the size of its\n * image. A product that cannot be shown (not found, failed, or with nowhere to link to) leaves no\n * gap. Defined once, at module level: the widget remounts a card whose component type changes, and\n * a remounted card would look its product up again.\n */\nfunction AgentProductCard({ sku }: Readonly<{ sku: string }>) {\n const { product, isLoading, error } = useProductById(sku);\n if (!isLoading && (error || !product?.seoInformation?.canonicalURL)) {\n return null;\n }\n return (\n <AgentProductSlot>\n <ProductCard productId={sku} />\n </AgentProductSlot>\n );\n}\n\nconst renderAgentProduct: NonNullable<\n SalesAIChatWidgetProps['renderProduct']\n> = (product) => <AgentProductCard sku={product.sku} />;\n\n/**\n * The NUi widget. With `products`, the product SDK draws the agent's product cards (looked up by\n * the SKU the agent sends) in place of the widget's own.\n */\nfunction AgentWidget({\n widgetProps,\n products,\n}: Readonly<AgentWidgetProps>): ReactElement {\n const environment = products?.environment;\n const market = products?.market;\n const language = products?.language;\n const client = useMemo(\n () =>\n environment && market && language\n ? withProductCache(\n createProductClient({ environment, market, language }),\n )\n : undefined,\n [environment, market, language],\n );\n\n if (!client) {\n return <SalesAIChatWidget {...widgetProps} />;\n }\n return (\n <ProductProvider client={client}>\n <SalesAIChatWidget\n renderProduct={renderAgentProduct}\n {...widgetProps}\n />\n </ProductProvider>\n );\n}\n\n/** The imperative handle the widget registers on `window` (see the widget's `open` options). */\ninterface SalesAIHandle {\n open: (options?: {\n query?: string;\n context?: Record<string, unknown> | null;\n }) => void;\n}\n\nfunction getSalesAIHandle(): SalesAIHandle | undefined {\n return (window as Window & { SalesAI?: SalesAIHandle }).SalesAI;\n}\n\n/** How the host's NUi app is reached and presented. */\nexport interface NuiAgentConfig {\n /** The NUi app key for the search surface. */\n appKey: string;\n /** Origin of the NUi API. */\n apiBaseUrl: string;\n /** UI language, e.g. `en-US`. */\n language?: string;\n /** Widget theme. Defaults to `nui-light`. */\n theme?: SalesAIChatWidgetProps['theme'];\n /** Context sent with every turn of the conversation, under the handoff context. */\n context?: Record<string, unknown>;\n}\n\nexport interface NuiAgentPanelProps {\n agent: NuiAgentConfig;\n /** The search the shopper submitted; sent to the agent as the first message. */\n query: string;\n /** Describes how the conversation started; layered over `agent.context`. */\n handoffContext: Record<string, unknown>;\n /** Draws the agent's product recommendations with the product SDK's cards. Absent: the widget's own. */\n products?: AgentProductsConfig;\n /** Called when the agent cannot be shown, so the host can fall back to plain search. */\n onUnavailable: () => void;\n}\n\ninterface BoundaryProps {\n children: ReactNode;\n onError: () => void;\n}\n\n/** Turns a failure to load or render the widget into a fallback instead of a broken panel. */\nclass AgentErrorBoundary extends Component<BoundaryProps, { failed: boolean }> {\n override state = { failed: false };\n\n static getDerivedStateFromError() {\n return { failed: true };\n }\n\n override componentDidCatch(error: Error) {\n console.warn('[search] The agent could not be shown:', error);\n this.props.onError();\n }\n\n override render() {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/** Hands the submitted query to the widget once its handle is available. */\nfunction useHandoff({\n query,\n handoffContext,\n agentContext,\n onUnavailable,\n}: {\n query: string;\n handoffContext: Record<string, unknown>;\n agentContext: Record<string, unknown> | undefined;\n onUnavailable: () => void;\n}) {\n // The fallback runs up to `HANDLE_TIMEOUT_MS` after the handoff starts: use the latest one.\n const onUnavailableRef = useRef(onUnavailable);\n useEffect(() => {\n onUnavailableRef.current = onUnavailable;\n });\n\n useEffect(() => {\n let canceled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const startedAt = Date.now();\n\n const tryOpen = () => {\n if (canceled) return;\n const handle = getSalesAIHandle();\n if (handle) {\n handle.open({\n query,\n context: { ...agentContext, ...handoffContext },\n });\n return;\n }\n if (Date.now() - startedAt >= HANDLE_TIMEOUT_MS) {\n console.warn(\n `[search] The agent did not start within ${HANDLE_TIMEOUT_MS / 1000} seconds.`,\n );\n onUnavailableRef.current();\n return;\n }\n timer = setTimeout(tryOpen, HANDLE_POLL_MS);\n };\n\n tryOpen();\n return () => {\n canceled = true;\n if (timer !== undefined) clearTimeout(timer);\n };\n // The handoff happens once per submitted query.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [query]);\n}\n\n/** The NUi widget, mounted in the search panel and handed the shopper's query. */\nexport function NuiAgentPanel({\n agent,\n query,\n handoffContext,\n products,\n onUnavailable,\n}: Readonly<NuiAgentPanelProps>): ReactElement {\n useHandoff({\n query,\n handoffContext,\n agentContext: agent.context,\n onUnavailable,\n });\n\n const widgetProps: SalesAIChatWidgetProps = {\n appKey: agent.appKey,\n apiBaseUrl: agent.apiBaseUrl,\n theme: agent.theme ?? 'nui-light',\n defaultOpen: true,\n hideFab: true,\n placement: 'host',\n ...(agent.language === undefined ? {} : { language: agent.language }),\n };\n\n return (\n <AgentErrorBoundary onError={onUnavailable}>\n <AgentWidget\n widgetProps={widgetProps}\n {...(products ? { products } : {})}\n />\n </AgentErrorBoundary>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchPanel } from '@nuskin/react-search-components';\nimport type { SearchPanelCopy } from '@nuskin/react-search-components';\nimport { useNuiAgentGate } from '../../hooks/useNuiAgentGate';\nimport { useRecentSearches } from '../../hooks/useRecentSearches';\nimport { useSearchSuggestions } from '../../hooks/useSearchSuggestions';\nimport { useSubmitRouting } from '../../hooks/useSubmitRouting';\nimport type { AgentHandoff } from '../../hooks/useSubmitRouting';\nimport type { SearchService } from '../../services/SearchApiService';\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n SuggestionOption,\n} from '../../types';\nimport { getVisibleSuggestions } from '../../utils/catalogHelpers';\nimport { isSuggestionDisabled } from '../../utils/catalogStatus';\nimport {\n DEFAULT_MAX_SUGGESTIONS,\n MINIMUM_SEARCH_CHAR_LENGTH,\n} from '../../constants';\nimport { SEARCH_GTM_SEARCH_TYPES } from '../../utils/gtmConstants';\nimport { trackProductSearch } from '../../utils/gtmTracking';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport { NuiAgentPanel } from './NuiAgentPanel';\nimport type { AgentProductsConfig, NuiAgentConfig } from './NuiAgentPanel';\n\n/** A row the modal shows: a product, or a \"did you mean\" term. */\ntype VisibleSuggestion = CatalogSuggestionItem | DidYouMeanItem;\n\nexport interface CommerceSearchViewProps {\n isOpen: boolean;\n onClose: () => void;\n /** From `createSearchService`. Keep its identity stable (memoize it). */\n service: SearchService;\n /** Takes the shopper to a path, using the host's router. The panel closes afterwards. */\n navigate: (path: string) => void;\n /** The NUi app the agent runs on. Without it the agent never shows and search stays plain. */\n agent?: NuiAgentConfig;\n /** Whether the configuration enables the agent for this visitor's kind of customer. */\n agentEnabledForCustomer: boolean;\n /** Draws the agent's product recommendations with the product SDK's cards. Absent: the widget's own. */\n agentProducts?: AgentProductsConfig;\n /** All of the panel's text, already loaded. */\n copy: SearchPanelCopy;\n logo?: ReactNode;\n /**\n * Terms shorter than this never hand off to the agent. Keep it equal to the\n * `minimumSearchLength` the `service` was created with. Defaults to\n * `MINIMUM_SEARCH_CHAR_LENGTH`.\n */\n minimumSearchLength?: number;\n /**\n * How many suggestions show. Keep it equal to the `maxSuggestions` the `service` was created\n * with. Defaults to `DEFAULT_MAX_SUGGESTIONS`.\n */\n maxSuggestions?: number;\n /** Host-known values for the search analytics events. */\n gtmContext?: Omit<SearchGtmContext, 'chatId'>;\n}\n\n/**\n * Product search with an agent fallback, for a `service` and `agent` the caller already has.\n * `CommerceSearch` is the entry point that reads the configuration and builds them.\n *\n * Shows Solr typeahead and recent searches in the library's `SearchPanel`. When a shopper the agent\n * is enabled for submits a term whose typeahead shows no products, the NUi agent takes over in the\n * same panel with that term as the first message. Everything else behaves as plain search.\n */\nexport function CommerceSearchView({\n copy,\n isOpen,\n onClose,\n service,\n navigate,\n agent,\n agentEnabledForCustomer,\n agentProducts,\n logo,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n maxSuggestions = DEFAULT_MAX_SUGGESTIONS,\n gtmContext,\n}: Readonly<CommerceSearchViewProps>): ReactElement {\n // The view owns these two, not `useSubmitRouting`: the typeahead is switched off during an\n // agent session, so it needs `agentQuery` before routing can read what the typeahead shows.\n const [handoff, setHandoff] = useState<AgentHandoff | null>(null);\n const agentQuery = handoff?.query ?? null;\n const [pendingTerm, setPendingTerm] = useState<string | null>(null);\n\n const search = useSearchSuggestions({\n service,\n maxSuggestions,\n enabled: isOpen && agentQuery === null,\n });\n const {\n clearQuery,\n didYouMean,\n emptyFetched,\n hasMoreResults,\n loading,\n query,\n suggestions,\n updateQuery,\n } = search;\n\n const agentEnabled = useNuiAgentGate({\n hasAgent: agent !== undefined,\n isOpen,\n enabledForCustomer: agentEnabledForCustomer,\n });\n const { recentSearches, clearRecentSearches } = useRecentSearches({\n service,\n isOpen,\n refreshKey: agentQuery,\n });\n const items = getVisibleSuggestions({\n didYouMean,\n suggestions,\n });\n const showDidYouMean = didYouMean.length > 0;\n\n const close = useCallback(() => {\n setHandoff(null);\n setPendingTerm(null);\n clearQuery();\n onClose();\n }, [clearQuery, onClose]);\n\n // The host can also close the panel from outside.\n useEffect(() => {\n if (!isOpen) {\n setHandoff(null);\n setPendingTerm(null);\n clearQuery();\n }\n }, [isOpen, clearQuery]);\n\n /** Navigates and closes. */\n const navigateTo = useCallback(\n (path: string | undefined) => {\n if (!path) return;\n navigate(path);\n close();\n },\n [navigate, close],\n );\n\n const trackSemantic = useCallback(\n (productResultsData: unknown) => {\n trackProductSearch({\n ...gtmContext,\n searchType: SEARCH_GTM_SEARCH_TYPES.SEMANTIC,\n productResultsData,\n });\n },\n [gtmContext],\n );\n\n const runSearch = useCallback(\n (term: string) => {\n trackSemantic(items.length > 0 ? items : { query: term });\n navigateTo(service.submitProductSearch(term));\n },\n [items, navigateTo, service, trackSemantic],\n );\n\n const handleSubmit = useSubmitRouting({\n enabled: agentEnabled,\n minimumSearchLength,\n search,\n ...(gtmContext ? { gtmContext } : {}),\n pendingTerm,\n setPendingTerm,\n onSearch: runSearch,\n onHandoff: setHandoff,\n });\n\n const handleSelect = useCallback(\n (option: VisibleSuggestion) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n const term = String(option['value'] ?? option['label'] ?? '');\n if (term.trim()) trackSemantic([option]);\n\n const suggestionOption = option as unknown as SuggestionOption;\n const href = service.getSuggestionHref(suggestionOption);\n navigateTo(\n href || service.submitProductSearch(term, suggestionOption),\n );\n },\n [navigateTo, service, trackSemantic],\n );\n\n const handleRunAction = useCallback(\n (option: VisibleSuggestion) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n navigateTo(\n service.activateSuggestionAction(\n option as unknown as SuggestionOption,\n ),\n );\n },\n [navigateTo, service],\n );\n\n const handleSeeMore = useCallback(() => {\n const term = query.trim();\n if (term) navigateTo(service.viewMoreResults({ query: term }));\n }, [navigateTo, query, service]);\n\n const handleRecentSelect = useCallback(\n (recentQuery: string) => {\n trackSemantic({ query: recentQuery });\n navigateTo(service.submitProductSearch(recentQuery));\n },\n [navigateTo, service, trackSemantic],\n );\n\n // The agent could not be shown: give the shopper the search they asked for.\n const handleAgentUnavailable = useCallback(() => {\n if (agentQuery !== null)\n navigateTo(service.submitProductSearch(agentQuery));\n }, [agentQuery, navigateTo, service]);\n\n // Built here, not inline, so no ternary nests in another (Sonar S3358).\n let agentPanel: ReactElement | undefined;\n if (handoff !== null && agent !== undefined) {\n agentPanel = (\n <NuiAgentPanel\n agent={agent}\n query={handoff.query}\n handoffContext={{\n source: 'storefront_search',\n trigger: 'zero_results',\n query: handoff.query,\n did_you_mean: handoff.didYouMean,\n }}\n {...(agentProducts ? { products: agentProducts } : {})}\n onUnavailable={handleAgentUnavailable}\n />\n );\n }\n\n return (\n <SearchPanel\n isOpen={isOpen}\n onClose={close}\n copy={copy}\n logo={logo}\n input={{\n value: query,\n onChange: updateQuery,\n onSubmit: handleSubmit,\n }}\n suggestions={{\n items,\n loading,\n showNoResults: !loading && emptyFetched && items.length === 0,\n showDidYouMean,\n hasMore: hasMoreResults,\n query,\n onSelect: handleSelect,\n onRunAction: handleRunAction,\n onSeeMore: handleSeeMore,\n }}\n recentSearches={{\n items: recentSearches,\n onSelect: handleRecentSelect,\n onClear: clearRecentSearches,\n }}\n agentPanel={agentPanel}\n />\n );\n}\n","import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { useCommerceSearchConfig } from '../../hooks/useCommerceSearchConfig';\nimport { useSearchPanelCopy } from '../../hooks/useSearchPanelCopy';\nimport { createSearchService } from '../../services/SearchApiService';\nimport type { AgentEnabledFor } from '../../config/commerceSearchConfig';\nimport { isValidMarket } from '../../services/localeParts';\nimport { fetchMarketConfig } from '../../services/marketConfig';\nimport { SEARCH_GTM_USER_STATUS } from '../../utils/gtmConstants';\nimport type { GetMarketConfig } from '../../types';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport { toNavigationTarget } from '../../utils/navigationTarget';\nimport type { NavigationTarget } from '../../utils/navigationTarget';\nimport { getProductEnvironment } from '../../utils/productEnvironment';\nimport { CommerceSearchUnavailable } from './CommerceSearchUnavailable';\nimport { CommerceSearchView } from './CommerceSearchView';\nimport type { AgentProductsConfig } from './NuiAgentPanel';\n\n/**\n * The account types the suggestions API distinguishes, sent as `X-Customer-Type`.\n *\n * TODO: PA-1254 validates this set, which is a best guess from the values the storefront sends,\n * against the storefront's customer types and what the suggestions API accepts.\n */\nexport type CustomerAccountType =\n | 'guest'\n | 'Brand Affiliate'\n | 'Retail Customer'\n | 'Preferred Customer/Member';\n\n/** Who is searching. */\nexport interface CommerceSearchCustomer {\n /**\n * Whether the visitor is signed in. The NUi agent is for signed-in visitors only, unless the\n * package's configuration allows guests.\n */\n isAuthenticated: boolean;\n /** Defaults to `guest`. Ignored for a visitor who is not signed in. */\n accountType?: CustomerAccountType;\n /** The signed-in visitor's id, for analytics. */\n userId?: string;\n}\n\nexport interface CommerceSearchProps {\n isOpen: boolean;\n onClose: () => void;\n /**\n * Takes the shopper to a destination, using the host's router for an internal path and a\n * full page load for an external URL. The panel closes afterwards.\n */\n navigate: (target: NavigationTarget) => void;\n /** Read on every request, so a change after sign-in is picked up. */\n customer: CommerceSearchCustomer;\n /** ISO 3166-1 alpha-2 market, for example `US`. */\n country: string;\n /** ISO 639-1 language, for example `en`. */\n language: string;\n /**\n * The client id the configuration service knows the host by. Without one the Configuration\n * SDK uses its own (the run config's), and the search's plain suggestions fail where there is\n * none, so a host that cannot rely on the run config should pass it.\n */\n clientId?: string;\n /** Shown at the top of the panel, for example the brand logo. */\n logo?: ReactNode;\n}\n\nconst GUEST: CustomerAccountType = 'guest';\n\n/**\n * Which of the configuration's switches decides for each kind of customer. A record, so that a\n * change to `CustomerAccountType` is a compile error here and not a customer with no switch.\n */\nconst AGENT_SWITCH_FOR: Readonly<\n Record<CustomerAccountType, keyof AgentEnabledFor>\n> = {\n guest: 'guest',\n 'Brand Affiliate': 'brandAffiliate',\n 'Retail Customer': 'retailCustomer',\n 'Preferred Customer/Member': 'preferredCustomer',\n};\n\n/** A map, so that a type like `constructor` is not found on the object's prototype. */\nconst AGENT_SWITCHES = new Map<string, keyof AgentEnabledFor>(\n Object.entries(AGENT_SWITCH_FOR),\n);\n\n/**\n * The commerce website's single search entry point: typeahead and recent searches over the\n * product catalog today, with the NUi agent taking over in the same panel when a shopper the\n * configuration enables it for searches for something with no products. What it can answer is not\n * limited to products — it is the commerce site's search, not a product-only search box.\n *\n * The package works out the rest itself: the market's catalog lookup, the minimum search length\n * and the number of suggestions, which NUi app to use and for whom, the panel's text and the\n * analytics fields.\n */\nexport function CommerceSearch(\n props: Readonly<CommerceSearchProps>,\n): ReactElement | null {\n // Checked before anything starts, so a market that is not valid makes no request and loads no\n // market's configuration.\n if (!isValidMarket(props.country, props.language)) {\n return (\n <CommerceSearchUnavailable\n isOpen={props.isOpen}\n onClose={props.onClose}\n country={props.country}\n language={props.language}\n logo={props.logo}\n />\n );\n }\n return <ValidMarketSearch {...props} />;\n}\n\nfunction ValidMarketSearch({\n isOpen,\n onClose,\n navigate,\n customer,\n country,\n language,\n clientId,\n logo,\n}: Readonly<CommerceSearchProps>): ReactElement | null {\n // Starts when the host mounts the search, not when the panel opens, so the text is ready by then.\n const copy = useSearchPanelCopy({ language });\n\n const { minimumSearchLength, maxSuggestions, agent, agentEnabledFor } =\n useCommerceSearchConfig({\n country,\n language,\n ...(clientId ? { clientId } : {}),\n isOpen,\n });\n\n // Read per request, so a change of customer does not rebuild the service.\n const customerType: CustomerAccountType = customer.isAuthenticated\n ? (customer.accountType ?? GUEST)\n : GUEST;\n const customerTypeRef = useRef<CustomerAccountType>(customerType);\n useEffect(() => {\n customerTypeRef.current = customerType;\n }, [customerType]);\n\n const agentEnabledForCustomer =\n agentEnabledFor[AGENT_SWITCHES.get(customerType) ?? 'guest'];\n\n const getMarketConfig = useCallback<GetMarketConfig>(\n (context) =>\n fetchMarketConfig({\n ...context,\n ...(clientId ? { clientId } : {}),\n }),\n [clientId],\n );\n\n const service = useMemo(\n () =>\n createSearchService({\n country,\n language,\n getMarketConfig,\n minimumSearchLength,\n maxSuggestions,\n getCustomerType: () => customerTypeRef.current,\n }),\n [\n country,\n language,\n getMarketConfig,\n minimumSearchLength,\n maxSuggestions,\n ],\n );\n\n const navigateToPath = useCallback(\n (path: string) => {\n const target = toNavigationTarget(path);\n if (target) {\n navigate(target);\n } else {\n console.warn(\n '[search] Not navigating to a path the SDK does not recognize:',\n path,\n );\n }\n },\n [navigate],\n );\n\n const { isAuthenticated, accountType, userId } = customer;\n const gtmContext = useMemo<Omit<SearchGtmContext, 'chatId'>>(\n () => ({\n countryCode: country,\n language,\n userStatus: isAuthenticated\n ? SEARCH_GTM_USER_STATUS.LOGGED_IN\n : SEARCH_GTM_USER_STATUS.GUEST,\n ...(isAuthenticated && accountType ? { accountType } : {}),\n ...(isAuthenticated && userId ? { userId } : {}),\n }),\n [country, language, isAuthenticated, accountType, userId],\n );\n\n // Where the agent's product cards are looked up. No product environment, no product SDK cards.\n const agentProducts = useMemo<AgentProductsConfig | undefined>(() => {\n const environment = getProductEnvironment();\n return environment\n ? {\n environment,\n market: country.toUpperCase(),\n language: language.toLowerCase(),\n }\n : undefined;\n }, [country, language]);\n\n // The panel has no text of its own, so it waits for the text.\n if (!copy) return null;\n\n return (\n <CommerceSearchView\n isOpen={isOpen}\n onClose={onClose}\n service={service}\n navigate={navigateToPath}\n {...(agent ? { agent } : {})}\n agentEnabledForCustomer={agentEnabledForCustomer}\n {...(agentProducts ? { agentProducts } : {})}\n copy={copy}\n logo={logo}\n minimumSearchLength={minimumSearchLength}\n maxSuggestions={maxSuggestions}\n gtmContext={gtmContext}\n />\n );\n}\n"]}