@curless/shopify-adapter 0.1.0 → 0.2.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 CHANGED
@@ -13,13 +13,14 @@ which prices and opens the checkout.
13
13
  npm install @curless/shopify-adapter
14
14
  ```
15
15
 
16
- ## The two halves
16
+ ## The three halves
17
17
 
18
18
  ```ts
19
19
  import {
20
20
  shopifyConfigFromEnv,
21
21
  fetchShopifyCatalog,
22
22
  writebackShopifyOrder,
23
+ refundShopifyOrder,
23
24
  } from '@curless/shopify-adapter';
24
25
 
25
26
  const shopify = shopifyConfigFromEnv(); // null unless SHOPIFY_* env is set
@@ -50,6 +51,23 @@ No money moves in Shopify — the order is marked **paid via an external transac
50
51
  and tagged `agentbank` + `protocol:…` + the agentbank order id, so it's traceable and
51
52
  never mistaken for a Shopify Payments sale.
52
53
 
54
+ **3. Refund** — when agentbank refunds the sale, stop the Shopify order reading as paid:
55
+
56
+ ```ts
57
+ // e.g. from your `order.refunded` webhook handler
58
+ await refundShopifyOrder(shopify, {
59
+ agentbankOrderId: [`order_${paymentIntentId}`, paymentIntentId], // any tag you wrote back with
60
+ reason: 'guest cancelled',
61
+ });
62
+ // → { refunded: true, id } | { refunded: false, reason }
63
+ ```
64
+
65
+ Like the writeback, this **records** the reversal rather than processing one: Shopify
66
+ never held this money, so the refund is created with no `transactions` and the order
67
+ goes to REFUNDED without Shopify trying to return funds it never took. Full-order only
68
+ — agentbank refunds the whole captured amount, and inventing a partial here would let
69
+ you record a reversal that doesn't match the money that actually went back.
70
+
53
71
  ## Notes
54
72
 
55
73
  - **Auth** is Shopify's 2026 **client-credentials** grant: a Dev Dashboard app no
@@ -69,6 +87,11 @@ never mistaken for a Shopify Payments sale.
69
87
  refresh, so two writebacks fired within a second can both miss and duplicate — add
70
88
  your own in-process guard on the order id if you fire them rapidly; the tag search
71
89
  is the cross-restart backstop.
90
+ - **Refunds are idempotent and safe to miss.** `refundShopifyOrder` takes one id or a
91
+ list, tries them in order, and returns `{refunded:false, reason}` — never throws —
92
+ when nothing matches or the order is already REFUNDED. Ids that could false-match a
93
+ Shopify search (spaces, operators) are dropped rather than searched: refunding the
94
+ wrong order is worse than refunding none.
72
95
  - **Pagination.** Products paginate to completion. A single product with more than
73
96
  250 variants has its tail dropped **with a warning** (not silently).
74
97
 
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI7D,KAAK,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IAGpB,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,WAAW,EAAE,OAAO,CAAA;SAAE,CAAC;QAAC,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;CAC1E,CAAC;AAUF,eAAO,MAAM,eAAe,GAC1B,UAAU,YAAY,EAAE,EACxB,cAAc,MAAM,EACpB,OAAM,CAAC,GAAG,EAAE,MAAM,KAAK,IAA4C,KAClE,WAAW,EA6Bb,CAAC;AAiCF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,aAAa,EACrB,YAAW,OAAO,KAAa,EAC/B,OAAM,CAAC,GAAG,EAAE,MAAM,KAAK,IAA4C,KAClE,OAAO,CAAC,WAAW,EAAE,CAkBvB,CAAC"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI7D,KAAK,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IAGpB,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,WAAW,EAAE,OAAO,CAAA;SAAE,CAAC;QAAC,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;CAC1E,CAAC;AAUF,eAAO,MAAM,eAAe,GAC1B,UAAU,YAAY,EAAE,EACxB,cAAc,MAAM,EACpB,OAAM,CAAC,GAAG,EAAE,MAAM,KAAK,IAA4C,KAClE,WAAW,EAuCb,CAAC;AAiCF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,aAAa,EACrB,YAAW,OAAO,KAAa,EAC/B,OAAM,CAAC,GAAG,EAAE,MAAM,KAAK,IAA4C,KAClE,OAAO,CAAC,WAAW,EAAE,CAkBvB,CAAC"}
package/dist/catalog.js CHANGED
@@ -22,10 +22,21 @@ export const productsToItems = (products, currencyCode, warn = (m) => console.wa
22
22
  warn(`skipping a "${p.title}" variant with no SKU`);
23
23
  continue;
24
24
  }
25
+ // A single unparseable price shouldn't take down the whole catalog load —
26
+ // skip and warn (toMinor rejects non-plain-decimal strings), so one bad
27
+ // product can't empty the merchant's catalog.
28
+ let priceMinor;
29
+ try {
30
+ priceMinor = toMinor(v.price, currencyCode);
31
+ }
32
+ catch {
33
+ warn(`skipping "${p.title}" (${v.sku}) — unparseable price ${JSON.stringify(v.price)}`);
34
+ continue;
35
+ }
25
36
  items.push({
26
37
  sku: v.sku,
27
38
  name: p.title,
28
- priceMinor: toMinor(v.price, currencyCode),
39
+ priceMinor,
29
40
  currency: currencyCode,
30
41
  description: p.description,
31
42
  imageUrl: p.featuredImage?.url,
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { shopifyConfigFromEnv, exchangeToken, shopifyGraphql } from './client.js';
2
2
  export { fetchShopifyCatalog, productsToItems } from './catalog.js';
3
- export { writebackShopifyOrder } from './orders.js';
3
+ export { writebackShopifyOrder, refundShopifyOrder } from './orders.js';
4
4
  export { decimalsFor, toMinor, toMajorString } from './money.js';
5
- export type { CatalogItem, ShopifyConfig, OrderWriteback, WritebackResult, } from './types.js';
5
+ export type { CatalogItem, ShopifyConfig, OrderWriteback, WritebackResult, OrderRefund, RefundResult, } from './types.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EACV,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EACV,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -10,8 +10,10 @@
10
10
  // // …after the agent pays through agentbank:
11
11
  // await writebackShopifyOrder(shopify, { variantId, quantity, protocol, agentbankOrderId,
12
12
  // unitPriceMinor, currency });
13
+ // // …and when agentbank refunds that sale (your `order.refunded` webhook):
14
+ // await refundShopifyOrder(shopify, { agentbankOrderId, reason });
13
15
  export { shopifyConfigFromEnv, exchangeToken, shopifyGraphql } from './client.js';
14
16
  export { fetchShopifyCatalog, productsToItems } from './catalog.js';
15
- export { writebackShopifyOrder } from './orders.js';
17
+ export { writebackShopifyOrder, refundShopifyOrder } from './orders.js';
16
18
  export { decimalsFor, toMinor, toMajorString } from './money.js';
17
19
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,uCAAuC;AACvC,EAAE;AACF,iFAAiF;AACjF,uFAAuF;AACvF,4EAA4E;AAC5E,gDAAgD;AAChD,4FAA4F;AAC5F,wEAAwE;AACxE,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,uCAAuC;AACvC,EAAE;AACF,iFAAiF;AACjF,uFAAuF;AACvF,4EAA4E;AAC5E,gDAAgD;AAChD,4FAA4F;AAC5F,wEAAwE;AACxE,8EAA8E;AAC9E,qEAAqE;AACrE,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/money.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  /** Minor-unit exponent for an ISO currency (default 2). */
2
2
  export declare const decimalsFor: (currency: string) => number;
3
- /** Decimal-string major amount ("2450.00") → integer minor units, for `currency`. */
3
+ /**
4
+ * Decimal-string major amount ("2450.00") → integer minor units, for `currency`.
5
+ * Accepts only a plain signed decimal — a thousands separator, scientific
6
+ * notation, or junk is REJECTED (throws) rather than silently becoming NaN or a
7
+ * wrong-magnitude/wrong-sign amount. The sign is applied to the whole value so a
8
+ * negative fraction can't flip positive (e.g. "-0.99" → -99, not +99).
9
+ */
4
10
  export declare const toMinor: (amount: string, currency: string) => number;
5
11
  /** Integer minor units → decimal-string major amount ("245000" → "2450.00"), for `currency`. */
6
12
  export declare const toMajorString: (minor: number, currency: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAmCA,2DAA2D;AAC3D,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,KAAG,MACG,CAAC;AAEnD,qFAAqF;AACrF,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAM1D,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,UAAU,MAAM,KAAG,MACM,CAAC"}
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAmCA,2DAA2D;AAC3D,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,KAAG,MACG,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAQ1D,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,UAAU,MAAM,KAAG,MACM,CAAC"}
package/dist/money.js CHANGED
@@ -33,13 +33,22 @@ const MINOR_UNIT_DECIMALS = {
33
33
  };
34
34
  /** Minor-unit exponent for an ISO currency (default 2). */
35
35
  export const decimalsFor = (currency) => MINOR_UNIT_DECIMALS[currency.toUpperCase()] ?? 2;
36
- /** Decimal-string major amount ("2450.00") → integer minor units, for `currency`. */
36
+ /**
37
+ * Decimal-string major amount ("2450.00") → integer minor units, for `currency`.
38
+ * Accepts only a plain signed decimal — a thousands separator, scientific
39
+ * notation, or junk is REJECTED (throws) rather than silently becoming NaN or a
40
+ * wrong-magnitude/wrong-sign amount. The sign is applied to the whole value so a
41
+ * negative fraction can't flip positive (e.g. "-0.99" → -99, not +99).
42
+ */
37
43
  export const toMinor = (amount, currency) => {
38
44
  const dp = decimalsFor(currency);
39
- const [wholeRaw = '0', fracRaw = ''] = amount.trim().split('.');
40
- const whole = wholeRaw === '' ? '0' : wholeRaw;
45
+ const m = /^(-?)(\d+)(?:\.(\d+))?$/.exec(amount.trim());
46
+ if (!m)
47
+ throw new Error(`toMinor: not a plain decimal amount: ${JSON.stringify(amount)}`);
48
+ const [, sign, wholeRaw, fracRaw = ''] = m;
41
49
  const frac = `${fracRaw}${'0'.repeat(dp)}`.slice(0, dp);
42
- return Number(whole) * 10 ** dp + (dp > 0 ? Number(frac) : 0);
50
+ const minor = Number(wholeRaw) * 10 ** dp + (dp > 0 ? Number(frac) : 0);
51
+ return sign === '-' ? -minor : minor;
43
52
  };
44
53
  /** Integer minor units → decimal-string major amount ("245000" → "2450.00"), for `currency`. */
45
54
  export const toMajorString = (minor, currency) => (minor / 10 ** decimalsFor(currency)).toFixed(decimalsFor(currency));
package/dist/money.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"money.js","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,gFAAgF;AAChF,4EAA4E;AAE5E,2EAA2E;AAC3E,uCAAuC;AACvC,MAAM,mBAAmB,GAA2B;IAClD,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;CACP,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAU,EAAE,CACtD,mBAAmB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;AAEnD,qFAAqF;AACrF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IAClE,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,CAAC,QAAQ,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/C,MAAM,IAAI,GAAG,GAAG,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,QAAgB,EAAU,EAAE,CACvE,CAAC,KAAK,GAAG,EAAE,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"money.js","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,gFAAgF;AAChF,4EAA4E;AAE5E,2EAA2E;AAC3E,uCAAuC;AACvC,MAAM,mBAAmB,GAA2B;IAClD,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;CACP,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAU,EAAE,CACtD,mBAAmB,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IAClE,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1F,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,GAAG,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACvC,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,QAAgB,EAAU,EAAE,CACvE,CAAC,KAAK,GAAG,EAAE,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC"}
package/dist/orders.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- import type { OrderWriteback, ShopifyConfig, WritebackResult } from './types.js';
1
+ import type { OrderRefund, OrderWriteback, RefundResult, ShopifyConfig, WritebackResult } from './types.js';
2
2
  export declare const writebackShopifyOrder: (config: ShopifyConfig, input: OrderWriteback, fetchImpl?: typeof fetch) => Promise<WritebackResult>;
3
+ export declare const refundShopifyOrder: (config: ShopifyConfig, input: OrderRefund, fetchImpl?: typeof fetch) => Promise<RefundResult>;
3
4
  //# sourceMappingURL=orders.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMjF,eAAO,MAAM,qBAAqB,GAChC,QAAQ,aAAa,EACrB,OAAO,cAAc,EACrB,YAAW,OAAO,KAAa,KAC9B,OAAO,CAAC,eAAe,CAoDzB,CAAC"}
1
+ {"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,YAAY,EACZ,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAMpB,eAAO,MAAM,qBAAqB,GAChC,QAAQ,aAAa,EACrB,OAAO,cAAc,EACrB,YAAW,OAAO,KAAa,KAC9B,OAAO,CAAC,eAAe,CA6DzB,CAAC;AAeF,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,aAAa,EACrB,OAAO,WAAW,EAClB,YAAW,OAAO,KAAa,KAC9B,OAAO,CAAC,YAAY,CAkEtB,CAAC"}
package/dist/orders.js CHANGED
@@ -17,16 +17,25 @@ const FIND_BY_TAG = 'query($q:String!){ orders(first:1, query:$q){ nodes{ id nam
17
17
  const ORDER_CREATE = 'mutation($o:OrderCreateOrderInput!){ orderCreate(order:$o){ order{ id name } userErrors{ field message } } }';
18
18
  export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) => {
19
19
  const token = await exchangeToken(config, fetchImpl);
20
+ // Only use the order id for idempotency if it's a safe, tag-searchable token —
21
+ // real ids (pi_…/ord_…/UUID) always are. A value with a space or a Shopify
22
+ // search operator would make `tag:${id}` false-match an unrelated order (and
23
+ // silently drop the writeback), and Shopify normalizes odd tags so the stored
24
+ // tag wouldn't equal the searched one (→ a duplicate). An unsafe id degrades to
25
+ // no-dedupe (create anyway), never mis-dedupe.
26
+ const idemTag = input.agentbankOrderId && /^[A-Za-z0-9_.:-]{1,255}$/.test(input.agentbankOrderId)
27
+ ? input.agentbankOrderId
28
+ : undefined;
20
29
  // Idempotency: find an existing order tagged with this agentbank order id.
21
- if (input.agentbankOrderId) {
22
- const found = await shopifyGraphql(config, token, FIND_BY_TAG, { q: `tag:${input.agentbankOrderId}` }, fetchImpl);
30
+ if (idemTag) {
31
+ const found = await shopifyGraphql(config, token, FIND_BY_TAG, { q: `tag:${idemTag}` }, fetchImpl);
23
32
  const existing = found.orders.nodes[0];
24
33
  if (existing)
25
34
  return { created: false, reason: `already written back (${existing.name})` };
26
35
  }
27
36
  const tags = ['agentbank', `protocol:${input.protocol}`];
28
- if (input.agentbankOrderId)
29
- tags.push(input.agentbankOrderId);
37
+ if (idemTag)
38
+ tags.push(idemTag);
30
39
  const note = `Paid via agentbank · protocol ${input.protocol}${input.agentbankOrderId ? ` · order ${input.agentbankOrderId}` : ''}`;
31
40
  const lineItem = {
32
41
  variantId: `gid://shopify/ProductVariant/${input.variantId}`,
@@ -37,11 +46,9 @@ export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) =>
37
46
  // variant's current price. Omitting unitPriceMinor/currency keeps the variant
38
47
  // price (Shopify's default).
39
48
  if (input.unitPriceMinor != null && input.currency) {
49
+ const currencyCode = input.currency.toUpperCase(); // Shopify's CurrencyCode enum is upper-case
40
50
  lineItem.priceSet = {
41
- shopMoney: {
42
- amount: toMajorString(input.unitPriceMinor, input.currency),
43
- currencyCode: input.currency,
44
- },
51
+ shopMoney: { amount: toMajorString(input.unitPriceMinor, currencyCode), currencyCode },
45
52
  };
46
53
  }
47
54
  const data = await shopifyGraphql(config, token, ORDER_CREATE, { o: { lineItems: [lineItem], financialStatus: 'PAID', note, tags } }, fetchImpl);
@@ -53,4 +60,60 @@ export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) =>
53
60
  return { created: false, reason: 'orderCreate returned no order' };
54
61
  return { created: true, name: order.name, id: order.id };
55
62
  };
63
+ const FIND_FOR_REFUND = 'query($q:String!){ orders(first:1, query:$q){ nodes{ id name displayFinancialStatus ' +
64
+ 'lineItems(first:50){ nodes{ id quantity } } } } }';
65
+ const REFUND_CREATE = 'mutation($i:RefundInput!){ refundCreate(input:$i){ refund{ id } userErrors{ field message } } }';
66
+ // Mark an agentbank-settled Shopify order as refunded. See OrderRefund for why
67
+ // this records a refund rather than processing one.
68
+ //
69
+ // Deliberately full-order only: agentbank refunds the whole captured amount
70
+ // (Curless refunds nothing else), so every line goes back in full. A partial
71
+ // would need to say WHICH lines and how many, and inventing that here would let
72
+ // a caller record a refund that doesn't match the money actually returned.
73
+ export const refundShopifyOrder = async (config, input, fetchImpl = fetch) => {
74
+ // Same reasoning as the writeback's idempotency tag: an id carrying a space or
75
+ // a Shopify search operator would false-match an unrelated order — and
76
+ // refunding the WRONG order is worse than not refunding this one. Unsafe
77
+ // candidates are dropped rather than searched.
78
+ const candidates = (Array.isArray(input.agentbankOrderId) ? input.agentbankOrderId : [input.agentbankOrderId]).filter((t) => typeof t === 'string' && /^[A-Za-z0-9_.:-]{1,255}$/.test(t));
79
+ if (candidates.length === 0) {
80
+ return { refunded: false, reason: 'no safe agentbank id to search by' };
81
+ }
82
+ const token = await exchangeToken(config, fetchImpl);
83
+ let order;
84
+ for (const tag of candidates) {
85
+ const found = await shopifyGraphql(config, token, FIND_FOR_REFUND, { q: `tag:${tag}` }, fetchImpl);
86
+ order = found.orders.nodes[0];
87
+ if (order)
88
+ break;
89
+ }
90
+ // No order is not an error worth retrying: this sale may predate the
91
+ // writeback, or the store may not be the one it was written to.
92
+ if (!order)
93
+ return { refunded: false, reason: 'no Shopify order tagged with that agentbank id' };
94
+ // Idempotent: a redelivered refund event finds it already refunded.
95
+ if (/REFUNDED/i.test(order.displayFinancialStatus)) {
96
+ return { refunded: false, reason: `already refunded (${order.name})` };
97
+ }
98
+ const data = await shopifyGraphql(config, token, REFUND_CREATE, {
99
+ i: {
100
+ orderId: order.id,
101
+ note: input.reason ? `Refunded via agentbank · ${input.reason}` : 'Refunded via agentbank',
102
+ // NO `transactions`. That is what makes this a record rather than a
103
+ // payment — see OrderRefund.
104
+ refundLineItems: order.lineItems.nodes.map((li) => ({
105
+ lineItemId: li.id,
106
+ quantity: li.quantity,
107
+ restockType: input.restock ? 'RETURN' : 'NO_RESTOCK',
108
+ })),
109
+ },
110
+ }, fetchImpl);
111
+ const errs = data.refundCreate?.userErrors ?? [];
112
+ if (errs.length)
113
+ return { refunded: false, reason: errs.map((e) => e.message).join('; ') };
114
+ const refund = data.refundCreate?.refund;
115
+ if (!refund)
116
+ return { refunded: false, reason: 'refundCreate returned no refund' };
117
+ return { refunded: true, id: refund.id };
118
+ };
56
119
  //# sourceMappingURL=orders.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orders.js","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orders.js","sourceRoot":"","sources":["../src/orders.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -43,4 +43,24 @@ export type WritebackResult = {
43
43
  created: false;
44
44
  reason: string;
45
45
  };
46
+ export type OrderRefund = {
47
+ /**
48
+ * The tag the writeback used. Accepts SEVERAL candidates, tried in order,
49
+ * because the writeback keys on `orderId ?? sessionId ?? paymentIntentId` —
50
+ * which of the three it landed on depends on the protocol, and a refund event
51
+ * doesn't know. Pass every id you hold rather than guessing one.
52
+ */
53
+ agentbankOrderId: string | string[];
54
+ /** Shown on the Shopify refund. */
55
+ reason?: string;
56
+ /** Put the units back into inventory. Default false — a booking has nothing to restock. */
57
+ restock?: boolean;
58
+ };
59
+ export type RefundResult = {
60
+ refunded: true;
61
+ id: string;
62
+ } | {
63
+ refunded: false;
64
+ reason: string;
65
+ };
46
66
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAKF,MAAM,MAAM,cAAc,GAAG;IAC3B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAO1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAKF,MAAM,MAAM,cAAc,GAAG;IAC3B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAO1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAavC,MAAM,MAAM,WAAW,GAAG;IACxB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@curless/shopify-adapter",
3
- "version": "0.1.0",
4
- "description": "Use a Shopify store as an agentbank catalog source, and record agent-settled sales back as paid Shopify orders. Maps Shopify Admin products → a generic CatalogItem your merchant backend prices from, and writes an order back after an agent pays through agentbank. Zero runtime dependencies (uses the platform fetch).",
3
+ "version": "0.2.0",
4
+ "description": "Use a Shopify store as an agentbank catalog source, and record agent-settled sales back as paid Shopify orders. Maps Shopify Admin products → a generic CatalogItem your merchant backend prices from, writes an order back after an agent pays through agentbank, and records the reversal when that sale is refunded. Zero runtime dependencies (uses the platform fetch).",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",