@askdialog/dialog-sdk 2.15.1 → 2.16.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 +14 -9
- package/dist/__tests__/dialogSearchAnalytics.spec.js +1 -1
- package/dist/__tests__/publicTypes.spec.js +6 -1
- package/dist/__tests__/searchController.spec.js +15 -15
- package/dist/__tests__/searchControllerAttribution.spec.js +23 -13
- package/dist/__tests__/searchImpressions.spec.js +1 -1
- package/dist/__tests__/searchService.spec.js +9 -10
- package/dist/searchController.d.ts +1 -1
- package/dist/searchController.d.ts.map +1 -1
- package/dist/searchController.js +3 -3
- package/dist/services/search.d.ts +2 -2
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +5 -5
- package/dist/types/search.d.ts +51 -17
- package/dist/types/search.d.ts.map +1 -1
- package/dist/types/search.js +1 -1
- package/dist/types/searchAnalytics.d.ts +1 -1
- package/dist/types/searchAnalytics.d.ts.map +1 -1
- package/dist/types/searchController.d.ts +6 -6
- package/dist/types/searchController.d.ts.map +1 -1
- package/dist/utils/searchControllerAnalytics.d.ts +4 -4
- package/dist/utils/searchControllerAnalytics.d.ts.map +1 -1
- package/dist/utils/searchControllerAnalytics.js +2 -1
- package/dist/utils/searchRequests.d.ts +6 -6
- package/dist/utils/searchRequests.d.ts.map +1 -1
- package/dist/utils/searchRequests.js +6 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -260,9 +260,9 @@ Example of expected result:
|
|
|
260
260
|
|
|
261
261
|
- Search products
|
|
262
262
|
|
|
263
|
-
`client.search()` sends a multi-index request to the public search API. Build names with `searchIndexName(index, language,
|
|
263
|
+
`client.search()` sends a multi-index request to the public search API. Build names with `searchIndexName(index, language, country)`: `<index>_<lang>_<country>`, e.g. `products_fr_be`. Supported indices: `products`, `collections`, `articles`, `pages`. Language must be a lowercase ISO 639-1 code (`fr`, `en`). Regional locales such as `fr-FR` are rejected. The country is the shopper's ISO 3166-1 alpha-2 code, lowercased in the index name.
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
The country is required and independent of language: `fr` with `CA` produces `products_fr_ca`. Product prices are in the base currency of the market that sells to that country. Names without a country suffix return 404.
|
|
266
266
|
|
|
267
267
|
```typescript
|
|
268
268
|
import { Dialog, DialogSearchError, searchIndexName } from '@askdialog/dialog-sdk';
|
|
@@ -273,7 +273,7 @@ const client = new Dialog({ apiKey: 'YOUR_API_KEY', locale: 'fr-FR', currency: '
|
|
|
273
273
|
const response: SearchResponse = await client.search({
|
|
274
274
|
requests: [
|
|
275
275
|
{
|
|
276
|
-
indexName: searchIndexName('products', 'fr',
|
|
276
|
+
indexName: searchIndexName('products', 'fr', 'BE'), // "products_fr_be"
|
|
277
277
|
query: 'shampoo',
|
|
278
278
|
page: 0, // optional, zero-indexed (default 0)
|
|
279
279
|
hitsPerPage: 20, // optional, 1-100 (default 20)
|
|
@@ -282,8 +282,11 @@ const response: SearchResponse = await client.search({
|
|
|
282
282
|
});
|
|
283
283
|
// response.results[n]: { index, hits, nbHits, page, nbPages, hitsPerPage,
|
|
284
284
|
// processingTimeMS, query, queryID }
|
|
285
|
-
//
|
|
286
|
-
//
|
|
285
|
+
// A products hit is Algolia's Shopify record (`SearchProductHit`), plus `url`
|
|
286
|
+
// and `currency`: { objectID (variant id), id (product id), title?, handle?,
|
|
287
|
+
// url?, image?, variants_min_price?, price?, compare_at_price?, ... }
|
|
288
|
+
// Collection, article and page hits are `SearchHit`: { objectID, title?, url?,
|
|
289
|
+
// handle?, imageUrl? }
|
|
287
290
|
```
|
|
288
291
|
|
|
289
292
|
With the IIFE bundle the results are plain runtime JSON (same shape, no types):
|
|
@@ -293,7 +296,7 @@ With the IIFE bundle the results are plain runtime JSON (same shape, no types):
|
|
|
293
296
|
<script>
|
|
294
297
|
const client = new window.DialogSDK.Dialog({ apiKey: 'YOUR_API_KEY', locale: 'fr-FR', currency: 'EUR' });
|
|
295
298
|
client
|
|
296
|
-
.search({ requests: [{ indexName: '
|
|
299
|
+
.search({ requests: [{ indexName: 'products_fr_be', query: 'shampoo' }] })
|
|
297
300
|
.then((response) => console.log(response.results[0].hits));
|
|
298
301
|
</script>
|
|
299
302
|
```
|
|
@@ -316,7 +319,7 @@ const client = new Dialog({ apiKey: 'YOUR_API_KEY', locale: 'fr-FR', currency: '
|
|
|
316
319
|
const controller = createSearchController({
|
|
317
320
|
search: (request, options) => client.search(request, options),
|
|
318
321
|
language: 'fr',
|
|
319
|
-
|
|
322
|
+
country: 'BE', // shopper's country
|
|
320
323
|
analytics: {
|
|
321
324
|
surface: 'search_page', // where results are displayed
|
|
322
325
|
trackViewSearchResults: (params) => client.trackViewSearchResults(params),
|
|
@@ -346,9 +349,11 @@ retryButton.onclick = () => controller.retry();
|
|
|
346
349
|
controller.dispose();
|
|
347
350
|
```
|
|
348
351
|
|
|
349
|
-
The client uses a BCP-47 `locale` such as `fr-FR` for assistant localization. Search controllers and React/Vue hooks require explicit `language` (ISO 639-1) and `
|
|
352
|
+
The client uses a BCP-47 `locale` such as `fr-FR` for assistant localization. Search controllers and React/Vue hooks require explicit `language` (ISO 639-1) and `country` (the shopper's ISO 3166-1 alpha-2 country), independently of the client locale.
|
|
350
353
|
|
|
351
|
-
For Shopify, use `window.Shopify.
|
|
354
|
+
For Shopify, use `window.Shopify.country` as the country. Controller options are fixed at creation; recreate the controller to change language or country.
|
|
355
|
+
|
|
356
|
+
Analytics send each product hit's `id` (the product id) as `product_id`; `navigate` receives the hit's `url`.
|
|
352
357
|
|
|
353
358
|
Framework integrations:
|
|
354
359
|
|
|
@@ -19,7 +19,12 @@ describe("public API types", () => {
|
|
|
19
19
|
expectTypeOf().toEqualTypeOf();
|
|
20
20
|
expectTypeOf().toEqualTypeOf();
|
|
21
21
|
expectTypeOf().toEqualTypeOf();
|
|
22
|
-
expectTypeOf().
|
|
22
|
+
expectTypeOf().toEqualTypeOf();
|
|
23
|
+
expectTypeOf().toEqualTypeOf();
|
|
24
|
+
expectTypeOf().toEqualTypeOf();
|
|
25
|
+
expectTypeOf().toEqualTypeOf();
|
|
26
|
+
expectTypeOf().toEqualTypeOf();
|
|
27
|
+
expectTypeOf().toEqualTypeOf();
|
|
23
28
|
const error = new DialogSearchError({ status: 404, message: "not found" });
|
|
24
29
|
expectTypeOf(error.status).toEqualTypeOf();
|
|
25
30
|
expectTypeOf(error.code).toEqualTypeOf();
|
|
@@ -15,7 +15,7 @@ const DEBOUNCE_MS = 250;
|
|
|
15
15
|
const response = (overrides = {}) => ({
|
|
16
16
|
results: [
|
|
17
17
|
{
|
|
18
|
-
index: "
|
|
18
|
+
index: "products_fr_fr",
|
|
19
19
|
hits: [{ objectID: "p1" }, { objectID: "p2" }],
|
|
20
20
|
nbHits: 2,
|
|
21
21
|
page: 0,
|
|
@@ -50,7 +50,7 @@ const createController = () => {
|
|
|
50
50
|
const controller = createSearchController({
|
|
51
51
|
search,
|
|
52
52
|
language: "fr",
|
|
53
|
-
|
|
53
|
+
country: "FR",
|
|
54
54
|
analytics: {
|
|
55
55
|
surface: "search_page",
|
|
56
56
|
trackViewSearchResults,
|
|
@@ -94,24 +94,24 @@ describe("createSearchController", () => {
|
|
|
94
94
|
});
|
|
95
95
|
expect(controller.getState().status).toBe(SearchStatus.SUCCESS);
|
|
96
96
|
});
|
|
97
|
-
it("sends one products entry with
|
|
97
|
+
it("sends one products entry with the language and the shopper's country", async () => {
|
|
98
98
|
const controller = createSearchController({
|
|
99
99
|
search,
|
|
100
100
|
language: "fr",
|
|
101
|
-
|
|
101
|
+
country: "US",
|
|
102
102
|
analytics: {
|
|
103
103
|
surface: "search_page",
|
|
104
104
|
trackViewSearchResults,
|
|
105
105
|
trackSelectSearchResult,
|
|
106
106
|
},
|
|
107
107
|
});
|
|
108
|
-
search.mockResolvedValue(response({ query: "shoes", index: "
|
|
108
|
+
search.mockResolvedValue(response({ query: "shoes", index: "products_fr_us" }));
|
|
109
109
|
controller.submit("shoes");
|
|
110
110
|
await settle();
|
|
111
111
|
expect(search.mock.calls[0][0]).toEqual({
|
|
112
112
|
requests: [
|
|
113
113
|
{
|
|
114
|
-
indexName: "
|
|
114
|
+
indexName: "products_fr_us",
|
|
115
115
|
query: "shoes",
|
|
116
116
|
page: 0,
|
|
117
117
|
hitsPerPage: 12,
|
|
@@ -305,7 +305,7 @@ describe("createSearchController", () => {
|
|
|
305
305
|
const controller = createSearchController({
|
|
306
306
|
search,
|
|
307
307
|
language: "fr",
|
|
308
|
-
|
|
308
|
+
country: "US",
|
|
309
309
|
analytics: {
|
|
310
310
|
surface: "search_page",
|
|
311
311
|
trackViewSearchResults,
|
|
@@ -315,30 +315,30 @@ describe("createSearchController", () => {
|
|
|
315
315
|
});
|
|
316
316
|
const collections = {
|
|
317
317
|
...response().results[0],
|
|
318
|
-
index: "
|
|
318
|
+
index: "collections_fr_us",
|
|
319
319
|
hits: [{ objectID: "c1" }],
|
|
320
320
|
nbHits: 1,
|
|
321
321
|
};
|
|
322
322
|
search.mockResolvedValueOnce({
|
|
323
|
-
results: [...response({ index: "
|
|
323
|
+
results: [...response({ index: "products_fr_us" }).results, collections],
|
|
324
324
|
});
|
|
325
325
|
controller.submit("shoes");
|
|
326
326
|
await settle();
|
|
327
327
|
expect(search.mock.calls[0][0].requests).toEqual([
|
|
328
328
|
{
|
|
329
|
-
indexName: "
|
|
329
|
+
indexName: "products_fr_us",
|
|
330
330
|
query: "shoes",
|
|
331
331
|
page: 0,
|
|
332
332
|
hitsPerPage: 12,
|
|
333
333
|
},
|
|
334
334
|
{
|
|
335
|
-
indexName: "
|
|
335
|
+
indexName: "collections_fr_us",
|
|
336
336
|
query: "shoes",
|
|
337
337
|
page: 0,
|
|
338
338
|
hitsPerPage: 5,
|
|
339
339
|
},
|
|
340
340
|
]);
|
|
341
|
-
expect(controller.getState().response?.index).toBe("
|
|
341
|
+
expect(controller.getState().response?.index).toBe("products_fr_us");
|
|
342
342
|
expect(controller.getState().sections).toEqual({ collections });
|
|
343
343
|
});
|
|
344
344
|
it("resolves a sections function per request and leaves a missing entry out", async () => {
|
|
@@ -346,7 +346,7 @@ describe("createSearchController", () => {
|
|
|
346
346
|
const controller = createSearchController({
|
|
347
347
|
search,
|
|
348
348
|
language: "fr",
|
|
349
|
-
|
|
349
|
+
country: "FR",
|
|
350
350
|
analytics: {
|
|
351
351
|
surface: "search_page",
|
|
352
352
|
trackViewSearchResults,
|
|
@@ -363,7 +363,7 @@ describe("createSearchController", () => {
|
|
|
363
363
|
expect(search.mock.calls[0][0].requests).toHaveLength(1);
|
|
364
364
|
expect(search.mock.calls[1][0].requests).toHaveLength(2);
|
|
365
365
|
expect(search.mock.calls[1][0].requests[1]).toMatchObject({
|
|
366
|
-
indexName: "
|
|
366
|
+
indexName: "collections_fr_fr",
|
|
367
367
|
hitsPerPage: 12,
|
|
368
368
|
});
|
|
369
369
|
expect(controller.getState().sections).toEqual({});
|
|
@@ -373,7 +373,7 @@ describe("createSearchController", () => {
|
|
|
373
373
|
const controller = createSearchController({
|
|
374
374
|
search,
|
|
375
375
|
language: "fr",
|
|
376
|
-
|
|
376
|
+
country: "FR",
|
|
377
377
|
analytics: {
|
|
378
378
|
surface: "search_page",
|
|
379
379
|
trackViewSearchResults,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint max-lines: ["error",
|
|
1
|
+
/* eslint max-lines: ["error", 310] */
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { createSearchController } from "../searchController";
|
|
4
4
|
const tracker = vi.hoisted(() => ({
|
|
@@ -11,13 +11,23 @@ const tracker = vi.hoisted(() => ({
|
|
|
11
11
|
vi.mock("../utils/searchImpressions", () => ({
|
|
12
12
|
createSearchImpressionTracker: () => tracker,
|
|
13
13
|
}));
|
|
14
|
+
// `objectID` is the variant id, `id` the product id the events carry.
|
|
15
|
+
const productHit = (objectID, id, url) => ({
|
|
16
|
+
objectID,
|
|
17
|
+
id,
|
|
18
|
+
url,
|
|
19
|
+
tags: [],
|
|
20
|
+
options: {},
|
|
21
|
+
option_names: [],
|
|
22
|
+
inventory_available: true,
|
|
23
|
+
});
|
|
14
24
|
const response = (overrides = {}) => ({
|
|
15
25
|
results: [
|
|
16
26
|
{
|
|
17
|
-
index: "
|
|
27
|
+
index: "products_fr_fr",
|
|
18
28
|
hits: [
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
productHit("v11", 101, "https://shop.example/p1"),
|
|
30
|
+
productHit("v22", 102),
|
|
21
31
|
],
|
|
22
32
|
nbHits: 30,
|
|
23
33
|
page: 0,
|
|
@@ -37,7 +47,7 @@ const navigate = vi.fn();
|
|
|
37
47
|
const createController = () => createSearchController({
|
|
38
48
|
search,
|
|
39
49
|
language: "fr",
|
|
40
|
-
|
|
50
|
+
country: "FR",
|
|
41
51
|
analytics: {
|
|
42
52
|
surface: "search_page",
|
|
43
53
|
trackViewSearchResults,
|
|
@@ -76,7 +86,7 @@ describe("search controller attribution", () => {
|
|
|
76
86
|
await settle();
|
|
77
87
|
expect(tracker.setContext).toHaveBeenCalledWith({
|
|
78
88
|
query_id: "qid-1",
|
|
79
|
-
index: "
|
|
89
|
+
index: "products_fr_fr",
|
|
80
90
|
surface: "search_page",
|
|
81
91
|
search_type: "lexical",
|
|
82
92
|
page: 2,
|
|
@@ -106,7 +116,7 @@ describe("search controller attribution", () => {
|
|
|
106
116
|
await settle();
|
|
107
117
|
expect(trackViewSearchResults).toHaveBeenCalledWith({
|
|
108
118
|
query_id: "qid-1",
|
|
109
|
-
index: "
|
|
119
|
+
index: "products_fr_fr",
|
|
110
120
|
surface: "search_page",
|
|
111
121
|
search_type: "lexical",
|
|
112
122
|
page: 1,
|
|
@@ -123,7 +133,7 @@ describe("search controller attribution", () => {
|
|
|
123
133
|
await settle();
|
|
124
134
|
controller.observeResult(element, 1);
|
|
125
135
|
expect(tracker.observe).toHaveBeenCalledWith(element, {
|
|
126
|
-
product_id: "
|
|
136
|
+
product_id: "102",
|
|
127
137
|
position: 2 * 12 + 2,
|
|
128
138
|
});
|
|
129
139
|
});
|
|
@@ -147,18 +157,18 @@ describe("search controller attribution", () => {
|
|
|
147
157
|
await settle();
|
|
148
158
|
controller.selectResult(0);
|
|
149
159
|
expect(tracker.forceImpression).toHaveBeenCalledWith({
|
|
150
|
-
product_id: "
|
|
160
|
+
product_id: "101",
|
|
151
161
|
position: 1,
|
|
152
162
|
});
|
|
153
163
|
expect(trackSelectSearchResult).toHaveBeenCalledWith({
|
|
154
164
|
query_id: "qid-1",
|
|
155
|
-
index: "
|
|
165
|
+
index: "products_fr_fr",
|
|
156
166
|
surface: "search_page",
|
|
157
167
|
search_type: "lexical",
|
|
158
168
|
page: 1,
|
|
159
169
|
total_hits: 30,
|
|
160
170
|
query_length: 5,
|
|
161
|
-
items: [{ product_id: "
|
|
171
|
+
items: [{ product_id: "101", position: 1 }],
|
|
162
172
|
});
|
|
163
173
|
expect(navigate).toHaveBeenCalledWith("https://shop.example/p1", landed.results[0].hits[0]);
|
|
164
174
|
expect(order).toEqual(["impression", "select", "navigate"]);
|
|
@@ -169,7 +179,7 @@ describe("search controller attribution", () => {
|
|
|
169
179
|
controller.submit("shoes");
|
|
170
180
|
await settle();
|
|
171
181
|
controller.selectResult(1);
|
|
172
|
-
expect(trackSelectSearchResult).toHaveBeenCalledWith(expect.objectContaining({ items: [{ product_id: "
|
|
182
|
+
expect(trackSelectSearchResult).toHaveBeenCalledWith(expect.objectContaining({ items: [{ product_id: "102", position: 2 }] }));
|
|
173
183
|
expect(navigate).not.toHaveBeenCalled();
|
|
174
184
|
});
|
|
175
185
|
it("returns true when the navigate adapter handles the transition", async () => {
|
|
@@ -203,7 +213,7 @@ describe("search controller attribution", () => {
|
|
|
203
213
|
const controller = createSearchController({
|
|
204
214
|
search,
|
|
205
215
|
language: "fr",
|
|
206
|
-
|
|
216
|
+
country: "FR",
|
|
207
217
|
analytics: {
|
|
208
218
|
surface: "search_page",
|
|
209
219
|
trackViewSearchResults,
|
|
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
3
3
|
import { createSearchImpressionTracker } from "../utils/searchImpressions";
|
|
4
4
|
const envelope = {
|
|
5
5
|
query_id: "query-1",
|
|
6
|
-
index: "
|
|
6
|
+
index: "products_fr_fr",
|
|
7
7
|
surface: "search_page",
|
|
8
8
|
search_type: "lexical",
|
|
9
9
|
page: 1,
|
|
@@ -41,17 +41,16 @@ afterEach(() => {
|
|
|
41
41
|
});
|
|
42
42
|
describe("searchIndexName", () => {
|
|
43
43
|
it.each([
|
|
44
|
-
["fr", "
|
|
45
|
-
["pt", "
|
|
46
|
-
["fr", "
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(searchIndexName("products", locale, currency)).toBe(name);
|
|
44
|
+
["fr", "BE", "products_fr_be"],
|
|
45
|
+
["pt", "br", "products_pt_br"],
|
|
46
|
+
["fr", "CA", "products_fr_ca"],
|
|
47
|
+
])("builds an index name from language %s and the shopper's country", (language, country, name) => {
|
|
48
|
+
expect(searchIndexName("products", language, country)).toBe(name);
|
|
50
49
|
});
|
|
51
|
-
it("names every logical index", () => {
|
|
52
|
-
expect(searchIndexName("collections", "en", "
|
|
53
|
-
expect(() => searchIndexName("products", "fr-FR", "
|
|
54
|
-
expect(() => searchIndexName("products", "fr", "")).toThrow(/ISO
|
|
50
|
+
it("names every logical index and rejects invalid codes", () => {
|
|
51
|
+
expect(searchIndexName("collections", "en", "US")).toBe("collections_en_us");
|
|
52
|
+
expect(() => searchIndexName("products", "fr-FR", "FR")).toThrow(/ISO 639-1/);
|
|
53
|
+
expect(() => searchIndexName("products", "fr", "EUR")).toThrow(/ISO 3166-1/);
|
|
55
54
|
});
|
|
56
55
|
});
|
|
57
56
|
describe("searchLexical", () => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { SearchController, SearchControllerOptions } from "./types/searchController";
|
|
2
|
-
export declare function createSearchController({ search, language,
|
|
2
|
+
export declare function createSearchController({ search, language, country, analytics, navigate, 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,
|
|
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"}
|
package/dist/searchController.js
CHANGED
|
@@ -10,11 +10,11 @@ const INITIAL_STATE = {
|
|
|
10
10
|
sections: undefined,
|
|
11
11
|
error: undefined,
|
|
12
12
|
};
|
|
13
|
-
export function createSearchController({ search, language,
|
|
13
|
+
export function createSearchController({ search, language, country, analytics, navigate, debounceMs = 250, hitsPerPage = 12, sections = [], }) {
|
|
14
14
|
const requestConfig = {
|
|
15
|
-
indexName: searchIndexName("products", language,
|
|
15
|
+
indexName: searchIndexName("products", language, country),
|
|
16
16
|
language,
|
|
17
|
-
|
|
17
|
+
country,
|
|
18
18
|
hitsPerPage,
|
|
19
19
|
};
|
|
20
20
|
let state = INITIAL_STATE;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SearchIndex, SearchOptions, SearchRequest, SearchResponse } from "../types/search";
|
|
2
|
-
/** Build an index name from an ISO 639-1 language and ISO
|
|
3
|
-
export declare const searchIndexName: (index: SearchIndex, language: string,
|
|
2
|
+
/** Build an index name from an ISO 639-1 language and the shopper's ISO 3166-1 alpha-2 country. */
|
|
3
|
+
export declare const searchIndexName: (index: SearchIndex, language: string, country: string) => string;
|
|
4
4
|
/** Send one request. The caller controls cancellation through `options.signal`. */
|
|
5
5
|
export declare const searchLexical: (apiKey: string, request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
|
|
6
6
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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;AAKzB,
|
|
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;AAKzB,mGAAmG;AACnG,eAAO,MAAM,eAAe,GAC1B,OAAO,WAAW,EAClB,UAAU,MAAM,EAChB,SAAS,MAAM,KACd,MASF,CAAC;AAoBF,mFAAmF;AACnF,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,EACd,SAAS,aAAa,EACtB,UAAU,aAAa,KACtB,OAAO,CAAC,cAAc,CAgBxB,CAAC"}
|
package/dist/services/search.js
CHANGED
|
@@ -2,15 +2,15 @@ import { config } from "../config";
|
|
|
2
2
|
import { DialogSearchError } from "../DialogSearchError";
|
|
3
3
|
const SEARCH_PATH = "/public/search/lexical";
|
|
4
4
|
const API_KEY_HEADER = "x-dialog-api-key";
|
|
5
|
-
/** Build an index name from an ISO 639-1 language and ISO
|
|
6
|
-
export const searchIndexName = (index, language,
|
|
5
|
+
/** Build an index name from an ISO 639-1 language and the shopper's ISO 3166-1 alpha-2 country. */
|
|
6
|
+
export const searchIndexName = (index, language, country) => {
|
|
7
7
|
if (!/^[a-z]{2}$/.test(language)) {
|
|
8
8
|
throw new Error("Search language must be a lowercase ISO 639-1 code.");
|
|
9
9
|
}
|
|
10
|
-
if (!/^[A-Za-z]{
|
|
11
|
-
throw new Error("Search
|
|
10
|
+
if (!/^[A-Za-z]{2}$/.test(country)) {
|
|
11
|
+
throw new Error("Search country must be an ISO 3166-1 alpha-2 code.");
|
|
12
12
|
}
|
|
13
|
-
return `${index}_${language}_${
|
|
13
|
+
return `${index}_${language}_${country.toLowerCase()}`;
|
|
14
14
|
};
|
|
15
15
|
const toSearchError = async (response) => {
|
|
16
16
|
let body;
|
package/dist/types/search.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Supported indices before adding language and
|
|
1
|
+
/** Supported indices before adding language and country. */
|
|
2
2
|
export declare const SEARCH_INDICES: readonly ["products", "collections", "articles", "pages"];
|
|
3
3
|
export type SearchIndex = (typeof SEARCH_INDICES)[number];
|
|
4
4
|
export interface SearchQuery {
|
|
5
5
|
/**
|
|
6
|
-
* `<index>_<lang>_<
|
|
7
|
-
* Use the same language and lowercase ISO
|
|
6
|
+
* `<index>_<lang>_<country>`, e.g. `products_fr_be`.
|
|
7
|
+
* Use the same language and lowercase ISO 3166-1 alpha-2 country for every entry.
|
|
8
8
|
* Unsupported index names return 404.
|
|
9
9
|
*/
|
|
10
10
|
indexName: string;
|
|
@@ -22,28 +22,62 @@ export interface SearchOptions {
|
|
|
22
22
|
/** Passed to fetch; cancellation rejects with `AbortError`. */
|
|
23
23
|
signal?: AbortSignal;
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
/** Decimal string, e.g. "24.90". */
|
|
27
|
-
amount: string;
|
|
28
|
-
/** Currency code, if provided by the index. */
|
|
29
|
-
currencyCode?: string;
|
|
30
|
-
}
|
|
31
|
-
export interface SearchPriceRange {
|
|
32
|
-
min: SearchPrice;
|
|
33
|
-
max: SearchPrice;
|
|
34
|
-
}
|
|
35
|
-
/** Indexed record. Display fields are optional; only products have `priceRange`. */
|
|
25
|
+
/** A collection, article or page hit. */
|
|
36
26
|
export interface SearchHit {
|
|
37
27
|
objectID: string;
|
|
38
28
|
title?: string;
|
|
39
29
|
url?: string;
|
|
40
30
|
handle?: string;
|
|
41
31
|
imageUrl?: string;
|
|
42
|
-
priceRange?: SearchPriceRange;
|
|
43
32
|
}
|
|
44
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A product hit: Algolia's Shopify record, plus `url` and `currency`.
|
|
35
|
+
* Prices are numbers in the base currency of the shopper's market (`currency`);
|
|
36
|
+
* a price the market lacks is absent.
|
|
37
|
+
*/
|
|
38
|
+
export interface SearchProductHit {
|
|
39
|
+
/** Variant id, the last segment of the Shopify GID. */
|
|
40
|
+
objectID: string;
|
|
41
|
+
/** Product id, a number when numeric. */
|
|
42
|
+
id: number | string;
|
|
43
|
+
title?: string;
|
|
44
|
+
handle?: string;
|
|
45
|
+
url?: string;
|
|
46
|
+
variant_title?: string;
|
|
47
|
+
position?: number;
|
|
48
|
+
image?: string;
|
|
49
|
+
product_image?: string;
|
|
50
|
+
body_html_safe?: string;
|
|
51
|
+
vendor?: string;
|
|
52
|
+
product_type?: string;
|
|
53
|
+
tags: string[];
|
|
54
|
+
sku?: string;
|
|
55
|
+
barcode?: string;
|
|
56
|
+
option1?: string;
|
|
57
|
+
option2?: string;
|
|
58
|
+
option3?: string;
|
|
59
|
+
/** Lowercase option name to selected value. */
|
|
60
|
+
options: Record<string, string>;
|
|
61
|
+
option_names: string[];
|
|
62
|
+
price?: number;
|
|
63
|
+
compare_at_price?: number;
|
|
64
|
+
variants_min_price?: number;
|
|
65
|
+
variants_max_price?: number;
|
|
66
|
+
variants_compare_at_price_min?: number;
|
|
67
|
+
variants_compare_at_price_max?: number;
|
|
68
|
+
/** ISO 4217 base currency of the shopper's market. */
|
|
69
|
+
currency?: string;
|
|
70
|
+
variants_count?: number;
|
|
71
|
+
inventory_quantity?: number;
|
|
72
|
+
inventory_available: boolean;
|
|
73
|
+
created_at?: string;
|
|
74
|
+
updated_at?: string;
|
|
75
|
+
published_at?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Products results carry `SearchProductHit`, other indices `SearchHit`. */
|
|
78
|
+
export interface SearchResult<THit = SearchProductHit | SearchHit> {
|
|
45
79
|
index: string;
|
|
46
|
-
hits:
|
|
80
|
+
hits: THit[];
|
|
47
81
|
nbHits: number;
|
|
48
82
|
page: number;
|
|
49
83
|
nbPages: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/types/search.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,eAAO,MAAM,cAAc,2DAKjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,yCAAyC;AACzC,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;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY,CAAC,IAAI,GAAG,gBAAgB,GAAG,SAAS;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,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,gCAAgC;AAChC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB"}
|
package/dist/types/search.js
CHANGED
|
@@ -4,7 +4,7 @@ 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
|
-
/** Index returned by the API, e.g. `
|
|
7
|
+
/** Index returned by the API, e.g. `products_fr_be`. */
|
|
8
8
|
index: string;
|
|
9
9
|
/** UI surface displaying the results. */
|
|
10
10
|
surface: SearchSurface;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchAnalytics.d.ts","sourceRoot":"","sources":["../../src/types/searchAnalytics.ts"],"names":[],"mappings":"AAEA,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,
|
|
1
|
+
{"version":3,"file":"searchAnalytics.d.ts","sourceRoot":"","sources":["../../src/types/searchAnalytics.ts"],"names":[],"mappings":"AAEA,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,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,aAAa,CAAC;IACvB,6CAA6C;IAC7C,WAAW,EAAE,UAAU,CAAC;IACxB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,qCAAqC;AACrC,MAAM,WAAW,wBAAyB,SAAQ,uBAAuB;IACvE,KAAK,EAAE,CAAC,gBAAgB,CAAC,CAAC;CAC3B;AAGD,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, SearchIndex, SearchOptions, SearchRequest, SearchResponse, SearchResult } from "./search";
|
|
1
|
+
import { SearchHit, SearchIndex, SearchOptions, SearchProductHit, SearchRequest, SearchResponse, SearchResult } from "./search";
|
|
2
2
|
import { SearchSurface, SelectSearchResultParams, ViewSearchResultsParams } from "./searchAnalytics";
|
|
3
3
|
export declare const SearchStatus: {
|
|
4
4
|
readonly IDLE: "idle";
|
|
@@ -20,8 +20,8 @@ export interface SearchControllerState {
|
|
|
20
20
|
/** Zero-based page of the last request. */
|
|
21
21
|
page: number;
|
|
22
22
|
/** Last products result; retained while loading and cleared on error or reset. */
|
|
23
|
-
response?: SearchResult
|
|
24
|
-
sections?: Partial<Record<SearchIndex, SearchResult
|
|
23
|
+
response?: SearchResult<SearchProductHit>;
|
|
24
|
+
sections?: Partial<Record<SearchIndex, SearchResult<SearchHit>>>;
|
|
25
25
|
error?: unknown;
|
|
26
26
|
}
|
|
27
27
|
export type SearchFunction = (request: SearchRequest, options?: SearchOptions) => Promise<SearchResponse>;
|
|
@@ -36,11 +36,11 @@ export interface SearchControllerOptions {
|
|
|
36
36
|
search: SearchFunction;
|
|
37
37
|
/** Lowercase ISO 639-1 language code, e.g. `fr`. */
|
|
38
38
|
language: string;
|
|
39
|
-
/** ISO
|
|
40
|
-
|
|
39
|
+
/** Shopper's ISO 3166-1 alpha-2 country, e.g. `BE`; prices follow its market. */
|
|
40
|
+
country: string;
|
|
41
41
|
analytics: SearchControllerAnalytics;
|
|
42
42
|
/** Navigate after recording selection. Omit to use native link navigation. */
|
|
43
|
-
navigate?: (url: string, hit:
|
|
43
|
+
navigate?: (url: string, hit: SearchProductHit) => void;
|
|
44
44
|
debounceMs?: number;
|
|
45
45
|
hitsPerPage?: number;
|
|
46
46
|
sections?: readonly SearchSection[] | (() => readonly SearchSection[]);
|
|
@@ -1 +1 @@
|
|
|
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,yCAAyC;;;CAGjC,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,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,QAAQ,CAAC,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { SearchResult } from "../types/search";
|
|
1
|
+
import { SearchProductHit, SearchResult } from "../types/search";
|
|
2
2
|
import { SearchControllerAnalytics } from "../types/searchController";
|
|
3
3
|
/** Internal binding for search impressions and selections. */
|
|
4
4
|
export interface ControllerAnalyticsBinding {
|
|
5
|
-
onResponse(result: SearchResult): void;
|
|
6
|
-
observeResult(element: Element, result: SearchResult
|
|
7
|
-
select(result: SearchResult
|
|
5
|
+
onResponse(result: SearchResult<SearchProductHit>): void;
|
|
6
|
+
observeResult(element: Element, result: SearchResult<SearchProductHit>, index: number): void;
|
|
7
|
+
select(result: SearchResult<SearchProductHit>, index: number): void;
|
|
8
8
|
dispose(): void;
|
|
9
9
|
}
|
|
10
10
|
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,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"searchControllerAnalytics.d.ts","sourceRoot":"","sources":["../../src/utils/searchControllerAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAMtE,8DAA8D;AAC9D,MAAM,WAAW,0BAA0B;IACzC,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;IACzD,aAAa,CACX,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,EACtC,KAAK,EAAE,MAAM,GACZ,IAAI,CAAC;IACR,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACpE,OAAO,IAAI,IAAI,CAAC;CACjB;AAYD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,yBAAyB,GACnC,0BAA0B,CAgD5B"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSearchImpressionTracker, } from "./searchImpressions";
|
|
2
2
|
const resultItem = (result, index) => ({
|
|
3
|
-
|
|
3
|
+
// `objectID` is the variant id; analytics count products.
|
|
4
|
+
product_id: String(result.hits[index].id),
|
|
4
5
|
// One-based position across all pages.
|
|
5
6
|
position: result.page * result.hitsPerPage + index + 1,
|
|
6
7
|
});
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { SearchIndex, SearchRequest, SearchResponse, SearchResult } from "../types/search";
|
|
1
|
+
import { SearchHit, SearchIndex, SearchProductHit, SearchRequest, SearchResponse, SearchResult } from "../types/search";
|
|
2
2
|
import { SearchSection } from "../types/searchController";
|
|
3
3
|
export declare const normalizeQuery: (rawQuery: string) => string | undefined;
|
|
4
4
|
interface SearchRequestConfig {
|
|
5
5
|
indexName: string;
|
|
6
6
|
language: string;
|
|
7
|
-
|
|
7
|
+
country: string;
|
|
8
8
|
hitsPerPage: number;
|
|
9
9
|
}
|
|
10
10
|
interface SearchResults {
|
|
11
|
-
response: SearchResult
|
|
12
|
-
sections: Partial<Record<SearchIndex, SearchResult
|
|
11
|
+
response: SearchResult<SearchProductHit>;
|
|
12
|
+
sections: Partial<Record<SearchIndex, SearchResult<SearchHit>>> | undefined;
|
|
13
13
|
}
|
|
14
|
-
export declare const buildSearchRequest: (query: string, page: number, sections: readonly SearchSection[], { indexName, language,
|
|
15
|
-
export declare const readSearchResults: (result: SearchResponse, requested: readonly SearchSection[], { indexName, language,
|
|
14
|
+
export declare const buildSearchRequest: (query: string, page: number, sections: readonly SearchSection[], { indexName, language, country, hitsPerPage }: SearchRequestConfig) => SearchRequest;
|
|
15
|
+
export declare const readSearchResults: (result: SearchResponse, requested: readonly SearchSection[], { indexName, language, country }: SearchRequestConfig) => SearchResults;
|
|
16
16
|
export {};
|
|
17
17
|
//# sourceMappingURL=searchRequests.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchRequests.d.ts","sourceRoot":"","sources":["../../src/utils/searchRequests.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,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,
|
|
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"}
|
|
@@ -5,32 +5,33 @@ export const normalizeQuery = (rawQuery) => {
|
|
|
5
5
|
const query = rawQuery.trim();
|
|
6
6
|
return [...query].length >= MIN_QUERY_CODE_POINTS ? query : undefined;
|
|
7
7
|
};
|
|
8
|
-
export const buildSearchRequest = (query, page, sections, { indexName, language,
|
|
8
|
+
export const buildSearchRequest = (query, page, sections, { indexName, language, country, hitsPerPage }) => ({
|
|
9
9
|
requests: [
|
|
10
10
|
{ indexName, query, page, hitsPerPage },
|
|
11
11
|
...sections.map((section) => ({
|
|
12
|
-
indexName: searchIndexName(section.index, language,
|
|
12
|
+
indexName: searchIndexName(section.index, language, country),
|
|
13
13
|
query,
|
|
14
14
|
page: 0,
|
|
15
15
|
hitsPerPage: section.hitsPerPage ?? hitsPerPage,
|
|
16
16
|
})),
|
|
17
17
|
],
|
|
18
18
|
});
|
|
19
|
-
export const readSearchResults = (result, requested, { indexName, language,
|
|
19
|
+
export const readSearchResults = (result, requested, { indexName, language, country }) => {
|
|
20
20
|
const response = result.results.find((entry) => entry.index === indexName);
|
|
21
21
|
if (response === undefined) {
|
|
22
22
|
throw new Error(`Dialog search returned no ${indexName} entry`);
|
|
23
23
|
}
|
|
24
24
|
const sections = {};
|
|
25
25
|
for (const section of requested) {
|
|
26
|
-
const requestedIndexName = searchIndexName(section.index, language,
|
|
26
|
+
const requestedIndexName = searchIndexName(section.index, language, country);
|
|
27
27
|
const entry = result.results.find((candidate) => candidate.index === requestedIndexName);
|
|
28
28
|
if (entry !== undefined) {
|
|
29
29
|
sections[section.index] = entry;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
return {
|
|
33
|
-
|
|
33
|
+
// The products index answers product records only.
|
|
34
|
+
response: response,
|
|
34
35
|
sections: requested.length === 0 ? undefined : sections,
|
|
35
36
|
};
|
|
36
37
|
};
|