@drawbridge/drawbridge-utils 0.0.176 → 0.0.177

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 (69) hide show
  1. package/dist/admin-B9ZaLvan.d.cts +697 -0
  2. package/dist/admin-C3HtEM6h.d.ts +697 -0
  3. package/dist/billing-Bc4yo9XG.d.cts +175 -0
  4. package/dist/billing-mNsKflmQ.d.ts +175 -0
  5. package/dist/billing.d.cts +1 -1
  6. package/dist/billing.d.ts +1 -1
  7. package/dist/connections/index.cjs +3077 -228
  8. package/dist/connections/index.d.cts +13 -4
  9. package/dist/connections/index.d.ts +13 -4
  10. package/dist/connections/index.js +3107 -255
  11. package/dist/features.cjs +2940 -226
  12. package/dist/features.d.cts +13 -4
  13. package/dist/features.d.ts +13 -4
  14. package/dist/features.js +2980 -260
  15. package/dist/http.cjs +10 -1
  16. package/dist/http.d.cts +10 -1
  17. package/dist/http.d.ts +10 -1
  18. package/dist/http.js +10 -1
  19. package/dist/{index-B8JhYfvU.d.ts → index-B546oDNo.d.ts} +2837 -956
  20. package/dist/{index-qY18QITf.d.cts → index-C59xHago.d.cts} +2837 -956
  21. package/dist/oauth/index.d.cts +1 -1
  22. package/dist/oauth/index.d.ts +1 -1
  23. package/dist/oauth-BJDh0sdM.d.cts +527 -0
  24. package/dist/oauth-DveZMLHx.d.ts +527 -0
  25. package/dist/partner-BOZltuh2.d.ts +94 -0
  26. package/dist/partner-ed2OfW1J.d.cts +94 -0
  27. package/dist/plans.cjs +2939 -225
  28. package/dist/plans.d.cts +13 -4
  29. package/dist/plans.d.ts +13 -4
  30. package/dist/plans.js +2980 -260
  31. package/dist/pricing.cjs +2972 -258
  32. package/dist/pricing.d.cts +13 -4
  33. package/dist/pricing.d.ts +13 -4
  34. package/dist/pricing.js +2977 -257
  35. package/dist/providers.cjs +2942 -247
  36. package/dist/providers.d.cts +12 -3
  37. package/dist/providers.d.ts +12 -3
  38. package/dist/providers.js +2946 -245
  39. package/dist/sendgrid.cjs +10 -1
  40. package/dist/sendgrid.js +10 -1
  41. package/dist/shopify/admin.cjs +562 -0
  42. package/dist/shopify/admin.d.cts +3 -0
  43. package/dist/shopify/admin.d.ts +3 -0
  44. package/dist/shopify/admin.js +528 -0
  45. package/dist/shopify/billing.cjs +166 -0
  46. package/dist/shopify/billing.d.cts +3 -0
  47. package/dist/shopify/billing.d.ts +3 -0
  48. package/dist/shopify/billing.js +140 -0
  49. package/dist/shopify/constants.cjs +63 -0
  50. package/dist/shopify/constants.d.cts +58 -0
  51. package/dist/shopify/constants.d.ts +58 -0
  52. package/dist/shopify/constants.js +32 -0
  53. package/dist/shopify/oauth.cjs +509 -0
  54. package/dist/shopify/oauth.d.cts +7 -0
  55. package/dist/shopify/oauth.d.ts +7 -0
  56. package/dist/shopify/oauth.js +466 -0
  57. package/dist/shopify/partner.cjs +156 -0
  58. package/dist/shopify/partner.d.cts +3 -0
  59. package/dist/shopify/partner.d.ts +3 -0
  60. package/dist/shopify/partner.js +130 -0
  61. package/dist/shopify/storefront.cjs +611 -0
  62. package/dist/shopify/storefront.d.cts +3 -0
  63. package/dist/shopify/storefront.d.ts +3 -0
  64. package/dist/shopify/storefront.js +576 -0
  65. package/dist/storefront-C8FKOGeD.d.cts +659 -0
  66. package/dist/storefront-DJFGLqPl.d.ts +659 -0
  67. package/dist/twilio.cjs +10 -1
  68. package/dist/twilio.js +10 -1
  69. package/package.json +98 -68
package/dist/sendgrid.cjs CHANGED
@@ -31,6 +31,15 @@ module.exports = __toCommonJS(sendgrid_exports);
31
31
  var DEFAULT_TIMEOUT_MS = 15e3;
32
32
  var request = async ({
33
33
  body,
34
+ // THE TRANSPORT, injectable and defaulted to the real one.
35
+ //
36
+ // Every other vendor client in this package takes a `fetcher` — it is how
37
+ // klaviyo, mailchimp and attentive are tested without a network, and it is a
38
+ // declared HOOK_OPTION. The Shopify client had no seam at all, so the only way
39
+ // to test a hook that used it was to inject the whole SDK namespace; that
40
+ // injection existed to work around an import cycle, and when the cycle went
41
+ // the tests lost their only hold. This is the seam they should have had.
42
+ fetcher = fetch,
34
43
  headers = {},
35
44
  method = "GET",
36
45
  query,
@@ -44,7 +53,7 @@ var request = async ({
44
53
  }
45
54
  ;
46
55
  const isForm = type === "form";
47
- const response = await fetch(fullUrl.toString(), {
56
+ const response = await fetcher(fullUrl.toString(), {
48
57
  method,
49
58
  headers: {
50
59
  "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json",
package/dist/sendgrid.js CHANGED
@@ -2,6 +2,15 @@
2
2
  var DEFAULT_TIMEOUT_MS = 15e3;
3
3
  var request = async ({
4
4
  body,
5
+ // THE TRANSPORT, injectable and defaulted to the real one.
6
+ //
7
+ // Every other vendor client in this package takes a `fetcher` — it is how
8
+ // klaviyo, mailchimp and attentive are tested without a network, and it is a
9
+ // declared HOOK_OPTION. The Shopify client had no seam at all, so the only way
10
+ // to test a hook that used it was to inject the whole SDK namespace; that
11
+ // injection existed to work around an import cycle, and when the cycle went
12
+ // the tests lost their only hold. This is the seam they should have had.
13
+ fetcher = fetch,
5
14
  headers = {},
6
15
  method = "GET",
7
16
  query,
@@ -15,7 +24,7 @@ var request = async ({
15
24
  }
16
25
  ;
17
26
  const isForm = type === "form";
18
- const response = await fetch(fullUrl.toString(), {
27
+ const response = await fetcher(fullUrl.toString(), {
19
28
  method,
20
29
  headers: {
21
30
  "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json",
@@ -0,0 +1,562 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // lib/shopify/admin.js
20
+ var admin_exports = {};
21
+ __export(admin_exports, {
22
+ adminFetch: () => adminFetch,
23
+ createDiscountCode: () => createDiscountCode,
24
+ createUsageRecord: () => createUsageRecord,
25
+ createUsageSubscription: () => createUsageSubscription,
26
+ getActiveAppSubscriptions: () => getActiveAppSubscriptions,
27
+ getDiscounts: () => getDiscounts,
28
+ getOrCreateCustomer: () => getOrCreateCustomer,
29
+ getProductInventory: () => getProductInventory,
30
+ sendProductResourceFeedback: () => sendProductResourceFeedback
31
+ });
32
+ module.exports = __toCommonJS(admin_exports);
33
+
34
+ // lib/http.js
35
+ var DEFAULT_TIMEOUT_MS = 15e3;
36
+ var request = async ({
37
+ body,
38
+ // THE TRANSPORT, injectable and defaulted to the real one.
39
+ //
40
+ // Every other vendor client in this package takes a `fetcher` — it is how
41
+ // klaviyo, mailchimp and attentive are tested without a network, and it is a
42
+ // declared HOOK_OPTION. The Shopify client had no seam at all, so the only way
43
+ // to test a hook that used it was to inject the whole SDK namespace; that
44
+ // injection existed to work around an import cycle, and when the cycle went
45
+ // the tests lost their only hold. This is the seam they should have had.
46
+ fetcher = fetch,
47
+ headers = {},
48
+ method = "GET",
49
+ query,
50
+ timeout = DEFAULT_TIMEOUT_MS,
51
+ type = "json",
52
+ url
53
+ }) => {
54
+ const fullUrl = new URL(url);
55
+ if (query) {
56
+ Object.entries(query).forEach(([k, v]) => fullUrl.searchParams.set(k, v));
57
+ }
58
+ ;
59
+ const isForm = type === "form";
60
+ const response = await fetcher(fullUrl.toString(), {
61
+ method,
62
+ headers: {
63
+ "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json",
64
+ ...headers
65
+ },
66
+ signal: AbortSignal.timeout(timeout),
67
+ ...body !== void 0 && {
68
+ body: isForm ? new URLSearchParams(body).toString() : JSON.stringify(body)
69
+ }
70
+ });
71
+ if (!response.ok) {
72
+ const text2 = await response.text().catch(() => "");
73
+ const error = new Error(text2 || response.statusText);
74
+ error.status = response.status;
75
+ throw error;
76
+ }
77
+ ;
78
+ const text = await response.text();
79
+ try {
80
+ return text ? JSON.parse(text) : null;
81
+ } catch {
82
+ return null;
83
+ }
84
+ };
85
+
86
+ // lib/shopify/constants.js
87
+ var SHOPIFY_ADMIN_API_VERSION = "2026-04";
88
+ var REFRESH_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1e3;
89
+ var ACCESS_TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
90
+ var PARTNER_API_VERSION = process.env.SHOPIFY_PARTNER_API_VERSION || "2026-07";
91
+
92
+ // lib/shopify/admin.js
93
+ var adminUrl = (domain) => `https://${domain}/admin/api/${SHOPIFY_ADMIN_API_VERSION}`;
94
+ var adminFetch = async ({ adminAccessToken, domain, fetcher, query, variables }) => {
95
+ var _a;
96
+ const { data, errors } = await request({
97
+ fetcher,
98
+ method: "POST",
99
+ url: adminUrl(domain) + "/graphql.json",
100
+ headers: {
101
+ "X-Shopify-Access-Token": adminAccessToken
102
+ },
103
+ body: {
104
+ query,
105
+ ...variables && { variables }
106
+ }
107
+ });
108
+ if (errors) {
109
+ throw new Error("Shopify GraphQL error: " + ((_a = errors[0]) == null ? void 0 : _a.message));
110
+ }
111
+ ;
112
+ return data;
113
+ };
114
+ var DISCOUNT_FIELDS = `
115
+ title
116
+ status
117
+ startsAt
118
+ endsAt
119
+ usageLimit
120
+ asyncUsageCount
121
+ appliesOncePerCustomer
122
+ context { __typename }
123
+ `;
124
+ var discountsQuery = (search, cursor, limit) => `{
125
+ codeDiscountNodes(first: ${limit}${search ? `, query: "title:*${search}*"` : ""}${cursor ? `, after: "${cursor}"` : ""}) {
126
+ edges {
127
+ node {
128
+ id
129
+ codeDiscount {
130
+ ... on DiscountCodeBasic { ${DISCOUNT_FIELDS} }
131
+ ... on DiscountCodeBxgy { ${DISCOUNT_FIELDS} }
132
+ ... on DiscountCodeFreeShipping { ${DISCOUNT_FIELDS} }
133
+ ... on DiscountCodeApp { ${DISCOUNT_FIELDS} }
134
+ }
135
+ }
136
+ }
137
+ pageInfo {
138
+ endCursor
139
+ hasNextPage
140
+ hasPreviousPage
141
+ startCursor
142
+ }
143
+ }
144
+ }`;
145
+ var getDiscounts = async ({ fetcher, adminAccessToken, domain, search, cursor, limit }) => {
146
+ const data = await adminFetch({
147
+ fetcher,
148
+ adminAccessToken,
149
+ domain,
150
+ query: discountsQuery(search, cursor, limit)
151
+ });
152
+ return data == null ? void 0 : data.codeDiscountNodes;
153
+ };
154
+ var discountGid = (id) => String(id).startsWith("gid://") ? String(id) : "gid://shopify/DiscountCodeNode/" + id;
155
+ var createDiscountCode = async ({ fetcher, adminAccessToken, domain, discountId, code }) => {
156
+ var _a, _b, _c, _d, _e, _f, _g, _h;
157
+ const added = await adminFetch({
158
+ fetcher,
159
+ adminAccessToken,
160
+ domain,
161
+ query: `
162
+ mutation DiscountRedeemCodeBulkAdd($discountId: ID!, $codes: [DiscountRedeemCodeInput!]!) {
163
+ discountRedeemCodeBulkAdd(discountId: $discountId, codes: $codes) {
164
+ bulkCreation {
165
+ id
166
+ }
167
+ userErrors {
168
+ field
169
+ message
170
+ }
171
+ }
172
+ }
173
+ `,
174
+ variables: {
175
+ codes: [{ code }],
176
+ discountId: discountGid(discountId)
177
+ }
178
+ });
179
+ const addErrors = (_a = added == null ? void 0 : added.discountRedeemCodeBulkAdd) == null ? void 0 : _a.userErrors;
180
+ if (addErrors == null ? void 0 : addErrors.length) {
181
+ throw new Error("Shopify discount code create failed: " + addErrors[0].message);
182
+ }
183
+ ;
184
+ const bulkCreationId = (_c = (_b = added == null ? void 0 : added.discountRedeemCodeBulkAdd) == null ? void 0 : _b.bulkCreation) == null ? void 0 : _c.id;
185
+ if (!bulkCreationId) {
186
+ throw new Error("Shopify discount code create failed: no bulk creation id returned");
187
+ }
188
+ ;
189
+ for (let attempt = 0; attempt < 15; attempt++) {
190
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
191
+ const polled = await adminFetch({
192
+ fetcher,
193
+ adminAccessToken,
194
+ domain,
195
+ query: `
196
+ query DiscountRedeemCodeBulkCreationPoll($id: ID!) {
197
+ discountRedeemCodeBulkCreation(id: $id) {
198
+ done
199
+ codes(first: 1) {
200
+ nodes {
201
+ code
202
+ discountRedeemCode {
203
+ id
204
+ }
205
+ errors {
206
+ message
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ `,
213
+ variables: {
214
+ id: bulkCreationId
215
+ }
216
+ });
217
+ const creation = polled == null ? void 0 : polled.discountRedeemCodeBulkCreation;
218
+ if (!(creation == null ? void 0 : creation.done)) continue;
219
+ const node = (_e = (_d = creation.codes) == null ? void 0 : _d.nodes) == null ? void 0 : _e[0];
220
+ if (!((_f = node == null ? void 0 : node.discountRedeemCode) == null ? void 0 : _f.id)) {
221
+ throw new Error("Shopify discount code create failed: " + (((_h = (_g = node == null ? void 0 : node.errors) == null ? void 0 : _g[0]) == null ? void 0 : _h.message) || "code was not created"));
222
+ }
223
+ ;
224
+ return {
225
+ code: node.code,
226
+ // Numeric tail keeps the stored shopifyDiscountId in the shape the
227
+ // legacy REST endpoint returned — it feeds a merchant-visible
228
+ // workflow template variable, so no gid:// leakage.
229
+ id: node.discountRedeemCode.id.split("/").pop()
230
+ };
231
+ }
232
+ ;
233
+ throw new Error("Shopify discount code create timed out waiting for bulk creation " + bulkCreationId);
234
+ };
235
+ var getOrCreateCustomer = async ({ fetcher, adminAccessToken, domain, email, firstName, lastName, source }) => {
236
+ var _a, _b, _c, _d, _e, _f, _g, _h;
237
+ const lookupQuery = `
238
+ query customerByEmail( $query : String! ) {
239
+ customers( first : 1, query : $query ) {
240
+ edges {
241
+ node {
242
+ id
243
+ }
244
+ }
245
+ }
246
+ }
247
+ `;
248
+ const data = await adminFetch({
249
+ fetcher,
250
+ adminAccessToken,
251
+ domain,
252
+ query: lookupQuery,
253
+ variables: { query: "email:" + email }
254
+ });
255
+ const existing = (_c = (_b = (_a = data == null ? void 0 : data.customers) == null ? void 0 : _a.edges) == null ? void 0 : _b[0]) == null ? void 0 : _c.node;
256
+ if (existing) return existing;
257
+ const input = { email };
258
+ if (firstName) input.firstName = firstName;
259
+ if (lastName) input.lastName = lastName;
260
+ if (source) {
261
+ input.metafields = [{
262
+ namespace: "drwbrdg",
263
+ key: "source",
264
+ type: "single_line_text_field",
265
+ value: source
266
+ }];
267
+ }
268
+ ;
269
+ const result = await adminFetch({
270
+ fetcher,
271
+ adminAccessToken,
272
+ domain,
273
+ query: `
274
+ mutation customerCreate( $input : CustomerInput! ) {
275
+ customerCreate( input : $input ) {
276
+ customer {
277
+ id
278
+ }
279
+ userErrors {
280
+ field
281
+ message
282
+ }
283
+ }
284
+ }
285
+ `,
286
+ variables: { input }
287
+ });
288
+ const userErrors = (_d = result == null ? void 0 : result.customerCreate) == null ? void 0 : _d.userErrors;
289
+ if (userErrors == null ? void 0 : userErrors.length) {
290
+ const emailTaken = userErrors.some((e) => {
291
+ var _a2;
292
+ return (_a2 = e.message) == null ? void 0 : _a2.includes("Email has already been taken");
293
+ });
294
+ if (emailTaken) {
295
+ const retry = await adminFetch({
296
+ fetcher,
297
+ adminAccessToken,
298
+ domain,
299
+ query: lookupQuery,
300
+ variables: { query: "email:" + email }
301
+ });
302
+ const found = (_g = (_f = (_e = retry == null ? void 0 : retry.customers) == null ? void 0 : _e.edges) == null ? void 0 : _f[0]) == null ? void 0 : _g.node;
303
+ if (found) return found;
304
+ }
305
+ ;
306
+ throw new Error("Shopify customer create failed: " + userErrors[0].message);
307
+ }
308
+ ;
309
+ return (_h = result == null ? void 0 : result.customerCreate) == null ? void 0 : _h.customer;
310
+ };
311
+ var getActiveAppSubscriptions = async ({ fetcher, adminAccessToken, domain }) => {
312
+ var _a, _b;
313
+ const data = await adminFetch({
314
+ fetcher,
315
+ adminAccessToken,
316
+ domain,
317
+ query: `{
318
+ currentAppInstallation {
319
+ activeSubscriptions {
320
+ id
321
+ name
322
+ status
323
+ test
324
+ lineItems {
325
+ id
326
+ plan {
327
+ pricingDetails {
328
+ __typename
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ shop {
335
+ myshopifyDomain
336
+ }
337
+ }`
338
+ });
339
+ return {
340
+ shopDomain: ((_a = data == null ? void 0 : data.shop) == null ? void 0 : _a.myshopifyDomain) || null,
341
+ subscriptions: (((_b = data == null ? void 0 : data.currentAppInstallation) == null ? void 0 : _b.activeSubscriptions) || []).map((subscription) => {
342
+ var _a2;
343
+ return {
344
+ ...subscription,
345
+ metered: ((subscription == null ? void 0 : subscription.lineItems) || []).some(
346
+ (item) => {
347
+ var _a3, _b2;
348
+ return ((_b2 = (_a3 = item == null ? void 0 : item.plan) == null ? void 0 : _a3.pricingDetails) == null ? void 0 : _b2.__typename) === "AppUsagePricing";
349
+ }
350
+ ),
351
+ // The usage line's own id — the address appUsageRecordCreate charges
352
+ // against. Null when the approval carries no usage component.
353
+ usageLineItemId: ((_a2 = ((subscription == null ? void 0 : subscription.lineItems) || []).find(
354
+ (item) => {
355
+ var _a3, _b2;
356
+ return ((_b2 = (_a3 = item == null ? void 0 : item.plan) == null ? void 0 : _a3.pricingDetails) == null ? void 0 : _b2.__typename) === "AppUsagePricing";
357
+ }
358
+ )) == null ? void 0 : _a2.id) || null
359
+ };
360
+ })
361
+ };
362
+ };
363
+ var createUsageSubscription = async ({ fetcher, adminAccessToken, cappedAmount, currencyCode = "USD", domain, name, recurringPrice = 0, returnUrl, terms, test = false }) => {
364
+ if (!name || !returnUrl || !terms || !(Number(cappedAmount) > 0)) {
365
+ throw new Error("createUsageSubscription requires name, returnUrl, terms, and a positive cappedAmount");
366
+ }
367
+ ;
368
+ const data = await adminFetch({
369
+ fetcher,
370
+ adminAccessToken,
371
+ domain,
372
+ query: `mutation createUsageSubscription( $lineItems : [AppSubscriptionLineItemInput!]!, $name : String!, $returnUrl : URL!, $test : Boolean ) {
373
+ appSubscriptionCreate( lineItems : $lineItems, name : $name, returnUrl : $returnUrl, test : $test ) {
374
+ appSubscription { id name status test lineItems { id plan { pricingDetails { __typename } } } }
375
+ confirmationUrl
376
+ userErrors { field message }
377
+ }
378
+ }`,
379
+ variables: {
380
+ lineItems: [
381
+ {
382
+ plan: {
383
+ appRecurringPricingDetails: {
384
+ interval: "EVERY_30_DAYS",
385
+ price: { amount: Number(recurringPrice), currencyCode }
386
+ }
387
+ }
388
+ },
389
+ {
390
+ plan: {
391
+ appUsagePricingDetails: {
392
+ cappedAmount: { amount: Number(cappedAmount), currencyCode },
393
+ terms
394
+ }
395
+ }
396
+ }
397
+ ],
398
+ name,
399
+ returnUrl,
400
+ test
401
+ }
402
+ });
403
+ const payload = data == null ? void 0 : data.appSubscriptionCreate;
404
+ const userErrors = (payload == null ? void 0 : payload.userErrors) || [];
405
+ if (userErrors.length) {
406
+ throw new Error("Shopify subscription create failed: " + userErrors.map((entry) => entry.message).join("; "));
407
+ }
408
+ ;
409
+ if (!(payload == null ? void 0 : payload.confirmationUrl)) {
410
+ throw new Error("Shopify subscription create failed: no confirmation url returned");
411
+ }
412
+ ;
413
+ return {
414
+ confirmationUrl: payload.confirmationUrl,
415
+ subscription: payload.appSubscription
416
+ };
417
+ };
418
+ var createUsageRecord = async ({ fetcher, adminAccessToken, amount, currencyCode = "USD", description, domain, idempotencyKey, subscriptionLineItemId }) => {
419
+ var _a;
420
+ if (!subscriptionLineItemId || !description || !(Number(amount) > 0)) {
421
+ throw new Error("createUsageRecord requires subscriptionLineItemId, description, and a positive amount");
422
+ }
423
+ ;
424
+ const data = await adminFetch({
425
+ fetcher,
426
+ adminAccessToken,
427
+ domain,
428
+ query: `mutation createUsageRecord( $description : String!, $idempotencyKey : String, $price : MoneyInput!, $subscriptionLineItemId : ID! ) {
429
+ appUsageRecordCreate( description : $description, idempotencyKey : $idempotencyKey, price : $price, subscriptionLineItemId : $subscriptionLineItemId ) {
430
+ appUsageRecord { id }
431
+ userErrors { field message }
432
+ }
433
+ }`,
434
+ variables: {
435
+ description,
436
+ idempotencyKey: idempotencyKey ? String(idempotencyKey) : null,
437
+ price: { amount: Number(amount), currencyCode },
438
+ subscriptionLineItemId
439
+ }
440
+ });
441
+ const payload = data == null ? void 0 : data.appUsageRecordCreate;
442
+ const userErrors = (payload == null ? void 0 : payload.userErrors) || [];
443
+ if (userErrors.length || !((_a = payload == null ? void 0 : payload.appUsageRecord) == null ? void 0 : _a.id)) {
444
+ throw new Error("Shopify usage record failed: " + (userErrors.map((entry) => entry.message).join("; ") || "no record returned"));
445
+ }
446
+ ;
447
+ return { id: payload.appUsageRecord.id };
448
+ };
449
+ var getProductInventory = async ({ fetcher, adminAccessToken, domain, productId }) => {
450
+ var _a, _b;
451
+ const data = await adminFetch({
452
+ fetcher,
453
+ adminAccessToken,
454
+ domain,
455
+ query: `{
456
+ product( id : "${productId}" ) {
457
+ variants( first : 100 ) {
458
+ edges {
459
+ node {
460
+ id
461
+ inventoryQuantity
462
+ }
463
+ }
464
+ }
465
+ }
466
+ }`
467
+ });
468
+ const edges = ((_b = (_a = data == null ? void 0 : data.product) == null ? void 0 : _a.variants) == null ? void 0 : _b.edges) || [];
469
+ return edges.reduce((accumulator, edge) => {
470
+ var _a2, _b2;
471
+ const id = (_a2 = edge == null ? void 0 : edge.node) == null ? void 0 : _a2.id;
472
+ const quantity = (_b2 = edge == null ? void 0 : edge.node) == null ? void 0 : _b2.inventoryQuantity;
473
+ if (id) {
474
+ accumulator[id] = Number.isFinite(quantity) ? quantity : 0;
475
+ }
476
+ ;
477
+ return accumulator;
478
+ }, {});
479
+ };
480
+ var getProductUpdatedAt = async ({ adminAccessToken, domain, fetcher, productId }) => {
481
+ var _a;
482
+ const data = await adminFetch({
483
+ fetcher,
484
+ adminAccessToken,
485
+ domain,
486
+ query: `
487
+ query ProductUpdatedAt($id: ID!) {
488
+ product(id: $id) {
489
+ updatedAt
490
+ }
491
+ }
492
+ `,
493
+ variables: { id: productId }
494
+ });
495
+ return ((_a = data == null ? void 0 : data.product) == null ? void 0 : _a.updatedAt) || null;
496
+ };
497
+ var NOT_ON_CHANNEL = "not available to the channel";
498
+ var OUTDATED_FEEDBACK = "later version";
499
+ var sendProductResourceFeedback = async ({ fetcher, adminAccessToken, domain, productId, state, messages = [] }) => {
500
+ var _a, _b, _c;
501
+ const productUpdatedAt = await getProductUpdatedAt({ adminAccessToken, domain, fetcher, productId });
502
+ if (!productUpdatedAt) return null;
503
+ const now = (/* @__PURE__ */ new Date()).toISOString();
504
+ const submit = async (version) => {
505
+ const data = await adminFetch({
506
+ fetcher,
507
+ adminAccessToken,
508
+ domain,
509
+ query: `
510
+ mutation ProductFeedback($feedbackInput: [ProductResourceFeedbackInput!]!) {
511
+ bulkProductResourceFeedbackCreate(feedbackInput: $feedbackInput) {
512
+ feedback {
513
+ productId
514
+ state
515
+ }
516
+ userErrors {
517
+ field
518
+ message
519
+ }
520
+ }
521
+ }
522
+ `,
523
+ variables: {
524
+ feedbackInput: [
525
+ {
526
+ productId,
527
+ state,
528
+ feedbackGeneratedAt: now,
529
+ productUpdatedAt: version,
530
+ messages
531
+ }
532
+ ]
533
+ }
534
+ });
535
+ return data == null ? void 0 : data.bulkProductResourceFeedbackCreate;
536
+ };
537
+ let result = await submit(productUpdatedAt);
538
+ if ((((_b = (_a = result == null ? void 0 : result.userErrors) == null ? void 0 : _a[0]) == null ? void 0 : _b.message) || "").toLowerCase().includes(OUTDATED_FEEDBACK)) {
539
+ result = await submit(now);
540
+ }
541
+ ;
542
+ const feedbackErrors = result == null ? void 0 : result.userErrors;
543
+ if (feedbackErrors == null ? void 0 : feedbackErrors.length) {
544
+ const message = feedbackErrors[0].message || "";
545
+ if (message.toLowerCase().includes(NOT_ON_CHANNEL)) return null;
546
+ throw new Error("Shopify product feedback failed: " + message);
547
+ }
548
+ ;
549
+ return ((_c = result == null ? void 0 : result.feedback) == null ? void 0 : _c[0]) || null;
550
+ };
551
+ // Annotate the CommonJS export names for ESM import in node:
552
+ 0 && (module.exports = {
553
+ adminFetch,
554
+ createDiscountCode,
555
+ createUsageRecord,
556
+ createUsageSubscription,
557
+ getActiveAppSubscriptions,
558
+ getDiscounts,
559
+ getOrCreateCustomer,
560
+ getProductInventory,
561
+ sendProductResourceFeedback
562
+ });
@@ -0,0 +1,3 @@
1
+ import '../http.cjs';
2
+ import './constants.cjs';
3
+ export { a as adminFetch, c as createDiscountCode, b as createUsageRecord, d as createUsageSubscription, g as getActiveAppSubscriptions, e as getDiscounts, f as getOrCreateCustomer, h as getProductInventory, s as sendProductResourceFeedback } from '../admin-B9ZaLvan.cjs';
@@ -0,0 +1,3 @@
1
+ import '../http.js';
2
+ import './constants.js';
3
+ export { a as adminFetch, c as createDiscountCode, b as createUsageRecord, d as createUsageSubscription, g as getActiveAppSubscriptions, e as getDiscounts, f as getOrCreateCustomer, h as getProductInventory, s as sendProductResourceFeedback } from '../admin-C3HtEM6h.js';