@misiki/gocommerce-connector 0.13.0 → 0.15.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 +5 -3
- package/dist/{index-DHKyh3CU.d.cts → index-GdjWgh5b.d.cts} +89 -72
- package/dist/{index-DHKyh3CU.d.ts → index-GdjWgh5b.d.ts} +89 -72
- package/dist/index.cjs +79 -42
- 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 +79 -42
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +79 -42
- 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 +79 -42
- 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,8 +153,9 @@ 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
|
-
| store record | the storefront's own config, with the engine's currency, menus and module switches over it |
|
|
156
|
+
| search words, type-ahead (plugin on) | `/x/meilisearch/search`, falling back to the engine's own search when it is off or down |
|
|
157
|
+
| store record | the storefront's own config, with the engine's currency, menus and module switches over it; the store's own logo, dark logo and icon (`logo_url`, `logo_dark_url`, `icon_url` from `/api/store`, D148) replace `logo`, `logoDark` and `favicon` when it has them |
|
|
158
|
+
| resized product pictures | `/images/{store}/cdn-cgi/image/width=…/…` — the store record's `plugins.imageCdn` is turned on with provider `cloudflare` and the engine's `images_path` (from `/api/store`, D139) after `PUBLIC_GOCOMMERCE_API_URL`, so the storefront's srcset asks the engine for each width; an engine without it leaves the static record's setting |
|
|
157
159
|
|
|
158
160
|
Blogs, banners, reels, chat, warranties, deals and uploads have no engine
|
|
159
161
|
equivalent. Their lists answer empty and anything that would write or open one
|
|
@@ -425,6 +425,12 @@ type StoreProfile = {
|
|
|
425
425
|
phone: string;
|
|
426
426
|
support_url: string;
|
|
427
427
|
language: string;
|
|
428
|
+
/** Where the engine serves this store's pictures resized (D139); absent on an engine before it. */
|
|
429
|
+
images_path?: string;
|
|
430
|
+
/** The store's logo, logo for dark backgrounds and square icon (D148); empty or absent when it has none. */
|
|
431
|
+
logo_url?: string;
|
|
432
|
+
logo_dark_url?: string;
|
|
433
|
+
icon_url?: string;
|
|
428
434
|
};
|
|
429
435
|
type Vendor = {
|
|
430
436
|
id: number;
|
|
@@ -578,6 +584,8 @@ type SearchResult = {
|
|
|
578
584
|
total: number;
|
|
579
585
|
limit: number;
|
|
580
586
|
offset: number;
|
|
587
|
+
/** Meilisearch did not answer: search the product listing instead. */
|
|
588
|
+
unavailable?: boolean;
|
|
581
589
|
};
|
|
582
590
|
/** One approved vendor's offer on a variant, from `GET /api/variants/{id}/offers`. Cheapest first. */
|
|
583
591
|
type Offer = {
|
|
@@ -1489,6 +1497,19 @@ type CatalogPage = {
|
|
|
1489
1497
|
declare class CatalogService extends BaseService {
|
|
1490
1498
|
protected readonly facts: StoreFacts;
|
|
1491
1499
|
protected queryCatalog(q: CatalogQuery): Promise<CatalogPage>;
|
|
1500
|
+
/**
|
|
1501
|
+
* The shelf from the Meilisearch module, or null when the store has it off,
|
|
1502
|
+
* sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
|
|
1503
|
+
* the caller asks the database instead of showing the shopper an error.
|
|
1504
|
+
*/
|
|
1505
|
+
protected fromIndex(q: CatalogQuery, o: {
|
|
1506
|
+
page: number;
|
|
1507
|
+
limit: number;
|
|
1508
|
+
search?: string;
|
|
1509
|
+
sortKey?: string;
|
|
1510
|
+
wantsRange: boolean;
|
|
1511
|
+
hierarchy: CatalogPage['categoryHierarchy'];
|
|
1512
|
+
}): Promise<CatalogPage | null>;
|
|
1492
1513
|
}
|
|
1493
1514
|
|
|
1494
1515
|
/**
|
|
@@ -2697,39 +2718,6 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2697
2718
|
search?: string;
|
|
2698
2719
|
limit?: number;
|
|
2699
2720
|
}): 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
2721
|
data: {
|
|
2734
2722
|
id: string;
|
|
2735
2723
|
slug: string;
|
|
@@ -2840,6 +2828,37 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2840
2828
|
metadata: Record<string, unknown> | null;
|
|
2841
2829
|
createdAt: string;
|
|
2842
2830
|
updatedAt: string;
|
|
2831
|
+
}[] | {
|
|
2832
|
+
id: string;
|
|
2833
|
+
slug: string;
|
|
2834
|
+
title: string;
|
|
2835
|
+
name: string;
|
|
2836
|
+
description: string;
|
|
2837
|
+
currency: string;
|
|
2838
|
+
price: number;
|
|
2839
|
+
mrp: number;
|
|
2840
|
+
minPrice: number;
|
|
2841
|
+
maxPrice: number;
|
|
2842
|
+
thumbnail: string | null;
|
|
2843
|
+
image_url: string | null;
|
|
2844
|
+
images: string;
|
|
2845
|
+
stock: number;
|
|
2846
|
+
hasStock: boolean;
|
|
2847
|
+
manageInventory: boolean;
|
|
2848
|
+
allowBackorder: boolean;
|
|
2849
|
+
productTags: string;
|
|
2850
|
+
category: {
|
|
2851
|
+
name: string;
|
|
2852
|
+
slug: string;
|
|
2853
|
+
} | null;
|
|
2854
|
+
vendor: {
|
|
2855
|
+
businessName: string;
|
|
2856
|
+
} | null;
|
|
2857
|
+
variants: ReturnType<typeof toVariant>[];
|
|
2858
|
+
options: never[];
|
|
2859
|
+
ratings: never[];
|
|
2860
|
+
link: string;
|
|
2861
|
+
updatedAt: string;
|
|
2843
2862
|
}[];
|
|
2844
2863
|
}>;
|
|
2845
2864
|
}
|
|
@@ -6145,12 +6164,12 @@ declare const menuService: MenuService;
|
|
|
6145
6164
|
/**
|
|
6146
6165
|
* The store record every page renders from.
|
|
6147
6166
|
*
|
|
6148
|
-
*
|
|
6149
|
-
*
|
|
6150
|
-
*
|
|
6151
|
-
* - the store's name and
|
|
6152
|
-
* storefront serves every store under `baseDomain`, so a name
|
|
6153
|
-
* record would be every store's
|
|
6167
|
+
* Theme and the rest are the storefront's own (its static store, registered
|
|
6168
|
+
* through `setStaticStore`); the engine has no opinion on them. Where the
|
|
6169
|
+
* engine does have one, it wins:
|
|
6170
|
+
* - the store's name, contact, logo and icon, as its owner set them in the
|
|
6171
|
+
* panel. One storefront serves every store under `baseDomain`, so a name or
|
|
6172
|
+
* a logo in the static record would be every store's;
|
|
6154
6173
|
* - the settlement currency. Every price on the site is formatted with it, and
|
|
6155
6174
|
* a store record saying USD over an engine charging INR would print the
|
|
6156
6175
|
* wrong symbol on every price;
|
|
@@ -6606,39 +6625,6 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6606
6625
|
q?: string;
|
|
6607
6626
|
search?: string;
|
|
6608
6627
|
}): 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
6628
|
data: {
|
|
6643
6629
|
id: string;
|
|
6644
6630
|
slug: string;
|
|
@@ -6749,6 +6735,37 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6749
6735
|
metadata: Record<string, unknown> | null;
|
|
6750
6736
|
createdAt: string;
|
|
6751
6737
|
updatedAt: string;
|
|
6738
|
+
}[] | {
|
|
6739
|
+
id: string;
|
|
6740
|
+
slug: string;
|
|
6741
|
+
title: string;
|
|
6742
|
+
name: string;
|
|
6743
|
+
description: string;
|
|
6744
|
+
currency: string;
|
|
6745
|
+
price: number;
|
|
6746
|
+
mrp: number;
|
|
6747
|
+
minPrice: number;
|
|
6748
|
+
maxPrice: number;
|
|
6749
|
+
thumbnail: string | null;
|
|
6750
|
+
image_url: string | null;
|
|
6751
|
+
images: string;
|
|
6752
|
+
stock: number;
|
|
6753
|
+
hasStock: boolean;
|
|
6754
|
+
manageInventory: boolean;
|
|
6755
|
+
allowBackorder: boolean;
|
|
6756
|
+
productTags: string;
|
|
6757
|
+
category: {
|
|
6758
|
+
name: string;
|
|
6759
|
+
slug: string;
|
|
6760
|
+
} | null;
|
|
6761
|
+
vendor: {
|
|
6762
|
+
businessName: string;
|
|
6763
|
+
} | null;
|
|
6764
|
+
variants: ReturnType<typeof toVariant>[];
|
|
6765
|
+
options: never[];
|
|
6766
|
+
ratings: never[];
|
|
6767
|
+
link: string;
|
|
6768
|
+
updatedAt: string;
|
|
6752
6769
|
}[];
|
|
6753
6770
|
}>;
|
|
6754
6771
|
}
|
|
@@ -425,6 +425,12 @@ type StoreProfile = {
|
|
|
425
425
|
phone: string;
|
|
426
426
|
support_url: string;
|
|
427
427
|
language: string;
|
|
428
|
+
/** Where the engine serves this store's pictures resized (D139); absent on an engine before it. */
|
|
429
|
+
images_path?: string;
|
|
430
|
+
/** The store's logo, logo for dark backgrounds and square icon (D148); empty or absent when it has none. */
|
|
431
|
+
logo_url?: string;
|
|
432
|
+
logo_dark_url?: string;
|
|
433
|
+
icon_url?: string;
|
|
428
434
|
};
|
|
429
435
|
type Vendor = {
|
|
430
436
|
id: number;
|
|
@@ -578,6 +584,8 @@ type SearchResult = {
|
|
|
578
584
|
total: number;
|
|
579
585
|
limit: number;
|
|
580
586
|
offset: number;
|
|
587
|
+
/** Meilisearch did not answer: search the product listing instead. */
|
|
588
|
+
unavailable?: boolean;
|
|
581
589
|
};
|
|
582
590
|
/** One approved vendor's offer on a variant, from `GET /api/variants/{id}/offers`. Cheapest first. */
|
|
583
591
|
type Offer = {
|
|
@@ -1489,6 +1497,19 @@ type CatalogPage = {
|
|
|
1489
1497
|
declare class CatalogService extends BaseService {
|
|
1490
1498
|
protected readonly facts: StoreFacts;
|
|
1491
1499
|
protected queryCatalog(q: CatalogQuery): Promise<CatalogPage>;
|
|
1500
|
+
/**
|
|
1501
|
+
* The shelf from the Meilisearch module, or null when the store has it off,
|
|
1502
|
+
* sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
|
|
1503
|
+
* the caller asks the database instead of showing the shopper an error.
|
|
1504
|
+
*/
|
|
1505
|
+
protected fromIndex(q: CatalogQuery, o: {
|
|
1506
|
+
page: number;
|
|
1507
|
+
limit: number;
|
|
1508
|
+
search?: string;
|
|
1509
|
+
sortKey?: string;
|
|
1510
|
+
wantsRange: boolean;
|
|
1511
|
+
hierarchy: CatalogPage['categoryHierarchy'];
|
|
1512
|
+
}): Promise<CatalogPage | null>;
|
|
1492
1513
|
}
|
|
1493
1514
|
|
|
1494
1515
|
/**
|
|
@@ -2697,39 +2718,6 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2697
2718
|
search?: string;
|
|
2698
2719
|
limit?: number;
|
|
2699
2720
|
}): 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
2721
|
data: {
|
|
2734
2722
|
id: string;
|
|
2735
2723
|
slug: string;
|
|
@@ -2840,6 +2828,37 @@ declare class MeilisearchService extends CatalogService {
|
|
|
2840
2828
|
metadata: Record<string, unknown> | null;
|
|
2841
2829
|
createdAt: string;
|
|
2842
2830
|
updatedAt: string;
|
|
2831
|
+
}[] | {
|
|
2832
|
+
id: string;
|
|
2833
|
+
slug: string;
|
|
2834
|
+
title: string;
|
|
2835
|
+
name: string;
|
|
2836
|
+
description: string;
|
|
2837
|
+
currency: string;
|
|
2838
|
+
price: number;
|
|
2839
|
+
mrp: number;
|
|
2840
|
+
minPrice: number;
|
|
2841
|
+
maxPrice: number;
|
|
2842
|
+
thumbnail: string | null;
|
|
2843
|
+
image_url: string | null;
|
|
2844
|
+
images: string;
|
|
2845
|
+
stock: number;
|
|
2846
|
+
hasStock: boolean;
|
|
2847
|
+
manageInventory: boolean;
|
|
2848
|
+
allowBackorder: boolean;
|
|
2849
|
+
productTags: string;
|
|
2850
|
+
category: {
|
|
2851
|
+
name: string;
|
|
2852
|
+
slug: string;
|
|
2853
|
+
} | null;
|
|
2854
|
+
vendor: {
|
|
2855
|
+
businessName: string;
|
|
2856
|
+
} | null;
|
|
2857
|
+
variants: ReturnType<typeof toVariant>[];
|
|
2858
|
+
options: never[];
|
|
2859
|
+
ratings: never[];
|
|
2860
|
+
link: string;
|
|
2861
|
+
updatedAt: string;
|
|
2843
2862
|
}[];
|
|
2844
2863
|
}>;
|
|
2845
2864
|
}
|
|
@@ -6145,12 +6164,12 @@ declare const menuService: MenuService;
|
|
|
6145
6164
|
/**
|
|
6146
6165
|
* The store record every page renders from.
|
|
6147
6166
|
*
|
|
6148
|
-
*
|
|
6149
|
-
*
|
|
6150
|
-
*
|
|
6151
|
-
* - the store's name and
|
|
6152
|
-
* storefront serves every store under `baseDomain`, so a name
|
|
6153
|
-
* record would be every store's
|
|
6167
|
+
* Theme and the rest are the storefront's own (its static store, registered
|
|
6168
|
+
* through `setStaticStore`); the engine has no opinion on them. Where the
|
|
6169
|
+
* engine does have one, it wins:
|
|
6170
|
+
* - the store's name, contact, logo and icon, as its owner set them in the
|
|
6171
|
+
* panel. One storefront serves every store under `baseDomain`, so a name or
|
|
6172
|
+
* a logo in the static record would be every store's;
|
|
6154
6173
|
* - the settlement currency. Every price on the site is formatted with it, and
|
|
6155
6174
|
* a store record saying USD over an engine charging INR would print the
|
|
6156
6175
|
* wrong symbol on every price;
|
|
@@ -6606,39 +6625,6 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6606
6625
|
q?: string;
|
|
6607
6626
|
search?: string;
|
|
6608
6627
|
}): 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
6628
|
data: {
|
|
6643
6629
|
id: string;
|
|
6644
6630
|
slug: string;
|
|
@@ -6749,6 +6735,37 @@ declare class AutocompleteService extends MeilisearchService {
|
|
|
6749
6735
|
metadata: Record<string, unknown> | null;
|
|
6750
6736
|
createdAt: string;
|
|
6751
6737
|
updatedAt: string;
|
|
6738
|
+
}[] | {
|
|
6739
|
+
id: string;
|
|
6740
|
+
slug: string;
|
|
6741
|
+
title: string;
|
|
6742
|
+
name: string;
|
|
6743
|
+
description: string;
|
|
6744
|
+
currency: string;
|
|
6745
|
+
price: number;
|
|
6746
|
+
mrp: number;
|
|
6747
|
+
minPrice: number;
|
|
6748
|
+
maxPrice: number;
|
|
6749
|
+
thumbnail: string | null;
|
|
6750
|
+
image_url: string | null;
|
|
6751
|
+
images: string;
|
|
6752
|
+
stock: number;
|
|
6753
|
+
hasStock: boolean;
|
|
6754
|
+
manageInventory: boolean;
|
|
6755
|
+
allowBackorder: boolean;
|
|
6756
|
+
productTags: string;
|
|
6757
|
+
category: {
|
|
6758
|
+
name: string;
|
|
6759
|
+
slug: string;
|
|
6760
|
+
} | null;
|
|
6761
|
+
vendor: {
|
|
6762
|
+
businessName: string;
|
|
6763
|
+
} | null;
|
|
6764
|
+
variants: ReturnType<typeof toVariant>[];
|
|
6765
|
+
options: never[];
|
|
6766
|
+
ratings: never[];
|
|
6767
|
+
link: string;
|
|
6768
|
+
updatedAt: string;
|
|
6752
6769
|
}[];
|
|
6753
6770
|
}>;
|
|
6754
6771
|
}
|
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
|
}
|
|
@@ -3023,6 +3043,12 @@ var StoreService = class extends BaseService {
|
|
|
3023
3043
|
...profile?.name ? { name: profile.name } : {},
|
|
3024
3044
|
...profile?.email ? { businessEmail: profile.email } : {},
|
|
3025
3045
|
...profile?.phone ? { businessPhone: profile.phone } : {},
|
|
3046
|
+
// The store's pictures (D148), the same: one it has not chosen keeps the static one.
|
|
3047
|
+
// Its own logo also replaces the static dark logo, which would be the deployment's
|
|
3048
|
+
// mark beside this store's; without a dark one of its own, its logo is the fallback.
|
|
3049
|
+
...profile?.logo_url ? { logo: mediaUrl(profile.logo_url), logoDark: void 0 } : {},
|
|
3050
|
+
...profile?.logo_dark_url ? { logoDark: mediaUrl(profile.logo_dark_url) } : {},
|
|
3051
|
+
...profile?.icon_url ? { favicon: mediaUrl(profile.icon_url) } : {},
|
|
3026
3052
|
currencyCode: code,
|
|
3027
3053
|
currencySymbol: sameCurrency ? base.currencySymbol ?? symbolFor(code) : symbolFor(code),
|
|
3028
3054
|
currency: {
|
|
@@ -3045,7 +3071,18 @@ var StoreService = class extends BaseService {
|
|
|
3045
3071
|
newsletter: { ...basePlugins.newsletter, ...flag(plugins.has("newsletter")) },
|
|
3046
3072
|
// Discount codes are core: every GoCommerce store takes them, so
|
|
3047
3073
|
// the code box is shown whatever the static record says.
|
|
3048
|
-
isDiscountCoupons: { ...basePlugins.isDiscountCoupons, active: true }
|
|
3074
|
+
isDiscountCoupons: { ...basePlugins.isDiscountCoupons, active: true },
|
|
3075
|
+
// The engine resizes the store's own pictures in Cloudflare's URL shape
|
|
3076
|
+
// (D139), so the storefront's srcset asks it for each width. Its public
|
|
3077
|
+
// origin, not the proxy path: an <img> needs no CORS, and the proxy would
|
|
3078
|
+
// put every picture through the storefront's server.
|
|
3079
|
+
...profile?.images_path && this.creds.apiUrl ? {
|
|
3080
|
+
imageCdn: {
|
|
3081
|
+
provider: "cloudflare",
|
|
3082
|
+
url: this.creds.apiUrl.trim().replace(/\/+$/, "") + profile.images_path,
|
|
3083
|
+
active: true
|
|
3084
|
+
}
|
|
3085
|
+
} : {}
|
|
3049
3086
|
},
|
|
3050
3087
|
...menus?.length ? { menu: menus } : {},
|
|
3051
3088
|
...deliverable(base, ships),
|