@waffo/pancake-ts 0.1.5 → 0.1.7
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 +7 -4
- package/README.md +54 -19
- package/dist/index.cjs +45 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -17
- package/dist/index.d.ts +68 -17
- package/dist/index.js +45 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,10 +8,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), version
|
|
|
8
8
|
|
|
9
9
|
### Added
|
|
10
10
|
|
|
11
|
-
- **Custom webhook public key** — `WaffoPancakeConfig` accepts
|
|
12
|
-
-
|
|
13
|
-
- **`
|
|
14
|
-
-
|
|
11
|
+
- **Custom webhook public key** — `WaffoPancakeConfig.webhookPublicKey` accepts `string` (shared) or `{ test?, prod? }` (per-environment) to override built-in keys.
|
|
12
|
+
- **Multi-level key resolution** — Webhook public key is resolved per environment: `options.publicKey` (per-call) → config key → `WAFFO_WEBHOOK_{TEST|PROD}_PUBLIC_KEY` env var → `WAFFO_WEBHOOK_PUBLIC_KEY` env var → built-in hardcoded key.
|
|
13
|
+
- **`client.webhooks.verify()`** — New resource namespace on the client instance. Injects config-level keys into the resolution chain automatically; supports per-call override via `options.publicKey`.
|
|
14
|
+
- **`VerifyWebhookOptions.publicKey`** — Per-call override for the standalone `verifyWebhook()` function (highest priority, skips all resolution).
|
|
15
|
+
- **`VerifyWebhookOptions.publicKeys`** — Config-level key(s) for the resolution chain (typically injected by `client.webhooks.verify()`).
|
|
16
|
+
- **`WebhookPublicKeys` type** — `string | { test?: string; prod?: string }`, exported from the package.
|
|
17
|
+
- **Public key normalization** — `normalizePublicKey()` handles the same flexible input formats as `normalizePrivateKey`: literal `\n` from environment variables, Windows `\r\n` line endings, raw base64 without PEM headers, single-line base64, and PKCS#1 (`BEGIN RSA PUBLIC KEY`) format. Applied automatically at every level of the resolution chain.
|
|
15
18
|
|
|
16
19
|
## [0.1.6] - 2026-03-18
|
|
17
20
|
|
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ const result = await client.graphql.query<{ stores: Array<{ id: string; name: st
|
|
|
59
59
|
| `privateKey` | `string` | Yes | RSA private key (see [Private Key Formats](#private-key-formats) below) |
|
|
60
60
|
| `baseUrl` | `string` | No | API base URL (default: `https://waffo-pancake-auth-service.vercel.app`) |
|
|
61
61
|
| `fetch` | `typeof fetch` | No | Custom fetch implementation |
|
|
62
|
-
| `webhookPublicKey` | `string` | No | Custom
|
|
62
|
+
| `webhookPublicKey` | `string \| { test?, prod? }` | No | Custom webhook public key(s) (see [Webhook Public Key Resolution](#webhook-public-key-resolution) below) |
|
|
63
63
|
|
|
64
64
|
### Private Key Formats
|
|
65
65
|
|
|
@@ -83,9 +83,43 @@ new WaffoPancake({ merchantId: "m_1", privateKey: fs.readFileSync("key.pem", "ut
|
|
|
83
83
|
new WaffoPancake({ merchantId: "m_1", privateKey: rawBase64String }); // raw base64
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### Webhook Public Key Resolution
|
|
87
|
+
|
|
88
|
+
The SDK resolves the webhook verification public key per environment using a multi-level fallback chain:
|
|
89
|
+
|
|
90
|
+
| Priority | Source | Description |
|
|
91
|
+
|----------|--------|-------------|
|
|
92
|
+
| 1 | `options.publicKey` | Per-call override (highest priority, skips all resolution) |
|
|
93
|
+
| 2 | `config.webhookPublicKey[env]` | Config object per-environment key |
|
|
94
|
+
| 3 | `config.webhookPublicKey` (string) | Config shared key (both environments) |
|
|
95
|
+
| 4 | `WAFFO_WEBHOOK_TEST_PUBLIC_KEY` / `WAFFO_WEBHOOK_PROD_PUBLIC_KEY` | Environment variable per-environment |
|
|
96
|
+
| 5 | `WAFFO_WEBHOOK_PUBLIC_KEY` | Environment variable shared |
|
|
97
|
+
| 6 | Built-in hardcoded key | SDK-embedded Waffo public key (default) |
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Shared key for both environments
|
|
101
|
+
new WaffoPancake({ merchantId: "m_1", privateKey: "...", webhookPublicKey: "MIIBIjAN..." });
|
|
102
|
+
|
|
103
|
+
// Per-environment keys
|
|
104
|
+
new WaffoPancake({
|
|
105
|
+
merchantId: "m_1",
|
|
106
|
+
privateKey: "...",
|
|
107
|
+
webhookPublicKey: {
|
|
108
|
+
test: process.env.WAFFO_TEST_PUB_KEY!,
|
|
109
|
+
prod: process.env.WAFFO_PROD_PUB_KEY!,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Or rely on environment variables (no config needed)
|
|
114
|
+
// export WAFFO_WEBHOOK_TEST_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n..."
|
|
115
|
+
// export WAFFO_WEBHOOK_PROD_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n..."
|
|
116
|
+
new WaffoPancake({ merchantId: "m_1", privateKey: "..." });
|
|
117
|
+
// => SDK auto-reads from env vars, falls back to built-in keys
|
|
118
|
+
```
|
|
119
|
+
|
|
86
120
|
### Public Key Formats
|
|
87
121
|
|
|
88
|
-
|
|
122
|
+
All public key inputs (config, env vars, per-call) accept the same flexible formats as private keys:
|
|
89
123
|
|
|
90
124
|
| Format | Example | Notes |
|
|
91
125
|
|--------|---------|-------|
|
|
@@ -462,33 +496,34 @@ const event = verifyWebhook(body, sig, { environment: "prod" });
|
|
|
462
496
|
const event = verifyWebhook(body, sig, { toleranceMs: 0 }); // disable replay check
|
|
463
497
|
```
|
|
464
498
|
|
|
465
|
-
### Option B — Client Instance Method (
|
|
499
|
+
### Option B — Client Instance Method (multi-level key resolution)
|
|
466
500
|
|
|
467
|
-
|
|
501
|
+
`client.webhooks.verify()` uses the [multi-level fallback chain](#webhook-public-key-resolution) automatically: config keys → env vars → built-in keys.
|
|
468
502
|
|
|
469
503
|
```typescript
|
|
504
|
+
// Per-environment keys via config
|
|
470
505
|
const client = new WaffoPancake({
|
|
471
506
|
merchantId: process.env.WAFFO_MERCHANT_ID!,
|
|
472
507
|
privateKey: process.env.WAFFO_PRIVATE_KEY!,
|
|
473
|
-
webhookPublicKey:
|
|
508
|
+
webhookPublicKey: {
|
|
509
|
+
test: process.env.WAFFO_TEST_PUB_KEY!,
|
|
510
|
+
prod: process.env.WAFFO_PROD_PUB_KEY!,
|
|
511
|
+
},
|
|
474
512
|
});
|
|
513
|
+
const event = client.webhooks.verify(rawBody, sig, { environment: "prod" });
|
|
475
514
|
|
|
476
|
-
//
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
### Standalone Function with Custom Key
|
|
484
|
-
|
|
485
|
-
You can also pass a custom key directly to the standalone function without creating a client:
|
|
515
|
+
// Or rely on env vars (WAFFO_WEBHOOK_TEST_PUBLIC_KEY / WAFFO_WEBHOOK_PROD_PUBLIC_KEY)
|
|
516
|
+
const client2 = new WaffoPancake({
|
|
517
|
+
merchantId: process.env.WAFFO_MERCHANT_ID!,
|
|
518
|
+
privateKey: process.env.WAFFO_PRIVATE_KEY!,
|
|
519
|
+
});
|
|
520
|
+
const event2 = client2.webhooks.verify(rawBody, sig); // auto-detect environment
|
|
486
521
|
|
|
487
|
-
|
|
488
|
-
const
|
|
522
|
+
// Per-call override (highest priority, skips all resolution)
|
|
523
|
+
const event3 = client.webhooks.verify(rawBody, sig, { publicKey: oneOffKey });
|
|
489
524
|
```
|
|
490
525
|
|
|
491
|
-
See [Webhook Guide](docs/webhook-guide.md) for
|
|
526
|
+
See [Webhook Guide](docs/webhook-guide.md) for event types, signature algorithm, public key resolution, and best practices.
|
|
492
527
|
|
|
493
528
|
## Error Handling
|
|
494
529
|
|
|
@@ -547,7 +582,7 @@ Runtime-accessible values. Both `Enum.Value` and string literal syntax are suppo
|
|
|
547
582
|
|
|
548
583
|
### Types
|
|
549
584
|
|
|
550
|
-
See [API Reference — Types](docs/api-reference.md#types) for the full list
|
|
585
|
+
Key types: `WaffoPancakeConfig`, `WebhookPublicKeys`, `VerifyWebhookOptions`, `WebhookEvent<T>`, `Store`, `OnetimeProductDetail`, `SubscriptionProductDetail`, `CheckoutSessionResult`, `GraphQLResponse<T>`, and 30+ more. See [API Reference — Types](docs/api-reference.md#types) for the full list.
|
|
551
586
|
|
|
552
587
|
## Development
|
|
553
588
|
|
package/dist/index.cjs
CHANGED
|
@@ -654,6 +654,23 @@ function rsaVerify(signatureInput, v1, publicKey) {
|
|
|
654
654
|
verifier.update(signatureInput);
|
|
655
655
|
return verifier.verify(publicKey, v1, "base64");
|
|
656
656
|
}
|
|
657
|
+
function resolveKeyForEnv(env, configKeys) {
|
|
658
|
+
if (typeof configKeys === "string") {
|
|
659
|
+
return normalizePublicKey(configKeys);
|
|
660
|
+
}
|
|
661
|
+
if (configKeys?.[env]) {
|
|
662
|
+
return normalizePublicKey(configKeys[env]);
|
|
663
|
+
}
|
|
664
|
+
const envSpecific = env === "test" ? process.env.WAFFO_WEBHOOK_TEST_PUBLIC_KEY : process.env.WAFFO_WEBHOOK_PROD_PUBLIC_KEY;
|
|
665
|
+
if (envSpecific) {
|
|
666
|
+
return normalizePublicKey(envSpecific);
|
|
667
|
+
}
|
|
668
|
+
const generic = process.env.WAFFO_WEBHOOK_PUBLIC_KEY;
|
|
669
|
+
if (generic) {
|
|
670
|
+
return normalizePublicKey(generic);
|
|
671
|
+
}
|
|
672
|
+
return env === "test" ? TEST_PUBLIC_KEY : PROD_PUBLIC_KEY;
|
|
673
|
+
}
|
|
657
674
|
function verifyWebhook(payload, signatureHeader, options) {
|
|
658
675
|
if (!signatureHeader) {
|
|
659
676
|
throw new Error("Missing X-Waffo-Signature header");
|
|
@@ -673,27 +690,25 @@ function verifyWebhook(payload, signatureHeader, options) {
|
|
|
673
690
|
}
|
|
674
691
|
}
|
|
675
692
|
const signatureInput = `${t}.${payload}`;
|
|
676
|
-
const
|
|
677
|
-
if (
|
|
678
|
-
const normalizedKey = normalizePublicKey(
|
|
693
|
+
const directKey = options?.publicKey;
|
|
694
|
+
if (directKey) {
|
|
695
|
+
const normalizedKey = normalizePublicKey(directKey);
|
|
679
696
|
if (!rsaVerify(signatureInput, v1, normalizedKey)) {
|
|
680
697
|
throw new Error("Invalid webhook signature (custom key)");
|
|
681
698
|
}
|
|
682
699
|
} else {
|
|
700
|
+
const configKeys = options?.publicKeys;
|
|
683
701
|
const env = options?.environment;
|
|
684
|
-
if (env === "test") {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
} else if (env === "prod") {
|
|
689
|
-
if (!rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY)) {
|
|
690
|
-
throw new Error("Invalid webhook signature (prod key)");
|
|
702
|
+
if (env === "test" || env === "prod") {
|
|
703
|
+
const key = resolveKeyForEnv(env, configKeys);
|
|
704
|
+
if (!rsaVerify(signatureInput, v1, key)) {
|
|
705
|
+
throw new Error(`Invalid webhook signature (${env} key)`);
|
|
691
706
|
}
|
|
692
707
|
} else {
|
|
693
|
-
const
|
|
694
|
-
if (!
|
|
695
|
-
const
|
|
696
|
-
if (!
|
|
708
|
+
const prodKey = resolveKeyForEnv("prod", configKeys);
|
|
709
|
+
if (!rsaVerify(signatureInput, v1, prodKey)) {
|
|
710
|
+
const testKey = resolveKeyForEnv("test", configKeys);
|
|
711
|
+
if (!rsaVerify(signatureInput, v1, testKey)) {
|
|
697
712
|
throw new Error("Invalid webhook signature (tried both prod and test keys)");
|
|
698
713
|
}
|
|
699
714
|
}
|
|
@@ -704,15 +719,19 @@ function verifyWebhook(payload, signatureHeader, options) {
|
|
|
704
719
|
|
|
705
720
|
// src/resources/webhooks.ts
|
|
706
721
|
var WebhooksResource = class {
|
|
707
|
-
/** @param
|
|
708
|
-
constructor(
|
|
709
|
-
this.
|
|
722
|
+
/** @param publicKeys - Optional config-level public key(s) from WaffoPancakeConfig */
|
|
723
|
+
constructor(publicKeys) {
|
|
724
|
+
this.publicKeys = publicKeys;
|
|
710
725
|
}
|
|
711
726
|
/**
|
|
712
727
|
* Verify and parse an incoming webhook event.
|
|
713
728
|
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
729
|
+
* Key resolution order:
|
|
730
|
+
* 1. `options.publicKey` — per-call override (highest priority)
|
|
731
|
+
* 2. `config.webhookPublicKey[env]` or `config.webhookPublicKey` (string)
|
|
732
|
+
* 3. `WAFFO_WEBHOOK_{TEST|PROD}_PUBLIC_KEY` environment variable
|
|
733
|
+
* 4. `WAFFO_WEBHOOK_PUBLIC_KEY` environment variable
|
|
734
|
+
* 5. Built-in hardcoded key
|
|
716
735
|
*
|
|
717
736
|
* @param payload - Raw request body string (must be unparsed)
|
|
718
737
|
* @param signatureHeader - Value of the `X-Waffo-Signature` header
|
|
@@ -724,13 +743,17 @@ var WebhooksResource = class {
|
|
|
724
743
|
* const event = client.webhooks.verify(rawBody, signatureHeader);
|
|
725
744
|
*
|
|
726
745
|
* @example
|
|
727
|
-
* //
|
|
728
|
-
* const event = client.webhooks.verify(rawBody, sig, {
|
|
746
|
+
* // Specify environment
|
|
747
|
+
* const event = client.webhooks.verify(rawBody, sig, { environment: "test" });
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* // Per-call key override
|
|
751
|
+
* const event = client.webhooks.verify(rawBody, sig, { publicKey: oneOffKey });
|
|
729
752
|
*/
|
|
730
753
|
verify(payload, signatureHeader, options) {
|
|
731
754
|
const mergedOptions = {
|
|
732
755
|
...options,
|
|
733
|
-
|
|
756
|
+
publicKeys: options?.publicKeys ?? this.publicKeys
|
|
734
757
|
};
|
|
735
758
|
return verifyWebhook(payload, signatureHeader, mergedOptions);
|
|
736
759
|
}
|