shop-client 3.16.0 → 3.18.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 +74 -7
- package/dist/ai/enrich.d.ts +1 -1
- package/dist/ai/enrich.mjs +2 -2
- package/dist/{chunk-QCB3U4AO.mjs → chunk-242GBM2V.mjs} +136 -14
- package/dist/{chunk-ZX4IG4TY.mjs → chunk-5TGMDRUF.mjs} +88 -44
- package/dist/chunk-6XDBGOFZ.mjs +804 -0
- package/dist/{chunk-D5MTUWFO.mjs → chunk-O77Z6OBJ.mjs} +21 -6
- package/dist/{chunk-G7OCMGA6.mjs → chunk-SBHTEKLB.mjs} +3 -1
- package/dist/{chunk-OA76XD32.mjs → chunk-YWAW6C74.mjs} +5 -5
- package/dist/collections.d.ts +16 -2
- package/dist/collections.mjs +2 -2
- package/dist/index.d.ts +8 -4
- package/dist/index.mjs +180 -79
- package/dist/products.d.ts +65 -2
- package/dist/products.mjs +2 -2
- package/dist/store.d.ts +1 -1
- package/dist/store.mjs +3 -3
- package/dist/{types-BRXamZMS.d.ts → types-B4WDm14E.d.ts} +58 -1
- package/dist/utils/detect-country.d.ts +1 -1
- package/dist/utils/detect-country.mjs +1 -1
- package/dist/utils/func.d.ts +1 -1
- package/dist/utils/rate-limit.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-THCO3JT4.mjs +0 -593
|
@@ -13,8 +13,12 @@ var RateLimiter = class {
|
|
|
13
13
|
this.tokens = this.options.maxRequestsPerInterval;
|
|
14
14
|
this.tryRun();
|
|
15
15
|
}, this.options.intervalMs);
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const t = this.refillTimer;
|
|
17
|
+
if (t && typeof t === "object") {
|
|
18
|
+
const rec = t;
|
|
19
|
+
if (typeof rec.unref === "function") {
|
|
20
|
+
rec.unref();
|
|
21
|
+
}
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
ensureRefillStarted() {
|
|
@@ -34,7 +38,11 @@ var RateLimiter = class {
|
|
|
34
38
|
schedule(fn) {
|
|
35
39
|
return new Promise((resolve, reject) => {
|
|
36
40
|
this.ensureRefillStarted();
|
|
37
|
-
this.queue.push({
|
|
41
|
+
this.queue.push({
|
|
42
|
+
fn,
|
|
43
|
+
resolve,
|
|
44
|
+
reject
|
|
45
|
+
});
|
|
38
46
|
this.tryRun();
|
|
39
47
|
});
|
|
40
48
|
}
|
|
@@ -70,7 +78,8 @@ function getHost(input) {
|
|
|
70
78
|
if (input instanceof URL) {
|
|
71
79
|
return input.host;
|
|
72
80
|
}
|
|
73
|
-
const
|
|
81
|
+
const rec = input;
|
|
82
|
+
const url = typeof rec.url === "string" ? rec.url : void 0;
|
|
74
83
|
if (url) {
|
|
75
84
|
return new URL(url).host;
|
|
76
85
|
}
|
|
@@ -162,6 +171,12 @@ async function rateLimitedFetch(input, init) {
|
|
|
162
171
|
...init,
|
|
163
172
|
signal: hasSignal ? init == null ? void 0 : init.signal : controller == null ? void 0 : controller.signal
|
|
164
173
|
};
|
|
174
|
+
const {
|
|
175
|
+
rateLimitClass: _klass,
|
|
176
|
+
retry: _retry,
|
|
177
|
+
timeoutMs: _timeoutMs,
|
|
178
|
+
...fetchInit
|
|
179
|
+
} = effInit;
|
|
165
180
|
const klass = init == null ? void 0 : init.rateLimitClass;
|
|
166
181
|
const byClass = klass ? classLimiters.get(klass) : void 0;
|
|
167
182
|
const byHost = getHostLimiter(getHost(input));
|
|
@@ -175,9 +190,9 @@ async function rateLimitedFetch(input, init) {
|
|
|
175
190
|
while (attempt <= maxRetries) {
|
|
176
191
|
try {
|
|
177
192
|
if (eff) {
|
|
178
|
-
response = await eff.schedule(() => fetch(input,
|
|
193
|
+
response = await eff.schedule(() => fetch(input, fetchInit));
|
|
179
194
|
} else {
|
|
180
|
-
response = await fetch(input,
|
|
195
|
+
response = await fetch(input, fetchInit);
|
|
181
196
|
}
|
|
182
197
|
if (!response || response.ok || !retryOnStatuses.includes(response.status)) {
|
|
183
198
|
if (timer) clearTimeout(timer);
|
|
@@ -93,7 +93,9 @@ async function detectShopCountry(html) {
|
|
|
93
93
|
try {
|
|
94
94
|
const raw = currencyJsonMatch[1];
|
|
95
95
|
const obj = JSON.parse(raw || "{}");
|
|
96
|
-
const
|
|
96
|
+
const rec = obj && typeof obj === "object" ? obj : null;
|
|
97
|
+
const active = rec && typeof rec.active === "string" ? rec.active : void 0;
|
|
98
|
+
const activeCode = active ? active.toUpperCase() : void 0;
|
|
97
99
|
const iso = activeCode ? CURRENCY_CODE_TO_COUNTRY[activeCode] : void 0;
|
|
98
100
|
if (activeCode) {
|
|
99
101
|
detectedCurrencyCode = activeCode;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rateLimitedFetch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-O77Z6OBJ.mjs";
|
|
4
4
|
import {
|
|
5
5
|
detectShopCountry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SBHTEKLB.mjs";
|
|
7
7
|
import {
|
|
8
8
|
extractDomainWithoutSuffix,
|
|
9
9
|
generateStoreSlug,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
// src/client/get-info.ts
|
|
14
14
|
import { unique } from "remeda";
|
|
15
15
|
async function getInfoForShop(args, options) {
|
|
16
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
16
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
17
17
|
const {
|
|
18
18
|
baseUrl,
|
|
19
19
|
storeDomain,
|
|
@@ -212,9 +212,9 @@ async function getInfoForShop(args, options) {
|
|
|
212
212
|
subDomain: myShopifySubdomain != null ? myShopifySubdomain : null
|
|
213
213
|
},
|
|
214
214
|
country: countryDetection.country,
|
|
215
|
-
currency: (countryDetection
|
|
215
|
+
currency: (_q = countryDetection.currencyCode) != null ? _q : null
|
|
216
216
|
};
|
|
217
|
-
const currencyCode = countryDetection
|
|
217
|
+
const currencyCode = countryDetection.currencyCode;
|
|
218
218
|
return { info, currencyCode };
|
|
219
219
|
}
|
|
220
220
|
|
package/dist/collections.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ShopInfo } from './store.js';
|
|
2
|
-
import { C as Collection, f as CurrencyCode, P as Product, b as ShopifyCollection } from './types-
|
|
2
|
+
import { C as Collection, f as CurrencyCode, P as Product, M as MinimalProduct, b as ShopifyCollection } from './types-B4WDm14E.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Interface for collection operations
|
|
@@ -52,6 +52,19 @@ interface CollectionOperations {
|
|
|
52
52
|
* Fetches all product slugs from a specific collection.
|
|
53
53
|
*/
|
|
54
54
|
slugs(collectionHandle: string): Promise<string[] | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Convenience minimal namespace to always return MinimalProduct types.
|
|
57
|
+
*/
|
|
58
|
+
minimal: {
|
|
59
|
+
paginated(collectionHandle: string, options?: {
|
|
60
|
+
page?: number;
|
|
61
|
+
limit?: number;
|
|
62
|
+
currency?: CurrencyCode;
|
|
63
|
+
}): Promise<MinimalProduct[] | null>;
|
|
64
|
+
all(collectionHandle: string, options?: {
|
|
65
|
+
currency?: CurrencyCode;
|
|
66
|
+
}): Promise<MinimalProduct[] | null>;
|
|
67
|
+
};
|
|
55
68
|
};
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
@@ -60,6 +73,7 @@ interface CollectionOperations {
|
|
|
60
73
|
declare function createCollectionOperations(baseUrl: string, storeDomain: string, fetchCollections: (page: number, limit: number) => Promise<Collection[] | null>, collectionsDto: (collections: ShopifyCollection[]) => Collection[], fetchPaginatedProductsFromCollection: (collectionHandle: string, options?: {
|
|
61
74
|
page?: number;
|
|
62
75
|
limit?: number;
|
|
63
|
-
|
|
76
|
+
minimal?: boolean;
|
|
77
|
+
}) => Promise<Product[] | MinimalProduct[] | null>, getStoreInfo: () => Promise<ShopInfo>, findCollection: (handle: string) => Promise<Collection | null>): CollectionOperations;
|
|
64
78
|
|
|
65
79
|
export { type CollectionOperations, createCollectionOperations };
|
package/dist/collections.mjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OpenRouterConfig, S as ShopifyProduct, P as Product, a as ShopifySingleProduct, b as ShopifyCollection, C as Collection, J as JsonLdEntry, c as StoreTypeBreakdown } from './types-
|
|
2
|
-
export { d as CountryDetectionResult, e as CountryScores, f as CurrencyCode, L as LocalizedPricing,
|
|
1
|
+
import { O as OpenRouterConfig, S as ShopifyProduct, P as Product, M as MinimalProduct, a as ShopifySingleProduct, b as ShopifyCollection, C as Collection, J as JsonLdEntry, c as StoreTypeBreakdown } from './types-B4WDm14E.js';
|
|
2
|
+
export { d as CountryDetectionResult, e as CountryScores, f as CurrencyCode, L as LocalizedPricing, g as MetaTag, h as ProductImage, i as ProductOption, j as ProductVariant, k as ProductVariantImage } from './types-B4WDm14E.js';
|
|
3
3
|
import { CheckoutOperations } from './checkout.js';
|
|
4
4
|
import { CollectionOperations } from './collections.js';
|
|
5
5
|
import { ProductOperations } from './products.js';
|
|
@@ -81,8 +81,12 @@ declare class ShopClient {
|
|
|
81
81
|
/**
|
|
82
82
|
* Transform Shopify products to our Product format
|
|
83
83
|
*/
|
|
84
|
-
productsDto(products: ShopifyProduct[]
|
|
85
|
-
|
|
84
|
+
productsDto(products: ShopifyProduct[], options?: {
|
|
85
|
+
minimal?: boolean;
|
|
86
|
+
}): Product[] | MinimalProduct[] | null;
|
|
87
|
+
productDto(product: ShopifySingleProduct, options?: {
|
|
88
|
+
minimal?: boolean;
|
|
89
|
+
}): Product | MinimalProduct;
|
|
86
90
|
collectionsDto(collections: ShopifyCollection[]): Collection[];
|
|
87
91
|
/**
|
|
88
92
|
* Enhanced error handling with context
|
package/dist/index.mjs
CHANGED
|
@@ -3,26 +3,26 @@ import {
|
|
|
3
3
|
} from "./chunk-W4SF6W2P.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createCollectionOperations
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-242GBM2V.mjs";
|
|
7
7
|
import {
|
|
8
8
|
createProductOperations
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6XDBGOFZ.mjs";
|
|
10
10
|
import {
|
|
11
11
|
createShopOperations,
|
|
12
12
|
getInfoForShop
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YWAW6C74.mjs";
|
|
14
14
|
import {
|
|
15
15
|
classifyProduct,
|
|
16
16
|
determineStoreType,
|
|
17
17
|
generateSEOContent
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5TGMDRUF.mjs";
|
|
19
19
|
import {
|
|
20
20
|
configureRateLimit,
|
|
21
21
|
rateLimitedFetch
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-O77Z6OBJ.mjs";
|
|
23
23
|
import {
|
|
24
24
|
detectShopCountry
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-SBHTEKLB.mjs";
|
|
26
26
|
import {
|
|
27
27
|
buildVariantOptionsMap,
|
|
28
28
|
calculateDiscount,
|
|
@@ -83,51 +83,64 @@ function collectionsDto(collections) {
|
|
|
83
83
|
// src/dto/products.mapped.ts
|
|
84
84
|
function mapVariants(product) {
|
|
85
85
|
var _a;
|
|
86
|
+
const toCents = (value) => {
|
|
87
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
const n = Number.parseFloat(value);
|
|
90
|
+
return Number.isFinite(n) ? Math.round(n * 100) : 0;
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
};
|
|
86
94
|
const variants = (_a = product.variants) != null ? _a : [];
|
|
87
95
|
return variants.map((variant) => {
|
|
88
|
-
var _a2;
|
|
96
|
+
var _a2, _b, _c;
|
|
97
|
+
const featuredImage = variant.featured_image ? {
|
|
98
|
+
id: variant.featured_image.id,
|
|
99
|
+
src: variant.featured_image.src,
|
|
100
|
+
width: variant.featured_image.width,
|
|
101
|
+
height: variant.featured_image.height,
|
|
102
|
+
position: variant.featured_image.position,
|
|
103
|
+
productId: variant.featured_image.product_id,
|
|
104
|
+
aspectRatio: (_a2 = variant.featured_image.aspect_ratio) != null ? _a2 : 0,
|
|
105
|
+
variantIds: (_b = variant.featured_image.variant_ids) != null ? _b : [],
|
|
106
|
+
createdAt: variant.featured_image.created_at,
|
|
107
|
+
updatedAt: variant.featured_image.updated_at,
|
|
108
|
+
alt: variant.featured_image.alt
|
|
109
|
+
} : null;
|
|
89
110
|
return {
|
|
90
111
|
id: variant.id.toString(),
|
|
91
112
|
platformId: variant.id.toString(),
|
|
92
|
-
name: variant.name,
|
|
113
|
+
name: "name" in variant ? variant.name : void 0,
|
|
93
114
|
title: variant.title,
|
|
94
115
|
option1: variant.option1 || null,
|
|
95
116
|
option2: variant.option2 || null,
|
|
96
117
|
option3: variant.option3 || null,
|
|
97
118
|
options: [variant.option1, variant.option2, variant.option3].filter(
|
|
98
|
-
Boolean
|
|
119
|
+
(v) => Boolean(v)
|
|
99
120
|
),
|
|
100
121
|
sku: variant.sku || null,
|
|
101
122
|
requiresShipping: variant.requires_shipping,
|
|
102
123
|
taxable: variant.taxable,
|
|
103
|
-
featuredImage
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
position: variant.featured_image.position,
|
|
109
|
-
productId: variant.featured_image.product_id,
|
|
110
|
-
aspectRatio: variant.featured_image.aspect_ratio || 0,
|
|
111
|
-
variantIds: variant.featured_image.variant_ids || [],
|
|
112
|
-
createdAt: variant.featured_image.created_at,
|
|
113
|
-
updatedAt: variant.featured_image.updated_at,
|
|
114
|
-
alt: variant.featured_image.alt
|
|
115
|
-
} : null,
|
|
116
|
-
available: Boolean(variant.available),
|
|
117
|
-
price: typeof variant.price === "string" ? Number.parseFloat(variant.price) * 100 : variant.price,
|
|
118
|
-
weightInGrams: (_a2 = variant.weightInGrams) != null ? _a2 : variant.grams,
|
|
119
|
-
compareAtPrice: variant.compare_at_price ? typeof variant.compare_at_price === "string" ? Number.parseFloat(variant.compare_at_price) * 100 : variant.compare_at_price : 0,
|
|
124
|
+
featuredImage,
|
|
125
|
+
available: typeof variant.available === "boolean" ? variant.available : true,
|
|
126
|
+
price: toCents(variant.price),
|
|
127
|
+
weightInGrams: "weightInGrams" in variant ? variant.weightInGrams : (_c = variant.grams) != null ? _c : void 0,
|
|
128
|
+
compareAtPrice: toCents(variant.compare_at_price),
|
|
120
129
|
position: variant.position,
|
|
121
130
|
productId: variant.product_id,
|
|
122
131
|
createdAt: variant.created_at,
|
|
123
|
-
updatedAt: variant.updated_at
|
|
132
|
+
updatedAt: variant.updated_at,
|
|
133
|
+
compareAtPriceVaries: false,
|
|
134
|
+
priceVaries: false
|
|
124
135
|
};
|
|
125
136
|
});
|
|
126
137
|
}
|
|
127
|
-
function mapProductsDto(products, ctx) {
|
|
138
|
+
function mapProductsDto(products, ctx, options) {
|
|
139
|
+
var _a;
|
|
128
140
|
if (!products || products.length === 0) return null;
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
const isMinimal = (_a = options == null ? void 0 : options.minimal) != null ? _a : true;
|
|
142
|
+
const mapOne = (product) => {
|
|
143
|
+
var _a2, _b, _c, _d, _e;
|
|
131
144
|
const optionNames = product.options.map((o) => o.name);
|
|
132
145
|
const variantOptionsMap = buildVariantOptionsMap(
|
|
133
146
|
optionNames,
|
|
@@ -142,11 +155,42 @@ function mapProductsDto(products, ctx) {
|
|
|
142
155
|
const compareAtMin = compareAtValues.length ? Math.min(...compareAtValues) : 0;
|
|
143
156
|
const compareAtMax = compareAtValues.length ? Math.max(...compareAtValues) : 0;
|
|
144
157
|
const compareAtVaries = mappedVariants.length > 1 && compareAtMin !== compareAtMax;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
158
|
+
const slug = genProductSlug({
|
|
159
|
+
handle: product.handle,
|
|
160
|
+
storeDomain: ctx.storeDomain
|
|
161
|
+
});
|
|
162
|
+
const url = `${ctx.storeDomain}/products/${product.handle}`;
|
|
163
|
+
const discount = calculateDiscount(priceMin, compareAtMin);
|
|
164
|
+
if (isMinimal) {
|
|
165
|
+
const minimal = {
|
|
166
|
+
title: product.title,
|
|
167
|
+
bodyHtml: product.body_html || null,
|
|
168
|
+
price: priceMin,
|
|
169
|
+
compareAtPrice: compareAtMin,
|
|
170
|
+
discount,
|
|
171
|
+
images: product.images.map((img) => ({
|
|
172
|
+
src: ctx.normalizeImageUrl(img.src)
|
|
173
|
+
})),
|
|
174
|
+
featuredImage: ((_b = (_a2 = product.images) == null ? void 0 : _a2[0]) == null ? void 0 : _b.src) ? ctx.normalizeImageUrl(product.images[0].src) : null,
|
|
175
|
+
available: mappedVariants.some((v) => v.available),
|
|
176
|
+
localizedPricing: {
|
|
177
|
+
priceFormatted: ctx.formatPrice(priceMin),
|
|
178
|
+
compareAtPriceFormatted: ctx.formatPrice(compareAtMin)
|
|
179
|
+
},
|
|
180
|
+
options: product.options.map((option) => ({
|
|
181
|
+
key: normalizeKey(option.name),
|
|
182
|
+
name: option.name,
|
|
183
|
+
values: option.values
|
|
184
|
+
})),
|
|
185
|
+
variantOptionsMap,
|
|
186
|
+
url,
|
|
187
|
+
slug,
|
|
188
|
+
platformId: product.id.toString()
|
|
189
|
+
};
|
|
190
|
+
return minimal;
|
|
191
|
+
}
|
|
192
|
+
const full = {
|
|
193
|
+
slug,
|
|
150
194
|
handle: product.handle,
|
|
151
195
|
platformId: product.id.toString(),
|
|
152
196
|
title: product.title,
|
|
@@ -159,7 +203,7 @@ function mapProductsDto(products, ctx) {
|
|
|
159
203
|
compareAtPriceMin: compareAtMin,
|
|
160
204
|
compareAtPriceMax: compareAtMax,
|
|
161
205
|
compareAtPriceVaries: compareAtVaries,
|
|
162
|
-
discount
|
|
206
|
+
discount,
|
|
163
207
|
currency: ctx.currency,
|
|
164
208
|
localizedPricing: {
|
|
165
209
|
currency: ctx.currency,
|
|
@@ -181,7 +225,7 @@ function mapProductsDto(products, ctx) {
|
|
|
181
225
|
productType: product.product_type || null,
|
|
182
226
|
tags: Array.isArray(product.tags) ? product.tags : [],
|
|
183
227
|
vendor: product.vendor,
|
|
184
|
-
featuredImage: ((
|
|
228
|
+
featuredImage: ((_d = (_c = product.images) == null ? void 0 : _c[0]) == null ? void 0 : _d.src) ? ctx.normalizeImageUrl(product.images[0].src) : null,
|
|
185
229
|
isProxyFeaturedImage: false,
|
|
186
230
|
createdAt: safeParseDate(product.created_at),
|
|
187
231
|
updatedAt: safeParseDate(product.updated_at),
|
|
@@ -199,29 +243,65 @@ function mapProductsDto(products, ctx) {
|
|
|
199
243
|
createdAt: image.created_at,
|
|
200
244
|
updatedAt: image.updated_at
|
|
201
245
|
})),
|
|
202
|
-
publishedAt: (
|
|
246
|
+
publishedAt: (_e = safeParseDate(product.published_at)) != null ? _e : null,
|
|
203
247
|
seo: null,
|
|
204
248
|
metaTags: null,
|
|
205
249
|
displayScore: void 0,
|
|
206
250
|
deletedAt: null,
|
|
207
251
|
storeSlug: ctx.storeSlug,
|
|
208
252
|
storeDomain: ctx.storeDomain,
|
|
209
|
-
url
|
|
253
|
+
url
|
|
210
254
|
};
|
|
211
|
-
|
|
255
|
+
return full;
|
|
256
|
+
};
|
|
257
|
+
return isMinimal ? products.map(mapOne) : products.map(mapOne);
|
|
212
258
|
}
|
|
213
|
-
function mapProductDto(product, ctx) {
|
|
214
|
-
var _a;
|
|
259
|
+
function mapProductDto(product, ctx, options) {
|
|
260
|
+
var _a, _b;
|
|
261
|
+
const isMinimal = (_a = options == null ? void 0 : options.minimal) != null ? _a : true;
|
|
215
262
|
const optionNames = product.options.map((o) => o.name);
|
|
216
263
|
const variantOptionsMap = buildVariantOptionsMap(
|
|
217
264
|
optionNames,
|
|
218
265
|
product.variants
|
|
219
266
|
);
|
|
267
|
+
const slug = genProductSlug({
|
|
268
|
+
handle: product.handle,
|
|
269
|
+
storeDomain: ctx.storeDomain
|
|
270
|
+
});
|
|
271
|
+
const url = product.url || `${ctx.storeDomain}/products/${product.handle}`;
|
|
272
|
+
const discount = calculateDiscount(
|
|
273
|
+
product.price,
|
|
274
|
+
product.compare_at_price || 0
|
|
275
|
+
);
|
|
276
|
+
if (isMinimal) {
|
|
277
|
+
return {
|
|
278
|
+
title: product.title,
|
|
279
|
+
bodyHtml: product.description || null,
|
|
280
|
+
price: product.price,
|
|
281
|
+
compareAtPrice: product.compare_at_price || 0,
|
|
282
|
+
discount,
|
|
283
|
+
images: Array.isArray(product.images) ? product.images.map((imageSrc) => ({
|
|
284
|
+
src: ctx.normalizeImageUrl(imageSrc)
|
|
285
|
+
})) : [],
|
|
286
|
+
featuredImage: ctx.normalizeImageUrl(product.featured_image),
|
|
287
|
+
available: product.available,
|
|
288
|
+
localizedPricing: {
|
|
289
|
+
priceFormatted: ctx.formatPrice(product.price),
|
|
290
|
+
compareAtPriceFormatted: ctx.formatPrice(product.compare_at_price || 0)
|
|
291
|
+
},
|
|
292
|
+
options: product.options.map((option) => ({
|
|
293
|
+
key: normalizeKey(option.name),
|
|
294
|
+
name: option.name,
|
|
295
|
+
values: option.values
|
|
296
|
+
})),
|
|
297
|
+
variantOptionsMap,
|
|
298
|
+
url,
|
|
299
|
+
slug,
|
|
300
|
+
platformId: product.id.toString()
|
|
301
|
+
};
|
|
302
|
+
}
|
|
220
303
|
const mapped = {
|
|
221
|
-
slug
|
|
222
|
-
handle: product.handle,
|
|
223
|
-
storeDomain: ctx.storeDomain
|
|
224
|
-
}),
|
|
304
|
+
slug,
|
|
225
305
|
handle: product.handle,
|
|
226
306
|
platformId: product.id.toString(),
|
|
227
307
|
title: product.title,
|
|
@@ -234,7 +314,7 @@ function mapProductDto(product, ctx) {
|
|
|
234
314
|
compareAtPriceMin: product.compare_at_price_min,
|
|
235
315
|
compareAtPriceMax: product.compare_at_price_max,
|
|
236
316
|
compareAtPriceVaries: product.compare_at_price_varies,
|
|
237
|
-
discount
|
|
317
|
+
discount,
|
|
238
318
|
currency: ctx.currency,
|
|
239
319
|
localizedPricing: {
|
|
240
320
|
currency: ctx.currency,
|
|
@@ -274,14 +354,14 @@ function mapProductDto(product, ctx) {
|
|
|
274
354
|
createdAt: product.created_at,
|
|
275
355
|
updatedAt: product.updated_at
|
|
276
356
|
})) : [],
|
|
277
|
-
publishedAt: (
|
|
357
|
+
publishedAt: (_b = safeParseDate(product.published_at)) != null ? _b : null,
|
|
278
358
|
seo: null,
|
|
279
359
|
metaTags: null,
|
|
280
360
|
displayScore: void 0,
|
|
281
361
|
deletedAt: null,
|
|
282
362
|
storeSlug: ctx.storeSlug,
|
|
283
363
|
storeDomain: ctx.storeDomain,
|
|
284
|
-
url
|
|
364
|
+
url
|
|
285
365
|
};
|
|
286
366
|
return mapped;
|
|
287
367
|
}
|
|
@@ -416,25 +496,33 @@ var ShopClient = class {
|
|
|
416
496
|
/**
|
|
417
497
|
* Transform Shopify products to our Product format
|
|
418
498
|
*/
|
|
419
|
-
productsDto(products) {
|
|
420
|
-
var _a;
|
|
421
|
-
return mapProductsDto(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
499
|
+
productsDto(products, options) {
|
|
500
|
+
var _a, _b;
|
|
501
|
+
return mapProductsDto(
|
|
502
|
+
products,
|
|
503
|
+
{
|
|
504
|
+
storeDomain: this.storeDomain,
|
|
505
|
+
storeSlug: this.storeSlug,
|
|
506
|
+
currency: (_a = this.storeCurrency) != null ? _a : "USD",
|
|
507
|
+
normalizeImageUrl: (url) => this.normalizeImageUrl(url),
|
|
508
|
+
formatPrice: (amount) => this.formatPrice(amount)
|
|
509
|
+
},
|
|
510
|
+
{ minimal: (_b = options == null ? void 0 : options.minimal) != null ? _b : false }
|
|
511
|
+
);
|
|
428
512
|
}
|
|
429
|
-
productDto(product) {
|
|
430
|
-
var _a;
|
|
431
|
-
return mapProductDto(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
513
|
+
productDto(product, options) {
|
|
514
|
+
var _a, _b;
|
|
515
|
+
return mapProductDto(
|
|
516
|
+
product,
|
|
517
|
+
{
|
|
518
|
+
storeDomain: this.storeDomain,
|
|
519
|
+
storeSlug: this.storeSlug,
|
|
520
|
+
currency: (_a = this.storeCurrency) != null ? _a : "USD",
|
|
521
|
+
normalizeImageUrl: (url) => this.normalizeImageUrl(url),
|
|
522
|
+
formatPrice: (amount) => this.formatPrice(amount)
|
|
523
|
+
},
|
|
524
|
+
{ minimal: (_b = options == null ? void 0 : options.minimal) != null ? _b : false }
|
|
525
|
+
);
|
|
438
526
|
}
|
|
439
527
|
collectionsDto(collections) {
|
|
440
528
|
var _a;
|
|
@@ -444,14 +532,17 @@ var ShopClient = class {
|
|
|
444
532
|
* Enhanced error handling with context
|
|
445
533
|
*/
|
|
446
534
|
handleFetchError(error, context, url) {
|
|
535
|
+
const getStatus = (err) => {
|
|
536
|
+
if (!err || typeof err !== "object") return void 0;
|
|
537
|
+
const rec = err;
|
|
538
|
+
const status = rec.status;
|
|
539
|
+
return typeof status === "number" ? status : void 0;
|
|
540
|
+
};
|
|
447
541
|
let errorMessage = `Error ${context}`;
|
|
448
542
|
let statusCode;
|
|
449
543
|
if (error instanceof Error) {
|
|
450
544
|
errorMessage += `: ${error.message}`;
|
|
451
|
-
|
|
452
|
-
if (anyErr && typeof anyErr.status === "number") {
|
|
453
|
-
statusCode = anyErr.status;
|
|
454
|
-
}
|
|
545
|
+
statusCode = getStatus(error);
|
|
455
546
|
} else if (typeof error === "string") {
|
|
456
547
|
errorMessage += `: ${error}`;
|
|
457
548
|
} else {
|
|
@@ -461,17 +552,22 @@ var ShopClient = class {
|
|
|
461
552
|
if (statusCode) {
|
|
462
553
|
errorMessage += ` (Status: ${statusCode})`;
|
|
463
554
|
}
|
|
464
|
-
const enhancedError =
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
555
|
+
const enhancedError = Object.assign(
|
|
556
|
+
new Error(errorMessage),
|
|
557
|
+
{
|
|
558
|
+
context,
|
|
559
|
+
url,
|
|
560
|
+
statusCode,
|
|
561
|
+
originalError: error
|
|
562
|
+
}
|
|
563
|
+
);
|
|
469
564
|
throw enhancedError;
|
|
470
565
|
}
|
|
471
566
|
/**
|
|
472
567
|
* Fetch products with pagination
|
|
473
568
|
*/
|
|
474
|
-
async fetchProducts(page, limit) {
|
|
569
|
+
async fetchProducts(page, limit, options) {
|
|
570
|
+
var _a;
|
|
475
571
|
try {
|
|
476
572
|
const url = `${this.baseUrl}products.json?page=${page}&limit=${limit}`;
|
|
477
573
|
const response = await rateLimitedFetch(url, {
|
|
@@ -481,7 +577,9 @@ var ShopClient = class {
|
|
|
481
577
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
482
578
|
}
|
|
483
579
|
const data = await response.json();
|
|
484
|
-
return this.productsDto(data.products
|
|
580
|
+
return this.productsDto(data.products, {
|
|
581
|
+
minimal: (_a = options == null ? void 0 : options.minimal) != null ? _a : false
|
|
582
|
+
});
|
|
485
583
|
} catch (error) {
|
|
486
584
|
this.handleFetchError(
|
|
487
585
|
error,
|
|
@@ -516,6 +614,7 @@ var ShopClient = class {
|
|
|
516
614
|
* Fetch paginated products from a specific collection
|
|
517
615
|
*/
|
|
518
616
|
async fetchPaginatedProductsFromCollection(collectionHandle, options = {}) {
|
|
617
|
+
var _a;
|
|
519
618
|
try {
|
|
520
619
|
const { page = 1, limit = 250 } = options;
|
|
521
620
|
let finalHandle = collectionHandle;
|
|
@@ -549,7 +648,9 @@ var ShopClient = class {
|
|
|
549
648
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
550
649
|
}
|
|
551
650
|
const data = await response.json();
|
|
552
|
-
return this.productsDto(data.products
|
|
651
|
+
return this.productsDto(data.products, {
|
|
652
|
+
minimal: (_a = options == null ? void 0 : options.minimal) != null ? _a : false
|
|
653
|
+
});
|
|
553
654
|
} catch (error) {
|
|
554
655
|
this.handleFetchError(
|
|
555
656
|
error,
|