@waffo/pancake-ts 0.8.0 → 0.10.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 +50 -0
- package/README.md +32 -8
- package/dist/index.cjs +11 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +11 -1
- 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,56 @@ 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.10.0] - 2026-06-01
|
|
8
|
+
|
|
9
|
+
Expands `NotificationSettings` to the full 19-field schema (8 consumer-email + 11 merchant-notify toggles) and narrows `UpdateStoreParams.notificationSettings` to the merchant-writable subset.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`NotificationSettings`** gains 11 fields aligning with the platform schema:
|
|
14
|
+
- Consumer email (platform-managed): `emailTrialStarted`, `emailTrialEnding`
|
|
15
|
+
- Merchant notify (merchant-writable): `notifySubscriptionCanceled`, `notifySubscriptionEnded`, `notifySubscriptionPastDue`, `notifySubscriptionRenewed`, `notifySubscriptionUncanceled`, `notifySubscriptionUpdated`, `notifyChargeback`, `notifyPayoutCompleted`, `notifyPayoutFailed`
|
|
16
|
+
- **`MerchantWritableNotificationSettings`** — new type exposing only the 11 `notify*` toggles. Use this for any merchant-side `update-store` call. `email*` toggles are managed by the PANCAKE platform (admin via DB) and silently dropped if passed to the merchant API.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **`UpdateStoreParams.notificationSettings` narrowed** from `Partial<NotificationSettings>` to `Partial<MerchantWritableNotificationSettings>`. Passing `email*` keys now fails TypeScript compilation rather than being silently dropped at the server.
|
|
21
|
+
- README "Update store" example pruned to only show writable `notify*` fields with an explicit comment on the platform-managed `email*` subset.
|
|
22
|
+
|
|
23
|
+
### Migration
|
|
24
|
+
|
|
25
|
+
If your `client.stores.update` calls passed any `emailOrderConfirmation` / `emailSubscription*` / `emailTrial*` keys in `notificationSettings`, remove them — these were already being dropped server-side as of v2026.5 (returned as a `warnings[].aiHint`). Only `notify*` keys are merchant-writable.
|
|
26
|
+
|
|
27
|
+
```diff
|
|
28
|
+
await client.stores.update({
|
|
29
|
+
id: storeId,
|
|
30
|
+
notificationSettings: {
|
|
31
|
+
- emailOrderConfirmation: true,
|
|
32
|
+
- emailSubscriptionCycled: true,
|
|
33
|
+
notifyNewOrders: true,
|
|
34
|
+
notifyNewSubscriptions: false,
|
|
35
|
+
+ notifyChargeback: true,
|
|
36
|
+
+ notifyPayoutFailed: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## [0.9.0] - 2026-05-21
|
|
42
|
+
|
|
43
|
+
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).
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- `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`).
|
|
48
|
+
- `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`).
|
|
49
|
+
- `RefundTicket.refundTicketMerchantExternalId` — response field (immutable across resubmits, max 128 chars).
|
|
50
|
+
- `WebhookEventData.orderMerchantExternalId` — present on order/payment events and on refund events (inherited from the related order).
|
|
51
|
+
- `WebhookEventData.refundTicketMerchantExternalId` — only present on `refund.*` events; coexists with `orderMerchantExternalId` on the same refund payload.
|
|
52
|
+
|
|
53
|
+
### Notes
|
|
54
|
+
|
|
55
|
+
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.
|
|
56
|
+
|
|
7
57
|
## [0.8.0] - 2026-05-17
|
|
8
58
|
|
|
9
59
|
### Fixed
|
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,6 +317,16 @@ 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.
|
|
@@ -343,18 +369,16 @@ const { store } = await client.stores.create({ name: "My Store" });
|
|
|
343
369
|
|
|
344
370
|
// Update settings (notification, checkout theme).
|
|
345
371
|
// NOTE: webhook configuration moved to client.webhooks (see Webhooks section below).
|
|
372
|
+
// NOTE: only merchant-facing `notify*` toggles (notifyNewOrders / notifyNewSubscriptions /
|
|
373
|
+
// notifySubscription* / notifyChargeback / notifyPayout*) are writable here;
|
|
374
|
+
// consumer email toggles (emailOrderConfirmation, emailSubscription*, emailTrial*) are
|
|
375
|
+
// managed by the PANCAKE platform and silently dropped if passed.
|
|
346
376
|
const { store: updated } = await client.stores.update({
|
|
347
377
|
id: store.id,
|
|
348
378
|
supportEmail: "help@example.com",
|
|
349
379
|
notificationSettings: {
|
|
350
|
-
emailOrderConfirmation: true,
|
|
351
|
-
emailSubscriptionConfirmation: true,
|
|
352
|
-
emailSubscriptionCycled: true,
|
|
353
|
-
emailSubscriptionCanceled: true,
|
|
354
|
-
emailSubscriptionRevoked: true,
|
|
355
|
-
emailSubscriptionPastDue: true,
|
|
356
380
|
notifyNewOrders: true,
|
|
357
|
-
notifyNewSubscriptions:
|
|
381
|
+
notifyNewSubscriptions: false,
|
|
358
382
|
},
|
|
359
383
|
});
|
|
360
384
|
|
package/dist/index.cjs
CHANGED
|
@@ -313,6 +313,11 @@ function validateEnum(field, value, allowed) {
|
|
|
313
313
|
fail(`Invalid ${field}: expected one of [${allowed.join(", ")}], got "${value}"`);
|
|
314
314
|
}
|
|
315
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
|
+
}
|
|
316
321
|
function validatePositiveInteger(field, value) {
|
|
317
322
|
if (!Number.isInteger(value) || value <= 0) {
|
|
318
323
|
fail(`Invalid ${field}: expected positive integer, got ${value}`);
|
|
@@ -355,6 +360,7 @@ function validateCheckoutCommon(params) {
|
|
|
355
360
|
if (params.expiresInSeconds !== void 0) {
|
|
356
361
|
validatePositiveInteger("expiresInSeconds", params.expiresInSeconds);
|
|
357
362
|
}
|
|
363
|
+
validateMaxLength("orderMerchantExternalId", params.orderMerchantExternalId, 128);
|
|
358
364
|
}
|
|
359
365
|
|
|
360
366
|
// src/resources/auth.ts
|
|
@@ -457,6 +463,7 @@ var BuyerSession = class {
|
|
|
457
463
|
* paymentId: "PAY_xxx",
|
|
458
464
|
* reason: "Product not as described",
|
|
459
465
|
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
466
|
+
* refundTicketMerchantExternalId: "REF-2026-00891",
|
|
460
467
|
* });
|
|
461
468
|
*/
|
|
462
469
|
async createRefundTicket(params) {
|
|
@@ -464,6 +471,7 @@ var BuyerSession = class {
|
|
|
464
471
|
validateRequired("reason", params.reason);
|
|
465
472
|
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
466
473
|
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
474
|
+
validateMaxLength("refundTicketMerchantExternalId", params.refundTicketMerchantExternalId, 128);
|
|
467
475
|
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/create-ticket", params));
|
|
468
476
|
}
|
|
469
477
|
/**
|
|
@@ -530,12 +538,13 @@ var CheckoutAnonymousResource = class {
|
|
|
530
538
|
* });
|
|
531
539
|
*
|
|
532
540
|
* @example
|
|
533
|
-
* // Pre-fill email
|
|
541
|
+
* // Pre-fill email + billing + attach business-side order reference
|
|
534
542
|
* const result = await client.checkout.anonymous.create({
|
|
535
543
|
* productId: "PROD_xxx",
|
|
536
544
|
* currency: "USD",
|
|
537
545
|
* buyerEmail: "customer@example.com",
|
|
538
546
|
* billingDetail: { country: "US", isBusiness: false, postcode: "10001" },
|
|
547
|
+
* orderMerchantExternalId: "ORDER-2026-00891",
|
|
539
548
|
* });
|
|
540
549
|
*/
|
|
541
550
|
async create(params) {
|
|
@@ -571,6 +580,7 @@ var CheckoutAuthenticatedResource = class {
|
|
|
571
580
|
* currency: "USD",
|
|
572
581
|
* buyerIdentity: "user-123",
|
|
573
582
|
* buyerEmail: "customer@example.com",
|
|
583
|
+
* orderMerchantExternalId: "ORDER-2026-00891",
|
|
574
584
|
* });
|
|
575
585
|
* // Redirect to result.checkoutUrl (includes #token=...)
|
|
576
586
|
*/
|