@nuskin/react-search-sdk 1.0.0-comx-2233.3 → 1.0.0-trying-again.1

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/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import React from 'react';
2
- import * as zustand_middleware from 'zustand/middleware';
3
- import * as zustand from 'zustand';
1
+ import React, { ReactNode, ReactElement } from 'react';
2
+ import { SearchModalCopy } from '@nuskin/react-search-components';
3
+ import { SalesAIChatWidgetProps } from '@nuskin/react-nui-chat-sdk';
4
4
 
5
5
  /**
6
6
  * Shared TypeScript types for the search SDK.
@@ -148,12 +148,20 @@ interface UseSearchSuggestionsResult {
148
148
  hasMoreResults: boolean;
149
149
  /** `true` when the trimmed query is non-empty. */
150
150
  hasQuery: boolean;
151
+ /** `true` when the latest suggestions request failed. */
152
+ suggestionFetchFailed: boolean;
151
153
  /** Normalised "Did You Mean?" items from the API. */
152
154
  didYouMean: DidYouMeanItem[];
153
155
  /** `true` while a debounced fetch is in flight. */
154
156
  loading: boolean;
155
157
  /** The current query string (unmodified, as typed by the user). */
156
158
  query: string;
159
+ /**
160
+ * The trimmed query the current results (or failure) belong to; `""` until a
161
+ * fetch has finished. Compare with `query.trim()` to know whether the
162
+ * results on screen are for the term the user has typed.
163
+ */
164
+ settledQuery: string;
157
165
  /** Raw React state setter — prefer `updateQuery` for controlled inputs. */
158
166
  setQuery: React.Dispatch<React.SetStateAction<string>>;
159
167
  /** Normalised product suggestion items from the catalog API. */
@@ -205,25 +213,25 @@ interface SearchServiceOptions {
205
213
  */
206
214
  onSuggestionAction?: (option: SuggestionOption) => Promise<boolean> | boolean | undefined;
207
215
  }
208
- /** Public API returned by `createSearchService`. Behaviour matches header-mfe. */
216
+ /** Public API returned by `createSearchService`. */
209
217
  interface SearchService {
210
218
  /** Returns fallback placeholder + aria-label copy. */
211
219
  getSearchChromeCopy: () => Promise<SearchChromeCopy>;
212
220
  /** Fetches typeahead suggestions from the Equinox catalog. */
213
221
  fetchSuggestions: (searchTerm: string) => Promise<SuggestionsResponse>;
214
222
  /**
215
- * Records the query in recent searches, then navigates to the option URL
216
- * or to the fallback search-results path. Returns the URL that was used.
223
+ * Records the query in recent searches, then returns the option URL or the
224
+ * fallback search-results path for the consuming router to navigate.
217
225
  */
218
226
  submitProductSearch: (query: string, option?: SuggestionOption) => string | undefined;
219
227
  /**
220
- * Follows the suggestion's URL if one is resolvable; otherwise submits
221
- * the suggestion's textual value as a product search.
228
+ * Returns the suggestion's URL if one is resolvable; otherwise submits the
229
+ * suggestion's textual value as a product search.
222
230
  */
223
231
  activateSuggestionAction: (option: SuggestionOption) => string | undefined;
224
232
  /** Returns the navigable URL for a suggestion option (or `""`). */
225
233
  getSuggestionHref: (option: SuggestionOption) => string;
226
- /** Navigates to the search-results page for `query`. */
234
+ /** Returns the search-results page path for `query`. */
227
235
  viewMoreResults: (input: {
228
236
  query: string;
229
237
  }) => string | undefined;
@@ -262,55 +270,6 @@ declare function resolveApiGatewayPath(apiGatewayPath: string | undefined | null
262
270
  */
263
271
  declare function createSearchService(options?: SearchServiceOptions): SearchService;
264
272
 
265
- /**
266
- * ChatService — two-step NuSkin AI chat API.
267
- *
268
- * Step 1: POST /chat/conversations → receives conversation_id
269
- * Step 2: POST /chat/messages → SSE stream parsed with eventsource-parser
270
- *
271
- * Products are embedded in AI response content as ```products [...] ``` code blocks.
272
- */
273
- interface ChatProduct {
274
- sku: string;
275
- name: string;
276
- category?: string;
277
- pv?: number;
278
- retail_price?: number;
279
- description?: string;
280
- image_url?: string;
281
- badge?: string;
282
- [key: string]: unknown;
283
- }
284
- interface ChatMessageResult {
285
- summary: string;
286
- products: ChatProduct[];
287
- /** Raw accumulated content including markdown, for downstream rendering. */
288
- rawContent: string;
289
- }
290
- interface ChatServiceOptions {
291
- /** POST endpoint for creating a conversation. */
292
- conversationsUrl?: string;
293
- /** POST endpoint for sending a message (SSE response). */
294
- messagesUrl?: string;
295
- /** X-Sales-AI-App-Key header value (from CS configurations). */
296
- salesAiAppKey?: string;
297
- /** X-Sales-AI-Parent-Origin header value (from CS configurations). */
298
- salesAiParentOrigin?: string;
299
- /** Market code (e.g., "US", "JP") for scope_context in message requests. */
300
- market?: string;
301
- /** Language code (e.g., "en", "ja") for scope_context in message requests. */
302
- language?: string;
303
- /** Override fetch for testing. */
304
- fetchImpl?: typeof fetch | null;
305
- }
306
- interface ChatService {
307
- /** Creates a conversation and returns the numeric conversation ID. */
308
- createConversation: (title?: string) => Promise<number>;
309
- /** Sends a message and streams back a parsed result. */
310
- sendMessage: (conversationId: number, content: string, onChunk?: (type: string, text: string) => void) => Promise<ChatMessageResult>;
311
- }
312
- declare function createChatService(options: ChatServiceOptions): ChatService;
313
-
314
273
  /**
315
274
  * useSearchSuggestions — Phase 0 lift-and-shift of
316
275
  * `header-mfe/src/components/search/auto-complete/hooks/useAutoComplete.js`
@@ -342,64 +301,6 @@ declare function createChatService(options: ChatServiceOptions): ChatService;
342
301
  */
343
302
  declare function useSearchSuggestions({ service, enabled, }: UseSearchSuggestionsOptions): UseSearchSuggestionsResult;
344
303
 
345
- interface SearchHistoryEntry {
346
- query: string;
347
- isAI: boolean;
348
- /** Serialized AI result payload; consumers cast to their concrete result type */
349
- aiResult?: unknown;
350
- timestamp: number;
351
- }
352
- interface SearchHistoryState {
353
- entries: SearchHistoryEntry[];
354
- /** Save a full entry (AI or non-AI); deduplicates by query (case-insensitive). */
355
- addEntry: (entry: Omit<SearchHistoryEntry, 'timestamp'>) => void;
356
- /** Convenience alias — saves a plain non-AI query entry. */
357
- addQuery: (query: string) => void;
358
- removeEntry: (query: string) => void;
359
- clearAll: () => void;
360
- }
361
- declare const useSearchHistoryStore: zustand.UseBoundStore<Omit<zustand.StoreApi<SearchHistoryState>, "persist"> & {
362
- persist: {
363
- setOptions: (options: Partial<zustand_middleware.PersistOptions<SearchHistoryState, unknown>>) => void;
364
- clearStorage: () => void;
365
- rehydrate: () => Promise<void> | void;
366
- hasHydrated: () => boolean;
367
- onHydrate: (fn: (state: SearchHistoryState) => void) => () => void;
368
- onFinishHydration: (fn: (state: SearchHistoryState) => void) => () => void;
369
- getOptions: () => Partial<zustand_middleware.PersistOptions<SearchHistoryState, unknown>>;
370
- };
371
- }>;
372
-
373
- interface UseSearchHistoryResult {
374
- entries: SearchHistoryEntry[];
375
- /** Derived string list of queries (backward compat) */
376
- queries: string[];
377
- addEntry: (entry: Omit<SearchHistoryEntry, 'timestamp'>) => void;
378
- /** @deprecated prefer addEntry */
379
- addQuery: (query: string) => void;
380
- removeEntry: (query: string) => void;
381
- clearAll: () => void;
382
- }
383
- /** React hook that subscribes to the tab-scoped search history store. */
384
- declare function useSearchHistory(): UseSearchHistoryResult;
385
-
386
- interface SpeechRecognitionErrorEventLike {
387
- error: string;
388
- }
389
- interface UseVoiceSearchOptions {
390
- lang?: string;
391
- onResult: (transcript: string) => void;
392
- onInterimResult?: (transcript: string) => void;
393
- onError?: (error: SpeechRecognitionErrorEventLike) => void;
394
- }
395
- interface UseVoiceSearchResult {
396
- listening: boolean;
397
- supported: boolean;
398
- start: () => void;
399
- stop: () => void;
400
- }
401
- declare function useVoiceSearch({ lang, onInterimResult, onResult, onError, }: UseVoiceSearchOptions): UseVoiceSearchResult;
402
-
403
304
  /**
404
305
  * Catalog-product normalisation helpers — Phase 0 lift-and-shift of the
405
306
  * relevant portions of
@@ -473,6 +374,249 @@ declare function getSeeMoreResultsPayload(query: string, totalResultsCount: numb
473
374
  visibleResultsCount: number;
474
375
  };
475
376
 
377
+ /**
378
+ * Types + Window augmentation for the GTM (Google Tag Manager) tracking layer.
379
+ */
380
+ declare global {
381
+ interface Window {
382
+ dataLayer?: unknown[];
383
+ }
384
+ }
385
+ type SearchGtmUserStatus = 'guest' | 'logged_in';
386
+ type SearchGtmSearchType = 'semantic search' | 'AI agent';
387
+ /**
388
+ * Context shared by every AI-chat GTM event. Values that are unknown at
389
+ * emit time should be passed as an empty string so the schema stays stable
390
+ * (matches the placeholder shape the data team provided in COMX-3277).
391
+ */
392
+ interface SearchGtmContext {
393
+ /** NUi conversation id (the widget's `onConversationChange`), coerced to string. */
394
+ chatId?: string | number;
395
+ /** Page type where the chat was initiated (e.g. `plp`, `pdp`, `home`). */
396
+ pageType?: string;
397
+ /** ISO 3166-1 alpha-2 country code (e.g. `US`, `DE`). */
398
+ countryCode?: string;
399
+ /** Language code (e.g. `en`, `de`). */
400
+ language?: string;
401
+ /**
402
+ * Whether the visitor is a guest or a logged-in user.
403
+ * Falls back to the `IsAuthenticated` localStorage flag written by the
404
+ * storefront `Session` model when not supplied by the host.
405
+ */
406
+ userStatus?: SearchGtmUserStatus;
407
+ /** Authenticated user id, or empty for guests. */
408
+ userId?: string;
409
+ /**
410
+ * Customer account type (e.g. `Retail Customer`, `Brand Affiliate`).
411
+ * Falls back to the `accountType` localStorage value written by the
412
+ * storefront `Customer` / `MyAccount` flows when not supplied.
413
+ */
414
+ accountType?: string;
415
+ }
416
+ /** Payload for the Search_Type event (query the user submitted). */
417
+ interface SearchTypeEventInput extends SearchGtmContext {
418
+ /** Type of AI search: `semantic search` or `AI agent`. */
419
+ searchType?: SearchGtmSearchType;
420
+ /** User's raw search query / response text. */
421
+ searchResponse?: string;
422
+ }
423
+ /** Payload for the ProductSearch event (results returned to the user). */
424
+ interface ProductSearchEventInput extends SearchGtmContext {
425
+ searchType?: SearchGtmSearchType;
426
+ /** Number of product results shown to the user. */
427
+ productResults?: number;
428
+ /** Raw products payload to send into Product_results as JSON string. */
429
+ productResultsData?: unknown;
430
+ }
431
+ /** Payload for the Error_popup event. */
432
+ interface ErrorPopupEventInput extends SearchGtmContext {
433
+ searchType?: SearchGtmSearchType;
434
+ }
435
+
436
+ /** How the host's NUi app is reached and presented. */
437
+ interface NuiAgentConfig {
438
+ /** The NUi app key for the search surface. */
439
+ appKey: string;
440
+ /** Origin of the NUi API. */
441
+ apiBaseUrl: string;
442
+ /** UI language, e.g. `en-US`. */
443
+ language?: string;
444
+ /** Widget theme. Defaults to `nui-light`. */
445
+ theme?: SalesAIChatWidgetProps['theme'];
446
+ /** Context sent with every turn of the conversation, under the handoff context. */
447
+ context?: Record<string, unknown>;
448
+ /** Lets the host draw the agent's product recommendations. */
449
+ renderProduct?: SalesAIChatWidgetProps['renderProduct'];
450
+ }
451
+
452
+ /** How long a submit waits for the typeahead of that exact term before it stays on search. */
453
+ declare const SUBMIT_WAIT_TIMEOUT_MS = 2000;
454
+ interface ProductSearchProps {
455
+ isOpen: boolean;
456
+ onClose: () => void;
457
+ /** From `createSearchService`. Keep its identity stable (memoize it). */
458
+ service: SearchService;
459
+ /** Takes the shopper to a path, using the host's router. The panel closes afterwards. */
460
+ navigate: (path: string) => void;
461
+ /** Whether the visitor is signed in (the storefront's `customerData.isAuthenticated`). */
462
+ isAuthenticated: boolean;
463
+ /** The NUi app the agent runs on. */
464
+ agent: NuiAgentConfig;
465
+ logo?: ReactNode;
466
+ cancelLabel?: string;
467
+ fallbackImageUrl?: string;
468
+ copy?: SearchModalCopy;
469
+ /** Host-known values for the search analytics events. */
470
+ gtmContext?: Omit<SearchGtmContext, 'chatId'>;
471
+ }
472
+ /**
473
+ * Product search with an agent fallback.
474
+ *
475
+ * Shows Solr typeahead and recent searches in the library's `SearchModal`. When a signed-in
476
+ * shopper submits a term whose typeahead shows no products, the NUi agent takes over in the same
477
+ * panel with that term as the first message. Everything else behaves as plain search.
478
+ */
479
+ declare function ProductSearch({ isOpen, onClose, service, navigate, isAuthenticated, agent, logo, cancelLabel, fallbackImageUrl, copy, gtmContext, }: Readonly<ProductSearchProps>): ReactElement;
480
+
481
+ /**
482
+ * The enable gate for NUi search.
483
+ *
484
+ * NUi search is on only for signed-in visitors who have switched it on with
485
+ * the `enableNuiSearch` flag, set by a cookie or by a URL query parameter
486
+ * (`?enableNuiSearch=true` or `=false`). The query parameter also writes the
487
+ * cookie, so the choice sticks while the visitor navigates. Off by default.
488
+ *
489
+ * The flag is a client-side feature toggle, not a security control. Real
490
+ * per-market and per-locale switching is a later step.
491
+ */
492
+ /** Name shared by the cookie and the URL query parameter. */
493
+ declare const NUI_SEARCH_FLAG = "enableNuiSearch";
494
+ /** Where the flag is read from and written to. Defaults to the browser. */
495
+ interface NuiSearchFlagEnv {
496
+ /** Query string, with or without the leading `?`. */
497
+ search?: string;
498
+ /** Cookie string, as in `document.cookie`. */
499
+ cookie?: string;
500
+ /** Called with a cookie string to store when the query parameter is set. */
501
+ setCookie?: (cookie: string) => void;
502
+ }
503
+ /**
504
+ * Resolves the flag. A valid query parameter wins over the cookie and is
505
+ * written back to the cookie; otherwise the cookie decides. `undefined` means
506
+ * it was never set. Safe to call during server rendering.
507
+ */
508
+ declare function resolveNuiSearchFlag(env?: NuiSearchFlagEnv): boolean | undefined;
509
+ interface IsNuiSearchEnabledInput {
510
+ /** From the host (the storefront's `customerData.isAuthenticated`). */
511
+ isAuthenticated: boolean | undefined;
512
+ /** The resolved flag; see `resolveNuiSearchFlag`. */
513
+ flag: boolean | undefined;
514
+ }
515
+ /** On only when the visitor is signed in and the flag is explicitly on. */
516
+ declare function isNuiSearchEnabled({ isAuthenticated, flag, }: IsNuiSearchEnabledInput): boolean;
517
+
518
+ /**
519
+ * Routing between Solr search and the NUi agent.
520
+ *
521
+ * Rule: when the shopper submits a search and the typeahead response for that
522
+ * exact term shows no products, the NUi widget takes over in the same panel.
523
+ * Anything else stays plain search. A pure function, so a smarter intent
524
+ * heuristic can replace it later without touching any UI.
525
+ */
526
+
527
+ /**
528
+ * - `search` — stay on Solr search (submit behaves as it does today).
529
+ * - `handoff` — hand the query to the NUi agent.
530
+ * - `wait` — the typeahead for this term has not settled yet; ask again when
531
+ * the snapshot changes. Callers should apply their own timeout and
532
+ * fall back to `search`, so a slow request never blocks a submit.
533
+ */
534
+ type SearchRoute = 'search' | 'handoff' | 'wait';
535
+ /** The slice of `useSearchSuggestions` state the rule reads. */
536
+ type RoutingSnapshot = Pick<UseSearchSuggestionsResult, 'query' | 'loading' | 'settledQuery' | 'suggestions' | 'suggestionFetchFailed'>;
537
+ interface DecideSearchRouteInput {
538
+ /** Whether NUi search is on for this visitor (see `isNuiSearchEnabled`). */
539
+ enabled: boolean;
540
+ snapshot: RoutingSnapshot;
541
+ }
542
+ /**
543
+ * Decides what a submitted search does.
544
+ *
545
+ * "No products" means the hook has nothing to show for the term. A response
546
+ * that only offers "did you mean" terms counts as no products: the hook hides
547
+ * the products in that case, so the shopper sees none either. A failed request
548
+ * is not "no products": an outage must not send every shopper to the agent.
549
+ */
550
+ declare function decideSearchRoute({ enabled, snapshot, }: DecideSearchRouteInput): SearchRoute;
551
+
552
+ /**
553
+ * Extracts `{ countryCode, language }` from a storefront-shaped path
554
+ * (`/{country}/{language}/...`, e.g. `/us/en/product/x`).
555
+ *
556
+ * Reads `window.location.pathname` when called with no argument. Returns `{}`
557
+ * if the first two path segments are not both 2-letter locale codes.
558
+ */
559
+ declare function getLocaleFromUrl(pathname?: string): {
560
+ countryCode?: string;
561
+ language?: string;
562
+ };
563
+
564
+ /**
565
+ * GTM constants — event names, storage keys, and enum-like value maps.
566
+ * Types are declared in `./gtmTypes` and imported here only for `satisfies`.
567
+ */
568
+ declare const SEARCH_GTM_EVENTS: {
569
+ readonly CHAT_ENTRY_POINT: "Begin_chat";
570
+ readonly SEARCH_TYPE: "Search_Type";
571
+ readonly PRODUCT_SEARCH: "ProductSearch";
572
+ readonly ERROR_POPUP: "Error_popup";
573
+ };
574
+ declare const SEARCH_GTM_SEARCH_TYPES: {
575
+ readonly SEMANTIC: "semantic search";
576
+ readonly AI_AGENT: "AI agent";
577
+ };
578
+ declare const SEARCH_GTM_USER_STATUS: {
579
+ readonly GUEST: "guest";
580
+ readonly LOGGED_IN: "logged_in";
581
+ };
582
+
583
+ /**
584
+ * GTM (Google Tag Manager) dataLayer tracking for the AI Chat Bot.
585
+ *
586
+ * Implements the events specified in COMX-3277:
587
+ * 1. Chatentry_Point - user initiates the AI chat from an entry point
588
+ * 2. Search_Type - user submits a query in the AI chat
589
+ * 3. ProductSearch - AI chat returns product results (fires even on 0)
590
+ * 4. Error_popup - API errors / unhandled exceptions during a session
591
+ *
592
+ * All UI repos (react-search-components, and any host consuming the SDK)
593
+ * should call these helpers instead of touching `window.dataLayer` directly,
594
+ * so that payload shape and error handling stay consistent.
595
+ *
596
+ * Types live in `./gtmTypes`, constants in `./gtmConstants`, and generic
597
+ * helpers in `./commonUtils` / `./storage`.
598
+ */
599
+
600
+ /**
601
+ * Pushes a raw event object onto `window.dataLayer`.
602
+ *
603
+ * Silently no-ops when `window` is unavailable (SSR) or the dataLayer is
604
+ * missing - GTM tag firing is a best-effort side effect, never a blocker for
605
+ * the search flow.
606
+ */
607
+ declare function pushGtmEvent(event: Record<string, unknown>): void;
608
+ /** Fires `Begin_chat` when the user initiates the AI chat. */
609
+ declare function trackChatEntryPoint(ctx: SearchGtmContext): void;
610
+ /** Fires `Search_Type` when the user submits a query in the AI chat. */
611
+ declare function trackSearchType(input: SearchTypeEventInput): void;
612
+ /**
613
+ * Fires `ProductSearch` when the AI chat returns results.
614
+ * Must be called even when 0 products are returned.
615
+ */
616
+ declare function trackProductSearch(input: ProductSearchEventInput): void;
617
+ /** Fires `Error_popup` for API errors and unhandled exceptions during chat. */
618
+ declare function trackErrorPopup(input: ErrorPopupEventInput): void;
619
+
476
620
  /**
477
621
  * Constants for the search SDK. Ported from
478
622
  * `header-mfe/src/utils/search/search.constants.js` — only the values the
@@ -504,15 +648,5 @@ declare const MAX_VISIBLE_SUGGESTIONS = 6;
504
648
  declare const SEARCH_PLACEHOLDER = "Search by product name, ingredient, benefits, or SKU";
505
649
  /** Fallback placeholder shown on the collapsed search trigger. */
506
650
  declare const TRIGGER_PLACEHOLDER = "Product Search";
507
- /**
508
- * Full path segment for the AI commerce chat SSE endpoint.
509
- * Appended to the consumer-provided `chatBaseUrl`.
510
- * Source: https://admin.tst.nuskin.ai/api/analytics/v1/embed
511
- */
512
- declare const DEFAULT_AI_CHAT_BASE_URL = "https://admin.tst.nuskin.ai/api/analytics/v1/embed";
513
- /** Default POST endpoint for creating an AI chat conversation. */
514
- declare const DEFAULT_AI_CHAT_CONVERSATIONS_URL = "https://admin.tst.nuskin.ai/api/analytics/v1/embed/conversations";
515
- /** Default POST endpoint for sending AI chat messages. */
516
- declare const DEFAULT_AI_CHAT_MESSAGES_URL = "https://admin.tst.nuskin.ai/api/analytics/v1/embed/messages";
517
651
 
518
- export { CATALOG_SUGGESTIONS_PATH, type CatalogSuggestionItem, type ChatMessageResult, type ChatProduct, type ChatService, type ChatServiceOptions, DEBOUNCE_MS, DEFAULT_AI_CHAT_BASE_URL, DEFAULT_AI_CHAT_CONVERSATIONS_URL, DEFAULT_AI_CHAT_MESSAGES_URL, DEFAULT_SEARCH_PATH, DEFAULT_SUGGESTION_PAGE, DEFAULT_SUGGESTION_SIZE, type DidYouMeanItem, type GetMarketConfig, type LocaleParts, type LocationLike, MAX_VISIBLE_SUGGESTIONS, type MarketConfig, type ProductType, RECENT_SEARCHES_DEFAULT_LIMIT, RECENT_SEARCHES_PREFIX, SEARCH_PLACEHOLDER, STOREFRONT_SHOPPING_CONTEXT, type SearchChromeCopy, type SearchHistoryEntry, type SearchHistoryState, type SearchHistoryEntry as SearchHistoryStoreEntry, type SearchService, type SearchServiceOptions, type SuggestionOption, type SuggestionsResponse, TRIGGER_PLACEHOLDER, type UseSearchHistoryResult, type UseSearchSuggestionsOptions, type UseSearchSuggestionsResult, type UseVoiceSearchOptions, type UseVoiceSearchResult, createChatService, createSearchService, getImageFromProperty, getIngredientTerms, getSeeMoreResultsPayload, getVisibleSuggestions, isCartActionDisabled, isSellableProductStatus, isSuggestionDisabled, mapCatalogProductToSuggestion, normalizeDidYouMean, resolveApiGatewayPath, resolveSuggestionImageSrc, useSearchHistory, useSearchHistoryStore, useSearchSuggestions, useVoiceSearch };
652
+ export { CATALOG_SUGGESTIONS_PATH, type CatalogSuggestionItem, DEBOUNCE_MS, DEFAULT_SEARCH_PATH, DEFAULT_SUGGESTION_PAGE, DEFAULT_SUGGESTION_SIZE, type DecideSearchRouteInput, type DidYouMeanItem, type ErrorPopupEventInput, type GetMarketConfig, type IsNuiSearchEnabledInput, type LocaleParts, type LocationLike, MAX_VISIBLE_SUGGESTIONS, type MarketConfig, NUI_SEARCH_FLAG, type NuiAgentConfig, type NuiSearchFlagEnv, ProductSearch, type ProductSearchEventInput, type ProductSearchProps, type ProductType, RECENT_SEARCHES_DEFAULT_LIMIT, RECENT_SEARCHES_PREFIX, type RoutingSnapshot, SEARCH_GTM_EVENTS, SEARCH_GTM_SEARCH_TYPES, SEARCH_GTM_USER_STATUS, SEARCH_PLACEHOLDER, STOREFRONT_SHOPPING_CONTEXT, SUBMIT_WAIT_TIMEOUT_MS, type SearchChromeCopy, type SearchGtmContext, type SearchGtmSearchType, type SearchGtmUserStatus, type SearchRoute, type SearchService, type SearchServiceOptions, type SearchTypeEventInput, type SuggestionOption, type SuggestionsResponse, TRIGGER_PLACEHOLDER, type UseSearchSuggestionsOptions, type UseSearchSuggestionsResult, createSearchService, decideSearchRoute, getImageFromProperty, getIngredientTerms, getLocaleFromUrl, getSeeMoreResultsPayload, getVisibleSuggestions, isCartActionDisabled, isNuiSearchEnabled, isSellableProductStatus, isSuggestionDisabled, mapCatalogProductToSuggestion, normalizeDidYouMean, pushGtmEvent, resolveApiGatewayPath, resolveNuiSearchFlag, resolveSuggestionImageSrc, trackChatEntryPoint, trackErrorPopup, trackProductSearch, trackSearchType, useSearchSuggestions };