{"version":3,"sources":["../src/webhooks.ts"],"sourcesContent":["/**\n * RevKeen Webhook Utilities for TypeScript/Node.js SDK\n *\n * This file is automatically bundled with the generated SDK.\n * It provides webhook signature verification and event construction.\n *\n * ## Webhook Headers\n *\n * RevKeen sends the following headers with each webhook delivery:\n * - `X-Revkeen-Signature`: HMAC signature (format: `t=xxx,v1=yyy`)\n * - `X-Revkeen-Version`: API version date (e.g., `2026-01-01`)\n * - `X-Revkeen-Account`: Merchant account ID\n * - `X-Revkeen-Event-Id`: Unique event identifier\n * - `X-Revkeen-Timestamp`: Unix timestamp\n *\n * @example Basic usage\n * ```typescript\n * import { RevKeen, constructEvent, WebhookSignatureVerificationError } from '@revkeen/sdk';\n *\n * // In your webhook endpoint\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n *   const signature = req.headers['x-revkeen-signature'] as string;\n *\n *   try {\n *     const event = constructEvent(req.body.toString(), signature, webhookSecret);\n *\n *     switch (event.type) {\n *       case 'invoice.paid':\n *         const invoice = event.data.object;\n *         // Handle invoice paid...\n *         break;\n *       case 'subscription.created':\n *         const subscription = event.data.object;\n *         // Handle subscription created...\n *         break;\n *     }\n *\n *     res.json({ received: true });\n *   } catch (error) {\n *     if (error instanceof WebhookSignatureVerificationError) {\n *       console.error('Webhook signature verification failed:', error.message);\n *       return res.status(400).json({ error: 'Invalid signature' });\n *     }\n *     throw error;\n *   }\n * });\n * ```\n *\n * @example With version headers (recommended)\n * ```typescript\n * import {\n *   extractWebhookHeaders,\n *   constructEventWithHeaders,\n *   WebhookSignatureVerificationError\n * } from '@revkeen/sdk';\n *\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n *   try {\n *     const headers = extractWebhookHeaders(req.headers);\n *     const event = constructEventWithHeaders(req.body.toString(), headers, webhookSecret);\n *\n *     console.log('API Version:', event.api_version);\n *     console.log('Account:', event.account);\n *\n *     // Handle the event...\n *     res.json({ received: true });\n *   } catch (error) {\n *     if (error instanceof WebhookSignatureVerificationError) {\n *       return res.status(400).json({ error: 'Invalid signature' });\n *     }\n *     throw error;\n *   }\n * });\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from \"crypto\";\n\n/**\n * Default tolerance for timestamp validation (5 minutes)\n */\nexport const WEBHOOK_TOLERANCE_IN_SECONDS = 300;\n\n/**\n * All possible webhook event types\n */\nexport type WebhookEventType =\n  // Invoice events\n  | \"invoice.created\"\n  | \"invoice.updated\"\n  | \"invoice.finalized\"\n  | \"invoice.sent\"\n  | \"invoice.paid\"\n  | \"invoice.voided\"\n  | \"invoice.payment_failed\"\n  | \"invoice.overdue\"\n  // Subscription events\n  | \"subscription.created\"\n  | \"subscription.updated\"\n  | \"subscription.renewed\"\n  | \"subscription.canceled\"\n  | \"subscription.paused\"\n  | \"subscription.resumed\"\n  | \"subscription.trial_ending\"\n  | \"subscription.trial_ended\"\n  | \"subscription.past_due\"\n  // Payment events\n  | \"payment.succeeded\"\n  | \"payment.failed\"\n  | \"payment.refunded\"\n  | \"payment.disputed\"\n  | \"payment.captured\"\n  // Customer events\n  | \"customer.created\"\n  | \"customer.updated\"\n  | \"customer.deleted\"\n  | \"customer.payment_method.attached\"\n  | \"customer.payment_method.detached\"\n  // Checkout events\n  | \"checkout.session.completed\"\n  | \"checkout.session.expired\"\n  | \"checkout.session.async_payment_succeeded\"\n  | \"checkout.session.async_payment_failed\"\n  // Order events\n  | \"order.created\"\n  | \"order.updated\"\n  | \"order.paid\"\n  | \"order.canceled\"\n  | \"order.fulfilled\"\n  // Plan/Product events\n  | \"plan.created\"\n  | \"plan.updated\"\n  | \"plan.deleted\"\n  | \"product.created\"\n  | \"product.updated\"\n  | \"product.deleted\"\n  // Price events\n  | \"price.created\"\n  | \"price.updated\"\n  | \"price.deleted\"\n  // Usage billing events\n  | \"usage.threshold.reached\"\n  | \"usage.period_finalized\"\n  | \"usage.invoice.created\"\n  | \"usage.event.ingested\"\n  | \"usage.event.rejected\"\n  | \"meter.created\"\n  | \"meter.updated\"\n  | \"meter.archived\"\n  | \"meter_price.created\"\n  | \"meter_price.updated\"\n  | \"meter_price.deactivated\"\n  // Integration events\n  | \"integration.product_mapping.created\"\n  | \"integration.product_mapping.updated\"\n  | \"integration.product_mapping.deleted\"\n  // Commerce cart events (headless Cart / RevKeen Embed)\n  | \"commerce.cart.created\"\n  | \"commerce.cart.updated\"\n  | \"commerce.cart.line_item_added\"\n  | \"commerce.cart.line_item_removed\"\n  | \"commerce.cart.addon_toggled\"\n  | \"commerce.cart.discount_applied\"\n  | \"commerce.cart.abandoned\"\n  | \"commerce.cart.recovered\"\n  | \"commerce.cart.converted\"\n  // Commerce checkout events\n  | \"commerce.checkout.started\"\n  | \"commerce.checkout.payment_method_attached\"\n  | \"commerce.checkout.completed\"\n  | \"commerce.checkout.failed\";\n\n/**\n * Webhook event data structure\n */\nexport interface WebhookEventData<T = unknown> {\n  /** The object that triggered the event */\n  object: T;\n  /** Previous attributes if this is an update event */\n  previous_attributes?: Partial<T>;\n}\n\n/**\n * Webhook event structure (Stripe-compatible)\n */\nexport interface WebhookEvent<T = unknown> {\n  /** Unique event identifier */\n  id: string;\n  /** Object type, always \"event\" */\n  object: \"event\";\n  /** Event type */\n  type: WebhookEventType;\n  /** Unix timestamp when the event was created */\n  created: number;\n  /** Whether this is a live mode event */\n  livemode: boolean;\n  /** API version used to render the event data */\n  api_version: string;\n  /** Merchant account ID */\n  account?: string;\n  /** Event data */\n  data: WebhookEventData<T>;\n  /** Request information */\n  request?: {\n    id?: string;\n    idempotency_key?: string;\n  };\n}\n\n/**\n * Options for webhook signature verification\n */\nexport interface WebhookVerifyOptions {\n  /** The raw request body as a string */\n  payload: string;\n  /** The signature header value (revkeen-signature) */\n  signature: string;\n  /** Your webhook secret (starts with rk_wh_) */\n  secret: string;\n  /** Tolerance in seconds for timestamp validation (default: 300) */\n  tolerance?: number;\n}\n\n/**\n * Webhook headers sent with each delivery\n */\nexport interface WebhookHeaders {\n  /** X-Revkeen-Signature: HMAC signature (t=xxx,v1=yyy) */\n  signature: string;\n  /** X-Revkeen-Version: API version date (e.g., \"2026-01-01\") */\n  version?: string;\n  /** X-Revkeen-Account: Merchant account ID */\n  account?: string;\n  /** X-Revkeen-Event-Id: Unique event identifier */\n  eventId?: string;\n  /** X-Revkeen-Timestamp: Unix timestamp */\n  timestamp?: string;\n}\n\n/**\n * Extract webhook headers from request headers\n * Works with both Request objects and plain header objects\n *\n * @example\n * ```typescript\n * // Express.js\n * const headers = extractWebhookHeaders({\n *   'x-revkeen-signature': req.headers['x-revkeen-signature'],\n *   'x-revkeen-version': req.headers['x-revkeen-version'],\n *   'x-revkeen-account': req.headers['x-revkeen-account'],\n *   'x-revkeen-event-id': req.headers['x-revkeen-event-id'],\n *   'x-revkeen-timestamp': req.headers['x-revkeen-timestamp'],\n * });\n *\n * // Next.js / Web Request\n * const headers = extractWebhookHeaders({\n *   'x-revkeen-signature': request.headers.get('x-revkeen-signature'),\n *   'x-revkeen-version': request.headers.get('x-revkeen-version'),\n *   'x-revkeen-account': request.headers.get('x-revkeen-account'),\n *   'x-revkeen-event-id': request.headers.get('x-revkeen-event-id'),\n *   'x-revkeen-timestamp': request.headers.get('x-revkeen-timestamp'),\n * });\n * ```\n */\nexport function extractWebhookHeaders(\n  headers: Record<string, string | string[] | null | undefined>\n): WebhookHeaders {\n  const getHeader = (name: string): string | undefined => {\n    const value = headers[name] || headers[name.toLowerCase()];\n    if (Array.isArray(value)) return value[0];\n    return value || undefined;\n  };\n\n  const signature = getHeader(\"X-Revkeen-Signature\") || getHeader(\"x-rk-signature\");\n  if (!signature) {\n    throw new WebhookSignatureVerificationError(\n      \"Missing webhook signature header (X-Revkeen-Signature or x-rk-signature)\"\n    );\n  }\n\n  return {\n    signature,\n    version: getHeader(\"X-Revkeen-Version\"),\n    account: getHeader(\"X-Revkeen-Account\"),\n    eventId: getHeader(\"X-Revkeen-Event-Id\"),\n    timestamp: getHeader(\"X-Revkeen-Timestamp\"),\n  };\n}\n\n/**\n * Error thrown when webhook signature verification fails\n */\nexport class WebhookSignatureVerificationError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"WebhookSignatureVerificationError\";\n    // Maintains proper stack trace for where our error was thrown\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, WebhookSignatureVerificationError);\n    }\n  }\n}\n\n/**\n * Parsed webhook signature components\n */\ninterface ParsedSignature {\n  timestamp: number;\n  signatures: string[];\n}\n\n/**\n * Parses a webhook signature header\n * Format: \"t={timestamp},v1={signature}\"\n */\nfunction parseSignatureHeader(header: string): ParsedSignature {\n  const parts = header.split(\",\");\n  let timestamp: number | undefined;\n  const signatures: string[] = [];\n\n  for (const part of parts) {\n    const [key, value] = part.split(\"=\");\n\n    if (key === \"t\") {\n      timestamp = parseInt(value, 10);\n    } else if (key === \"v1\") {\n      signatures.push(value);\n    }\n  }\n\n  if (!timestamp || signatures.length === 0) {\n    throw new WebhookSignatureVerificationError(\n      \"Invalid signature header: missing timestamp or signature\"\n    );\n  }\n\n  return { timestamp, signatures };\n}\n\n/**\n * Verifies a webhook signature and returns whether it's valid\n *\n * @param options - Verification options\n * @returns true if the signature is valid\n * @throws WebhookSignatureVerificationError if verification fails\n */\nexport function verifySignature(options: WebhookVerifyOptions): boolean {\n  const {\n    payload,\n    signature,\n    secret,\n    tolerance = WEBHOOK_TOLERANCE_IN_SECONDS,\n  } = options;\n\n  // Check if signature header exists\n  if (!signature) {\n    throw new WebhookSignatureVerificationError(\n      \"Missing webhook signature header\"\n    );\n  }\n\n  // Parse signature header\n  const parsed = parseSignatureHeader(signature);\n\n  // Check timestamp tolerance (prevent replay attacks)\n  const currentTime = Math.floor(Date.now() / 1000);\n  const timeDiff = Math.abs(currentTime - parsed.timestamp);\n\n  if (timeDiff > tolerance) {\n    throw new WebhookSignatureVerificationError(\n      `Timestamp outside tolerance window (${timeDiff}s > ${tolerance}s). ` +\n        \"The webhook might be a replay attack, or your server's clock might be out of sync.\"\n    );\n  }\n\n  // Generate expected signature\n  const signedPayload = `${parsed.timestamp}.${payload}`;\n  const expectedSignature = createHmac(\"sha256\", secret)\n    .update(signedPayload, \"utf8\")\n    .digest(\"hex\");\n\n  // Compare signatures using constant-time comparison\n  const signatureValid = parsed.signatures.some((sig) => {\n    try {\n      const sigBuffer = Buffer.from(sig, \"hex\");\n      const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n      // Only compare if lengths match\n      if (sigBuffer.length !== expectedBuffer.length) {\n        return false;\n      }\n\n      return timingSafeEqual(sigBuffer, expectedBuffer);\n    } catch {\n      return false;\n    }\n  });\n\n  if (!signatureValid) {\n    throw new WebhookSignatureVerificationError(\n      \"Signature verification failed. \" +\n        \"Ensure you're using the correct webhook secret and the raw request body.\"\n    );\n  }\n\n  return true;\n}\n\n/**\n * Constructs and verifies a webhook event from a raw payload\n *\n * @param payload - The raw request body as a string\n * @param signature - The signature header value (revkeen-signature header)\n * @param secret - Your webhook secret (starts with rk_wh_)\n * @param options - Additional options\n * @returns The verified webhook event\n * @throws WebhookSignatureVerificationError if verification fails\n *\n * @example\n * ```typescript\n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n *   const event = constructEvent(\n *     req.body.toString(),\n *     req.headers['revkeen-signature'] as string,\n *     process.env.REVKEEN_WEBHOOK_SECRET!\n *   );\n *\n *   console.log('Received event:', event.type);\n *   res.json({ received: true });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Next.js API route example\n * export async function POST(req: Request) {\n *   const body = await req.text();\n *   const signature = req.headers.get('revkeen-signature')!;\n *\n *   const event = constructEvent(body, signature, process.env.REVKEEN_WEBHOOK_SECRET!);\n *\n *   // Handle the event...\n *   return Response.json({ received: true });\n * }\n * ```\n */\nexport function constructEvent(\n  payload: string,\n  signature: string,\n  secret: string,\n  options?: {\n    tolerance?: number;\n  }\n): WebhookEvent {\n  // Verify the signature\n  verifySignature({\n    payload,\n    signature,\n    secret,\n    tolerance: options?.tolerance,\n  });\n\n  // Parse and return the event\n  try {\n    const event = JSON.parse(payload) as WebhookEvent;\n\n    // Basic validation\n    if (!event.id || !event.type || !event.data) {\n      throw new Error(\"Invalid event structure\");\n    }\n\n    return event;\n  } catch (error) {\n    if (error instanceof SyntaxError) {\n      throw new WebhookSignatureVerificationError(\n        \"Invalid JSON payload: \" + error.message\n      );\n    }\n    throw error;\n  }\n}\n\n/**\n * Constructs and verifies a webhook event with header metadata\n *\n * This function extracts version information from headers and merges it\n * with the event payload for a richer event object.\n *\n * @param payload - The raw request body as a string\n * @param headers - Webhook headers extracted from the request\n * @param secret - Your webhook secret (starts with rk_wh_)\n * @param options - Additional options\n * @returns The verified webhook event with header metadata\n * @throws WebhookSignatureVerificationError if verification fails\n *\n * @example\n * ```typescript\n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n *   const headers = extractWebhookHeaders(req.headers);\n *   const event = constructEventWithHeaders(\n *     req.body.toString(),\n *     headers,\n *     process.env.REVKEEN_WEBHOOK_SECRET!\n *   );\n *\n *   console.log('API Version:', event.api_version);\n *   console.log('Account:', event.account);\n *   res.json({ received: true });\n * });\n * ```\n */\nexport function constructEventWithHeaders(\n  payload: string,\n  headers: WebhookHeaders,\n  secret: string,\n  options?: {\n    tolerance?: number;\n  }\n): WebhookEvent {\n  // Verify the signature using the header\n  verifySignature({\n    payload,\n    signature: headers.signature,\n    secret,\n    tolerance: options?.tolerance,\n  });\n\n  // Parse the event\n  try {\n    const event = JSON.parse(payload) as WebhookEvent;\n\n    // Basic validation\n    if (!event.id || !event.type || !event.data) {\n      throw new Error(\"Invalid event structure\");\n    }\n\n    // Merge header metadata into event if not already present\n    return {\n      ...event,\n      api_version: event.api_version || headers.version || \"unknown\",\n      account: event.account || headers.account,\n    };\n  } catch (error) {\n    if (error instanceof SyntaxError) {\n      throw new WebhookSignatureVerificationError(\n        \"Invalid JSON payload: \" + error.message\n      );\n    }\n    throw error;\n  }\n}\n\n/**\n * Webhook utilities namespace for SDK integration\n */\nexport const webhooks = {\n  /**\n   * Constructs and verifies a webhook event\n   * @see constructEvent\n   */\n  constructEvent,\n\n  /**\n   * Constructs and verifies a webhook event with header metadata\n   * @see constructEventWithHeaders\n   */\n  constructEventWithHeaders,\n\n  /**\n   * Extract webhook headers from request\n   * @see extractWebhookHeaders\n   */\n  extractWebhookHeaders,\n\n  /**\n   * Verifies a webhook signature without parsing the payload\n   * @see verifySignature\n   */\n  verifySignature,\n\n  /**\n   * Default timestamp tolerance in seconds\n   */\n  TOLERANCE_IN_SECONDS: WEBHOOK_TOLERANCE_IN_SECONDS,\n};\n\nexport default webhooks;\n"],"mappings":"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","names":[]}