@genesis-tech/genesispay-seller 0.8.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +330 -0
  2. package/LICENSE +21 -0
  3. package/README.md +429 -0
  4. package/dist/client.d.ts +275 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +541 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/customers.d.ts +41 -0
  9. package/dist/customers.d.ts.map +1 -0
  10. package/dist/customers.js +76 -0
  11. package/dist/customers.js.map +1 -0
  12. package/dist/errors.d.ts +63 -0
  13. package/dist/errors.d.ts.map +1 -0
  14. package/dist/errors.js +162 -0
  15. package/dist/errors.js.map +1 -0
  16. package/dist/index.d.ts +13 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +13 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/invoices.d.ts +80 -0
  21. package/dist/invoices.d.ts.map +1 -0
  22. package/dist/invoices.js +133 -0
  23. package/dist/invoices.js.map +1 -0
  24. package/dist/mandate-gate.d.ts +49 -0
  25. package/dist/mandate-gate.d.ts.map +1 -0
  26. package/dist/mandate-gate.js +109 -0
  27. package/dist/mandate-gate.js.map +1 -0
  28. package/dist/mandates.d.ts +172 -0
  29. package/dist/mandates.d.ts.map +1 -0
  30. package/dist/mandates.js +213 -0
  31. package/dist/mandates.js.map +1 -0
  32. package/dist/networks.d.ts +10 -0
  33. package/dist/networks.d.ts.map +1 -0
  34. package/dist/networks.js +22 -0
  35. package/dist/networks.js.map +1 -0
  36. package/dist/payment-gate.d.ts +67 -0
  37. package/dist/payment-gate.d.ts.map +1 -0
  38. package/dist/payment-gate.js +106 -0
  39. package/dist/payment-gate.js.map +1 -0
  40. package/dist/peerpay-settlement.d.ts +27 -0
  41. package/dist/peerpay-settlement.d.ts.map +1 -0
  42. package/dist/peerpay-settlement.js +100 -0
  43. package/dist/peerpay-settlement.js.map +1 -0
  44. package/dist/plans.d.ts +68 -0
  45. package/dist/plans.d.ts.map +1 -0
  46. package/dist/plans.js +127 -0
  47. package/dist/plans.js.map +1 -0
  48. package/dist/resource.d.ts +47 -0
  49. package/dist/resource.d.ts.map +1 -0
  50. package/dist/resource.js +71 -0
  51. package/dist/resource.js.map +1 -0
  52. package/dist/usdc-amount.d.ts +7 -0
  53. package/dist/usdc-amount.d.ts.map +1 -0
  54. package/dist/usdc-amount.js +21 -0
  55. package/dist/usdc-amount.js.map +1 -0
  56. package/dist/webhooks.d.ts +277 -0
  57. package/dist/webhooks.d.ts.map +1 -0
  58. package/dist/webhooks.js +223 -0
  59. package/dist/webhooks.js.map +1 -0
  60. package/package.json +58 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Every event type this SDK version knows. Mirrors the server's
3
+ * `WebhookEventType` (`src/features/sellers/webhooks.ts`) — the drift alarm is
4
+ * `src/features/sellers/webhook-signature-contract.test.ts`, which fails when
5
+ * the server grows a type this list does not have.
6
+ *
7
+ * Exported as a runtime array (not only as a type) so a handler can ask
8
+ * `isKnownPeerPayEventType(event.type)` before it decides what to do.
9
+ */
10
+ export declare const PEERPAY_EVENT_TYPES: readonly ["payment.confirmed", "link.paid", "agent_payment.pending_approval", "agent_payment.settled", "mandate.active", "mandate.charged", "mandate.charge_failed", "mandate.revoked", "subscription.renewed", "subscription.past_due"];
11
+ /** Union of the event types this SDK version knows. */
12
+ export type PeerPayEventType = (typeof PEERPAY_EVENT_TYPES)[number];
13
+ /** True when `type` is an event type this SDK version knows about. */
14
+ export declare function isKnownPeerPayEventType(type: string): type is PeerPayEventType;
15
+ /** Shared envelope; `type`/`data` are pinned per event by the union below. */
16
+ type PeerPayEventEnvelope<TType extends string, TData> = {
17
+ /** Stable across delivery retries — the idempotency key to dedupe on. */
18
+ id: string;
19
+ type: TType;
20
+ createdAt: string;
21
+ data: TData;
22
+ };
23
+ /**
24
+ * `data` of `payment.confirmed` / `link.paid`. Mirrors the server's
25
+ * `PaymentWebhookEventPayload`; amounts stay strings (minor units are `bigint`
26
+ * on the server and would lose precision as a JSON number).
27
+ */
28
+ export type PeerPayPaymentEventData = {
29
+ link: {
30
+ publicId: string;
31
+ title: string;
32
+ /**
33
+ * The currency `amount` is denominated in. Read it before you book the
34
+ * money: a EURC link settles in euros, and nothing else in this payload
35
+ * says so.
36
+ *
37
+ * **Optional on purpose, unlike every other field here.** The payload is
38
+ * not re-validated at runtime — `constructEvent` checks the signature and
39
+ * the envelope, then hands the body over — and a delivery enqueued before
40
+ * this field existed is stored and *retried* verbatim, so it can still
41
+ * arrive without one. There is no safe default to fill in: guessing
42
+ * `"USDC"` on a euro payment is the exact confusion this field was added to
43
+ * remove. Treat an absent asset as "cannot book this yet" — ack the
44
+ * delivery, alert, resolve the link through `checkout.retrieve`.
45
+ */
46
+ asset?: "USDC" | "EURC";
47
+ /**
48
+ * Decimal amount in `asset` — euros on a EURC link, dollars on a USDC one.
49
+ * A delivery that predates this field omits it, but unlike `asset` it has a
50
+ * safe fallback: `amount ?? amountUsdc`, which always carried the identical
51
+ * value. That is why this one is typed as present and `asset` is not.
52
+ *
53
+ * The two are emitted by the same code path, so a delivery missing one is
54
+ * missing the other and the `asset` guard fires first — the fallback is
55
+ * belt-and-braces, not the main line of defence. Keep them emitted together
56
+ * if you ever change that path.
57
+ */
58
+ amount: string;
59
+ amountUsdcMinor: string;
60
+ /**
61
+ * @deprecated Same value as `amount`. The name is wrong on a EURC link —
62
+ * it carries euros there — which is why `amount` replaced it. Still sent on
63
+ * every delivery; removed no earlier than 1.0.
64
+ */
65
+ amountUsdc: string;
66
+ linkType: "single" | "reusable";
67
+ /** Correlation data set at link creation, echoed verbatim. */
68
+ metadata: Record<string, string> | null;
69
+ clientReferenceId: string | null;
70
+ };
71
+ attempt: {
72
+ id: string;
73
+ /** `null` for simulated payments — there is no transaction to link to. */
74
+ txHash: string | null;
75
+ /**
76
+ * The chain `txHash` is on. Today every settlement reports `8453`/`84532`
77
+ * (Base mainnet/Sepolia) — but do **not** hard-code that as the whole set.
78
+ * Match the chain you expect and treat anything else as unrecognized rather
79
+ * than as test money; a bare `chainId !== 8453` test inverts on the first
80
+ * chain that is added.
81
+ *
82
+ * Read it *with* the hash and never separately: the same hash string
83
+ * resolves to nothing on the wrong chain, and a testnet settlement is
84
+ * otherwise indistinguishable from a mainnet one.
85
+ *
86
+ * It sits here rather than on `link` because the two can differ: a
87
+ * settlement broadcast by a provider lands on the chain that provider uses,
88
+ * which is not necessarily the chain the link was created for.
89
+ *
90
+ * `null` when there is no hash to resolve, or the provider named no chain.
91
+ * Optional — a delivery enqueued before this field existed is retried
92
+ * verbatim and arrives without it. **Do not default it.** Note the polarity
93
+ * trap: `undefined !== 8453` is true, so the natural `if (chainId !== 8453)`
94
+ * check reads a *missing* chain as testnet, and the mirror check reads it as
95
+ * mainnet. Branch on presence first.
96
+ */
97
+ chainId?: number | null;
98
+ payerWallet: string | null;
99
+ createdAt: string;
100
+ confirmedAt: string | null;
101
+ /**
102
+ * `true` when no funds moved — a test-mode `simulate-payment` attempt.
103
+ * `false` for a real settlement, including on testnet and in provider
104
+ * sandboxes: this is the fabricated-payment axis, not the environment axis.
105
+ */
106
+ simulated: boolean;
107
+ /**
108
+ * The gross the link is priced at, in minor units of `link.asset` (=
109
+ * `link.amountUsdcMinor`). Additive with the fee triplet below; older
110
+ * deliveries enqueued before these fields existed arrive without them, so
111
+ * treat them as optional and do not default `feeCollected` (MR-804).
112
+ */
113
+ amountMinor?: string;
114
+ /** Platform fee snapshot in minor units of `link.asset`. */
115
+ feeMinor?: string;
116
+ /**
117
+ * `amountMinor − feeMinor` — what the seller nets IF the fee is collected
118
+ * on-chain. Do not book it unconditionally: the seller's actual on-chain
119
+ * credit is `feeCollected ? netMinor : amountMinor`. A record-only leg
120
+ * (`feeCollected: false`) credited the seller the full `amountMinor` — the
121
+ * fee is a receivable that did not move at settlement.
122
+ */
123
+ netMinor?: string;
124
+ /**
125
+ * Whether the fee actually moved to the treasury on-chain. `false` on a
126
+ * record-only leg (single-auth checkout, agent, EUR, or a pending
127
+ * receivable) is correct, not a bug. Do not infer it from the presence of
128
+ * `feeTxHash` alone; read this flag — it is the switch for what the seller
129
+ * was credited: `feeCollected ? netMinor : amountMinor`.
130
+ */
131
+ feeCollected?: boolean;
132
+ /** The fee leg's tx hash; `null` unless the fee was collected on-chain. */
133
+ feeTxHash?: string | null;
134
+ };
135
+ occurredAt: string;
136
+ };
137
+ /** `data` of the mandate/subscription events; mirrors `buildMandateWebhookPayload`. */
138
+ export type PeerPayMandateEventData = {
139
+ mandate: {
140
+ id: string;
141
+ kind: string;
142
+ status: string;
143
+ payerWallet: string;
144
+ /**
145
+ * Which plan the subscription belongs to — without it a `mandate.active`
146
+ * handler knows *that* someone subscribed but not *to what*. `null` for
147
+ * mandates proposed directly rather than through a plan checkout. Like
148
+ * every field here it mirrors the current server payload and is not
149
+ * re-validated at runtime, so read it as `?? null` if you also accept
150
+ * deliveries from a deployment that predates the field.
151
+ */
152
+ subscriptionPlanId: string | null;
153
+ asset: string;
154
+ allowanceMinor: string;
155
+ capPerChargeMinor: string;
156
+ spentMinor: string;
157
+ amountPerPeriodMinor: string | null;
158
+ periodDays: number | null;
159
+ nextChargeAt: string | null;
160
+ };
161
+ charge: {
162
+ id: string;
163
+ kind: string;
164
+ amountMinor: string;
165
+ status: string;
166
+ txHash: string | null;
167
+ /**
168
+ * The platform fee in minor units of the mandate's `asset` (MR-104). The
169
+ * seller receives `amountMinor − feeMinor` once the fee is collected.
170
+ *
171
+ * Optional like every field added after launch: `webhook_deliveries` rows
172
+ * are replayed verbatim, so a delivery enqueued before this field existed
173
+ * arrives without it. Read it as `?? null`.
174
+ */
175
+ feeMinor?: string;
176
+ /**
177
+ * Whether the fee was collected on-chain (MR-1008/MR-1009). `true` only
178
+ * when the fee leg's transfer confirmed; `false` on every record-only leg
179
+ * (a deployment not collecting on the mandate leg, or a still-pending
180
+ * receivable) — and that `false` is the honest state, not an error. Do NOT
181
+ * default a missing value to `false`: absent means the delivery predates the
182
+ * field, not that nothing was collected.
183
+ */
184
+ feeCollected?: boolean;
185
+ /** The fee leg's tx hash; `null` unless the fee was collected on-chain. */
186
+ feeTxHash?: string | null;
187
+ resourceUrl: string | null;
188
+ failureReason: string | null;
189
+ } | null;
190
+ occurredAt: string;
191
+ };
192
+ export type PeerPayPaymentEvent = PeerPayEventEnvelope<"payment.confirmed" | "link.paid", PeerPayPaymentEventData>;
193
+ export type PeerPayMandateEvent = PeerPayEventEnvelope<"mandate.active" | "mandate.charged" | "mandate.charge_failed" | "mandate.revoked" | "subscription.renewed" | "subscription.past_due", PeerPayMandateEventData>;
194
+ /**
195
+ * Agent-payment events are reserved on the server but have no emitter yet, so
196
+ * their payload is deliberately left open rather than invented here.
197
+ */
198
+ export type PeerPayAgentPaymentEvent = PeerPayEventEnvelope<"agent_payment.pending_approval" | "agent_payment.settled", Record<string, unknown>>;
199
+ /**
200
+ * An event type this SDK version does not know — a newer server talking to an
201
+ * older SDK. It is a *valid* event: `constructEvent` verifies and returns it
202
+ * like any other (see `PeerPayAnyEvent`), it never throws on the type.
203
+ */
204
+ export type PeerPayUnknownEvent = PeerPayEventEnvelope<string, Record<string, unknown>>;
205
+ /**
206
+ * Verified webhook delivery, discriminated on `type`:
207
+ *
208
+ * ```ts
209
+ * if (event.type === "payment.confirmed") {
210
+ * event.data.attempt.txHash; // typed, no cast
211
+ * }
212
+ * ```
213
+ *
214
+ * **Why this union has no `{ type: string & {} }` member.** TypeScript only
215
+ * narrows on a discriminant whose type is a literal in *every* constituent: add
216
+ * one member with a plain `string` type and `event.type === "payment.confirmed"`
217
+ * stops narrowing `data` for all the others too — the exact regression R1 sets
218
+ * out to fix. Forward compatibility therefore lives at runtime (an unknown type
219
+ * is verified and returned, never rejected) plus in `PeerPayAnyEvent` /
220
+ * `PeerPayUnknownEvent` for handlers that want to model the open world:
221
+ *
222
+ * ```ts
223
+ * const any: PeerPayAnyEvent = event; // widens, no cast needed
224
+ * if (!isKnownPeerPayEventType(any.type)) return new Response("ok"); // ack & ignore
225
+ * ```
226
+ */
227
+ export type PeerPayEvent = PeerPayPaymentEvent | PeerPayMandateEvent | PeerPayAgentPaymentEvent;
228
+ /**
229
+ * Open-world view of a delivery: every known event widens to it, and it is the
230
+ * honest type for an event whose `type` this SDK version does not know.
231
+ */
232
+ export type PeerPayAnyEvent = PeerPayEvent | PeerPayUnknownEvent;
233
+ /**
234
+ * Thrown for every rejection path: malformed/missing header, missing `t`/`v1`,
235
+ * timestamp outside the tolerance window, signature mismatch, non-JSON body.
236
+ * Messages never contain the secret or the expected signature.
237
+ */
238
+ export declare class PeerPaySignatureVerificationError extends Error {
239
+ constructor(message: string);
240
+ }
241
+ export type ConstructEventOptions = {
242
+ /** Replay window in seconds, applied in both directions. Default 300. */
243
+ toleranceSeconds?: number;
244
+ /** Injectable clock (epoch milliseconds); defaults to `Date.now()`. */
245
+ nowMs?: number;
246
+ };
247
+ /**
248
+ * Verifies a GenesisPay webhook delivery and returns the parsed event.
249
+ *
250
+ * Pass the **raw** request body exactly as received — never a re-serialized
251
+ * `JSON.parse` + `JSON.stringify` round trip, which changes the bytes and
252
+ * invalidates the signature. Parsing happens only after verification succeeds.
253
+ *
254
+ * An event type this SDK version does not know is **not** a failure: the
255
+ * delivery is verified and returned unchanged, so a server that adds a new
256
+ * event type can never turn a customer's webhook route into a 400. Only the
257
+ * signature and the envelope (`id`, `type`, `createdAt`, object `data`) can
258
+ * reject a delivery. Widen to `PeerPayAnyEvent` and use
259
+ * `isKnownPeerPayEventType()` if you want to handle that case explicitly.
260
+ *
261
+ * @throws {PeerPaySignatureVerificationError} on any verification failure.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * const event = await constructEvent(
266
+ * await request.text(),
267
+ * request.headers.get("peerpay-signature") ?? "",
268
+ * process.env.PEERPAY_WEBHOOK_SECRET!,
269
+ * );
270
+ * if (event.type === "payment.confirmed") {
271
+ * fulfil(event.data.link.clientReferenceId, event.data.attempt.txHash);
272
+ * }
273
+ * ```
274
+ */
275
+ export declare function constructEvent(rawBody: string | Uint8Array, signatureHeader: string, secret: string, opts?: ConstructEventOptions): Promise<PeerPayEvent>;
276
+ export {};
277
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,223 @@
1
+ // Webhook signature verification for GenesisPay deliveries.
2
+ //
3
+ // The server signs every delivery in `src/features/sellers/webhooks.ts`:
4
+ //
5
+ // PEERPAY-SIGNATURE: t=<unix-seconds>,v1=<hex>
6
+ // v1 = HMAC_SHA256(secret, `${t}.${rawBody}`)
7
+ //
8
+ // Deliberately implemented on WebCrypto (`globalThis.crypto.subtle`) rather
9
+ // than `node:crypto` so the SDK also runs on Edge runtimes, Cloudflare Workers
10
+ // and Bun. That is why `constructEvent` is async — a conscious deviation from
11
+ // Stripe's synchronous `constructEvent`.
12
+ /**
13
+ * Every event type this SDK version knows. Mirrors the server's
14
+ * `WebhookEventType` (`src/features/sellers/webhooks.ts`) — the drift alarm is
15
+ * `src/features/sellers/webhook-signature-contract.test.ts`, which fails when
16
+ * the server grows a type this list does not have.
17
+ *
18
+ * Exported as a runtime array (not only as a type) so a handler can ask
19
+ * `isKnownPeerPayEventType(event.type)` before it decides what to do.
20
+ */
21
+ export const PEERPAY_EVENT_TYPES = [
22
+ "payment.confirmed",
23
+ "link.paid",
24
+ "agent_payment.pending_approval",
25
+ "agent_payment.settled",
26
+ "mandate.active",
27
+ "mandate.charged",
28
+ "mandate.charge_failed",
29
+ "mandate.revoked",
30
+ "subscription.renewed",
31
+ "subscription.past_due",
32
+ ];
33
+ /** True when `type` is an event type this SDK version knows about. */
34
+ export function isKnownPeerPayEventType(type) {
35
+ return PEERPAY_EVENT_TYPES.includes(type);
36
+ }
37
+ /**
38
+ * Thrown for every rejection path: malformed/missing header, missing `t`/`v1`,
39
+ * timestamp outside the tolerance window, signature mismatch, non-JSON body.
40
+ * Messages never contain the secret or the expected signature.
41
+ */
42
+ export class PeerPaySignatureVerificationError extends Error {
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "PeerPaySignatureVerificationError";
46
+ }
47
+ }
48
+ const DEFAULT_TOLERANCE_SECONDS = 300;
49
+ const SIGNATURE_HEADER_NAME = "PEERPAY-SIGNATURE";
50
+ const textEncoder = new TextEncoder();
51
+ const textDecoder = new TextDecoder("utf-8", { fatal: false });
52
+ /**
53
+ * Parses `t=…,v1=…` tolerantly: any order, surrounding whitespace, and
54
+ * repeated `v1=` values (secret rotation — one match is enough).
55
+ */
56
+ function parseSignatureHeader(header) {
57
+ let timestampRaw;
58
+ const signatures = [];
59
+ for (const rawPart of header.split(",")) {
60
+ const part = rawPart.trim();
61
+ if (part.length === 0)
62
+ continue;
63
+ const separator = part.indexOf("=");
64
+ if (separator <= 0) {
65
+ throw new PeerPaySignatureVerificationError(`Malformed ${SIGNATURE_HEADER_NAME} header: expected comma-separated key=value pairs.`);
66
+ }
67
+ const key = part.slice(0, separator).trim();
68
+ const value = part.slice(separator + 1).trim();
69
+ if (key === "t") {
70
+ // A second `t=` would make the signed payload ambiguous.
71
+ if (timestampRaw !== undefined) {
72
+ throw new PeerPaySignatureVerificationError(`Malformed ${SIGNATURE_HEADER_NAME} header: duplicate "t" value.`);
73
+ }
74
+ timestampRaw = value;
75
+ }
76
+ else if (key === "v1") {
77
+ if (value.length > 0)
78
+ signatures.push(value);
79
+ }
80
+ // Unknown keys (future scheme versions) are ignored on purpose.
81
+ }
82
+ if (timestampRaw === undefined || timestampRaw.length === 0) {
83
+ throw new PeerPaySignatureVerificationError(`Missing "t" in ${SIGNATURE_HEADER_NAME} header.`);
84
+ }
85
+ if (!/^\d+$/.test(timestampRaw)) {
86
+ throw new PeerPaySignatureVerificationError(`Invalid "t" in ${SIGNATURE_HEADER_NAME} header: expected unix seconds.`);
87
+ }
88
+ const timestampSeconds = Number(timestampRaw);
89
+ if (!Number.isSafeInteger(timestampSeconds)) {
90
+ throw new PeerPaySignatureVerificationError(`Invalid "t" in ${SIGNATURE_HEADER_NAME} header: expected unix seconds.`);
91
+ }
92
+ if (signatures.length === 0) {
93
+ throw new PeerPaySignatureVerificationError(`Missing "v1" in ${SIGNATURE_HEADER_NAME} header.`);
94
+ }
95
+ return { timestampSeconds, signatures };
96
+ }
97
+ function getSubtleCrypto() {
98
+ const subtle = globalThis.crypto?.subtle;
99
+ if (!subtle) {
100
+ throw new PeerPaySignatureVerificationError("WebCrypto (globalThis.crypto.subtle) is unavailable in this runtime; webhook verification requires it.");
101
+ }
102
+ return subtle;
103
+ }
104
+ async function computeExpectedSignature(secret, signedPayload) {
105
+ const subtle = getSubtleCrypto();
106
+ const key = await subtle.importKey("raw", textEncoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
107
+ const signature = await subtle.sign("HMAC", key, textEncoder.encode(signedPayload));
108
+ return toHex(new Uint8Array(signature));
109
+ }
110
+ function toHex(bytes) {
111
+ let hex = "";
112
+ for (const byte of bytes) {
113
+ hex += byte.toString(16).padStart(2, "0");
114
+ }
115
+ return hex;
116
+ }
117
+ /**
118
+ * Constant-time string comparison. Length is checked first (lengths are not
119
+ * secret), then every byte is folded into an XOR accumulator — no early return
120
+ * and no `===` on the hex strings, so timing does not leak the position of the
121
+ * first differing byte.
122
+ */
123
+ function timingSafeEqualStrings(a, b) {
124
+ if (a.length !== b.length)
125
+ return false;
126
+ let diff = 0;
127
+ for (let i = 0; i < a.length; i += 1) {
128
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
129
+ }
130
+ return diff === 0;
131
+ }
132
+ function decodeRawBody(rawBody) {
133
+ if (typeof rawBody === "string")
134
+ return rawBody;
135
+ return textDecoder.decode(rawBody);
136
+ }
137
+ /**
138
+ * Verifies a GenesisPay webhook delivery and returns the parsed event.
139
+ *
140
+ * Pass the **raw** request body exactly as received — never a re-serialized
141
+ * `JSON.parse` + `JSON.stringify` round trip, which changes the bytes and
142
+ * invalidates the signature. Parsing happens only after verification succeeds.
143
+ *
144
+ * An event type this SDK version does not know is **not** a failure: the
145
+ * delivery is verified and returned unchanged, so a server that adds a new
146
+ * event type can never turn a customer's webhook route into a 400. Only the
147
+ * signature and the envelope (`id`, `type`, `createdAt`, object `data`) can
148
+ * reject a delivery. Widen to `PeerPayAnyEvent` and use
149
+ * `isKnownPeerPayEventType()` if you want to handle that case explicitly.
150
+ *
151
+ * @throws {PeerPaySignatureVerificationError} on any verification failure.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const event = await constructEvent(
156
+ * await request.text(),
157
+ * request.headers.get("peerpay-signature") ?? "",
158
+ * process.env.PEERPAY_WEBHOOK_SECRET!,
159
+ * );
160
+ * if (event.type === "payment.confirmed") {
161
+ * fulfil(event.data.link.clientReferenceId, event.data.attempt.txHash);
162
+ * }
163
+ * ```
164
+ */
165
+ export async function constructEvent(rawBody, signatureHeader, secret, opts = {}) {
166
+ if (typeof signatureHeader !== "string" || signatureHeader.trim().length === 0) {
167
+ throw new PeerPaySignatureVerificationError(`Missing ${SIGNATURE_HEADER_NAME} header.`);
168
+ }
169
+ if (typeof secret !== "string" || secret.length === 0) {
170
+ throw new PeerPaySignatureVerificationError("Missing webhook signing secret.");
171
+ }
172
+ const toleranceSeconds = opts.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
173
+ if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) {
174
+ throw new PeerPaySignatureVerificationError("Invalid toleranceSeconds: expected a non-negative number.");
175
+ }
176
+ const { timestampSeconds, signatures } = parseSignatureHeader(signatureHeader);
177
+ const nowMs = opts.nowMs ?? Date.now();
178
+ const nowSeconds = Math.floor(nowMs / 1_000);
179
+ const skewSeconds = Math.abs(nowSeconds - timestampSeconds);
180
+ if (skewSeconds > toleranceSeconds) {
181
+ // Rejects future timestamps too — a clock-skewed or replayed delivery.
182
+ throw new PeerPaySignatureVerificationError(`Webhook timestamp is outside the tolerance window of ${toleranceSeconds}s (off by ${skewSeconds}s).`);
183
+ }
184
+ const body = decodeRawBody(rawBody);
185
+ const expected = await computeExpectedSignature(secret, `${timestampSeconds}.${body}`);
186
+ let matched = false;
187
+ for (const candidate of signatures) {
188
+ // No early break: every candidate is compared so the work does not depend
189
+ // on which one matches.
190
+ matched = timingSafeEqualStrings(expected, candidate.toLowerCase()) || matched;
191
+ }
192
+ if (!matched) {
193
+ throw new PeerPaySignatureVerificationError("Webhook signature mismatch: the payload does not match the signing secret.");
194
+ }
195
+ let parsed;
196
+ try {
197
+ parsed = JSON.parse(body);
198
+ }
199
+ catch {
200
+ throw new PeerPaySignatureVerificationError("Webhook body is not valid JSON.");
201
+ }
202
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
203
+ throw new PeerPaySignatureVerificationError("Webhook body is not a JSON object.");
204
+ }
205
+ // The envelope is asserted rather than cast. `id` in particular is the
206
+ // documented idempotency key — it is stable across delivery retries, so an
207
+ // integrator deduping on it would silently process a payment twice if it
208
+ // arrived as undefined. A signed body that does not carry the envelope means
209
+ // the sender is not the GenesisPay we know, so failing here is correct.
210
+ const envelope = parsed;
211
+ for (const field of ["id", "type", "createdAt"]) {
212
+ if (typeof envelope[field] !== "string" || envelope[field] === "") {
213
+ throw new PeerPaySignatureVerificationError(`Webhook body is missing a string "${field}" field.`);
214
+ }
215
+ }
216
+ if (typeof envelope.data !== "object" ||
217
+ envelope.data === null ||
218
+ Array.isArray(envelope.data)) {
219
+ throw new PeerPaySignatureVerificationError('Webhook body is missing an object "data" field.');
220
+ }
221
+ return parsed;
222
+ }
223
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@genesis-tech/genesispay-seller",
3
+ "version": "0.8.0",
4
+ "description": "Framework-agnostic x402 payment gate for sellers, powered by GenesisPay.",
5
+ "license": "MIT",
6
+ "author": "GenesisTech",
7
+ "homepage": "https://github.com/GenesisTechAT/genesispay-js/tree/main/packages/seller-sdk#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/GenesisTechAT/genesispay-js.git",
11
+ "directory": "packages/seller-sdk"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/GenesisTechAT/genesispay-js/issues"
15
+ },
16
+ "keywords": [
17
+ "x402",
18
+ "http-402",
19
+ "payments",
20
+ "usdc",
21
+ "stablecoin",
22
+ "base",
23
+ "paywall",
24
+ "api-monetization",
25
+ "payment-gate"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "node": ">=20.9.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.js"
39
+ }
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "!dist/**/*.test.*",
44
+ "README.md",
45
+ "CHANGELOG.md"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsc -b",
49
+ "typecheck": "tsc --noEmit"
50
+ },
51
+ "dependencies": {
52
+ "@genesis-tech/genesispay-protocol": "^0.1.0",
53
+ "viem": "^2.48.11"
54
+ },
55
+ "devDependencies": {
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }