@askdialog/dialog-sdk 2.16.0 → 2.17.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,9 @@ 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 and page hits are `SearchHit`: { objectID, title?, url?, handle?, imageUrl? }
290
291
  ```
291
292
 
292
293
  With the IIFE bundle the results are plain runtime JSON (same shape, no types):
@@ -326,6 +327,7 @@ const controller = createSearchController({
326
327
  trackSelectSearchResult: (params) => client.trackSelectSearchResult(params),
327
328
  },
328
329
  navigate: (url) => router.push(url), // optional platform routing adapter
330
+ buildProductUrl: (hit) => `/products/${hit.handle}`, // optional, for hits without `url`
329
331
  debounceMs: 250, // optional (default 250)
330
332
  hitsPerPage: 12, // optional (default 12)
331
333
  sections: [{ index: 'collections', hitsPerPage: 5 }], // optional, first page only; a function is resolved per request
@@ -353,7 +355,7 @@ The client uses a BCP-47 `locale` such as `fr-FR` for assistant localization. Se
353
355
 
354
356
  For Shopify, use `window.Shopify.country` as the country. Controller options are fixed at creation; recreate the controller to change language or country.
355
357
 
356
- Analytics send each product hit's `id` (the product id) as `product_id`; `navigate` receives the hit's `url`.
358
+ 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
359
 
358
360
  Framework integrations:
359
361
 
@@ -25,6 +25,7 @@ describe("public API types", () => {
25
25
  expectTypeOf().toEqualTypeOf();
26
26
  expectTypeOf().toEqualTypeOf();
27
27
  expectTypeOf().toEqualTypeOf();
28
+ expectTypeOf().toEqualTypeOf();
28
29
  const error = new DialogSearchError({ status: 404, message: "not found" });
29
30
  expectTypeOf(error.status).toEqualTypeOf();
30
31
  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,21 @@ 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
+ /** An article or page hit. */
26
40
  export interface SearchHit {
27
41
  objectID: string;
28
42
  title?: string;
@@ -74,8 +88,14 @@ export interface SearchProductHit {
74
88
  updated_at?: string;
75
89
  published_at?: string;
76
90
  }
77
- /** Products results carry `SearchProductHit`, other indices `SearchHit`. */
78
- export interface SearchResult<THit = SearchProductHit | SearchHit> {
91
+ /** The hit each index answers. */
92
+ export interface SearchHitByIndex {
93
+ products: SearchProductHit;
94
+ collections: SearchCollectionHit;
95
+ articles: SearchHit;
96
+ pages: SearchHit;
97
+ }
98
+ export interface SearchResult<THit = SearchHitByIndex[SearchIndex]> {
79
99
  index: string;
80
100
  hits: THit[];
81
101
  nbHits: number;
@@ -86,6 +106,10 @@ export interface SearchResult<THit = SearchProductHit | SearchHit> {
86
106
  query: string;
87
107
  queryID: string;
88
108
  }
109
+ /** Results of the sections searched next to products, keyed by index. */
110
+ export type SearchSections = {
111
+ [Index in Exclude<SearchIndex, "products">]?: SearchResult<SearchHitByIndex[Index]>;
112
+ };
89
113
  /** Results in request order. */
90
114
  export interface SearchResponse {
91
115
  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.17.0",
4
4
  "private": false,
5
5
  "description": "Dialog SDK",
6
6
  "main": "dist/index.js",