shop-client 3.23.0 → 3.25.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 +48 -7
- package/dist/ai/enrich.d.ts +1 -1
- package/dist/{chunk-HEQDULXV.mjs → chunk-ISOBE3NA.mjs} +117 -60
- package/dist/{chunk-LAJWR2GQ.mjs → chunk-RWIOOEQS.mjs} +6 -9
- package/dist/{chunk-BNTNHHDI.mjs → chunk-X5KZU6K4.mjs} +1 -1
- package/dist/{chunk-U3RQRBXZ.mjs → chunk-YIDIKN7A.mjs} +30 -0
- package/dist/collections.d.ts +10 -10
- package/dist/collections.mjs +2 -2
- package/dist/index.d.ts +10 -9
- package/dist/index.mjs +36 -8
- package/dist/products.d.ts +31 -31
- package/dist/products.mjs +2 -2
- package/dist/store.d.ts +1 -1
- package/dist/store.mjs +2 -2
- package/dist/{types-C0NvqVL-.d.ts → types-CpduFbl-.d.ts} +3 -1
- package/dist/utils/detect-country.d.ts +1 -1
- package/dist/utils/func.d.ts +9 -2
- package/dist/utils/func.mjs +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -351,6 +351,8 @@ const storeInfo = await shop.getInfo();
|
|
|
351
351
|
|
|
352
352
|
### Products
|
|
353
353
|
|
|
354
|
+
- Gift cards are excluded from product responses. Any product whose `product_type` / `type` contains `"gift card"` will be skipped (and `products.find()` returns `null` for gift cards).
|
|
355
|
+
|
|
354
356
|
#### `products.all()`
|
|
355
357
|
|
|
356
358
|
Fetches all products from the store with automatic pagination handling.
|
|
@@ -359,7 +361,7 @@ Fetches all products from the store with automatic pagination handling.
|
|
|
359
361
|
const allProducts = await shop.products.all();
|
|
360
362
|
```
|
|
361
363
|
|
|
362
|
-
**Returns:** `ProductResult[] | null`
|
|
364
|
+
**Returns:** `ProductResult[] | null` (typed based on `columns`, defaults to minimal)
|
|
363
365
|
|
|
364
366
|
#### `products.paginated(options)`
|
|
365
367
|
|
|
@@ -379,7 +381,7 @@ const products = await shop.products.paginated({
|
|
|
379
381
|
- `limit` (number, optional): Products per page (default: 250, max: 250)
|
|
380
382
|
- `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']` (e.g., `"USD"`, `"EUR"`, `"JPY"`)
|
|
381
383
|
|
|
382
|
-
**Returns:** `ProductResult[] | null`
|
|
384
|
+
**Returns:** `ProductResult[] | null` (typed based on `columns`, defaults to minimal)
|
|
383
385
|
|
|
384
386
|
#### `products.find(handle)`
|
|
385
387
|
|
|
@@ -397,7 +399,26 @@ const productEur = await shop.products.find("product-handle", { currency: "EUR"
|
|
|
397
399
|
- `options` (object, optional): Additional options
|
|
398
400
|
- `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']`
|
|
399
401
|
|
|
400
|
-
**Returns:** `ProductResult | null`
|
|
402
|
+
**Returns:** `ProductResult | null` (typed based on `columns`, defaults to minimal)
|
|
403
|
+
|
|
404
|
+
#### `products.findEnhanced(handle, options)`
|
|
405
|
+
|
|
406
|
+
Finds a product by handle and returns the product plus AI enrichment from the worker endpoint. The `product` field is typed the same way as `products.find()` based on `columns`.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
const enhanced = await shop.products.findEnhanced("product-handle", {
|
|
410
|
+
apiKey: process.env.ENRICH_API_KEY!,
|
|
411
|
+
columns: { mode: "full", images: "full", options: "full" },
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
if (enhanced) {
|
|
415
|
+
console.log(enhanced.cache); // e.g. "hit" | "miss"
|
|
416
|
+
console.log(enhanced.enrichment.markdown);
|
|
417
|
+
console.log(enhanced.product.handle); // available when mode: "full"
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Returns:** `EnhancedProductResponse<ProductResult> | null` (typed based on `columns`)
|
|
401
422
|
|
|
402
423
|
#### `products.showcased()`
|
|
403
424
|
|
|
@@ -475,7 +496,7 @@ const results = await shop.products.predictiveSearch("dress", {
|
|
|
475
496
|
- Extracts handles from Ajax results, fetches full products via `find`
|
|
476
497
|
- Falls back to non-locale path when locale returns 404/417
|
|
477
498
|
|
|
478
|
-
**Returns:** `ProductResult[]`
|
|
499
|
+
**Returns:** `ProductResult[]` (typed based on `columns`, defaults to minimal)
|
|
479
500
|
|
|
480
501
|
### Recommendations
|
|
481
502
|
|
|
@@ -497,7 +518,7 @@ const recos = await shop.products.recommendations(1234567890, {
|
|
|
497
518
|
|
|
498
519
|
### Product Columns
|
|
499
520
|
|
|
500
|
-
Default product payload is minimal. Use `columns` to override the product payload shape
|
|
521
|
+
Default product payload is minimal. Use `columns` to override the product payload shape, and TypeScript will reflect the shape in the returned type:
|
|
501
522
|
|
|
502
523
|
```typescript
|
|
503
524
|
// Minimal products (default)
|
|
@@ -514,6 +535,11 @@ const minimalOne = await shop.products.find("product-handle", {
|
|
|
514
535
|
});
|
|
515
536
|
```
|
|
516
537
|
|
|
538
|
+
Quick mental model:
|
|
539
|
+
- `mode: "minimal"` returns a minimal product shape (no `handle`, no `priceMin/priceMax`, no `currency` field)
|
|
540
|
+
- `mode: "full"` returns a full product shape (includes `handle`, pricing range fields, `currency`, variants, etc.)
|
|
541
|
+
- `images: "full"` and `options: "full"` expand those subfields while keeping the chosen `mode`
|
|
542
|
+
|
|
517
543
|
### Collections
|
|
518
544
|
|
|
519
545
|
#### `collections.all()`
|
|
@@ -568,6 +594,8 @@ const collectionsPage = await shop.collections.paginated({
|
|
|
568
594
|
|
|
569
595
|
### Collection Products
|
|
570
596
|
|
|
597
|
+
- Gift cards are excluded from collection product responses (same rules as `Products`).
|
|
598
|
+
|
|
571
599
|
#### `collections.products.all(handle)`
|
|
572
600
|
|
|
573
601
|
Fetches all products from a specific collection.
|
|
@@ -579,7 +607,7 @@ const products = await shop.collections.products.all("collection-handle");
|
|
|
579
607
|
**Parameters:**
|
|
580
608
|
- `handle` (string): The collection handle
|
|
581
609
|
|
|
582
|
-
**Returns:** `ProductResult[] | null`
|
|
610
|
+
**Returns:** `ProductResult[] | null` (typed based on `columns`, defaults to minimal)
|
|
583
611
|
|
|
584
612
|
#### `collections.products.paginated(handle, options)`
|
|
585
613
|
|
|
@@ -600,7 +628,7 @@ const products = await shop.collections.products.paginated("collection-handle",
|
|
|
600
628
|
- `limit` (number, optional): Products per page (default: 250)
|
|
601
629
|
- `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']`
|
|
602
630
|
|
|
603
|
-
**Returns:** `ProductResult[] | null`
|
|
631
|
+
**Returns:** `ProductResult[] | null` (typed based on `columns`, defaults to minimal)
|
|
604
632
|
|
|
605
633
|
Collection products also default to minimal. To request full products from collections, pass `columns`:
|
|
606
634
|
|
|
@@ -616,6 +644,7 @@ By default, pricing is formatted using the store’s detected currency.
|
|
|
616
644
|
You can override the currency for product and collection queries by passing a `currency` option.
|
|
617
645
|
This override updates pricing display fields only:
|
|
618
646
|
- `ProductResult.localizedPricing` formatted strings
|
|
647
|
+
- For full products (`mode: "full"`), `ProductResult.currency` is also set to the override
|
|
619
648
|
|
|
620
649
|
### Showcased Products
|
|
621
650
|
|
|
@@ -899,7 +928,9 @@ type Product = {
|
|
|
899
928
|
sellingPlanGroups?: unknown;
|
|
900
929
|
// Keys formatted as name#value parts joined by '##' (alphabetically sorted), e.g., "color#blue##size#xl"
|
|
901
930
|
variantOptionsMap: Record<string, string>;
|
|
931
|
+
variantPriceMap: Record<string, number>;
|
|
902
932
|
};
|
|
933
|
+
```
|
|
903
934
|
|
|
904
935
|
#### Date Handling
|
|
905
936
|
|
|
@@ -909,9 +940,19 @@ type Product = {
|
|
|
909
940
|
#### Variant Options Map
|
|
910
941
|
|
|
911
942
|
- Each product includes `variantOptionsMap: Record<string, string>` when variants are present.
|
|
943
|
+
- Each product includes `variantPriceMap: Record<string, number>` using the same keys; values are prices in cents.
|
|
912
944
|
- Keys are composed of normalized option name/value pairs in the form `name#value`, joined by `##` and sorted alphabetically for stability.
|
|
913
945
|
- Example: `{ "color#blue##size#xl": "123", "color#red##size#m": "456" }`.
|
|
914
946
|
- Normalization uses `normalizeKey` (lowercases; spaces → `_`; non-space separators like `-` remain intact).
|
|
947
|
+
|
|
948
|
+
Generate keys using `buildVariantKey` (exported from the main entrypoint):
|
|
949
|
+
|
|
950
|
+
```typescript
|
|
951
|
+
import { buildVariantKey } from "shop-client";
|
|
952
|
+
|
|
953
|
+
const key = buildVariantKey({ Size: "XL", Color: "Blue" }); // "color#blue##size#xl"
|
|
954
|
+
const variantId = product.variantOptionsMap[key];
|
|
955
|
+
const priceInCents = product.variantPriceMap[key];
|
|
915
956
|
```
|
|
916
957
|
|
|
917
958
|
### ProductVariant
|
package/dist/ai/enrich.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as OpenRouterConfig,
|
|
1
|
+
import { O as OpenRouterConfig, q as ProductClassification, r as SEOContent, s as SystemUserPrompt, e as ShopifySingleProduct } from '../types-CpduFbl-.js';
|
|
2
2
|
|
|
3
3
|
declare function buildEnrichPrompt(args: {
|
|
4
4
|
bodyInput: string;
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-4GPP2KXF.mjs";
|
|
4
4
|
import {
|
|
5
5
|
formatPrice
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YIDIKN7A.mjs";
|
|
7
7
|
|
|
8
8
|
// src/products.ts
|
|
9
9
|
import { filter, isNonNullish } from "remeda";
|
|
@@ -21,12 +21,10 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
21
21
|
findCache.set(key, { ts: Date.now(), value });
|
|
22
22
|
};
|
|
23
23
|
function applyCurrencyOverride(product, currency) {
|
|
24
|
-
var _a, _b, _c, _d, _e;
|
|
25
24
|
if ("priceMin" in product) {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const compareAtMin = typeof p.compareAtPriceMin === "number" ? p.compareAtPriceMin : (_c = p.compareAtPrice) != null ? _c : 0;
|
|
25
|
+
const priceMin = product.priceMin;
|
|
26
|
+
const priceMax = product.priceMax;
|
|
27
|
+
const compareAtMin = product.compareAtPriceMin;
|
|
30
28
|
return {
|
|
31
29
|
...product,
|
|
32
30
|
currency,
|
|
@@ -39,12 +37,11 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
39
37
|
}
|
|
40
38
|
};
|
|
41
39
|
}
|
|
42
|
-
const compareAtPrice = (_d = product.compareAtPrice) != null ? _d : 0;
|
|
43
40
|
return {
|
|
44
41
|
...product,
|
|
45
42
|
localizedPricing: {
|
|
46
|
-
priceFormatted: formatPrice(
|
|
47
|
-
compareAtPriceFormatted: formatPrice(compareAtPrice, currency)
|
|
43
|
+
priceFormatted: formatPrice(product.price, currency),
|
|
44
|
+
compareAtPriceFormatted: formatPrice(product.compareAtPrice, currency)
|
|
48
45
|
}
|
|
49
46
|
};
|
|
50
47
|
}
|
|
@@ -61,6 +58,13 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
61
58
|
options: (_f = (_e = override == null ? void 0 : override.options) != null ? _e : base.options) != null ? _f : "minimal"
|
|
62
59
|
};
|
|
63
60
|
};
|
|
61
|
+
const isGiftCardType = (value) => {
|
|
62
|
+
if (typeof value !== "string") return false;
|
|
63
|
+
const s = value.trim().toLowerCase();
|
|
64
|
+
if (!s) return false;
|
|
65
|
+
if (s === "gift card" || s === "giftcard") return true;
|
|
66
|
+
return s.includes("gift card") || s.includes("giftcard");
|
|
67
|
+
};
|
|
64
68
|
async function allInternal(options) {
|
|
65
69
|
const limit = 250;
|
|
66
70
|
const allProducts = [];
|
|
@@ -68,16 +72,23 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
68
72
|
async function fetchAll() {
|
|
69
73
|
let currentPage = 1;
|
|
70
74
|
while (true) {
|
|
71
|
-
const
|
|
72
|
-
|
|
75
|
+
const url = `${baseUrl}products.json?page=${currentPage}&limit=${limit}`;
|
|
76
|
+
const response = await rateLimitedFetch(url, {
|
|
77
|
+
rateLimitClass: "products:list"
|
|
73
78
|
});
|
|
74
|
-
if (!
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
81
|
+
}
|
|
82
|
+
const data = await response.json();
|
|
83
|
+
const rawProducts = Array.isArray(data.products) ? data.products : [];
|
|
84
|
+
const filteredRawProducts = rawProducts.filter(
|
|
85
|
+
(p) => !isGiftCardType(p.product_type)
|
|
86
|
+
);
|
|
87
|
+
const normalized = productsDto(filteredRawProducts, { columns }) || [];
|
|
88
|
+
allProducts.push(...normalized);
|
|
89
|
+
if (rawProducts.length === 0 || rawProducts.length < limit) {
|
|
78
90
|
break;
|
|
79
91
|
}
|
|
80
|
-
allProducts.push(...products);
|
|
81
92
|
currentPage++;
|
|
82
93
|
}
|
|
83
94
|
return allProducts;
|
|
@@ -107,10 +118,14 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
107
118
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
108
119
|
}
|
|
109
120
|
const data = await response.json();
|
|
110
|
-
|
|
121
|
+
const rawProducts = Array.isArray(data.products) ? data.products : [];
|
|
122
|
+
const filteredRawProducts = rawProducts.filter(
|
|
123
|
+
(p) => !isGiftCardType(p.product_type)
|
|
124
|
+
);
|
|
125
|
+
if (rawProducts.length === 0) {
|
|
111
126
|
return [];
|
|
112
127
|
}
|
|
113
|
-
const normalized = productsDto(
|
|
128
|
+
const normalized = productsDto(filteredRawProducts, {
|
|
114
129
|
columns
|
|
115
130
|
});
|
|
116
131
|
return maybeOverrideProductsCurrency(
|
|
@@ -184,6 +199,14 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
184
199
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
185
200
|
}
|
|
186
201
|
const product = await response.json();
|
|
202
|
+
if (isGiftCardType(product.type)) {
|
|
203
|
+
setCached(cacheKey, null);
|
|
204
|
+
if (finalHandle !== sanitizedHandle) {
|
|
205
|
+
const finalKey = `${finalHandle}|${columns.mode}|${columns.images}|${columns.options}`;
|
|
206
|
+
setCached(finalKey, null);
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
187
210
|
const productData = productDto(product, { columns });
|
|
188
211
|
setCached(cacheKey, productData);
|
|
189
212
|
if (finalHandle !== sanitizedHandle) {
|
|
@@ -232,15 +255,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
232
255
|
}
|
|
233
256
|
const data = await resp.json();
|
|
234
257
|
const raw = (_d = (_c = (_b = data == null ? void 0 : data.resources) == null ? void 0 : _b.results) == null ? void 0 : _c.products) != null ? _d : [];
|
|
235
|
-
const handles = raw.filter((p) => p.available !== false).map((p) => p.handle).filter((h) => typeof h === "string" && h.length > 0).slice(0, limit);
|
|
258
|
+
const handles = raw.filter((p) => p.available !== false && !isGiftCardType(p.type)).map((p) => p.handle).filter((h) => typeof h === "string" && h.length > 0).slice(0, limit);
|
|
236
259
|
const fetched = await Promise.all(
|
|
237
260
|
handles.map((h) => findInternal(h, { columns }))
|
|
238
261
|
);
|
|
239
262
|
const results = filter(fetched, isNonNullish);
|
|
240
|
-
return (_e = maybeOverrideProductsCurrency(
|
|
241
|
-
results,
|
|
242
|
-
options.currency
|
|
243
|
-
)) != null ? _e : [];
|
|
263
|
+
return (_e = maybeOverrideProductsCurrency(results, options.currency)) != null ? _e : [];
|
|
244
264
|
}
|
|
245
265
|
async function recommendationsInternal(productId, options) {
|
|
246
266
|
var _a, _b;
|
|
@@ -267,11 +287,11 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
267
287
|
const data = await resp.json();
|
|
268
288
|
const isRecord = (v) => typeof v === "object" && v !== null;
|
|
269
289
|
const productsArray = Array.isArray(data) ? data : isRecord(data) && Array.isArray(data.products) ? data.products : [];
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
normalized,
|
|
273
|
-
options.currency
|
|
290
|
+
const filtered = productsArray.filter(
|
|
291
|
+
(p) => !isGiftCardType(p.product_type)
|
|
274
292
|
);
|
|
293
|
+
const normalized = productsDto(filtered, { columns }) || [];
|
|
294
|
+
return maybeOverrideProductsCurrency(normalized, options.currency);
|
|
275
295
|
}
|
|
276
296
|
async function findEnhancedInternal(productHandle, options) {
|
|
277
297
|
var _a;
|
|
@@ -279,12 +299,11 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
279
299
|
if (!apiKey || typeof apiKey !== "string" || !apiKey.trim()) {
|
|
280
300
|
throw new Error("apiKey is required");
|
|
281
301
|
}
|
|
282
|
-
const updatedAt = options.updatedAt;
|
|
283
302
|
let updatedAtTrimmed;
|
|
284
|
-
if (typeof updatedAt === "string") {
|
|
285
|
-
const trimmed = updatedAt.trim();
|
|
303
|
+
if (typeof options.updatedAt === "string") {
|
|
304
|
+
const trimmed = options.updatedAt.trim();
|
|
286
305
|
updatedAtTrimmed = trimmed ? trimmed : void 0;
|
|
287
|
-
} else if (updatedAt != null) {
|
|
306
|
+
} else if (options.updatedAt != null) {
|
|
288
307
|
throw new Error("updatedAt must be a string");
|
|
289
308
|
}
|
|
290
309
|
const columns = resolveColumns(options.columns);
|
|
@@ -358,12 +377,26 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
358
377
|
const raw = parsed.shopify;
|
|
359
378
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
360
379
|
if ("body_html" in raw) {
|
|
380
|
+
if (isGiftCardType(raw.product_type)) {
|
|
381
|
+
return {
|
|
382
|
+
enrichment: parsed.enrichment,
|
|
383
|
+
cache: parsed.cache,
|
|
384
|
+
product: mappedProduct
|
|
385
|
+
};
|
|
386
|
+
}
|
|
361
387
|
const mapped = productsDto([raw], {
|
|
362
388
|
columns
|
|
363
389
|
});
|
|
364
390
|
const first = Array.isArray(mapped) ? mapped[0] : null;
|
|
365
391
|
if (first) mappedProduct = first;
|
|
366
392
|
} else if ("description" in raw) {
|
|
393
|
+
if (isGiftCardType(raw.type)) {
|
|
394
|
+
return {
|
|
395
|
+
enrichment: parsed.enrichment,
|
|
396
|
+
cache: parsed.cache,
|
|
397
|
+
product: mappedProduct
|
|
398
|
+
};
|
|
399
|
+
}
|
|
367
400
|
mappedProduct = productDto(raw, {
|
|
368
401
|
columns
|
|
369
402
|
});
|
|
@@ -396,10 +429,13 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
396
429
|
* });
|
|
397
430
|
* ```
|
|
398
431
|
*/
|
|
399
|
-
all: async (options) =>
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
432
|
+
all: async (options) => {
|
|
433
|
+
const res = await allInternal({
|
|
434
|
+
currency: options == null ? void 0 : options.currency,
|
|
435
|
+
columns: options == null ? void 0 : options.columns
|
|
436
|
+
});
|
|
437
|
+
return res;
|
|
438
|
+
},
|
|
403
439
|
/**
|
|
404
440
|
* Fetches products with pagination support.
|
|
405
441
|
*
|
|
@@ -422,12 +458,15 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
422
458
|
* const secondPage = await shop.products.paginated({ page: 2, limit: 50 });
|
|
423
459
|
* ```
|
|
424
460
|
*/
|
|
425
|
-
paginated: async (options) =>
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
461
|
+
paginated: async (options) => {
|
|
462
|
+
const res = await paginatedInternal({
|
|
463
|
+
page: options == null ? void 0 : options.page,
|
|
464
|
+
limit: options == null ? void 0 : options.limit,
|
|
465
|
+
currency: options == null ? void 0 : options.currency,
|
|
466
|
+
columns: options == null ? void 0 : options.columns
|
|
467
|
+
});
|
|
468
|
+
return res;
|
|
469
|
+
},
|
|
431
470
|
/**
|
|
432
471
|
* Finds a specific product by its handle.
|
|
433
472
|
*
|
|
@@ -453,10 +492,13 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
453
492
|
* const productWithVariant = await shop.products.find('t-shirt?variant=123');
|
|
454
493
|
* ```
|
|
455
494
|
*/
|
|
456
|
-
find: async (productHandle, options) =>
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
495
|
+
find: async (productHandle, options) => {
|
|
496
|
+
const res = await findInternal(productHandle, {
|
|
497
|
+
currency: options == null ? void 0 : options.currency,
|
|
498
|
+
columns: options == null ? void 0 : options.columns
|
|
499
|
+
});
|
|
500
|
+
return res;
|
|
501
|
+
},
|
|
460
502
|
findEnhanced: async (productHandle, options) => findEnhancedInternal(productHandle, options),
|
|
461
503
|
/**
|
|
462
504
|
* Enrich a product by generating merged markdown from body_html and product page.
|
|
@@ -466,9 +508,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
466
508
|
if (!productHandle || typeof productHandle !== "string") {
|
|
467
509
|
throw new Error("Product handle is required and must be a string");
|
|
468
510
|
}
|
|
469
|
-
const baseProduct = await findInternal(
|
|
470
|
-
|
|
471
|
-
|
|
511
|
+
const baseProduct = await findInternal(
|
|
512
|
+
productHandle,
|
|
513
|
+
{
|
|
514
|
+
columns: { mode: "full", images: "full", options: "full" }
|
|
515
|
+
}
|
|
516
|
+
);
|
|
472
517
|
if (!baseProduct) return null;
|
|
473
518
|
const handle = baseProduct.handle;
|
|
474
519
|
const { enrichProduct } = await import("./ai/enrich.mjs");
|
|
@@ -490,9 +535,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
490
535
|
if (!productHandle || typeof productHandle !== "string") {
|
|
491
536
|
throw new Error("Product handle is required and must be a string");
|
|
492
537
|
}
|
|
493
|
-
const baseProduct = await findInternal(
|
|
494
|
-
|
|
495
|
-
|
|
538
|
+
const baseProduct = await findInternal(
|
|
539
|
+
productHandle,
|
|
540
|
+
{
|
|
541
|
+
columns: { mode: "full", images: "full", options: "full" }
|
|
542
|
+
}
|
|
543
|
+
);
|
|
496
544
|
if (!baseProduct) throw new Error("Product not found");
|
|
497
545
|
const handle = baseProduct.handle;
|
|
498
546
|
const { buildEnrichPromptForProduct } = await import("./ai/enrich.mjs");
|
|
@@ -546,9 +594,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
546
594
|
if (!productHandle || typeof productHandle !== "string") {
|
|
547
595
|
throw new Error("Product handle is required and must be a string");
|
|
548
596
|
}
|
|
549
|
-
const baseProduct = await findInternal(
|
|
550
|
-
|
|
551
|
-
|
|
597
|
+
const baseProduct = await findInternal(
|
|
598
|
+
productHandle,
|
|
599
|
+
{
|
|
600
|
+
columns: { mode: "full", images: "full", options: "full" }
|
|
601
|
+
}
|
|
602
|
+
);
|
|
552
603
|
if (!baseProduct) throw new Error("Product not found");
|
|
553
604
|
const handle = baseProduct.handle;
|
|
554
605
|
const { buildClassifyPromptForProduct } = await import("./ai/enrich.mjs");
|
|
@@ -562,9 +613,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
562
613
|
if (!productHandle || typeof productHandle !== "string") {
|
|
563
614
|
throw new Error("Product handle is required and must be a string");
|
|
564
615
|
}
|
|
565
|
-
const baseProduct = await findInternal(
|
|
566
|
-
|
|
567
|
-
|
|
616
|
+
const baseProduct = await findInternal(
|
|
617
|
+
productHandle,
|
|
618
|
+
{
|
|
619
|
+
columns: { mode: "full", images: "full", options: "full" }
|
|
620
|
+
}
|
|
621
|
+
);
|
|
568
622
|
if (!baseProduct) return null;
|
|
569
623
|
const payload = {
|
|
570
624
|
title: baseProduct.title,
|
|
@@ -606,9 +660,12 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
606
660
|
if (content) {
|
|
607
661
|
return extractMainSection(content);
|
|
608
662
|
}
|
|
609
|
-
const baseProduct = await findInternal(
|
|
610
|
-
|
|
611
|
-
|
|
663
|
+
const baseProduct = await findInternal(
|
|
664
|
+
productHandle,
|
|
665
|
+
{
|
|
666
|
+
columns: { mode: "full", images: "full", options: "full" }
|
|
667
|
+
}
|
|
668
|
+
);
|
|
612
669
|
if (!baseProduct) return null;
|
|
613
670
|
const pageHtml = await fetchProductPage(storeDomain, baseProduct.handle);
|
|
614
671
|
return extractMainSection(pageHtml);
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-4GPP2KXF.mjs";
|
|
4
4
|
import {
|
|
5
5
|
formatPrice
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YIDIKN7A.mjs";
|
|
7
7
|
|
|
8
8
|
// src/collections.ts
|
|
9
9
|
import { filter, isNonNullish } from "remeda";
|
|
@@ -21,12 +21,10 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
|
|
|
21
21
|
findCache.set(key, { ts: Date.now(), value });
|
|
22
22
|
};
|
|
23
23
|
function applyCurrencyOverride(product, currency) {
|
|
24
|
-
var _a, _b, _c, _d, _e;
|
|
25
24
|
if ("priceMin" in product) {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const compareAtMin = typeof p.compareAtPriceMin === "number" ? p.compareAtPriceMin : (_c = p.compareAtPrice) != null ? _c : 0;
|
|
25
|
+
const priceMin = product.priceMin;
|
|
26
|
+
const priceMax = product.priceMax;
|
|
27
|
+
const compareAtMin = product.compareAtPriceMin;
|
|
30
28
|
return {
|
|
31
29
|
...product,
|
|
32
30
|
currency,
|
|
@@ -39,12 +37,11 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
|
|
|
39
37
|
}
|
|
40
38
|
};
|
|
41
39
|
}
|
|
42
|
-
const compareAtPrice = (_d = product.compareAtPrice) != null ? _d : 0;
|
|
43
40
|
return {
|
|
44
41
|
...product,
|
|
45
42
|
localizedPricing: {
|
|
46
|
-
priceFormatted: formatPrice(
|
|
47
|
-
compareAtPriceFormatted: formatPrice(compareAtPrice, currency)
|
|
43
|
+
priceFormatted: formatPrice(product.price, currency),
|
|
44
|
+
compareAtPriceFormatted: formatPrice(product.compareAtPrice, currency)
|
|
48
45
|
}
|
|
49
46
|
};
|
|
50
47
|
}
|
|
@@ -110,6 +110,35 @@ function buildVariantOptionsMap(optionNames, variants) {
|
|
|
110
110
|
}
|
|
111
111
|
return map;
|
|
112
112
|
}
|
|
113
|
+
function buildVariantPriceMap(optionNames, variants) {
|
|
114
|
+
const toCents = (value) => {
|
|
115
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
116
|
+
if (typeof value === "string") {
|
|
117
|
+
const n = Number.parseFloat(value);
|
|
118
|
+
return Number.isFinite(n) ? Math.round(n * 100) : 0;
|
|
119
|
+
}
|
|
120
|
+
return 0;
|
|
121
|
+
};
|
|
122
|
+
const keys = optionNames.map(normalizeKey);
|
|
123
|
+
const map = {};
|
|
124
|
+
for (const v of variants) {
|
|
125
|
+
const parts = [];
|
|
126
|
+
if (keys[0] && v.option1)
|
|
127
|
+
parts.push(`${keys[0]}#${normalizeKey(v.option1)}`);
|
|
128
|
+
if (keys[1] && v.option2)
|
|
129
|
+
parts.push(`${keys[1]}#${normalizeKey(v.option2)}`);
|
|
130
|
+
if (keys[2] && v.option3)
|
|
131
|
+
parts.push(`${keys[2]}#${normalizeKey(v.option3)}`);
|
|
132
|
+
if (parts.length > 0) {
|
|
133
|
+
if (parts.length > 1) parts.sort();
|
|
134
|
+
const key = parts.join("##");
|
|
135
|
+
if (map[key] === void 0) {
|
|
136
|
+
map[key] = toCents(v.price);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return map;
|
|
141
|
+
}
|
|
113
142
|
function buildVariantKey(obj) {
|
|
114
143
|
const parts = [];
|
|
115
144
|
for (const [name, value] of Object.entries(obj)) {
|
|
@@ -142,6 +171,7 @@ export {
|
|
|
142
171
|
safeParseDate,
|
|
143
172
|
normalizeKey,
|
|
144
173
|
buildVariantOptionsMap,
|
|
174
|
+
buildVariantPriceMap,
|
|
145
175
|
buildVariantKey,
|
|
146
176
|
formatPrice
|
|
147
177
|
};
|
package/dist/collections.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ShopInfo } from './store.js';
|
|
2
|
-
import {
|
|
2
|
+
import { g as Collection, a as ProductColumnsMode, b as ProductImagesMode, c as ProductOptionsMode, k as CurrencyCode, P as ProductColumnsConfig, d as ProductResult, f as ShopifyCollection } from './types-CpduFbl-.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Interface for collection operations
|
|
@@ -37,19 +37,19 @@ interface CollectionOperations {
|
|
|
37
37
|
/**
|
|
38
38
|
* Fetches products from a specific collection with pagination support.
|
|
39
39
|
*/
|
|
40
|
-
paginated(collectionHandle: string, options?: {
|
|
40
|
+
paginated<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(collectionHandle: string, options?: {
|
|
41
41
|
page?: number;
|
|
42
42
|
limit?: number;
|
|
43
43
|
currency?: CurrencyCode;
|
|
44
|
-
columns?: ProductColumnsConfig
|
|
45
|
-
}): Promise<ProductResult[] | null>;
|
|
44
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
45
|
+
}): Promise<ProductResult<C, I, O>[] | null>;
|
|
46
46
|
/**
|
|
47
47
|
* Fetches all products from a specific collection.
|
|
48
48
|
*/
|
|
49
|
-
all(collectionHandle: string, options?: {
|
|
49
|
+
all<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(collectionHandle: string, options?: {
|
|
50
50
|
currency?: CurrencyCode;
|
|
51
|
-
columns?: ProductColumnsConfig
|
|
52
|
-
}): Promise<ProductResult[] | null>;
|
|
51
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
52
|
+
}): Promise<ProductResult<C, I, O>[] | null>;
|
|
53
53
|
/**
|
|
54
54
|
* Fetches all product slugs from a specific collection.
|
|
55
55
|
*/
|
|
@@ -59,10 +59,10 @@ interface CollectionOperations {
|
|
|
59
59
|
/**
|
|
60
60
|
* Creates collection operations for a store instance
|
|
61
61
|
*/
|
|
62
|
-
declare function createCollectionOperations(baseUrl: string, storeDomain: string, fetchCollections: (page: number, limit: number) => Promise<Collection[] | null>, collectionsDto: (collections: ShopifyCollection[]) => Collection[], fetchPaginatedProductsFromCollection: (collectionHandle: string, options?: {
|
|
62
|
+
declare function createCollectionOperations(baseUrl: string, storeDomain: string, fetchCollections: (page: number, limit: number) => Promise<Collection[] | null>, collectionsDto: (collections: ShopifyCollection[]) => Collection[], fetchPaginatedProductsFromCollection: <C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(collectionHandle: string, options?: {
|
|
63
63
|
page?: number;
|
|
64
64
|
limit?: number;
|
|
65
|
-
columns?: ProductColumnsConfig
|
|
66
|
-
}) => Promise<ProductResult[] | null>, getStoreInfo: () => Promise<ShopInfo>, findCollection: (handle: string) => Promise<Collection | null>): CollectionOperations;
|
|
65
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
66
|
+
}) => Promise<ProductResult<C, I, O>[] | null>, getStoreInfo: () => Promise<ShopInfo>, findCollection: (handle: string) => Promise<Collection | null>): CollectionOperations;
|
|
67
67
|
|
|
68
68
|
export { type CollectionOperations, createCollectionOperations };
|
package/dist/collections.mjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { O as OpenRouterConfig, P as ProductColumnsConfig, C as CollectionColumnsConfig, S as ShopifyProduct,
|
|
2
|
-
export {
|
|
1
|
+
import { O as OpenRouterConfig, P as ProductColumnsConfig, C as CollectionColumnsConfig, a as ProductColumnsMode, b as ProductImagesMode, c as ProductOptionsMode, S as ShopifyProduct, d as ProductResult, e as ShopifySingleProduct, f as ShopifyCollection, g as Collection, J as JsonLdEntry, h as StoreTypeBreakdown } from './types-CpduFbl-.js';
|
|
2
|
+
export { i as CountryDetectionResult, j as CountryScores, k as CurrencyCode, L as LocalizedPricing, M as MetaTag, l as Product, m as ProductImage, n as ProductOption, o as ProductVariant, p as ProductVariantImage } from './types-CpduFbl-.js';
|
|
3
3
|
import { CheckoutOperations } from './checkout.js';
|
|
4
4
|
import { CollectionOperations } from './collections.js';
|
|
5
5
|
import { ProductOperations } from './products.js';
|
|
6
6
|
import { ShopOperations, ShopInfo, OpenGraphMeta } from './store.js';
|
|
7
7
|
export { classifyProduct, generateSEOContent } from './ai/enrich.js';
|
|
8
8
|
export { detectShopCountry } from './utils/detect-country.js';
|
|
9
|
-
export { calculateDiscount, extractDomainWithoutSuffix, genProductSlug, generateStoreSlug, safeParseDate, sanitizeDomain } from './utils/func.js';
|
|
9
|
+
export { buildVariantKey, calculateDiscount, extractDomainWithoutSuffix, genProductSlug, generateStoreSlug, safeParseDate, sanitizeDomain } from './utils/func.js';
|
|
10
10
|
export { configureRateLimit } from './utils/rate-limit.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -85,12 +85,12 @@ declare class ShopClient {
|
|
|
85
85
|
/**
|
|
86
86
|
* Transform Shopify products to our Product format
|
|
87
87
|
*/
|
|
88
|
-
productsDto(products: ShopifyProduct[], options?: {
|
|
89
|
-
columns?: ProductColumnsConfig
|
|
90
|
-
}): ProductResult[] | null;
|
|
91
|
-
productDto(product: ShopifySingleProduct, options?: {
|
|
92
|
-
columns?: ProductColumnsConfig
|
|
93
|
-
}): ProductResult
|
|
88
|
+
productsDto<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(products: ShopifyProduct[], options?: {
|
|
89
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
90
|
+
}): ProductResult<C, I, O>[] | null;
|
|
91
|
+
productDto<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(product: ShopifySingleProduct, options?: {
|
|
92
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
93
|
+
}): ProductResult<C, I, O>;
|
|
94
94
|
collectionsDto(collections: ShopifyCollection[]): Collection[];
|
|
95
95
|
/**
|
|
96
96
|
* Enhanced error handling with context
|
|
@@ -108,6 +108,7 @@ declare class ShopClient {
|
|
|
108
108
|
* Fetch paginated products from a specific collection
|
|
109
109
|
*/
|
|
110
110
|
private fetchPaginatedProductsFromCollection;
|
|
111
|
+
private isGiftCardProductType;
|
|
111
112
|
/**
|
|
112
113
|
* Validate if a product exists (with caching)
|
|
113
114
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
} from "./chunk-W4SF6W2P.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createCollectionOperations
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RWIOOEQS.mjs";
|
|
7
7
|
import {
|
|
8
8
|
createProductOperations
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ISOBE3NA.mjs";
|
|
10
10
|
import {
|
|
11
11
|
createShopOperations,
|
|
12
12
|
getInfoForShop
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-X5KZU6K4.mjs";
|
|
14
14
|
import {
|
|
15
15
|
classifyProduct,
|
|
16
16
|
determineStoreType,
|
|
@@ -24,7 +24,9 @@ import {
|
|
|
24
24
|
detectShopCountry
|
|
25
25
|
} from "./chunk-SBHTEKLB.mjs";
|
|
26
26
|
import {
|
|
27
|
+
buildVariantKey,
|
|
27
28
|
buildVariantOptionsMap,
|
|
29
|
+
buildVariantPriceMap,
|
|
28
30
|
calculateDiscount,
|
|
29
31
|
extractDomainWithoutSuffix,
|
|
30
32
|
genProductSlug,
|
|
@@ -32,7 +34,7 @@ import {
|
|
|
32
34
|
normalizeKey,
|
|
33
35
|
safeParseDate,
|
|
34
36
|
sanitizeDomain
|
|
35
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-YIDIKN7A.mjs";
|
|
36
38
|
|
|
37
39
|
// src/ai/determine-store-type.ts
|
|
38
40
|
async function determineStoreTypeForStore(args) {
|
|
@@ -193,6 +195,7 @@ function mapProductsDto(products, ctx, options) {
|
|
|
193
195
|
optionNames,
|
|
194
196
|
product.variants
|
|
195
197
|
);
|
|
198
|
+
const variantPriceMap = buildVariantPriceMap(optionNames, product.variants);
|
|
196
199
|
const mappedVariants = mapVariants(product);
|
|
197
200
|
const priceValues = mappedVariants.map((v) => v.price).filter((p) => typeof p === "number" && !Number.isNaN(p));
|
|
198
201
|
const compareAtValues = mappedVariants.map((v) => v.compareAtPrice || 0).filter((p) => typeof p === "number" && !Number.isNaN(p));
|
|
@@ -255,6 +258,7 @@ function mapProductsDto(products, ctx, options) {
|
|
|
255
258
|
compareAtPriceFormatted: ctx.formatPrice(compareAtMin)
|
|
256
259
|
},
|
|
257
260
|
variantOptionsMap,
|
|
261
|
+
variantPriceMap,
|
|
258
262
|
url,
|
|
259
263
|
slug,
|
|
260
264
|
platformId: product.id.toString()
|
|
@@ -289,6 +293,7 @@ function mapProductsDto(products, ctx, options) {
|
|
|
289
293
|
compareAtPriceFormatted: ctx.formatPrice(compareAtMin)
|
|
290
294
|
},
|
|
291
295
|
variantOptionsMap,
|
|
296
|
+
variantPriceMap,
|
|
292
297
|
bodyHtml: product.body_html || null,
|
|
293
298
|
active: true,
|
|
294
299
|
productType: product.product_type || null,
|
|
@@ -329,6 +334,7 @@ function mapProductDto(product, ctx, options) {
|
|
|
329
334
|
optionNames,
|
|
330
335
|
product.variants
|
|
331
336
|
);
|
|
337
|
+
const variantPriceMap = buildVariantPriceMap(optionNames, product.variants);
|
|
332
338
|
const slug = genProductSlug({
|
|
333
339
|
handle: product.handle,
|
|
334
340
|
storeDomain: ctx.storeDomain
|
|
@@ -385,6 +391,7 @@ function mapProductDto(product, ctx, options) {
|
|
|
385
391
|
compareAtPriceFormatted: ctx.formatPrice(product.compare_at_price || 0)
|
|
386
392
|
},
|
|
387
393
|
variantOptionsMap,
|
|
394
|
+
variantPriceMap,
|
|
388
395
|
url,
|
|
389
396
|
slug,
|
|
390
397
|
platformId: product.id.toString()
|
|
@@ -419,6 +426,7 @@ function mapProductDto(product, ctx, options) {
|
|
|
419
426
|
compareAtPriceFormatted: ctx.formatPrice(product.compare_at_price || 0)
|
|
420
427
|
},
|
|
421
428
|
variantOptionsMap,
|
|
429
|
+
variantPriceMap,
|
|
422
430
|
bodyHtml: product.description || null,
|
|
423
431
|
active: true,
|
|
424
432
|
productType: product.type || null,
|
|
@@ -608,7 +616,9 @@ var ShopClient = class {
|
|
|
608
616
|
normalizeImageUrl: (url) => this.normalizeImageUrl(url),
|
|
609
617
|
formatPrice: (amount) => this.formatPrice(amount)
|
|
610
618
|
},
|
|
611
|
-
{
|
|
619
|
+
{
|
|
620
|
+
columns: (_b = options == null ? void 0 : options.columns) != null ? _b : this.productColumns
|
|
621
|
+
}
|
|
612
622
|
);
|
|
613
623
|
}
|
|
614
624
|
productDto(product, options) {
|
|
@@ -622,7 +632,9 @@ var ShopClient = class {
|
|
|
622
632
|
normalizeImageUrl: (url) => this.normalizeImageUrl(url),
|
|
623
633
|
formatPrice: (amount) => this.formatPrice(amount)
|
|
624
634
|
},
|
|
625
|
-
{
|
|
635
|
+
{
|
|
636
|
+
columns: (_b = options == null ? void 0 : options.columns) != null ? _b : this.productColumns
|
|
637
|
+
}
|
|
626
638
|
);
|
|
627
639
|
}
|
|
628
640
|
collectionsDto(collections) {
|
|
@@ -678,7 +690,11 @@ var ShopClient = class {
|
|
|
678
690
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
679
691
|
}
|
|
680
692
|
const data = await response.json();
|
|
681
|
-
|
|
693
|
+
const rawProducts = Array.isArray(data.products) ? data.products : [];
|
|
694
|
+
const filteredRawProducts = rawProducts.filter(
|
|
695
|
+
(p) => !this.isGiftCardProductType(p.product_type)
|
|
696
|
+
);
|
|
697
|
+
return this.productsDto(filteredRawProducts, {
|
|
682
698
|
columns: (_a = options == null ? void 0 : options.columns) != null ? _a : this.productColumns
|
|
683
699
|
});
|
|
684
700
|
} catch (error) {
|
|
@@ -749,7 +765,11 @@ var ShopClient = class {
|
|
|
749
765
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
750
766
|
}
|
|
751
767
|
const data = await response.json();
|
|
752
|
-
|
|
768
|
+
const rawProducts = Array.isArray(data.products) ? data.products : [];
|
|
769
|
+
const filteredRawProducts = rawProducts.filter(
|
|
770
|
+
(p) => !this.isGiftCardProductType(p.product_type)
|
|
771
|
+
);
|
|
772
|
+
return this.productsDto(filteredRawProducts, {
|
|
753
773
|
columns: (_a = options == null ? void 0 : options.columns) != null ? _a : this.productColumns
|
|
754
774
|
});
|
|
755
775
|
} catch (error) {
|
|
@@ -760,6 +780,13 @@ var ShopClient = class {
|
|
|
760
780
|
);
|
|
761
781
|
}
|
|
762
782
|
}
|
|
783
|
+
isGiftCardProductType(value) {
|
|
784
|
+
if (typeof value !== "string") return false;
|
|
785
|
+
const s = value.trim().toLowerCase();
|
|
786
|
+
if (!s) return false;
|
|
787
|
+
if (s === "gift card" || s === "giftcard") return true;
|
|
788
|
+
return s.includes("gift card") || s.includes("giftcard");
|
|
789
|
+
}
|
|
763
790
|
/**
|
|
764
791
|
* Validate if a product exists (with caching)
|
|
765
792
|
*/
|
|
@@ -1009,6 +1036,7 @@ var ShopClient = class {
|
|
|
1009
1036
|
};
|
|
1010
1037
|
export {
|
|
1011
1038
|
ShopClient,
|
|
1039
|
+
buildVariantKey,
|
|
1012
1040
|
calculateDiscount,
|
|
1013
1041
|
classifyProduct,
|
|
1014
1042
|
configureRateLimit,
|
package/dist/products.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ShopInfo } from './store.js';
|
|
2
|
-
import {
|
|
2
|
+
import { a as ProductColumnsMode, b as ProductImagesMode, c as ProductOptionsMode, k as CurrencyCode, P as ProductColumnsConfig, d as ProductResult, E as EnhancedProductResponse, l as Product, q as ProductClassification, r as SEOContent, S as ShopifyProduct, e as ShopifySingleProduct, O as OpenRouterConfig } from './types-CpduFbl-.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Interface for product operations
|
|
@@ -8,26 +8,26 @@ interface ProductOperations {
|
|
|
8
8
|
/**
|
|
9
9
|
* Fetches all products from the store across all pages.
|
|
10
10
|
*/
|
|
11
|
-
all(options?: {
|
|
11
|
+
all<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(options?: {
|
|
12
12
|
currency?: CurrencyCode;
|
|
13
|
-
columns?: ProductColumnsConfig
|
|
14
|
-
}): Promise<ProductResult[] | null>;
|
|
13
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
14
|
+
}): Promise<ProductResult<C, I, O>[] | null>;
|
|
15
15
|
/**
|
|
16
16
|
* Fetches products with pagination support.
|
|
17
17
|
*/
|
|
18
|
-
paginated(options?: {
|
|
18
|
+
paginated<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(options?: {
|
|
19
19
|
page?: number;
|
|
20
20
|
limit?: number;
|
|
21
21
|
currency?: CurrencyCode;
|
|
22
|
-
columns?: ProductColumnsConfig
|
|
23
|
-
}): Promise<ProductResult[] | null>;
|
|
22
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
23
|
+
}): Promise<ProductResult<C, I, O>[] | null>;
|
|
24
24
|
/**
|
|
25
25
|
* Finds a specific product by its handle.
|
|
26
26
|
*/
|
|
27
|
-
find(productHandle: string, options?: {
|
|
27
|
+
find<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(productHandle: string, options?: {
|
|
28
28
|
currency?: CurrencyCode;
|
|
29
|
-
columns?: ProductColumnsConfig
|
|
30
|
-
}): Promise<ProductResult | null>;
|
|
29
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
30
|
+
}): Promise<ProductResult<C, I, O> | null>;
|
|
31
31
|
/**
|
|
32
32
|
* Finds a product and enhances it with AI-generated content using an external service.
|
|
33
33
|
*
|
|
@@ -37,12 +37,12 @@ interface ProductOperations {
|
|
|
37
37
|
* @param options.updatedAt - Optional product updatedAt timestamp used to cache-bust/invalidate enrichment.
|
|
38
38
|
* @param options.endpoint - Optional custom endpoint URL for the enhancement service. Defaults to the standard worker URL.
|
|
39
39
|
*/
|
|
40
|
-
findEnhanced(productHandle: string, options: {
|
|
40
|
+
findEnhanced<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(productHandle: string, options: {
|
|
41
41
|
apiKey: string;
|
|
42
42
|
updatedAt?: string;
|
|
43
43
|
endpoint?: string;
|
|
44
|
-
columns?: ProductColumnsConfig
|
|
45
|
-
}): Promise<EnhancedProductResponse<ProductResult
|
|
44
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
45
|
+
}): Promise<EnhancedProductResponse<ProductResult<C, I, O>> | null>;
|
|
46
46
|
/**
|
|
47
47
|
* Finds a product by handle and enriches its content using LLM.
|
|
48
48
|
* Requires an OpenRouter API key via options.apiKey or ShopClient options.
|
|
@@ -93,9 +93,9 @@ interface ProductOperations {
|
|
|
93
93
|
/**
|
|
94
94
|
* Fetches products that are showcased/featured on the store's homepage.
|
|
95
95
|
*/
|
|
96
|
-
showcased(options?: {
|
|
97
|
-
columns?: ProductColumnsConfig
|
|
98
|
-
}): Promise<ProductResult[]>;
|
|
96
|
+
showcased<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(options?: {
|
|
97
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
98
|
+
}): Promise<ProductResult<C, I, O>[]>;
|
|
99
99
|
/**
|
|
100
100
|
* Creates a filter map of variant options and their distinct values from all products.
|
|
101
101
|
*/
|
|
@@ -103,36 +103,36 @@ interface ProductOperations {
|
|
|
103
103
|
/**
|
|
104
104
|
* Predictive product search using Shopify Ajax API.
|
|
105
105
|
*/
|
|
106
|
-
predictiveSearch(query: string, options?: {
|
|
106
|
+
predictiveSearch<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(query: string, options?: {
|
|
107
107
|
limit?: number;
|
|
108
108
|
locale?: string;
|
|
109
109
|
currency?: CurrencyCode;
|
|
110
110
|
unavailableProducts?: "show" | "hide" | "last";
|
|
111
|
-
columns?: ProductColumnsConfig
|
|
112
|
-
}): Promise<ProductResult[]>;
|
|
111
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
112
|
+
}): Promise<ProductResult<C, I, O>[]>;
|
|
113
113
|
/**
|
|
114
114
|
* Product recommendations for a given product ID using Shopify Ajax API.
|
|
115
115
|
*/
|
|
116
|
-
recommendations(productId: number, options?: {
|
|
116
|
+
recommendations<C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(productId: number, options?: {
|
|
117
117
|
limit?: number;
|
|
118
118
|
intent?: "related" | "complementary";
|
|
119
119
|
locale?: string;
|
|
120
120
|
currency?: CurrencyCode;
|
|
121
|
-
columns?: ProductColumnsConfig
|
|
122
|
-
}): Promise<ProductResult[] | null>;
|
|
121
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
122
|
+
}): Promise<ProductResult<C, I, O>[] | null>;
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
125
|
* Creates product operations for a store instance
|
|
126
126
|
*/
|
|
127
|
-
declare function createProductOperations(baseUrl: string, storeDomain: string, fetchProducts: (page: number, limit: number, options?: {
|
|
128
|
-
columns?: ProductColumnsConfig
|
|
129
|
-
}) => Promise<ProductResult[] | null>, productsDto: (products: ShopifyProduct[], options?: {
|
|
130
|
-
columns?: ProductColumnsConfig
|
|
131
|
-
}) => ProductResult[] | null, productDto: (product: ShopifySingleProduct, options?: {
|
|
132
|
-
columns?: ProductColumnsConfig
|
|
133
|
-
}) => ProductResult, getStoreInfo: () => Promise<ShopInfo>, _findProduct: (handle: string, options?: {
|
|
134
|
-
columns?: ProductColumnsConfig
|
|
135
|
-
}) => Promise<ProductResult | null>, getDefaultProductColumns: () => ProductColumnsConfig, ai?: {
|
|
127
|
+
declare function createProductOperations(baseUrl: string, storeDomain: string, fetchProducts: <C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(page: number, limit: number, options?: {
|
|
128
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
129
|
+
}) => Promise<ProductResult<C, I, O>[] | null>, productsDto: <C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(products: ShopifyProduct[], options?: {
|
|
130
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
131
|
+
}) => ProductResult<C, I, O>[] | null, productDto: <C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(product: ShopifySingleProduct, options?: {
|
|
132
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
133
|
+
}) => ProductResult<C, I, O>, getStoreInfo: () => Promise<ShopInfo>, _findProduct: <C extends ProductColumnsMode = "minimal", I extends ProductImagesMode = "minimal", O extends ProductOptionsMode = "minimal">(handle: string, options?: {
|
|
134
|
+
columns?: ProductColumnsConfig<C, I, O>;
|
|
135
|
+
}) => Promise<ProductResult<C, I, O> | null>, getDefaultProductColumns: () => ProductColumnsConfig, ai?: {
|
|
136
136
|
openRouter?: OpenRouterConfig;
|
|
137
137
|
}): ProductOperations;
|
|
138
138
|
|
package/dist/products.mjs
CHANGED
package/dist/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as JsonLdEntry,
|
|
1
|
+
import { J as JsonLdEntry, i as CountryDetectionResult, k as CurrencyCode } from './types-CpduFbl-.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Store operations interface for managing store-related functionality.
|
package/dist/store.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createShopOperations
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-X5KZU6K4.mjs";
|
|
4
4
|
import "./chunk-4GPP2KXF.mjs";
|
|
5
5
|
import "./chunk-SBHTEKLB.mjs";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-YIDIKN7A.mjs";
|
|
7
7
|
export {
|
|
8
8
|
createShopOperations
|
|
9
9
|
};
|
|
@@ -321,6 +321,7 @@ type Product = {
|
|
|
321
321
|
requiresSellingPlan?: boolean | null;
|
|
322
322
|
sellingPlanGroups?: unknown;
|
|
323
323
|
variantOptionsMap: Record<string, string>;
|
|
324
|
+
variantPriceMap: Record<string, number>;
|
|
324
325
|
enriched_content?: string;
|
|
325
326
|
};
|
|
326
327
|
/**
|
|
@@ -345,6 +346,7 @@ type MinimalProduct = {
|
|
|
345
346
|
values: string[];
|
|
346
347
|
}[];
|
|
347
348
|
variantOptionsMap: Record<string, string>;
|
|
349
|
+
variantPriceMap: Record<string, number>;
|
|
348
350
|
url: string;
|
|
349
351
|
slug: string;
|
|
350
352
|
platformId: string;
|
|
@@ -519,4 +521,4 @@ type EnhancedProductResponse<TProduct = Product> = {
|
|
|
519
521
|
};
|
|
520
522
|
type StoreTypeBreakdown = Partial<Record<"adult_male" | "adult_female" | "kid_male" | "kid_female" | "generic", Partial<Record<"clothing" | "beauty" | "accessories" | "home-decor" | "food-and-beverages", string[]>>>>;
|
|
521
523
|
|
|
522
|
-
export type { CollectionColumnsConfig as C, EnhancedProductResponse as E, JsonLdEntry as J, LocalizedPricing as L, MetaTag as M, OpenRouterConfig as O, ProductColumnsConfig as P, ShopifyProduct as S,
|
|
524
|
+
export type { CollectionColumnsConfig as C, EnhancedProductResponse as E, JsonLdEntry as J, LocalizedPricing as L, MetaTag as M, OpenRouterConfig as O, ProductColumnsConfig as P, ShopifyProduct as S, ProductColumnsMode as a, ProductImagesMode as b, ProductOptionsMode as c, ProductResult as d, ShopifySingleProduct as e, ShopifyCollection as f, Collection as g, StoreTypeBreakdown as h, CountryDetectionResult as i, CountryScores as j, CurrencyCode as k, Product as l, ProductImage as m, ProductOption as n, ProductVariant as o, ProductVariantImage as p, ProductClassification as q, SEOContent as r, SystemUserPrompt as s };
|
package/dist/utils/func.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as CurrencyCode } from '../types-CpduFbl-.js';
|
|
2
2
|
|
|
3
3
|
declare function extractDomainWithoutSuffix(domain: string): string | null;
|
|
4
4
|
declare function generateStoreSlug(domain: string): string;
|
|
@@ -43,6 +43,13 @@ declare function buildVariantOptionsMap(optionNames: string[], variants: Array<{
|
|
|
43
43
|
option2: string | null;
|
|
44
44
|
option3: string | null;
|
|
45
45
|
}>): Record<string, string>;
|
|
46
|
+
declare function buildVariantPriceMap(optionNames: string[], variants: Array<{
|
|
47
|
+
id: number;
|
|
48
|
+
option1: string | null;
|
|
49
|
+
option2: string | null;
|
|
50
|
+
option3: string | null;
|
|
51
|
+
price: string | number;
|
|
52
|
+
}>): Record<string, number>;
|
|
46
53
|
/**
|
|
47
54
|
* Build a normalized variant key string from an object of option name → value.
|
|
48
55
|
* - Normalizes both names and values using `normalizeKey`
|
|
@@ -58,4 +65,4 @@ declare function buildVariantKey(obj: Record<string, string | null | undefined>)
|
|
|
58
65
|
*/
|
|
59
66
|
declare function formatPrice(amountInCents: number, currency: CurrencyCode): string;
|
|
60
67
|
|
|
61
|
-
export { buildVariantKey, buildVariantOptionsMap, calculateDiscount, extractDomainWithoutSuffix, formatPrice, genProductSlug, generateStoreSlug, normalizeKey, safeParseDate, sanitizeDomain };
|
|
68
|
+
export { buildVariantKey, buildVariantOptionsMap, buildVariantPriceMap, calculateDiscount, extractDomainWithoutSuffix, formatPrice, genProductSlug, generateStoreSlug, normalizeKey, safeParseDate, sanitizeDomain };
|
package/dist/utils/func.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildVariantKey,
|
|
3
3
|
buildVariantOptionsMap,
|
|
4
|
+
buildVariantPriceMap,
|
|
4
5
|
calculateDiscount,
|
|
5
6
|
extractDomainWithoutSuffix,
|
|
6
7
|
formatPrice,
|
|
@@ -9,10 +10,11 @@ import {
|
|
|
9
10
|
normalizeKey,
|
|
10
11
|
safeParseDate,
|
|
11
12
|
sanitizeDomain
|
|
12
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-YIDIKN7A.mjs";
|
|
13
14
|
export {
|
|
14
15
|
buildVariantKey,
|
|
15
16
|
buildVariantOptionsMap,
|
|
17
|
+
buildVariantPriceMap,
|
|
16
18
|
calculateDiscount,
|
|
17
19
|
extractDomainWithoutSuffix,
|
|
18
20
|
formatPrice,
|