@misiki/gocommerce-connector 0.13.0 → 0.14.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 +3 -2
- package/dist/{index-DHKyh3CU.d.cts → index-C0CR05Q4.d.cts} +77 -66
- package/dist/{index-DHKyh3CU.d.ts → index-C0CR05Q4.d.ts} +77 -66
- package/dist/index.cjs +61 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +61 -41
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +61 -41
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.cts +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +61 -41
- package/dist/services/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,8 @@ gocommerce -identity -wishlist -reviews -cms -faq -menus serve
|
|
|
45
45
|
|
|
46
46
|
Each is optional. Without `-identity` there is no sign-in (guest checkout
|
|
47
47
|
always works); without `-reviews` products show no stars; and so on. Add
|
|
48
|
-
`-meilisearch` (with `MEILI_HOST` and keys) for
|
|
48
|
+
`-meilisearch` (with `MEILI_HOST` and keys) for typo-tolerant search once a store
|
|
49
|
+
switches the Meilisearch plugin on,
|
|
49
50
|
`-newsletter` and `-contact` for the signup box and contact form, and `-b2b` for
|
|
50
51
|
business buyers (see "Beyond the storefront's screens").
|
|
51
52
|
|
|
@@ -152,7 +153,7 @@ down stays best-effort: the storefront renders from its static record.
|
|
|
152
153
|
| attribute filters (`?attributes.color=Red`) | `/api/products?attr=color:Red` |
|
|
153
154
|
| newsletter box | `/x/newsletter/subscribe` |
|
|
154
155
|
| contact form, product enquiries | `/x/contact/messages` |
|
|
155
|
-
|
|
|
156
|
+
| search words, type-ahead (plugin on) | `/x/meilisearch/search`, falling back to the engine's own search when it is off or down |
|
|
156
157
|
| store record | the storefront's own config, with the engine's currency, menus and module switches over it |
|
|
157
158
|
|
|
158
159
|
Blogs, banners, reels, chat, warranties, deals and uploads have no engine
|
|
@@ -578,6 +578,8 @@ type SearchResult = {
|
|
|
578
578
|
total: number;
|
|
579
579
|
limit: number;
|
|
580
580
|
offset: number;
|
|
581
|
+
/** Meilisearch did not answer: search the product listing instead. */
|
|
582
|
+
unavailable?: boolean;
|
|
581
583
|
};
|
|
582
584
|
/** One approved vendor's offer on a variant, from `GET /api/variants/{id}/offers`. Cheapest first. */
|
|
583
585
|
type Offer = {
|
|
@@ -1489,6 +1491,19 @@ type CatalogPage = {
|
|
|
1489
1491
|
declare class CatalogService extends BaseService {
|
|
1490
1492
|
protected readonly facts: StoreFacts;
|
|
1491
1493
|
protected queryCatalog(q: CatalogQuery): Promise<CatalogPage>;
|
|
1494
|
+
/**
|
|
1495
|
+
* The shelf from the Meilisearch module, or null when the store has it off,
|
|
1496
|
+
* sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
|
|
1497
|
+
* the caller asks the database instead of showing the shopper an error.
|
|
1498
|
+
*/
|
|
1499
|
+
protected fromIndex(q: CatalogQuery, o: {
|
|
1500
|
+
page: number;
|
|
1501
|
+
limit: number;
|
|
1502
|
+
search?: string;
|
|
1503
|
+
sortKey?: string;
|
|
1504
|
+
wantsRange: boolean;
|
|
1505
|
+
hierarchy: CatalogPage['categoryHierarchy'];
|
|
1506
|
+
}): Promise<CatalogPage | null>;
|
|
1492
1507
|
}
|
|
1493
1508
|
|
|
1494
1509
|
/**
|
|
@@ -2697,39 +2712,6 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2697
2712
|
search?: string;
|
|
2698
2713
|
limit?: number;
|
|
2699
2714
|
}): Promise<{
|
|
2700
|
-
data: {
|
|
2701
|
-
id: string;
|
|
2702
|
-
slug: string;
|
|
2703
|
-
title: string;
|
|
2704
|
-
name: string;
|
|
2705
|
-
description: string;
|
|
2706
|
-
currency: string;
|
|
2707
|
-
price: number;
|
|
2708
|
-
mrp: number;
|
|
2709
|
-
minPrice: number;
|
|
2710
|
-
maxPrice: number;
|
|
2711
|
-
thumbnail: string | null;
|
|
2712
|
-
image_url: string | null;
|
|
2713
|
-
images: string;
|
|
2714
|
-
stock: number;
|
|
2715
|
-
hasStock: boolean;
|
|
2716
|
-
manageInventory: boolean;
|
|
2717
|
-
allowBackorder: boolean;
|
|
2718
|
-
productTags: string;
|
|
2719
|
-
category: {
|
|
2720
|
-
name: string;
|
|
2721
|
-
slug: string;
|
|
2722
|
-
} | null;
|
|
2723
|
-
vendor: {
|
|
2724
|
-
businessName: string;
|
|
2725
|
-
} | null;
|
|
2726
|
-
variants: ReturnType<typeof toVariant>[];
|
|
2727
|
-
options: never[];
|
|
2728
|
-
ratings: never[];
|
|
2729
|
-
link: string;
|
|
2730
|
-
updatedAt: string;
|
|
2731
|
-
}[];
|
|
2732
|
-
} | {
|
|
2733
2715
|
data: {
|
|
2734
2716
|
id: string;
|
|
2735
2717
|
slug: string;
|
|
@@ -2840,6 +2822,37 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2840
2822
|
metadata: Record<string, unknown> | null;
|
|
2841
2823
|
createdAt: string;
|
|
2842
2824
|
updatedAt: string;
|
|
2825
|
+
}[] | {
|
|
2826
|
+
id: string;
|
|
2827
|
+
slug: string;
|
|
2828
|
+
title: string;
|
|
2829
|
+
name: string;
|
|
2830
|
+
description: string;
|
|
2831
|
+
currency: string;
|
|
2832
|
+
price: number;
|
|
2833
|
+
mrp: number;
|
|
2834
|
+
minPrice: number;
|
|
2835
|
+
maxPrice: number;
|
|
2836
|
+
thumbnail: string | null;
|
|
2837
|
+
image_url: string | null;
|
|
2838
|
+
images: string;
|
|
2839
|
+
stock: number;
|
|
2840
|
+
hasStock: boolean;
|
|
2841
|
+
manageInventory: boolean;
|
|
2842
|
+
allowBackorder: boolean;
|
|
2843
|
+
productTags: string;
|
|
2844
|
+
category: {
|
|
2845
|
+
name: string;
|
|
2846
|
+
slug: string;
|
|
2847
|
+
} | null;
|
|
2848
|
+
vendor: {
|
|
2849
|
+
businessName: string;
|
|
2850
|
+
} | null;
|
|
2851
|
+
variants: ReturnType<typeof toVariant>[];
|
|
2852
|
+
options: never[];
|
|
2853
|
+
ratings: never[];
|
|
2854
|
+
link: string;
|
|
2855
|
+
updatedAt: string;
|
|
2843
2856
|
}[];
|
|
2844
2857
|
}>;
|
|
2845
2858
|
}
|
|
@@ -6606,39 +6619,6 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6606
6619
|
q?: string;
|
|
6607
6620
|
search?: string;
|
|
6608
6621
|
}): Promise<{
|
|
6609
|
-
data: {
|
|
6610
|
-
id: string;
|
|
6611
|
-
slug: string;
|
|
6612
|
-
title: string;
|
|
6613
|
-
name: string;
|
|
6614
|
-
description: string;
|
|
6615
|
-
currency: string;
|
|
6616
|
-
price: number;
|
|
6617
|
-
mrp: number;
|
|
6618
|
-
minPrice: number;
|
|
6619
|
-
maxPrice: number;
|
|
6620
|
-
thumbnail: string | null;
|
|
6621
|
-
image_url: string | null;
|
|
6622
|
-
images: string;
|
|
6623
|
-
stock: number;
|
|
6624
|
-
hasStock: boolean;
|
|
6625
|
-
manageInventory: boolean;
|
|
6626
|
-
allowBackorder: boolean;
|
|
6627
|
-
productTags: string;
|
|
6628
|
-
category: {
|
|
6629
|
-
name: string;
|
|
6630
|
-
slug: string;
|
|
6631
|
-
} | null;
|
|
6632
|
-
vendor: {
|
|
6633
|
-
businessName: string;
|
|
6634
|
-
} | null;
|
|
6635
|
-
variants: ReturnType<typeof toVariant>[];
|
|
6636
|
-
options: never[];
|
|
6637
|
-
ratings: never[];
|
|
6638
|
-
link: string;
|
|
6639
|
-
updatedAt: string;
|
|
6640
|
-
}[];
|
|
6641
|
-
} | {
|
|
6642
6622
|
data: {
|
|
6643
6623
|
id: string;
|
|
6644
6624
|
slug: string;
|
|
@@ -6749,6 +6729,37 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6749
6729
|
metadata: Record<string, unknown> | null;
|
|
6750
6730
|
createdAt: string;
|
|
6751
6731
|
updatedAt: string;
|
|
6732
|
+
}[] | {
|
|
6733
|
+
id: string;
|
|
6734
|
+
slug: string;
|
|
6735
|
+
title: string;
|
|
6736
|
+
name: string;
|
|
6737
|
+
description: string;
|
|
6738
|
+
currency: string;
|
|
6739
|
+
price: number;
|
|
6740
|
+
mrp: number;
|
|
6741
|
+
minPrice: number;
|
|
6742
|
+
maxPrice: number;
|
|
6743
|
+
thumbnail: string | null;
|
|
6744
|
+
image_url: string | null;
|
|
6745
|
+
images: string;
|
|
6746
|
+
stock: number;
|
|
6747
|
+
hasStock: boolean;
|
|
6748
|
+
manageInventory: boolean;
|
|
6749
|
+
allowBackorder: boolean;
|
|
6750
|
+
productTags: string;
|
|
6751
|
+
category: {
|
|
6752
|
+
name: string;
|
|
6753
|
+
slug: string;
|
|
6754
|
+
} | null;
|
|
6755
|
+
vendor: {
|
|
6756
|
+
businessName: string;
|
|
6757
|
+
} | null;
|
|
6758
|
+
variants: ReturnType<typeof toVariant>[];
|
|
6759
|
+
options: never[];
|
|
6760
|
+
ratings: never[];
|
|
6761
|
+
link: string;
|
|
6762
|
+
updatedAt: string;
|
|
6752
6763
|
}[];
|
|
6753
6764
|
}>;
|
|
6754
6765
|
}
|
|
@@ -578,6 +578,8 @@ type SearchResult = {
|
|
|
578
578
|
total: number;
|
|
579
579
|
limit: number;
|
|
580
580
|
offset: number;
|
|
581
|
+
/** Meilisearch did not answer: search the product listing instead. */
|
|
582
|
+
unavailable?: boolean;
|
|
581
583
|
};
|
|
582
584
|
/** One approved vendor's offer on a variant, from `GET /api/variants/{id}/offers`. Cheapest first. */
|
|
583
585
|
type Offer = {
|
|
@@ -1489,6 +1491,19 @@ type CatalogPage = {
|
|
|
1489
1491
|
declare class CatalogService extends BaseService {
|
|
1490
1492
|
protected readonly facts: StoreFacts;
|
|
1491
1493
|
protected queryCatalog(q: CatalogQuery): Promise<CatalogPage>;
|
|
1494
|
+
/**
|
|
1495
|
+
* The shelf from the Meilisearch module, or null when the store has it off,
|
|
1496
|
+
* sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
|
|
1497
|
+
* the caller asks the database instead of showing the shopper an error.
|
|
1498
|
+
*/
|
|
1499
|
+
protected fromIndex(q: CatalogQuery, o: {
|
|
1500
|
+
page: number;
|
|
1501
|
+
limit: number;
|
|
1502
|
+
search?: string;
|
|
1503
|
+
sortKey?: string;
|
|
1504
|
+
wantsRange: boolean;
|
|
1505
|
+
hierarchy: CatalogPage['categoryHierarchy'];
|
|
1506
|
+
}): Promise<CatalogPage | null>;
|
|
1492
1507
|
}
|
|
1493
1508
|
|
|
1494
1509
|
/**
|
|
@@ -2697,39 +2712,6 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2697
2712
|
search?: string;
|
|
2698
2713
|
limit?: number;
|
|
2699
2714
|
}): Promise<{
|
|
2700
|
-
data: {
|
|
2701
|
-
id: string;
|
|
2702
|
-
slug: string;
|
|
2703
|
-
title: string;
|
|
2704
|
-
name: string;
|
|
2705
|
-
description: string;
|
|
2706
|
-
currency: string;
|
|
2707
|
-
price: number;
|
|
2708
|
-
mrp: number;
|
|
2709
|
-
minPrice: number;
|
|
2710
|
-
maxPrice: number;
|
|
2711
|
-
thumbnail: string | null;
|
|
2712
|
-
image_url: string | null;
|
|
2713
|
-
images: string;
|
|
2714
|
-
stock: number;
|
|
2715
|
-
hasStock: boolean;
|
|
2716
|
-
manageInventory: boolean;
|
|
2717
|
-
allowBackorder: boolean;
|
|
2718
|
-
productTags: string;
|
|
2719
|
-
category: {
|
|
2720
|
-
name: string;
|
|
2721
|
-
slug: string;
|
|
2722
|
-
} | null;
|
|
2723
|
-
vendor: {
|
|
2724
|
-
businessName: string;
|
|
2725
|
-
} | null;
|
|
2726
|
-
variants: ReturnType<typeof toVariant>[];
|
|
2727
|
-
options: never[];
|
|
2728
|
-
ratings: never[];
|
|
2729
|
-
link: string;
|
|
2730
|
-
updatedAt: string;
|
|
2731
|
-
}[];
|
|
2732
|
-
} | {
|
|
2733
2715
|
data: {
|
|
2734
2716
|
id: string;
|
|
2735
2717
|
slug: string;
|
|
@@ -2840,6 +2822,37 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2840
2822
|
metadata: Record<string, unknown> | null;
|
|
2841
2823
|
createdAt: string;
|
|
2842
2824
|
updatedAt: string;
|
|
2825
|
+
}[] | {
|
|
2826
|
+
id: string;
|
|
2827
|
+
slug: string;
|
|
2828
|
+
title: string;
|
|
2829
|
+
name: string;
|
|
2830
|
+
description: string;
|
|
2831
|
+
currency: string;
|
|
2832
|
+
price: number;
|
|
2833
|
+
mrp: number;
|
|
2834
|
+
minPrice: number;
|
|
2835
|
+
maxPrice: number;
|
|
2836
|
+
thumbnail: string | null;
|
|
2837
|
+
image_url: string | null;
|
|
2838
|
+
images: string;
|
|
2839
|
+
stock: number;
|
|
2840
|
+
hasStock: boolean;
|
|
2841
|
+
manageInventory: boolean;
|
|
2842
|
+
allowBackorder: boolean;
|
|
2843
|
+
productTags: string;
|
|
2844
|
+
category: {
|
|
2845
|
+
name: string;
|
|
2846
|
+
slug: string;
|
|
2847
|
+
} | null;
|
|
2848
|
+
vendor: {
|
|
2849
|
+
businessName: string;
|
|
2850
|
+
} | null;
|
|
2851
|
+
variants: ReturnType<typeof toVariant>[];
|
|
2852
|
+
options: never[];
|
|
2853
|
+
ratings: never[];
|
|
2854
|
+
link: string;
|
|
2855
|
+
updatedAt: string;
|
|
2843
2856
|
}[];
|
|
2844
2857
|
}>;
|
|
2845
2858
|
}
|
|
@@ -6606,39 +6619,6 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6606
6619
|
q?: string;
|
|
6607
6620
|
search?: string;
|
|
6608
6621
|
}): Promise<{
|
|
6609
|
-
data: {
|
|
6610
|
-
id: string;
|
|
6611
|
-
slug: string;
|
|
6612
|
-
title: string;
|
|
6613
|
-
name: string;
|
|
6614
|
-
description: string;
|
|
6615
|
-
currency: string;
|
|
6616
|
-
price: number;
|
|
6617
|
-
mrp: number;
|
|
6618
|
-
minPrice: number;
|
|
6619
|
-
maxPrice: number;
|
|
6620
|
-
thumbnail: string | null;
|
|
6621
|
-
image_url: string | null;
|
|
6622
|
-
images: string;
|
|
6623
|
-
stock: number;
|
|
6624
|
-
hasStock: boolean;
|
|
6625
|
-
manageInventory: boolean;
|
|
6626
|
-
allowBackorder: boolean;
|
|
6627
|
-
productTags: string;
|
|
6628
|
-
category: {
|
|
6629
|
-
name: string;
|
|
6630
|
-
slug: string;
|
|
6631
|
-
} | null;
|
|
6632
|
-
vendor: {
|
|
6633
|
-
businessName: string;
|
|
6634
|
-
} | null;
|
|
6635
|
-
variants: ReturnType<typeof toVariant>[];
|
|
6636
|
-
options: never[];
|
|
6637
|
-
ratings: never[];
|
|
6638
|
-
link: string;
|
|
6639
|
-
updatedAt: string;
|
|
6640
|
-
}[];
|
|
6641
|
-
} | {
|
|
6642
6622
|
data: {
|
|
6643
6623
|
id: string;
|
|
6644
6624
|
slug: string;
|
|
@@ -6749,6 +6729,37 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6749
6729
|
metadata: Record<string, unknown> | null;
|
|
6750
6730
|
createdAt: string;
|
|
6751
6731
|
updatedAt: string;
|
|
6732
|
+
}[] | {
|
|
6733
|
+
id: string;
|
|
6734
|
+
slug: string;
|
|
6735
|
+
title: string;
|
|
6736
|
+
name: string;
|
|
6737
|
+
description: string;
|
|
6738
|
+
currency: string;
|
|
6739
|
+
price: number;
|
|
6740
|
+
mrp: number;
|
|
6741
|
+
minPrice: number;
|
|
6742
|
+
maxPrice: number;
|
|
6743
|
+
thumbnail: string | null;
|
|
6744
|
+
image_url: string | null;
|
|
6745
|
+
images: string;
|
|
6746
|
+
stock: number;
|
|
6747
|
+
hasStock: boolean;
|
|
6748
|
+
manageInventory: boolean;
|
|
6749
|
+
allowBackorder: boolean;
|
|
6750
|
+
productTags: string;
|
|
6751
|
+
category: {
|
|
6752
|
+
name: string;
|
|
6753
|
+
slug: string;
|
|
6754
|
+
} | null;
|
|
6755
|
+
vendor: {
|
|
6756
|
+
businessName: string;
|
|
6757
|
+
} | null;
|
|
6758
|
+
variants: ReturnType<typeof toVariant>[];
|
|
6759
|
+
options: never[];
|
|
6760
|
+
ratings: never[];
|
|
6761
|
+
link: string;
|
|
6762
|
+
updatedAt: string;
|
|
6752
6763
|
}[];
|
|
6753
6764
|
}>;
|
|
6754
6765
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1216,14 +1216,17 @@ var CatalogService = class extends BaseService {
|
|
|
1216
1216
|
const attr = Object.entries(q.attributes ?? {}).flatMap(
|
|
1217
1217
|
([handle, values]) => values.filter(Boolean).map((v) => `${handle}:${v}`)
|
|
1218
1218
|
);
|
|
1219
|
-
|
|
1219
|
+
const refined = attr.length > 0 || !!(q.tags?.length || q.vendors?.length || q.productTypes?.length);
|
|
1220
|
+
const triedIndex = !!search && !refined;
|
|
1221
|
+
const counted = q.facets && !legacyListing.has(this.engineBase());
|
|
1222
|
+
const facetListing = async (page2, limit2) => {
|
|
1220
1223
|
const { currency } = await this.facts.ready();
|
|
1221
1224
|
const minor = (n) => Number.isFinite(n) ? Math.max(0, toMinor(n, currency)) : void 0;
|
|
1222
|
-
|
|
1225
|
+
return this.engine("/api/products", {
|
|
1223
1226
|
query: {
|
|
1224
1227
|
q: search,
|
|
1225
|
-
page,
|
|
1226
|
-
limit,
|
|
1228
|
+
page: page2,
|
|
1229
|
+
limit: limit2,
|
|
1227
1230
|
channel: this.creds.channel,
|
|
1228
1231
|
category: q.category,
|
|
1229
1232
|
tag: q.tags,
|
|
@@ -1236,6 +1239,16 @@ var CatalogService = class extends BaseService {
|
|
|
1236
1239
|
facets: 1
|
|
1237
1240
|
}
|
|
1238
1241
|
});
|
|
1242
|
+
};
|
|
1243
|
+
if (triedIndex && await this.facts.pluginOn("meilisearch")) {
|
|
1244
|
+
const [found, rail] = await Promise.all([
|
|
1245
|
+
this.fromIndex(q, { page, limit, search, sortKey, wantsRange, hierarchy }),
|
|
1246
|
+
counted ? facetListing(1, 1).catch(() => null) : null
|
|
1247
|
+
]);
|
|
1248
|
+
if (found) return rail?.meta?.facets ? { ...found, facets: rail.meta.facets } : found;
|
|
1249
|
+
}
|
|
1250
|
+
if (counted) {
|
|
1251
|
+
const env2 = await facetListing(page, limit);
|
|
1239
1252
|
if (env2.meta?.facets) {
|
|
1240
1253
|
return {
|
|
1241
1254
|
...toPage(env2, (p) => toProduct(p)),
|
|
@@ -1246,39 +1259,9 @@ var CatalogService = class extends BaseService {
|
|
|
1246
1259
|
}
|
|
1247
1260
|
legacyListing.add(this.engineBase());
|
|
1248
1261
|
}
|
|
1249
|
-
if ((sortKey || wantsRange)
|
|
1250
|
-
const
|
|
1251
|
-
if (
|
|
1252
|
-
const names = (await this.facts.subtree(q.category).catch(() => [])).map(
|
|
1253
|
-
(c) => quote(c.full_name)
|
|
1254
|
-
);
|
|
1255
|
-
if (!names.length) return { ...emptyCatalog(limit), categoryHierarchy: hierarchy, sorted: true };
|
|
1256
|
-
filters.push(`category IN [${names.join(", ")}]`);
|
|
1257
|
-
}
|
|
1258
|
-
if (wantsRange) {
|
|
1259
|
-
const { currency } = await this.facts.ready();
|
|
1260
|
-
if (Number.isFinite(q.priceFrom)) filters.push(`price_minor >= ${toMinor(q.priceFrom, currency)}`);
|
|
1261
|
-
if (Number.isFinite(q.priceTo)) filters.push(`price_minor <= ${toMinor(q.priceTo, currency)}`);
|
|
1262
|
-
}
|
|
1263
|
-
const res = await this.data("/x/meilisearch/search", {
|
|
1264
|
-
query: {
|
|
1265
|
-
q: search ?? "",
|
|
1266
|
-
limit,
|
|
1267
|
-
offset: (page - 1) * limit,
|
|
1268
|
-
filter: filters.join(" AND ") || void 0,
|
|
1269
|
-
sort: sortKey
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
const total = res.total ?? 0;
|
|
1273
|
-
return {
|
|
1274
|
-
data: (res.hits ?? []).map(fromSearchDoc),
|
|
1275
|
-
count: total,
|
|
1276
|
-
pageSize: limit,
|
|
1277
|
-
noOfPage: Math.max(1, Math.ceil(total / limit)),
|
|
1278
|
-
page,
|
|
1279
|
-
categoryHierarchy: hierarchy,
|
|
1280
|
-
sorted: true
|
|
1281
|
-
};
|
|
1262
|
+
if (!triedIndex && (sortKey || wantsRange)) {
|
|
1263
|
+
const found = await this.fromIndex(q, { page, limit, search, sortKey, wantsRange, hierarchy });
|
|
1264
|
+
if (found) return found;
|
|
1282
1265
|
}
|
|
1283
1266
|
const sorted = !sortKey && !wantsRange;
|
|
1284
1267
|
if (q.category && !search) {
|
|
@@ -1298,6 +1281,45 @@ var CatalogService = class extends BaseService {
|
|
|
1298
1281
|
});
|
|
1299
1282
|
return { ...toPage(env, (p) => toProduct(p)), categoryHierarchy: hierarchy, sorted };
|
|
1300
1283
|
}
|
|
1284
|
+
/**
|
|
1285
|
+
* The shelf from the Meilisearch module, or null when the store has it off,
|
|
1286
|
+
* sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
|
|
1287
|
+
* the caller asks the database instead of showing the shopper an error.
|
|
1288
|
+
*/
|
|
1289
|
+
async fromIndex(q, o) {
|
|
1290
|
+
if (this.creds.channel || !await this.facts.pluginOn("meilisearch")) return null;
|
|
1291
|
+
const filters = [];
|
|
1292
|
+
if (q.category) {
|
|
1293
|
+
const names = (await this.facts.subtree(q.category).catch(() => [])).map((c) => quote(c.full_name));
|
|
1294
|
+
if (!names.length) return { ...emptyCatalog(o.limit), categoryHierarchy: o.hierarchy, sorted: true };
|
|
1295
|
+
filters.push(`category IN [${names.join(", ")}]`);
|
|
1296
|
+
}
|
|
1297
|
+
if (o.wantsRange) {
|
|
1298
|
+
const { currency } = await this.facts.ready();
|
|
1299
|
+
if (Number.isFinite(q.priceFrom)) filters.push(`price_minor >= ${toMinor(q.priceFrom, currency)}`);
|
|
1300
|
+
if (Number.isFinite(q.priceTo)) filters.push(`price_minor <= ${toMinor(q.priceTo, currency)}`);
|
|
1301
|
+
}
|
|
1302
|
+
const res = await this.data("/x/meilisearch/search", {
|
|
1303
|
+
query: {
|
|
1304
|
+
q: o.search ?? "",
|
|
1305
|
+
limit: o.limit,
|
|
1306
|
+
offset: (o.page - 1) * o.limit,
|
|
1307
|
+
filter: filters.join(" AND ") || void 0,
|
|
1308
|
+
sort: o.sortKey
|
|
1309
|
+
}
|
|
1310
|
+
}).catch(() => null);
|
|
1311
|
+
if (!res || res.unavailable || o.search && !res.hits?.length) return null;
|
|
1312
|
+
const total = res.total ?? 0;
|
|
1313
|
+
return {
|
|
1314
|
+
data: (res.hits ?? []).map(fromSearchDoc),
|
|
1315
|
+
count: total,
|
|
1316
|
+
pageSize: o.limit,
|
|
1317
|
+
noOfPage: Math.max(1, Math.ceil(total / o.limit)),
|
|
1318
|
+
page: o.page,
|
|
1319
|
+
categoryHierarchy: o.hierarchy,
|
|
1320
|
+
sorted: true
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1301
1323
|
};
|
|
1302
1324
|
function emptyCatalog(limit = PAGE_SIZE) {
|
|
1303
1325
|
return { data: [], count: 0, pageSize: limit, noOfPage: 0, page: 1 };
|
|
@@ -1595,10 +1617,8 @@ var MeilisearchService = class extends CatalogService {
|
|
|
1595
1617
|
async searchAutoComplete({ query, search, limit = 8 } = {}) {
|
|
1596
1618
|
const q = (query ?? search ?? "").trim();
|
|
1597
1619
|
if (!q) return { data: [] };
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
return { data: (res.hits ?? []).map(fromSearchDoc) };
|
|
1601
|
-
}
|
|
1620
|
+
const found = await this.fromIndex({}, { page: 1, limit, search: q, wantsRange: false, hierarchy: [] });
|
|
1621
|
+
if (found) return { data: found.data };
|
|
1602
1622
|
const rows = await this.data("/api/products", { query: { q, limit, channel: this.creds.channel } }) ?? [];
|
|
1603
1623
|
return { data: rows.map((p) => toProduct(p)) };
|
|
1604
1624
|
}
|