@waffo/pancake-ts 0.11.0 → 0.12.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 +12 -0
- package/README.md +41 -41
- package/dist/index.cjs +147 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +187 -173
- package/dist/index.d.ts +187 -173
- package/dist/index.js +147 -131
- package/dist/index.js.map +1 -1
- package/docs/api-reference.md +28 -28
- package/docs/webhook-guide.md +14 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.12.0] - 2026-07-14
|
|
8
|
+
|
|
9
|
+
Renames the "buyer" persona to "customer" across the SDK's public API — "customer" is the Waffo term for the merchant's end consumer (the session-token JWT role). Old names remain available as deprecated aliases. Wire-level request and webhook field names (`buyerIdentity`, `buyerEmail`, `merchantProvidedBuyerIdentity`) are part of the server contract and are unchanged.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **`client.customer(token)`** — creates the customer self-service session (class `CustomerSession`, previously `BuyerSession`). Same methods: `cancelSubscription()`, `cancelOnetimeOrder()`, `reactivateSubscription()`, `createRefundTicket()`, `resubmitRefundTicket()`, `graphql.query<T>()`.
|
|
14
|
+
|
|
15
|
+
### Deprecated
|
|
16
|
+
|
|
17
|
+
- **`client.buyer(token)`** — use `client.customer(token)` instead. Thin wrapper around `client.customer()`, identical behavior; will be removed in a future major version.
|
|
18
|
+
|
|
7
19
|
## [0.11.0] - 2026-06-05
|
|
8
20
|
|
|
9
21
|
Aligns Create/Update Product params with backend product-service v2026.6.4: `description` and `successUrl` accept `null` for explicit field clearing (previously only `undefined` / omitted). Backend also tightens `name` to ≤ 64 characters to match the PSP `goodsName` cap — passing a longer name now returns 400.
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install @waffo/pancake-ts
|
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
18
|
-
> Most merchants create stores and products in the [Dashboard](https://pancake.waffo.ai/dashboard). The SDK is primarily used for **checkout integration** — redirecting
|
|
18
|
+
> Most merchants create stores and products in the [Dashboard](https://pancake.waffo.ai/dashboard). The SDK is primarily used for **checkout integration** — redirecting customers from your site to the Waffo checkout page.
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
import { WaffoPancake } from "@waffo/pancake-ts";
|
|
@@ -33,7 +33,7 @@ const result = await client.checkout.authenticated.create({
|
|
|
33
33
|
buyerIdentity: req.user.email, // your user's identity
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
// Redirect
|
|
36
|
+
// Redirect customer to the checkout page (opens in new tab)
|
|
37
37
|
res.json({ checkoutUrl: result.checkoutUrl });
|
|
38
38
|
// => checkoutUrl includes #token=... (form pre-filled)
|
|
39
39
|
```
|
|
@@ -52,24 +52,24 @@ The SDK auto-normalizes key formats: standard PEM, PKCS#1, literal `\n` from env
|
|
|
52
52
|
|
|
53
53
|
## Checkout Integration
|
|
54
54
|
|
|
55
|
-
Waffo supports two checkout modes based on whether the merchant knows the
|
|
55
|
+
Waffo supports two checkout modes based on whether the merchant knows the customer's identity:
|
|
56
56
|
|
|
57
|
-
- **Merchants with their own sites** know who the
|
|
58
|
-
- **Template stores and shared links** have no prior
|
|
57
|
+
- **Merchants with their own sites** know who the customer is — they have user accounts, login systems, or collect customer info before checkout. The merchant provides the customer's identity upfront, and the checkout form arrives pre-filled.
|
|
58
|
+
- **Template stores and shared links** have no prior customer context — the customer arrives directly at the checkout page and fills in their own details.
|
|
59
59
|
|
|
60
|
-
| Mode | Method |
|
|
60
|
+
| Mode | Method | Customer Identity | Form State | Use Case |
|
|
61
61
|
| ----------------- | --------------------------------- | ----------------- | ---------- | ---------------------------------------- |
|
|
62
62
|
| **Authenticated** | `checkout.authenticated.create()` | Merchant provides | Pre-filled | Merchant sites with user accounts |
|
|
63
63
|
| **Anonymous** | `checkout.anonymous.create()` | Not provided | Empty | Template stores, one-time purchase links |
|
|
64
64
|
|
|
65
|
-
> **We recommend authenticated checkout whenever possible.** The most important reason: authenticated checkout binds the order to the `buyerIdentity` you provide, which is a **merchant-controlled stable identifier**. Even if the
|
|
65
|
+
> **We recommend authenticated checkout whenever possible.** The most important reason: authenticated checkout binds the order to the `buyerIdentity` you provide, which is a **merchant-controlled stable identifier**. Even if the customer changes the email on the checkout form, the order is still tied to the identity you specified. In anonymous mode, the customer self-reports their email on the form — if they enter a different address, the system treats them as a new user, which means **previous orders become unlinked** and **subscription trial periods can be exploited** (a new email = a new user = a fresh trial).
|
|
66
66
|
>
|
|
67
|
-
> | | Authenticated
|
|
68
|
-
> | ----------------- |
|
|
69
|
-
> | **Identity** | Merchant-provided, stable across orders
|
|
70
|
-
> | **Form** | Pre-filled from merchant-provided identity
|
|
71
|
-
> | **Post-purchase** | Full self-service (see [
|
|
72
|
-
> | **Session** | 5-minute TTL, auto-refreshes
|
|
67
|
+
> | | Authenticated | Anonymous |
|
|
68
|
+
> | ----------------- | ----------------------------------------------------------------------- | -------------------------------------------------- |
|
|
69
|
+
> | **Identity** | Merchant-provided, stable across orders | Self-reported email, may vary |
|
|
70
|
+
> | **Form** | Pre-filled from merchant-provided identity | Empty, customer fills manually |
|
|
71
|
+
> | **Post-purchase** | Full self-service (see [Customer Self-Service](#customer-self-service)) | Create orders only — no post-purchase self-service |
|
|
72
|
+
> | **Session** | 5-minute TTL, auto-refreshes | 1-minute, single-use |
|
|
73
73
|
|
|
74
74
|
Both modes support **dynamic pricing** and **trial control** at checkout time:
|
|
75
75
|
|
|
@@ -78,12 +78,12 @@ Both modes support **dynamic pricing** and **trial control** at checkout time:
|
|
|
78
78
|
|
|
79
79
|
### Authenticated Checkout (Recommended)
|
|
80
80
|
|
|
81
|
-
The merchant provides
|
|
81
|
+
The merchant provides customer identity — the SDK issues a session token, creates a checkout session, and returns a checkout URL with the token appended as a URL fragment. One call does everything.
|
|
82
82
|
|
|
83
83
|
`buyerIdentity` is for order attribution and trial tracking only — it is not rendered on the checkout page. To pre-fill the email field on the checkout form, pass `buyerEmail` explicitly.
|
|
84
84
|
|
|
85
85
|
```typescript
|
|
86
|
-
// Basic —
|
|
86
|
+
// Basic — customer identity only (checkout page email field stays empty)
|
|
87
87
|
const result = await client.checkout.authenticated.create({
|
|
88
88
|
productId: "PROD_xxx",
|
|
89
89
|
currency: "USD",
|
|
@@ -118,7 +118,7 @@ The token is passed via the URL fragment (after `#`), which is never sent to the
|
|
|
118
118
|
|
|
119
119
|
### Anonymous Checkout
|
|
120
120
|
|
|
121
|
-
No
|
|
121
|
+
No customer identity required — the customer fills in billing details manually on the checkout page.
|
|
122
122
|
|
|
123
123
|
```typescript
|
|
124
124
|
const result = await client.checkout.anonymous.create({
|
|
@@ -142,7 +142,7 @@ window.open(result.checkoutUrl, "_blank", "noopener,noreferrer");
|
|
|
142
142
|
|
|
143
143
|
**We recommend opening the checkout page in a new tab** rather than navigating in the current page:
|
|
144
144
|
|
|
145
|
-
-
|
|
145
|
+
- Customers can return to your site immediately after payment or if they close the checkout tab
|
|
146
146
|
- Merchant page state (cart, forms, scroll position) is preserved
|
|
147
147
|
- Payment flow is decoupled from the browsing experience, reducing checkout abandonment
|
|
148
148
|
|
|
@@ -154,13 +154,13 @@ window.open(result.checkoutUrl, "_blank", "noopener,noreferrer");
|
|
|
154
154
|
// <a href={checkoutUrl} target="_blank" rel="noopener noreferrer">Proceed to Checkout</a>
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
> **Not recommended:** `window.location.href = result.checkoutUrl` replaces the current page, preventing
|
|
157
|
+
> **Not recommended:** `window.location.href = result.checkoutUrl` replaces the current page, preventing customers from returning to your site without browser back navigation.
|
|
158
158
|
|
|
159
159
|
See [API Reference — Checkout](docs/api-reference.md#checkout) for full parameter tables and `BillingDetail` field requirements.
|
|
160
160
|
|
|
161
161
|
## Webhook Verification
|
|
162
162
|
|
|
163
|
-
After a
|
|
163
|
+
After a customer completes payment, Waffo sends webhook events to your server with rich data including order details, amounts, product info, and event-specific fields (payment, subscription, or refund). The SDK provides two ways to verify signatures:
|
|
164
164
|
|
|
165
165
|
### Standalone Function (built-in keys)
|
|
166
166
|
|
|
@@ -179,7 +179,7 @@ app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
|
|
|
179
179
|
case WebhookEventType.OrderCompleted:
|
|
180
180
|
// Rich data: order, amount, product, payment fields
|
|
181
181
|
console.log(`Order ${event.data.orderId} completed — ${event.data.total} ${event.data.currency}`);
|
|
182
|
-
console.log(`Product: ${event.data.productName},
|
|
182
|
+
console.log(`Product: ${event.data.productName}, Customer: ${event.data.buyerEmail}`);
|
|
183
183
|
if (event.data.orderMetadata) console.log("Metadata:", event.data.orderMetadata);
|
|
184
184
|
break;
|
|
185
185
|
case WebhookEventType.SubscriptionActivated:
|
|
@@ -226,34 +226,34 @@ const event = client.webhooks.verify(rawBody, sig, { environment: "prod" });
|
|
|
226
226
|
|
|
227
227
|
See [Webhook Guide](docs/webhook-guide.md) for event types, `WebhookEventData` field reference, dual-environment key architecture, key resolution chain, retry mechanism, and best practices.
|
|
228
228
|
|
|
229
|
-
##
|
|
229
|
+
## Customer Self-Service
|
|
230
230
|
|
|
231
|
-
Beyond checkout, you can let
|
|
231
|
+
Beyond checkout, you can let customers manage their own orders and subscriptions — for example, embedding a "Cancel Subscription" or "Request Refund" button in your site.
|
|
232
232
|
|
|
233
|
-
Issue a session token, then use `client.
|
|
233
|
+
Issue a session token, then use `client.customer(token)` to get a session with self-service methods:
|
|
234
234
|
|
|
235
235
|
```typescript
|
|
236
|
-
// Your backend — issue a session token for the
|
|
236
|
+
// Your backend — issue a session token for the customer
|
|
237
237
|
const { token } = await client.auth.issueSessionToken({
|
|
238
238
|
storeId: "STO_xxx",
|
|
239
239
|
buyerIdentity: req.user.email,
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
-
// Create a
|
|
243
|
-
const
|
|
242
|
+
// Create a customer session
|
|
243
|
+
const customer = client.customer(token);
|
|
244
244
|
|
|
245
245
|
// Cancel a subscription
|
|
246
|
-
const { orderId, status } = await
|
|
246
|
+
const { orderId, status } = await customer.cancelSubscription({ orderId: "ORD_xxx" });
|
|
247
247
|
// status: "canceling" (active) or "canceled" (pending)
|
|
248
248
|
|
|
249
249
|
// Reactivate a canceled subscription
|
|
250
|
-
await
|
|
250
|
+
await customer.reactivateSubscription({ orderId: "ORD_xxx" });
|
|
251
251
|
|
|
252
252
|
// Cancel a one-time order (while payment is pending)
|
|
253
|
-
await
|
|
253
|
+
await customer.cancelOnetimeOrder({ orderId: "ORD_yyy" });
|
|
254
254
|
|
|
255
255
|
// Submit a refund request
|
|
256
|
-
const { ticket } = await
|
|
256
|
+
const { ticket } = await customer.createRefundTicket({
|
|
257
257
|
paymentId: "PAY_xxx",
|
|
258
258
|
reason: "Product not as described",
|
|
259
259
|
requestedAmount: { amount: "29.00", currency: "USD" },
|
|
@@ -261,22 +261,22 @@ const { ticket } = await buyer.createRefundTicket({
|
|
|
261
261
|
});
|
|
262
262
|
|
|
263
263
|
// Resubmit a rejected refund ticket
|
|
264
|
-
await
|
|
264
|
+
await customer.resubmitRefundTicket({
|
|
265
265
|
ticketId: "TKT_xxx",
|
|
266
266
|
paymentId: "PAY_xxx",
|
|
267
267
|
reason: "Updated reason with more detail",
|
|
268
268
|
requestedAmount: { amount: "29.00", currency: "USD" },
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
-
// Query the
|
|
272
|
-
const result = await
|
|
271
|
+
// Query the customer's own orders via GraphQL
|
|
272
|
+
const result = await customer.graphql.query({
|
|
273
273
|
query: `query { orders { id status createdAt } }`,
|
|
274
274
|
});
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
The token is scoped to the specified store and
|
|
277
|
+
The token is scoped to the specified store and customer identity — customers can only access their own data. Token TTL is 5 minutes and auto-refreshes on each API call.
|
|
278
278
|
|
|
279
|
-
> **Note**: This uses the same `buyerIdentity` as `checkout.authenticated.create()`. Orders placed via authenticated checkout are automatically tied to this identity, so the
|
|
279
|
+
> **Note**: This uses the same `buyerIdentity` as `checkout.authenticated.create()`. Orders placed via authenticated checkout are automatically tied to this identity, so the customer can manage them later with a token issued here.
|
|
280
280
|
|
|
281
281
|
## Business-Side Identifiers
|
|
282
282
|
|
|
@@ -285,7 +285,7 @@ Attach your own internal references to a checkout or a refund ticket so cross-sy
|
|
|
285
285
|
| Field | Attach at | Inherited by |
|
|
286
286
|
| -------------------------------- | ------------------------------------------- | ---------------------------------------------------------- |
|
|
287
287
|
| `orderMerchantExternalId` | `checkout.{authenticated,anonymous}.create` | `Order`, `Payment` (incl. subscription renewals), `Refund` |
|
|
288
|
-
| `refundTicketMerchantExternalId` | `
|
|
288
|
+
| `refundTicketMerchantExternalId` | `customer.createRefundTicket` | `RefundTicket`, `Refund` |
|
|
289
289
|
|
|
290
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
291
|
|
|
@@ -531,11 +531,11 @@ try {
|
|
|
531
531
|
| `client.checkout.authenticated` | `create()` | Authenticated checkout (recommended) |
|
|
532
532
|
| `client.checkout.anonymous` | `create()` | Anonymous checkout |
|
|
533
533
|
| `client.checkout` | `createSession()` | Low-level checkout session |
|
|
534
|
-
| `client.
|
|
535
|
-
| `client.
|
|
534
|
+
| `client.customer(token)` | `cancelSubscription()` `cancelOnetimeOrder()` `reactivateSubscription()` `createRefundTicket()` `resubmitRefundTicket()` | Customer self-service |
|
|
535
|
+
| `client.customer(token).graphql` | `query<T>()` | Customer-scoped GraphQL queries |
|
|
536
536
|
| `client.webhooks` | `verify<T>()` `add()` `update()` `remove()` | Webhook config + signature verification |
|
|
537
537
|
| `client.graphql` | `query<T>()` | Merchant GraphQL queries |
|
|
538
|
-
| `client.auth` | `issueSessionToken()` | Issue a
|
|
538
|
+
| `client.auth` | `issueSessionToken()` | Issue a customer session token (JWT) |
|
|
539
539
|
| `client.stores` | `create()` `update()` `delete()` | Store management |
|
|
540
540
|
| `client.storeMerchants` | `add()` `remove()` `updateRole()` | Store members (coming soon) |
|
|
541
541
|
| `client.onetimeProducts` | `create()` `update()` `publish()` `updateStatus()` | One-time products |
|
|
@@ -603,7 +603,7 @@ src/
|
|
|
603
603
|
├── index.ts # Unified export entry
|
|
604
604
|
├── client.ts # WaffoPancake main class
|
|
605
605
|
├── http-client.ts # HTTP client (API Key, auto-signing + idempotency)
|
|
606
|
-
├──
|
|
606
|
+
├── customer-http-client.ts # HTTP client (Bearer token, customer self-service)
|
|
607
607
|
├── signing.ts # RSA-SHA256 request signing
|
|
608
608
|
├── errors.ts # WaffoPancakeError
|
|
609
609
|
├── webhooks.ts # Webhook verification (embedded keys)
|
|
@@ -617,7 +617,7 @@ src/
|
|
|
617
617
|
├── onetime-products.ts
|
|
618
618
|
├── subscription-products.ts
|
|
619
619
|
├── subscription-product-groups.ts
|
|
620
|
-
├──
|
|
620
|
+
├── customer.ts
|
|
621
621
|
├── orders.ts
|
|
622
622
|
├── checkout.ts
|
|
623
623
|
├── checkout-anonymous.ts
|
package/dist/index.cjs
CHANGED
|
@@ -53,9 +53,9 @@ var WaffoPancakeError = class extends Error {
|
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
// src/
|
|
56
|
+
// src/customer-http-client.ts
|
|
57
57
|
var DEFAULT_BASE_URL = "https://api.waffo.ai";
|
|
58
|
-
var
|
|
58
|
+
var CustomerHttpClient = class {
|
|
59
59
|
token;
|
|
60
60
|
baseUrl;
|
|
61
61
|
_fetch;
|
|
@@ -369,7 +369,7 @@ var AuthResource = class {
|
|
|
369
369
|
this.http = http;
|
|
370
370
|
}
|
|
371
371
|
/**
|
|
372
|
-
* Issue a session token for a
|
|
372
|
+
* Issue a session token for a customer.
|
|
373
373
|
*
|
|
374
374
|
* @param params - Token issuance parameters
|
|
375
375
|
* @returns Issued session token with expiration
|
|
@@ -403,122 +403,6 @@ var AuthResource = class {
|
|
|
403
403
|
}
|
|
404
404
|
};
|
|
405
405
|
|
|
406
|
-
// src/resources/buyer.ts
|
|
407
|
-
var BuyerSession = class {
|
|
408
|
-
constructor(http) {
|
|
409
|
-
this.http = http;
|
|
410
|
-
this.graphql = new BuyerGraphQL(http);
|
|
411
|
-
}
|
|
412
|
-
/** GraphQL query access scoped to the buyer's data. */
|
|
413
|
-
graphql;
|
|
414
|
-
/**
|
|
415
|
-
* Cancel a subscription order.
|
|
416
|
-
*
|
|
417
|
-
* @param params - Order to cancel
|
|
418
|
-
* @returns Order ID and resulting status
|
|
419
|
-
*
|
|
420
|
-
* @example
|
|
421
|
-
* const { orderId, status } = await buyer.cancelSubscription({ orderId: "ORD_xxx" });
|
|
422
|
-
* // status: "canceled" (was pending) or "canceling" (was active)
|
|
423
|
-
*/
|
|
424
|
-
async cancelSubscription(params) {
|
|
425
|
-
validateShortId("orderId", params.orderId, "ORD");
|
|
426
|
-
return unwrapAction(await this.http.post("/v1/actions/subscription-order/cancel-order", params));
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Cancel a one-time order (only while payment is still pending).
|
|
430
|
-
*
|
|
431
|
-
* @param params - Order to cancel
|
|
432
|
-
* @returns Order ID and resulting status
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* const { orderId, status } = await buyer.cancelOnetimeOrder({ orderId: "ORD_xxx" });
|
|
436
|
-
*/
|
|
437
|
-
async cancelOnetimeOrder(params) {
|
|
438
|
-
validateShortId("orderId", params.orderId, "ORD");
|
|
439
|
-
return unwrapAction(await this.http.post("/v1/actions/onetime-order/cancel-order", params));
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Reactivate a subscription that is in `canceling` status.
|
|
443
|
-
*
|
|
444
|
-
* @param params - Order to reactivate
|
|
445
|
-
* @returns Order ID and resulting status
|
|
446
|
-
*
|
|
447
|
-
* @example
|
|
448
|
-
* const { orderId, status } = await buyer.reactivateSubscription({ orderId: "ORD_xxx" });
|
|
449
|
-
* // status: "active"
|
|
450
|
-
*/
|
|
451
|
-
async reactivateSubscription(params) {
|
|
452
|
-
validateShortId("orderId", params.orderId, "ORD");
|
|
453
|
-
return unwrapAction(await this.http.post("/v1/actions/subscription-order/reactivate-order", params));
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Submit a refund request for a payment.
|
|
457
|
-
*
|
|
458
|
-
* @param params - Refund ticket details
|
|
459
|
-
* @returns Created refund ticket
|
|
460
|
-
*
|
|
461
|
-
* @example
|
|
462
|
-
* const { ticket } = await buyer.createRefundTicket({
|
|
463
|
-
* paymentId: "PAY_xxx",
|
|
464
|
-
* reason: "Product not as described",
|
|
465
|
-
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
466
|
-
* refundTicketMerchantExternalId: "REF-2026-00891",
|
|
467
|
-
* });
|
|
468
|
-
*/
|
|
469
|
-
async createRefundTicket(params) {
|
|
470
|
-
validateShortId("paymentId", params.paymentId, "PAY");
|
|
471
|
-
validateRequired("reason", params.reason);
|
|
472
|
-
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
473
|
-
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
474
|
-
validateMaxLength("refundTicketMerchantExternalId", params.refundTicketMerchantExternalId, 128);
|
|
475
|
-
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/create-ticket", params));
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Resubmit a previously rejected refund ticket with updated details.
|
|
479
|
-
*
|
|
480
|
-
* @param params - Updated ticket details
|
|
481
|
-
* @returns Updated refund ticket
|
|
482
|
-
*
|
|
483
|
-
* @example
|
|
484
|
-
* const { ticket } = await buyer.resubmitRefundTicket({
|
|
485
|
-
* ticketId: "TKT_xxx",
|
|
486
|
-
* paymentId: "PAY_xxx",
|
|
487
|
-
* reason: "Updated reason with more detail",
|
|
488
|
-
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
489
|
-
* });
|
|
490
|
-
*/
|
|
491
|
-
async resubmitRefundTicket(params) {
|
|
492
|
-
validateShortId("ticketId", params.ticketId, "TKT");
|
|
493
|
-
validateShortId("paymentId", params.paymentId, "PAY");
|
|
494
|
-
validateRequired("reason", params.reason);
|
|
495
|
-
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
496
|
-
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
497
|
-
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/resubmit-ticket", params));
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
var BuyerGraphQL = class {
|
|
501
|
-
constructor(http) {
|
|
502
|
-
this.http = http;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Execute a GraphQL query scoped to the buyer's data.
|
|
506
|
-
*
|
|
507
|
-
* @param params - GraphQL query and variables
|
|
508
|
-
* @returns GraphQL response
|
|
509
|
-
*
|
|
510
|
-
* @example
|
|
511
|
-
* const result = await buyer.graphql.query({
|
|
512
|
-
* query: `query { orders { id status } }`,
|
|
513
|
-
* });
|
|
514
|
-
*/
|
|
515
|
-
async query(params) {
|
|
516
|
-
validateRequired("query", params.query);
|
|
517
|
-
const result = await this.http.post("/v1/graphql", params);
|
|
518
|
-
return { data: result.data, errors: result.errors, warnings: result.warnings };
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
406
|
// src/resources/checkout-anonymous.ts
|
|
523
407
|
var CheckoutAnonymousResource = class {
|
|
524
408
|
constructor(http) {
|
|
@@ -527,11 +411,11 @@ var CheckoutAnonymousResource = class {
|
|
|
527
411
|
/**
|
|
528
412
|
* Create an anonymous checkout session.
|
|
529
413
|
*
|
|
530
|
-
* @param params - Checkout parameters (no
|
|
414
|
+
* @param params - Checkout parameters (no customer identity required)
|
|
531
415
|
* @returns Session ID, checkout URL, and expiration
|
|
532
416
|
*
|
|
533
417
|
* @example
|
|
534
|
-
* // Minimal —
|
|
418
|
+
* // Minimal — customer fills everything on the page
|
|
535
419
|
* const result = await client.checkout.anonymous.create({
|
|
536
420
|
* productId: "PROD_xxx",
|
|
537
421
|
* currency: "USD",
|
|
@@ -571,7 +455,7 @@ var CheckoutAuthenticatedResource = class {
|
|
|
571
455
|
* `buyerIdentity` and `buyerEmail` are independent inputs: identity is for the JWT,
|
|
572
456
|
* email is for pre-filling the checkout page. The SDK forwards each to its own endpoint.
|
|
573
457
|
*
|
|
574
|
-
* @param params - Checkout parameters including
|
|
458
|
+
* @param params - Checkout parameters including customer identity
|
|
575
459
|
* @returns Session details with token-appended checkout URL
|
|
576
460
|
*
|
|
577
461
|
* @example
|
|
@@ -620,9 +504,9 @@ var CheckoutResource = class {
|
|
|
620
504
|
this.anonymous = new CheckoutAnonymousResource(http);
|
|
621
505
|
this.authenticated = new CheckoutAuthenticatedResource(http);
|
|
622
506
|
}
|
|
623
|
-
/** Anonymous checkout — no
|
|
507
|
+
/** Anonymous checkout — no customer identity, empty form. */
|
|
624
508
|
anonymous;
|
|
625
|
-
/** Authenticated checkout — merchant provides
|
|
509
|
+
/** Authenticated checkout — merchant provides customer identity. */
|
|
626
510
|
authenticated;
|
|
627
511
|
/**
|
|
628
512
|
* Create a checkout session (low-level). Returns a URL to redirect the customer to.
|
|
@@ -648,6 +532,122 @@ var CheckoutResource = class {
|
|
|
648
532
|
}
|
|
649
533
|
};
|
|
650
534
|
|
|
535
|
+
// src/resources/customer.ts
|
|
536
|
+
var CustomerSession = class {
|
|
537
|
+
constructor(http) {
|
|
538
|
+
this.http = http;
|
|
539
|
+
this.graphql = new CustomerGraphQL(http);
|
|
540
|
+
}
|
|
541
|
+
/** GraphQL query access scoped to the customer's data. */
|
|
542
|
+
graphql;
|
|
543
|
+
/**
|
|
544
|
+
* Cancel a subscription order.
|
|
545
|
+
*
|
|
546
|
+
* @param params - Order to cancel
|
|
547
|
+
* @returns Order ID and resulting status
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* const { orderId, status } = await customer.cancelSubscription({ orderId: "ORD_xxx" });
|
|
551
|
+
* // status: "canceled" (was pending) or "canceling" (was active)
|
|
552
|
+
*/
|
|
553
|
+
async cancelSubscription(params) {
|
|
554
|
+
validateShortId("orderId", params.orderId, "ORD");
|
|
555
|
+
return unwrapAction(await this.http.post("/v1/actions/subscription-order/cancel-order", params));
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Cancel a one-time order (only while payment is still pending).
|
|
559
|
+
*
|
|
560
|
+
* @param params - Order to cancel
|
|
561
|
+
* @returns Order ID and resulting status
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* const { orderId, status } = await customer.cancelOnetimeOrder({ orderId: "ORD_xxx" });
|
|
565
|
+
*/
|
|
566
|
+
async cancelOnetimeOrder(params) {
|
|
567
|
+
validateShortId("orderId", params.orderId, "ORD");
|
|
568
|
+
return unwrapAction(await this.http.post("/v1/actions/onetime-order/cancel-order", params));
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Reactivate a subscription that is in `canceling` status.
|
|
572
|
+
*
|
|
573
|
+
* @param params - Order to reactivate
|
|
574
|
+
* @returns Order ID and resulting status
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* const { orderId, status } = await customer.reactivateSubscription({ orderId: "ORD_xxx" });
|
|
578
|
+
* // status: "active"
|
|
579
|
+
*/
|
|
580
|
+
async reactivateSubscription(params) {
|
|
581
|
+
validateShortId("orderId", params.orderId, "ORD");
|
|
582
|
+
return unwrapAction(await this.http.post("/v1/actions/subscription-order/reactivate-order", params));
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Submit a refund request for a payment.
|
|
586
|
+
*
|
|
587
|
+
* @param params - Refund ticket details
|
|
588
|
+
* @returns Created refund ticket
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* const { ticket } = await customer.createRefundTicket({
|
|
592
|
+
* paymentId: "PAY_xxx",
|
|
593
|
+
* reason: "Product not as described",
|
|
594
|
+
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
595
|
+
* refundTicketMerchantExternalId: "REF-2026-00891",
|
|
596
|
+
* });
|
|
597
|
+
*/
|
|
598
|
+
async createRefundTicket(params) {
|
|
599
|
+
validateShortId("paymentId", params.paymentId, "PAY");
|
|
600
|
+
validateRequired("reason", params.reason);
|
|
601
|
+
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
602
|
+
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
603
|
+
validateMaxLength("refundTicketMerchantExternalId", params.refundTicketMerchantExternalId, 128);
|
|
604
|
+
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/create-ticket", params));
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Resubmit a previously rejected refund ticket with updated details.
|
|
608
|
+
*
|
|
609
|
+
* @param params - Updated ticket details
|
|
610
|
+
* @returns Updated refund ticket
|
|
611
|
+
*
|
|
612
|
+
* @example
|
|
613
|
+
* const { ticket } = await customer.resubmitRefundTicket({
|
|
614
|
+
* ticketId: "TKT_xxx",
|
|
615
|
+
* paymentId: "PAY_xxx",
|
|
616
|
+
* reason: "Updated reason with more detail",
|
|
617
|
+
* requestedAmount: { amount: "29.00", currency: "USD" },
|
|
618
|
+
* });
|
|
619
|
+
*/
|
|
620
|
+
async resubmitRefundTicket(params) {
|
|
621
|
+
validateShortId("ticketId", params.ticketId, "TKT");
|
|
622
|
+
validateShortId("paymentId", params.paymentId, "PAY");
|
|
623
|
+
validateRequired("reason", params.reason);
|
|
624
|
+
validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
|
|
625
|
+
validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
|
|
626
|
+
return unwrapAction(await this.http.post("/v1/actions/refund-ticket/resubmit-ticket", params));
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
var CustomerGraphQL = class {
|
|
630
|
+
constructor(http) {
|
|
631
|
+
this.http = http;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Execute a GraphQL query scoped to the customer's data.
|
|
635
|
+
*
|
|
636
|
+
* @param params - GraphQL query and variables
|
|
637
|
+
* @returns GraphQL response
|
|
638
|
+
*
|
|
639
|
+
* @example
|
|
640
|
+
* const result = await customer.graphql.query({
|
|
641
|
+
* query: `query { orders { id status } }`,
|
|
642
|
+
* });
|
|
643
|
+
*/
|
|
644
|
+
async query(params) {
|
|
645
|
+
validateRequired("query", params.query);
|
|
646
|
+
const result = await this.http.post("/v1/graphql", params);
|
|
647
|
+
return { data: result.data, errors: result.errors, warnings: result.warnings };
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
651
651
|
// src/resources/graphql.ts
|
|
652
652
|
var GraphQLResource = class {
|
|
653
653
|
constructor(http) {
|
|
@@ -1339,29 +1339,45 @@ var WaffoPancake = class {
|
|
|
1339
1339
|
this.webhooks = new WebhooksResource(this.http, config.webhookPublicKey);
|
|
1340
1340
|
}
|
|
1341
1341
|
/**
|
|
1342
|
-
* Create a
|
|
1342
|
+
* Create a customer session for self-service operations.
|
|
1343
1343
|
*
|
|
1344
1344
|
* The returned session uses Bearer token authentication and provides
|
|
1345
1345
|
* methods for order cancellation, subscription management, refund tickets,
|
|
1346
1346
|
* and scoped GraphQL queries.
|
|
1347
1347
|
*
|
|
1348
1348
|
* @param token - Session token from `client.auth.issueSessionToken()`
|
|
1349
|
-
* @returns A
|
|
1349
|
+
* @returns A customer session with self-service methods
|
|
1350
1350
|
*
|
|
1351
1351
|
* @example
|
|
1352
1352
|
* const { token } = await client.auth.issueSessionToken({
|
|
1353
1353
|
* storeId: "STO_xxx",
|
|
1354
1354
|
* buyerIdentity: "customer@example.com",
|
|
1355
1355
|
* });
|
|
1356
|
-
* const
|
|
1357
|
-
* await
|
|
1356
|
+
* const customer = client.customer(token);
|
|
1357
|
+
* await customer.cancelSubscription({ orderId: "ORD_xxx" });
|
|
1358
1358
|
*/
|
|
1359
|
-
|
|
1360
|
-
const
|
|
1359
|
+
customer(token) {
|
|
1360
|
+
const customerHttp = new CustomerHttpClient(token, {
|
|
1361
1361
|
baseUrl: this.config.baseUrl,
|
|
1362
1362
|
fetch: this.config.fetch
|
|
1363
1363
|
});
|
|
1364
|
-
return new
|
|
1364
|
+
return new CustomerSession(customerHttp);
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Create a customer session for self-service operations.
|
|
1368
|
+
*
|
|
1369
|
+
* @param token - Session token from `client.auth.issueSessionToken()`
|
|
1370
|
+
* @returns A customer session with self-service methods
|
|
1371
|
+
*
|
|
1372
|
+
* @example
|
|
1373
|
+
* ```typescript
|
|
1374
|
+
* const session = client.buyer(token); // prefer client.customer(token)
|
|
1375
|
+
* ```
|
|
1376
|
+
*
|
|
1377
|
+
* @deprecated Use {@link WaffoPancake.customer} instead.
|
|
1378
|
+
*/
|
|
1379
|
+
buyer(token) {
|
|
1380
|
+
return this.customer(token);
|
|
1365
1381
|
}
|
|
1366
1382
|
};
|
|
1367
1383
|
|