@amirabaris/webhook-kit 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +676 -2
- package/bin/webhook-kit.mjs +138 -0
- package/dist/index.cjs +1867 -0
- package/dist/index.d.cts +1091 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +1091 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +1091 -0
- package/dist/index.js +1867 -0
- package/dist/index.mjs +1808 -0
- package/dist/index.mjs.map +1 -0
- package/docs/agent-rules.md +159 -0
- package/package.json +87 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1091 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all webhook-kit errors.
|
|
3
|
+
*/
|
|
4
|
+
export declare class WebhookKitError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
constructor(message: string, code?: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Thrown or returned when signature verification fails (e.g. invalid HMAC or mismatched hash).
|
|
10
|
+
*/
|
|
11
|
+
export declare class SignatureVerificationError extends WebhookKitError {
|
|
12
|
+
constructor(message?: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Thrown when the signature header is missing or malformed.
|
|
16
|
+
*/
|
|
17
|
+
export declare class InvalidSignatureHeaderError extends WebhookKitError {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when the timestamp outside the allowed tolerance window (replay attack protection).
|
|
22
|
+
*/
|
|
23
|
+
export declare class TimestampToleranceError extends WebhookKitError {
|
|
24
|
+
readonly timestamp: number;
|
|
25
|
+
readonly toleranceSeconds: number;
|
|
26
|
+
constructor(timestamp: number, toleranceSeconds: number, message?: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Thrown when extracting raw payload from request or stream fails.
|
|
30
|
+
*/
|
|
31
|
+
export declare class PayloadExtractionError extends WebhookKitError {
|
|
32
|
+
constructor(message?: string);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Thrown or returned when a webhook event ID has already been processed in the replay store.
|
|
36
|
+
*/
|
|
37
|
+
export declare class ReplayAttackError extends WebhookKitError {
|
|
38
|
+
readonly eventId: string;
|
|
39
|
+
constructor(eventId: string, message?: string);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Supported raw body representations across runtimes (Node, Edge, Browser, Bun, Deno).
|
|
43
|
+
*/
|
|
44
|
+
export type RawBody = string | Uint8Array | ArrayBuffer | ArrayBufferView | ReadableStream<Uint8Array> | Request;
|
|
45
|
+
/**
|
|
46
|
+
* Standard or framework headers representation.
|
|
47
|
+
*/
|
|
48
|
+
export type HeaderRecord = Record<string, string | string[] | undefined> | Headers;
|
|
49
|
+
/**
|
|
50
|
+
* Supported HMAC cryptographic algorithms in Web Cryptography API.
|
|
51
|
+
*/
|
|
52
|
+
export type SupportedAlgorithm = "SHA-256" | "SHA-384" | "SHA-512" | "SHA-1";
|
|
53
|
+
/**
|
|
54
|
+
* Built-in webhook provider names supported by the unified verification API.
|
|
55
|
+
*/
|
|
56
|
+
export type BuiltinProviderName = "stripe" | "github" | "shopify";
|
|
57
|
+
/**
|
|
58
|
+
* Lightweight idempotency / replay store interface (`has(eventId)` / `set(eventId, ttl)`).
|
|
59
|
+
* Supports both synchronous (in-memory) and asynchronous (Redis, Upstash, Cloudflare KV) implementations.
|
|
60
|
+
*/
|
|
61
|
+
export interface WebhookReplayStore {
|
|
62
|
+
/**
|
|
63
|
+
* Returns `true` if `eventId` is already present and unexpired in the store.
|
|
64
|
+
*
|
|
65
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
66
|
+
*/
|
|
67
|
+
has(eventId: string): boolean | Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Records `eventId` in the store with the given time-to-live in seconds.
|
|
70
|
+
*
|
|
71
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
72
|
+
* @param ttlSeconds - Time-to-live in seconds before the entry expires.
|
|
73
|
+
*/
|
|
74
|
+
set(eventId: string, ttlSeconds: number): unknown | Promise<unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* Atomically records `eventId` with TTL if it does not already exist in the store (set-if-not-exists).
|
|
77
|
+
*
|
|
78
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
79
|
+
* @param ttlSeconds - Time-to-live in seconds before expiration.
|
|
80
|
+
* @returns `true` if newly recorded, `false` if already present in the store.
|
|
81
|
+
*/
|
|
82
|
+
setNx?(eventId: string, ttlSeconds: number): boolean | Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Optional method to remove a specific event ID from the store.
|
|
85
|
+
*
|
|
86
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
87
|
+
* @returns `true` if the entry existed and was removed, `false` otherwise.
|
|
88
|
+
*/
|
|
89
|
+
delete?(eventId: string): boolean | Promise<boolean>;
|
|
90
|
+
/**
|
|
91
|
+
* Optional method to clear all tracked event IDs from the store.
|
|
92
|
+
*/
|
|
93
|
+
clear?(): void | Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Options for generic or provider-specific webhook signature verification.
|
|
97
|
+
*/
|
|
98
|
+
export interface WebhookVerifyOptions {
|
|
99
|
+
/**
|
|
100
|
+
* The raw incoming body (Request, string, buffer, or stream).
|
|
101
|
+
* MUST NOT be pre-parsed JSON.
|
|
102
|
+
*/
|
|
103
|
+
body: RawBody;
|
|
104
|
+
/**
|
|
105
|
+
* Signature string provided in the webhook header.
|
|
106
|
+
* Optional when `headers` or a `Request` `body` containing the signature header is passed.
|
|
107
|
+
*/
|
|
108
|
+
signature?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Shared secret key or signing secret.
|
|
111
|
+
*/
|
|
112
|
+
secret: string | Uint8Array;
|
|
113
|
+
/**
|
|
114
|
+
* Optional built-in provider name ('stripe', 'github', 'shopify') or custom provider plugin.
|
|
115
|
+
* When omitted, generic HMAC verification is performed.
|
|
116
|
+
*/
|
|
117
|
+
provider?: BuiltinProviderName | WebhookProviderPlugin<unknown, never>;
|
|
118
|
+
/**
|
|
119
|
+
* Cryptographic hash algorithm for generic HMAC verification. Defaults to 'SHA-256'.
|
|
120
|
+
*/
|
|
121
|
+
algorithm?: SupportedAlgorithm;
|
|
122
|
+
/**
|
|
123
|
+
* Signature digest encoding for generic HMAC verification. Defaults to 'hex'.
|
|
124
|
+
*/
|
|
125
|
+
encoding?: "hex" | "base64";
|
|
126
|
+
/**
|
|
127
|
+
* Optional incoming HTTP headers if provider or generic verifier requires extracting metadata.
|
|
128
|
+
*/
|
|
129
|
+
headers?: HeaderRecord;
|
|
130
|
+
/**
|
|
131
|
+
* Maximum allowed age of the webhook in seconds to mitigate replay attacks.
|
|
132
|
+
*/
|
|
133
|
+
toleranceSeconds?: number;
|
|
134
|
+
/**
|
|
135
|
+
* Timestamp extracted from header or options (Unix seconds).
|
|
136
|
+
*/
|
|
137
|
+
timestamp?: number | string;
|
|
138
|
+
/**
|
|
139
|
+
* Current Unix timestamp in seconds (defaults to Math.floor(Date.now() / 1000)).
|
|
140
|
+
* Useful for deterministic testing.
|
|
141
|
+
*/
|
|
142
|
+
currentTimestamp?: number;
|
|
143
|
+
/**
|
|
144
|
+
* Optional idempotency / replay store (`has(eventId)` / `set(eventId, ttl)`) to reject duplicate webhooks.
|
|
145
|
+
*/
|
|
146
|
+
store?: WebhookReplayStore;
|
|
147
|
+
/**
|
|
148
|
+
* Optional explicit webhook event ID for idempotency / replay store tracking.
|
|
149
|
+
* When omitted, `webhook-kit` automatically extracts the delivery ID from headers or payload.
|
|
150
|
+
*/
|
|
151
|
+
eventId?: string;
|
|
152
|
+
/**
|
|
153
|
+
* Optional TTL in seconds for entries recorded in `store` (defaults to `toleranceSeconds` or `300`).
|
|
154
|
+
*/
|
|
155
|
+
storeTtlSeconds?: number;
|
|
156
|
+
/**
|
|
157
|
+
* Whether to automatically parse the verified body as JSON. Defaults to true.
|
|
158
|
+
*/
|
|
159
|
+
parseJson?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* If true, throws a WebhookKitError on failure instead of returning `{ valid: false, error }`.
|
|
162
|
+
*/
|
|
163
|
+
throwOnError?: boolean;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Successful outcome returned by verification operations.
|
|
167
|
+
*/
|
|
168
|
+
export interface WebhookVerificationSuccess<T = unknown> {
|
|
169
|
+
/**
|
|
170
|
+
* True when signature matches and all validations (e.g. timestamp) passed.
|
|
171
|
+
*/
|
|
172
|
+
valid: true;
|
|
173
|
+
/**
|
|
174
|
+
* Exact raw body string used in the HMAC calculation.
|
|
175
|
+
*/
|
|
176
|
+
rawBody: string;
|
|
177
|
+
/**
|
|
178
|
+
* Typed parsed JSON payload (or undefined if parseJson is false or body is non-JSON).
|
|
179
|
+
*/
|
|
180
|
+
payload: T;
|
|
181
|
+
/**
|
|
182
|
+
* Verified timestamp if present in the signature header or options.
|
|
183
|
+
*/
|
|
184
|
+
timestamp?: number;
|
|
185
|
+
/**
|
|
186
|
+
* Extracted or supplied webhook event ID if resolved.
|
|
187
|
+
*/
|
|
188
|
+
eventId?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Undefined on successful verification.
|
|
191
|
+
*/
|
|
192
|
+
error?: undefined;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Failed outcome returned by verification operations.
|
|
196
|
+
*/
|
|
197
|
+
export interface WebhookVerificationFailure {
|
|
198
|
+
/**
|
|
199
|
+
* False when signature or timestamp validation failed.
|
|
200
|
+
*/
|
|
201
|
+
valid: false;
|
|
202
|
+
/**
|
|
203
|
+
* Exact raw body string used in the HMAC calculation.
|
|
204
|
+
*/
|
|
205
|
+
rawBody: string;
|
|
206
|
+
/**
|
|
207
|
+
* Undefined on failed verification.
|
|
208
|
+
*/
|
|
209
|
+
payload?: undefined;
|
|
210
|
+
/**
|
|
211
|
+
* Extracted timestamp if parsed prior to failure.
|
|
212
|
+
*/
|
|
213
|
+
timestamp?: number;
|
|
214
|
+
/**
|
|
215
|
+
* Extracted or supplied webhook event ID if resolved prior to failure.
|
|
216
|
+
*/
|
|
217
|
+
eventId?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Verification error details explaining the failure.
|
|
220
|
+
*/
|
|
221
|
+
error: WebhookKitError;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Discriminated union outcome returned by verification operations.
|
|
225
|
+
* Narrowing via `if (result.valid)` narrows `result.payload` to `T`,
|
|
226
|
+
* while `if (!result.valid)` narrows `result.error` to `WebhookKitError`.
|
|
227
|
+
*/
|
|
228
|
+
export type WebhookVerificationResult<T = unknown> = WebhookVerificationSuccess<T> | WebhookVerificationFailure;
|
|
229
|
+
/**
|
|
230
|
+
* Interface for extensible provider plugins (Stripe, GitHub, Shopify, etc.).
|
|
231
|
+
*/
|
|
232
|
+
export interface WebhookProviderPlugin<TPayload = unknown, TOptions = unknown> {
|
|
233
|
+
/**
|
|
234
|
+
* Unique name of the provider plugin (e.g. 'stripe', 'github', 'shopify').
|
|
235
|
+
*/
|
|
236
|
+
readonly name: string;
|
|
237
|
+
/**
|
|
238
|
+
* Verify an incoming webhook for this specific provider format.
|
|
239
|
+
*/
|
|
240
|
+
verify(options: TOptions): Promise<WebhookVerificationResult<TPayload>>;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Configuration options for `InMemoryReplayStore` / `createInMemoryReplayStore`.
|
|
244
|
+
*/
|
|
245
|
+
export interface InMemoryReplayStoreOptions {
|
|
246
|
+
/**
|
|
247
|
+
* Maximum number of entries retained in memory before evicting expired or oldest entries.
|
|
248
|
+
* Defaults to `10_000`.
|
|
249
|
+
*/
|
|
250
|
+
maxSize?: number;
|
|
251
|
+
/**
|
|
252
|
+
* Default time-to-live in seconds when `ttlSeconds` is omitted or invalid.
|
|
253
|
+
* Defaults to `300` (5 minutes).
|
|
254
|
+
*/
|
|
255
|
+
defaultTtlSeconds?: number;
|
|
256
|
+
/**
|
|
257
|
+
* Optional clock function returning current time in milliseconds (defaults to `Date.now`).
|
|
258
|
+
* Useful for deterministic unit testing.
|
|
259
|
+
*/
|
|
260
|
+
now?: () => number;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Options for checking and recording an event ID in a `WebhookReplayStore`.
|
|
264
|
+
*/
|
|
265
|
+
export interface VerifyReplayStoreOptions {
|
|
266
|
+
/**
|
|
267
|
+
* Optional replay store instance.
|
|
268
|
+
*/
|
|
269
|
+
store?: WebhookReplayStore;
|
|
270
|
+
/**
|
|
271
|
+
* Resolved event ID to check and record.
|
|
272
|
+
*/
|
|
273
|
+
eventId?: string;
|
|
274
|
+
/**
|
|
275
|
+
* Explicit TTL in seconds for `store.set(eventId, ttl)`.
|
|
276
|
+
*/
|
|
277
|
+
storeTtlSeconds?: number;
|
|
278
|
+
/**
|
|
279
|
+
* Fallback tolerance window in seconds used when `storeTtlSeconds` is not provided.
|
|
280
|
+
*/
|
|
281
|
+
toleranceSeconds?: number;
|
|
282
|
+
}
|
|
283
|
+
export declare const DEFAULT_REPLAY_STORE_MAX_SIZE = 10000;
|
|
284
|
+
export declare const DEFAULT_REPLAY_STORE_TTL_SECONDS = 300;
|
|
285
|
+
export declare const GENERIC_EVENT_ID_HEADERS: readonly ["x-webhook-id", "webhook-id", "svix-id", "x-github-delivery", "x-shopify-webhook-id", "x-event-id", "x-idempotency-key"];
|
|
286
|
+
/**
|
|
287
|
+
* Default in-memory TTL replay store backed by a JavaScript `Map`.
|
|
288
|
+
* Automatically evicts expired entries on lookup and enforces an upper capacity bound
|
|
289
|
+
* with LRU (Least Recently Used) eviction.
|
|
290
|
+
*/
|
|
291
|
+
export declare class InMemoryReplayStore implements WebhookReplayStore {
|
|
292
|
+
private readonly maxSize;
|
|
293
|
+
private readonly defaultTtlSeconds;
|
|
294
|
+
private readonly now;
|
|
295
|
+
private readonly entries;
|
|
296
|
+
private lastPruneMs;
|
|
297
|
+
constructor(options?: InMemoryReplayStoreOptions);
|
|
298
|
+
/**
|
|
299
|
+
* Checks whether `eventId` is currently tracked and unexpired in the store.
|
|
300
|
+
*
|
|
301
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
302
|
+
* @returns `true` if `eventId` is present and unexpired, `false` otherwise.
|
|
303
|
+
*/
|
|
304
|
+
has(eventId: string): boolean;
|
|
305
|
+
/**
|
|
306
|
+
* Records `eventId` in the store with the specified TTL in seconds.
|
|
307
|
+
*
|
|
308
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
309
|
+
* @param ttlSeconds - Time-to-live in seconds before expiration.
|
|
310
|
+
*/
|
|
311
|
+
set(eventId: string, ttlSeconds?: number): void;
|
|
312
|
+
/**
|
|
313
|
+
* Atomically records `eventId` with TTL if it does not already exist in the store (set-if-not-exists).
|
|
314
|
+
*
|
|
315
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
316
|
+
* @param ttlSeconds - Time-to-live in seconds before expiration.
|
|
317
|
+
* @returns `true` if newly recorded, `false` if already present in the store.
|
|
318
|
+
*/
|
|
319
|
+
setNx(eventId: string, ttlSeconds?: number): boolean;
|
|
320
|
+
/**
|
|
321
|
+
* Removes a specific `eventId` from the store.
|
|
322
|
+
*
|
|
323
|
+
* @param eventId - Unique webhook event or delivery identifier.
|
|
324
|
+
* @returns `true` if the entry existed and was removed.
|
|
325
|
+
*/
|
|
326
|
+
delete(eventId: string): boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Clears all tracked event IDs from the store.
|
|
329
|
+
*/
|
|
330
|
+
clear(): void;
|
|
331
|
+
/**
|
|
332
|
+
* Removes all expired entries from the store and returns the number of purged entries.
|
|
333
|
+
*
|
|
334
|
+
* @returns Count of expired entries removed.
|
|
335
|
+
*/
|
|
336
|
+
prune(): number;
|
|
337
|
+
/**
|
|
338
|
+
* Returns the current number of entries stored in the underlying map.
|
|
339
|
+
*/
|
|
340
|
+
get size(): number;
|
|
341
|
+
/**
|
|
342
|
+
* Returns the maximum capacity of the store.
|
|
343
|
+
*/
|
|
344
|
+
get capacity(): number;
|
|
345
|
+
/**
|
|
346
|
+
* Prepares a map slot for insertion by evicting an existing key or pruning capacity.
|
|
347
|
+
*
|
|
348
|
+
* @param eventId - Candidate event ID key.
|
|
349
|
+
*/
|
|
350
|
+
private prepareInsertSlot;
|
|
351
|
+
/**
|
|
352
|
+
* Fast-path check from the head of the insertion-ordered Map to purge expired entries.
|
|
353
|
+
*
|
|
354
|
+
* @param currentMs - Current time in milliseconds.
|
|
355
|
+
*/
|
|
356
|
+
private evictHeadExpired;
|
|
357
|
+
private evictExpiredOrOldest;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Creates a new `InMemoryReplayStore` instance with optional capacity and TTL settings.
|
|
361
|
+
*
|
|
362
|
+
* @param options - Optional capacity, default TTL, and clock configuration.
|
|
363
|
+
* @returns Configured `InMemoryReplayStore` instance.
|
|
364
|
+
*/
|
|
365
|
+
export declare function createInMemoryReplayStore(options?: InMemoryReplayStoreOptions): InMemoryReplayStore;
|
|
366
|
+
/**
|
|
367
|
+
* Resolves the unique webhook event ID from explicit options, delivery headers, or payload `id`.
|
|
368
|
+
*
|
|
369
|
+
* @param options - Source options containing explicit `eventId`, `headers`, `body`, `payload`, and `rawBody`.
|
|
370
|
+
* @param headerCandidates - Ordered delivery ID header names to inspect prior to payload fallback.
|
|
371
|
+
* @returns Resolved non-empty event ID string or `undefined`.
|
|
372
|
+
*/
|
|
373
|
+
export declare function resolveWebhookEventId(options: {
|
|
374
|
+
eventId?: string;
|
|
375
|
+
headers?: HeaderRecord;
|
|
376
|
+
body?: RawBody;
|
|
377
|
+
payload?: unknown;
|
|
378
|
+
rawBody?: string;
|
|
379
|
+
}, headerCandidates?: readonly string[]): string | undefined;
|
|
380
|
+
/**
|
|
381
|
+
* Verifies that `eventId` has not already been seen in `store`, and records it with a TTL if unseen.
|
|
382
|
+
* Automatically leverages atomic `setNx` when supported, or serializes in-flight checks to prevent
|
|
383
|
+
* TOCTOU race conditions under high concurrency.
|
|
384
|
+
*
|
|
385
|
+
* @param options - Store instance, resolved `eventId`, and TTL configuration.
|
|
386
|
+
* @returns `ReplayAttackError` if `eventId` is already present in `store`, or `null` if unseen / no store.
|
|
387
|
+
*/
|
|
388
|
+
export declare function checkAndRecordReplay(options: VerifyReplayStoreOptions): Promise<ReplayAttackError | null>;
|
|
389
|
+
export interface ProviderVerifyOptions {
|
|
390
|
+
/**
|
|
391
|
+
* Raw body input (Request, string, buffer). Must not be pre-parsed.
|
|
392
|
+
*/
|
|
393
|
+
body: RawBody;
|
|
394
|
+
/**
|
|
395
|
+
* Webhook signing secret provided by the platform dashboard.
|
|
396
|
+
*/
|
|
397
|
+
secret: string | Uint8Array;
|
|
398
|
+
/**
|
|
399
|
+
* Request headers or header value containing the signature.
|
|
400
|
+
*/
|
|
401
|
+
headers?: HeaderRecord;
|
|
402
|
+
/**
|
|
403
|
+
* Explicit signature header value if already extracted.
|
|
404
|
+
*/
|
|
405
|
+
signature?: string;
|
|
406
|
+
/**
|
|
407
|
+
* Tolerance in seconds for replay-attack prevention (where supported).
|
|
408
|
+
*/
|
|
409
|
+
toleranceSeconds?: number;
|
|
410
|
+
/**
|
|
411
|
+
* Optional idempotency / replay store (`has(eventId)` / `set(eventId, ttl)`) to reject duplicate webhooks.
|
|
412
|
+
*/
|
|
413
|
+
store?: WebhookReplayStore;
|
|
414
|
+
/**
|
|
415
|
+
* Optional explicit webhook event ID for idempotency / replay store tracking.
|
|
416
|
+
*/
|
|
417
|
+
eventId?: string;
|
|
418
|
+
/**
|
|
419
|
+
* Optional TTL in seconds for entries recorded in `store` (defaults to `toleranceSeconds` or `300`).
|
|
420
|
+
*/
|
|
421
|
+
storeTtlSeconds?: number;
|
|
422
|
+
/**
|
|
423
|
+
* Whether to automatically parse the verified body as JSON. Defaults to true.
|
|
424
|
+
*/
|
|
425
|
+
parseJson?: boolean;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Standard shape of a GitHub Webhook Event payload.
|
|
429
|
+
*/
|
|
430
|
+
export interface GithubWebhookEvent {
|
|
431
|
+
action?: string;
|
|
432
|
+
sender?: Record<string, unknown>;
|
|
433
|
+
repository?: Record<string, unknown>;
|
|
434
|
+
organization?: Record<string, unknown>;
|
|
435
|
+
installation?: Record<string, unknown>;
|
|
436
|
+
zen?: string;
|
|
437
|
+
hook_id?: number;
|
|
438
|
+
hook?: Record<string, unknown>;
|
|
439
|
+
[key: string]: unknown;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Options for GitHub webhook verification.
|
|
443
|
+
*/
|
|
444
|
+
export interface GithubVerifyOptions extends ProviderVerifyOptions {
|
|
445
|
+
/**
|
|
446
|
+
* X-Hub-Signature-256 header format: `sha256=d57c68d10b284e3d...`
|
|
447
|
+
*/
|
|
448
|
+
signature?: string;
|
|
449
|
+
/**
|
|
450
|
+
* If true, throws errors rather than returning `{ valid: false, error }`.
|
|
451
|
+
*/
|
|
452
|
+
throwOnError?: boolean;
|
|
453
|
+
/**
|
|
454
|
+
* Whether to automatically parse the verified body as JSON. Defaults to true.
|
|
455
|
+
*/
|
|
456
|
+
parseJson?: boolean;
|
|
457
|
+
}
|
|
458
|
+
export declare const GITHUB_SIGNATURE_PREFIX = "sha256=";
|
|
459
|
+
export declare const GITHUB_SIGNATURE_HEX_REGEX: RegExp;
|
|
460
|
+
export declare const GITHUB_EVENT_ID_HEADERS: readonly ["x-github-delivery", "x-webhook-id", "webhook-id"];
|
|
461
|
+
/**
|
|
462
|
+
* Parses an `X-Hub-Signature-256` header, validating and extracting the hex signature.
|
|
463
|
+
*
|
|
464
|
+
* @param header - Raw `X-Hub-Signature-256` header string (e.g. `sha256=d57c68d1...`).
|
|
465
|
+
* @returns Hexadecimal signature string after the `sha256=` prefix.
|
|
466
|
+
* @throws {InvalidSignatureHeaderError} If header is missing, empty, or lacks a valid sha256= prefix.
|
|
467
|
+
*/
|
|
468
|
+
export declare function parseGithubSignature(header: string): string;
|
|
469
|
+
/**
|
|
470
|
+
* Resolves the raw signature header string from options, headers record, or request.
|
|
471
|
+
*
|
|
472
|
+
* @param options - GitHub verification options.
|
|
473
|
+
* @returns GitHub signature header string or undefined if not found.
|
|
474
|
+
*/
|
|
475
|
+
export declare function resolveGithubSignatureHeader(options: GithubVerifyOptions): string | undefined;
|
|
476
|
+
/**
|
|
477
|
+
* Validates preconditions for GitHub webhook verification.
|
|
478
|
+
*
|
|
479
|
+
* @param options - GitHub verification options.
|
|
480
|
+
* @param rawHeader - Resolved header string.
|
|
481
|
+
* @returns Error if preconditions fail, null otherwise.
|
|
482
|
+
*/
|
|
483
|
+
export declare function validateGithubPreconditions(options: GithubVerifyOptions, rawHeader: string | undefined): WebhookKitError | null;
|
|
484
|
+
/**
|
|
485
|
+
* Safely parses the raw signature header without uncaught exceptions.
|
|
486
|
+
*
|
|
487
|
+
* @param rawHeader - Raw header string.
|
|
488
|
+
* @returns Extracted signature string or error object.
|
|
489
|
+
*/
|
|
490
|
+
export declare function safeParseGithubHeader(rawHeader: string): {
|
|
491
|
+
signature: string;
|
|
492
|
+
} | {
|
|
493
|
+
error: WebhookKitError;
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* Verifies a GitHub webhook payload signature against `X-Hub-Signature-256`.
|
|
497
|
+
*
|
|
498
|
+
* GitHub signs the raw request payload using HMAC-SHA256 with the webhook secret.
|
|
499
|
+
*
|
|
500
|
+
* @param options - GitHub verification options.
|
|
501
|
+
* @returns Verification result with typed payload.
|
|
502
|
+
*/
|
|
503
|
+
export declare function verifyGithubWebhook<T = GithubWebhookEvent>(options: GithubVerifyOptions): Promise<WebhookVerificationResult<T>>;
|
|
504
|
+
/**
|
|
505
|
+
* Asserts that a GitHub webhook payload signature is valid, throwing on verification failure.
|
|
506
|
+
*
|
|
507
|
+
* @param options - GitHub verification options.
|
|
508
|
+
* @returns Parsed and typed event payload.
|
|
509
|
+
* @throws {SignatureVerificationError} If signature verification fails.
|
|
510
|
+
* @throws {InvalidSignatureHeaderError} If header format is invalid or missing.
|
|
511
|
+
*/
|
|
512
|
+
export declare function assertGithubWebhook<T = GithubWebhookEvent>(options: GithubVerifyOptions): Promise<T>;
|
|
513
|
+
/**
|
|
514
|
+
* Webhook provider plugin for GitHub.
|
|
515
|
+
*/
|
|
516
|
+
export declare const githubPlugin: WebhookProviderPlugin<GithubWebhookEvent, GithubVerifyOptions>;
|
|
517
|
+
/**
|
|
518
|
+
* Standard shape of a Shopify Webhook Event payload.
|
|
519
|
+
*/
|
|
520
|
+
export interface ShopifyWebhookEvent {
|
|
521
|
+
id?: number | string;
|
|
522
|
+
admin_graphql_api_id?: string;
|
|
523
|
+
created_at?: string;
|
|
524
|
+
updated_at?: string;
|
|
525
|
+
[key: string]: unknown;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Options for Shopify webhook verification.
|
|
529
|
+
*/
|
|
530
|
+
export interface ShopifyVerifyOptions extends ProviderVerifyOptions {
|
|
531
|
+
/**
|
|
532
|
+
* X-Shopify-Hmac-Sha256 base64-encoded signature header.
|
|
533
|
+
*/
|
|
534
|
+
signature?: string;
|
|
535
|
+
/**
|
|
536
|
+
* If true, throws errors rather than returning `{ valid: false, error }`.
|
|
537
|
+
*/
|
|
538
|
+
throwOnError?: boolean;
|
|
539
|
+
/**
|
|
540
|
+
* Whether to automatically parse the verified body as JSON. Defaults to true.
|
|
541
|
+
*/
|
|
542
|
+
parseJson?: boolean;
|
|
543
|
+
}
|
|
544
|
+
export declare const BASE64_REGEX: RegExp;
|
|
545
|
+
export declare const SHOPIFY_EVENT_ID_HEADERS: readonly ["x-shopify-webhook-id", "x-webhook-id", "webhook-id"];
|
|
546
|
+
/**
|
|
547
|
+
* Parses an `X-Shopify-Hmac-Sha256` header, validating and normalizing the Base64 signature.
|
|
548
|
+
*
|
|
549
|
+
* @param header - Raw `X-Shopify-Hmac-Sha256` Base64 header string.
|
|
550
|
+
* @returns Normalized Base64-encoded HMAC-SHA256 signature string.
|
|
551
|
+
* @throws {InvalidSignatureHeaderError} If header is missing, empty, or not valid Base64.
|
|
552
|
+
*/
|
|
553
|
+
export declare function parseShopifySignature(header: string): string;
|
|
554
|
+
/**
|
|
555
|
+
* Resolves the raw signature header string from options, headers record, or request.
|
|
556
|
+
*
|
|
557
|
+
* @param options - Shopify verification options.
|
|
558
|
+
* @returns Shopify signature header string or undefined if not found.
|
|
559
|
+
*/
|
|
560
|
+
export declare function resolveShopifySignatureHeader(options: ShopifyVerifyOptions): string | undefined;
|
|
561
|
+
/**
|
|
562
|
+
* Validates preconditions for Shopify webhook verification.
|
|
563
|
+
*
|
|
564
|
+
* @param options - Shopify verification options.
|
|
565
|
+
* @param rawHeader - Resolved header string.
|
|
566
|
+
* @returns Error if preconditions fail, null otherwise.
|
|
567
|
+
*/
|
|
568
|
+
export declare function validateShopifyPreconditions(options: ShopifyVerifyOptions, rawHeader: string | undefined): WebhookKitError | null;
|
|
569
|
+
/**
|
|
570
|
+
* Safely parses the raw signature header without uncaught exceptions.
|
|
571
|
+
*
|
|
572
|
+
* @param rawHeader - Raw header string.
|
|
573
|
+
* @returns Extracted Base64 signature string or error object.
|
|
574
|
+
*/
|
|
575
|
+
export declare function safeParseShopifyHeader(rawHeader: string): {
|
|
576
|
+
signature: string;
|
|
577
|
+
} | {
|
|
578
|
+
error: WebhookKitError;
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Verifies a Shopify webhook payload signature against `X-Shopify-Hmac-Sha256`.
|
|
582
|
+
*
|
|
583
|
+
* Shopify computes HMAC-SHA256 of the raw body and encodes it as Base64.
|
|
584
|
+
*
|
|
585
|
+
* @param options - Shopify verification options.
|
|
586
|
+
* @returns Verification result with typed payload.
|
|
587
|
+
*/
|
|
588
|
+
export declare function verifyShopifyWebhook<T = ShopifyWebhookEvent>(options: ShopifyVerifyOptions): Promise<WebhookVerificationResult<T>>;
|
|
589
|
+
/**
|
|
590
|
+
* Asserts that a Shopify webhook payload signature is valid, throwing on verification failure.
|
|
591
|
+
*
|
|
592
|
+
* @param options - Shopify verification options.
|
|
593
|
+
* @returns Parsed and typed event payload.
|
|
594
|
+
* @throws {SignatureVerificationError} If signature verification fails.
|
|
595
|
+
* @throws {InvalidSignatureHeaderError} If header format is invalid or missing.
|
|
596
|
+
*/
|
|
597
|
+
export declare function assertShopifyWebhook<T = ShopifyWebhookEvent>(options: ShopifyVerifyOptions): Promise<T>;
|
|
598
|
+
/**
|
|
599
|
+
* Webhook provider plugin for Shopify.
|
|
600
|
+
*/
|
|
601
|
+
export declare const shopifyPlugin: WebhookProviderPlugin<ShopifyWebhookEvent, ShopifyVerifyOptions>;
|
|
602
|
+
/**
|
|
603
|
+
* Parsed components of a `Stripe-Signature` header.
|
|
604
|
+
*/
|
|
605
|
+
export interface StripeParsedSignatureHeader {
|
|
606
|
+
/**
|
|
607
|
+
* Extracted Unix timestamp in seconds.
|
|
608
|
+
*/
|
|
609
|
+
timestamp: number;
|
|
610
|
+
/**
|
|
611
|
+
* One or more valid v1 HMAC-SHA256 signatures.
|
|
612
|
+
*/
|
|
613
|
+
signatures: string[];
|
|
614
|
+
/**
|
|
615
|
+
* Optional v0 legacy signatures if present.
|
|
616
|
+
*/
|
|
617
|
+
v0Signatures?: string[];
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Standard shape of a Stripe Webhook Event payload.
|
|
621
|
+
*/
|
|
622
|
+
export interface StripeWebhookEvent {
|
|
623
|
+
id: string;
|
|
624
|
+
object: string;
|
|
625
|
+
type: string;
|
|
626
|
+
created: number;
|
|
627
|
+
data: {
|
|
628
|
+
object: Record<string, unknown>;
|
|
629
|
+
[key: string]: unknown;
|
|
630
|
+
};
|
|
631
|
+
livemode?: boolean;
|
|
632
|
+
pending_webhooks?: number;
|
|
633
|
+
request?: {
|
|
634
|
+
id: string | null;
|
|
635
|
+
idempotency_key: string | null;
|
|
636
|
+
};
|
|
637
|
+
[key: string]: unknown;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Options for Stripe webhook verification.
|
|
641
|
+
*/
|
|
642
|
+
export interface StripeVerifyOptions extends ProviderVerifyOptions {
|
|
643
|
+
/**
|
|
644
|
+
* Stripe-Signature header format: `t=1492774577,v1=5257a869e7ecebeda32affa62cd4923...`
|
|
645
|
+
*/
|
|
646
|
+
signature?: string;
|
|
647
|
+
/**
|
|
648
|
+
* Timestamp tolerance window in seconds (Stripe default is 300s).
|
|
649
|
+
* Pass 0 to disable replay protection check.
|
|
650
|
+
*/
|
|
651
|
+
toleranceSeconds?: number;
|
|
652
|
+
/**
|
|
653
|
+
* Current Unix timestamp in seconds (defaults to Math.floor(Date.now() / 1000)).
|
|
654
|
+
* Useful for deterministic testing.
|
|
655
|
+
*/
|
|
656
|
+
currentTimestamp?: number;
|
|
657
|
+
/**
|
|
658
|
+
* If true, throws errors rather than returning `{ valid: false, error }`.
|
|
659
|
+
*/
|
|
660
|
+
throwOnError?: boolean;
|
|
661
|
+
}
|
|
662
|
+
export declare const STRIPE_EVENT_ID_HEADERS: readonly ["x-stripe-webhook-id", "x-webhook-id", "webhook-id"];
|
|
663
|
+
/**
|
|
664
|
+
* Parses a Stripe signature header string (`t=...,v1=...,v0=...`).
|
|
665
|
+
*
|
|
666
|
+
* @param header - Raw `Stripe-Signature` header string.
|
|
667
|
+
* @returns Parsed header components including timestamp and signatures.
|
|
668
|
+
* @throws {InvalidSignatureHeaderError} If header format is invalid or missing required tags.
|
|
669
|
+
*/
|
|
670
|
+
export declare function parseStripeSignature(header: string): StripeParsedSignatureHeader;
|
|
671
|
+
/**
|
|
672
|
+
* Validates that a webhook timestamp falls within the allowed tolerance window.
|
|
673
|
+
*
|
|
674
|
+
* @param timestamp - Unix timestamp in seconds from the signature header.
|
|
675
|
+
* @param toleranceSeconds - Maximum allowed drift/age in seconds (default: 300s). Pass 0 to disable.
|
|
676
|
+
* @param currentTimestamp - Optional current Unix timestamp in seconds (defaults to now).
|
|
677
|
+
* @throws {TimestampToleranceError} If timestamp falls outside the tolerance window.
|
|
678
|
+
*/
|
|
679
|
+
export declare function validateTimestampTolerance(timestamp: number, toleranceSeconds?: number, currentTimestamp?: number): void;
|
|
680
|
+
/**
|
|
681
|
+
* Resolves the raw signature header string from options, headers record, or request.
|
|
682
|
+
*
|
|
683
|
+
* @param options - Stripe verification options.
|
|
684
|
+
* @returns Stripe signature header string or undefined if not found.
|
|
685
|
+
*/
|
|
686
|
+
export declare function resolveStripeSignatureHeader(options: StripeVerifyOptions): string | undefined;
|
|
687
|
+
/**
|
|
688
|
+
* Validates preconditions for Stripe webhook verification.
|
|
689
|
+
*
|
|
690
|
+
* @param options - Stripe verification options.
|
|
691
|
+
* @param rawHeader - Resolved header string.
|
|
692
|
+
* @returns Error if preconditions fail, null otherwise.
|
|
693
|
+
*/
|
|
694
|
+
export declare function validateStripePreconditions(options: StripeVerifyOptions, rawHeader: string | undefined): WebhookKitError | null;
|
|
695
|
+
/**
|
|
696
|
+
* Safely parses the raw signature header without uncaught exceptions.
|
|
697
|
+
*
|
|
698
|
+
* @param rawHeader - Raw header string.
|
|
699
|
+
* @returns Parsed header or error object.
|
|
700
|
+
*/
|
|
701
|
+
export declare function safeParseStripeHeader(rawHeader: string): StripeParsedSignatureHeader | {
|
|
702
|
+
error: WebhookKitError;
|
|
703
|
+
};
|
|
704
|
+
/**
|
|
705
|
+
* Checks timestamp tolerance, returning an error if tolerance window is exceeded.
|
|
706
|
+
*
|
|
707
|
+
* @param timestamp - Unix timestamp in seconds.
|
|
708
|
+
* @param options - Stripe verification options.
|
|
709
|
+
* @returns TimestampToleranceError if exceeded, null otherwise.
|
|
710
|
+
*/
|
|
711
|
+
export declare function checkStripeTolerance(timestamp: number, options: StripeVerifyOptions): TimestampToleranceError | null;
|
|
712
|
+
/**
|
|
713
|
+
* Compares an expected HMAC hex signature against candidate signatures in constant time.
|
|
714
|
+
*
|
|
715
|
+
* @param expectedSignature - Computed hex signature.
|
|
716
|
+
* @param candidates - List of candidate hex signatures from the header.
|
|
717
|
+
* @returns `true` if any candidate matches the expected signature.
|
|
718
|
+
*/
|
|
719
|
+
export declare function matchesAnyStripeSignature(expectedSignature: string, candidates: string[]): boolean;
|
|
720
|
+
/**
|
|
721
|
+
* Verifies a Stripe webhook event signature.
|
|
722
|
+
*
|
|
723
|
+
* Stripe computes HMAC-SHA256 over `${timestamp}.${rawPayload}` and compares
|
|
724
|
+
* against the `v1` signature tag in `Stripe-Signature`.
|
|
725
|
+
*
|
|
726
|
+
* @param options - Stripe verification options
|
|
727
|
+
* @returns Verification result with typed payload
|
|
728
|
+
*/
|
|
729
|
+
export declare function verifyStripeWebhook<T = StripeWebhookEvent>(options: StripeVerifyOptions): Promise<WebhookVerificationResult<T>>;
|
|
730
|
+
/**
|
|
731
|
+
* Asserts that a Stripe webhook event signature is valid, throwing on verification failure.
|
|
732
|
+
*
|
|
733
|
+
* @param options - Stripe verification options.
|
|
734
|
+
* @returns Parsed and typed event payload.
|
|
735
|
+
* @throws {SignatureVerificationError} If signature verification fails.
|
|
736
|
+
* @throws {TimestampToleranceError} If timestamp falls outside the tolerance window.
|
|
737
|
+
* @throws {InvalidSignatureHeaderError} If header format is invalid or missing.
|
|
738
|
+
*/
|
|
739
|
+
export declare function assertStripeWebhook<T = StripeWebhookEvent>(options: StripeVerifyOptions): Promise<T>;
|
|
740
|
+
/**
|
|
741
|
+
* Webhook provider plugin for Stripe.
|
|
742
|
+
*/
|
|
743
|
+
export declare const stripePlugin: WebhookProviderPlugin<StripeWebhookEvent, StripeVerifyOptions>;
|
|
744
|
+
/**
|
|
745
|
+
* Built-in provider plugin registry keyed by lowercase provider name.
|
|
746
|
+
*/
|
|
747
|
+
export declare const PROVIDER_REGISTRY: Record<BuiltinProviderName, WebhookProviderPlugin<unknown, never>>;
|
|
748
|
+
/**
|
|
749
|
+
* Verifies an incoming Stripe webhook signature via the unified verification API.
|
|
750
|
+
*/
|
|
751
|
+
export declare function verifyWebhookSignature<T = StripeWebhookEvent>(options: WebhookVerifyOptions & {
|
|
752
|
+
provider: "stripe";
|
|
753
|
+
}): Promise<WebhookVerificationResult<T>>;
|
|
754
|
+
/**
|
|
755
|
+
* Verifies an incoming GitHub webhook signature via the unified verification API.
|
|
756
|
+
*/
|
|
757
|
+
export declare function verifyWebhookSignature<T = GithubWebhookEvent>(options: WebhookVerifyOptions & {
|
|
758
|
+
provider: "github";
|
|
759
|
+
}): Promise<WebhookVerificationResult<T>>;
|
|
760
|
+
/**
|
|
761
|
+
* Verifies an incoming Shopify webhook signature via the unified verification API.
|
|
762
|
+
*/
|
|
763
|
+
export declare function verifyWebhookSignature<T = ShopifyWebhookEvent>(options: WebhookVerifyOptions & {
|
|
764
|
+
provider: "shopify";
|
|
765
|
+
}): Promise<WebhookVerificationResult<T>>;
|
|
766
|
+
/**
|
|
767
|
+
* Verifies an incoming webhook signature using a custom `WebhookProviderPlugin`.
|
|
768
|
+
*/
|
|
769
|
+
export declare function verifyWebhookSignature<T>(options: WebhookVerifyOptions & {
|
|
770
|
+
provider: WebhookProviderPlugin<T, never>;
|
|
771
|
+
}): Promise<WebhookVerificationResult<T>>;
|
|
772
|
+
/**
|
|
773
|
+
* Verifies an incoming webhook signature against the raw request body using constant-time HMAC check.
|
|
774
|
+
*
|
|
775
|
+
* @param options - Verification options including body, signature, secret, and optional provider or tolerance
|
|
776
|
+
* @returns Verification result object with validity, extracted raw body, and narrowed payload or error
|
|
777
|
+
*/
|
|
778
|
+
export declare function verifyWebhookSignature<T = unknown>(options: WebhookVerifyOptions): Promise<WebhookVerificationResult<T>>;
|
|
779
|
+
/**
|
|
780
|
+
* Asserts that an incoming Stripe webhook signature is valid, returning the typed payload or throwing.
|
|
781
|
+
*/
|
|
782
|
+
export declare function assertWebhookSignature<T = StripeWebhookEvent>(options: WebhookVerifyOptions & {
|
|
783
|
+
provider: "stripe";
|
|
784
|
+
}): Promise<T>;
|
|
785
|
+
/**
|
|
786
|
+
* Asserts that an incoming GitHub webhook signature is valid, returning the typed payload or throwing.
|
|
787
|
+
*/
|
|
788
|
+
export declare function assertWebhookSignature<T = GithubWebhookEvent>(options: WebhookVerifyOptions & {
|
|
789
|
+
provider: "github";
|
|
790
|
+
}): Promise<T>;
|
|
791
|
+
/**
|
|
792
|
+
* Asserts that an incoming Shopify webhook signature is valid, returning the typed payload or throwing.
|
|
793
|
+
*/
|
|
794
|
+
export declare function assertWebhookSignature<T = ShopifyWebhookEvent>(options: WebhookVerifyOptions & {
|
|
795
|
+
provider: "shopify";
|
|
796
|
+
}): Promise<T>;
|
|
797
|
+
/**
|
|
798
|
+
* Asserts that an incoming webhook signature is valid using a custom `WebhookProviderPlugin`.
|
|
799
|
+
*/
|
|
800
|
+
export declare function assertWebhookSignature<T>(options: WebhookVerifyOptions & {
|
|
801
|
+
provider: WebhookProviderPlugin<T, never>;
|
|
802
|
+
}): Promise<T>;
|
|
803
|
+
/**
|
|
804
|
+
* Asserts that an incoming webhook signature is valid, throwing a `WebhookKitError` if invalid.
|
|
805
|
+
* Returns the typed payload if valid and parsed.
|
|
806
|
+
*
|
|
807
|
+
* @throws {SignatureVerificationError} If signature verification fails
|
|
808
|
+
* @throws {TimestampToleranceError} If timestamp tolerance is exceeded
|
|
809
|
+
*/
|
|
810
|
+
export declare function assertWebhookSignature<T = unknown>(options: WebhookVerifyOptions): Promise<T>;
|
|
811
|
+
/**
|
|
812
|
+
* Structural duck-type for Hono's `Context` (and compatible edge routers that expose
|
|
813
|
+
* the underlying Web Standard `Request` at `req.raw`).
|
|
814
|
+
*/
|
|
815
|
+
export interface WebhookLikeContext {
|
|
816
|
+
readonly req: {
|
|
817
|
+
readonly raw: Request;
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Supported first-argument inputs to a universal webhook route handler:
|
|
822
|
+
* - Web Standard `Request` (Next.js App Router, Remix, SvelteKit, Astro, Cloudflare Workers, Bun, Deno)
|
|
823
|
+
* - Framework context object exposing `{ req: { raw: Request } }` (Hono)
|
|
824
|
+
*/
|
|
825
|
+
export type WebhookRequestInput = Request | WebhookLikeContext;
|
|
826
|
+
/**
|
|
827
|
+
* Static secret value or dynamic secret resolver function.
|
|
828
|
+
*/
|
|
829
|
+
export type SecretResolver<TContext = Request> = string | Uint8Array | ((context: TContext, request: Request) => string | Uint8Array | Promise<string | Uint8Array>);
|
|
830
|
+
/**
|
|
831
|
+
* Static replay store instance or dynamic store resolver function.
|
|
832
|
+
*/
|
|
833
|
+
export type ReplayStoreResolver<TContext = Request> = WebhookReplayStore | ((context: TContext, request: Request) => WebhookReplayStore | undefined | Promise<WebhookReplayStore | undefined>);
|
|
834
|
+
/**
|
|
835
|
+
* Metadata passed as the second argument to `onEvent` alongside the verified payload.
|
|
836
|
+
*/
|
|
837
|
+
export interface WebhookEventMeta<TContext = Request> {
|
|
838
|
+
readonly context: TContext;
|
|
839
|
+
readonly request: Request;
|
|
840
|
+
readonly rawBody: string;
|
|
841
|
+
readonly timestamp?: number;
|
|
842
|
+
readonly eventId?: string;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Metadata passed as the second argument to `onError` when verification fails.
|
|
846
|
+
*/
|
|
847
|
+
export interface WebhookErrorMeta<TContext = Request> {
|
|
848
|
+
readonly context: TContext;
|
|
849
|
+
readonly request: Request;
|
|
850
|
+
readonly rawBody?: string;
|
|
851
|
+
readonly timestamp?: number;
|
|
852
|
+
readonly eventId?: string;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Return value allowed from `onEvent`.
|
|
856
|
+
*/
|
|
857
|
+
export type WebhookHandlerReturn = Response | Record<string, unknown> | void | undefined;
|
|
858
|
+
/**
|
|
859
|
+
* Configuration options for `createWebhookHandler`.
|
|
860
|
+
*/
|
|
861
|
+
export interface WebhookHandlerOptions<TPayload = unknown, TContext extends WebhookRequestInput = Request> {
|
|
862
|
+
/**
|
|
863
|
+
* Optional built-in provider name (`'stripe'`, `'github'`, `'shopify'`) or custom provider plugin.
|
|
864
|
+
* When omitted, generic HMAC verification is performed.
|
|
865
|
+
*/
|
|
866
|
+
provider?: BuiltinProviderName | WebhookProviderPlugin<TPayload, never>;
|
|
867
|
+
/**
|
|
868
|
+
* Shared signing secret or dynamic resolver function receiving `(context, request)`.
|
|
869
|
+
*/
|
|
870
|
+
secret: SecretResolver<TContext>;
|
|
871
|
+
/**
|
|
872
|
+
* Optional idempotency / replay store (`has(eventId)` / `set(eventId, ttl)`) or dynamic resolver function.
|
|
873
|
+
*/
|
|
874
|
+
store?: ReplayStoreResolver<TContext>;
|
|
875
|
+
/**
|
|
876
|
+
* Optional explicit webhook event ID for idempotency / replay store tracking.
|
|
877
|
+
*/
|
|
878
|
+
eventId?: string;
|
|
879
|
+
/**
|
|
880
|
+
* Optional TTL in seconds for entries recorded in `store` (defaults to `toleranceSeconds` or `300`).
|
|
881
|
+
*/
|
|
882
|
+
storeTtlSeconds?: number;
|
|
883
|
+
/**
|
|
884
|
+
* Callback invoked after the webhook signature and timestamp have been verified.
|
|
885
|
+
*/
|
|
886
|
+
onEvent: (event: TPayload, meta: WebhookEventMeta<TContext>) => WebhookHandlerReturn | Promise<WebhookHandlerReturn>;
|
|
887
|
+
/**
|
|
888
|
+
* Optional custom error responder invoked when signature verification or body extraction fails.
|
|
889
|
+
*/
|
|
890
|
+
onError?: (error: WebhookKitError, meta: WebhookErrorMeta<TContext>) => Response | Promise<Response>;
|
|
891
|
+
/**
|
|
892
|
+
* Cryptographic hash algorithm for generic HMAC verification. Defaults to `'SHA-256'`.
|
|
893
|
+
*/
|
|
894
|
+
algorithm?: SupportedAlgorithm;
|
|
895
|
+
/**
|
|
896
|
+
* Signature digest encoding for generic HMAC verification. Defaults to `'hex'`.
|
|
897
|
+
*/
|
|
898
|
+
encoding?: "hex" | "base64";
|
|
899
|
+
/**
|
|
900
|
+
* Maximum allowed age of the webhook in seconds to mitigate replay attacks.
|
|
901
|
+
*/
|
|
902
|
+
toleranceSeconds?: number;
|
|
903
|
+
/**
|
|
904
|
+
* Current Unix timestamp in seconds (defaults to `Math.floor(Date.now() / 1000)`).
|
|
905
|
+
*/
|
|
906
|
+
currentTimestamp?: number;
|
|
907
|
+
/**
|
|
908
|
+
* Whether to automatically parse the verified body as JSON. Defaults to `true`.
|
|
909
|
+
*/
|
|
910
|
+
parseJson?: boolean;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Universal webhook route handler function produced by `createWebhookHandler`.
|
|
914
|
+
*/
|
|
915
|
+
export type UniversalWebhookHandler<TContext extends WebhookRequestInput = Request> = (input: TContext) => Promise<Response>;
|
|
916
|
+
/**
|
|
917
|
+
* Creates a universal Stripe webhook route handler for Next.js App Router, Hono, and WinterCG runtimes.
|
|
918
|
+
*/
|
|
919
|
+
export declare function createWebhookHandler<TPayload = StripeWebhookEvent, TContext extends WebhookRequestInput = Request>(options: WebhookHandlerOptions<TPayload, TContext> & {
|
|
920
|
+
provider: "stripe";
|
|
921
|
+
}): UniversalWebhookHandler<TContext>;
|
|
922
|
+
/**
|
|
923
|
+
* Creates a universal GitHub webhook route handler for Next.js App Router, Hono, and WinterCG runtimes.
|
|
924
|
+
*/
|
|
925
|
+
export declare function createWebhookHandler<TPayload = GithubWebhookEvent, TContext extends WebhookRequestInput = Request>(options: WebhookHandlerOptions<TPayload, TContext> & {
|
|
926
|
+
provider: "github";
|
|
927
|
+
}): UniversalWebhookHandler<TContext>;
|
|
928
|
+
/**
|
|
929
|
+
* Creates a universal Shopify webhook route handler for Next.js App Router, Hono, and WinterCG runtimes.
|
|
930
|
+
*/
|
|
931
|
+
export declare function createWebhookHandler<TPayload = ShopifyWebhookEvent, TContext extends WebhookRequestInput = Request>(options: WebhookHandlerOptions<TPayload, TContext> & {
|
|
932
|
+
provider: "shopify";
|
|
933
|
+
}): UniversalWebhookHandler<TContext>;
|
|
934
|
+
/**
|
|
935
|
+
* Creates a universal webhook route handler using a custom `WebhookProviderPlugin`.
|
|
936
|
+
*/
|
|
937
|
+
export declare function createWebhookHandler<TPayload, TContext extends WebhookRequestInput = Request>(options: WebhookHandlerOptions<TPayload, TContext> & {
|
|
938
|
+
provider: WebhookProviderPlugin<TPayload, never>;
|
|
939
|
+
}): UniversalWebhookHandler<TContext>;
|
|
940
|
+
/**
|
|
941
|
+
* Creates a universal webhook route handler that unwraps a Web Standard `Request` (Next.js App Router,
|
|
942
|
+
* Cloudflare Workers, Remix, Bun, Deno) or `{ req: { raw: Request } }` context (Hono), verifies the
|
|
943
|
+
* cryptographic signature, and dispatches the typed payload to `onEvent`.
|
|
944
|
+
*
|
|
945
|
+
* @param options - Provider, secret resolver, event handler, and optional verification settings.
|
|
946
|
+
* @returns Universal async route handler `(input: TContext) => Promise<Response>`.
|
|
947
|
+
*/
|
|
948
|
+
export declare function createWebhookHandler<TPayload = unknown, TContext extends WebhookRequestInput = Request>(options: WebhookHandlerOptions<TPayload, TContext>): UniversalWebhookHandler<TContext>;
|
|
949
|
+
/**
|
|
950
|
+
* Safely extracts the unmodified raw string body from various input representations:
|
|
951
|
+
* Web Standard `Request`, `ReadableStream`, `Uint8Array`, `ArrayBuffer`, `ArrayBufferView`, or primitive `string`.
|
|
952
|
+
*
|
|
953
|
+
* @param body The raw request or body object.
|
|
954
|
+
* @returns Unmodified string representation suitable for cryptographic HMAC verification.
|
|
955
|
+
* @throws {PayloadExtractionError} If body cannot be read or is invalid.
|
|
956
|
+
*/
|
|
957
|
+
export declare function extractRawBody(body: RawBody): Promise<string>;
|
|
958
|
+
/**
|
|
959
|
+
* Web Cryptography API helper utilities using globalThis.crypto.subtle.
|
|
960
|
+
* Provides zero-dependency, edge-compatible HMAC computation and constant-time verification.
|
|
961
|
+
*/
|
|
962
|
+
/**
|
|
963
|
+
* Output encodings supported by `computeSubtleHmac`.
|
|
964
|
+
*/
|
|
965
|
+
export type SubtleHmacEncoding = "hex" | "base64" | "uint8array" | "binary";
|
|
966
|
+
/**
|
|
967
|
+
* Options for configuring HMAC computation output.
|
|
968
|
+
*/
|
|
969
|
+
export interface SubtleHmacOptions {
|
|
970
|
+
/**
|
|
971
|
+
* Output encoding format. Defaults to `'uint8array'`.
|
|
972
|
+
*/
|
|
973
|
+
encoding?: SubtleHmacEncoding;
|
|
974
|
+
/**
|
|
975
|
+
* Whether to bypass the in-memory CryptoKey cache. Defaults to `false`.
|
|
976
|
+
*/
|
|
977
|
+
bypassCache?: boolean;
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Lightweight LRU (Least Recently Used) cache backed by a JavaScript `Map`.
|
|
981
|
+
* Reuses compiled WebCrypto keys across concurrent requests and evicts the
|
|
982
|
+
* oldest entries when capacity is reached.
|
|
983
|
+
*/
|
|
984
|
+
export declare class CryptoKeyLruCache {
|
|
985
|
+
private readonly maxSize;
|
|
986
|
+
private readonly map;
|
|
987
|
+
constructor(maxSize?: number);
|
|
988
|
+
get(key: string): Promise<CryptoKey> | undefined;
|
|
989
|
+
set(key: string, value: Promise<CryptoKey>): void;
|
|
990
|
+
has(key: string): boolean;
|
|
991
|
+
delete(key: string): boolean;
|
|
992
|
+
clear(): void;
|
|
993
|
+
get size(): number;
|
|
994
|
+
get capacity(): number;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Clears all compiled WebCrypto HMAC keys from the global key cache.
|
|
998
|
+
*/
|
|
999
|
+
export declare function clearCryptoKeyCache(): void;
|
|
1000
|
+
/**
|
|
1001
|
+
* Returns the current number of compiled WebCrypto HMAC keys stored in the global key cache.
|
|
1002
|
+
*/
|
|
1003
|
+
export declare function getCryptoKeyCacheSize(): number;
|
|
1004
|
+
/**
|
|
1005
|
+
* Retrieves a cached WebCrypto HMAC key or compiles and caches a new one.
|
|
1006
|
+
*
|
|
1007
|
+
* @param algorithm HMAC digest algorithm (e.g. `'SHA-256'`).
|
|
1008
|
+
* @param secret Raw secret string or byte array.
|
|
1009
|
+
* @param cache Optional custom `CryptoKeyLruCache` instance.
|
|
1010
|
+
* @returns Compiled `CryptoKey` instance.
|
|
1011
|
+
*/
|
|
1012
|
+
export declare function getCachedCryptoKey(algorithm: string, secret: string | Uint8Array, cache?: CryptoKeyLruCache): Promise<CryptoKey>;
|
|
1013
|
+
/**
|
|
1014
|
+
* Constant-time comparison between two buffers or strings to prevent timing side-channel attacks.
|
|
1015
|
+
*
|
|
1016
|
+
* @param a First byte array or string.
|
|
1017
|
+
* @param b Second byte array or string.
|
|
1018
|
+
* @returns `true` if byte sequences are identical, `false` otherwise.
|
|
1019
|
+
*/
|
|
1020
|
+
export declare function timingSafeEqual(a: Uint8Array | string, b: Uint8Array | string): boolean;
|
|
1021
|
+
/**
|
|
1022
|
+
* Computes an HMAC digest using `crypto.subtle` across modern JavaScript runtimes.
|
|
1023
|
+
*
|
|
1024
|
+
* @param algorithm HMAC digest algorithm (`'SHA-256'`, `'SHA-384'`, `'SHA-512'`, `'SHA-1'`).
|
|
1025
|
+
* @param secret Shared secret key as UTF-8 string or raw bytes.
|
|
1026
|
+
* @param data Raw payload string or bytes.
|
|
1027
|
+
* @param encodingOrOptions Output encoding (`'uint8array'`, `'hex'`, `'base64'`) or options object.
|
|
1028
|
+
* @returns Raw HMAC digest bytes (`Uint8Array`) or encoded digest string.
|
|
1029
|
+
*/
|
|
1030
|
+
export declare function computeSubtleHmac(algorithm: string, secret: string | Uint8Array, data: string | Uint8Array, encodingOrOptions?: "uint8array" | "binary" | {
|
|
1031
|
+
encoding?: "uint8array" | "binary";
|
|
1032
|
+
bypassCache?: boolean;
|
|
1033
|
+
}): Promise<Uint8Array>;
|
|
1034
|
+
export declare function computeSubtleHmac(algorithm: string, secret: string | Uint8Array, data: string | Uint8Array, encodingOrOptions: "hex" | "base64" | {
|
|
1035
|
+
encoding: "hex" | "base64";
|
|
1036
|
+
bypassCache?: boolean;
|
|
1037
|
+
}): Promise<string>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Converts a `Uint8Array` into a lowercase hexadecimal string.
|
|
1040
|
+
*
|
|
1041
|
+
* @param bytes Input byte array.
|
|
1042
|
+
* @returns Lowercase hexadecimal string.
|
|
1043
|
+
*/
|
|
1044
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
1045
|
+
/**
|
|
1046
|
+
* Converts a hexadecimal string into a `Uint8Array`.
|
|
1047
|
+
*
|
|
1048
|
+
* @param hex Hexadecimal string (with optional `0x` prefix).
|
|
1049
|
+
* @returns Decoded byte array.
|
|
1050
|
+
*/
|
|
1051
|
+
export declare function hexToBytes(hex: string): Uint8Array;
|
|
1052
|
+
/**
|
|
1053
|
+
* Converts a `Uint8Array` into a Base64-encoded string using standard Web APIs.
|
|
1054
|
+
*
|
|
1055
|
+
* @param bytes Input byte array.
|
|
1056
|
+
* @returns Base64-encoded string.
|
|
1057
|
+
*/
|
|
1058
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
1059
|
+
/**
|
|
1060
|
+
* Converts a Base64-encoded string into a `Uint8Array` using standard Web APIs.
|
|
1061
|
+
*
|
|
1062
|
+
* @param base64 Base64-encoded string.
|
|
1063
|
+
* @returns Decoded byte array.
|
|
1064
|
+
*/
|
|
1065
|
+
export declare function base64ToBytes(base64: string): Uint8Array;
|
|
1066
|
+
/**
|
|
1067
|
+
* Asserts that a header value is a non-empty string.
|
|
1068
|
+
*
|
|
1069
|
+
* @param header - Candidate header value.
|
|
1070
|
+
* @param errorMessage - Error message to throw if header is invalid or missing.
|
|
1071
|
+
*/
|
|
1072
|
+
export declare function assertNonEmptyHeader(header: unknown, errorMessage: string): asserts header is string;
|
|
1073
|
+
/**
|
|
1074
|
+
* Constructs a failed WebhookVerificationResult or throws if throwOnError is set.
|
|
1075
|
+
*
|
|
1076
|
+
* @param rawBody - Raw body string.
|
|
1077
|
+
* @param error - WebhookKitError instance.
|
|
1078
|
+
* @param throwOnError - Optional flag to throw immediately.
|
|
1079
|
+
* @param timestamp - Optional parsed timestamp.
|
|
1080
|
+
* @param eventId - Optional webhook event ID.
|
|
1081
|
+
* @returns Failed verification result.
|
|
1082
|
+
*/
|
|
1083
|
+
export declare function failVerification(rawBody: string, error: WebhookKitError, throwOnError?: boolean, timestamp?: number, eventId?: string): WebhookVerificationResult<never>;
|
|
1084
|
+
/**
|
|
1085
|
+
* Attempts to parse the raw body as JSON.
|
|
1086
|
+
*
|
|
1087
|
+
* @param rawBody - Raw body payload string.
|
|
1088
|
+
* @returns Parsed payload or undefined.
|
|
1089
|
+
*/
|
|
1090
|
+
export declare function tryParseJson<T>(rawBody: string): T | undefined;
|
|
1091
|
+
//# sourceMappingURL=index.d.mts.map
|