@askdialog/dialog-sdk 2.16.0 → 2.18.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.
package/README.md CHANGED
@@ -285,8 +285,13 @@ const response: SearchResponse = await client.search({
285
285
  // A products hit is Algolia's Shopify record (`SearchProductHit`), plus `url`
286
286
  // and `currency`: { objectID (variant id), id (product id), title?, handle?,
287
287
  // url?, image?, variants_min_price?, price?, compare_at_price?, ... }
288
- // Collection, article and page hits are `SearchHit`: { objectID, title?, url?,
289
- // handle?, imageUrl? }
288
+ // Collection hits are `SearchCollectionHit`, Algolia's collection record:
289
+ // { objectID, title?, handle?, url?, body_html_safe?, image?, products_count?, ... }
290
+ // Article hits are `SearchArticleHit`, Algolia's article record:
291
+ // { objectID, title?, handle?, tags, blog?: { title?, handle? }, author?: { name },
292
+ // image?, published_at?, updated_at?, body_html_safe?, url? }
293
+ // Page hits are `SearchPageHit`, Algolia's page record:
294
+ // { objectID, title?, handle?, author?, updated_at?, body_html_safe?, url? }
290
295
  ```
291
296
 
292
297
  With the IIFE bundle the results are plain runtime JSON (same shape, no types):
@@ -326,6 +331,7 @@ const controller = createSearchController({
326
331
  trackSelectSearchResult: (params) => client.trackSelectSearchResult(params),
327
332
  },
328
333
  navigate: (url) => router.push(url), // optional platform routing adapter
334
+ buildProductUrl: (hit) => `/products/${hit.handle}`, // optional, for hits without `url`
329
335
  debounceMs: 250, // optional (default 250)
330
336
  hitsPerPage: 12, // optional (default 12)
331
337
  sections: [{ index: 'collections', hitsPerPage: 5 }], // optional, first page only; a function is resolved per request
@@ -353,7 +359,7 @@ The client uses a BCP-47 `locale` such as `fr-FR` for assistant localization. Se
353
359
 
354
360
  For Shopify, use `window.Shopify.country` as the country. Controller options are fixed at creation; recreate the controller to change language or country.
355
361
 
356
- Analytics send each product hit's `id` (the product id) as `product_id`; `navigate` receives the hit's `url`.
362
+ Analytics send each product hit's `id` (the product id) as `product_id`; `navigate` receives `controller.productUrl(hit)`: the hit's `url`, else `buildProductUrl`'s result.
357
363
 
358
364
  Framework integrations:
359
365
 
@@ -25,6 +25,8 @@ describe("public API types", () => {
25
25
  expectTypeOf().toEqualTypeOf();
26
26
  expectTypeOf().toEqualTypeOf();
27
27
  expectTypeOf().toEqualTypeOf();
28
+ expectTypeOf().toEqualTypeOf();
29
+ expectTypeOf().toEqualTypeOf();
28
30
  const error = new DialogSearchError({ status: 404, message: "not found" });
29
31
  expectTypeOf(error.status).toEqualTypeOf();
30
32
  expectTypeOf(error.code).toEqualTypeOf();
package/dist/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export * from "./services/search";
6
6
  export * from "./types";
7
7
  export { isRtlLanguageCode, resolveTextDirection, type TextDirection, } from "./utils/localization";
8
8
  export * from "./utils/searchImpressions";
9
+ export * from "./utils/searchPrice";
9
10
  export * from "./windowAudit";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -6,4 +6,5 @@ export * from "./services/search";
6
6
  export * from "./types";
7
7
  export { isRtlLanguageCode, resolveTextDirection, } from "./utils/localization";
8
8
  export * from "./utils/searchImpressions";
9
+ export * from "./utils/searchPrice";
9
10
  export * from "./windowAudit";
@@ -1,3 +1,3 @@
1
1
  import { SearchController, SearchControllerOptions } from "./types/searchController";
2
- export declare function createSearchController({ search, language, country, analytics, navigate, debounceMs, hitsPerPage, sections, }: SearchControllerOptions): SearchController;
2
+ export declare function createSearchController({ search, language, country, analytics, navigate, buildProductUrl, debounceMs, hitsPerPage, sections, }: SearchControllerOptions): SearchController;
3
3
  //# sourceMappingURL=searchController.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../src/searchController.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EAGxB,MAAM,0BAA0B,CAAC;AAiBlC,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,QAAQ,EACR,OAAO,EACP,SAAS,EACT,QAAQ,EACR,UAAgB,EAChB,WAAgB,EAChB,QAAa,GACd,EAAE,uBAAuB,GAAG,gBAAgB,CAuK5C"}
1
+ {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../src/searchController.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EAGxB,MAAM,0BAA0B,CAAC;AASlC,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,QAAQ,EACR,OAAO,EACP,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAgB,EAChB,WAAgB,EAChB,QAAa,GACd,EAAE,uBAAuB,GAAG,gBAAgB,CA4K5C"}
@@ -1,23 +1,15 @@
1
1
  import { searchIndexName } from "./services/search";
2
2
  import { SearchStatus, } from "./types/searchController";
3
3
  import { createControllerAnalytics } from "./utils/searchControllerAnalytics";
4
- import { buildSearchRequest, normalizeQuery, readSearchResults, } from "./utils/searchRequests";
5
- const INITIAL_STATE = {
6
- status: SearchStatus.IDLE,
7
- query: "",
8
- page: 0,
9
- response: undefined,
10
- sections: undefined,
11
- error: undefined,
12
- };
13
- export function createSearchController({ search, language, country, analytics, navigate, debounceMs = 250, hitsPerPage = 12, sections = [], }) {
4
+ import { buildSearchRequest, INITIAL_SEARCH_STATE, normalizeQuery, readSearchResults, } from "./utils/searchRequests";
5
+ export function createSearchController({ search, language, country, analytics, navigate, buildProductUrl, debounceMs = 250, hitsPerPage = 12, sections = [], }) {
14
6
  const requestConfig = {
15
7
  indexName: searchIndexName("products", language, country),
16
8
  language,
17
9
  country,
18
10
  hitsPerPage,
19
11
  };
20
- let state = INITIAL_STATE;
12
+ let state = INITIAL_SEARCH_STATE;
21
13
  const listeners = new Set();
22
14
  const controllerAnalytics = createControllerAnalytics(analytics);
23
15
  let debounceTimer;
@@ -31,6 +23,7 @@ export function createSearchController({ search, language, country, analytics, n
31
23
  listener(state);
32
24
  }
33
25
  };
26
+ const productUrl = (hit) => hit.url !== undefined && hit.url !== "" ? hit.url : buildProductUrl?.(hit);
34
27
  const cancelPendingSearch = () => {
35
28
  clearTimeout(debounceTimer);
36
29
  pendingQuery = undefined;
@@ -85,7 +78,7 @@ export function createSearchController({ search, language, country, analytics, n
85
78
  cancelPendingSearch();
86
79
  const query = normalizeQuery(rawQuery);
87
80
  if (query === undefined) {
88
- setState(INITIAL_STATE);
81
+ setState(INITIAL_SEARCH_STATE);
89
82
  return;
90
83
  }
91
84
  pendingQuery = query;
@@ -98,7 +91,7 @@ export function createSearchController({ search, language, country, analytics, n
98
91
  cancelPendingSearch();
99
92
  const query = normalizeQuery(rawQuery);
100
93
  if (query === undefined) {
101
- setState(INITIAL_STATE);
94
+ setState(INITIAL_SEARCH_STATE);
102
95
  return;
103
96
  }
104
97
  void run(query, 0);
@@ -135,7 +128,7 @@ export function createSearchController({ search, language, country, analytics, n
135
128
  return false;
136
129
  }
137
130
  controllerAnalytics.select(response, index);
138
- const url = response.hits[index].url;
131
+ const url = productUrl(response.hits[index]);
139
132
  const runAdapter = options?.navigate ?? true;
140
133
  if (runAdapter && navigate !== undefined && url !== undefined) {
141
134
  navigate(url, response.hits[index]);
@@ -143,6 +136,7 @@ export function createSearchController({ search, language, country, analytics, n
143
136
  }
144
137
  return false;
145
138
  },
139
+ productUrl,
146
140
  subscribe(listener) {
147
141
  listeners.add(listener);
148
142
  return () => {
@@ -22,7 +22,52 @@ export interface SearchOptions {
22
22
  /** Passed to fetch; cancellation rejects with `AbortError`. */
23
23
  signal?: AbortSignal;
24
24
  }
25
- /** A collection, article or page hit. */
25
+ /** Algolia's collection record, plus `url`. */
26
+ export interface SearchCollectionHit {
27
+ /** Collection id, the last segment of the Shopify GID. */
28
+ objectID: string;
29
+ title?: string;
30
+ handle?: string;
31
+ url?: string;
32
+ body_html?: string;
33
+ body_html_safe?: string;
34
+ image?: string;
35
+ products_count?: number;
36
+ template_suffix?: string;
37
+ updated_at?: string;
38
+ }
39
+ /** Algolia's article record, plus `url`. */
40
+ export interface SearchArticleHit {
41
+ /** Article id, the last segment of the Shopify GID. */
42
+ objectID: string;
43
+ title?: string;
44
+ handle?: string;
45
+ tags: string[];
46
+ blog?: {
47
+ title?: string;
48
+ handle?: string;
49
+ };
50
+ author?: {
51
+ name: string;
52
+ };
53
+ image?: string;
54
+ published_at?: string;
55
+ updated_at?: string;
56
+ body_html_safe?: string;
57
+ url?: string;
58
+ }
59
+ /** Algolia's page record, plus `url`. */
60
+ export interface SearchPageHit {
61
+ /** Page id, the last segment of the Shopify GID. */
62
+ objectID: string;
63
+ title?: string;
64
+ handle?: string;
65
+ author?: string;
66
+ updated_at?: string;
67
+ body_html_safe?: string;
68
+ url?: string;
69
+ }
70
+ /** @deprecated No index answers it: article hits are `SearchArticleHit`, page hits `SearchPageHit`. */
26
71
  export interface SearchHit {
27
72
  objectID: string;
28
73
  title?: string;
@@ -74,8 +119,14 @@ export interface SearchProductHit {
74
119
  updated_at?: string;
75
120
  published_at?: string;
76
121
  }
77
- /** Products results carry `SearchProductHit`, other indices `SearchHit`. */
78
- export interface SearchResult<THit = SearchProductHit | SearchHit> {
122
+ /** The hit each index answers. */
123
+ export interface SearchHitByIndex {
124
+ products: SearchProductHit;
125
+ collections: SearchCollectionHit;
126
+ articles: SearchArticleHit;
127
+ pages: SearchPageHit;
128
+ }
129
+ export interface SearchResult<THit = SearchHitByIndex[SearchIndex]> {
79
130
  index: string;
80
131
  hits: THit[];
81
132
  nbHits: number;
@@ -86,6 +137,10 @@ export interface SearchResult<THit = SearchProductHit | SearchHit> {
86
137
  query: string;
87
138
  queryID: string;
88
139
  }
140
+ /** Results of the sections searched next to products, keyed by index. */
141
+ export type SearchSections = {
142
+ [Index in Exclude<SearchIndex, "products">]?: SearchResult<SearchHitByIndex[Index]>;
143
+ };
89
144
  /** Results in request order. */
90
145
  export interface SearchResponse {
91
146
  results: SearchResult[];
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { SearchHit, SearchIndex, SearchOptions, SearchProductHit, SearchRequest, SearchResponse, SearchResult } from "./search";
1
+ import { SearchIndex, SearchOptions, SearchProductHit, SearchRequest, SearchResponse, SearchResult, SearchSections } from "./search";
2
2
  import { SearchSurface, SelectSearchResultParams, ViewSearchResultsParams } from "./searchAnalytics";
3
3
  export declare const SearchStatus: {
4
4
  readonly IDLE: "idle";
@@ -21,7 +21,7 @@ export interface SearchControllerState {
21
21
  page: number;
22
22
  /** Last products result; retained while loading and cleared on error or reset. */
23
23
  response?: SearchResult<SearchProductHit>;
24
- sections?: Partial<Record<SearchIndex, SearchResult<SearchHit>>>;
24
+ sections?: SearchSections;
25
25
  error?: unknown;
26
26
  }
27
27
  export type SearchFunction = (request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
@@ -41,6 +41,8 @@ export interface SearchControllerOptions {
41
41
  analytics: SearchControllerAnalytics;
42
42
  /** Navigate after recording selection. Omit to use native link navigation. */
43
43
  navigate?: (url: string, hit: SearchProductHit) => void;
44
+ /** Build a product's link when its hit has no `url`, e.g. `/products/${hit.handle}`. */
45
+ buildProductUrl?: (hit: SearchProductHit) => string | undefined;
44
46
  debounceMs?: number;
45
47
  hitsPerPage?: number;
46
48
  sections?: readonly SearchSection[] | (() => readonly SearchSection[]);
@@ -65,6 +67,8 @@ export interface SearchController {
65
67
  selectResult(index: number, options?: {
66
68
  navigate?: boolean;
67
69
  }): boolean;
70
+ /** The hit's `url`, else `buildProductUrl`'s result; undefined when neither gives one. */
71
+ productUrl(hit: SearchProductHit): string | undefined;
68
72
  /** Subscribe to state changes; returns an unsubscribe function. */
69
73
  subscribe(listener: (state: SearchControllerState) => void): () => void;
70
74
  getState(): SearchControllerState;
@@ -1 +1 @@
1
- {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { SearchProductHit } from "../types/search";
2
+ /** The lowest variant price only, as on the Shopify storefront search. */
3
+ export declare const formatSearchPrice: ({ variants_min_price: amount, currency }: SearchProductHit, locale?: string) => string;
4
+ /**
5
+ * The lowest compare-at price, struck next to the price, only when it is
6
+ * higher than a shown price; it may belong to another variant.
7
+ */
8
+ export declare const formatSearchCompareAtPrice: (hit: SearchProductHit, locale?: string) => string;
9
+ //# sourceMappingURL=searchPrice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchPrice.d.ts","sourceRoot":"","sources":["../../src/utils/searchPrice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAsBxD,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,GAC5B,0CAA0C,gBAAgB,EAC1D,SAAS,MAAM,KACd,MAAgD,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,KAAK,gBAAgB,EACrB,SAAS,MAAM,KACd,MAeF,CAAC"}
@@ -0,0 +1,30 @@
1
+ // Hide a missing or invalid amount; show a bare amount when currency is absent.
2
+ const formatAmount = (amount, currency, locale) => {
3
+ if (amount === undefined || !Number.isFinite(amount)) {
4
+ return "";
5
+ }
6
+ try {
7
+ return currency === undefined
8
+ ? new Intl.NumberFormat(locale).format(amount)
9
+ : new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount);
10
+ }
11
+ catch {
12
+ return "";
13
+ }
14
+ };
15
+ /** The lowest variant price only, as on the Shopify storefront search. */
16
+ export const formatSearchPrice = ({ variants_min_price: amount, currency }, locale) => formatAmount(amount, currency, locale);
17
+ /**
18
+ * The lowest compare-at price, struck next to the price, only when it is
19
+ * higher than a shown price; it may belong to another variant.
20
+ */
21
+ export const formatSearchCompareAtPrice = (hit, locale) => {
22
+ const { variants_min_price: price, variants_compare_at_price_min: compareAt, } = hit;
23
+ if (price === undefined ||
24
+ compareAt === undefined ||
25
+ !(compareAt > price) ||
26
+ formatSearchPrice(hit, locale) === "") {
27
+ return "";
28
+ }
29
+ return formatAmount(compareAt, hit.currency, locale);
30
+ };
@@ -1,5 +1,6 @@
1
- import { SearchHit, SearchIndex, SearchProductHit, SearchRequest, SearchResponse, SearchResult } from "../types/search";
2
- import { SearchSection } from "../types/searchController";
1
+ import { SearchProductHit, SearchRequest, SearchResponse, SearchResult, SearchSections } from "../types/search";
2
+ import { SearchControllerState, SearchSection } from "../types/searchController";
3
+ export declare const INITIAL_SEARCH_STATE: SearchControllerState;
3
4
  export declare const normalizeQuery: (rawQuery: string) => string | undefined;
4
5
  interface SearchRequestConfig {
5
6
  indexName: string;
@@ -9,7 +10,7 @@ interface SearchRequestConfig {
9
10
  }
10
11
  interface SearchResults {
11
12
  response: SearchResult<SearchProductHit>;
12
- sections: Partial<Record<SearchIndex, SearchResult<SearchHit>>> | undefined;
13
+ sections: SearchSections | undefined;
13
14
  }
14
15
  export declare const buildSearchRequest: (query: string, page: number, sections: readonly SearchSection[], { indexName, language, country, hitsPerPage }: SearchRequestConfig) => SearchRequest;
15
16
  export declare const readSearchResults: (result: SearchResponse, requested: readonly SearchSection[], { indexName, language, country }: SearchRequestConfig) => SearchResults;
@@ -1 +1 @@
1
- {"version":3,"file":"searchRequests.d.ts","sourceRoot":"","sources":["../../src/utils/searchRequests.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK1D,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAI1D,CAAC;AAEF,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,aAAa;IACrB,QAAQ,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;IACzC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7E;AAED,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,UAAU,SAAS,aAAa,EAAE,EAClC,+CAA+C,mBAAmB,KACjE,aAUD,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,cAAc,EACtB,WAAW,SAAS,aAAa,EAAE,EACnC,kCAAkC,mBAAmB,KACpD,aAyBF,CAAC"}
1
+ {"version":3,"file":"searchRequests.d.ts","sourceRoot":"","sources":["../../src/utils/searchRequests.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,cAAc,EACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qBAAqB,EACrB,aAAa,EAEd,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,oBAAoB,EAAE,qBAOlC,CAAC;AAKF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAI1D,CAAC;AAEF,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,aAAa;IACrB,QAAQ,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;IACzC,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAC;CACtC;AAED,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,MAAM,MAAM,EACZ,UAAU,SAAS,aAAa,EAAE,EAClC,+CAA+C,mBAAmB,KACjE,aAUD,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,cAAc,EACtB,WAAW,SAAS,aAAa,EAAE,EACnC,kCAAkC,mBAAmB,KACpD,aAyBF,CAAC"}
@@ -1,4 +1,13 @@
1
1
  import { searchIndexName } from "../services/search";
2
+ import { SearchStatus, } from "../types/searchController";
3
+ export const INITIAL_SEARCH_STATE = {
4
+ status: SearchStatus.IDLE,
5
+ query: "",
6
+ page: 0,
7
+ response: undefined,
8
+ sections: undefined,
9
+ error: undefined,
10
+ };
2
11
  // Match the API minimum query length.
3
12
  const MIN_QUERY_CODE_POINTS = 2;
4
13
  export const normalizeQuery = (rawQuery) => {
@@ -30,7 +39,7 @@ export const readSearchResults = (result, requested, { indexName, language, coun
30
39
  }
31
40
  }
32
41
  return {
33
- // The products index answers product records only.
42
+ // Each index answers its own record type.
34
43
  response: response,
35
44
  sections: requested.length === 0 ? undefined : sections,
36
45
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askdialog/dialog-sdk",
3
- "version": "2.16.0",
3
+ "version": "2.18.0",
4
4
  "private": false,
5
5
  "description": "Dialog SDK",
6
6
  "main": "dist/index.js",