shopify_storefront_sdk 1.0.4 → 2.0.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 +136 -70
- package/dist/cjs/client/client.js +110 -22
- package/dist/cjs/generated/shopify.js +25 -49
- package/dist/cjs/helpers/CartManager.js +55 -0
- package/dist/cjs/helpers/CustomerSession.js +41 -0
- package/dist/cjs/index.js +210 -27
- package/dist/cjs/tests/integration/sdk.test.js +266 -0
- package/dist/cjs/tests/unit/cache.test.js +86 -0
- package/dist/cjs/tests/unit/cartManager.test.js +43 -0
- package/dist/cjs/tests/unit/client.test.js +134 -0
- package/dist/cjs/tests/unit/customerSession.test.js +50 -0
- package/dist/cjs/tests/unit/pagination.test.js +41 -0
- package/dist/cjs/tests/unit/webhooks.test.js +41 -0
- package/dist/cjs/utils/cache.js +29 -0
- package/dist/cjs/utils/errors.js +53 -0
- package/dist/cjs/utils/pagination.js +30 -0
- package/dist/cjs/utils/webhooks.js +33 -0
- package/dist/client/client.d.ts +12 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +111 -21
- package/dist/client/client.js.map +1 -1
- package/dist/generated/shopify.d.ts +4048 -2764
- package/dist/generated/shopify.d.ts.map +1 -1
- package/dist/generated/shopify.js +26 -50
- package/dist/generated/shopify.js.map +1 -1
- package/dist/helpers/CartManager.d.ts +32 -0
- package/dist/helpers/CartManager.d.ts.map +1 -0
- package/dist/helpers/CartManager.js +53 -0
- package/dist/helpers/CartManager.js.map +1 -0
- package/dist/helpers/CustomerSession.d.ts +27 -0
- package/dist/helpers/CustomerSession.d.ts.map +1 -0
- package/dist/helpers/CustomerSession.js +40 -0
- package/dist/helpers/CustomerSession.js.map +1 -0
- package/dist/index.d.ts +179 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +204 -28
- package/dist/index.js.map +1 -1
- package/dist/tests/integration/sdk.test.d.ts +2 -0
- package/dist/tests/integration/sdk.test.d.ts.map +1 -0
- package/dist/tests/integration/sdk.test.js +245 -0
- package/dist/tests/integration/sdk.test.js.map +1 -0
- package/dist/tests/unit/cache.test.d.ts +2 -0
- package/dist/tests/unit/cache.test.d.ts.map +1 -0
- package/dist/tests/unit/cache.test.js +85 -0
- package/dist/tests/unit/cache.test.js.map +1 -0
- package/dist/tests/unit/cartManager.test.d.ts +2 -0
- package/dist/tests/unit/cartManager.test.d.ts.map +1 -0
- package/dist/tests/unit/cartManager.test.js +43 -0
- package/dist/tests/unit/cartManager.test.js.map +1 -0
- package/dist/tests/unit/client.test.d.ts +2 -0
- package/dist/tests/unit/client.test.d.ts.map +1 -0
- package/dist/tests/unit/client.test.js +133 -0
- package/dist/tests/unit/client.test.js.map +1 -0
- package/dist/tests/unit/customerSession.test.d.ts +2 -0
- package/dist/tests/unit/customerSession.test.d.ts.map +1 -0
- package/dist/tests/unit/customerSession.test.js +49 -0
- package/dist/tests/unit/customerSession.test.js.map +1 -0
- package/dist/tests/unit/pagination.test.d.ts +2 -0
- package/dist/tests/unit/pagination.test.d.ts.map +1 -0
- package/dist/tests/unit/pagination.test.js +40 -0
- package/dist/tests/unit/pagination.test.js.map +1 -0
- package/dist/tests/unit/webhooks.test.d.ts +2 -0
- package/dist/tests/unit/webhooks.test.d.ts.map +1 -0
- package/dist/tests/unit/webhooks.test.js +40 -0
- package/dist/tests/unit/webhooks.test.js.map +1 -0
- package/dist/utils/cache.d.ts +14 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +24 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/config.d.ts +6 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/errors.d.ts +30 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/pagination.d.ts +20 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/pagination.js +28 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/webhooks.d.ts +10 -0
- package/dist/utils/webhooks.d.ts.map +1 -0
- package/dist/utils/webhooks.js +31 -0
- package/dist/utils/webhooks.js.map +1 -0
- package/package.json +11 -7
- package/dist/cjs/tests/test.js +0 -201
- package/dist/tests/test.d.ts +0 -34
- package/dist/tests/test.d.ts.map +0 -1
- package/dist/tests/test.js +0 -202
- package/dist/tests/test.js.map +0 -1
package/dist/client/client.js
CHANGED
|
@@ -1,31 +1,121 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import { ShopifyNetworkError, ShopifyGraphQLError, ShopifyInvalidRequestError, ShopifyUserError } from "../utils/errors.js";
|
|
2
3
|
class ShopifyClient {
|
|
3
4
|
endpoint;
|
|
4
5
|
token;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
maxRetries;
|
|
7
|
+
cache;
|
|
8
|
+
cacheTtl;
|
|
9
|
+
constructor({ storeUrl, storefrontToken, apiVersion = "2025-01", maxRetries = 3, cache, defaultCacheTtl = 60 }) {
|
|
10
|
+
if (!storeUrl || !storeUrl.includes(".myshopify.com")) {
|
|
11
|
+
throw new ShopifyInvalidRequestError(`The store URL "${storeUrl}" is invalid or not supported by Shopify.`);
|
|
8
12
|
}
|
|
9
|
-
(
|
|
10
|
-
(
|
|
13
|
+
if (!storefrontToken) {
|
|
14
|
+
throw new ShopifyInvalidRequestError("A valid storefront access token must be provided.");
|
|
15
|
+
}
|
|
16
|
+
this.endpoint = `https://${storeUrl}/api/${apiVersion}/graphql.json`;
|
|
17
|
+
this.token = storefrontToken;
|
|
18
|
+
this.maxRetries = maxRetries;
|
|
19
|
+
this.cache = cache;
|
|
20
|
+
this.cacheTtl = defaultCacheTtl;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generates a deterministic hash for a GraphQL query and its variables.
|
|
24
|
+
*/
|
|
25
|
+
generateCacheKey(query, variables) {
|
|
26
|
+
return crypto.createHash("sha256").update(query + JSON.stringify(variables || {})).digest("hex");
|
|
11
27
|
}
|
|
12
28
|
async query(query, variables = {}) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
if (res.data?.errors)
|
|
24
|
-
throw new Error(JSON.stringify(res.data.errors, null, 2));
|
|
25
|
-
return res.data?.data;
|
|
29
|
+
const isMutation = query.trim().startsWith("mutation");
|
|
30
|
+
let cacheKey = "";
|
|
31
|
+
// 1. Check Cache (Only for Queries, never Mutations)
|
|
32
|
+
if (this.cache && !isMutation) {
|
|
33
|
+
cacheKey = this.generateCacheKey(query, variables);
|
|
34
|
+
const cachedResponse = await this.cache.get(cacheKey);
|
|
35
|
+
if (cachedResponse) {
|
|
36
|
+
return cachedResponse;
|
|
37
|
+
}
|
|
26
38
|
}
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
let attempt = 0;
|
|
40
|
+
while (attempt <= this.maxRetries) {
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetch(this.endpoint, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"X-Shopify-Storefront-Access-Token": this.token,
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify({
|
|
49
|
+
query,
|
|
50
|
+
variables,
|
|
51
|
+
})
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
// Handle Rate Limits (429) or Server Errors (503) by throwing so we can retry
|
|
55
|
+
if (res.status === 429 || res.status === 503) {
|
|
56
|
+
throw new ShopifyNetworkError(`Shopify returned HTTP ${res.status}: Rate Limited or Service Unavailable`);
|
|
57
|
+
}
|
|
58
|
+
// Handle other HTTP errors
|
|
59
|
+
if (res.status >= 400 && res.status < 500) {
|
|
60
|
+
throw new ShopifyInvalidRequestError(`Shopify returned a client error: HTTP ${res.status}`);
|
|
61
|
+
}
|
|
62
|
+
throw new ShopifyNetworkError(`Shopify Server Error: HTTP ${res.status}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await res.json();
|
|
65
|
+
// 2. Handle top-level GraphQL Errors
|
|
66
|
+
if (data?.errors && data.errors.length > 0) {
|
|
67
|
+
throw new ShopifyGraphQLError(data.errors[0]?.message || "GraphQL API returned errors", data.errors);
|
|
68
|
+
}
|
|
69
|
+
// 3. Scan for nested User Errors (commonly found in mutations)
|
|
70
|
+
if (data?.data) {
|
|
71
|
+
this.checkForUserErrors(data.data);
|
|
72
|
+
}
|
|
73
|
+
// 4. Save to Cache
|
|
74
|
+
if (this.cache && !isMutation && data?.data) {
|
|
75
|
+
await this.cache.set(cacheKey, data.data, this.cacheTtl);
|
|
76
|
+
}
|
|
77
|
+
return data?.data;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// If it's a structural/GraphQL/User error, or a 4xx error (except 429), re-throw immediately.
|
|
81
|
+
if (error instanceof ShopifyGraphQLError ||
|
|
82
|
+
error instanceof ShopifyInvalidRequestError ||
|
|
83
|
+
error instanceof ShopifyUserError) {
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
// If it's a network error or 429/503 and we have retries left, wait and retry.
|
|
87
|
+
if (attempt < this.maxRetries) {
|
|
88
|
+
attempt++;
|
|
89
|
+
// Exponential backoff: 500ms, 1000ms, 2000ms...
|
|
90
|
+
const backoff = Math.pow(2, attempt) * 500;
|
|
91
|
+
await new Promise(r => setTimeout(r, backoff));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Out of retries or unexpected error
|
|
95
|
+
throw new ShopifyNetworkError(`Network Error: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw new ShopifyNetworkError("Maximum retries exceeded");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Helper function to recursively check for `userErrors` inside the GraphQL response data.
|
|
102
|
+
*/
|
|
103
|
+
checkForUserErrors(data) {
|
|
104
|
+
if (!data || typeof data !== "object")
|
|
105
|
+
return;
|
|
106
|
+
for (const key of Object.keys(data)) {
|
|
107
|
+
const value = data[key];
|
|
108
|
+
if (value && typeof value === "object") {
|
|
109
|
+
if ("userErrors" in value && Array.isArray(value.userErrors) && value.userErrors.length > 0) {
|
|
110
|
+
throw new ShopifyUserError(value.userErrors[0]?.message || "A user error occurred during the mutation", value.userErrors);
|
|
111
|
+
}
|
|
112
|
+
else if ("customerUserErrors" in value && Array.isArray(value.customerUserErrors) && value.customerUserErrors.length > 0) {
|
|
113
|
+
throw new ShopifyUserError(value.customerUserErrors[0]?.message || "A customer user error occurred", value.customerUserErrors);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.checkForUserErrors(value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
29
119
|
}
|
|
30
120
|
}
|
|
31
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|