@askdialog/dialog-sdk 2.9.1 → 2.11.0

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.
Files changed (40) hide show
  1. package/README.md +44 -10
  2. package/dist/Dialog.d.ts +21 -6
  3. package/dist/Dialog.d.ts.map +1 -1
  4. package/dist/Dialog.js +72 -12
  5. package/dist/__tests__/dialogCurrentProduct.spec.d.ts +2 -0
  6. package/dist/__tests__/dialogCurrentProduct.spec.d.ts.map +1 -0
  7. package/dist/__tests__/dialogCurrentProduct.spec.js +134 -0
  8. package/dist/__tests__/dialogSearchAnalytics.spec.js +1 -0
  9. package/dist/__tests__/publicTypes.spec.js +2 -1
  10. package/dist/__tests__/searchController.spec.js +126 -35
  11. package/dist/__tests__/searchControllerAttribution.spec.js +30 -26
  12. package/dist/__tests__/searchImpressions.spec.js +3 -20
  13. package/dist/__tests__/searchService.spec.js +65 -60
  14. package/dist/config/config.development.js +1 -1
  15. package/dist/config/config.production.js +1 -1
  16. package/dist/config/index.js +1 -1
  17. package/dist/searchController.d.ts +1 -1
  18. package/dist/searchController.d.ts.map +1 -1
  19. package/dist/searchController.js +34 -24
  20. package/dist/services/search.d.ts +3 -2
  21. package/dist/services/search.d.ts.map +1 -1
  22. package/dist/services/search.js +4 -9
  23. package/dist/types/constructor.d.ts +15 -0
  24. package/dist/types/constructor.d.ts.map +1 -1
  25. package/dist/types/search.d.ts +24 -22
  26. package/dist/types/search.d.ts.map +1 -1
  27. package/dist/types/search.js +7 -4
  28. package/dist/types/searchAnalytics.d.ts +2 -0
  29. package/dist/types/searchAnalytics.d.ts.map +1 -1
  30. package/dist/types/searchController.d.ts +13 -5
  31. package/dist/types/searchController.d.ts.map +1 -1
  32. package/dist/utils/searchControllerAnalytics.d.ts +4 -4
  33. package/dist/utils/searchControllerAnalytics.d.ts.map +1 -1
  34. package/dist/utils/searchControllerAnalytics.js +14 -16
  35. package/dist/utils/searchImpressions.d.ts.map +1 -1
  36. package/dist/utils/searchImpressions.js +1 -6
  37. package/dist/utils/searchSections.d.ts +5 -0
  38. package/dist/utils/searchSections.d.ts.map +1 -0
  39. package/dist/utils/searchSections.js +21 -0
  40. package/package.json +1 -1
@@ -1,5 +1,12 @@
1
+ // This controller is one cohesive unit: `selectResult` reports whether the
2
+ // navigate adapter handled the transition and the response is split into the
3
+ // products entry plus its sections, pushing the file past the default 200-line
4
+ // cap — raised modestly rather than split artificially.
5
+ /* eslint max-lines: ["error", 240] */
6
+ import { searchIndexName } from "./services/search";
1
7
  import { SearchStatus, } from "./types/searchController";
2
8
  import { createControllerAnalytics } from "./utils/searchControllerAnalytics";
9
+ import { buildSectionQueries, pickSectionResults, } from "./utils/searchSections";
3
10
  const DEFAULT_DEBOUNCE_MS = 250;
4
11
  const DEFAULT_HITS_PER_PAGE = 12;
5
12
  // `SearchRequest` rejects queries under two visible characters (code points).
@@ -9,9 +16,12 @@ const INITIAL_STATE = {
9
16
  query: "",
10
17
  page: 0,
11
18
  response: undefined,
19
+ sections: undefined,
12
20
  error: undefined,
13
21
  };
14
- export function createSearchController({ search, analytics, navigate, debounceMs = DEFAULT_DEBOUNCE_MS, hitsPerPage = DEFAULT_HITS_PER_PAGE, locale, countryCode, }) {
22
+ export function createSearchController({ search, analytics, navigate, debounceMs = DEFAULT_DEBOUNCE_MS, hitsPerPage = DEFAULT_HITS_PER_PAGE, locale, sections = [], }) {
23
+ const indexName = searchIndexName("products", locale);
24
+ const resolveSections = () => typeof sections === "function" ? sections() : sections;
15
25
  let state = INITIAL_STATE;
16
26
  const listeners = new Set();
17
27
  const controllerAnalytics = createControllerAnalytics(analytics);
@@ -34,39 +44,34 @@ export function createSearchController({ search, analytics, navigate, debounceMs
34
44
  abortController?.abort();
35
45
  abortController = undefined;
36
46
  };
37
- const buildRequest = (query, page) => {
38
- const request = { query, page, hitsPerPage };
39
- if (locale !== undefined) {
40
- request.locale = locale;
41
- }
42
- if (countryCode !== undefined) {
43
- request.countryCode = countryCode;
44
- }
45
- // Query unchanged since the last response: resend its queryId; a new
46
- // query gets a fresh engine-generated one.
47
- const previous = state.response;
48
- if (previous?.query === query) {
49
- request.queryId = previous.queryId;
50
- }
51
- return request;
52
- };
47
+ const buildRequest = (query, page, requested) => ({
48
+ requests: [
49
+ { indexName, query, page, hitsPerPage },
50
+ ...buildSectionQueries(requested, query, locale, hitsPerPage),
51
+ ],
52
+ });
53
53
  const run = async (query, page) => {
54
54
  cancelInFlight();
55
55
  abortController = new AbortController();
56
56
  const id = ++requestId;
57
- const request = buildRequest(query, page);
58
57
  setState({ status: SearchStatus.LOADING, query, page });
59
58
  try {
60
- const response = await search(request, {
59
+ const requested = resolveSections();
60
+ const response = await search(buildRequest(query, page, requested), {
61
61
  signal: abortController.signal,
62
62
  });
63
63
  if (id !== requestId) {
64
64
  return; // A newer request landed first: this response is stale.
65
65
  }
66
- controllerAnalytics.onResponse(response);
66
+ const result = response.results.find((entry) => entry.index === indexName);
67
+ if (result === undefined) {
68
+ throw new Error(`Dialog search returned no ${indexName} entry`);
69
+ }
70
+ controllerAnalytics.onResponse(result);
67
71
  setState({
68
- status: response.nbHits === 0 ? SearchStatus.EMPTY : SearchStatus.SUCCESS,
69
- response,
72
+ status: result.nbHits === 0 ? SearchStatus.EMPTY : SearchStatus.SUCCESS,
73
+ response: result,
74
+ sections: pickSectionResults(response, requested, locale),
70
75
  error: undefined,
71
76
  });
72
77
  }
@@ -77,7 +82,12 @@ export function createSearchController({ search, analytics, navigate, debounceMs
77
82
  if (id !== requestId) {
78
83
  return;
79
84
  }
80
- setState({ status: SearchStatus.ERROR, error, response: undefined });
85
+ setState({
86
+ status: SearchStatus.ERROR,
87
+ error,
88
+ response: undefined,
89
+ sections: undefined,
90
+ });
81
91
  }
82
92
  };
83
93
  // Shared by `setQuery`/`submit`: undefined = reset to idle (query too short).
@@ -146,7 +156,7 @@ export function createSearchController({ search, analytics, navigate, debounceMs
146
156
  return false;
147
157
  }
148
158
  controllerAnalytics.select(response, index);
149
- const url = response.hits[index].product.url;
159
+ const url = response.hits[index].url;
150
160
  const runAdapter = options?.navigate ?? true;
151
161
  if (runAdapter && navigate !== undefined && url !== undefined) {
152
162
  navigate(url, response.hits[index]);
@@ -1,7 +1,8 @@
1
- import { SearchOptions, SearchRequest, SearchResponse } from "../types/search";
1
+ import { SearchIndex, SearchOptions, SearchRequest, SearchResponse } from "../types/search";
2
+ export declare const searchIndexName: (index: SearchIndex, locale: string) => string;
2
3
  /**
3
4
  * One POST per invocation — no debounce, cache, retry or request state; the
4
5
  * caller owns cancellation through `options.signal`.
5
6
  */
6
- export declare const searchProducts: (apiKey: string, request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
7
+ export declare const searchLexical: (apiKey: string, request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
7
8
  //# sourceMappingURL=search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/services/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAgC/E;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,QAAQ,MAAM,EACd,SAAS,aAAa,EACtB,UAAU,aAAa,KACtB,OAAO,CAAC,cAAc,CAgBxB,CAAC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/services/search.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAC;AAMzB,eAAO,MAAM,eAAe,GAAI,OAAO,WAAW,EAAE,QAAQ,MAAM,KAAG,MACzB,CAAC;AAoB7C;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,EACd,SAAS,aAAa,EACtB,UAAU,aAAa,KACtB,OAAO,CAAC,cAAc,CAgBxB,CAAC"}
@@ -1,8 +1,9 @@
1
1
  import { config } from "../config";
2
2
  import { DialogSearchError } from "../DialogSearchError";
3
3
  import { toIso639LanguageCode } from "../utils/localization";
4
- const SEARCH_PATH = "/public/search";
4
+ const SEARCH_PATH = "/public/search/lexical";
5
5
  const API_KEY_HEADER = "x-dialog-api-key";
6
+ export const searchIndexName = (index, locale) => `${index}_${toIso639LanguageCode(locale)}`;
6
7
  const toSearchError = async (response) => {
7
8
  let body;
8
9
  try {
@@ -17,24 +18,18 @@ const toSearchError = async (response) => {
17
18
  : response.statusText;
18
19
  return new DialogSearchError({ status: response.status, code, message });
19
20
  };
20
- // Every search path (Dialog instance, search controller, direct transport)
21
- // funnels through here, so the locale reaches the wire as the bare ISO 639-1
22
- // language whatever tag the caller holds.
23
- const withNormalizedLocale = (request) => request.locale === undefined
24
- ? request
25
- : { ...request, locale: toIso639LanguageCode(request.locale) };
26
21
  /**
27
22
  * One POST per invocation — no debounce, cache, retry or request state; the
28
23
  * caller owns cancellation through `options.signal`.
29
24
  */
30
- export const searchProducts = async (apiKey, request, options) => {
25
+ export const searchLexical = async (apiKey, request, options) => {
31
26
  const response = await fetch(`${config.monolithApiUrl}${SEARCH_PATH}`, {
32
27
  method: "POST",
33
28
  headers: {
34
29
  "Content-Type": "application/json",
35
30
  [API_KEY_HEADER]: apiKey,
36
31
  },
37
- body: JSON.stringify(withNormalizedLocale(request)),
32
+ body: JSON.stringify(request),
38
33
  signal: options?.signal,
39
34
  });
40
35
  if (!response.ok) {
@@ -5,6 +5,11 @@ export interface DialogCallbacks {
5
5
  addToCart: (input: AddToCartInput) => Promise<void>;
6
6
  getProduct: (productId: string, variantId?: string) => Promise<SimplifiedProduct>;
7
7
  }
8
+ export interface CurrentProduct {
9
+ /** The catalog product id — must match the id in the Dialog product feed. */
10
+ id: string;
11
+ variantId?: string;
12
+ }
8
13
  export interface DialogConstructor {
9
14
  apiKey: string;
10
15
  locale: string;
@@ -40,5 +45,15 @@ export interface DialogConstructor {
40
45
  * Product links and recommendation browsing are unaffected.
41
46
  */
42
47
  disableAddToCart?: boolean;
48
+ /**
49
+ * The product of the page the SDK is instantiated on, when it is a product
50
+ * page. The assistant uses it as the conversation's product context for
51
+ * entry points that carry no product of their own (floating bookmark,
52
+ * resume surface, free-text questions), so answers stay grounded on the
53
+ * product under the visitor's eyes after PDP-to-PDP navigation. On
54
+ * single-page storefronts, update it on navigation with
55
+ * `setCurrentProduct()` / `clearCurrentProduct()`.
56
+ */
57
+ product?: CurrentProduct;
43
58
  }
44
59
  //# sourceMappingURL=constructor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constructor.d.ts","sourceRoot":"","sources":["../../src/types/constructor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
1
+ {"version":3,"file":"constructor.d.ts","sourceRoot":"","sources":["../../src/types/constructor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B"}
@@ -1,14 +1,18 @@
1
- export interface SearchRequest {
1
+ /** Logical indices the public search serves; the wire name adds the locale. */
2
+ export declare const SEARCH_INDICES: readonly ["products", "collections", "articles", "pages"];
3
+ export type SearchIndex = (typeof SEARCH_INDICES)[number];
4
+ export interface SearchQuery {
5
+ /** `<index>_<locale>` (e.g. `products_fr`), one shared locale per request; unknown or unserved → 404. */
6
+ indexName: string;
2
7
  /** Trimmed server-side; must keep at least two visible characters (code points). */
3
8
  query: string;
4
9
  /** Zero-indexed results page. Defaults to 0 server-side. */
5
10
  page?: number;
6
11
  /** Between 1 and 100. Defaults to 20 server-side. */
7
12
  hitsPerPage?: number;
8
- /** Previous response's queryId while the query is unchanged; omit for a new query. */
9
- queryId?: string;
10
- locale?: string;
11
- countryCode?: string;
13
+ }
14
+ export interface SearchRequest {
15
+ requests: SearchQuery[];
12
16
  }
13
17
  export interface SearchOptions {
14
18
  /** Forwarded to fetch untouched: aborting rejects with the native AbortError. */
@@ -17,41 +21,39 @@ export interface SearchOptions {
17
21
  export interface SearchPrice {
18
22
  /** Decimal amount as a string, exactly as indexed (e.g. "24.90"). */
19
23
  amount: string;
20
- currencyCode: string;
24
+ /** Absent when the price was indexed without a currency. */
25
+ currencyCode?: string;
21
26
  }
22
27
  export interface SearchPriceRange {
23
28
  min: SearchPrice;
24
29
  max: SearchPrice;
25
30
  }
26
31
  /**
27
- * Storefront-ready projection of a search hit. Every display field is
28
- * best-effort: a product may carry only its id.
32
+ * A flat, storefront-ready record: `objectID` plus the record's attributes.
33
+ * Every display field is best-effort a hit may carry only its id;
34
+ * `priceRange` only comes from the products index.
29
35
  */
30
- export interface SearchProduct {
31
- id: string;
36
+ export interface SearchHit {
37
+ objectID: string;
32
38
  title?: string;
33
39
  url?: string;
34
- /** Shopify URL handle, lets the storefront build `/products/{handle}` when `url` is absent (DEC-2543). */
35
40
  handle?: string;
36
41
  imageUrl?: string;
37
42
  priceRange?: SearchPriceRange;
38
- compareAtPriceRange?: SearchPriceRange;
39
- inStock?: boolean;
40
43
  }
41
- export interface SearchHit {
42
- id: string;
43
- score: number;
44
- product: SearchProduct;
45
- }
46
- export interface SearchResponse {
47
- /** Engine-generated id for search attribution analytics. */
48
- queryId: string;
44
+ export interface SearchResult {
45
+ index: string;
49
46
  hits: SearchHit[];
50
47
  nbHits: number;
51
48
  page: number;
52
49
  nbPages: number;
53
50
  hitsPerPage: number;
54
- processingTimeMs: number;
51
+ processingTimeMS: number;
55
52
  query: string;
53
+ queryID: string;
54
+ }
55
+ /** One entry per request entry, in request order. */
56
+ export interface SearchResponse {
57
+ results: SearchResult[];
56
58
  }
57
59
  //# sourceMappingURL=search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,WAAW,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0GAA0G;IAC1G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,mBAAmB,CAAC,EAAE,gBAAgB,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,eAAO,MAAM,cAAc,2DAKjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B,yGAAyG;IACzG,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,WAAW,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB"}
@@ -1,4 +1,7 @@
1
- // Mirrors the public Nest storefront-search DTO exactly (POST /public/search,
2
- // `storefrontSearchRequestSchema` / `storefrontSearchResponseSchema` in
3
- // @dialog/shared-schemas) — camelCase wire format, no internal Python casing.
4
- export {};
1
+ /** Logical indices the public search serves; the wire name adds the locale. */
2
+ export const SEARCH_INDICES = [
3
+ "products",
4
+ "collections",
5
+ "articles",
6
+ "pages",
7
+ ];
@@ -4,6 +4,8 @@ export declare const SEARCH_TYPES: readonly ["lexical"];
4
4
  export type SearchType = (typeof SEARCH_TYPES)[number];
5
5
  export interface SearchAnalyticsEnvelope {
6
6
  query_id: string;
7
+ /** Public index name the result came from (e.g. `products_fr`) — the Algolia Insights tuple's index. */
8
+ index: string;
7
9
  /** Where results are displayed — not the integration technology. */
8
10
  surface: SearchSurface;
9
11
  /** Retrieval mode that produced the results. */
@@ -1 +1 @@
1
- {"version":3,"file":"searchAnalytics.d.ts","sourceRoot":"","sources":["../../src/types/searchAnalytics.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,uEAKlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,YAAY,sBAAuB,CAAC;AAEjD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAQvD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,aAAa,CAAC;IACvB,gDAAgD;IAChD,WAAW,EAAE,UAAU,CAAC;IACxB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAGD,MAAM,WAAW,wBAAyB,SAAQ,uBAAuB;IACvE,KAAK,EAAE,CAAC,gBAAgB,CAAC,CAAC;CAC3B;AAKD,MAAM,WAAW,6BAA8B,SAAQ,uBAAuB;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,8BACf,SAAQ,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"searchAnalytics.d.ts","sourceRoot":"","sources":["../../src/types/searchAnalytics.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,uEAKlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,YAAY,sBAAuB,CAAC;AAEjD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,wGAAwG;IACxG,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,EAAE,aAAa,CAAC;IACvB,gDAAgD;IAChD,WAAW,EAAE,UAAU,CAAC;IACxB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAGD,MAAM,WAAW,wBAAyB,SAAQ,uBAAuB;IACvE,KAAK,EAAE,CAAC,gBAAgB,CAAC,CAAC;CAC3B;AAKD,MAAM,WAAW,6BAA8B,SAAQ,uBAAuB;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,8BACf,SAAQ,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -1,4 +1,4 @@
1
- import { SearchHit, SearchOptions, SearchRequest, SearchResponse } from "./search";
1
+ import { SearchHit, SearchIndex, SearchOptions, SearchRequest, SearchResponse, SearchResult } from "./search";
2
2
  import { SearchSurface, SelectSearchResultParams, ViewSearchResultsParams } from "./searchAnalytics";
3
3
  export declare const SearchStatus: {
4
4
  readonly IDLE: "idle";
@@ -9,14 +9,22 @@ export declare const SearchStatus: {
9
9
  readonly ERROR: "error";
10
10
  };
11
11
  export type SearchStatus = (typeof SearchStatus)[keyof typeof SearchStatus];
12
+ export interface SearchSection {
13
+ index: Exclude<SearchIndex, "products">;
14
+ hitsPerPage?: number;
15
+ }
12
16
  export interface SearchControllerState {
13
17
  status: SearchStatus;
14
18
  /** Last committed (run) query — not the text currently being typed. */
15
19
  query: string;
16
20
  /** Zero-indexed page of the last run. */
17
21
  page: number;
18
- /** Last landed response; kept while the next page loads, cleared on error. */
19
- response?: SearchResponse;
22
+ /**
23
+ * Products entry of the last landed response; kept while the next page
24
+ * loads, cleared on error. Hits are flat records (`objectID`, `title`, …).
25
+ */
26
+ response?: SearchResult;
27
+ sections?: Partial<Record<SearchIndex, SearchResult>>;
20
28
  error?: unknown;
21
29
  }
22
30
  export type SearchFunction = (request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
@@ -44,8 +52,8 @@ export interface SearchControllerOptions {
44
52
  navigate?: (url: string, hit: SearchHit) => void;
45
53
  debounceMs?: number;
46
54
  hitsPerPage?: number;
47
- locale?: string;
48
- countryCode?: string;
55
+ locale: string;
56
+ sections?: readonly SearchSection[] | (() => readonly SearchSection[]);
49
57
  }
50
58
  /**
51
59
  * Framework-agnostic stateful search behavior around the stateless
@@ -1 +1 @@
1
- {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,YAAY;;;;IAIvB,yGAAyG;;;CAGjG,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,sBAAsB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAClE,uBAAuB,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;IACvE,mEAAmE;IACnE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxE,QAAQ,IAAI,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,YAAY;;;;IAIvB,yGAAyG;;;CAGjG,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,sBAAsB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAClE,uBAAuB,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,CAAC,MAAM,SAAS,aAAa,EAAE,CAAC,CAAC;CACxE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;IACvE,mEAAmE;IACnE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxE,QAAQ,IAAI,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB"}
@@ -1,13 +1,13 @@
1
- import { SearchResponse } from "../types/search";
1
+ import { SearchResult } from "../types/search";
2
2
  import { SearchControllerAnalytics } from "../types/searchController";
3
3
  /**
4
4
  * Internal DEC-2448 wiring of the search controller: envelope computation,
5
5
  * viewport impressions and selection attribution. Not part of the public API.
6
6
  */
7
7
  export interface ControllerAnalyticsBinding {
8
- onResponse(response: SearchResponse): void;
9
- observeResult(element: Element, response: SearchResponse, index: number): void;
10
- select(response: SearchResponse, index: number): void;
8
+ onResponse(result: SearchResult): void;
9
+ observeResult(element: Element, result: SearchResult, index: number): void;
10
+ select(result: SearchResult, index: number): void;
11
11
  dispose(): void;
12
12
  }
13
13
  export declare function createControllerAnalytics(analytics: SearchControllerAnalytics): ControllerAnalyticsBinding;
@@ -1 +1 @@
1
- {"version":3,"file":"searchControllerAnalytics.d.ts","sourceRoot":"","sources":["../../src/utils/searchControllerAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAMtE;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,UAAU,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAC3C,aAAa,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,MAAM,GACZ,IAAI,CAAC;IACR,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACtD,OAAO,IAAI,IAAI,CAAC;CACjB;AAWD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,yBAAyB,GACnC,0BAA0B,CAoD5B"}
1
+ {"version":3,"file":"searchControllerAnalytics.d.ts","sourceRoot":"","sources":["../../src/utils/searchControllerAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAMtE;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3E,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD,OAAO,IAAI,IAAI,CAAC;CACjB;AAQD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,yBAAyB,GACnC,0BAA0B,CAkD5B"}
@@ -1,8 +1,8 @@
1
1
  import { createSearchImpressionTracker, } from "./searchImpressions";
2
- const resultItem = (response, index) => ({
3
- product_id: response.hits[index].product.id,
2
+ const resultItem = (result, index) => ({
3
+ product_id: result.hits[index].objectID,
4
4
  // 1-based and absolute across pages (page 2, first item, 20/page → 21).
5
- position: response.page * response.hitsPerPage + index + 1,
5
+ position: result.page * result.hitsPerPage + index + 1,
6
6
  });
7
7
  export function createControllerAnalytics(analytics) {
8
8
  let impressions;
@@ -16,35 +16,33 @@ export function createControllerAnalytics(analytics) {
16
16
  return impressions;
17
17
  };
18
18
  return {
19
- onResponse(response) {
19
+ onResponse(result) {
20
20
  envelope = {
21
- // Straight off the response: the controller resends the previous
22
- // queryId while the query text is unchanged, so the id is stable
23
- // across pagination and rotates with the query.
24
- query_id: response.queryId,
21
+ query_id: result.queryID,
22
+ index: result.index,
25
23
  surface: analytics.surface,
26
24
  // The storefront search API is lexical-only today.
27
25
  search_type: "lexical",
28
26
  // Analytics pages are 1-based; the wire response is 0-based.
29
- page: response.page + 1,
30
- total_hits: response.nbHits,
31
- query_length: [...response.query].length,
27
+ page: result.page + 1,
28
+ total_hits: result.nbHits,
29
+ query_length: [...result.query].length,
32
30
  };
33
31
  tracker().setContext(envelope);
34
- if (response.nbHits === 0) {
32
+ if (result.nbHits === 0) {
35
33
  // A rendered no-results state is the view event with zero items; it
36
34
  // shows above the fold, no viewport gating needed.
37
35
  analytics.trackViewSearchResults({ ...envelope, items: [] });
38
36
  }
39
37
  },
40
- observeResult(element, response, index) {
41
- tracker().observe(element, resultItem(response, index));
38
+ observeResult(element, result, index) {
39
+ tracker().observe(element, resultItem(result, index));
42
40
  },
43
- select(response, index) {
41
+ select(result, index) {
44
42
  if (envelope === undefined) {
45
43
  return;
46
44
  }
47
- const item = resultItem(response, index);
45
+ const item = resultItem(result, index);
48
46
  // The click forces the item's impression so CTR by position stays ≤100%.
49
47
  tracker().forceImpression(item);
50
48
  analytics.trackSelectSearchResult({ ...envelope, items: [item] });
@@ -1 +1 @@
1
- {"version":3,"file":"searchImpressions.d.ts","sourceRoot":"","sources":["../../src/utils/searchImpressions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAWlC,MAAM,WAAW,8BAA8B;IAC7C,gFAAgF;IAChF,IAAI,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,uFAAuF;IACvF,UAAU,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACpD,gEAAgE;IAChE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxD,kFAAkF;IAClF,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC9C,KAAK,IAAI,IAAI,CAAC;IACd,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,wBAAgB,6BAA6B,CAAC,EAC5C,IAAI,EACJ,mBAAkD,EAClD,OAA0B,EAC1B,WAAmC,EACnC,gBAA8C,GAC/C,EAAE,8BAA8B,GAAG,uBAAuB,CAsI1D"}
1
+ {"version":3,"file":"searchImpressions.d.ts","sourceRoot":"","sources":["../../src/utils/searchImpressions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAWlC,MAAM,WAAW,8BAA8B;IAC7C,gFAAgF;IAChF,IAAI,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,uFAAuF;IACvF,UAAU,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACpD,gEAAgE;IAChE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxD,kFAAkF;IAClF,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC9C,KAAK,IAAI,IAAI,CAAC;IACd,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,wBAAgB,6BAA6B,CAAC,EAC5C,IAAI,EACJ,mBAAkD,EAClD,OAA0B,EAC1B,WAAmC,EACnC,gBAA8C,GAC/C,EAAE,8BAA8B,GAAG,uBAAuB,CA+H1D"}
@@ -98,12 +98,7 @@ export function createSearchImpressionTracker({ emit, visibilityThreshold = DEFA
98
98
  setContext(nextEnvelope) {
99
99
  // Pending impressions belong to the envelope they qualified under.
100
100
  flush();
101
- // Dedup only needs to span one query's lifetime (pagination keeps its
102
- // query_id): dropping older keys bounds the set across search-as-you-type.
103
- if (envelope !== undefined &&
104
- envelope.query_id !== nextEnvelope.query_id) {
105
- seen.clear();
106
- }
101
+ seen.clear();
107
102
  envelope = nextEnvelope;
108
103
  stopObserving();
109
104
  },
@@ -0,0 +1,5 @@
1
+ import { SearchIndex, SearchQuery, SearchResponse, SearchResult } from "../types/search";
2
+ import { SearchSection } from "../types/searchController";
3
+ export declare const buildSectionQueries: (sections: readonly SearchSection[], query: string, locale: string, hitsPerPage: number) => SearchQuery[];
4
+ export declare const pickSectionResults: (response: SearchResponse, sections: readonly SearchSection[], locale: string) => Partial<Record<SearchIndex, SearchResult>> | undefined;
5
+ //# sourceMappingURL=searchSections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchSections.d.ts","sourceRoot":"","sources":["../../src/utils/searchSections.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,aAAa,EAAE,EAClC,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,aAAa,MAAM,KAClB,WAAW,EAMT,CAAC;AAEN,eAAO,MAAM,kBAAkB,GAC7B,UAAU,cAAc,EACxB,UAAU,SAAS,aAAa,EAAE,EAClC,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,GAAG,SAgB/C,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { searchIndexName } from "../services/search";
2
+ export const buildSectionQueries = (sections, query, locale, hitsPerPage) => sections.map((section) => ({
3
+ indexName: searchIndexName(section.index, locale),
4
+ query,
5
+ page: 0,
6
+ hitsPerPage: section.hitsPerPage ?? hitsPerPage,
7
+ }));
8
+ export const pickSectionResults = (response, sections, locale) => {
9
+ if (sections.length === 0) {
10
+ return undefined;
11
+ }
12
+ const picked = {};
13
+ for (const section of sections) {
14
+ const sectionIndexName = searchIndexName(section.index, locale);
15
+ const entry = response.results.find((candidate) => candidate.index === sectionIndexName);
16
+ if (entry !== undefined) {
17
+ picked[section.index] = entry;
18
+ }
19
+ }
20
+ return picked;
21
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askdialog/dialog-sdk",
3
- "version": "2.9.1",
3
+ "version": "2.11.0",
4
4
  "private": false,
5
5
  "description": "Dialog SDK",
6
6
  "main": "dist/index.js",