@waffo/pancake-ts 0.7.0 → 0.9.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/CHANGELOG.md +49 -0
- package/README.md +53 -1
- package/dist/index.cjs +125 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -55
- package/dist/index.d.ts +141 -55
- package/dist/index.js +125 -73
- package/dist/index.js.map +1 -1
- package/docs/api-reference.md +45 -41
- package/docs/graphql-guide.md +26 -0
- package/docs/webhook-guide.md +11 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,55 @@ All notable changes to `@waffo/pancake-ts` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.9.0] - 2026-05-21
|
|
8
|
+
|
|
9
|
+
Adds flat dual-key external-id fields across write inputs, response entities, and webhook payload. The same field name now appears at every layer (REST request body / REST response / webhook payload / GraphQL).
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `CreateCheckoutSessionParams.orderMerchantExternalId` — order business identifier (optional, max 128 chars). Inherited by orders, payments, and refunds; surfaces in webhook payload (`data.orderMerchantExternalId`) and GraphQL (`Order.orderMerchantExternalId` / `Payment.orderMerchantExternalId` / `Refund.orderMerchantExternalId`).
|
|
14
|
+
- `CreateRefundTicketParams.refundTicketMerchantExternalId` — refund-ticket business identifier (optional, max 128 chars). Inherited by the executed refund record on PSP success; surfaces in webhook payload (`data.refundTicketMerchantExternalId`) and GraphQL (`RefundTicket.refundTicketMerchantExternalId` / `Refund.refundTicketMerchantExternalId`).
|
|
15
|
+
- `RefundTicket.refundTicketMerchantExternalId` — response field (immutable across resubmits, max 128 chars).
|
|
16
|
+
- `WebhookEventData.orderMerchantExternalId` — present on order/payment events and on refund events (inherited from the related order).
|
|
17
|
+
- `WebhookEventData.refundTicketMerchantExternalId` — only present on `refund.*` events; coexists with `orderMerchantExternalId` on the same refund payload.
|
|
18
|
+
|
|
19
|
+
### Notes
|
|
20
|
+
|
|
21
|
+
Non-breaking for SDK users — all five new fields are additive. The dual flat key naming is the canonical wire surface from this version onward.
|
|
22
|
+
|
|
23
|
+
## [0.8.0] - 2026-05-17
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **GraphQL queries actually return data.** Prior versions assumed a double-wrapped envelope (`{data:{data,errors,warnings}}`) and stripped one layer too many, so `result.data` was always `undefined` regardless of what the server returned. The wire is in fact the standard single-layer GraphQL envelope (`{data, errors?, warnings?}`); the SDK now returns it verbatim.
|
|
28
|
+
- **GraphQL queries no longer carry `X-Idempotency-Key`.** Queries are read-only; the gateway was caching them for 24h and serving stale snapshots on subsequent identical requests. Side-effect-free queries now hit the live DB on every call.
|
|
29
|
+
- **REST `warnings` are no longer dropped.** Every REST action endpoint can return `warnings: Notice[]` (handbook `command-layer.md`); prior `HttpClient.post()` returned only the unwrapped `data` field, throwing away migration `aiHint` notices like `update-store`'s `webhookSettings field ignored → Switch to client.webhooks.add/update/remove`.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **Resource method return types widened** from `Promise<X>` to `Promise<X & { warnings?: Notice[] }>` for every REST action method (`stores`, `storeMerchants`, `onetimeProducts`, `subscriptionProducts`, `subscriptionProductGroups`, `orders`, `checkout.*`, `webhooks.add/update/remove`, `auth.issueSessionToken`, `buyer.cancelSubscription / cancelOnetimeOrder / reactivateSubscription / createRefundTicket / resubmitRefundTicket`). Existing destructuring (`const { store } = await client.stores.create(...)`) keeps working; add `warnings` to the destructure to read advisories.
|
|
34
|
+
- **Transport refactored**: `HttpClient.post<T>()` now returns the parsed envelope plus HTTP status (`PostResult<T> = { status, data, errors?, warnings? }`) without throwing on `errors[]`. Throw / unwrap / warnings handling moved to the resource layer via the internal `unwrapAction` helper. GraphQL resources return the envelope verbatim.
|
|
35
|
+
- **`GraphQLResource.query` and `BuyerGraphQL.query` pass `noIdempotency: true`** to the transport (suppresses `X-Idempotency-Key`).
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **`Notice` type** (`{ message, layer, aiHint? }`) — unified shape used by both REST and GraphQL `errors[]` / `warnings[]`. Exported from `index.ts`.
|
|
40
|
+
- **`Envelope<T>` / `PostResult<T>` types** — transport-level envelope (and `PostResult` adds HTTP `status`). Exported for advanced callers.
|
|
41
|
+
- **`GraphQLResponse.errors[].layer?`** — optional field carrying which service stage produced the error (`"graphql"`, `"gateway"`).
|
|
42
|
+
- **`PostOptions.noIdempotency`** — boolean to suppress the `X-Idempotency-Key` header on a per-call basis.
|
|
43
|
+
- **README "Warnings (Migration Notices)" section** with REST + GraphQL examples and explicit guidance for LLM/agent consumers to act on `aiHint`.
|
|
44
|
+
|
|
45
|
+
### Deprecated
|
|
46
|
+
|
|
47
|
+
- **`ApiError`, `ApiResponse`, `ApiSuccessResponse`, `ApiErrorResponse`** — kept as type aliases for backwards compatibility; prefer `Notice` and the new `Envelope<T>` / `PostResult<T>`.
|
|
48
|
+
|
|
49
|
+
### Migration
|
|
50
|
+
|
|
51
|
+
- **Most callers need no changes.** Destructuring (`const { store } = ...`) still works; the new `warnings` field is optional and untouched code ignores it.
|
|
52
|
+
- **GraphQL callers**: if you have hacks that read `(result as any).stores` directly (bypassing the broken `result.data`), revert to `result.data.stores` — the bug that motivated the hack is gone.
|
|
53
|
+
- **LLM/agent consumers**: read `result.warnings?.[].aiHint` on every action — that's where the platform team puts canonical migration instructions when an API evolves (e.g. `update-store`'s deprecated `webhookSettings` field).
|
|
54
|
+
- **Direct `HttpClient.post` consumers** (rare; `HttpClient` is internal but reachable): return type changed from `T` to `PostResult<T>`; access `.data` to get the unwrapped payload, inspect `.errors` / `.warnings` directly. The transport no longer throws on `errors[]`.
|
|
55
|
+
|
|
7
56
|
## [0.7.0] - 2026-05-11
|
|
8
57
|
|
|
9
58
|
### Changed
|
package/README.md
CHANGED
|
@@ -107,6 +107,7 @@ const result = await client.checkout.authenticated.create({
|
|
|
107
107
|
buyerEmail: "customer@example.com",
|
|
108
108
|
withTrial: true, // force enable trial (false = skip, omit = default rules)
|
|
109
109
|
billingDetail: { country: "US", isBusiness: false },
|
|
110
|
+
orderMerchantExternalId: "ORDER-2026-00891", // optional, see Business-Side Identifiers below
|
|
110
111
|
});
|
|
111
112
|
|
|
112
113
|
// result.checkoutUrl = "https://pancake.waffo.ai/store/{slug}/checkout/{sessionId}#token={JWT}"
|
|
@@ -125,12 +126,13 @@ const result = await client.checkout.anonymous.create({
|
|
|
125
126
|
currency: "USD",
|
|
126
127
|
});
|
|
127
128
|
|
|
128
|
-
// Also supports priceSnapshot and
|
|
129
|
+
// Also supports priceSnapshot, withTrial, and orderMerchantExternalId
|
|
129
130
|
const result = await client.checkout.anonymous.create({
|
|
130
131
|
productId: "PROD_xxx",
|
|
131
132
|
currency: "USD",
|
|
132
133
|
priceSnapshot: { amount: "4.99", taxCategory: "saas" },
|
|
133
134
|
withTrial: false, // skip trial for this session
|
|
135
|
+
orderMerchantExternalId: "ORDER-2026-00891", // optional, API Key auth only
|
|
134
136
|
});
|
|
135
137
|
|
|
136
138
|
window.open(result.checkoutUrl, "_blank", "noopener,noreferrer");
|
|
@@ -186,6 +188,8 @@ app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
|
|
|
186
188
|
break;
|
|
187
189
|
case WebhookEventType.RefundSucceeded:
|
|
188
190
|
console.log(`Refund succeeded: ${event.data.refundReason}`);
|
|
191
|
+
// refund.* events carry both business identifiers (see Business-Side Identifiers section)
|
|
192
|
+
await ledger.closeRefundTicket(event.data.refundTicketMerchantExternalId, event.data.orderMerchantExternalId);
|
|
189
193
|
break;
|
|
190
194
|
}
|
|
191
195
|
} catch {
|
|
@@ -253,6 +257,7 @@ const { ticket } = await buyer.createRefundTicket({
|
|
|
253
257
|
paymentId: "PAY_xxx",
|
|
254
258
|
reason: "Product not as described",
|
|
255
259
|
requestedAmount: { amount: "29.00", currency: "USD" },
|
|
260
|
+
refundTicketMerchantExternalId: "REF-2026-00012", // optional, see Business-Side Identifiers below
|
|
256
261
|
});
|
|
257
262
|
|
|
258
263
|
// Resubmit a rejected refund ticket
|
|
@@ -273,6 +278,17 @@ The token is scoped to the specified store and buyer identity — buyers can onl
|
|
|
273
278
|
|
|
274
279
|
> **Note**: This uses the same `buyerIdentity` as `checkout.authenticated.create()`. Orders placed via authenticated checkout are automatically tied to this identity, so the buyer can manage them later with a token issued here.
|
|
275
280
|
|
|
281
|
+
## Business-Side Identifiers
|
|
282
|
+
|
|
283
|
+
Attach your own internal references to a checkout or a refund ticket so cross-system reconciliation does not require Waffo IDs. Two flat keys, both optional (max 128 chars):
|
|
284
|
+
|
|
285
|
+
| Field | Attach at | Inherited by |
|
|
286
|
+
| -------------------------------- | ------------------------------------------- | ---------------------------------------------------------- |
|
|
287
|
+
| `orderMerchantExternalId` | `checkout.{authenticated,anonymous}.create` | `Order`, `Payment` (incl. subscription renewals), `Refund` |
|
|
288
|
+
| `refundTicketMerchantExternalId` | `buyer.createRefundTicket` | `RefundTicket`, `Refund` |
|
|
289
|
+
|
|
290
|
+
The same field name appears at every layer it surfaces: request body, response entity, webhook payload (`data.orderMerchantExternalId` / `data.refundTicketMerchantExternalId`), and every GraphQL type that carries the value. A `refund.*` webhook event carries **both** keys (order key inherited from the originating order). Query by either key via GraphQL filters — see [GraphQL Guide](docs/graphql-guide.md).
|
|
291
|
+
|
|
276
292
|
## GraphQL — Typed Queries
|
|
277
293
|
|
|
278
294
|
```typescript
|
|
@@ -301,10 +317,46 @@ const detail = await client.graphql.query({
|
|
|
301
317
|
}`,
|
|
302
318
|
variables: { id: "STO_xxx" },
|
|
303
319
|
});
|
|
320
|
+
|
|
321
|
+
// Look up by your business-side identifier (see Business-Side Identifiers above)
|
|
322
|
+
const byRef = await client.graphql.query({
|
|
323
|
+
query: `query ($ref: String!) {
|
|
324
|
+
payments(filter: { orderMerchantExternalId: { eq: $ref } }) {
|
|
325
|
+
id orderId status orderMerchantExternalId
|
|
326
|
+
}
|
|
327
|
+
}`,
|
|
328
|
+
variables: { ref: "ORDER-2026-00891" },
|
|
329
|
+
});
|
|
304
330
|
```
|
|
305
331
|
|
|
306
332
|
See [GraphQL Guide](docs/graphql-guide.md) for filters, analytics queries, delivery logs, and more.
|
|
307
333
|
|
|
334
|
+
## Warnings (Migration Notices)
|
|
335
|
+
|
|
336
|
+
Every successful REST action and GraphQL query may carry a `warnings` array alongside the data. Warnings describe non-fatal advisories the server wants you to act on — typically deprecated parameters, fields scheduled for removal, or new APIs you should switch to. Each `Notice` has `message` (human-readable), `layer` (which service produced it), and `aiHint` (a structured migration instruction aimed at LLM consumers).
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// REST action — warnings spread onto the result alongside the typed payload
|
|
340
|
+
const { store, warnings } = await client.stores.update({
|
|
341
|
+
id: "STO_xxx",
|
|
342
|
+
webhookSettings: { ... }, // deprecated input
|
|
343
|
+
});
|
|
344
|
+
if (warnings) {
|
|
345
|
+
for (const w of warnings) {
|
|
346
|
+
console.warn(`[${w.layer}] ${w.message}`, w.aiHint);
|
|
347
|
+
// e.g. layer=store, aiHint="Switch to client.webhooks.add / update / remove"
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// GraphQL — warnings sit on the envelope alongside data and errors
|
|
352
|
+
const result = await client.graphql.query<StoresQuery>({
|
|
353
|
+
query: `query { stores { id } }`,
|
|
354
|
+
});
|
|
355
|
+
result.warnings?.forEach(w => console.warn(w.message, w.aiHint));
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**LLM/agent consumers**: always check `aiHint` on every warning — it is the canonical migration instruction (npm package, version, method name, endpoint path) the platform team intends for you to follow when the underlying API evolves.
|
|
359
|
+
|
|
308
360
|
## Programmatic Store & Product Management
|
|
309
361
|
|
|
310
362
|
> Most merchants manage stores and products in the [Dashboard](https://pancake.waffo.ai/dashboard). The following APIs are for merchants who need programmatic automation.
|
package/dist/index.cjs
CHANGED
|
@@ -65,12 +65,10 @@ var BuyerHttpClient = class {
|
|
|
65
65
|
this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Send a Bearer-authenticated POST
|
|
68
|
+
* Send a Bearer-authenticated POST and return the full envelope plus HTTP status.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
* @
|
|
72
|
-
* @returns Parsed `data` field from the response
|
|
73
|
-
* @throws {WaffoPancakeError} When the API returns errors
|
|
70
|
+
* Does NOT throw on `errors[]` or non-2xx status — caller inspects the result.
|
|
71
|
+
* Throws {@link WaffoPancakeError} only when the response body is not valid JSON.
|
|
74
72
|
*/
|
|
75
73
|
async post(path, body) {
|
|
76
74
|
const response = await this._fetch(`${this.baseUrl}${path}`, {
|
|
@@ -81,11 +79,13 @@ var BuyerHttpClient = class {
|
|
|
81
79
|
},
|
|
82
80
|
body: JSON.stringify(body)
|
|
83
81
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
let envelope;
|
|
83
|
+
try {
|
|
84
|
+
envelope = await response.json();
|
|
85
|
+
} catch {
|
|
86
|
+
throw new WaffoPancakeError(response.status, [{ message: `Non-JSON response from ${path}`, layer: "sdk" }]);
|
|
87
87
|
}
|
|
88
|
-
return
|
|
88
|
+
return { status: response.status, ...envelope };
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
91
|
|
|
@@ -201,48 +201,64 @@ var HttpClient = class {
|
|
|
201
201
|
this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
|
-
* Send a signed POST
|
|
204
|
+
* Send a signed POST and return the full envelope plus HTTP status.
|
|
205
205
|
*
|
|
206
206
|
* Behavior:
|
|
207
|
-
* -
|
|
208
|
-
* -
|
|
209
|
-
*
|
|
210
|
-
* -
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* @
|
|
207
|
+
* - Builds RSA-SHA256 signature (`X-Merchant-Id` / `X-Timestamp` / `X-Signature`)
|
|
208
|
+
* - Attaches `X-Idempotency-Key` (deterministic `sha256(merchantId + path + body)`)
|
|
209
|
+
* unless `options.noIdempotency` is set
|
|
210
|
+
* - When `options.idempotencyWindow` is set, a floored timestamp is mixed into the
|
|
211
|
+
* key so identical params produce a new key after the window elapses
|
|
212
|
+
* - Does NOT throw on `errors[]` or non-2xx status — caller inspects the result
|
|
213
|
+
* - Throws {@link WaffoPancakeError} only on transport failures (non-JSON body)
|
|
214
|
+
*
|
|
215
|
+
* @param path - API path (e.g. `/v1/actions/store/create-store`, `/v1/graphql`)
|
|
214
216
|
* @param body - Request body object
|
|
215
217
|
* @param options - Optional settings
|
|
216
|
-
* @
|
|
217
|
-
* @
|
|
218
|
-
* @throws {WaffoPancakeError} When the API returns errors
|
|
218
|
+
* @returns Parsed envelope with HTTP status
|
|
219
|
+
* @throws {WaffoPancakeError} When the response body is not valid JSON
|
|
219
220
|
*/
|
|
220
221
|
async post(path, body, options) {
|
|
221
222
|
const bodyStr = JSON.stringify(body);
|
|
222
|
-
const
|
|
223
|
-
const timestampSec = Math.floor(now / 1e3);
|
|
223
|
+
const timestampSec = Math.floor(Date.now() / 1e3);
|
|
224
224
|
const timestamp = timestampSec.toString();
|
|
225
225
|
const signature = signRequest("POST", path, timestamp, bodyStr, this.privateKey);
|
|
226
|
-
const
|
|
227
|
-
|
|
226
|
+
const headers = {
|
|
227
|
+
"Content-Type": "application/json",
|
|
228
|
+
"X-Merchant-Id": this.merchantId,
|
|
229
|
+
"X-Timestamp": timestamp,
|
|
230
|
+
"X-Signature": signature
|
|
231
|
+
};
|
|
232
|
+
if (!options?.noIdempotency) {
|
|
233
|
+
headers["X-Idempotency-Key"] = computeIdempotencyKey(this.merchantId, path, bodyStr, timestampSec, options);
|
|
234
|
+
}
|
|
228
235
|
const response = await this._fetch(`${this.baseUrl}${path}`, {
|
|
229
236
|
method: "POST",
|
|
230
|
-
headers
|
|
231
|
-
"Content-Type": "application/json",
|
|
232
|
-
"X-Merchant-Id": this.merchantId,
|
|
233
|
-
"X-Timestamp": timestamp,
|
|
234
|
-
"X-Signature": signature,
|
|
235
|
-
"X-Idempotency-Key": (0, import_node_crypto2.createHash)("sha256").update(idempotencyInput).digest("hex")
|
|
236
|
-
},
|
|
237
|
+
headers,
|
|
237
238
|
body: bodyStr
|
|
238
239
|
});
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
let envelope;
|
|
241
|
+
try {
|
|
242
|
+
envelope = await response.json();
|
|
243
|
+
} catch {
|
|
244
|
+
throw new WaffoPancakeError(response.status, [{ message: `Non-JSON response from ${path}`, layer: "sdk" }]);
|
|
242
245
|
}
|
|
243
|
-
return
|
|
246
|
+
return { status: response.status, ...envelope };
|
|
244
247
|
}
|
|
245
248
|
};
|
|
249
|
+
function computeIdempotencyKey(merchantId, path, bodyStr, timestampSec, options) {
|
|
250
|
+
const base = `${merchantId}:${path}:${bodyStr}`;
|
|
251
|
+
const input = options?.idempotencyWindow ? `${base}:${Math.floor(timestampSec / options.idempotencyWindow)}` : base;
|
|
252
|
+
return (0, import_node_crypto2.createHash)("sha256").update(input).digest("hex");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/resources/internal.ts
|
|
256
|
+
function unwrapAction(r) {
|
|
257
|
+
if (r.errors?.length) {
|
|
258
|
+
throw new WaffoPancakeError(r.status, r.errors);
|
|
259
|
+
}
|
|
260
|
+
return { ...r.data, ...r.warnings ? { warnings: r.warnings } : {} };
|
|
261
|
+
}
|
|
246
262
|
|
|
247
263
|
// src/validation.ts
|
|
248
264
|
var SHORT_ID_REGEX = /^[A-Z]{2,5}_[0-9A-Za-z]{22}$/;
|
|
@@ -297,6 +313,11 @@ function validateEnum(field, value, allowed) {
|
|
|
297
313
|
fail(`Invalid ${field}: expected one of [${allowed.join(", ")}], got "${value}"`);
|
|
298
314
|
}
|
|
299
315
|
}
|
|
316
|
+
function validateMaxLength(field, value, max) {
|
|
317
|
+
if (value !== void 0 && value.length > max) {
|
|
318
|
+
fail(`${field} must be at most ${max} characters, got ${value.length}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
300
321
|
function validatePositiveInteger(field, value) {
|
|
301
322
|
if (!Number.isInteger(value) || value <= 0) {
|
|
302
323
|
fail(`Invalid ${field}: expected positive integer, got ${value}`);
|
|
@@ -339,6 +360,7 @@ function validateCheckoutCommon(params) {
|
|
|
339
360
|
if (params.expiresInSeconds !== void 0) {
|
|
340
361
|
validatePositiveInteger("expiresInSeconds", params.expiresInSeconds);
|
|
341
362
|
}
|
|
363
|
+
validateMaxLength("orderMerchantExternalId", params.orderMerchantExternalId, 128);
|
|
342
364
|
}
|
|
343
365
|
|
|
344
366
|
// src/resources/auth.ts
|
|
@@ -377,7 +399,7 @@ var AuthResource = class {
|
|
|
377
399
|
validateShortId("productId", params.productId, "PROD");
|
|
378
400
|
}
|
|
379
401
|
validateRequired("buyerIdentity", params.buyerIdentity);
|
|
380
|
-
return this.http.post("/v1/actions/auth/issue-session-token", params);
|
|
402
|
+
return unwrapAction(await this.http.post("/v1/actions/auth/issue-session-token", params));
|
|
381
403
|
}
|
|
382
404
|
};
|
|
383
405
|
|
|
@@ -401,7 +423,7 @@ var BuyerSession = class {
|
|
|
401
423
|
*/
|
|
402
424
|
async cancelSubscription(params) {
|
|
403
425
|
validateShortId("orderId", params.orderId, "ORD");
|
|
404
|
-
return this.http.post("/v1/actions/subscription-order/cancel-order", params);
|
|
426
|
+
return unwrapAction(await this.http.post("/v1/actions/subscription-order/cancel-order", params));
|
|
405
427
|
}
|
|
406
428
|
/**
|
|
407
429
|
* Cancel a one-time order (only while payment is still pending).
|
|
@@ -414,7 +436,7 @@ var BuyerSession = class {
|
|
|
414
436
|
*/
|
|
415
437
|
async cancelOnetimeOrder(params) {
|
|
416
438
|
validateShortId("orderId", params.orderId, "ORD");
|
|
417
|
-
return this.http.post("/v1/actions/onetime-order/cancel-order", params);
|
|
439
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-order/cancel-order", params));
|
|
418
440
|
}
|
|
419
441
|
/**
|
|
420
442
|
* Reactivate a subscription that is in `canceling` status.
|
|
@@ -428,7 +450,7 @@ var BuyerSession = class {
|
|
|
428
450
|
*/
|
|
429
451
|
async reactivateSubscription(params) {
|
|
430
452
|
validateShortId("orderId", params.orderId, "ORD");
|
|
431
|
-
return this.http.post("/v1/actions/subscription-order/reactivate-order", params);
|
|
453
|
+
return unwrapAction(await this.http.post("/v1/actions/subscription-order/reactivate-order", params));
|
|
432
454
|
}
|
|
433
455
|
/**
|
|
434
456
|
* Submit a refund request for a payment.
|
|
@@ -441,6 +463,7 @@ var BuyerSession = class {
|
|
|
441
463
|
* paymentId: "PAY_xxx",
|
|
442
464
|
* reason: "Product not as described",
|
|
443
465
|
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
466
|
+
* refundTicketMerchantExternalId: "REF-2026-00891",
|
|
444
467
|
* });
|
|
445
468
|
*/
|
|
446
469
|
async createRefundTicket(params) {
|
|
@@ -448,7 +471,8 @@ var BuyerSession = class {
|
|
|
448
471
|
validateRequired("reason", params.reason);
|
|
449
472
|
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
450
473
|
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
451
|
-
|
|
474
|
+
validateMaxLength("refundTicketMerchantExternalId", params.refundTicketMerchantExternalId, 128);
|
|
475
|
+
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/create-ticket", params));
|
|
452
476
|
}
|
|
453
477
|
/**
|
|
454
478
|
* Resubmit a previously rejected refund ticket with updated details.
|
|
@@ -470,7 +494,7 @@ var BuyerSession = class {
|
|
|
470
494
|
validateRequired("reason", params.reason);
|
|
471
495
|
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
472
496
|
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
473
|
-
return this.http.post("/v1/actions/refund-ticket/resubmit-ticket", params);
|
|
497
|
+
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/resubmit-ticket", params));
|
|
474
498
|
}
|
|
475
499
|
};
|
|
476
500
|
var BuyerGraphQL = class {
|
|
@@ -490,7 +514,8 @@ var BuyerGraphQL = class {
|
|
|
490
514
|
*/
|
|
491
515
|
async query(params) {
|
|
492
516
|
validateRequired("query", params.query);
|
|
493
|
-
|
|
517
|
+
const result = await this.http.post("/v1/graphql", params);
|
|
518
|
+
return { data: result.data, errors: result.errors, warnings: result.warnings };
|
|
494
519
|
}
|
|
495
520
|
};
|
|
496
521
|
|
|
@@ -513,17 +538,20 @@ var CheckoutAnonymousResource = class {
|
|
|
513
538
|
* });
|
|
514
539
|
*
|
|
515
540
|
* @example
|
|
516
|
-
* // Pre-fill email
|
|
541
|
+
* // Pre-fill email + billing + attach business-side order reference
|
|
517
542
|
* const result = await client.checkout.anonymous.create({
|
|
518
543
|
* productId: "PROD_xxx",
|
|
519
544
|
* currency: "USD",
|
|
520
545
|
* buyerEmail: "customer@example.com",
|
|
521
546
|
* billingDetail: { country: "US", isBusiness: false, postcode: "10001" },
|
|
547
|
+
* orderMerchantExternalId: "ORDER-2026-00891",
|
|
522
548
|
* });
|
|
523
549
|
*/
|
|
524
550
|
async create(params) {
|
|
525
551
|
validateCheckoutCommon(params);
|
|
526
|
-
return
|
|
552
|
+
return unwrapAction(
|
|
553
|
+
await this.http.post("/v1/actions/checkout/create-session", params, { idempotencyWindow: 60 })
|
|
554
|
+
);
|
|
527
555
|
}
|
|
528
556
|
};
|
|
529
557
|
|
|
@@ -552,6 +580,7 @@ var CheckoutAuthenticatedResource = class {
|
|
|
552
580
|
* currency: "USD",
|
|
553
581
|
* buyerIdentity: "user-123",
|
|
554
582
|
* buyerEmail: "customer@example.com",
|
|
583
|
+
* orderMerchantExternalId: "ORDER-2026-00891",
|
|
555
584
|
* });
|
|
556
585
|
* // Redirect to result.checkoutUrl (includes #token=...)
|
|
557
586
|
*/
|
|
@@ -570,12 +599,16 @@ var CheckoutAuthenticatedResource = class {
|
|
|
570
599
|
),
|
|
571
600
|
this.http.post("/v1/actions/checkout/create-session", sessionParams, { idempotencyWindow: 60 })
|
|
572
601
|
]);
|
|
602
|
+
const token = unwrapAction(tokenResult);
|
|
603
|
+
const session = unwrapAction(sessionResult);
|
|
604
|
+
const warnings = [...token.warnings ?? [], ...session.warnings ?? []];
|
|
573
605
|
return {
|
|
574
|
-
sessionId:
|
|
575
|
-
checkoutUrl: `${
|
|
576
|
-
expiresAt:
|
|
577
|
-
token:
|
|
578
|
-
tokenExpiresAt:
|
|
606
|
+
sessionId: session.sessionId,
|
|
607
|
+
checkoutUrl: `${session.checkoutUrl}#token=${token.token}`,
|
|
608
|
+
expiresAt: session.expiresAt,
|
|
609
|
+
token: token.token,
|
|
610
|
+
tokenExpiresAt: token.expiresAt,
|
|
611
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
579
612
|
};
|
|
580
613
|
}
|
|
581
614
|
};
|
|
@@ -609,7 +642,9 @@ var CheckoutResource = class {
|
|
|
609
642
|
* // Redirect to session.checkoutUrl
|
|
610
643
|
*/
|
|
611
644
|
async createSession(params) {
|
|
612
|
-
return
|
|
645
|
+
return unwrapAction(
|
|
646
|
+
await this.http.post("/v1/actions/checkout/create-session", params, { idempotencyWindow: 60 })
|
|
647
|
+
);
|
|
613
648
|
}
|
|
614
649
|
};
|
|
615
650
|
|
|
@@ -638,7 +673,8 @@ var GraphQLResource = class {
|
|
|
638
673
|
*/
|
|
639
674
|
async query(params) {
|
|
640
675
|
validateRequired("query", params.query);
|
|
641
|
-
|
|
676
|
+
const result = await this.http.post("/v1/graphql", params, { noIdempotency: true });
|
|
677
|
+
return { data: result.data, errors: result.errors, warnings: result.warnings };
|
|
642
678
|
}
|
|
643
679
|
};
|
|
644
680
|
|
|
@@ -664,7 +700,7 @@ var OnetimeProductsResource = class {
|
|
|
664
700
|
validateShortId("storeId", params.storeId, "STO");
|
|
665
701
|
validateRequired("name", params.name);
|
|
666
702
|
validatePrices("prices", params.prices);
|
|
667
|
-
return this.http.post("/v1/actions/onetime-product/create-product", params);
|
|
703
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-product/create-product", params));
|
|
668
704
|
}
|
|
669
705
|
/**
|
|
670
706
|
* Update a one-time product. Creates a new version; skips if unchanged.
|
|
@@ -690,7 +726,7 @@ var OnetimeProductsResource = class {
|
|
|
690
726
|
validateShortId("id", params.id, "PROD");
|
|
691
727
|
if (params.name !== void 0) validateRequired("name", params.name);
|
|
692
728
|
if (params.prices) validatePrices("prices", params.prices);
|
|
693
|
-
return this.http.post("/v1/actions/onetime-product/update-product", params);
|
|
729
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-product/update-product", params));
|
|
694
730
|
}
|
|
695
731
|
/**
|
|
696
732
|
* Publish a one-time product's test version to production.
|
|
@@ -703,7 +739,7 @@ var OnetimeProductsResource = class {
|
|
|
703
739
|
*/
|
|
704
740
|
async publish(params) {
|
|
705
741
|
validateShortId("id", params.id, "PROD");
|
|
706
|
-
return this.http.post("/v1/actions/onetime-product/publish-product", params);
|
|
742
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-product/publish-product", params));
|
|
707
743
|
}
|
|
708
744
|
/**
|
|
709
745
|
* Update a one-time product's status (active/inactive).
|
|
@@ -720,7 +756,7 @@ var OnetimeProductsResource = class {
|
|
|
720
756
|
async updateStatus(params) {
|
|
721
757
|
validateShortId("id", params.id, "PROD");
|
|
722
758
|
validateEnum("status", params.status, ["active", "inactive"]);
|
|
723
|
-
return this.http.post("/v1/actions/onetime-product/update-status", params);
|
|
759
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-product/update-status", params));
|
|
724
760
|
}
|
|
725
761
|
};
|
|
726
762
|
|
|
@@ -746,7 +782,7 @@ var OrdersResource = class {
|
|
|
746
782
|
*/
|
|
747
783
|
async cancelSubscription(params) {
|
|
748
784
|
validateShortId("orderId", params.orderId, "ORD");
|
|
749
|
-
return this.http.post("/v1/actions/subscription-order/cancel-order", params);
|
|
785
|
+
return unwrapAction(await this.http.post("/v1/actions/subscription-order/cancel-order", params));
|
|
750
786
|
}
|
|
751
787
|
};
|
|
752
788
|
|
|
@@ -772,7 +808,7 @@ var StoreMerchantsResource = class {
|
|
|
772
808
|
validateShortId("storeId", params.storeId, "STO");
|
|
773
809
|
validateRequired("email", params.email);
|
|
774
810
|
validateEnum("role", params.role, ["admin", "member"]);
|
|
775
|
-
return this.http.post("/v1/actions/store-merchant/add-merchant", params);
|
|
811
|
+
return unwrapAction(await this.http.post("/v1/actions/store-merchant/add-merchant", params));
|
|
776
812
|
}
|
|
777
813
|
/**
|
|
778
814
|
* Remove a merchant from a store.
|
|
@@ -789,7 +825,7 @@ var StoreMerchantsResource = class {
|
|
|
789
825
|
async remove(params) {
|
|
790
826
|
validateShortId("storeId", params.storeId, "STO");
|
|
791
827
|
validateShortId("merchantId", params.merchantId, "MER");
|
|
792
|
-
return this.http.post("/v1/actions/store-merchant/remove-merchant", params);
|
|
828
|
+
return unwrapAction(await this.http.post("/v1/actions/store-merchant/remove-merchant", params));
|
|
793
829
|
}
|
|
794
830
|
/**
|
|
795
831
|
* Update a merchant's role in a store.
|
|
@@ -808,7 +844,7 @@ var StoreMerchantsResource = class {
|
|
|
808
844
|
validateShortId("storeId", params.storeId, "STO");
|
|
809
845
|
validateShortId("merchantId", params.merchantId, "MER");
|
|
810
846
|
validateEnum("role", params.role, ["admin", "member"]);
|
|
811
|
-
return this.http.post("/v1/actions/store-merchant/update-role", params);
|
|
847
|
+
return unwrapAction(await this.http.post("/v1/actions/store-merchant/update-role", params));
|
|
812
848
|
}
|
|
813
849
|
};
|
|
814
850
|
|
|
@@ -828,7 +864,7 @@ var StoresResource = class {
|
|
|
828
864
|
*/
|
|
829
865
|
async create(params) {
|
|
830
866
|
validateRequired("name", params.name);
|
|
831
|
-
return this.http.post("/v1/actions/store/create-store", params);
|
|
867
|
+
return unwrapAction(await this.http.post("/v1/actions/store/create-store", params));
|
|
832
868
|
}
|
|
833
869
|
/**
|
|
834
870
|
* Update an existing store's settings.
|
|
@@ -860,7 +896,7 @@ var StoresResource = class {
|
|
|
860
896
|
*/
|
|
861
897
|
async update(params) {
|
|
862
898
|
validateShortId("id", params.id, "STO");
|
|
863
|
-
return this.http.post("/v1/actions/store/update-store", params);
|
|
899
|
+
return unwrapAction(await this.http.post("/v1/actions/store/update-store", params));
|
|
864
900
|
}
|
|
865
901
|
/**
|
|
866
902
|
* Soft-delete a store. Only the owner can delete.
|
|
@@ -873,7 +909,7 @@ var StoresResource = class {
|
|
|
873
909
|
*/
|
|
874
910
|
async delete(params) {
|
|
875
911
|
validateShortId("id", params.id, "STO");
|
|
876
|
-
return this.http.post("/v1/actions/store/delete-store", params);
|
|
912
|
+
return unwrapAction(await this.http.post("/v1/actions/store/delete-store", params));
|
|
877
913
|
}
|
|
878
914
|
};
|
|
879
915
|
|
|
@@ -899,7 +935,9 @@ var SubscriptionProductGroupsResource = class {
|
|
|
899
935
|
async create(params) {
|
|
900
936
|
validateShortId("storeId", params.storeId, "STO");
|
|
901
937
|
validateRequired("name", params.name);
|
|
902
|
-
return
|
|
938
|
+
return unwrapAction(
|
|
939
|
+
await this.http.post("/v1/actions/subscription-product-group/create-group", params)
|
|
940
|
+
);
|
|
903
941
|
}
|
|
904
942
|
/**
|
|
905
943
|
* Update a subscription product group. `productIds` is a full replacement.
|
|
@@ -915,7 +953,9 @@ var SubscriptionProductGroupsResource = class {
|
|
|
915
953
|
*/
|
|
916
954
|
async update(params) {
|
|
917
955
|
validateRequired("id", params.id);
|
|
918
|
-
return
|
|
956
|
+
return unwrapAction(
|
|
957
|
+
await this.http.post("/v1/actions/subscription-product-group/update-group", params)
|
|
958
|
+
);
|
|
919
959
|
}
|
|
920
960
|
/**
|
|
921
961
|
* Hard-delete a subscription product group.
|
|
@@ -928,7 +968,9 @@ var SubscriptionProductGroupsResource = class {
|
|
|
928
968
|
*/
|
|
929
969
|
async delete(params) {
|
|
930
970
|
validateRequired("id", params.id);
|
|
931
|
-
return
|
|
971
|
+
return unwrapAction(
|
|
972
|
+
await this.http.post("/v1/actions/subscription-product-group/delete-group", params)
|
|
973
|
+
);
|
|
932
974
|
}
|
|
933
975
|
/**
|
|
934
976
|
* Publish a test-environment group to production (upsert).
|
|
@@ -941,7 +983,9 @@ var SubscriptionProductGroupsResource = class {
|
|
|
941
983
|
*/
|
|
942
984
|
async publish(params) {
|
|
943
985
|
validateRequired("id", params.id);
|
|
944
|
-
return
|
|
986
|
+
return unwrapAction(
|
|
987
|
+
await this.http.post("/v1/actions/subscription-product-group/publish-group", params)
|
|
988
|
+
);
|
|
945
989
|
}
|
|
946
990
|
};
|
|
947
991
|
|
|
@@ -969,7 +1013,9 @@ var SubscriptionProductsResource = class {
|
|
|
969
1013
|
validateRequired("name", params.name);
|
|
970
1014
|
validateEnum("billingPeriod", params.billingPeriod, ["weekly", "monthly", "quarterly", "yearly"]);
|
|
971
1015
|
validatePrices("prices", params.prices);
|
|
972
|
-
return
|
|
1016
|
+
return unwrapAction(
|
|
1017
|
+
await this.http.post("/v1/actions/subscription-product/create-product", params)
|
|
1018
|
+
);
|
|
973
1019
|
}
|
|
974
1020
|
/**
|
|
975
1021
|
* Update a subscription product. Creates a new version; skips if unchanged.
|
|
@@ -998,7 +1044,9 @@ var SubscriptionProductsResource = class {
|
|
|
998
1044
|
if (params.billingPeriod !== void 0)
|
|
999
1045
|
validateEnum("billingPeriod", params.billingPeriod, ["weekly", "monthly", "quarterly", "yearly"]);
|
|
1000
1046
|
if (params.prices) validatePrices("prices", params.prices);
|
|
1001
|
-
return
|
|
1047
|
+
return unwrapAction(
|
|
1048
|
+
await this.http.post("/v1/actions/subscription-product/update-product", params)
|
|
1049
|
+
);
|
|
1002
1050
|
}
|
|
1003
1051
|
/**
|
|
1004
1052
|
* Publish a subscription product's test version to production.
|
|
@@ -1011,7 +1059,9 @@ var SubscriptionProductsResource = class {
|
|
|
1011
1059
|
*/
|
|
1012
1060
|
async publish(params) {
|
|
1013
1061
|
validateShortId("id", params.id, "PROD");
|
|
1014
|
-
return
|
|
1062
|
+
return unwrapAction(
|
|
1063
|
+
await this.http.post("/v1/actions/subscription-product/publish-product", params)
|
|
1064
|
+
);
|
|
1015
1065
|
}
|
|
1016
1066
|
/**
|
|
1017
1067
|
* Update a subscription product's status (active/inactive).
|
|
@@ -1028,7 +1078,9 @@ var SubscriptionProductsResource = class {
|
|
|
1028
1078
|
async updateStatus(params) {
|
|
1029
1079
|
validateShortId("id", params.id, "PROD");
|
|
1030
1080
|
validateEnum("status", params.status, ["active", "inactive"]);
|
|
1031
|
-
return
|
|
1081
|
+
return unwrapAction(
|
|
1082
|
+
await this.http.post("/v1/actions/subscription-product/update-status", params)
|
|
1083
|
+
);
|
|
1032
1084
|
}
|
|
1033
1085
|
};
|
|
1034
1086
|
|
|
@@ -1185,7 +1237,7 @@ var WebhooksResource = class {
|
|
|
1185
1237
|
validateShortId("storeId", params.storeId, "STO");
|
|
1186
1238
|
validateRequired("channel", params.channel);
|
|
1187
1239
|
validateRequired("url", params.url);
|
|
1188
|
-
return this.http.post("/v1/actions/store/add-webhook", params);
|
|
1240
|
+
return unwrapAction(await this.http.post("/v1/actions/store/add-webhook", params));
|
|
1189
1241
|
}
|
|
1190
1242
|
/**
|
|
1191
1243
|
* Update an existing webhook (only `url`, `events`, and `secret` are mutable).
|
|
@@ -1205,7 +1257,7 @@ var WebhooksResource = class {
|
|
|
1205
1257
|
*/
|
|
1206
1258
|
async update(params) {
|
|
1207
1259
|
validateRequired("id", params.id);
|
|
1208
|
-
return this.http.post("/v1/actions/store/update-webhook", params);
|
|
1260
|
+
return unwrapAction(await this.http.post("/v1/actions/store/update-webhook", params));
|
|
1209
1261
|
}
|
|
1210
1262
|
/**
|
|
1211
1263
|
* Hard-delete a webhook. Historical `webhook_deliveries` rows are retained
|
|
@@ -1219,7 +1271,7 @@ var WebhooksResource = class {
|
|
|
1219
1271
|
*/
|
|
1220
1272
|
async remove(params) {
|
|
1221
1273
|
validateRequired("id", params.id);
|
|
1222
|
-
return this.http.post("/v1/actions/store/remove-webhook", params);
|
|
1274
|
+
return unwrapAction(await this.http.post("/v1/actions/store/remove-webhook", params));
|
|
1223
1275
|
}
|
|
1224
1276
|
/**
|
|
1225
1277
|
* Verify and parse an incoming webhook event.
|