@waffo/pancake-ts 0.3.1 → 0.3.2
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 +6 -0
- package/README.md +66 -69
- package/dist/index.cjs +36 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +36 -64
- package/dist/index.js.map +1 -1
- package/docs/api-reference.md +290 -289
- package/docs/graphql-guide.md +12 -12
- package/docs/webhook-guide.md +79 -82
- package/package.json +15 -2
package/docs/graphql-guide.md
CHANGED
|
@@ -438,12 +438,12 @@ const counts = await client.graphql.query({
|
|
|
438
438
|
|
|
439
439
|
## Filter Types
|
|
440
440
|
|
|
441
|
-
| Filter Type
|
|
442
|
-
|
|
443
|
-
| `StringFilter`
|
|
444
|
-
| `DateTimeFilter` | `eq`, `ne`, `gt`, `gte`, `lt`, `lte`
|
|
445
|
-
| `IntFilter`
|
|
446
|
-
| `BooleanFilter`
|
|
441
|
+
| Filter Type | Operations | Example Fields |
|
|
442
|
+
| ---------------- | ------------------------------------------------------ | ------------------------------------- |
|
|
443
|
+
| `StringFilter` | `eq`, `ne`, `contains`, `startsWith`, `endsWith`, `in` | `status`, `name`, `email`, `currency` |
|
|
444
|
+
| `DateTimeFilter` | `eq`, `ne`, `gt`, `gte`, `lt`, `lte` | `createdAt`, `updatedAt`, `expiresAt` |
|
|
445
|
+
| `IntFilter` | `eq`, `ne`, `gt`, `gte`, `lt`, `lte` | `amount`, `totalAmount` |
|
|
446
|
+
| `BooleanFilter` | `eq` | `prodEnabled`, `testMode` |
|
|
447
447
|
|
|
448
448
|
> To see which filter fields are available for a specific entity, use introspection:
|
|
449
449
|
> `__type(name: "OnetimeOrderFilter") { fields { name type { name } } }`
|
|
@@ -456,12 +456,12 @@ Analytics queries provide aggregated statistics, trends, and insights. All analy
|
|
|
456
456
|
|
|
457
457
|
### AnalyticsFilterInput
|
|
458
458
|
|
|
459
|
-
| Field
|
|
460
|
-
|
|
461
|
-
| `filter.timeRange.startDate` | `String` | Yes
|
|
462
|
-
| `filter.timeRange.endDate`
|
|
463
|
-
| `filter.currency`
|
|
464
|
-
| `filter.status`
|
|
459
|
+
| Field | Type | Required | Description |
|
|
460
|
+
| ---------------------------- | -------- | -------- | -------------------------- |
|
|
461
|
+
| `filter.timeRange.startDate` | `String` | Yes | Start time (ISO 8601) |
|
|
462
|
+
| `filter.timeRange.endDate` | `String` | Yes | End time (ISO 8601) |
|
|
463
|
+
| `filter.currency` | `String` | No | Currency filter (ISO 4217) |
|
|
464
|
+
| `filter.status` | `String` | No | Status filter |
|
|
465
465
|
|
|
466
466
|
### TimePeriodGranularity
|
|
467
467
|
|
package/docs/webhook-guide.md
CHANGED
|
@@ -29,10 +29,7 @@ import { verifyWebhook, WebhookEventType } from "@waffo/pancake-ts";
|
|
|
29
29
|
// IMPORTANT: Use raw body — parsed JSON will break signature verification
|
|
30
30
|
app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
|
|
31
31
|
try {
|
|
32
|
-
const event = verifyWebhook(
|
|
33
|
-
req.body.toString("utf-8"),
|
|
34
|
-
req.headers["x-waffo-signature"] as string,
|
|
35
|
-
);
|
|
32
|
+
const event = verifyWebhook(req.body.toString("utf-8"), req.headers["x-waffo-signature"] as string);
|
|
36
33
|
|
|
37
34
|
// Respond immediately, process asynchronously
|
|
38
35
|
res.status(200).send("OK");
|
|
@@ -92,20 +89,20 @@ const event = verifyWebhook(body, sig, { toleranceMs: 600000 });
|
|
|
92
89
|
|
|
93
90
|
## Parameters
|
|
94
91
|
|
|
95
|
-
| Parameter
|
|
96
|
-
|
|
97
|
-
| `payload`
|
|
92
|
+
| Parameter | Type | Description |
|
|
93
|
+
| ----------------- | ----------------------------- | ------------------------------------------------------------------------- |
|
|
94
|
+
| `payload` | `string` | Raw request body string (must be unparsed) |
|
|
98
95
|
| `signatureHeader` | `string \| undefined \| null` | `X-Waffo-Signature` header value (format: `t=<timestamp>,v1=<signature>`) |
|
|
99
|
-
| `options`
|
|
96
|
+
| `options` | `VerifyWebhookOptions` | Optional configuration |
|
|
100
97
|
|
|
101
98
|
### `VerifyWebhookOptions`
|
|
102
99
|
|
|
103
|
-
| Field
|
|
104
|
-
|
|
105
|
-
| `environment` | `"test" \| "prod"`
|
|
106
|
-
| `toleranceMs` | `number`
|
|
107
|
-
| `publicKey`
|
|
108
|
-
| `publicKeys`
|
|
100
|
+
| Field | Type | Default | Description |
|
|
101
|
+
| ------------- | ---------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `environment` | `"test" \| "prod"` | auto-detect | Which environment's key to resolve. When omitted, tries prod first, then test. Ignored when `publicKey` is set. |
|
|
103
|
+
| `toleranceMs` | `number` | `300000` (5 min) | Timestamp tolerance in ms. Set to `0` to skip timestamp check |
|
|
104
|
+
| `publicKey` | `string` | — | Per-call public key override (highest priority, skips all resolution) |
|
|
105
|
+
| `publicKeys` | `string \| { test?, prod? }` | — | Config-level key(s) for the resolution chain. Typically injected automatically by `client.webhooks.verify()` |
|
|
109
106
|
|
|
110
107
|
## Dual-Environment Public Key Architecture
|
|
111
108
|
|
|
@@ -233,10 +230,10 @@ const client = new WaffoPancake({
|
|
|
233
230
|
|
|
234
231
|
When no config key is found, the SDK reads from process environment variables:
|
|
235
232
|
|
|
236
|
-
| Environment | Variable Name
|
|
237
|
-
|
|
238
|
-
| test
|
|
239
|
-
| prod
|
|
233
|
+
| Environment | Variable Name |
|
|
234
|
+
| ----------- | ------------------------------- |
|
|
235
|
+
| test | `WAFFO_WEBHOOK_TEST_PUBLIC_KEY` |
|
|
236
|
+
| prod | `WAFFO_WEBHOOK_PROD_PUBLIC_KEY` |
|
|
240
237
|
|
|
241
238
|
> **When built-in hardcoded keys become invalid (e.g., Waffo rotates platform keys, or you migrate to a self-hosted deployment), the minimum-effort fix is to set environment variables. No code changes, no redeployment of application code — just update the env vars in your hosting platform (Vercel, AWS, Docker, etc.) and the SDK picks them up automatically on the next request.**
|
|
242
239
|
|
|
@@ -271,8 +268,8 @@ client.webhooks.verify(body, sig, { environment: "prod" });
|
|
|
271
268
|
|
|
272
269
|
A single env var for both environments:
|
|
273
270
|
|
|
274
|
-
| Variable Name
|
|
275
|
-
|
|
271
|
+
| Variable Name | Used for |
|
|
272
|
+
| -------------------------- | ------------------ |
|
|
276
273
|
| `WAFFO_WEBHOOK_PUBLIC_KEY` | Both test and prod |
|
|
277
274
|
|
|
278
275
|
```bash
|
|
@@ -292,27 +289,27 @@ const event = verifyWebhook(body, sig);
|
|
|
292
289
|
|
|
293
290
|
### Resolution Examples
|
|
294
291
|
|
|
295
|
-
| Scenario
|
|
296
|
-
|
|
297
|
-
| Default (no config) | —
|
|
298
|
-
| Shared config key
|
|
299
|
-
| Per-env config
|
|
300
|
-
| Env var only
|
|
301
|
-
| Config + env var
|
|
302
|
-
| Per-call override
|
|
292
|
+
| Scenario | Config | Env Var | Result (prod) |
|
|
293
|
+
| ------------------- | ------------------------------------- | ------------------------------------- | ------------------------ |
|
|
294
|
+
| Default (no config) | — | — | Built-in prod key |
|
|
295
|
+
| Shared config key | `webhookPublicKey: "KEY_A"` | — | `KEY_A` |
|
|
296
|
+
| Per-env config | `webhookPublicKey: { prod: "KEY_B" }` | — | `KEY_B` |
|
|
297
|
+
| Env var only | — | `WAFFO_WEBHOOK_PROD_PUBLIC_KEY=KEY_C` | `KEY_C` |
|
|
298
|
+
| Config + env var | `webhookPublicKey: { prod: "KEY_D" }` | `WAFFO_WEBHOOK_PROD_PUBLIC_KEY=KEY_E` | `KEY_D` (config wins) |
|
|
299
|
+
| Per-call override | `webhookPublicKey: { prod: "KEY_F" }` | — | `options.publicKey` wins |
|
|
303
300
|
|
|
304
301
|
## Public Key Formats
|
|
305
302
|
|
|
306
303
|
All public key inputs at every level (config, env vars, per-call) are automatically **normalized** by the SDK. The following formats are accepted:
|
|
307
304
|
|
|
308
|
-
| Format
|
|
309
|
-
|
|
310
|
-
| Standard SPKI PEM
|
|
311
|
-
| PKCS#1 PEM
|
|
312
|
-
| Literal `\n` (env vars) | `"-----BEGIN PUBLIC KEY-----\\nMIIB..."`
|
|
313
|
-
| Windows line endings
|
|
314
|
-
| Raw base64 (no headers) | `MIIBIjANBgkqhki...`
|
|
315
|
-
| Single-line base64
|
|
305
|
+
| Format | Example | Notes |
|
|
306
|
+
| ----------------------- | ----------------------------------------------------------- | --------------------------------------- |
|
|
307
|
+
| Standard SPKI PEM | `-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----` | Recommended |
|
|
308
|
+
| PKCS#1 PEM | `-----BEGIN RSA PUBLIC KEY-----\n...` | Also accepted |
|
|
309
|
+
| Literal `\n` (env vars) | `"-----BEGIN PUBLIC KEY-----\\nMIIB..."` | Common in `.env` files and CI secrets |
|
|
310
|
+
| Windows line endings | `\r\n` | Converted to `\n` |
|
|
311
|
+
| Raw base64 (no headers) | `MIIBIjANBgkqhki...` | Wrapped with SPKI headers automatically |
|
|
312
|
+
| Single-line base64 | Header + all base64 on one line + footer | Re-wrapped to 64-char lines |
|
|
316
313
|
|
|
317
314
|
Normalization is applied **on every call** — there is no eager validation at construction time (unlike `privateKey`). Invalid keys produce a descriptive error at verification time.
|
|
318
315
|
|
|
@@ -325,9 +322,9 @@ Best for simple setups where you don't need the SDK client. Uses env vars and bu
|
|
|
325
322
|
```typescript
|
|
326
323
|
import { verifyWebhook } from "@waffo/pancake-ts";
|
|
327
324
|
|
|
328
|
-
const event = verifyWebhook(body, sig);
|
|
329
|
-
const event = verifyWebhook(body, sig, { environment: "prod" });
|
|
330
|
-
const event = verifyWebhook(body, sig, { publicKey: customKey });
|
|
325
|
+
const event = verifyWebhook(body, sig); // built-in keys
|
|
326
|
+
const event = verifyWebhook(body, sig, { environment: "prod" }); // explicit env
|
|
327
|
+
const event = verifyWebhook(body, sig, { publicKey: customKey }); // per-call key
|
|
331
328
|
```
|
|
332
329
|
|
|
333
330
|
### Client Instance Method — `client.webhooks.verify()`
|
|
@@ -346,9 +343,9 @@ const client = new WaffoPancake({
|
|
|
346
343
|
},
|
|
347
344
|
});
|
|
348
345
|
|
|
349
|
-
const event = client.webhooks.verify(body, sig);
|
|
346
|
+
const event = client.webhooks.verify(body, sig); // auto-detect with config keys
|
|
350
347
|
const event = client.webhooks.verify(body, sig, { environment: "test" }); // explicit env
|
|
351
|
-
const event = client.webhooks.verify(body, sig, { publicKey: oneOff });
|
|
348
|
+
const event = client.webhooks.verify(body, sig, { publicKey: oneOff }); // per-call override
|
|
352
349
|
```
|
|
353
350
|
|
|
354
351
|
Both APIs share the same underlying verification logic and resolution chain.
|
|
@@ -357,41 +354,41 @@ Both APIs share the same underlying verification logic and resolution chain.
|
|
|
357
354
|
|
|
358
355
|
### `WebhookEvent<T>`
|
|
359
356
|
|
|
360
|
-
| Field
|
|
361
|
-
|
|
362
|
-
| `id`
|
|
363
|
-
| `timestamp` | `string` | Event timestamp (ISO 8601 UTC)
|
|
364
|
-
| `eventType` | `string` | Event type (e.g. `"order.completed"`)
|
|
365
|
-
| `eventId`
|
|
366
|
-
| `storeId`
|
|
367
|
-
| `mode`
|
|
368
|
-
| `data`
|
|
357
|
+
| Field | Type | Description |
|
|
358
|
+
| ----------- | -------- | ------------------------------------------------------------------- |
|
|
359
|
+
| `id` | `string` | Delivery record unique ID (UUID) — use for idempotent deduplication |
|
|
360
|
+
| `timestamp` | `string` | Event timestamp (ISO 8601 UTC) |
|
|
361
|
+
| `eventType` | `string` | Event type (e.g. `"order.completed"`) |
|
|
362
|
+
| `eventId` | `string` | Business event ID (e.g. payment ID) |
|
|
363
|
+
| `storeId` | `string` | Store ID the event belongs to |
|
|
364
|
+
| `mode` | `string` | Environment (`"test"` or `"prod"`) |
|
|
365
|
+
| `data` | `T` | Event data (defaults to `WebhookEventData`) |
|
|
369
366
|
|
|
370
367
|
### `WebhookEventData`
|
|
371
368
|
|
|
372
|
-
| Field
|
|
373
|
-
|
|
374
|
-
| `orderId`
|
|
375
|
-
| `buyerEmail`
|
|
376
|
-
| `currency`
|
|
377
|
-
| `amount`
|
|
378
|
-
| `taxAmount`
|
|
379
|
-
| `productName` | `string` | Product name
|
|
369
|
+
| Field | Type | Description |
|
|
370
|
+
| ------------- | -------- | --------------------------------------------------------------------------------- |
|
|
371
|
+
| `orderId` | `string` | Associated order ID |
|
|
372
|
+
| `buyerEmail` | `string` | Buyer email address |
|
|
373
|
+
| `currency` | `string` | Currency code (ISO 4217) |
|
|
374
|
+
| `amount` | `string` | Amount in display format (e.g., `"29.00"` for $29.00 USD, `"4500"` for ¥4500 JPY) |
|
|
375
|
+
| `taxAmount` | `string` | Tax amount in display format (e.g., `"2.90"`) |
|
|
376
|
+
| `productName` | `string` | Product name |
|
|
380
377
|
|
|
381
378
|
## Event Types
|
|
382
379
|
|
|
383
|
-
| Enum Value
|
|
384
|
-
|
|
385
|
-
| `OrderCompleted`
|
|
386
|
-
| `SubscriptionActivated`
|
|
387
|
-
| `SubscriptionPaymentSucceeded` | `subscription.payment_succeeded` | Subscription renewal payment succeeded
|
|
388
|
-
| `SubscriptionCanceling`
|
|
389
|
-
| `SubscriptionUncanceled`
|
|
390
|
-
| `SubscriptionUpdated`
|
|
391
|
-
| `SubscriptionCanceled`
|
|
392
|
-
| `SubscriptionPastDue`
|
|
393
|
-
| `RefundSucceeded`
|
|
394
|
-
| `RefundFailed`
|
|
380
|
+
| Enum Value | String | Trigger |
|
|
381
|
+
| ------------------------------ | -------------------------------- | --------------------------------------------------------------- |
|
|
382
|
+
| `OrderCompleted` | `order.completed` | One-time order first payment succeeded |
|
|
383
|
+
| `SubscriptionActivated` | `subscription.activated` | New subscription activated |
|
|
384
|
+
| `SubscriptionPaymentSucceeded` | `subscription.payment_succeeded` | Subscription renewal payment succeeded |
|
|
385
|
+
| `SubscriptionCanceling` | `subscription.canceling` | Buyer initiated cancellation (expires at end of billing period) |
|
|
386
|
+
| `SubscriptionUncanceled` | `subscription.uncanceled` | Buyer withdrew cancellation request |
|
|
387
|
+
| `SubscriptionUpdated` | `subscription.updated` | Subscription product changed (upgrade/downgrade) |
|
|
388
|
+
| `SubscriptionCanceled` | `subscription.canceled` | Subscription fully terminated |
|
|
389
|
+
| `SubscriptionPastDue` | `subscription.past_due` | Renewal payment failed (past due) |
|
|
390
|
+
| `RefundSucceeded` | `refund.succeeded` | Refund completed successfully |
|
|
391
|
+
| `RefundFailed` | `refund.failed` | Refund failed |
|
|
395
392
|
|
|
396
393
|
## Key Rotation & Migration
|
|
397
394
|
|
|
@@ -423,23 +420,23 @@ When rotating keys, the old key remains valid for a transition period:
|
|
|
423
420
|
|
|
424
421
|
### Choosing the right level
|
|
425
422
|
|
|
426
|
-
| Situation
|
|
427
|
-
|
|
428
|
-
| Standard Waffo Pancake user | Level 6 (default)
|
|
429
|
-
| Built-in keys expired
|
|
430
|
-
| Self-hosted deployment
|
|
431
|
-
| Testing a new key
|
|
432
|
-
| CI/CD with different keys
|
|
423
|
+
| Situation | Recommended Level | Why |
|
|
424
|
+
| --------------------------- | ------------------ | --------------------------------------- |
|
|
425
|
+
| Standard Waffo Pancake user | Level 6 (default) | Built-in keys just work, zero config |
|
|
426
|
+
| Built-in keys expired | Level 4 (env var) | No code changes, set env var and done |
|
|
427
|
+
| Self-hosted deployment | Level 2/3 (config) | Custom keys are part of your app config |
|
|
428
|
+
| Testing a new key | Level 1 (per-call) | One-off override, no permanent change |
|
|
429
|
+
| CI/CD with different keys | Level 4 (env var) | Each environment sets its own env var |
|
|
433
430
|
|
|
434
431
|
## Retry Mechanism
|
|
435
432
|
|
|
436
433
|
When delivery fails (non-2xx response or timeout), the system automatically retries using **exponential backoff** (managed by the underlying message queue). Default: 3 retries.
|
|
437
434
|
|
|
438
|
-
| Delivery Status | Description
|
|
439
|
-
|
|
440
|
-
| `pending`
|
|
441
|
-
| `success`
|
|
442
|
-
| `failed`
|
|
435
|
+
| Delivery Status | Description |
|
|
436
|
+
| --------------- | ----------------------------------------- |
|
|
437
|
+
| `pending` | Created, waiting for delivery or retrying |
|
|
438
|
+
| `success` | Delivery successful (server returned 2xx) |
|
|
439
|
+
| `failed` | All retries exhausted, final failure |
|
|
443
440
|
|
|
444
441
|
You can view each delivery's status, HTTP status code, and response content in the dashboard's Webhook logs.
|
|
445
442
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waffo/pancake-ts",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "TypeScript SDK for Waffo Pancake API (Merchant API Key authentication)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -30,13 +30,16 @@
|
|
|
30
30
|
"test": "vitest run",
|
|
31
31
|
"test:watch": "vitest",
|
|
32
32
|
"test:coverage": "vitest run --coverage",
|
|
33
|
-
"prepublishOnly": "npm run lint && npm run test && npm run build"
|
|
33
|
+
"prepublishOnly": "npm run lint && npm run test && npm run build",
|
|
34
|
+
"prepare": "husky"
|
|
34
35
|
},
|
|
35
36
|
"engines": {
|
|
36
37
|
"node": ">=20.0.0"
|
|
37
38
|
},
|
|
38
39
|
"license": "MIT",
|
|
39
40
|
"devDependencies": {
|
|
41
|
+
"@commitlint/cli": "^20.5.0",
|
|
42
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
40
43
|
"@types/node": "^25.3.5",
|
|
41
44
|
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
|
42
45
|
"@typescript-eslint/parser": "^8.20.0",
|
|
@@ -45,9 +48,19 @@
|
|
|
45
48
|
"eslint-import-resolver-typescript": "^3.7.0",
|
|
46
49
|
"eslint-plugin-import": "^2.31.0",
|
|
47
50
|
"eslint-plugin-jsdoc": "^50.6.3",
|
|
51
|
+
"husky": "^9.1.7",
|
|
52
|
+
"lint-staged": "^16.4.0",
|
|
53
|
+
"prettier": "^3.8.1",
|
|
48
54
|
"tsup": "^8.5.1",
|
|
49
55
|
"typescript": "^5.4.0",
|
|
50
56
|
"typescript-eslint": "^8.20.0",
|
|
51
57
|
"vitest": "^4.0.16"
|
|
58
|
+
},
|
|
59
|
+
"lint-staged": {
|
|
60
|
+
"*.{ts,tsx}": [
|
|
61
|
+
"eslint --fix",
|
|
62
|
+
"prettier --write"
|
|
63
|
+
],
|
|
64
|
+
"*.{json,md,css}": "prettier --write"
|
|
52
65
|
}
|
|
53
66
|
}
|