shop-client 3.11.0 → 3.13.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 +40 -10
- package/dist/{chunk-EUAKMCAX.mjs → chunk-CUL7ZM2W.mjs} +3 -1
- package/dist/{chunk-CNJRHWIK.mjs → chunk-ZF4M6GMB.mjs} +68 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +3 -2
- package/dist/products.d.ts +18 -0
- package/dist/products.mjs +1 -1
- package/dist/store.d.ts +2 -1
- package/dist/store.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Shop
|
|
1
|
+
# Shop Client
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/shop-client)
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
@@ -205,17 +205,8 @@ Notes:
|
|
|
205
205
|
|
|
206
206
|
### Migration: Barrel → Subpath Imports
|
|
207
207
|
|
|
208
|
-
#### Package Rename: `shop-search` → `shop-client` (v3.8.2)
|
|
209
|
-
- Install: `npm i shop-client` (replaces `shop-search`)
|
|
210
|
-
- Update imports to `shop-client` (API unchanged)
|
|
211
|
-
|
|
212
208
|
TypeScript:
|
|
213
209
|
```ts
|
|
214
|
-
// Before (pre-rename: shop-search)
|
|
215
|
-
import { Store } from 'shop-search';
|
|
216
|
-
const store = new Store("your-store.myshopify.com");
|
|
217
|
-
|
|
218
|
-
// After (post-rename: shop-client v3.8.2+)
|
|
219
210
|
import { ShopClient } from 'shop-client';
|
|
220
211
|
const client = new ShopClient("your-store.myshopify.com");
|
|
221
212
|
```
|
|
@@ -354,6 +345,8 @@ const storeInfo = await shop.getInfo();
|
|
|
354
345
|
- `headerLinks`: Navigation menu links
|
|
355
346
|
- `showcase`: Featured products and collections
|
|
356
347
|
- `jsonLdData`: Structured data from the store
|
|
348
|
+
- `country`: ISO 3166-1 alpha-2 code (e.g., `US`, `GB`)
|
|
349
|
+
- `currency`: ISO 4217 currency code (e.g., `USD`, `EUR`)
|
|
357
350
|
|
|
358
351
|
### Products
|
|
359
352
|
|
|
@@ -444,6 +437,43 @@ Object.entries(filters || {}).forEach(([optionName, values]) => {
|
|
|
444
437
|
- Handles products with multiple variant options
|
|
445
438
|
- Returns empty object `{}` if no products have variants
|
|
446
439
|
|
|
440
|
+
### Predictive Search
|
|
441
|
+
|
|
442
|
+
#### `products.predictiveSearch(query, options?)`
|
|
443
|
+
|
|
444
|
+
Locale-aware Shopify Ajax predictive search for products.
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
const results = await shop.products.predictiveSearch("dress", {
|
|
448
|
+
limit: 10, // clamps 1–10
|
|
449
|
+
locale: "en", // defaults to "en"
|
|
450
|
+
// unavailableProducts defaults to "hide"
|
|
451
|
+
currency: "USD", // optional override
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
- Hides unavailable items by default
|
|
456
|
+
- Extracts handles from Ajax results, fetches full products via `find`
|
|
457
|
+
- Falls back to non-locale path when locale returns 404/417
|
|
458
|
+
|
|
459
|
+
### Recommendations
|
|
460
|
+
|
|
461
|
+
#### `products.recommendations(productId, options?)`
|
|
462
|
+
|
|
463
|
+
Shopify Ajax product recommendations for a given product.
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const recos = await shop.products.recommendations(1234567890, {
|
|
467
|
+
limit: 6, // clamps 1–10 (default 10)
|
|
468
|
+
intent: "related", // or "complementary" (default: related)
|
|
469
|
+
locale: "en", // defaults to "en"
|
|
470
|
+
currency: "USD", // optional override
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
- Returns normalized `Product[]`
|
|
475
|
+
- Locale-aware endpoint `/{locale}/recommendations/products.json`
|
|
476
|
+
|
|
447
477
|
### Collections
|
|
448
478
|
|
|
449
479
|
#### `collections.all()`
|
|
@@ -192,7 +192,8 @@ async function getInfoForStore(args, options) {
|
|
|
192
192
|
walletId: shopifyWalletId,
|
|
193
193
|
subDomain: myShopifySubdomain != null ? myShopifySubdomain : null
|
|
194
194
|
},
|
|
195
|
-
country: countryDetection.country
|
|
195
|
+
country: countryDetection.country,
|
|
196
|
+
currency: (countryDetection == null ? void 0 : countryDetection.currencyCode) || null
|
|
196
197
|
};
|
|
197
198
|
const currencyCode = countryDetection == null ? void 0 : countryDetection.currencyCode;
|
|
198
199
|
return { info, currencyCode };
|
|
@@ -218,6 +219,7 @@ function createStoreOperations(context) {
|
|
|
218
219
|
* - `jsonLdData` - Structured data from JSON-LD scripts
|
|
219
220
|
* - `techProvider` - Shopify-specific information (walletId, subDomain)
|
|
220
221
|
* - `country` - Country detection results with ISO 3166-1 alpha-2 codes (e.g., "US", "GB")
|
|
222
|
+
* - `currency` - ISO 4217 currency code inferred from store (e.g., "USD")
|
|
221
223
|
*
|
|
222
224
|
* @throws {Error} When the store URL is unreachable or returns an error
|
|
223
225
|
*
|
|
@@ -450,6 +450,74 @@ function createProductOperations(baseUrl, storeDomain, fetchProducts, productsDt
|
|
|
450
450
|
console.error("Failed to create product filters:", storeDomain, error);
|
|
451
451
|
throw error;
|
|
452
452
|
}
|
|
453
|
+
},
|
|
454
|
+
predictiveSearch: async (query, options) => {
|
|
455
|
+
var _a, _b, _c, _d, _e;
|
|
456
|
+
if (!query || typeof query !== "string") {
|
|
457
|
+
throw new Error("Query is required and must be a string");
|
|
458
|
+
}
|
|
459
|
+
const limit = Math.max(1, Math.min((_a = options == null ? void 0 : options.limit) != null ? _a : 10, 10));
|
|
460
|
+
const unavailable = (options == null ? void 0 : options.unavailableProducts) === "show" || (options == null ? void 0 : options.unavailableProducts) === "hide" ? options.unavailableProducts : "hide";
|
|
461
|
+
const localeValue = (options == null ? void 0 : options.locale) && options.locale.trim() || "en";
|
|
462
|
+
const localePrefix = `${localeValue.replace(/^\/|\/$/g, "")}/`;
|
|
463
|
+
const url = `${baseUrl}${localePrefix}search/suggest.json?q=${encodeURIComponent(query)}&resources[type]=product&resources[limit]=${limit}&resources[options][unavailable_products]=${unavailable}`;
|
|
464
|
+
const response = await rateLimitedFetch(url, {
|
|
465
|
+
rateLimitClass: "search:predictive",
|
|
466
|
+
timeoutMs: 7e3,
|
|
467
|
+
retry: { maxRetries: 2, baseDelayMs: 300 }
|
|
468
|
+
});
|
|
469
|
+
let resp = response;
|
|
470
|
+
if (!resp.ok && (resp.status === 404 || resp.status === 417)) {
|
|
471
|
+
const fallbackUrl = `${baseUrl}search/suggest.json?q=${encodeURIComponent(query)}&resources[type]=product&resources[limit]=${limit}&resources[options][unavailable_products]=${unavailable}`;
|
|
472
|
+
resp = await rateLimitedFetch(fallbackUrl, {
|
|
473
|
+
rateLimitClass: "search:predictive",
|
|
474
|
+
timeoutMs: 7e3,
|
|
475
|
+
retry: { maxRetries: 2, baseDelayMs: 300 }
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
if (!resp.ok) {
|
|
479
|
+
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
|
|
480
|
+
}
|
|
481
|
+
const data = await resp.json();
|
|
482
|
+
const raw = (_d = (_c = (_b = data == null ? void 0 : data.resources) == null ? void 0 : _b.results) == null ? void 0 : _c.products) != null ? _d : [];
|
|
483
|
+
const handles = raw.filter((p) => {
|
|
484
|
+
var _a2;
|
|
485
|
+
return Boolean((_a2 = p == null ? void 0 : p.available) != null ? _a2 : true);
|
|
486
|
+
}).map((p) => {
|
|
487
|
+
var _a2;
|
|
488
|
+
return String((_a2 = p == null ? void 0 : p.handle) != null ? _a2 : "");
|
|
489
|
+
}).filter((h) => h.length > 0).slice(0, limit);
|
|
490
|
+
const fetched = await Promise.all(handles.map((h) => findProduct(h)));
|
|
491
|
+
const results = filter(fetched, isNonNullish);
|
|
492
|
+
const finalProducts = (_e = maybeOverrideProductsCurrency(results, options == null ? void 0 : options.currency)) != null ? _e : [];
|
|
493
|
+
return finalProducts;
|
|
494
|
+
},
|
|
495
|
+
recommendations: async (productId, options) => {
|
|
496
|
+
var _a, _b;
|
|
497
|
+
if (!Number.isFinite(productId) || productId <= 0) {
|
|
498
|
+
throw new Error("Valid productId is required");
|
|
499
|
+
}
|
|
500
|
+
const limit = Math.max(1, Math.min((_a = options == null ? void 0 : options.limit) != null ? _a : 10, 10));
|
|
501
|
+
const intent = (options == null ? void 0 : options.intent) === "complementary" ? "complementary" : "related";
|
|
502
|
+
const localeValue = (options == null ? void 0 : options.locale) && options.locale.trim() || "en";
|
|
503
|
+
const localePrefix = `${localeValue.replace(/^\/|\/$/g, "")}/`;
|
|
504
|
+
const url = `${baseUrl}${localePrefix}recommendations/products.json?product_id=${encodeURIComponent(String(productId))}&limit=${limit}&intent=${intent}`;
|
|
505
|
+
const resp = await rateLimitedFetch(url, {
|
|
506
|
+
rateLimitClass: "products:recommendations",
|
|
507
|
+
timeoutMs: 7e3,
|
|
508
|
+
retry: { maxRetries: 2, baseDelayMs: 300 }
|
|
509
|
+
});
|
|
510
|
+
if (!resp.ok) {
|
|
511
|
+
if (resp.status === 404) {
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
|
|
515
|
+
}
|
|
516
|
+
const data = await resp.json();
|
|
517
|
+
const productsArray = Array.isArray(data) ? data : Array.isArray(data == null ? void 0 : data.products) ? data.products : [];
|
|
518
|
+
const normalized = productsDto(productsArray) || [];
|
|
519
|
+
const finalProducts = (_b = maybeOverrideProductsCurrency(normalized, options == null ? void 0 : options.currency)) != null ? _b : [];
|
|
520
|
+
return finalProducts;
|
|
453
521
|
}
|
|
454
522
|
};
|
|
455
523
|
return operations;
|
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,7 @@ declare class ShopClient {
|
|
|
132
132
|
* - `jsonLdData` - Structured data from JSON-LD scripts
|
|
133
133
|
* - `techProvider` - Shopify-specific information (walletId, subDomain)
|
|
134
134
|
* - `country` - Country detection results with ISO 3166-1 alpha-2 codes (e.g., "US", "GB")
|
|
135
|
+
* - `currency` - ISO 4217 currency code inferred from store (e.g., "USD")
|
|
135
136
|
*
|
|
136
137
|
* @throws {Error} When the store URL is unreachable or returns an error
|
|
137
138
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
} from "./chunk-554O5ED6.mjs";
|
|
7
7
|
import {
|
|
8
8
|
createProductOperations
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZF4M6GMB.mjs";
|
|
10
10
|
import {
|
|
11
11
|
createStoreOperations,
|
|
12
12
|
getInfoForStore
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-CUL7ZM2W.mjs";
|
|
14
14
|
import {
|
|
15
15
|
classifyProduct,
|
|
16
16
|
determineStoreType,
|
|
@@ -656,6 +656,7 @@ var ShopClient = class {
|
|
|
656
656
|
* - `jsonLdData` - Structured data from JSON-LD scripts
|
|
657
657
|
* - `techProvider` - Shopify-specific information (walletId, subDomain)
|
|
658
658
|
* - `country` - Country detection results with ISO 3166-1 alpha-2 codes (e.g., "US", "GB")
|
|
659
|
+
* - `currency` - ISO 4217 currency code inferred from store (e.g., "USD")
|
|
659
660
|
*
|
|
660
661
|
* @throws {Error} When the store URL is unreachable or returns an error
|
|
661
662
|
*
|
package/dist/products.d.ts
CHANGED
|
@@ -55,6 +55,24 @@ interface ProductOperations {
|
|
|
55
55
|
* Creates a filter map of variant options and their distinct values from all products.
|
|
56
56
|
*/
|
|
57
57
|
filter(): Promise<Record<string, string[]> | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Predictive product search using Shopify Ajax API.
|
|
60
|
+
*/
|
|
61
|
+
predictiveSearch(query: string, options?: {
|
|
62
|
+
limit?: number;
|
|
63
|
+
locale?: string;
|
|
64
|
+
currency?: CurrencyCode;
|
|
65
|
+
unavailableProducts?: "show" | "hide" | "last";
|
|
66
|
+
}): Promise<Product[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Product recommendations for a given product ID using Shopify Ajax API.
|
|
69
|
+
*/
|
|
70
|
+
recommendations(productId: number, options?: {
|
|
71
|
+
limit?: number;
|
|
72
|
+
intent?: "related" | "complementary";
|
|
73
|
+
locale?: string;
|
|
74
|
+
currency?: CurrencyCode;
|
|
75
|
+
}): Promise<Product[] | null>;
|
|
58
76
|
}
|
|
59
77
|
/**
|
|
60
78
|
* Creates product operations for a store instance
|
package/dist/products.mjs
CHANGED
package/dist/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as JsonLdEntry, d as CountryDetectionResult } from './types-luPg5O08.js';
|
|
1
|
+
import { J as JsonLdEntry, d as CountryDetectionResult, f as CurrencyCode } from './types-luPg5O08.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Store operations interface for managing store-related functionality.
|
|
@@ -36,6 +36,7 @@ interface StoreInfo {
|
|
|
36
36
|
subDomain: string | null;
|
|
37
37
|
};
|
|
38
38
|
country: CountryDetectionResult["country"];
|
|
39
|
+
currency: CurrencyCode | null;
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
42
|
* Creates store operations for a ShopClient instance.
|
package/dist/store.mjs
CHANGED