@nuskin/react-search-sdk 1.0.0-trying-again.6 → 1.0.0-trying-again.8
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.
- package/README.md +1 -13
- package/dist/index.js +23 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/configurationSdk.ts","../src/constants.ts","../src/config/commerceSearchConfig.ts","../src/hooks/useCommerceSearchConfig.ts","../src/services/SearchApiService.ts","../src/services/marketConfig.ts","../src/utils/gtmConstants.ts","../src/utils/navigationTarget.ts","../src/utils/productEnvironment.ts","../src/utils/catalogHelpers.ts","../src/hooks/useSearchSuggestions.ts","../src/utils/commonUtils.ts","../src/utils/gtmTracking.ts","../src/utils/nuiSearchGate.ts","../src/utils/searchRouting.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":["configurationSdk","useState","useEffect","useRef","useCallback","styled","lazy","useProductById","jsx","ProductCard","useMemo","createProductClient","Suspense","ProductProvider","Component","SearchModal"],"mappings":"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","file":"index.js","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","/**\n * Constants for the search SDK. Ported from\n * `header-mfe/src/utils/search/search.constants.js` — only the values the\n * SDK itself needs (Phase 0 lift-and-shift). CMS keys, GTM tracking config,\n * and mobile-only placeholder rotation constants stay in header-mfe.\n */\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. Preserved from header-mfe. */\nexport const DEBOUNCE_MS = 220;\n\n/** Terms shorter than this are not sent to the suggestions API (as in header-mfe). */\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: move 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: Replace 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 // eslint-disable-next-line no-console\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","/**\n * SearchApiService — Phase 0 lift-and-shift of\n * `header-mfe/src/services/HeaderSearchService.js`.\n *\n * Behaviour follows the header search contract for URL formats,\n * `sessionStorage` key format, fetch parameter shape, and fallback values.\n * Navigation side effects are left to the consuming router.\n *\n * Two responsibilities were intentionally moved OUT of the SDK to preserve\n * the SDK-narrow boundary:\n * 1. Market-config resolution (`equinoxMarketsConfig.js` — depends on\n * `@nuskin/configuration-sdk`). Consumers inject a `getMarketConfig`\n * callback if they want automatic URL/store-id resolution.\n * 2. Locale resolution from the browser URL (`getLocale`). Consumers must\n * pass `country`/`language` explicitly.\n */\n\nimport {\n CATALOG_SUGGESTIONS_PATH,\n DEFAULT_SEARCH_PATH,\n DEFAULT_SUGGESTION_PAGE,\n DEFAULT_SUGGESTION_SIZE,\n MINIMUM_SEARCH_CHAR_LENGTH,\n RECENT_SEARCHES_DEFAULT_LIMIT,\n RECENT_SEARCHES_PREFIX,\n STOREFRONT_SHOPPING_CONTEXT,\n} from '../constants';\nimport type {\n GetMarketConfig,\n LocaleParts,\n LocationLike,\n MarketConfig,\n SearchServiceOptions,\n SuggestionOption,\n SuggestionsResponse,\n} from '../types';\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/* 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\nfunction 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\n/* -------------------------------------------------------------------------- */\n/* Locale + storage-key helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction normalizeLocaleParts({\n country,\n language,\n locale,\n}: {\n country: string | undefined;\n language: string | undefined;\n locale: string | undefined;\n}): LocaleParts {\n const normalizedCountry = String(country ?? '')\n .trim()\n .toUpperCase();\n const normalizedLanguage = String(language ?? '')\n .trim()\n .toLowerCase();\n const normalizedLocale = String(locale ?? '').trim() || 'UNKNOWN';\n\n return {\n country: normalizedCountry || 'UNKNOWN',\n language: normalizedLanguage || 'unknown',\n locale: normalizedLocale,\n };\n}\n\nfunction getRecentHeaderSearchesStorageKey(localeParts: LocaleParts): string {\n const { country, language, locale } = normalizeLocaleParts(localeParts);\n return `${RECENT_SEARCHES_PREFIX}:${locale}:${country}:${language}`;\n}\n\nfunction 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\nfunction 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\nfunction 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\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/* 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. Ported from the equivalent helper\n * in `equinoxMarketsConfig.js` so the SDK has no runtime dependency on it.\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\nfunction resolveSuggestionsUrl(\n suggestionsApi: string | undefined,\n locationLike: LocationLike | null,\n): string {\n const pathOrUrl = String(suggestionsApi ?? '').trim();\n if (!pathOrUrl) return '';\n\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n const normalizedPath = pathOrUrl.startsWith('/')\n ? pathOrUrl\n : `/${pathOrUrl}`;\n const origin = String(locationLike?.origin ?? '').trim();\n return origin ? `${origin}${normalizedPath}` : normalizedPath;\n}\n\nasync function resolveCatalogRequestConfig({\n suggestionsApi,\n storeIdOption,\n locationLike,\n country,\n getMarketConfig,\n}: {\n suggestionsApi: string | undefined;\n storeIdOption: string | number | undefined;\n locationLike: LocationLike | null;\n country: string;\n getMarketConfig: GetMarketConfig | undefined;\n}): Promise<{ suggestionsUrl: string; storeId: string }> {\n const explicitStoreId =\n storeIdOption !== undefined &&\n storeIdOption !== null &&\n String(storeIdOption).trim() !== ''\n ? String(storeIdOption).trim()\n : '';\n\n const marketConfig = getMarketConfig\n ? ((await getMarketConfig({ locationLike, country })) ?? null)\n : null;\n const configuredApiBase = resolveCatalogApiBaseUrl(marketConfig);\n const configuredStoreId = resolveCatalogStoreId(marketConfig);\n const explicitSuggestionsApi = String(suggestionsApi ?? '').trim();\n\n return {\n suggestionsUrl: explicitSuggestionsApi\n ? resolveSuggestionsUrl(explicitSuggestionsApi, locationLike)\n : buildCatalogSuggestionsUrl(configuredApiBase),\n storeId: explicitStoreId || configuredStoreId,\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Path + slug helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction toCatalogLocale(localeParts: LocaleParts): string {\n const language = String(localeParts.language ?? 'en').toLowerCase();\n const country = String(localeParts.country ?? 'US').toUpperCase();\n return `${language}_${country}`;\n}\n\nfunction 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 const country = localeParts.country.toLowerCase();\n const language = localeParts.language.toLowerCase();\n return `/${country}/${language}${DEFAULT_SEARCH_PATH}/${encodedQuery}`;\n}\n\nfunction normalizeOptionUrl(rawValue: unknown): string {\n if (typeof rawValue !== 'string') return '';\n return rawValue.trim();\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 const country = String(localeParts.country ?? 'US').toLowerCase();\n const language = String(localeParts.language ?? 'en').toLowerCase();\n return `/${country}/${language}/product/${slug}`;\n}\n\nfunction isNavigableUrl(value: string): boolean {\n if (!value) return false;\n return value.startsWith('/') || /^https?:\\/\\//i.test(value);\n}\n\nfunction stripLocalePrefix(path: string, localeParts: LocaleParts): string {\n const prefix = `/${localeParts.country.toLowerCase()}/${localeParts.language.toLowerCase()}`;\n return path.startsWith(prefix) ? path.slice(prefix.length) || '/' : path;\n}\n\nfunction 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\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. */\nfunction 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. */\nasync function fetchJsonFromCandidates(\n fetchImpl: typeof fetch,\n requestUrls: string[],\n requestHeaders: Record<string, string> = {},\n): Promise<unknown> {\n let lastError: unknown;\n\n for (const requestUrl of requestUrls) {\n try {\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 lastError = new Error(\n `Request failed with status ${response.status}`,\n );\n continue;\n }\n\n return await response.json();\n } catch (error) {\n lastError = error;\n }\n }\n\n throw lastError ?? new Error('Unable to fetch header search data');\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 suggestionsApi,\n storeId: storeIdOption,\n country,\n language,\n locale,\n getMarketConfig,\n getCustomerType,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n } = options;\n\n const fetchImpl: typeof fetch | null =\n fetchImplOption !== undefined\n ? fetchImplOption\n : typeof fetch === 'function'\n ? fetch.bind(globalThis)\n : null;\n\n const locationLike = getBrowserLocation(providedLocation);\n const storage = getSessionStorage(providedStorage);\n const localeParts = normalizeLocaleParts({ country, language, locale });\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 suggestionsApi,\n storeIdOption,\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 // eslint-disable-next-line no-console\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 !fetchImpl\n ) {\n return {\n suggestions: [],\n didYouMean: [],\n totalResultsCount: 0,\n };\n }\n\n const { suggestionsUrl, storeId } =\n await loadCatalogRequestConfig();\n\n if (!suggestionsUrl || !storeId) {\n return {\n suggestions: [],\n didYouMean: [],\n totalResultsCount: 0,\n };\n }\n\n const queryParams = new URLSearchParams({\n searchTerm: trimmedSearchTerm,\n page: String(DEFAULT_SUGGESTION_PAGE),\n size: String(DEFAULT_SUGGESTION_SIZE),\n locale: toCatalogLocale(localeParts),\n storeId: String(storeId),\n });\n\n const requestUrls = [`${suggestionsUrl}?${queryParams.toString()}`];\n\n const responsePayload = (await fetchJsonFromCandidates(\n fetchImpl,\n requestUrls,\n resolveCustomerTypeHeaders(getCustomerType),\n )) as SuggestionsResponse | null | undefined;\n\n const suggestionsField = Array.isArray(responsePayload?.suggestions)\n ? (responsePayload?.suggestions as unknown[])\n : [];\n const productField = Array.isArray(responsePayload?.product)\n ? (responsePayload?.product as unknown[])\n : null;\n\n const rawDidYouMean =\n responsePayload?.didYouMean ?? responsePayload?.did_you_mean;\n const didYouMeanField = Array.isArray(rawDidYouMean)\n ? (rawDidYouMean as unknown[])\n : [];\n\n const pageableTotal = Number(\n responsePayload?.pageableInfo?.totalCount ?? Number.NaN,\n );\n const totalResultsCount =\n typeof responsePayload?.totalResultsCount === 'number'\n ? responsePayload.totalResultsCount\n : !Number.isNaN(pageableTotal)\n ? pageableTotal\n : (productField?.length ?? suggestionsField.length);\n\n return {\n ...(responsePayload ?? {}),\n suggestions: suggestionsField,\n didYouMean: didYouMeanField,\n totalResultsCount,\n };\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 =\n String(country ?? '')\n .trim()\n .toUpperCase() || 'US';\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\n/** Classifies a path from the search service as internal or external. */\nexport function toNavigationTarget(path: string): NavigationTarget {\n return /^https?:\\/\\//i.test(path)\n ? { type: 'external', url: path }\n : { type: 'internal', path };\n}\n","import type { ProductEnvironment } from '@nuskin/react-product-sdk';\nimport { getEnvironmentCode } from '../config/configurationSdk';\n\nconst PRODUCT_ENVIRONMENTS: ReadonlyArray<string> = ['dev', 'test', 'prod'];\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 && PRODUCT_ENVIRONMENTS.includes(environmentCode)\n ? (environmentCode as ProductEnvironment)\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","/**\n * Catalog-product normalisation helpers — Phase 0 lift-and-shift of the\n * relevant portions of\n * `header-mfe/src/components/search/auto-complete/autoComplete.helpers.js`.\n *\n * Only the data-processing helpers are included here. UI-specific helpers\n * (keyboard event handlers, ARIA attribute computation, display-data\n * extraction) live in `react-search-components` because they depend on DOM\n * refs and component-level props.\n *\n * Key difference from the original:\n * `resolveSuggestionImageSrc` returns `\"\"` when the source is absent\n * instead of falling back to a bundled PNG asset. Components apply their\n * own `<img onError>` / CSS placeholder; the SDK must not bundle assets.\n */\n\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n ProductType,\n} from '../types';\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/* -------------------------------------------------------------------------- */\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 * Normalises 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 normalised\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 normalisation */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Normalises 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 (matching the original header-mfe behaviour).\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 — Phase 0 lift-and-shift of\n * `header-mfe/src/components/search/auto-complete/hooks/useAutoComplete.js`\n * (`useAutoCompleteSuggestions` export).\n *\n * Behaviour is preserved verbatim:\n * - 220 ms debounce (DEBOUNCE_MS constant — do not change)\n * - Request-ID stale-response guard (replaces AbortController in the original)\n * - `MAX_VISIBLE_SUGGESTIONS` cap applied before setting state\n * - `didYouMean` items take precedence: when present, `suggestions` is set\n * to `[]` and the DYM items are used as the visible list\n * - `emptyFetched` is only set to `true` when BOTH arrays are empty after\n * a successful fetch\n * - `enabled = false` clears state without firing an API call\n *\n * Keyboard navigation (`useAutoCompleteKeyboard`) and all display-data helpers\n * live in `react-search-components` — they depend on DOM refs and component props.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type React 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 trimmed query is non-empty. */\n hasQuery: boolean;\n /** `true` when the latest suggestions request failed. */\n suggestionFetchFailed: boolean;\n /** Normalised \"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 /** Raw React state setter — prefer `updateQuery` for controlled inputs. */\n setQuery: React.Dispatch<React.SetStateAction<string>>;\n /** Normalised product suggestion items from the catalog API. */\n suggestions: CatalogSuggestionItem[];\n /** Total match count reported by the Equinox API. */\n totalResultsCount: number;\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 normalisation (mirrors useAutoComplete.js) */\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/* -------------------------------------------------------------------------- */\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, locale, suggestionsApi, storeId });\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 [totalResultsCount, setTotalResultsCount] = useState(0);\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 setTotalResultsCount(0);\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 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 try {\n const fetchedSuggestions =\n await service.fetchSuggestions(trimmedQuery);\n\n // Discard stale response if a newer request has since been issued\n if (requestId !== latestRequestId.current) {\n return;\n }\n\n const {\n suggestions: allSuggestions,\n didYouMean: suggestedTerms,\n } = normalizeSuggestionsResponse(fetchedSuggestions);\n\n const visibleSuggestions = allSuggestions.slice(\n 0,\n MAX_VISIBLE_SUGGESTIONS,\n );\n const hasDidYouMean = suggestedTerms.length > 0;\n\n const normalizedTotal =\n typeof fetchedSuggestions.totalResultsCount === 'number'\n ? fetchedSuggestions.totalResultsCount\n : typeof fetchedSuggestions.pageableInfo?.totalCount ===\n 'number'\n ? fetchedSuggestions.pageableInfo.totalCount\n : allSuggestions.length;\n\n const effectiveTotal = hasDidYouMean\n ? suggestedTerms.length\n : Math.max(normalizedTotal, allSuggestions.length);\n\n setDidYouMean(suggestedTerms);\n setSuggestions(hasDidYouMean ? [] : visibleSuggestions);\n setHasMoreResults(\n !hasDidYouMean && effectiveTotal > MAX_VISIBLE_SUGGESTIONS,\n );\n setTotalResultsCount(effectiveTotal);\n setSuggestionFetchFailed(false);\n setSettledQuery(trimmedQuery);\n setEmptyFetched(\n hasDidYouMean\n ? false\n : visibleSuggestions.length === 0 &&\n suggestedTerms.length === 0,\n );\n } catch {\n if (requestId !== latestRequestId.current) {\n return;\n }\n setSuggestions([]);\n setDidYouMean([]);\n setEmptyFetched(true);\n setSuggestionFetchFailed(true);\n setHasMoreResults(false);\n setTotalResultsCount(0);\n setSettledQuery(trimmedQuery);\n } finally {\n if (requestId === latestRequestId.current) {\n setLoading(false);\n }\n }\n },\n [enabled, service, resetSuggestionsState],\n );\n\n useEffect(() => {\n if (!enabled) {\n resetSuggestionsState();\n return undefined;\n }\n\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n\n // Mark any in-flight request as stale before the debounce fires\n latestRequestId.current += 1;\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 hasQuery: Boolean(query.trim()),\n didYouMean,\n loading,\n query,\n settledQuery,\n setQuery: setQuery as React.Dispatch<React.SetStateAction<string>>,\n suggestionFetchFailed,\n suggestions,\n totalResultsCount,\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/* -------------------------------------------------------------------------- */\n/* Safe localStorage / sessionStorage wrappers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Match the pattern used by the storefront `configUtils` — JSON-parse the\n * stored value, fall back to the raw string when parsing fails, and never\n * throw (SSR, private-mode Safari, quota errors, etc.).\n */\nfunction safeParse(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** JSON-stringifies and writes a value to localStorage. Silent on failure. */\nexport function setLocalStorage(key: string, value: unknown): void {\n if (!IS_BROWSER) return;\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* silent — storage failures never break the caller */\n }\n}\n\n/** Reads a sessionStorage key and JSON-parses it. Returns `undefined` if absent. */\nexport function getSessionStorage(key: string): unknown {\n if (!IS_BROWSER) return undefined;\n try {\n const raw = window.sessionStorage.getItem(key);\n return raw === null ? undefined : safeParse(raw);\n } catch {\n return undefined;\n }\n}\n\n/** JSON-stringifies and writes a value to sessionStorage. Silent on failure. */\nexport function setSessionStorage(key: string, value: unknown): void {\n if (!IS_BROWSER) return;\n try {\n window.sessionStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* silent */\n }\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. Chatentry_Point - 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 * All UI repos (react-search-components, and any host consuming the SDK)\n * should call these helpers instead of touching `window.dataLayer` directly,\n * so that payload shape and error handling stay consistent.\n *\n * Types live in `./gtmTypes`, constants in `./gtmConstants`, and generic\n * helpers in `./commonUtils` / `./storage`.\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 * 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, set by a cookie or by a URL query parameter\n * (`?enableNuiSearch=true` or `=false`). The query parameter also writes the\n * cookie, so the choice sticks while the visitor navigates. Off by default.\n * Visitors must also be signed in, unless the configuration 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 const rawValue = part.slice(separator + 1);\n try {\n return parseFlagValue(decodeURIComponent(rawValue));\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\n/** Where the flag is read from and written to. Defaults to the browser. */\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 /** Called with a cookie string to store when the query parameter is set. */\n setCookie?: (cookie: string) => void;\n}\n\n/**\n * Resolves the flag. A valid query parameter wins over the cookie and is\n * written back to the cookie; otherwise the cookie decides. `undefined` means\n * it was never set. Safe to call during server rendering.\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 const setCookie =\n env.setCookie ??\n (inBrowser\n ? (value: string) => {\n document.cookie = value;\n }\n : undefined);\n\n const fromQuery = parseFlagValue(\n new URLSearchParams(search).get(NUI_SEARCH_FLAG),\n );\n if (fromQuery !== undefined) {\n const secure =\n inBrowser && window.location.protocol === 'https:'\n ? '; Secure'\n : '';\n setCookie?.(\n `${NUI_SEARCH_FLAG}=${fromQuery}; path=/; SameSite=Lax${secure}`,\n );\n return fromQuery;\n }\n return readCookieFlag(cookie);\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","/**\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 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, Suspense, lazy, useEffect, useMemo } from 'react';\nimport type { ErrorInfo, ReactElement, ReactNode } from 'react';\nimport type { SalesAIChatWidgetProps } from '@nuskin/react-nui-chat-sdk';\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/**\n * The platform chat widget, loaded only when a search hands off to the agent.\n *\n * `@nuskin/react-nui-chat-sdk` brings LiveKit, Recharts and Markdown with it; a static\n * import would put all of that in every host bundle for a panel most shoppers never open. The\n * stylesheet is loaded alongside. From widget 1.3.0 that stylesheet is scoped to the widget's own\n * root (1.2.0's carries Tailwind's global reset, so pin 1.3.0 or later for a host page; 1.4.0 is\n * the first version on npmjs under this name). A\n * failed load surfaces as a render error, which `AgentErrorBoundary` turns into the plain-search\n * fallback.\n */\nconst SalesAIChatWidget = lazy(() =>\n Promise.all([\n import('@nuskin/react-nui-chat-sdk'),\n import('@nuskin/react-nui-chat-sdk/styles.css'),\n ]).then(([mod]) => ({ default: mod.SalesAIChatWidget })),\n);\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 // Nothing is shown while the widget's code loads: the panel it sits in already shows the\n // shopper's query, and the handoff keeps polling for the widget's handle until it mounts.\n if (!client) {\n return (\n <Suspense fallback={null}>\n <SalesAIChatWidget {...widgetProps} />\n </Suspense>\n );\n }\n return (\n <ProductProvider client={client}>\n <Suspense fallback={null}>\n <SalesAIChatWidget\n renderProduct={renderAgentProduct}\n {...widgetProps}\n />\n </Suspense>\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, _info: ErrorInfo) {\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 useEffect(() => {\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const startedAt = Date.now();\n\n const tryOpen = () => {\n if (cancelled) 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 onUnavailable();\n return;\n }\n timer = setTimeout(tryOpen, HANDLE_POLL_MS);\n };\n\n tryOpen();\n return () => {\n cancelled = 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, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchModal } from '@nuskin/react-search-components';\nimport type { SuggestionOptionWithTracking } from '@nuskin/react-search-components';\nimport { useSearchSuggestions } from '../../hooks/useSearchSuggestions';\nimport type { SearchService } from '../../services/SearchApiService';\nimport type { SuggestionOption } from '../../types';\nimport {\n getVisibleSuggestions,\n isSuggestionDisabled,\n} from '../../utils/catalogHelpers';\nimport { MINIMUM_SEARCH_CHAR_LENGTH } from '../../constants';\nimport { SEARCH_GTM_SEARCH_TYPES } from '../../utils/gtmConstants';\nimport {\n trackChatEntryPoint,\n trackProductSearch,\n} from '../../utils/gtmTracking';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport {\n isNuiSearchEnabled,\n resolveNuiSearchFlag,\n} from '../../utils/nuiSearchGate';\nimport { decideSearchRoute } from '../../utils/searchRouting';\nimport type { SearchRoute } from '../../utils/searchRouting';\nimport { NuiAgentPanel } from './NuiAgentPanel';\nimport type { AgentProductsConfig, NuiAgentConfig } from './NuiAgentPanel';\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\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 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\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/**\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 `SearchModal`. 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 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 const [flag, setFlag] = useState<boolean | undefined>(undefined);\n // The agent's start: what was submitted and the \"did you mean\" terms Solr offered for it.\n const [handoff, setHandoff] = useState<{\n query: string;\n didYouMean: string[];\n } | null>(null);\n const agentQuery = handoff?.query ?? null;\n const [pendingTerm, setPendingTerm] = useState<string | null>(null);\n const [recentSearches, setRecentSearches] = useState<string[]>([]);\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 settledQuery,\n suggestionFetchFailed,\n suggestions,\n updateQuery,\n } = search;\n\n const enabled =\n agent !== undefined &&\n isNuiSearchEnabled({\n isAuthenticated,\n flag,\n allowGuests: allowGuestAgent,\n });\n const items = getVisibleSuggestions({\n didYouMean,\n suggestions,\n }) as unknown as SuggestionOptionWithTracking[];\n const showDidYouMean = didYouMean.length > 0;\n\n useEffect(() => {\n if (isOpen) setFlag(resolveNuiSearchFlag());\n }, [isOpen]);\n\n useEffect(() => {\n if (isOpen) {\n setRecentSearches(\n uniqueRecentSearches(service.getRecentSearches()),\n );\n }\n }, [isOpen, service, agentQuery]);\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 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 setHandoff({\n query: term,\n didYouMean: didYouMean.map((item) => item.value),\n });\n return;\n }\n runSearch(term);\n },\n [didYouMean, gtmContext, runSearch],\n );\n\n const handleSubmit = 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 runSearch(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, runSearch],\n );\n\n // A submit that beat the typeahead waits for it to settle, then re-decides. If it never\n // settles, the shopper gets plain search rather than a stuck panel.\n const latest = useRef({ act, decide });\n latest.current = { act, decide };\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 const handleSelect = useCallback(\n (option: SuggestionOptionWithTracking) => {\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: SuggestionOptionWithTracking) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n const result = service.activateSuggestionAction(\n option as unknown as SuggestionOption,\n );\n void Promise.resolve(result)\n .then(navigateTo)\n .catch(() => undefined);\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 const handleClearRecent = useCallback(() => {\n service.clearRecentSearches();\n setRecentSearches([]);\n }, [service]);\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 // Spread rather than `products={agentProducts}`: an absent configuration must be absent,\n // not an explicit undefined. Built here, outside the JSX, so no ternary nests in another.\n const agentProductsProps = agentProducts ? { products: agentProducts } : {};\n const agentPanel =\n handoff === null || agent === undefined ? undefined : (\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 {...agentProductsProps}\n onUnavailable={handleAgentUnavailable}\n />\n );\n\n return (\n <SearchModal\n isOpen={isOpen}\n onClose={close}\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: handleClearRecent,\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 { createSearchService } from '../../services/SearchApiService';\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 { 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: this set is a best guess from the values the storefront sends. Confirm what the\n * suggestions API accepts, experimentally, once the search runs against it.\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 isOpen,\n onClose,\n navigate,\n customer,\n country,\n language,\n logo,\n}: Readonly<CommerceSearchProps>): ReactElement {\n const [hasOpened, setHasOpened] = useState(false);\n useEffect(() => {\n if (isOpen) setHasOpened(true);\n }, [isOpen]);\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 customerTypeRef = useRef<CustomerAccountType>(GUEST);\n customerTypeRef.current = customer.isAuthenticated\n ? (customer.accountType ?? GUEST)\n : GUEST;\n\n const service = useMemo(\n () =>\n createSearchService({\n country,\n language,\n locale: `${country.toUpperCase()}-${language.toLowerCase()}`,\n getMarketConfig: fetchMarketConfig,\n minimumSearchLength,\n getCustomerType: () => customerTypeRef.current,\n }),\n [country, language, minimumSearchLength],\n );\n\n const navigateToPath = useCallback(\n (path: string) => navigate(toNavigationTarget(path)),\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 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 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/services/SearchApiService.ts","../src/services/marketConfig.ts","../src/utils/gtmConstants.ts","../src/utils/navigationTarget.ts","../src/utils/productEnvironment.ts","../src/utils/catalogHelpers.ts","../src/hooks/useSearchSuggestions.ts","../src/utils/commonUtils.ts","../src/utils/gtmTracking.ts","../src/utils/nuiSearchGate.ts","../src/utils/searchRouting.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":["configurationSdk","useState","useEffect","useRef","useCallback","styled","useProductById","jsx","ProductCard","useMemo","createProductClient","SalesAIChatWidget","ProductProvider","Component","SearchModal"],"mappings":"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","file":"index.js","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","/**\n * Constants for the search SDK. Ported from\n * `header-mfe/src/utils/search/search.constants.js` — only the values the\n * SDK itself needs (Phase 0 lift-and-shift). CMS keys, GTM tracking config,\n * and mobile-only placeholder rotation constants stay in header-mfe.\n */\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. Preserved from header-mfe. */\nexport const DEBOUNCE_MS = 220;\n\n/** Terms shorter than this are not sent to the suggestions API (as in header-mfe). */\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: move 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: Replace 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 // eslint-disable-next-line no-console\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","/**\n * SearchApiService — Phase 0 lift-and-shift of\n * `header-mfe/src/services/HeaderSearchService.js`.\n *\n * Behaviour follows the header search contract for URL formats,\n * `sessionStorage` key format, fetch parameter shape, and fallback values.\n * Navigation side effects are left to the consuming router.\n *\n * Two responsibilities were intentionally moved OUT of the SDK to preserve\n * the SDK-narrow boundary:\n * 1. Market-config resolution (`equinoxMarketsConfig.js` — depends on\n * `@nuskin/configuration-sdk`). Consumers inject a `getMarketConfig`\n * callback if they want automatic URL/store-id resolution.\n * 2. Locale resolution from the browser URL (`getLocale`). Consumers must\n * pass `country`/`language` explicitly.\n */\n\nimport {\n CATALOG_SUGGESTIONS_PATH,\n DEFAULT_SEARCH_PATH,\n DEFAULT_SUGGESTION_PAGE,\n DEFAULT_SUGGESTION_SIZE,\n MINIMUM_SEARCH_CHAR_LENGTH,\n RECENT_SEARCHES_DEFAULT_LIMIT,\n RECENT_SEARCHES_PREFIX,\n STOREFRONT_SHOPPING_CONTEXT,\n} from '../constants';\nimport type {\n GetMarketConfig,\n LocaleParts,\n LocationLike,\n MarketConfig,\n SearchServiceOptions,\n SuggestionOption,\n SuggestionsResponse,\n} from '../types';\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/* 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\nfunction 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\n/* -------------------------------------------------------------------------- */\n/* Locale + storage-key helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction normalizeLocaleParts({\n country,\n language,\n locale,\n}: {\n country: string | undefined;\n language: string | undefined;\n locale: string | undefined;\n}): LocaleParts {\n const normalizedCountry = String(country ?? '')\n .trim()\n .toUpperCase();\n const normalizedLanguage = String(language ?? '')\n .trim()\n .toLowerCase();\n const normalizedLocale = String(locale ?? '').trim() || 'UNKNOWN';\n\n return {\n country: normalizedCountry || 'UNKNOWN',\n language: normalizedLanguage || 'unknown',\n locale: normalizedLocale,\n };\n}\n\nfunction getRecentHeaderSearchesStorageKey(localeParts: LocaleParts): string {\n const { country, language, locale } = normalizeLocaleParts(localeParts);\n return `${RECENT_SEARCHES_PREFIX}:${locale}:${country}:${language}`;\n}\n\nfunction 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\nfunction 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\nfunction 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\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/* 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. Ported from the equivalent helper\n * in `equinoxMarketsConfig.js` so the SDK has no runtime dependency on it.\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\nfunction resolveSuggestionsUrl(\n suggestionsApi: string | undefined,\n locationLike: LocationLike | null,\n): string {\n const pathOrUrl = String(suggestionsApi ?? '').trim();\n if (!pathOrUrl) return '';\n\n if (pathOrUrl.startsWith('http://') || pathOrUrl.startsWith('https://')) {\n return pathOrUrl;\n }\n\n const normalizedPath = pathOrUrl.startsWith('/')\n ? pathOrUrl\n : `/${pathOrUrl}`;\n const origin = String(locationLike?.origin ?? '').trim();\n return origin ? `${origin}${normalizedPath}` : normalizedPath;\n}\n\nasync function resolveCatalogRequestConfig({\n suggestionsApi,\n storeIdOption,\n locationLike,\n country,\n getMarketConfig,\n}: {\n suggestionsApi: string | undefined;\n storeIdOption: string | number | undefined;\n locationLike: LocationLike | null;\n country: string;\n getMarketConfig: GetMarketConfig | undefined;\n}): Promise<{ suggestionsUrl: string; storeId: string }> {\n const explicitStoreId =\n storeIdOption !== undefined &&\n storeIdOption !== null &&\n String(storeIdOption).trim() !== ''\n ? String(storeIdOption).trim()\n : '';\n\n const marketConfig = getMarketConfig\n ? ((await getMarketConfig({ locationLike, country })) ?? null)\n : null;\n const configuredApiBase = resolveCatalogApiBaseUrl(marketConfig);\n const configuredStoreId = resolveCatalogStoreId(marketConfig);\n const explicitSuggestionsApi = String(suggestionsApi ?? '').trim();\n\n return {\n suggestionsUrl: explicitSuggestionsApi\n ? resolveSuggestionsUrl(explicitSuggestionsApi, locationLike)\n : buildCatalogSuggestionsUrl(configuredApiBase),\n storeId: explicitStoreId || configuredStoreId,\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Path + slug helpers */\n/* -------------------------------------------------------------------------- */\n\nfunction toCatalogLocale(localeParts: LocaleParts): string {\n const language = String(localeParts.language ?? 'en').toLowerCase();\n const country = String(localeParts.country ?? 'US').toUpperCase();\n return `${language}_${country}`;\n}\n\nfunction 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 const country = localeParts.country.toLowerCase();\n const language = localeParts.language.toLowerCase();\n return `/${country}/${language}${DEFAULT_SEARCH_PATH}/${encodedQuery}`;\n}\n\nfunction normalizeOptionUrl(rawValue: unknown): string {\n if (typeof rawValue !== 'string') return '';\n return rawValue.trim();\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 const country = String(localeParts.country ?? 'US').toLowerCase();\n const language = String(localeParts.language ?? 'en').toLowerCase();\n return `/${country}/${language}/product/${slug}`;\n}\n\nfunction isNavigableUrl(value: string): boolean {\n if (!value) return false;\n return value.startsWith('/') || /^https?:\\/\\//i.test(value);\n}\n\nfunction stripLocalePrefix(path: string, localeParts: LocaleParts): string {\n const prefix = `/${localeParts.country.toLowerCase()}/${localeParts.language.toLowerCase()}`;\n return path.startsWith(prefix) ? path.slice(prefix.length) || '/' : path;\n}\n\nfunction 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\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. */\nfunction 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. */\nasync function fetchJsonFromCandidates(\n fetchImpl: typeof fetch,\n requestUrls: string[],\n requestHeaders: Record<string, string> = {},\n): Promise<unknown> {\n let lastError: unknown;\n\n for (const requestUrl of requestUrls) {\n try {\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 lastError = new Error(\n `Request failed with status ${response.status}`,\n );\n continue;\n }\n\n return await response.json();\n } catch (error) {\n lastError = error;\n }\n }\n\n throw lastError ?? new Error('Unable to fetch header search data');\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 suggestionsApi,\n storeId: storeIdOption,\n country,\n language,\n locale,\n getMarketConfig,\n getCustomerType,\n minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,\n } = options;\n\n const fetchImpl: typeof fetch | null =\n fetchImplOption !== undefined\n ? fetchImplOption\n : typeof fetch === 'function'\n ? fetch.bind(globalThis)\n : null;\n\n const locationLike = getBrowserLocation(providedLocation);\n const storage = getSessionStorage(providedStorage);\n const localeParts = normalizeLocaleParts({ country, language, locale });\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 suggestionsApi,\n storeIdOption,\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 // eslint-disable-next-line no-console\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 !fetchImpl\n ) {\n return {\n suggestions: [],\n didYouMean: [],\n totalResultsCount: 0,\n };\n }\n\n const { suggestionsUrl, storeId } =\n await loadCatalogRequestConfig();\n\n if (!suggestionsUrl || !storeId) {\n return {\n suggestions: [],\n didYouMean: [],\n totalResultsCount: 0,\n };\n }\n\n const queryParams = new URLSearchParams({\n searchTerm: trimmedSearchTerm,\n page: String(DEFAULT_SUGGESTION_PAGE),\n size: String(DEFAULT_SUGGESTION_SIZE),\n locale: toCatalogLocale(localeParts),\n storeId: String(storeId),\n });\n\n const requestUrls = [`${suggestionsUrl}?${queryParams.toString()}`];\n\n const responsePayload = (await fetchJsonFromCandidates(\n fetchImpl,\n requestUrls,\n resolveCustomerTypeHeaders(getCustomerType),\n )) as SuggestionsResponse | null | undefined;\n\n const suggestionsField = Array.isArray(responsePayload?.suggestions)\n ? (responsePayload?.suggestions as unknown[])\n : [];\n const productField = Array.isArray(responsePayload?.product)\n ? (responsePayload?.product as unknown[])\n : null;\n\n const rawDidYouMean =\n responsePayload?.didYouMean ?? responsePayload?.did_you_mean;\n const didYouMeanField = Array.isArray(rawDidYouMean)\n ? (rawDidYouMean as unknown[])\n : [];\n\n const pageableTotal = Number(\n responsePayload?.pageableInfo?.totalCount ?? Number.NaN,\n );\n const totalResultsCount =\n typeof responsePayload?.totalResultsCount === 'number'\n ? responsePayload.totalResultsCount\n : !Number.isNaN(pageableTotal)\n ? pageableTotal\n : (productField?.length ?? suggestionsField.length);\n\n return {\n ...(responsePayload ?? {}),\n suggestions: suggestionsField,\n didYouMean: didYouMeanField,\n totalResultsCount,\n };\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 =\n String(country ?? '')\n .trim()\n .toUpperCase() || 'US';\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\n/** Classifies a path from the search service as internal or external. */\nexport function toNavigationTarget(path: string): NavigationTarget {\n return /^https?:\\/\\//i.test(path)\n ? { type: 'external', url: path }\n : { type: 'internal', path };\n}\n","import type { ProductEnvironment } from '@nuskin/react-product-sdk';\nimport { getEnvironmentCode } from '../config/configurationSdk';\n\nconst PRODUCT_ENVIRONMENTS: ReadonlyArray<string> = ['dev', 'test', 'prod'];\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 && PRODUCT_ENVIRONMENTS.includes(environmentCode)\n ? (environmentCode as ProductEnvironment)\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","/**\n * Catalog-product normalisation helpers — Phase 0 lift-and-shift of the\n * relevant portions of\n * `header-mfe/src/components/search/auto-complete/autoComplete.helpers.js`.\n *\n * Only the data-processing helpers are included here. UI-specific helpers\n * (keyboard event handlers, ARIA attribute computation, display-data\n * extraction) live in `react-search-components` because they depend on DOM\n * refs and component-level props.\n *\n * Key difference from the original:\n * `resolveSuggestionImageSrc` returns `\"\"` when the source is absent\n * instead of falling back to a bundled PNG asset. Components apply their\n * own `<img onError>` / CSS placeholder; the SDK must not bundle assets.\n */\n\nimport type {\n CatalogSuggestionItem,\n DidYouMeanItem,\n ProductType,\n} from '../types';\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/* -------------------------------------------------------------------------- */\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 * Normalises 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 normalised\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 normalisation */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Normalises 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 (matching the original header-mfe behaviour).\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 — Phase 0 lift-and-shift of\n * `header-mfe/src/components/search/auto-complete/hooks/useAutoComplete.js`\n * (`useAutoCompleteSuggestions` export).\n *\n * Behaviour is preserved verbatim:\n * - 220 ms debounce (DEBOUNCE_MS constant — do not change)\n * - Request-ID stale-response guard (replaces AbortController in the original)\n * - `MAX_VISIBLE_SUGGESTIONS` cap applied before setting state\n * - `didYouMean` items take precedence: when present, `suggestions` is set\n * to `[]` and the DYM items are used as the visible list\n * - `emptyFetched` is only set to `true` when BOTH arrays are empty after\n * a successful fetch\n * - `enabled = false` clears state without firing an API call\n *\n * Keyboard navigation (`useAutoCompleteKeyboard`) and all display-data helpers\n * live in `react-search-components` — they depend on DOM refs and component props.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type React 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 trimmed query is non-empty. */\n hasQuery: boolean;\n /** `true` when the latest suggestions request failed. */\n suggestionFetchFailed: boolean;\n /** Normalised \"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 /** Raw React state setter — prefer `updateQuery` for controlled inputs. */\n setQuery: React.Dispatch<React.SetStateAction<string>>;\n /** Normalised product suggestion items from the catalog API. */\n suggestions: CatalogSuggestionItem[];\n /** Total match count reported by the Equinox API. */\n totalResultsCount: number;\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 normalisation (mirrors useAutoComplete.js) */\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/* -------------------------------------------------------------------------- */\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, locale, suggestionsApi, storeId });\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 [totalResultsCount, setTotalResultsCount] = useState(0);\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 setTotalResultsCount(0);\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 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 try {\n const fetchedSuggestions =\n await service.fetchSuggestions(trimmedQuery);\n\n // Discard stale response if a newer request has since been issued\n if (requestId !== latestRequestId.current) {\n return;\n }\n\n const {\n suggestions: allSuggestions,\n didYouMean: suggestedTerms,\n } = normalizeSuggestionsResponse(fetchedSuggestions);\n\n const visibleSuggestions = allSuggestions.slice(\n 0,\n MAX_VISIBLE_SUGGESTIONS,\n );\n const hasDidYouMean = suggestedTerms.length > 0;\n\n const normalizedTotal =\n typeof fetchedSuggestions.totalResultsCount === 'number'\n ? fetchedSuggestions.totalResultsCount\n : typeof fetchedSuggestions.pageableInfo?.totalCount ===\n 'number'\n ? fetchedSuggestions.pageableInfo.totalCount\n : allSuggestions.length;\n\n const effectiveTotal = hasDidYouMean\n ? suggestedTerms.length\n : Math.max(normalizedTotal, allSuggestions.length);\n\n setDidYouMean(suggestedTerms);\n setSuggestions(hasDidYouMean ? [] : visibleSuggestions);\n setHasMoreResults(\n !hasDidYouMean && effectiveTotal > MAX_VISIBLE_SUGGESTIONS,\n );\n setTotalResultsCount(effectiveTotal);\n setSuggestionFetchFailed(false);\n setSettledQuery(trimmedQuery);\n setEmptyFetched(\n hasDidYouMean\n ? false\n : visibleSuggestions.length === 0 &&\n suggestedTerms.length === 0,\n );\n } catch {\n if (requestId !== latestRequestId.current) {\n return;\n }\n setSuggestions([]);\n setDidYouMean([]);\n setEmptyFetched(true);\n setSuggestionFetchFailed(true);\n setHasMoreResults(false);\n setTotalResultsCount(0);\n setSettledQuery(trimmedQuery);\n } finally {\n if (requestId === latestRequestId.current) {\n setLoading(false);\n }\n }\n },\n [enabled, service, resetSuggestionsState],\n );\n\n useEffect(() => {\n if (!enabled) {\n resetSuggestionsState();\n return undefined;\n }\n\n if (fetchDebounced.current) {\n clearTimeout(fetchDebounced.current);\n }\n\n // Mark any in-flight request as stale before the debounce fires\n latestRequestId.current += 1;\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 hasQuery: Boolean(query.trim()),\n didYouMean,\n loading,\n query,\n settledQuery,\n setQuery: setQuery as React.Dispatch<React.SetStateAction<string>>,\n suggestionFetchFailed,\n suggestions,\n totalResultsCount,\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/* -------------------------------------------------------------------------- */\n/* Safe localStorage / sessionStorage wrappers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Match the pattern used by the storefront `configUtils` — JSON-parse the\n * stored value, fall back to the raw string when parsing fails, and never\n * throw (SSR, private-mode Safari, quota errors, etc.).\n */\nfunction safeParse(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** JSON-stringifies and writes a value to localStorage. Silent on failure. */\nexport function setLocalStorage(key: string, value: unknown): void {\n if (!IS_BROWSER) return;\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* silent — storage failures never break the caller */\n }\n}\n\n/** Reads a sessionStorage key and JSON-parses it. Returns `undefined` if absent. */\nexport function getSessionStorage(key: string): unknown {\n if (!IS_BROWSER) return undefined;\n try {\n const raw = window.sessionStorage.getItem(key);\n return raw === null ? undefined : safeParse(raw);\n } catch {\n return undefined;\n }\n}\n\n/** JSON-stringifies and writes a value to sessionStorage. Silent on failure. */\nexport function setSessionStorage(key: string, value: unknown): void {\n if (!IS_BROWSER) return;\n try {\n window.sessionStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* silent */\n }\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. Chatentry_Point - 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 * All UI repos (react-search-components, and any host consuming the SDK)\n * should call these helpers instead of touching `window.dataLayer` directly,\n * so that payload shape and error handling stay consistent.\n *\n * Types live in `./gtmTypes`, constants in `./gtmConstants`, and generic\n * helpers in `./commonUtils` / `./storage`.\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 * 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, set by a cookie or by a URL query parameter\n * (`?enableNuiSearch=true` or `=false`). The query parameter also writes the\n * cookie, so the choice sticks while the visitor navigates. Off by default.\n * Visitors must also be signed in, unless the configuration 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 const rawValue = part.slice(separator + 1);\n try {\n return parseFlagValue(decodeURIComponent(rawValue));\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\n/** Where the flag is read from and written to. Defaults to the browser. */\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 /** Called with a cookie string to store when the query parameter is set. */\n setCookie?: (cookie: string) => void;\n}\n\n/**\n * Resolves the flag. A valid query parameter wins over the cookie and is\n * written back to the cookie; otherwise the cookie decides. `undefined` means\n * it was never set. Safe to call during server rendering.\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 const setCookie =\n env.setCookie ??\n (inBrowser\n ? (value: string) => {\n document.cookie = value;\n }\n : undefined);\n\n const fromQuery = parseFlagValue(\n new URLSearchParams(search).get(NUI_SEARCH_FLAG),\n );\n if (fromQuery !== undefined) {\n const secure =\n inBrowser && window.location.protocol === 'https:'\n ? '; Secure'\n : '';\n setCookie?.(\n `${NUI_SEARCH_FLAG}=${fromQuery}; path=/; SameSite=Lax${secure}`,\n );\n return fromQuery;\n }\n return readCookieFlag(cookie);\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","/**\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 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 } from 'react';\nimport type { ErrorInfo, 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, _info: ErrorInfo) {\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 useEffect(() => {\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const startedAt = Date.now();\n\n const tryOpen = () => {\n if (cancelled) 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 onUnavailable();\n return;\n }\n timer = setTimeout(tryOpen, HANDLE_POLL_MS);\n };\n\n tryOpen();\n return () => {\n cancelled = 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, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { SearchModal } from '@nuskin/react-search-components';\nimport type { SuggestionOptionWithTracking } from '@nuskin/react-search-components';\nimport { useSearchSuggestions } from '../../hooks/useSearchSuggestions';\nimport type { SearchService } from '../../services/SearchApiService';\nimport type { SuggestionOption } from '../../types';\nimport {\n getVisibleSuggestions,\n isSuggestionDisabled,\n} from '../../utils/catalogHelpers';\nimport { MINIMUM_SEARCH_CHAR_LENGTH } from '../../constants';\nimport { SEARCH_GTM_SEARCH_TYPES } from '../../utils/gtmConstants';\nimport {\n trackChatEntryPoint,\n trackProductSearch,\n} from '../../utils/gtmTracking';\nimport type { SearchGtmContext } from '../../utils/gtmTypes';\nimport {\n isNuiSearchEnabled,\n resolveNuiSearchFlag,\n} from '../../utils/nuiSearchGate';\nimport { decideSearchRoute } from '../../utils/searchRouting';\nimport type { SearchRoute } from '../../utils/searchRouting';\nimport { NuiAgentPanel } from './NuiAgentPanel';\nimport type { AgentProductsConfig, NuiAgentConfig } from './NuiAgentPanel';\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\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 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\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/**\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 `SearchModal`. 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 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 const [flag, setFlag] = useState<boolean | undefined>(undefined);\n // The agent's start: what was submitted and the \"did you mean\" terms Solr offered for it.\n const [handoff, setHandoff] = useState<{\n query: string;\n didYouMean: string[];\n } | null>(null);\n const agentQuery = handoff?.query ?? null;\n const [pendingTerm, setPendingTerm] = useState<string | null>(null);\n const [recentSearches, setRecentSearches] = useState<string[]>([]);\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 settledQuery,\n suggestionFetchFailed,\n suggestions,\n updateQuery,\n } = search;\n\n const enabled =\n agent !== undefined &&\n isNuiSearchEnabled({\n isAuthenticated,\n flag,\n allowGuests: allowGuestAgent,\n });\n const items = getVisibleSuggestions({\n didYouMean,\n suggestions,\n }) as unknown as SuggestionOptionWithTracking[];\n const showDidYouMean = didYouMean.length > 0;\n\n useEffect(() => {\n if (isOpen) setFlag(resolveNuiSearchFlag());\n }, [isOpen]);\n\n useEffect(() => {\n if (isOpen) {\n setRecentSearches(\n uniqueRecentSearches(service.getRecentSearches()),\n );\n }\n }, [isOpen, service, agentQuery]);\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 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 setHandoff({\n query: term,\n didYouMean: didYouMean.map((item) => item.value),\n });\n return;\n }\n runSearch(term);\n },\n [didYouMean, gtmContext, runSearch],\n );\n\n const handleSubmit = 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 runSearch(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, runSearch],\n );\n\n // A submit that beat the typeahead waits for it to settle, then re-decides. If it never\n // settles, the shopper gets plain search rather than a stuck panel.\n const latest = useRef({ act, decide });\n latest.current = { act, decide };\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 const handleSelect = useCallback(\n (option: SuggestionOptionWithTracking) => {\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: SuggestionOptionWithTracking) => {\n if (\n isSuggestionDisabled(\n option as unknown as Record<string, unknown>,\n )\n ) {\n return;\n }\n const result = service.activateSuggestionAction(\n option as unknown as SuggestionOption,\n );\n void Promise.resolve(result)\n .then(navigateTo)\n .catch(() => undefined);\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 const handleClearRecent = useCallback(() => {\n service.clearRecentSearches();\n setRecentSearches([]);\n }, [service]);\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 <SearchModal\n isOpen={isOpen}\n onClose={close}\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: handleClearRecent,\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 { createSearchService } from '../../services/SearchApiService';\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 { 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: this set is a best guess from the values the storefront sends. Confirm what the\n * suggestions API accepts, experimentally, once the search runs against it.\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 isOpen,\n onClose,\n navigate,\n customer,\n country,\n language,\n logo,\n}: Readonly<CommerceSearchProps>): ReactElement {\n const [hasOpened, setHasOpened] = useState(false);\n useEffect(() => {\n if (isOpen) setHasOpened(true);\n }, [isOpen]);\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 customerTypeRef = useRef<CustomerAccountType>(GUEST);\n customerTypeRef.current = customer.isAuthenticated\n ? (customer.accountType ?? GUEST)\n : GUEST;\n\n const service = useMemo(\n () =>\n createSearchService({\n country,\n language,\n locale: `${country.toUpperCase()}-${language.toLowerCase()}`,\n getMarketConfig: fetchMarketConfig,\n minimumSearchLength,\n getCustomerType: () => customerTypeRef.current,\n }),\n [country, language, minimumSearchLength],\n );\n\n const navigateToPath = useCallback(\n (path: string) => navigate(toNavigationTarget(path)),\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 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 logo={logo}\n minimumSearchLength={minimumSearchLength}\n gtmContext={gtmContext}\n />\n );\n}\n"]}
|