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.
Files changed (89) hide show
  1. package/README.md +136 -70
  2. package/dist/cjs/client/client.js +110 -22
  3. package/dist/cjs/generated/shopify.js +25 -49
  4. package/dist/cjs/helpers/CartManager.js +55 -0
  5. package/dist/cjs/helpers/CustomerSession.js +41 -0
  6. package/dist/cjs/index.js +210 -27
  7. package/dist/cjs/tests/integration/sdk.test.js +266 -0
  8. package/dist/cjs/tests/unit/cache.test.js +86 -0
  9. package/dist/cjs/tests/unit/cartManager.test.js +43 -0
  10. package/dist/cjs/tests/unit/client.test.js +134 -0
  11. package/dist/cjs/tests/unit/customerSession.test.js +50 -0
  12. package/dist/cjs/tests/unit/pagination.test.js +41 -0
  13. package/dist/cjs/tests/unit/webhooks.test.js +41 -0
  14. package/dist/cjs/utils/cache.js +29 -0
  15. package/dist/cjs/utils/errors.js +53 -0
  16. package/dist/cjs/utils/pagination.js +30 -0
  17. package/dist/cjs/utils/webhooks.js +33 -0
  18. package/dist/client/client.d.ts +12 -1
  19. package/dist/client/client.d.ts.map +1 -1
  20. package/dist/client/client.js +111 -21
  21. package/dist/client/client.js.map +1 -1
  22. package/dist/generated/shopify.d.ts +4048 -2764
  23. package/dist/generated/shopify.d.ts.map +1 -1
  24. package/dist/generated/shopify.js +26 -50
  25. package/dist/generated/shopify.js.map +1 -1
  26. package/dist/helpers/CartManager.d.ts +32 -0
  27. package/dist/helpers/CartManager.d.ts.map +1 -0
  28. package/dist/helpers/CartManager.js +53 -0
  29. package/dist/helpers/CartManager.js.map +1 -0
  30. package/dist/helpers/CustomerSession.d.ts +27 -0
  31. package/dist/helpers/CustomerSession.d.ts.map +1 -0
  32. package/dist/helpers/CustomerSession.js +40 -0
  33. package/dist/helpers/CustomerSession.js.map +1 -0
  34. package/dist/index.d.ts +179 -16
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +204 -28
  37. package/dist/index.js.map +1 -1
  38. package/dist/tests/integration/sdk.test.d.ts +2 -0
  39. package/dist/tests/integration/sdk.test.d.ts.map +1 -0
  40. package/dist/tests/integration/sdk.test.js +245 -0
  41. package/dist/tests/integration/sdk.test.js.map +1 -0
  42. package/dist/tests/unit/cache.test.d.ts +2 -0
  43. package/dist/tests/unit/cache.test.d.ts.map +1 -0
  44. package/dist/tests/unit/cache.test.js +85 -0
  45. package/dist/tests/unit/cache.test.js.map +1 -0
  46. package/dist/tests/unit/cartManager.test.d.ts +2 -0
  47. package/dist/tests/unit/cartManager.test.d.ts.map +1 -0
  48. package/dist/tests/unit/cartManager.test.js +43 -0
  49. package/dist/tests/unit/cartManager.test.js.map +1 -0
  50. package/dist/tests/unit/client.test.d.ts +2 -0
  51. package/dist/tests/unit/client.test.d.ts.map +1 -0
  52. package/dist/tests/unit/client.test.js +133 -0
  53. package/dist/tests/unit/client.test.js.map +1 -0
  54. package/dist/tests/unit/customerSession.test.d.ts +2 -0
  55. package/dist/tests/unit/customerSession.test.d.ts.map +1 -0
  56. package/dist/tests/unit/customerSession.test.js +49 -0
  57. package/dist/tests/unit/customerSession.test.js.map +1 -0
  58. package/dist/tests/unit/pagination.test.d.ts +2 -0
  59. package/dist/tests/unit/pagination.test.d.ts.map +1 -0
  60. package/dist/tests/unit/pagination.test.js +40 -0
  61. package/dist/tests/unit/pagination.test.js.map +1 -0
  62. package/dist/tests/unit/webhooks.test.d.ts +2 -0
  63. package/dist/tests/unit/webhooks.test.d.ts.map +1 -0
  64. package/dist/tests/unit/webhooks.test.js +40 -0
  65. package/dist/tests/unit/webhooks.test.js.map +1 -0
  66. package/dist/utils/cache.d.ts +14 -0
  67. package/dist/utils/cache.d.ts.map +1 -0
  68. package/dist/utils/cache.js +24 -0
  69. package/dist/utils/cache.js.map +1 -0
  70. package/dist/utils/config.d.ts +6 -0
  71. package/dist/utils/config.d.ts.map +1 -1
  72. package/dist/utils/errors.d.ts +30 -0
  73. package/dist/utils/errors.d.ts.map +1 -0
  74. package/dist/utils/errors.js +48 -0
  75. package/dist/utils/errors.js.map +1 -0
  76. package/dist/utils/pagination.d.ts +20 -0
  77. package/dist/utils/pagination.d.ts.map +1 -0
  78. package/dist/utils/pagination.js +28 -0
  79. package/dist/utils/pagination.js.map +1 -0
  80. package/dist/utils/webhooks.d.ts +10 -0
  81. package/dist/utils/webhooks.d.ts.map +1 -0
  82. package/dist/utils/webhooks.js +31 -0
  83. package/dist/utils/webhooks.js.map +1 -0
  84. package/package.json +11 -7
  85. package/dist/cjs/tests/test.js +0 -201
  86. package/dist/tests/test.d.ts +0 -34
  87. package/dist/tests/test.d.ts.map +0 -1
  88. package/dist/tests/test.js +0 -202
  89. package/dist/tests/test.js.map +0 -1
@@ -1,31 +1,121 @@
1
- import axios from "axios";
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
- constructor({ storeUrl, storefrontToken }) {
6
- if (!storeUrl?.includes(".myshopify.com")) {
7
- throw new Error(`The store url ${storeUrl} is not supported by shopify`);
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
- (this.endpoint = `https://${storeUrl}/api/2025-04/graphql.json`),
10
- (this.token = storefrontToken);
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
- try {
14
- const res = await axios.post(this.endpoint, {
15
- query,
16
- variables,
17
- }, {
18
- headers: {
19
- "X-Shopify-Storefront-Access-Token": this.token,
20
- "Content-Type": "application/json",
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
- catch (error) {
28
- throw new Error(`Shopify Error: ${error.message}`);
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":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,aAAa;IACT,QAAQ,CAAC;IACT,KAAK,CAAC;IACd,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAe;QACpD,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,8BAA8B,CAAC,CAAC;QAC3E,CAAC;QACD,CAAC,IAAI,CAAC,QAAQ,GAAG,WAAW,QAAQ,2BAA2B,CAAC;YAC9D,CAAC,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK,CAAU,KAAa,EAAE,SAAS,GAAG,EAAE;QAChD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAC1B,IAAI,CAAC,QAAQ,EACb;gBACE,KAAK;gBACL,SAAS;aACV,EACD;gBACE,OAAO,EAAE;oBACP,mCAAmC,EAAE,IAAI,CAAC,KAAK;oBAC/C,cAAc,EAAE,kBAAkB;iBACnC;aACF,CACF,CAAC;YACF,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM;gBAClB,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5D,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;QACxB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;CACF;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}