shop-client 3.15.0 → 3.17.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 CHANGED
@@ -359,7 +359,7 @@ Fetches all products from the store with automatic pagination handling.
359
359
  const allProducts = await shop.products.all();
360
360
  ```
361
361
 
362
- **Returns:** `Product[]` - Array of all products in the store
362
+ **Returns:** `Product[] | null`
363
363
 
364
364
  #### `products.paginated(options)`
365
365
 
@@ -379,7 +379,7 @@ const products = await shop.products.paginated({
379
379
  - `limit` (number, optional): Products per page (default: 250, max: 250)
380
380
  - `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']` (e.g., `"USD"`, `"EUR"`, `"JPY"`)
381
381
 
382
- **Returns:** `Product[]` - Array of products for the specified page
382
+ **Returns:** `Product[] | null`
383
383
 
384
384
  #### `products.find(handle)`
385
385
 
@@ -397,7 +397,7 @@ const productEur = await shop.products.find("product-handle", { currency: "EUR"
397
397
  - `options` (object, optional): Additional options
398
398
  - `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']`
399
399
 
400
- **Returns:** `Product | null` - Product object or null if not found
400
+ **Returns:** `Product | null`
401
401
 
402
402
  #### `products.showcased()`
403
403
 
@@ -407,7 +407,25 @@ Fetches products featured on the store's homepage.
407
407
  const showcasedProducts = await shop.products.showcased();
408
408
  ```
409
409
 
410
- **Returns:** `Product[]` - Array of featured products
410
+ **Returns:** `Product[]`
411
+
412
+ #### `products.infoHtml(productHandle, content?)`
413
+
414
+ Fetches the extracted HTML content from the product page. This is useful for getting the main product description and content directly from the page HTML.
415
+
416
+ ```typescript
417
+ // Fetch from store
418
+ const html = await shop.products.infoHtml("product-handle");
419
+
420
+ // Use provided HTML
421
+ const htmlFromContent = await shop.products.infoHtml("product-handle", "<html>...</html>");
422
+ ```
423
+
424
+ **Parameters:**
425
+ - `productHandle` (string): The product handle
426
+ - `content` (string, optional): HTML content to extract from. If provided, skips fetching the product page.
427
+
428
+ **Returns:** `Promise<string | null>` - Extracted HTML content or null if not found
411
429
 
412
430
  #### `products.filter()`
413
431
 
@@ -457,6 +475,8 @@ const results = await shop.products.predictiveSearch("dress", {
457
475
  - Extracts handles from Ajax results, fetches full products via `find`
458
476
  - Falls back to non-locale path when locale returns 404/417
459
477
 
478
+ **Returns:** `Product[]`
479
+
460
480
  ### Recommendations
461
481
 
462
482
  #### `products.recommendations(productId, options?)`
@@ -475,6 +495,30 @@ const recos = await shop.products.recommendations(1234567890, {
475
495
  - Returns normalized `Product[]`
476
496
  - Locale-aware endpoint `/{locale}/recommendations/products.json`
477
497
 
498
+ ### Minimal Products
499
+
500
+ Convenience methods for minimal product returns:
501
+
502
+ ```typescript
503
+ // All products (minimal)
504
+ const minimalAll = await shop.products.minimal.all();
505
+
506
+ // Paginated (minimal)
507
+ const minimalPage = await shop.products.minimal.paginated({ page: 1, limit: 25 });
508
+
509
+ // Find one (minimal)
510
+ const minimalOne = await shop.products.minimal.find("product-handle");
511
+
512
+ // Showcased (minimal)
513
+ const minimalShowcased = await shop.products.showcase.minimal();
514
+
515
+ // Predictive search (minimal)
516
+ const minimalSearch = await shop.products.minimal.predictiveSearch("dress", { limit: 10 });
517
+
518
+ // Recommendations (minimal)
519
+ const minimalRecos = await shop.products.minimal.recommendations(1234567890, { limit: 6 });
520
+ ```
521
+
478
522
  ### Collections
479
523
 
480
524
  #### `collections.all()`
@@ -540,7 +584,7 @@ const products = await shop.collections.products.all("collection-handle");
540
584
  **Parameters:**
541
585
  - `handle` (string): The collection handle
542
586
 
543
- **Returns:** `Product[] | null` - Array of products in the collection
587
+ **Returns:** `Product[] | null`
544
588
 
545
589
  #### `collections.products.paginated(handle, options)`
546
590
 
@@ -561,13 +605,52 @@ const products = await shop.collections.products.paginated("collection-handle",
561
605
  - `limit` (number, optional): Products per page (default: 250)
562
606
  - `currency` (CurrencyCode, optional): ISO 4217 code aligned with `Intl.NumberFormatOptions['currency']`
563
607
 
564
- **Returns:** `Product[]` - Array of products for the specified page
608
+ **Returns:** `Product[] | null`
609
+
610
+ #### `collections.products.minimal.*`
611
+
612
+ Convenience methods for minimal product returns from collections:
613
+
614
+ ```typescript
615
+ // All products (minimal)
616
+ const minimalCollectionAll = await shop.collections.products.minimal.all("collection-handle");
617
+
618
+ // Paginated (minimal)
619
+ const minimalCollectionPage = await shop.collections.products.minimal.paginated("collection-handle", {
620
+ page: 1,
621
+ limit: 25,
622
+ });
623
+ ```
565
624
 
566
625
  #### Currency Override
567
626
 
568
627
  By default, pricing is formatted using the store’s detected currency.
569
628
  You can override the currency for product and collection queries by passing a `currency` option.
570
- This override updates `Product.currency` and `Product.localizedPricing.currency` (and related formatted strings) only.
629
+ This override updates product pricing display fields only:
630
+ - `Product.localizedPricing` formatted strings
631
+ - `MinimalProduct.localizedPricing` formatted strings
632
+
633
+ ### Showcased Products
634
+
635
+ #### `products.showcased()`
636
+
637
+ Fetches products showcased on the store’s homepage as full products.
638
+
639
+ ```typescript
640
+ const featuredProducts = await shop.products.showcased();
641
+ ```
642
+
643
+ **Returns:** `Product[]`
644
+
645
+ #### `products.showcase.minimal()`
646
+
647
+ Fetches showcased products as minimal product items.
648
+
649
+ ```typescript
650
+ const minimalFeatured = await shop.products.showcase.minimal();
651
+ ```
652
+
653
+ **Returns:** `MinimalProduct[]`
571
654
 
572
655
  ```typescript
573
656
  // Products
@@ -739,6 +822,12 @@ const enrichedMarkdown = await shop.products.enriched('some-product-handle', {
739
822
  });
740
823
  // enrichedMarkdown?.enriched_content → markdown
741
824
 
825
+ // Use provided content instead of fetching product page
826
+ const enrichedFromContent = await shop.products.enriched('some-product-handle', {
827
+ outputFormat: 'markdown',
828
+ content: '<html>...</html>',
829
+ });
830
+
742
831
  const enrichedJson = await shop.products.enriched('some-product-handle', {
743
832
  outputFormat: 'json',
744
833
  });
@@ -747,6 +836,7 @@ const enrichedJson = await shop.products.enriched('some-product-handle', {
747
836
  // Build prompts without calling the LLM (useful for debugging)
748
837
  const { system, user } = await shop.products.enrichedPrompts('some-product-handle', {
749
838
  outputFormat: 'markdown',
839
+ content: '<html>...</html>', // Optional content
750
840
  });
751
841
  ```
752
842
 
@@ -976,6 +1066,7 @@ type MetaTag =
976
1066
  ```typescript
977
1067
  async function searchProducts(shop: ShopClient, query: string) {
978
1068
  const allProducts = await shop.products.all();
1069
+ if (!allProducts) return [];
979
1070
  return allProducts.filter(product =>
980
1071
  product.title.toLowerCase().includes(query.toLowerCase()) ||
981
1072
  product.tags.some(tag => tag.toLowerCase().includes(query.toLowerCase()))
@@ -988,6 +1079,7 @@ async function searchProducts(shop: ShopClient, query: string) {
988
1079
  ```typescript
989
1080
  async function monitorPrices(shop: ShopClient) {
990
1081
  const products = await shop.products.all();
1082
+ if (!products) return [];
991
1083
  return products.map(product => ({
992
1084
  handle: product.handle,
993
1085
  title: product.title,
@@ -1,4 +1,4 @@
1
- import { O as OpenRouterConfig, k as ProductClassification, l as SEOContent, m as SystemUserPrompt, a as ShopifySingleProduct } from '../types-BRXamZMS.js';
1
+ import { O as OpenRouterConfig, l as ProductClassification, m as SEOContent, n as SystemUserPrompt, a as ShopifySingleProduct } from '../types-w9n4csBQ.js';
2
2
 
3
3
  declare function buildEnrichPrompt(args: {
4
4
  bodyInput: string;
@@ -11,10 +11,12 @@ declare function buildEnrichPromptForProduct(domain: string, handle: string, opt
11
11
  useGfm?: boolean;
12
12
  inputType?: "markdown" | "html";
13
13
  outputFormat?: "markdown" | "json";
14
+ htmlContent?: string;
14
15
  }): Promise<SystemUserPrompt>;
15
16
  declare function buildClassifyPromptForProduct(domain: string, handle: string, options?: {
16
17
  useGfm?: boolean;
17
18
  inputType?: "markdown" | "html";
19
+ htmlContent?: string;
18
20
  }): Promise<SystemUserPrompt>;
19
21
  interface EnrichedProductResult {
20
22
  bodyHtml: string;
@@ -63,6 +65,7 @@ declare function enrichProduct(domain: string, handle: string, options?: {
63
65
  model?: string;
64
66
  outputFormat?: "markdown" | "json";
65
67
  openRouter?: OpenRouterConfig;
68
+ htmlContent?: string;
66
69
  }): Promise<EnrichedProductResult>;
67
70
  /**
68
71
  * Classify product content into a three-tier hierarchy using LLM.
@@ -13,8 +13,8 @@ import {
13
13
  htmlToMarkdown,
14
14
  mergeWithLLM,
15
15
  pruneBreakdownForSignals
16
- } from "../chunk-2W623LCW.mjs";
17
- import "../chunk-D5MTUWFO.mjs";
16
+ } from "../chunk-5TGMDRUF.mjs";
17
+ import "../chunk-O77Z6OBJ.mjs";
18
18
  export {
19
19
  buildClassifyPrompt,
20
20
  buildClassifyPromptForProduct,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rateLimitedFetch
3
- } from "./chunk-D5MTUWFO.mjs";
3
+ } from "./chunk-O77Z6OBJ.mjs";
4
4
  import {
5
5
  formatPrice
6
6
  } from "./chunk-U3RQRBXZ.mjs";
@@ -37,10 +37,25 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
37
37
  }
38
38
  };
39
39
  }
40
+ function applyCurrencyOverrideMinimal(product, currency) {
41
+ var _a;
42
+ const compareAtPrice = (_a = product.compareAtPrice) != null ? _a : 0;
43
+ return {
44
+ ...product,
45
+ localizedPricing: {
46
+ priceFormatted: formatPrice(product.price, currency),
47
+ compareAtPriceFormatted: formatPrice(compareAtPrice, currency)
48
+ }
49
+ };
50
+ }
40
51
  function maybeOverrideProductsCurrency(products, currency) {
41
- if (!products || !currency) return products;
52
+ if (!products || !currency || products.length === 0) return products;
42
53
  return products.map((p) => applyCurrencyOverride(p, currency));
43
54
  }
55
+ function maybeOverrideMinimalProductsCurrency(products, currency) {
56
+ if (!products || !currency || products.length === 0) return products;
57
+ return products.map((p) => applyCurrencyOverrideMinimal(p, currency));
58
+ }
44
59
  return {
45
60
  /**
46
61
  * Fetches collections with pagination support.
@@ -141,7 +156,7 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
141
156
  * ```
142
157
  */
143
158
  find: async (collectionHandle) => {
144
- var _a, _b;
159
+ var _a, _b, _c;
145
160
  if (!collectionHandle || typeof collectionHandle !== "string") {
146
161
  throw new Error("Collection handle is required and must be a string");
147
162
  }
@@ -174,17 +189,25 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
174
189
  result.collection.handle,
175
190
  {
176
191
  limit: 1,
177
- page: 1
192
+ page: 1,
193
+ minimal: true
178
194
  }
179
195
  )) == null ? void 0 : _a.at(0);
180
196
  const collectionProductImage = (_b = collectionProduct == null ? void 0 : collectionProduct.images) == null ? void 0 : _b[0];
181
197
  if (collectionProduct && collectionProductImage) {
182
- collectionImage = {
183
- id: collectionProductImage.id,
184
- src: collectionProductImage.src,
185
- alt: collectionProductImage.alt || collectionProduct.title,
186
- created_at: collectionProductImage.createdAt || (/* @__PURE__ */ new Date()).toISOString()
187
- };
198
+ const rec = collectionProductImage;
199
+ const src = typeof rec.src === "string" ? rec.src : String((_c = rec.src) != null ? _c : "");
200
+ if (src) {
201
+ const id = typeof rec.id === "number" ? rec.id : 0;
202
+ const alt = typeof rec.alt === "string" && rec.alt.trim() ? rec.alt : collectionProduct.title;
203
+ const createdAt = typeof rec.createdAt === "string" && rec.createdAt.trim() ? rec.createdAt : typeof rec.created_at === "string" && rec.created_at.trim() ? rec.created_at : (/* @__PURE__ */ new Date()).toISOString();
204
+ collectionImage = {
205
+ id,
206
+ src,
207
+ alt,
208
+ created_at: createdAt
209
+ };
210
+ }
188
211
  }
189
212
  }
190
213
  const collectionData = collectionsDto([
@@ -256,6 +279,7 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
256
279
  * @param options - Pagination options
257
280
  * @param options.page - Page number (default: 1)
258
281
  * @param options.limit - Number of products per page (default: 250, max: 250)
282
+ * Use `shop.collections.products.minimal.paginated()` for MinimalProduct returns.
259
283
  *
260
284
  * @returns {Promise<Product[] | null>} Array of products from the collection or null if error occurs
261
285
  *
@@ -296,14 +320,22 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
296
320
  }
297
321
  const products = await fetchPaginatedProductsFromCollection(
298
322
  sanitizedHandle,
299
- { page, limit }
323
+ {
324
+ page,
325
+ limit,
326
+ minimal: false
327
+ }
328
+ );
329
+ return maybeOverrideProductsCurrency(
330
+ products,
331
+ options == null ? void 0 : options.currency
300
332
  );
301
- return maybeOverrideProductsCurrency(products, options == null ? void 0 : options.currency);
302
333
  },
303
334
  /**
304
335
  * Fetches all products from a specific collection.
305
336
  *
306
337
  * @param collectionHandle - The collection handle to fetch products from
338
+ * Use `shop.collections.products.minimal.all()` for MinimalProduct returns.
307
339
  *
308
340
  * @returns {Promise<Product[] | null>} Array of all products from the collection or null if error occurs
309
341
  *
@@ -342,7 +374,8 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
342
374
  sanitizedHandle,
343
375
  {
344
376
  page: currentPage,
345
- limit
377
+ limit,
378
+ minimal: false
346
379
  }
347
380
  );
348
381
  if (!products || products.length === 0 || products.length < limit) {
@@ -354,7 +387,10 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
354
387
  allProducts.push(...products);
355
388
  currentPage++;
356
389
  }
357
- return maybeOverrideProductsCurrency(allProducts, options == null ? void 0 : options.currency);
390
+ return maybeOverrideProductsCurrency(
391
+ allProducts,
392
+ options == null ? void 0 : options.currency
393
+ );
358
394
  } catch (error) {
359
395
  console.error(
360
396
  `Error fetching all products for collection ${sanitizedHandle}:`,
@@ -421,6 +457,92 @@ function createCollectionOperations(baseUrl, storeDomain, fetchCollections, coll
421
457
  );
422
458
  return null;
423
459
  }
460
+ },
461
+ minimal: {
462
+ paginated: async (collectionHandle, options) => {
463
+ var _a, _b;
464
+ if (!collectionHandle || typeof collectionHandle !== "string") {
465
+ throw new Error(
466
+ "Collection handle is required and must be a string"
467
+ );
468
+ }
469
+ const sanitizedHandle = collectionHandle.trim().replace(/[^a-zA-Z0-9\-_]/g, "");
470
+ if (!sanitizedHandle) {
471
+ throw new Error("Invalid collection handle format");
472
+ }
473
+ if (sanitizedHandle.length > 255) {
474
+ throw new Error("Collection handle is too long");
475
+ }
476
+ const page = (_a = options == null ? void 0 : options.page) != null ? _a : 1;
477
+ const limit = (_b = options == null ? void 0 : options.limit) != null ? _b : 250;
478
+ if (page < 1 || limit < 1 || limit > 250) {
479
+ throw new Error(
480
+ "Invalid pagination parameters: page must be >= 1, limit must be between 1 and 250"
481
+ );
482
+ }
483
+ const products = await fetchPaginatedProductsFromCollection(
484
+ sanitizedHandle,
485
+ {
486
+ page,
487
+ limit,
488
+ minimal: true
489
+ }
490
+ );
491
+ const final = maybeOverrideMinimalProductsCurrency(
492
+ products,
493
+ options == null ? void 0 : options.currency
494
+ );
495
+ return final || null;
496
+ },
497
+ all: async (collectionHandle, options) => {
498
+ if (!collectionHandle || typeof collectionHandle !== "string") {
499
+ throw new Error(
500
+ "Collection handle is required and must be a string"
501
+ );
502
+ }
503
+ const sanitizedHandle = collectionHandle.trim().replace(/[^a-zA-Z0-9\-_]/g, "");
504
+ if (!sanitizedHandle) {
505
+ throw new Error("Invalid collection handle format");
506
+ }
507
+ if (sanitizedHandle.length > 255) {
508
+ throw new Error("Collection handle is too long");
509
+ }
510
+ try {
511
+ const limit = 250;
512
+ const allProducts = [];
513
+ let currentPage = 1;
514
+ while (true) {
515
+ const products = await fetchPaginatedProductsFromCollection(
516
+ sanitizedHandle,
517
+ {
518
+ page: currentPage,
519
+ limit,
520
+ minimal: true
521
+ }
522
+ );
523
+ if (!products || products.length === 0 || products.length < limit) {
524
+ if (products && products.length > 0) {
525
+ allProducts.push(...products);
526
+ }
527
+ break;
528
+ }
529
+ allProducts.push(...products);
530
+ currentPage++;
531
+ }
532
+ const final = maybeOverrideMinimalProductsCurrency(
533
+ allProducts,
534
+ options == null ? void 0 : options.currency
535
+ );
536
+ return final || null;
537
+ } catch (error) {
538
+ console.error(
539
+ `Error fetching all products for collection ${sanitizedHandle}:`,
540
+ baseUrl,
541
+ error
542
+ );
543
+ return null;
544
+ }
545
+ }
424
546
  }
425
547
  }
426
548
  };