@curless/shopify-adapter 0.1.1 → 0.3.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
@@ -46,9 +47,33 @@ await writebackShopifyOrder(shopify, {
46
47
  });
47
48
  ```
48
49
 
49
- No money moves in Shopify the order is marked **paid via an external transaction**
50
- and tagged `agentbank` + `protocol:…` + the agentbank order id, so it's traceable and
51
- never mistaken for a Shopify Payments sale.
50
+ No money moves in Shopify. The order is booked with a **SALE transaction on the
51
+ `agentbank` gateway** (not just `financialStatus: PAID`, which paints the label and
52
+ creates no transaction — such an order can never be refunded) and tagged `agentbank` +
53
+ `protocol:…` + the agentbank order id, so it's traceable and never mistaken for a
54
+ Shopify Payments sale. Pass `unitPriceMinor` + `currency` or there is no total to book
55
+ the transaction with, and the order won't be reversible.
56
+
57
+ **3. Refund** — when agentbank refunds the sale, stop the Shopify order reading as paid:
58
+
59
+ ```ts
60
+ // e.g. from your `order.refunded` webhook handler
61
+ await refundShopifyOrder(shopify, {
62
+ agentbankOrderId: [`order_${paymentIntentId}`, paymentIntentId], // any tag you wrote back with
63
+ reason: 'guest cancelled',
64
+ });
65
+ // → { refunded: true, id } | { refunded: false, reason }
66
+ ```
67
+
68
+ It **records** the reversal rather than processing one — the sale was booked on our
69
+ own gateway, so the matching REFUND transaction moves no real money. It does have to
70
+ BE a transaction, though: a refund with none attached is a 0.00 refund and the order
71
+ goes on reading PAID. An order written back before this adapter recorded a sale
72
+ transaction has no parent to refund against and comes back
73
+ `{refunded:false, reason:'…no SALE transaction…'}` — reverse those in the admin once.
74
+
75
+ Full-order only — agentbank refunds the whole captured amount, and inventing a partial
76
+ here would let you record a reversal that doesn't match the money that actually went back.
52
77
 
53
78
  ## Notes
54
79
 
@@ -69,6 +94,11 @@ never mistaken for a Shopify Payments sale.
69
94
  refresh, so two writebacks fired within a second can both miss and duplicate — add
70
95
  your own in-process guard on the order id if you fire them rapidly; the tag search
71
96
  is the cross-restart backstop.
97
+ - **Refunds are idempotent and safe to miss.** `refundShopifyOrder` takes one id or a
98
+ list, tries them in order, and returns `{refunded:false, reason}` — never throws —
99
+ when nothing matches or the order is already REFUNDED. Ids that could false-match a
100
+ Shopify search (spaces, operators) are dropped rather than searched: refunding the
101
+ wrong order is worse than refunding none.
72
102
  - **Pagination.** Products paginate to completion. A single product with more than
73
103
  250 variants has its tail dropped **with a warning** (not silently).
74
104
 
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/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,CA6DzB,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;AAUpB,eAAO,MAAM,qBAAqB,GAChC,QAAQ,aAAa,EACrB,OAAO,cAAc,EACrB,YAAW,OAAO,KAAa,KAC9B,OAAO,CAAC,eAAe,CAyFzB,CAAC;AAiBF,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,aAAa,EACrB,OAAO,WAAW,EAClB,YAAW,OAAO,KAAa,KAC9B,OAAO,CAAC,YAAY,CA+FtB,CAAC"}
package/dist/orders.js CHANGED
@@ -14,6 +14,10 @@
14
14
  import { exchangeToken, shopifyGraphql } from './client.js';
15
15
  import { toMajorString } from './money.js';
16
16
  const FIND_BY_TAG = 'query($q:String!){ orders(first:1, query:$q){ nodes{ id name } } }';
17
+ // The gateway name on the transactions we write. Shopify shows it verbatim in the
18
+ // order's payment section and in finance reports, so it says where the money
19
+ // actually is rather than implying a Shopify Payments sale.
20
+ const SALE_GATEWAY = 'agentbank';
17
21
  const ORDER_CREATE = 'mutation($o:OrderCreateOrderInput!){ orderCreate(order:$o){ order{ id name } userErrors{ field message } } }';
18
22
  export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) => {
19
23
  const token = await exchangeToken(config, fetchImpl);
@@ -45,13 +49,41 @@ export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) =>
45
49
  // records what was really paid rather than Shopify re-deriving it from the
46
50
  // variant's current price. Omitting unitPriceMinor/currency keeps the variant
47
51
  // price (Shopify's default).
52
+ const transactions = [];
48
53
  if (input.unitPriceMinor != null && input.currency) {
49
54
  const currencyCode = input.currency.toUpperCase(); // Shopify's CurrencyCode enum is upper-case
50
55
  lineItem.priceSet = {
51
56
  shopMoney: { amount: toMajorString(input.unitPriceMinor, currencyCode), currencyCode },
52
57
  };
58
+ // A SALE transaction on our own gateway, not just financialStatus:'PAID'.
59
+ //
60
+ // `financialStatus` alone paints the label and creates NO transaction, and an
61
+ // order with no transaction cannot be refunded: Shopify requires a REFUND
62
+ // transaction to carry a parent, so the reversal has nothing to attach to and
63
+ // records a 0.00 refund that leaves the order reading PAID forever. It is also
64
+ // simply more truthful — the sale really was collected on an external gateway,
65
+ // which is what the store's own finance reporting needs to see.
66
+ transactions.push({
67
+ kind: 'SALE',
68
+ status: 'SUCCESS',
69
+ gateway: SALE_GATEWAY,
70
+ amountSet: {
71
+ shopMoney: {
72
+ amount: toMajorString(input.unitPriceMinor * input.quantity, currencyCode),
73
+ currencyCode,
74
+ },
75
+ },
76
+ });
53
77
  }
54
- const data = await shopifyGraphql(config, token, ORDER_CREATE, { o: { lineItems: [lineItem], financialStatus: 'PAID', note, tags } }, fetchImpl);
78
+ const data = await shopifyGraphql(config, token, ORDER_CREATE, {
79
+ o: {
80
+ lineItems: [lineItem],
81
+ financialStatus: 'PAID',
82
+ note,
83
+ tags,
84
+ ...(transactions.length ? { transactions } : {}),
85
+ },
86
+ }, fetchImpl);
55
87
  const errs = data.orderCreate?.userErrors ?? [];
56
88
  if (errs.length)
57
89
  return { created: false, reason: errs.map((e) => e.message).join('; ') };
@@ -60,4 +92,86 @@ export const writebackShopifyOrder = async (config, input, fetchImpl = fetch) =>
60
92
  return { created: false, reason: 'orderCreate returned no order' };
61
93
  return { created: true, name: order.name, id: order.id };
62
94
  };
95
+ const FIND_FOR_REFUND = 'query($q:String!){ orders(first:1, query:$q){ nodes{ id name displayFinancialStatus ' +
96
+ 'totalPriceSet{ shopMoney{ amount currencyCode } } ' +
97
+ 'transactions{ id kind status gateway amountSet{ shopMoney{ amount } } } ' +
98
+ 'lineItems(first:50){ nodes{ id quantity } } } } }';
99
+ const REFUND_CREATE = 'mutation($i:RefundInput!){ refundCreate(input:$i){ refund{ id } userErrors{ field message } } }';
100
+ // Mark an agentbank-settled Shopify order as refunded. See OrderRefund for why
101
+ // this records a refund rather than processing one.
102
+ //
103
+ // Deliberately full-order only: agentbank refunds the whole captured amount
104
+ // (Curless refunds nothing else), so every line goes back in full. A partial
105
+ // would need to say WHICH lines and how many, and inventing that here would let
106
+ // a caller record a refund that doesn't match the money actually returned.
107
+ export const refundShopifyOrder = async (config, input, fetchImpl = fetch) => {
108
+ // Same reasoning as the writeback's idempotency tag: an id carrying a space or
109
+ // a Shopify search operator would false-match an unrelated order — and
110
+ // refunding the WRONG order is worse than not refunding this one. Unsafe
111
+ // candidates are dropped rather than searched.
112
+ const candidates = (Array.isArray(input.agentbankOrderId) ? input.agentbankOrderId : [input.agentbankOrderId]).filter((t) => typeof t === 'string' && /^[A-Za-z0-9_.:-]{1,255}$/.test(t));
113
+ if (candidates.length === 0) {
114
+ return { refunded: false, reason: 'no safe agentbank id to search by' };
115
+ }
116
+ const token = await exchangeToken(config, fetchImpl);
117
+ let order;
118
+ for (const tag of candidates) {
119
+ const found = await shopifyGraphql(config, token, FIND_FOR_REFUND, { q: `tag:${tag}` }, fetchImpl);
120
+ order = found.orders.nodes[0];
121
+ if (order)
122
+ break;
123
+ }
124
+ // No order is not an error worth retrying: this sale may predate the
125
+ // writeback, or the store may not be the one it was written to.
126
+ if (!order)
127
+ return { refunded: false, reason: 'no Shopify order tagged with that agentbank id' };
128
+ // Idempotent: a redelivered refund event finds it already refunded.
129
+ if (/REFUNDED/i.test(order.displayFinancialStatus)) {
130
+ return { refunded: false, reason: `already refunded (${order.name})` };
131
+ }
132
+ // The transaction the refund attaches to. Shopify rejects a REFUND transaction
133
+ // with no `parentId` on any gateway but store-credit/exchange-credit/cash, and
134
+ // a refund with NO transactions at all is a 0.00 refund: it files a refund
135
+ // record and leaves the order reading PAID. So a missing sale transaction is a
136
+ // hard stop, not something to paper over — say so instead of writing a reversal
137
+ // that reverses nothing.
138
+ const sale = order.transactions.find((t) => t.kind?.toUpperCase() === 'SALE' && t.status?.toUpperCase() === 'SUCCESS');
139
+ if (!sale) {
140
+ return {
141
+ refunded: false,
142
+ reason: `Shopify order ${order.name} has no SALE transaction to refund against (written back before the adapter recorded one) — reverse it in the Shopify admin`,
143
+ };
144
+ }
145
+ const data = await shopifyGraphql(config, token, REFUND_CREATE, {
146
+ i: {
147
+ orderId: order.id,
148
+ note: input.reason ? `Refunded via agentbank · ${input.reason}` : 'Refunded via agentbank',
149
+ // A REFUND transaction against the sale, for the full order total. This
150
+ // moves no real money — the gateway is ours, and Shopify never held the
151
+ // funds — but it is what actually flips the order to REFUNDED, which
152
+ // refundLineItems alone does not do.
153
+ transactions: [
154
+ {
155
+ orderId: order.id,
156
+ parentId: sale.id,
157
+ gateway: sale.gateway,
158
+ kind: 'REFUND',
159
+ amount: order.totalPriceSet.shopMoney.amount,
160
+ },
161
+ ],
162
+ refundLineItems: order.lineItems.nodes.map((li) => ({
163
+ lineItemId: li.id,
164
+ quantity: li.quantity,
165
+ restockType: input.restock ? 'RETURN' : 'NO_RESTOCK',
166
+ })),
167
+ },
168
+ }, fetchImpl);
169
+ const errs = data.refundCreate?.userErrors ?? [];
170
+ if (errs.length)
171
+ return { refunded: false, reason: errs.map((e) => e.message).join('; ') };
172
+ const refund = data.refundCreate?.refund;
173
+ if (!refund)
174
+ return { refunded: false, reason: 'refundCreate returned no refund' };
175
+ return { refunded: true, id: refund.id };
176
+ };
63
177
  //# 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;AAOF,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.1",
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.3.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",