@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.
- package/CHANGELOG.md +330 -0
- package/LICENSE +21 -0
- package/README.md +429 -0
- package/dist/client.d.ts +275 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +541 -0
- package/dist/client.js.map +1 -0
- package/dist/customers.d.ts +41 -0
- package/dist/customers.d.ts.map +1 -0
- package/dist/customers.js +76 -0
- package/dist/customers.js.map +1 -0
- package/dist/errors.d.ts +63 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +162 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/invoices.d.ts +80 -0
- package/dist/invoices.d.ts.map +1 -0
- package/dist/invoices.js +133 -0
- package/dist/invoices.js.map +1 -0
- package/dist/mandate-gate.d.ts +49 -0
- package/dist/mandate-gate.d.ts.map +1 -0
- package/dist/mandate-gate.js +109 -0
- package/dist/mandate-gate.js.map +1 -0
- package/dist/mandates.d.ts +172 -0
- package/dist/mandates.d.ts.map +1 -0
- package/dist/mandates.js +213 -0
- package/dist/mandates.js.map +1 -0
- package/dist/networks.d.ts +10 -0
- package/dist/networks.d.ts.map +1 -0
- package/dist/networks.js +22 -0
- package/dist/networks.js.map +1 -0
- package/dist/payment-gate.d.ts +67 -0
- package/dist/payment-gate.d.ts.map +1 -0
- package/dist/payment-gate.js +106 -0
- package/dist/payment-gate.js.map +1 -0
- package/dist/peerpay-settlement.d.ts +27 -0
- package/dist/peerpay-settlement.d.ts.map +1 -0
- package/dist/peerpay-settlement.js +100 -0
- package/dist/peerpay-settlement.js.map +1 -0
- package/dist/plans.d.ts +68 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +127 -0
- package/dist/plans.js.map +1 -0
- package/dist/resource.d.ts +47 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +71 -0
- package/dist/resource.js.map +1 -0
- package/dist/usdc-amount.d.ts +7 -0
- package/dist/usdc-amount.d.ts.map +1 -0
- package/dist/usdc-amount.js +21 -0
- package/dist/usdc-amount.js.map +1 -0
- package/dist/webhooks.d.ts +277 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +223 -0
- package/dist/webhooks.js.map +1 -0
- 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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"}
|
package/dist/webhooks.js
ADDED
|
@@ -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":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,iDAAiD;AACjD,gDAAgD;AAChD,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,yCAAyC;AAEzC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,mBAAmB;IACnB,WAAW;IACX,gCAAgC;IAChC,uBAAuB;IACvB,gBAAgB;IAChB,iBAAiB;IACjB,uBAAuB;IACvB,iBAAiB;IACjB,sBAAsB;IACtB,uBAAuB;CACf,CAAC;AAKX,sEAAsE;AACtE,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAQ,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAyPD;;;;GAIG;AACH,MAAM,OAAO,iCAAkC,SAAQ,KAAK;IAC1D,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mCAAmC,CAAC;IAClD,CAAC;CACF;AASD,MAAM,yBAAyB,GAAG,GAAG,CAAC;AACtC,MAAM,qBAAqB,GAAG,mBAAmB,CAAC;AAElD,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAO/D;;;GAGG;AACH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,IAAI,YAAgC,CAAC;IACrC,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEhC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,iCAAiC,CACzC,aAAa,qBAAqB,oDAAoD,CACvF,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE/C,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YAChB,yDAAyD;YACzD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,MAAM,IAAI,iCAAiC,CACzC,aAAa,qBAAqB,+BAA+B,CAClE,CAAC;YACJ,CAAC;YACD,YAAY,GAAG,KAAK,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC;QACD,gEAAgE;IAClE,CAAC;IAED,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,iCAAiC,CACzC,kBAAkB,qBAAqB,UAAU,CAClD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,iCAAiC,CACzC,kBAAkB,qBAAqB,iCAAiC,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,iCAAiC,CACzC,kBAAkB,qBAAqB,iCAAiC,CACzE,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,iCAAiC,CACzC,mBAAmB,qBAAqB,UAAU,CACnD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,iCAAiC,CACzC,wGAAwG,CACzG,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,MAAc,EACd,aAAqB;IAErB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAChC,KAAK,EACL,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAC1B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,MAAM,CAAC,CACT,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,IAAI,CACjC,MAAM,EACN,GAAG,EACH,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAClC,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,KAAK,CAAC,KAAiB;IAC9B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,SAAS,sBAAsB,CAAC,CAAS,EAAE,CAAS;IAClD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,aAAa,CAAC,OAA4B;IACjD,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA4B,EAC5B,eAAuB,EACvB,MAAc,EACd,OAA8B,EAAE;IAEhC,IAAI,OAAO,eAAe,KAAK,QAAQ,IAAI,eAAe,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,iCAAiC,CACzC,WAAW,qBAAqB,UAAU,CAC3C,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,iCAAiC,CACzC,iCAAiC,CAClC,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,yBAAyB,CAAC;IAC5E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,gBAAgB,GAAG,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,iCAAiC,CACzC,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,oBAAoB,CAAC,eAAe,CAAC,CAAC;IAE/E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;IAC5D,IAAI,WAAW,GAAG,gBAAgB,EAAE,CAAC;QACnC,uEAAuE;QACvE,MAAM,IAAI,iCAAiC,CACzC,wDAAwD,gBAAgB,aAAa,WAAW,KAAK,CACtG,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,MAAM,EACN,GAAG,gBAAgB,IAAI,IAAI,EAAE,CAC9B,CAAC;IAEF,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,0EAA0E;QAC1E,wBAAwB;QACxB,OAAO,GAAG,sBAAsB,CAAC,QAAQ,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,CAAC;IACjF,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,iCAAiC,CACzC,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,iCAAiC,CACzC,iCAAiC,CAClC,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,iCAAiC,CACzC,oCAAoC,CACrC,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,wEAAwE;IACxE,MAAM,QAAQ,GAAG,MAAsC,CAAC;IACxD,KAAK,MAAM,KAAK,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAU,EAAE,CAAC;QACzD,IAAI,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAClE,MAAM,IAAI,iCAAiC,CACzC,qCAAqC,KAAK,UAAU,CACrD,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IACE,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,QAAQ,CAAC,IAAI,KAAK,IAAI;QACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC5B,CAAC;QACD,MAAM,IAAI,iCAAiC,CACzC,iDAAiD,CAClD,CAAC;IACJ,CAAC;IAED,OAAO,MAAsB,CAAC;AAChC,CAAC"}
|
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
|
+
}
|