{"version":3,"sources":["../../src/core/webhook-utils.ts","../../src/webhooks/handler.ts","../../src/webhooks/middleware.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Webhook signature verification utilities.\n *\n * Supports both Web Crypto API (browsers, Deno, Cloudflare Workers)\n * and Node.js crypto module with automatic runtime detection.\n * Uses constant-time comparison to prevent timing attacks.\n */\n\n/**\n * Verify an HMAC-SHA256 webhook signature.\n *\n * @param payload - The raw request body string\n * @param signature - The signature from the webhook header\n * @param secret - The webhook signing secret\n * @returns true if the signature is valid\n */\nexport async function verifyWebhookSignature(\n  payload: string,\n  signature: string,\n  secret: string\n): Promise<boolean> {\n  const hexDigest = await computeHmacSha256(payload, secret);\n\n  // Backend sends \"sha256=<hex>\" format — support both prefixed and raw signatures\n  const expectedPrefixed = `sha256=${hexDigest}`;\n\n  if (signature.startsWith('sha256=')) {\n    return constantTimeEqual(signature, expectedPrefixed);\n  }\n\n  return constantTimeEqual(signature, hexDigest);\n}\n\n/**\n * Compute HMAC-SHA256 hex digest.\n * Automatically selects Web Crypto API or Node.js crypto.\n */\nasync function computeHmacSha256(message: string, secret: string): Promise<string> {\n  // Try Web Crypto API first (browsers, Deno, Cloudflare Workers, Node 18+)\n  if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n    const encoder = new TextEncoder();\n    const key = await globalThis.crypto.subtle.importKey(\n      'raw',\n      encoder.encode(secret),\n      { name: 'HMAC', hash: 'SHA-256' },\n      false,\n      ['sign']\n    );\n    const sig = await globalThis.crypto.subtle.sign('HMAC', key, encoder.encode(message));\n    return Array.from(new Uint8Array(sig))\n      .map((b) => b.toString(16).padStart(2, '0'))\n      .join('');\n  }\n\n  // Fallback to Node.js crypto module\n  try {\n    const { createHmac } = await import('crypto');\n    return createHmac('sha256', secret).update(message).digest('hex');\n  } catch {\n    throw new Error(\n      'No crypto implementation available. Requires Web Crypto API or Node.js crypto module.'\n    );\n  }\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks.\n */\nfunction constantTimeEqual(a: string, b: string): boolean {\n  if (a.length !== b.length) {\n    return false;\n  }\n\n  let result = 0;\n  for (let i = 0; i < a.length; i++) {\n    result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n  }\n  return result === 0;\n}\n","/**\n * Webhook event handler with signature verification and typed dispatch.\n */\n\nimport { verifyWebhookSignature } from '../core/webhook-utils';\nimport type {\n  WebhookEvent,\n  WebhookEventType,\n  WebhookEventHandler,\n  WebhookAnyHandler,\n  WebhookHandlerConfig,\n} from './types';\n\nexport class WebhookHandler {\n  private handlers = new Map<WebhookEventType, WebhookEventHandler[]>();\n  private anyHandlers: WebhookAnyHandler[] = [];\n  private readonly secret: string;\n  private readonly tolerance: number;\n\n  constructor(config: WebhookHandlerConfig) {\n    this.secret = config.secret;\n    this.tolerance = config.tolerance ?? 300000; // 5 minutes\n  }\n\n  /**\n   * Register a handler for a specific event type.\n   */\n  on<T extends WebhookEventType>(\n    eventType: T,\n    handler: WebhookEventHandler<T>\n  ): this {\n    const existing = this.handlers.get(eventType) || [];\n    existing.push(handler as unknown as WebhookEventHandler);\n    this.handlers.set(eventType, existing);\n    return this;\n  }\n\n  /**\n   * Register a catch-all handler for all event types.\n   */\n  onAny(handler: WebhookAnyHandler): this {\n    this.anyHandlers.push(handler);\n    return this;\n  }\n\n  /**\n   * Verify signature and parse the webhook body.\n   */\n  async verifyAndParse(body: string, signature: string): Promise<WebhookEvent> {\n    const isValid = await verifyWebhookSignature(body, signature, this.secret);\n    if (!isValid) {\n      throw new Error('Invalid webhook signature');\n    }\n\n    return this.parseAndValidate(body);\n  }\n\n  /**\n   * Verify signature, parse, and dispatch to registered handlers.\n   */\n  async handle(body: string, signature: string): Promise<void> {\n    const event = await this.verifyAndParse(body, signature);\n    await this.dispatch(event);\n  }\n\n  /**\n   * Parse an event without signature verification (for testing).\n   */\n  parseEvent(body: string): WebhookEvent {\n    return this.parseAndValidate(body);\n  }\n\n  private parseAndValidate(body: string): WebhookEvent {\n    const event = JSON.parse(body) as WebhookEvent;\n\n    if (!event.type || !event.id || !event.timestamp) {\n      throw new Error('Invalid webhook event: missing required fields (type, id, timestamp)');\n    }\n\n    // Timestamp tolerance check\n    if (this.tolerance > 0) {\n      const eventTime = new Date(event.timestamp).getTime();\n      const now = Date.now();\n      if (Math.abs(now - eventTime) > this.tolerance) {\n        throw new Error(\n          `Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`\n        );\n      }\n    }\n\n    return event;\n  }\n\n  private async dispatch(event: WebhookEvent): Promise<void> {\n    const typeHandlers = this.handlers.get(event.type) || [];\n    const allHandlers = [...typeHandlers, ...this.anyHandlers];\n\n    for (const handler of allHandlers) {\n      await (handler as WebhookAnyHandler)(event);\n    }\n  }\n}\n","/**\n * Framework middleware helpers for webhook handling.\n *\n * Provides pre-built integrations for Express/Connect and Next.js App Router.\n */\n\nimport { WebhookHandler } from './handler';\nimport type { WebhookHandlerConfig, WebhookEventType, WebhookEventHandler, WebhookAnyHandler } from './types';\n\nexport interface WebhookMiddlewareOptions extends WebhookHandlerConfig {\n  /** Event handlers to register */\n  handlers?: Partial<Record<WebhookEventType, WebhookEventHandler>>;\n  /** Catch-all handler */\n  onAny?: WebhookAnyHandler;\n}\n\n/**\n * Create an Express/Connect-compatible middleware for webhook handling.\n *\n * Expects the raw body to be available as `req.body` (string).\n * Use `express.raw({ type: 'application/json' })` or similar middleware upstream.\n */\nexport function createWebhookMiddleware(options: WebhookMiddlewareOptions) {\n  const handler = buildHandler(options);\n  const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n  return async (\n    req: { body: string | Buffer; headers: Record<string, string | string[] | undefined> },\n    res: { status(code: number): { json(body: unknown): void }; json?(body: unknown): void },\n    next?: (err?: unknown) => void\n  ) => {\n    try {\n      const body = typeof req.body === 'string' ? req.body : req.body.toString('utf-8');\n      const signature = req.headers[signatureHeader];\n\n      if (!signature || typeof signature !== 'string') {\n        res.status(401).json({ error: 'Missing webhook signature' });\n        return;\n      }\n\n      await handler.handle(body, signature);\n      res.status(200).json({ received: true });\n    } catch (error) {\n      const message = error instanceof Error ? error.message : 'Webhook processing failed';\n\n      if (message.includes('signature')) {\n        res.status(401).json({ error: message });\n      } else if (message.includes('tolerance') || message.includes('timestamp')) {\n        res.status(400).json({ error: message });\n      } else if (next) {\n        next(error);\n      } else {\n        res.status(500).json({ error: message });\n      }\n    }\n  };\n}\n\n/**\n * Create a Next.js App Router-compatible webhook handler.\n *\n * Returns an async function `(request: Request) => Promise<Response>`.\n */\nexport function createNextWebhookHandler(\n  options: WebhookMiddlewareOptions\n): (request: Request) => Promise<Response> {\n  const handler = buildHandler(options);\n  const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n  return async (request: Request): Promise<Response> => {\n    try {\n      const body = await request.text();\n      const signature = request.headers.get(signatureHeader);\n\n      if (!signature) {\n        return new Response(JSON.stringify({ error: 'Missing webhook signature' }), {\n          status: 401,\n          headers: { 'Content-Type': 'application/json' },\n        });\n      }\n\n      await handler.handle(body, signature);\n\n      return new Response(JSON.stringify({ received: true }), {\n        status: 200,\n        headers: { 'Content-Type': 'application/json' },\n      });\n    } catch (error) {\n      const message = error instanceof Error ? error.message : 'Webhook processing failed';\n      const status = message.includes('signature')\n        ? 401\n        : message.includes('tolerance') || message.includes('timestamp')\n          ? 400\n          : 500;\n\n      return new Response(JSON.stringify({ error: message }), {\n        status,\n        headers: { 'Content-Type': 'application/json' },\n      });\n    }\n  };\n}\n\nfunction buildHandler(options: WebhookMiddlewareOptions): WebhookHandler {\n  const handler = new WebhookHandler(options);\n\n  if (options.handlers) {\n    for (const [eventType, eventHandler] of Object.entries(options.handlers)) {\n      if (eventHandler) {\n        handler.on(eventType as WebhookEventType, eventHandler);\n      }\n    }\n  }\n\n  if (options.onAny) {\n    handler.onAny(options.onAny);\n  }\n\n  return handler;\n}\n"]}