@amirabaris/webhook-kit 0.1.1 → 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/dist/index.d.ts CHANGED
@@ -72,6 +72,25 @@ export interface WebhookReplayStore {
72
72
  * @param ttlSeconds - Time-to-live in seconds before the entry expires.
73
73
  */
74
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>;
75
94
  }
76
95
  /**
77
96
  * Options for generic or provider-specific webhook signature verification.
@@ -261,6 +280,9 @@ export interface VerifyReplayStoreOptions {
261
280
  */
262
281
  toleranceSeconds?: number;
263
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"];
264
286
  /**
265
287
  * Default in-memory TTL replay store backed by a JavaScript `Map`.
266
288
  * Automatically evicts expired entries on lookup and enforces an upper capacity bound
@@ -271,6 +293,7 @@ export declare class InMemoryReplayStore implements WebhookReplayStore {
271
293
  private readonly defaultTtlSeconds;
272
294
  private readonly now;
273
295
  private readonly entries;
296
+ private lastPruneMs;
274
297
  constructor(options?: InMemoryReplayStoreOptions);
275
298
  /**
276
299
  * Checks whether `eventId` is currently tracked and unexpired in the store.
@@ -286,6 +309,14 @@ export declare class InMemoryReplayStore implements WebhookReplayStore {
286
309
  * @param ttlSeconds - Time-to-live in seconds before expiration.
287
310
  */
288
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;
289
320
  /**
290
321
  * Removes a specific `eventId` from the store.
291
322
  *
@@ -311,6 +342,18 @@ export declare class InMemoryReplayStore implements WebhookReplayStore {
311
342
  * Returns the maximum capacity of the store.
312
343
  */
313
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;
314
357
  private evictExpiredOrOldest;
315
358
  }
316
359
  /**
@@ -336,6 +379,8 @@ export declare function resolveWebhookEventId(options: {
336
379
  }, headerCandidates?: readonly string[]): string | undefined;
337
380
  /**
338
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.
339
384
  *
340
385
  * @param options - Store instance, resolved `eventId`, and TTL configuration.
341
386
  * @returns `ReplayAttackError` if `eventId` is already present in `store`, or `null` if unseen / no store.
@@ -410,6 +455,9 @@ export interface GithubVerifyOptions extends ProviderVerifyOptions {
410
455
  */
411
456
  parseJson?: boolean;
412
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"];
413
461
  /**
414
462
  * Parses an `X-Hub-Signature-256` header, validating and extracting the hex signature.
415
463
  *
@@ -418,6 +466,32 @@ export interface GithubVerifyOptions extends ProviderVerifyOptions {
418
466
  * @throws {InvalidSignatureHeaderError} If header is missing, empty, or lacks a valid sha256= prefix.
419
467
  */
420
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
+ };
421
495
  /**
422
496
  * Verifies a GitHub webhook payload signature against `X-Hub-Signature-256`.
423
497
  *
@@ -467,6 +541,8 @@ export interface ShopifyVerifyOptions extends ProviderVerifyOptions {
467
541
  */
468
542
  parseJson?: boolean;
469
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"];
470
546
  /**
471
547
  * Parses an `X-Shopify-Hmac-Sha256` header, validating and normalizing the Base64 signature.
472
548
  *
@@ -475,6 +551,32 @@ export interface ShopifyVerifyOptions extends ProviderVerifyOptions {
475
551
  * @throws {InvalidSignatureHeaderError} If header is missing, empty, or not valid Base64.
476
552
  */
477
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
+ };
478
580
  /**
479
581
  * Verifies a Shopify webhook payload signature against `X-Shopify-Hmac-Sha256`.
480
582
  *
@@ -557,6 +659,7 @@ export interface StripeVerifyOptions extends ProviderVerifyOptions {
557
659
  */
558
660
  throwOnError?: boolean;
559
661
  }
662
+ export declare const STRIPE_EVENT_ID_HEADERS: readonly ["x-stripe-webhook-id", "x-webhook-id", "webhook-id"];
560
663
  /**
561
664
  * Parses a Stripe signature header string (`t=...,v1=...,v0=...`).
562
665
  *
@@ -574,6 +677,46 @@ export declare function parseStripeSignature(header: string): StripeParsedSignat
574
677
  * @throws {TimestampToleranceError} If timestamp falls outside the tolerance window.
575
678
  */
576
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;
577
720
  /**
578
721
  * Verifies a Stripe webhook event signature.
579
722
  *
@@ -920,4 +1063,29 @@ export declare function bytesToBase64(bytes: Uint8Array): string;
920
1063
  * @returns Decoded byte array.
921
1064
  */
922
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;
923
1091
  //# sourceMappingURL=index.d.mts.map