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
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # 📦 Shopify Storefront SDK (Node.js + TypeScript)
2
2
 
3
+ [![CI](https://github.com/kiddo9/shopify_storefront_sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/kiddo9/shopify_storefront_sdk/actions/workflows/ci.yml)
4
+
3
5
  A fully typed, lightweight, and developer-friendly **Node.js SDK for the Shopify Storefront GraphQL API**.
4
- Built with TypeScript, GraphQL Codegen, and graphql-request — designed to help developers move faster when building Shopify headless storefronts.
6
+ Built with TypeScript, designed to help developers move faster when building Shopify headless storefronts.
5
7
 
6
8
  ✔ Fully typed queries & responses
7
9
  ✔ Simple, intuitive API
@@ -15,18 +17,20 @@ Built with TypeScript, GraphQL Codegen, and graphql-request — designed to help
15
17
  ## 🔧 Installation
16
18
 
17
19
  ```bash
18
- npm install shopify-storefront-sdk
20
+ npm install shopify_storefront_sdk
19
21
  # or
20
- yarn add shopify-storefront-sdk
22
+ yarn add shopify_storefront_sdk
21
23
  # or
22
- pnpm add shopify-storefront-sdk
24
+ pnpm add shopify_storefront_sdk
23
25
 
24
26
  ```
25
27
 
26
28
  ## 🚀 Quick Start
27
29
 
28
30
  ```ts
29
- import { ShopifyStorefront } from "shopify-storefront-sdk";
31
+ import ShopifyStorefront from "shopify-storefront-sdk";
32
+ // or
33
+ const { default: ShopifyStorefront } = require("shopify_storefront_sdk");
30
34
 
31
35
  const shopify = new ShopifyStorefront({
32
36
  domain: process.env.SHOPIFY_STORE_DOMAIN!,
@@ -34,9 +38,10 @@ const shopify = new ShopifyStorefront({
34
38
  });
35
39
 
36
40
  // Fetch a product
37
- const product = await shopify.getProductById(
38
- "gid://shopify/Product/1234567890"
39
- );
41
+ const product = await client.getProductById({
42
+ id: "id",
43
+ metafields: [],
44
+ });
40
45
 
41
46
  console.log(product.title);
42
47
  ```
@@ -53,10 +58,8 @@ console.log(product.title);
53
58
  - Carts (create/get/update)
54
59
  - Customers (create, login, recovery flow)
55
60
 
56
- - **GraphQL Codegen built in**
57
61
  - **Consistent error handling**
58
62
  - **Supports custom queries**
59
- - **Zero heavy dependencies**
60
63
 
61
64
  ---
62
65
 
@@ -68,65 +71,165 @@ console.log(product.title);
68
71
  const shopify = new ShopifyStorefront({
69
72
  domain: "yourstore.myshopify.com",
70
73
  token: "your-storefront-access-token",
74
+ apiVersion: "2025-01", // Optional: defaults to 2025-01. Can be set to "unstable" or future versions.
75
+ maxRetries: 3, // Optional: Automatically retries on rate limits (429/503). Defaults to 3.
71
76
  });
72
77
  ```
73
78
 
74
79
  ---
75
80
 
81
+ ### Verify Webhooks
82
+
83
+ Easily verify incoming Shopify Webhooks using our static helper method (useful for API routes):
84
+
85
+ ```ts
86
+ const isValid = ShopifyStorefront.verifyWebhook(
87
+ rawBodyBuffer,
88
+ req.headers['x-shopify-hmac-sha256'],
89
+ process.env.SHOPIFY_WEBHOOK_SECRET
90
+ );
91
+
92
+ if (!isValid) throw new Error("Unauthorized");
93
+ ```
94
+
95
+ ---
96
+
97
+ ### Pagination
98
+
99
+ Automatically fetch all pages of a GraphQL connection without manually managing cursors:
100
+
101
+ ```ts
102
+ const allProducts = await shopify.autoPaginate(
103
+ (cursor) => shopify.getProducts({ first: 250, after: cursor }),
104
+ (response) => response.products
105
+ );
106
+
107
+ // allProducts is now a flat array of Product nodes!
108
+ ```
109
+
110
+ ### Shop Info
111
+
112
+ Retrieve general store configuration such as name, description, and currency settings:
113
+
114
+ ```ts
115
+ const shop = await shopify.getShopInfo();
116
+ console.log(shop.shop.name);
117
+ ```
118
+
119
+ ---
120
+
76
121
  ### Products
77
122
 
78
123
  #### Get product by ID
79
124
 
80
125
  ```ts
81
- await shopify.getProductById(productId);
126
+ await shopify.getProductById({
127
+ id: "id",
128
+ metafields: [],
129
+ });
82
130
  ```
83
131
 
84
132
  #### Get product by handle
85
133
 
86
134
  ```ts
87
- await shopify.getProductByHandle("my-product");
135
+ await shopify.getProductByHandle({
136
+ handle: "",
137
+ });
88
138
  ```
89
139
 
90
140
  #### Recommendations
91
141
 
92
142
  ```ts
93
- await shopify.getProductRecommendations(productId);
143
+ await shopify.getProductRecommendations({
144
+ productId: "",
145
+ });
94
146
  ```
95
147
 
96
148
  ---
97
149
 
98
- ### Carts
150
+ ### ⚡ Advanced Caching
99
151
 
100
- #### Create a cart
152
+ Repeatedly fetching the same data (like Store Info or Product details) can waste network time and hit Shopify rate limits. The SDK comes with a powerful, flexible caching layer.
101
153
 
102
154
  ```ts
103
- await shopify.createCart({
104
- lines: [{ merchandiseId: "...", quantity: 1 }],
155
+ import { ShopifyStorefront, InMemoryCache } from 'shopify_storefront_sdk';
156
+
157
+ const shopify = new ShopifyStorefront({
158
+ domain: "yourstore.myshopify.com",
159
+ token: "your-storefront-access-token",
160
+ cache: new InMemoryCache(), // Automatically caches GraphQL Queries
161
+ defaultCacheTtl: 60 // Cache duration in seconds (default is 60)
105
162
  });
163
+
164
+ // 1st Call: Hits the network (~200ms)
165
+ const shopInfo1 = await shopify.getShopInfo();
166
+
167
+ // 2nd Call: Instantly returns from memory (~0ms)
168
+ const shopInfo2 = await shopify.getShopInfo();
106
169
  ```
107
170
 
108
- #### Get cart
171
+ **Note:** The SDK intelligently ignores mutations. `createCart` or `addCartLines` will *never* be cached.
172
+
173
+ You can also use your own cache (like Redis) by passing an object that matches the `ShopifyCache` interface (`get(key)`, `set(key, value, ttl)`).
174
+
175
+ ---
176
+
177
+ ### 🛒 Cart Manager (Recommended)
178
+
179
+ Managing a Cart manually can be tedious. The SDK includes a stateful `CartManager` that automatically handles cart creation in the background:
109
180
 
110
181
  ```ts
111
- await shopify.getCart(cartId);
182
+ // Initialize with no ID to lazily create a cart, or pass an existing ID.
183
+ const cart = shopify.cart();
184
+
185
+ // Will automatically call createCart() in the background!
186
+ await cart.addLines([{ merchandiseId: "gid://...", quantity: 1 }]);
187
+
188
+ // The newly created cart ID is safely stored
189
+ console.log(cart.id);
190
+
191
+ // Easily fetch the latest state
192
+ const state = await cart.get();
112
193
  ```
113
194
 
114
195
  ---
115
196
 
116
- ### Customers
197
+ ### Manual Cart Operations
198
+
199
+ #### Create a cart
117
200
 
118
201
  ```ts
119
- await shopify.createCustomer({ email, password });
120
- await shopify.sendResetEmail(email);
121
- await shopify.verifyToken(token);
202
+ await shopify.createCart({
203
+ input: {
204
+ lines: [
205
+ {
206
+ quantity: 1,
207
+ merchandiseId: "",
208
+ },
209
+ ],
210
+ },
211
+ first: 20,
212
+ });
122
213
  ```
123
214
 
124
215
  ---
125
216
 
126
- ### Blogs & Articles
217
+ ### 👤 Customer Session Manager
218
+
219
+ Passing the `customerAccessToken` into every method manually can be repetitive. Use the stateful `CustomerSession` to automatically bind the token to all operations for that user:
127
220
 
128
221
  ```ts
129
- await shopify.getBlog("news", 10);
222
+ // 1. Log the customer in
223
+ const auth = await shopify.loginCustomer({ email: "...", password: "..." });
224
+ const token = auth.customerAccessTokenCreate.customerAccessToken.accessToken;
225
+
226
+ // 2. Initialize a Customer Session for that user
227
+ const session = shopify.customer(token);
228
+
229
+ // 3. Effortlessly manage their account!
230
+ const isValid = await session.verify();
231
+ const orders = await session.getOrders({ first: 10 });
232
+ await session.update({ customer: { firstName: "John" } });
130
233
  ```
131
234
 
132
235
  ---
@@ -135,12 +238,11 @@ await shopify.getBlog("news", 10);
135
238
 
136
239
  ```
137
240
  /src
138
- /queries → .graphql operations
241
+ /client
242
+ /utils
243
+ /graphql → .graphql operations
139
244
  /generated → Auto-generated code
140
245
  index.ts → SDK export
141
-
142
- /codegen.yml → Codegen config
143
- /schema.graphql → Shopify schema
144
246
  ```
145
247
 
146
248
  ---
@@ -148,8 +250,8 @@ await shopify.getBlog("news", 10);
148
250
  ## 🛠 Development Setup
149
251
 
150
252
  ```bash
151
- git clone https://github.com/YOUR_USERNAME/shopify-storefront-sdk.git
152
- cd shopify-storefront-sdk
253
+ git clone https://github.com/kiddo9/shopify_storefront_sdk.git
254
+ cd shopify_storefront_sdk
153
255
  npm install
154
256
  ```
155
257
 
@@ -165,14 +267,14 @@ SHOPIFY_STOREFRONT_TOKEN=xxxx
165
267
  ## 🔨 Build
166
268
 
167
269
  ```bash
168
- npm run build
270
+ npm run prepare
169
271
  ```
170
272
 
171
273
  Outputs:
172
274
 
173
275
  ```
276
+ dist/cjs/index.js
174
277
  dist/index.js
175
- dist/index.cjs
176
278
  dist/index.d.ts
177
279
  ```
178
280
 
@@ -181,36 +283,13 @@ dist/index.d.ts
181
283
  ## 🧪 Testing
182
284
 
183
285
  ```bash
184
- npm run dev
286
+ npm run dev:test
185
287
  # after build:
186
288
  npm run test
187
289
  ```
188
290
 
189
291
  ---
190
292
 
191
- ## 🧬 Code Generation
192
-
193
- Regenerate types & operations:
194
-
195
- ```bash
196
- npm run generate
197
- ```
198
-
199
- Scans:
200
-
201
- ```
202
- src/queries/*.graphql
203
- schema.graphql
204
- ```
205
-
206
- Generates:
207
-
208
- ```
209
- src/generated/
210
- ```
211
-
212
- ---
213
-
214
293
  ## 🌐 Requirements
215
294
 
216
295
  - Node.js 18+
@@ -243,16 +322,3 @@ it helps others discover it and motivates future improvements!
243
322
 
244
323
  ---
245
324
 
246
- ```
247
-
248
- If you want, I can also generate:
249
-
250
- ✅ Better badges (npm version, downloads, license, TypeScript)
251
- ✅ CONTRIBUTING.md
252
- ✅ API documentation table
253
- ✅ Full GitHub project template (issues, PR templates, workflows)
254
- ```
255
-
256
- ```
257
-
258
- ```
@@ -1,32 +1,120 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const axios_1 = require("axios");
3
+ const crypto = require("node:crypto");
4
+ const errors_js_1 = require("../utils/errors.js");
4
5
  class ShopifyClient {
5
- constructor({ storeUrl, storefrontToken }) {
6
- if (!(storeUrl === null || storeUrl === void 0 ? void 0 : storeUrl.includes(".myshopify.com"))) {
7
- throw new Error(`The store url ${storeUrl} is not supported by shopify`);
6
+ constructor({ storeUrl, storefrontToken, apiVersion = "2025-01", maxRetries = 3, cache, defaultCacheTtl = 60 }) {
7
+ if (!storeUrl || !storeUrl.includes(".myshopify.com")) {
8
+ throw new errors_js_1.ShopifyInvalidRequestError(`The store URL "${storeUrl}" is invalid or not supported by Shopify.`);
8
9
  }
9
- (this.endpoint = `https://${storeUrl}/api/2025-04/graphql.json`),
10
- (this.token = storefrontToken);
10
+ if (!storefrontToken) {
11
+ throw new errors_js_1.ShopifyInvalidRequestError("A valid storefront access token must be provided.");
12
+ }
13
+ this.endpoint = `https://${storeUrl}/api/${apiVersion}/graphql.json`;
14
+ this.token = storefrontToken;
15
+ this.maxRetries = maxRetries;
16
+ this.cache = cache;
17
+ this.cacheTtl = defaultCacheTtl;
18
+ }
19
+ /**
20
+ * Generates a deterministic hash for a GraphQL query and its variables.
21
+ */
22
+ generateCacheKey(query, variables) {
23
+ return crypto.createHash("sha256").update(query + JSON.stringify(variables || {})).digest("hex");
11
24
  }
12
25
  async query(query, variables = {}) {
13
- var _a, _b;
14
- try {
15
- const res = await axios_1.default.post(this.endpoint, {
16
- query,
17
- variables,
18
- }, {
19
- headers: {
20
- "X-Shopify-Storefront-Access-Token": this.token,
21
- "Content-Type": "application/json",
22
- },
23
- });
24
- if ((_a = res.data) === null || _a === void 0 ? void 0 : _a.errors)
25
- throw new Error(JSON.stringify(res.data.errors, null, 2));
26
- return (_b = res.data) === null || _b === void 0 ? void 0 : _b.data;
26
+ var _a;
27
+ const isMutation = query.trim().startsWith("mutation");
28
+ let cacheKey = "";
29
+ // 1. Check Cache (Only for Queries, never Mutations)
30
+ if (this.cache && !isMutation) {
31
+ cacheKey = this.generateCacheKey(query, variables);
32
+ const cachedResponse = await this.cache.get(cacheKey);
33
+ if (cachedResponse) {
34
+ return cachedResponse;
35
+ }
27
36
  }
28
- catch (error) {
29
- throw new Error(`Shopify Error: ${error.message}`);
37
+ let attempt = 0;
38
+ while (attempt <= this.maxRetries) {
39
+ try {
40
+ const res = await fetch(this.endpoint, {
41
+ method: "POST",
42
+ headers: {
43
+ "X-Shopify-Storefront-Access-Token": this.token,
44
+ "Content-Type": "application/json",
45
+ },
46
+ body: JSON.stringify({
47
+ query,
48
+ variables,
49
+ })
50
+ });
51
+ if (!res.ok) {
52
+ // Handle Rate Limits (429) or Server Errors (503) by throwing so we can retry
53
+ if (res.status === 429 || res.status === 503) {
54
+ throw new errors_js_1.ShopifyNetworkError(`Shopify returned HTTP ${res.status}: Rate Limited or Service Unavailable`);
55
+ }
56
+ // Handle other HTTP errors
57
+ if (res.status >= 400 && res.status < 500) {
58
+ throw new errors_js_1.ShopifyInvalidRequestError(`Shopify returned a client error: HTTP ${res.status}`);
59
+ }
60
+ throw new errors_js_1.ShopifyNetworkError(`Shopify Server Error: HTTP ${res.status}`);
61
+ }
62
+ const data = await res.json();
63
+ // 2. Handle top-level GraphQL Errors
64
+ if ((data === null || data === void 0 ? void 0 : data.errors) && data.errors.length > 0) {
65
+ throw new errors_js_1.ShopifyGraphQLError(((_a = data.errors[0]) === null || _a === void 0 ? void 0 : _a.message) || "GraphQL API returned errors", data.errors);
66
+ }
67
+ // 3. Scan for nested User Errors (commonly found in mutations)
68
+ if (data === null || data === void 0 ? void 0 : data.data) {
69
+ this.checkForUserErrors(data.data);
70
+ }
71
+ // 4. Save to Cache
72
+ if (this.cache && !isMutation && (data === null || data === void 0 ? void 0 : data.data)) {
73
+ await this.cache.set(cacheKey, data.data, this.cacheTtl);
74
+ }
75
+ return data === null || data === void 0 ? void 0 : data.data;
76
+ }
77
+ catch (error) {
78
+ // If it's a structural/GraphQL/User error, or a 4xx error (except 429), re-throw immediately.
79
+ if (error instanceof errors_js_1.ShopifyGraphQLError ||
80
+ error instanceof errors_js_1.ShopifyInvalidRequestError ||
81
+ error instanceof errors_js_1.ShopifyUserError) {
82
+ throw error;
83
+ }
84
+ // If it's a network error or 429/503 and we have retries left, wait and retry.
85
+ if (attempt < this.maxRetries) {
86
+ attempt++;
87
+ // Exponential backoff: 500ms, 1000ms, 2000ms...
88
+ const backoff = Math.pow(2, attempt) * 500;
89
+ await new Promise(r => setTimeout(r, backoff));
90
+ continue;
91
+ }
92
+ // Out of retries or unexpected error
93
+ throw new errors_js_1.ShopifyNetworkError(`Network Error: ${error.message}`);
94
+ }
95
+ }
96
+ throw new errors_js_1.ShopifyNetworkError("Maximum retries exceeded");
97
+ }
98
+ /**
99
+ * Helper function to recursively check for `userErrors` inside the GraphQL response data.
100
+ */
101
+ checkForUserErrors(data) {
102
+ var _a, _b;
103
+ if (!data || typeof data !== "object")
104
+ return;
105
+ for (const key of Object.keys(data)) {
106
+ const value = data[key];
107
+ if (value && typeof value === "object") {
108
+ if ("userErrors" in value && Array.isArray(value.userErrors) && value.userErrors.length > 0) {
109
+ throw new errors_js_1.ShopifyUserError(((_a = value.userErrors[0]) === null || _a === void 0 ? void 0 : _a.message) || "A user error occurred during the mutation", value.userErrors);
110
+ }
111
+ else if ("customerUserErrors" in value && Array.isArray(value.customerUserErrors) && value.customerUserErrors.length > 0) {
112
+ throw new errors_js_1.ShopifyUserError(((_b = value.customerUserErrors[0]) === null || _b === void 0 ? void 0 : _b.message) || "A customer user error occurred", value.customerUserErrors);
113
+ }
114
+ else {
115
+ this.checkForUserErrors(value);
116
+ }
117
+ }
30
118
  }
31
119
  }
32
120
  }
@@ -903,100 +903,76 @@ const defaultWrapper = (action, _operationName, _operationType, _variables) => a
903
903
  function getSdk(client, withWrapper = defaultWrapper) {
904
904
  return {
905
905
  getProducts(variables, requestHeaders) {
906
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductsDocument, variables, {
907
- ...requestHeaders,
908
- ...wrappedRequestHeaders,
909
- }), "getProducts", "query", variables);
906
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getProducts', 'query', variables);
910
907
  },
911
908
  getProductById(variables, requestHeaders) {
912
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductByIdDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getProductById", "query", variables);
909
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductByIdDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getProductById', 'query', variables);
913
910
  },
914
911
  GetProductRecommendations(variables, requestHeaders) {
915
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductRecommendationsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetProductRecommendations", "query", variables);
912
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductRecommendationsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetProductRecommendations', 'query', variables);
916
913
  },
917
914
  GetProductByHandle(variables, requestHeaders) {
918
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductByHandleDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetProductByHandle", "query", variables);
915
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetProductByHandleDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetProductByHandle', 'query', variables);
919
916
  },
920
917
  GetAllProductTypes(variables, requestHeaders) {
921
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetAllProductTypesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetAllProductTypes", "query", variables);
918
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetAllProductTypesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetAllProductTypes', 'query', variables);
922
919
  },
923
920
  getCollections(variables, requestHeaders) {
924
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCollectionsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getCollections", "query", variables);
921
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCollectionsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getCollections', 'query', variables);
925
922
  },
926
923
  getShopInfo(variables, requestHeaders) {
927
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetShopInfoDocument, variables, {
928
- ...requestHeaders,
929
- ...wrappedRequestHeaders,
930
- }), "getShopInfo", "query", variables);
924
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetShopInfoDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getShopInfo', 'query', variables);
931
925
  },
932
926
  GetCart(variables, requestHeaders) {
933
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCartDocument, variables, {
934
- ...requestHeaders,
935
- ...wrappedRequestHeaders,
936
- }), "GetCart", "query", variables);
927
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCartDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetCart', 'query', variables);
937
928
  },
938
929
  cartCreate(variables, requestHeaders) {
939
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartCreateDocument, variables, {
940
- ...requestHeaders,
941
- ...wrappedRequestHeaders,
942
- }), "cartCreate", "mutation", variables);
930
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartCreateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartCreate', 'mutation', variables);
943
931
  },
944
932
  cartLinesUpdate(variables, requestHeaders) {
945
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "cartLinesUpdate", "mutation", variables);
933
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartLinesUpdate', 'mutation', variables);
946
934
  },
947
935
  cartBuyerIdentityUpdate(variables, requestHeaders) {
948
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartBuyerIdentityUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "cartBuyerIdentityUpdate", "mutation", variables);
936
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartBuyerIdentityUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartBuyerIdentityUpdate', 'mutation', variables);
949
937
  },
950
938
  cartMetafieldsSet(variables, requestHeaders) {
951
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartMetafieldsSetDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "cartMetafieldsSet", "mutation", variables);
939
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartMetafieldsSetDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartMetafieldsSet', 'mutation', variables);
952
940
  },
953
941
  cartLinesAdd(variables, requestHeaders) {
954
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesAddDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "cartLinesAdd", "mutation", variables);
942
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesAddDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartLinesAdd', 'mutation', variables);
955
943
  },
956
944
  cartLinesRemove(variables, requestHeaders) {
957
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesRemoveDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "cartLinesRemove", "mutation", variables);
945
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CartLinesRemoveDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'cartLinesRemove', 'mutation', variables);
958
946
  },
959
947
  customerCreate(variables, requestHeaders) {
960
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerCreateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "customerCreate", "mutation", variables);
948
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerCreateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'customerCreate', 'mutation', variables);
961
949
  },
962
950
  customerAccessTokenCreate(variables, requestHeaders) {
963
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerAccessTokenCreateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "customerAccessTokenCreate", "mutation", variables);
951
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerAccessTokenCreateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'customerAccessTokenCreate', 'mutation', variables);
964
952
  },
965
953
  customerUpdate(variables, requestHeaders) {
966
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "customerUpdate", "mutation", variables);
954
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerUpdateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'customerUpdate', 'mutation', variables);
967
955
  },
968
956
  getCustomer(variables, requestHeaders) {
969
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCustomerDocument, variables, {
970
- ...requestHeaders,
971
- ...wrappedRequestHeaders,
972
- }), "getCustomer", "query", variables);
957
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCustomerDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getCustomer', 'query', variables);
973
958
  },
974
959
  customerRecover(variables, requestHeaders) {
975
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerRecoverDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "customerRecover", "mutation", variables);
960
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.CustomerRecoverDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'customerRecover', 'mutation', variables);
976
961
  },
977
962
  GetBlogs(variables, requestHeaders) {
978
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetBlogsDocument, variables, {
979
- ...requestHeaders,
980
- ...wrappedRequestHeaders,
981
- }), "GetBlogs", "query", variables);
963
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetBlogsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetBlogs', 'query', variables);
982
964
  },
983
965
  GetBlog(variables, requestHeaders) {
984
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetBlogDocument, variables, {
985
- ...requestHeaders,
986
- ...wrappedRequestHeaders,
987
- }), "GetBlog", "query", variables);
966
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetBlogDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetBlog', 'query', variables);
988
967
  },
989
968
  GetArticles(variables, requestHeaders) {
990
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetArticlesDocument, variables, {
991
- ...requestHeaders,
992
- ...wrappedRequestHeaders,
993
- }), "GetArticles", "query", variables);
969
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetArticlesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'GetArticles', 'query', variables);
994
970
  },
995
971
  getSingleArticle(variables, requestHeaders) {
996
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetSingleArticleDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getSingleArticle", "query", variables);
972
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetSingleArticleDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getSingleArticle', 'query', variables);
997
973
  },
998
974
  getCustomerOrders(variables, requestHeaders) {
999
- return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCustomerOrdersDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getCustomerOrders", "query", variables);
1000
- },
975
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(exports.GetCustomerOrdersDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getCustomerOrders', 'query', variables);
976
+ }
1001
977
  };
1002
978
  }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CartManager = void 0;
4
+ /**
5
+ * A stateful high-level manager for a Shopify Cart.
6
+ * Automatically handles lazy creation of the cart if an ID is not provided.
7
+ */
8
+ class CartManager {
9
+ constructor(sdk, cartId) {
10
+ this.sdk = sdk;
11
+ this.id = cartId || null;
12
+ }
13
+ /**
14
+ * Ensures a cart exists. If not, it creates one and stores the ID.
15
+ */
16
+ async ensureCart() {
17
+ var _a, _b;
18
+ if (!this.id) {
19
+ const res = await this.sdk.createCart({ input: {}, first: 250 });
20
+ this.id = ((_b = (_a = res.cartCreate) === null || _a === void 0 ? void 0 : _a.cart) === null || _b === void 0 ? void 0 : _b.id) || null;
21
+ if (!this.id) {
22
+ throw new Error("Failed to create cart during lazy initialization.");
23
+ }
24
+ }
25
+ }
26
+ /**
27
+ * Fetches the latest cart details.
28
+ */
29
+ async get(first = 250) {
30
+ await this.ensureCart();
31
+ return this.sdk.getCart({ cartId: this.id, first });
32
+ }
33
+ /**
34
+ * Adds line items to the cart. Creates the cart if it doesn't exist.
35
+ */
36
+ async addLines(lines) {
37
+ await this.ensureCart();
38
+ return this.sdk.addCartLines({ cartId: this.id, lines });
39
+ }
40
+ /**
41
+ * Removes line items from the cart. Creates the cart if it doesn't exist.
42
+ */
43
+ async removeLines(lineIds) {
44
+ await this.ensureCart();
45
+ return this.sdk.removeCartLines({ cartId: this.id, lineIds });
46
+ }
47
+ /**
48
+ * Updates line items in the cart (e.g. modifying quantity).
49
+ */
50
+ async updateLines(lines, first = 250) {
51
+ await this.ensureCart();
52
+ return this.sdk.updateCartLines({ cartId: this.id, lines, first });
53
+ }
54
+ }
55
+ exports.CartManager = CartManager;