@gravito/echo 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/README.md +211 -0
  2. package/dist/atlas/src/DB.d.ts +301 -0
  3. package/dist/atlas/src/OrbitAtlas.d.ts +9 -0
  4. package/dist/atlas/src/config/defineConfig.d.ts +14 -0
  5. package/dist/atlas/src/config/index.d.ts +7 -0
  6. package/dist/atlas/src/config/loadConfig.d.ts +48 -0
  7. package/dist/atlas/src/connection/Connection.d.ts +108 -0
  8. package/dist/atlas/src/connection/ConnectionManager.d.ts +111 -0
  9. package/dist/atlas/src/drivers/BunSQLDriver.d.ts +32 -0
  10. package/dist/atlas/src/drivers/BunSQLPreparedStatement.d.ts +118 -0
  11. package/dist/atlas/src/drivers/MongoDBDriver.d.ts +36 -0
  12. package/dist/atlas/src/drivers/MySQLDriver.d.ts +66 -0
  13. package/dist/atlas/src/drivers/PostgresDriver.d.ts +83 -0
  14. package/dist/atlas/src/drivers/RedisDriver.d.ts +43 -0
  15. package/dist/atlas/src/drivers/SQLiteDriver.d.ts +45 -0
  16. package/dist/atlas/src/drivers/types.d.ts +260 -0
  17. package/dist/atlas/src/errors/index.d.ts +45 -0
  18. package/dist/atlas/src/grammar/Grammar.d.ts +342 -0
  19. package/dist/atlas/src/grammar/MongoGrammar.d.ts +47 -0
  20. package/dist/atlas/src/grammar/MySQLGrammar.d.ts +54 -0
  21. package/dist/atlas/src/grammar/NullGrammar.d.ts +35 -0
  22. package/dist/atlas/src/grammar/PostgresGrammar.d.ts +62 -0
  23. package/dist/atlas/src/grammar/SQLiteGrammar.d.ts +32 -0
  24. package/dist/atlas/src/index.d.ts +67 -0
  25. package/dist/atlas/src/migration/Migration.d.ts +64 -0
  26. package/dist/atlas/src/migration/MigrationRepository.d.ts +65 -0
  27. package/dist/atlas/src/migration/Migrator.d.ts +110 -0
  28. package/dist/atlas/src/migration/index.d.ts +6 -0
  29. package/dist/atlas/src/observability/AtlasMetrics.d.ts +11 -0
  30. package/dist/atlas/src/observability/AtlasObservability.d.ts +15 -0
  31. package/dist/atlas/src/observability/AtlasTracer.d.ts +12 -0
  32. package/dist/atlas/src/observability/index.d.ts +9 -0
  33. package/dist/atlas/src/orm/index.d.ts +5 -0
  34. package/dist/atlas/src/orm/model/DirtyTracker.d.ts +121 -0
  35. package/dist/atlas/src/orm/model/Model.d.ts +449 -0
  36. package/dist/atlas/src/orm/model/ModelRegistry.d.ts +20 -0
  37. package/dist/atlas/src/orm/model/concerns/HasAttributes.d.ts +136 -0
  38. package/dist/atlas/src/orm/model/concerns/HasEvents.d.ts +36 -0
  39. package/dist/atlas/src/orm/model/concerns/HasPersistence.d.ts +87 -0
  40. package/dist/atlas/src/orm/model/concerns/HasRelationships.d.ts +117 -0
  41. package/dist/atlas/src/orm/model/concerns/HasSerialization.d.ts +64 -0
  42. package/dist/atlas/src/orm/model/concerns/applyMixins.d.ts +15 -0
  43. package/dist/atlas/src/orm/model/concerns/index.d.ts +12 -0
  44. package/dist/atlas/src/orm/model/decorators.d.ts +109 -0
  45. package/dist/atlas/src/orm/model/errors.d.ts +52 -0
  46. package/dist/atlas/src/orm/model/index.d.ts +10 -0
  47. package/dist/atlas/src/orm/model/relationships.d.ts +207 -0
  48. package/dist/atlas/src/orm/model/types.d.ts +12 -0
  49. package/dist/atlas/src/orm/schema/SchemaRegistry.d.ts +123 -0
  50. package/dist/atlas/src/orm/schema/SchemaSniffer.d.ts +54 -0
  51. package/dist/atlas/src/orm/schema/index.d.ts +6 -0
  52. package/dist/atlas/src/orm/schema/types.d.ts +85 -0
  53. package/dist/atlas/src/query/Expression.d.ts +60 -0
  54. package/dist/atlas/src/query/NPlusOneDetector.d.ts +10 -0
  55. package/dist/atlas/src/query/QueryBuilder.d.ts +573 -0
  56. package/dist/atlas/src/query/clauses/GroupByClause.d.ts +51 -0
  57. package/dist/atlas/src/query/clauses/HavingClause.d.ts +70 -0
  58. package/dist/atlas/src/query/clauses/JoinClause.d.ts +87 -0
  59. package/dist/atlas/src/query/clauses/LimitClause.d.ts +82 -0
  60. package/dist/atlas/src/query/clauses/OrderByClause.d.ts +69 -0
  61. package/dist/atlas/src/query/clauses/SelectClause.d.ts +71 -0
  62. package/dist/atlas/src/query/clauses/WhereClause.d.ts +167 -0
  63. package/dist/atlas/src/query/clauses/index.d.ts +11 -0
  64. package/dist/atlas/src/schema/Blueprint.d.ts +276 -0
  65. package/dist/atlas/src/schema/ColumnDefinition.d.ts +154 -0
  66. package/dist/atlas/src/schema/ForeignKeyDefinition.d.ts +37 -0
  67. package/dist/atlas/src/schema/Schema.d.ts +131 -0
  68. package/dist/atlas/src/schema/grammars/MySQLSchemaGrammar.d.ts +23 -0
  69. package/dist/atlas/src/schema/grammars/PostgresSchemaGrammar.d.ts +26 -0
  70. package/dist/atlas/src/schema/grammars/SQLiteSchemaGrammar.d.ts +28 -0
  71. package/dist/atlas/src/schema/grammars/SchemaGrammar.d.ts +97 -0
  72. package/dist/atlas/src/schema/grammars/index.d.ts +7 -0
  73. package/dist/atlas/src/schema/index.d.ts +8 -0
  74. package/dist/atlas/src/seed/Factory.d.ts +90 -0
  75. package/dist/atlas/src/seed/Seeder.d.ts +28 -0
  76. package/dist/atlas/src/seed/SeederRunner.d.ts +74 -0
  77. package/dist/atlas/src/seed/index.d.ts +6 -0
  78. package/dist/atlas/src/types/index.d.ts +1100 -0
  79. package/dist/atlas/src/utils/levenshtein.d.ts +9 -0
  80. package/dist/core/src/Application.d.ts +215 -0
  81. package/dist/core/src/CommandKernel.d.ts +33 -0
  82. package/dist/core/src/ConfigManager.d.ts +26 -0
  83. package/dist/core/src/Container.d.ts +108 -0
  84. package/dist/core/src/ErrorHandler.d.ts +63 -0
  85. package/dist/core/src/Event.d.ts +5 -0
  86. package/dist/core/src/EventManager.d.ts +123 -0
  87. package/dist/core/src/GlobalErrorHandlers.d.ts +47 -0
  88. package/dist/core/src/GravitoServer.d.ts +28 -0
  89. package/dist/core/src/HookManager.d.ts +496 -0
  90. package/dist/core/src/Listener.d.ts +4 -0
  91. package/dist/core/src/Logger.d.ts +20 -0
  92. package/dist/core/src/PlanetCore.d.ts +289 -0
  93. package/dist/core/src/Route.d.ts +36 -0
  94. package/dist/core/src/Router.d.ts +284 -0
  95. package/dist/core/src/ServiceProvider.d.ts +156 -0
  96. package/dist/core/src/adapters/GravitoEngineAdapter.d.ts +27 -0
  97. package/dist/core/src/adapters/PhotonAdapter.d.ts +171 -0
  98. package/dist/core/src/adapters/bun/BunContext.d.ts +45 -0
  99. package/dist/core/src/adapters/bun/BunNativeAdapter.d.ts +31 -0
  100. package/dist/core/src/adapters/bun/BunRequest.d.ts +31 -0
  101. package/dist/core/src/adapters/bun/RadixNode.d.ts +19 -0
  102. package/dist/core/src/adapters/bun/RadixRouter.d.ts +31 -0
  103. package/dist/core/src/adapters/bun/types.d.ts +20 -0
  104. package/dist/core/src/adapters/photon-types.d.ts +73 -0
  105. package/dist/core/src/adapters/types.d.ts +235 -0
  106. package/dist/core/src/engine/AOTRouter.d.ts +124 -0
  107. package/dist/core/src/engine/FastContext.d.ts +100 -0
  108. package/dist/core/src/engine/Gravito.d.ts +137 -0
  109. package/dist/core/src/engine/MinimalContext.d.ts +79 -0
  110. package/dist/core/src/engine/analyzer.d.ts +27 -0
  111. package/dist/core/src/engine/constants.d.ts +23 -0
  112. package/dist/core/src/engine/index.d.ts +26 -0
  113. package/dist/core/src/engine/path.d.ts +26 -0
  114. package/dist/core/src/engine/pool.d.ts +83 -0
  115. package/dist/core/src/engine/types.d.ts +143 -0
  116. package/dist/core/src/events/CircuitBreaker.d.ts +229 -0
  117. package/dist/core/src/events/DeadLetterQueue.d.ts +145 -0
  118. package/dist/core/src/events/EventBackend.d.ts +11 -0
  119. package/dist/core/src/events/EventOptions.d.ts +109 -0
  120. package/dist/core/src/events/EventPriorityQueue.d.ts +202 -0
  121. package/dist/core/src/events/IdempotencyCache.d.ts +60 -0
  122. package/dist/core/src/events/index.d.ts +14 -0
  123. package/dist/core/src/events/observability/EventMetrics.d.ts +132 -0
  124. package/dist/core/src/events/observability/EventTracer.d.ts +68 -0
  125. package/dist/core/src/events/observability/EventTracing.d.ts +161 -0
  126. package/dist/core/src/events/observability/OTelEventMetrics.d.ts +240 -0
  127. package/dist/core/src/events/observability/ObservableHookManager.d.ts +108 -0
  128. package/dist/core/src/events/observability/index.d.ts +20 -0
  129. package/dist/core/src/events/observability/metrics-types.d.ts +16 -0
  130. package/dist/core/src/events/types.d.ts +75 -0
  131. package/dist/core/src/exceptions/AuthenticationException.d.ts +8 -0
  132. package/dist/core/src/exceptions/AuthorizationException.d.ts +8 -0
  133. package/dist/core/src/exceptions/CircularDependencyException.d.ts +9 -0
  134. package/dist/core/src/exceptions/GravitoException.d.ts +23 -0
  135. package/dist/core/src/exceptions/HttpException.d.ts +9 -0
  136. package/dist/core/src/exceptions/ModelNotFoundException.d.ts +10 -0
  137. package/dist/core/src/exceptions/ValidationException.d.ts +22 -0
  138. package/dist/core/src/exceptions/index.d.ts +7 -0
  139. package/dist/core/src/helpers/Arr.d.ts +19 -0
  140. package/dist/core/src/helpers/Str.d.ts +23 -0
  141. package/dist/core/src/helpers/data.d.ts +25 -0
  142. package/dist/core/src/helpers/errors.d.ts +34 -0
  143. package/dist/core/src/helpers/response.d.ts +41 -0
  144. package/dist/core/src/helpers.d.ts +338 -0
  145. package/dist/core/src/http/CookieJar.d.ts +51 -0
  146. package/dist/core/src/http/cookie.d.ts +29 -0
  147. package/dist/core/src/http/middleware/BodySizeLimit.d.ts +16 -0
  148. package/dist/core/src/http/middleware/Cors.d.ts +24 -0
  149. package/dist/core/src/http/middleware/Csrf.d.ts +23 -0
  150. package/dist/core/src/http/middleware/HeaderTokenGate.d.ts +28 -0
  151. package/dist/core/src/http/middleware/SecurityHeaders.d.ts +29 -0
  152. package/dist/core/src/http/middleware/ThrottleRequests.d.ts +18 -0
  153. package/dist/core/src/http/types.d.ts +355 -0
  154. package/dist/core/src/index.d.ts +76 -0
  155. package/dist/core/src/instrumentation/index.d.ts +35 -0
  156. package/dist/core/src/instrumentation/opentelemetry.d.ts +178 -0
  157. package/dist/core/src/instrumentation/types.d.ts +182 -0
  158. package/dist/core/src/reliability/DeadLetterQueueManager.d.ts +316 -0
  159. package/dist/core/src/reliability/RetryPolicy.d.ts +217 -0
  160. package/dist/core/src/reliability/index.d.ts +6 -0
  161. package/dist/core/src/router/ControllerDispatcher.d.ts +12 -0
  162. package/dist/core/src/router/RequestValidator.d.ts +20 -0
  163. package/dist/core/src/runtime.d.ts +119 -0
  164. package/dist/core/src/security/Encrypter.d.ts +33 -0
  165. package/dist/core/src/security/Hasher.d.ts +29 -0
  166. package/dist/core/src/testing/HttpTester.d.ts +39 -0
  167. package/dist/core/src/testing/TestResponse.d.ts +78 -0
  168. package/dist/core/src/testing/index.d.ts +2 -0
  169. package/dist/core/src/types/events.d.ts +94 -0
  170. package/dist/echo/src/OrbitEcho.d.ts +115 -0
  171. package/dist/echo/src/dlq/DeadLetterQueue.d.ts +94 -0
  172. package/dist/echo/src/dlq/MemoryDeadLetterQueue.d.ts +36 -0
  173. package/dist/echo/src/dlq/index.d.ts +2 -0
  174. package/dist/echo/src/index.d.ts +64 -0
  175. package/dist/echo/src/middleware/RequestBufferMiddleware.d.ts +62 -0
  176. package/dist/echo/src/middleware/index.d.ts +8 -0
  177. package/dist/echo/src/observability/index.d.ts +3 -0
  178. package/dist/echo/src/observability/logging/ConsoleEchoLogger.d.ts +37 -0
  179. package/dist/echo/src/observability/logging/EchoLogger.d.ts +38 -0
  180. package/dist/echo/src/observability/logging/index.d.ts +2 -0
  181. package/dist/echo/src/observability/metrics/MetricsProvider.d.ts +69 -0
  182. package/dist/echo/src/observability/metrics/NoopMetricsProvider.d.ts +17 -0
  183. package/dist/echo/src/observability/metrics/PrometheusMetricsProvider.d.ts +39 -0
  184. package/dist/echo/src/observability/metrics/index.d.ts +3 -0
  185. package/dist/echo/src/observability/tracing/NoopTracer.d.ts +33 -0
  186. package/dist/echo/src/observability/tracing/Tracer.d.ts +75 -0
  187. package/dist/echo/src/observability/tracing/index.d.ts +2 -0
  188. package/dist/echo/src/providers/GenericProvider.d.ts +53 -0
  189. package/dist/echo/src/providers/GitHubProvider.d.ts +35 -0
  190. package/dist/echo/src/providers/LinearProvider.d.ts +27 -0
  191. package/dist/echo/src/providers/PaddleProvider.d.ts +31 -0
  192. package/dist/echo/src/providers/ShopifyProvider.d.ts +27 -0
  193. package/dist/echo/src/providers/SlackProvider.d.ts +27 -0
  194. package/dist/echo/src/providers/StripeProvider.d.ts +38 -0
  195. package/dist/echo/src/providers/TwilioProvider.d.ts +31 -0
  196. package/dist/echo/src/providers/base/BaseProvider.d.ts +87 -0
  197. package/dist/echo/src/providers/base/HeaderUtils.d.ts +34 -0
  198. package/dist/echo/src/providers/index.d.ts +14 -0
  199. package/dist/echo/src/receive/SignatureValidator.d.ts +67 -0
  200. package/dist/echo/src/receive/WebhookReceiver.d.ts +185 -0
  201. package/dist/echo/src/receive/index.d.ts +2 -0
  202. package/dist/echo/src/replay/WebhookReplayService.d.ts +35 -0
  203. package/dist/echo/src/replay/index.d.ts +1 -0
  204. package/dist/echo/src/resilience/CircuitBreaker.d.ts +117 -0
  205. package/dist/echo/src/resilience/index.d.ts +10 -0
  206. package/dist/echo/src/rotation/KeyRotationManager.d.ts +127 -0
  207. package/dist/echo/src/rotation/index.d.ts +10 -0
  208. package/dist/echo/src/send/WebhookDispatcher.d.ts +198 -0
  209. package/dist/echo/src/send/index.d.ts +1 -0
  210. package/dist/echo/src/storage/MemoryWebhookStore.d.ts +14 -0
  211. package/dist/echo/src/storage/WebhookStore.d.ts +236 -0
  212. package/dist/echo/src/storage/index.d.ts +2 -0
  213. package/dist/echo/src/types.d.ts +756 -0
  214. package/dist/index.js +1332 -190
  215. package/dist/index.js.map +28 -10
  216. package/dist/photon/src/index.d.ts +84 -0
  217. package/dist/photon/src/middleware/binary.d.ts +31 -0
  218. package/dist/photon/src/middleware/htmx.d.ts +39 -0
  219. package/dist/photon/src/middleware/ratelimit.d.ts +157 -0
  220. package/dist/photon/src/openapi.d.ts +19 -0
  221. package/package.json +7 -5
package/dist/index.js.map CHANGED
@@ -1,16 +1,34 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/receive/SignatureValidator.ts", "../src/providers/GenericProvider.ts", "../src/providers/GitHubProvider.ts", "../src/providers/StripeProvider.ts", "../src/receive/WebhookReceiver.ts", "../src/send/WebhookDispatcher.ts", "../src/OrbitEcho.ts"],
3
+ "sources": ["../src/dlq/MemoryDeadLetterQueue.ts", "../src/middleware/RequestBufferMiddleware.ts", "../src/observability/logging/ConsoleEchoLogger.ts", "../src/observability/metrics/MetricsProvider.ts", "../src/observability/metrics/NoopMetricsProvider.ts", "../src/observability/metrics/PrometheusMetricsProvider.ts", "../src/observability/tracing/NoopTracer.ts", "../src/observability/tracing/Tracer.ts", "../src/receive/SignatureValidator.ts", "../src/providers/base/HeaderUtils.ts", "../src/providers/base/BaseProvider.ts", "../src/providers/GenericProvider.ts", "../src/providers/GitHubProvider.ts", "../src/providers/LinearProvider.ts", "../src/providers/PaddleProvider.ts", "../src/providers/ShopifyProvider.ts", "../src/providers/SlackProvider.ts", "../src/providers/StripeProvider.ts", "../src/providers/TwilioProvider.ts", "../src/receive/WebhookReceiver.ts", "../src/rotation/KeyRotationManager.ts", "../src/resilience/CircuitBreaker.ts", "../src/send/WebhookDispatcher.ts", "../src/OrbitEcho.ts", "../src/replay/WebhookReplayService.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * @fileoverview Signature validation utilities\n *\n * Provides HMAC-based signature verification for webhook payloads.\n *\n * @module @gravito/echo/receive\n */\n\n/**\n * Compute HMAC-SHA256 signature\n */\nexport async function computeHmacSha256(payload: string | Buffer, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('hex')\n}\n\n/**\n * Compute HMAC-SHA1 signature (for legacy providers)\n */\nexport async function computeHmacSha1(payload: string | Buffer, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-1' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('hex')\n}\n\n/**\n * Timing-safe string comparison to prevent timing attacks\n */\nexport function timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n const aBytes = new TextEncoder().encode(a)\n const bBytes = new TextEncoder().encode(b)\n\n let result = 0\n for (let i = 0; i < aBytes.length; i++) {\n result |= (aBytes[i] ?? 0) ^ (bBytes[i] ?? 0)\n }\n\n return result === 0\n}\n\n/**\n * Validate timestamp is within tolerance\n *\n * @param timestamp - Unix timestamp in seconds\n * @param tolerance - Tolerance in seconds (default: 300 = 5 minutes)\n */\nexport function validateTimestamp(timestamp: number, tolerance = 300): boolean {\n const now = Math.floor(Date.now() / 1000)\n return Math.abs(now - timestamp) <= tolerance\n}\n\n/**\n * Parse Stripe-style signature header\n * Format: t=timestamp,v1=signature,v1=signature2\n */\nexport function parseStripeSignature(\n header: string\n): { timestamp: number; signatures: string[] } | null {\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 if (key === 't' && value !== undefined) {\n timestamp = parseInt(value, 10)\n } else if (key === 'v1' && value !== undefined) {\n signatures.push(value)\n }\n }\n\n if (timestamp === undefined || signatures.length === 0) {\n return null\n }\n\n return { timestamp, signatures }\n}\n",
6
- "/**\n * @fileoverview Generic webhook provider\n *\n * Simple HMAC-SHA256 signature verification.\n *\n * @module @gravito/echo/providers\n */\n\nimport {\n computeHmacSha256,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookProvider, WebhookVerificationResult } from '../types'\n\n/**\n * Generic webhook provider using HMAC-SHA256\n *\n * Expected headers:\n * - X-Webhook-Signature: HMAC-SHA256 hex signature\n * - X-Webhook-Timestamp: Unix timestamp (optional)\n *\n * @example\n * ```typescript\n * const provider = new GenericProvider()\n * const result = await provider.verify(body, headers, secret)\n * ```\n */\nexport class GenericProvider implements WebhookProvider {\n readonly name = 'generic'\n\n private signatureHeader: string\n private timestampHeader: string\n private tolerance: number\n\n constructor(\n options: {\n signatureHeader?: string\n timestampHeader?: string\n tolerance?: number\n } = {}\n ) {\n this.signatureHeader = options.signatureHeader ?? 'x-webhook-signature'\n this.timestampHeader = options.timestampHeader ?? 'x-webhook-timestamp'\n this.tolerance = options.tolerance ?? 300\n }\n\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n // Get signature from headers\n const signature = this.getHeader(headers, this.signatureHeader)\n if (!signature) {\n return {\n valid: false,\n error: `Missing signature header: ${this.signatureHeader}`,\n }\n }\n\n // Validate timestamp if present\n const timestampStr = this.getHeader(headers, this.timestampHeader)\n if (timestampStr) {\n const timestamp = parseInt(timestampStr, 10)\n if (Number.isNaN(timestamp) || !validateTimestamp(timestamp, this.tolerance)) {\n return {\n valid: false,\n error: 'Timestamp validation failed',\n }\n }\n }\n\n // Compute expected signature\n const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf-8')\n const expectedSignature = await computeHmacSha256(payloadStr, secret)\n\n // Compare signatures\n if (!timingSafeEqual(signature.toLowerCase(), expectedSignature.toLowerCase())) {\n return {\n valid: false,\n error: 'Signature verification failed',\n }\n }\n\n // Parse payload\n try {\n const parsed = JSON.parse(payloadStr)\n return {\n valid: true,\n payload: parsed,\n eventType: parsed.type ?? parsed.event ?? parsed.eventType,\n webhookId: parsed.id ?? parsed.webhookId,\n }\n } catch {\n return {\n valid: true,\n payload: payloadStr,\n }\n }\n }\n\n private getHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n ): string | undefined {\n const value = headers[name] ?? headers[name.toLowerCase()]\n return Array.isArray(value) ? value[0] : value\n }\n}\n",
7
- "/**\n * @fileoverview GitHub webhook provider\n *\n * Implements GitHub's webhook signature verification.\n * @see https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries\n *\n * @module @gravito/echo/providers\n */\n\nimport { computeHmacSha256, timingSafeEqual } from '../receive/SignatureValidator'\nimport type { WebhookProvider, WebhookVerificationResult } from '../types'\n\n/**\n * GitHub webhook provider\n *\n * Verifies GitHub webhook signatures using the X-Hub-Signature-256 header.\n *\n * @example\n * ```typescript\n * const provider = new GitHubProvider()\n * const result = await provider.verify(body, headers, process.env.GITHUB_WEBHOOK_SECRET)\n * ```\n */\nexport class GitHubProvider implements WebhookProvider {\n readonly name = 'github'\n\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n // GitHub sends signature in X-Hub-Signature-256 header\n const signature = this.getHeader(headers, 'x-hub-signature-256')\n if (!signature) {\n return {\n valid: false,\n error: 'Missing X-Hub-Signature-256 header',\n }\n }\n\n // Signature format: sha256=<hex>\n if (!signature.startsWith('sha256=')) {\n return {\n valid: false,\n error: 'Invalid signature format (expected sha256=...)',\n }\n }\n\n const signatureValue = signature.slice(7) // Remove 'sha256=' prefix\n\n // Compute expected signature\n const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf-8')\n const expectedSignature = await computeHmacSha256(payloadStr, secret)\n\n // Compare signatures\n if (!timingSafeEqual(signatureValue.toLowerCase(), expectedSignature.toLowerCase())) {\n return {\n valid: false,\n error: 'Signature verification failed',\n }\n }\n\n // Parse payload\n try {\n const event = JSON.parse(payloadStr)\n const eventType = this.getHeader(headers, 'x-github-event')\n const deliveryId = this.getHeader(headers, 'x-github-delivery')\n\n return {\n valid: true,\n payload: event,\n eventType: eventType ?? undefined,\n webhookId: deliveryId ?? undefined,\n }\n } catch {\n return {\n valid: false,\n error: 'Failed to parse webhook payload',\n }\n }\n }\n\n parseEventType(payload: unknown): string | undefined {\n if (typeof payload === 'object' && payload !== null && 'action' in payload) {\n return (payload as { action: string }).action\n }\n return undefined\n }\n\n private getHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n ): string | undefined {\n const value = headers[name] ?? headers[name.toLowerCase()]\n return Array.isArray(value) ? value[0] : value\n }\n}\n",
8
- "/**\n * @fileoverview Stripe webhook provider\n *\n * Implements Stripe's webhook signature verification.\n * @see https://stripe.com/docs/webhooks/signatures\n *\n * @module @gravito/echo/providers\n */\n\nimport {\n computeHmacSha256,\n parseStripeSignature,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookProvider, WebhookVerificationResult } from '../types'\n\n/**\n * Stripe webhook provider\n *\n * Verifies Stripe webhook signatures using their standard format.\n *\n * @example\n * ```typescript\n * const provider = new StripeProvider()\n * const result = await provider.verify(body, headers, process.env.STRIPE_WEBHOOK_SECRET)\n * ```\n */\nexport class StripeProvider implements WebhookProvider {\n readonly name = 'stripe'\n\n private tolerance: number\n\n constructor(options: { tolerance?: number } = {}) {\n this.tolerance = options.tolerance ?? 300\n }\n\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n // Get signature header\n const signatureHeader = this.getHeader(headers, 'stripe-signature')\n if (!signatureHeader) {\n return {\n valid: false,\n error: 'Missing Stripe-Signature header',\n }\n }\n\n // Parse signature header\n const parsed = parseStripeSignature(signatureHeader)\n if (!parsed) {\n return {\n valid: false,\n error: 'Invalid Stripe-Signature header format',\n }\n }\n\n const { timestamp, signatures } = parsed\n\n // Validate timestamp\n if (!validateTimestamp(timestamp, this.tolerance)) {\n return {\n valid: false,\n error: `Timestamp outside tolerance window (${this.tolerance}s)`,\n }\n }\n\n // Compute expected signature\n const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf-8')\n const signedPayload = `${timestamp}.${payloadStr}`\n const expectedSignature = await computeHmacSha256(signedPayload, secret)\n\n // Check if any signature matches\n const signatureValid = signatures.some((sig) =>\n timingSafeEqual(sig.toLowerCase(), expectedSignature.toLowerCase())\n )\n\n if (!signatureValid) {\n return {\n valid: false,\n error: 'Signature verification failed',\n }\n }\n\n // Parse payload\n try {\n const event = JSON.parse(payloadStr)\n return {\n valid: true,\n payload: event,\n eventType: event.type,\n webhookId: event.id,\n }\n } catch {\n return {\n valid: false,\n error: 'Failed to parse webhook payload',\n }\n }\n }\n\n parseEventType(payload: unknown): string | undefined {\n if (typeof payload === 'object' && payload !== null && 'type' in payload) {\n return (payload as { type: string }).type\n }\n return undefined\n }\n\n private getHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n ): string | undefined {\n const value = headers[name] ?? headers[name.toLowerCase()]\n return Array.isArray(value) ? value[0] : value\n }\n}\n",
9
- "/**\n * @fileoverview Webhook Receiver\n *\n * Handles incoming webhooks with signature verification.\n *\n * @module @gravito/echo/receive\n */\n\nimport { GenericProvider } from '../providers/GenericProvider'\nimport { GitHubProvider } from '../providers/GitHubProvider'\nimport { StripeProvider } from '../providers/StripeProvider'\nimport type {\n WebhookEvent,\n WebhookHandler,\n WebhookProvider,\n WebhookVerificationResult,\n} from '../types'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ProviderClass = new (options?: any) => WebhookProvider\n\n/**\n * Webhook Receiver\n *\n * Manages webhook providers and routes incoming webhooks to handlers.\n *\n * @example\n * ```typescript\n * const receiver = new WebhookReceiver()\n *\n * // Register provider\n * receiver.registerProvider('stripe', process.env.STRIPE_WEBHOOK_SECRET!)\n *\n * // Register handler\n * receiver.on('stripe', 'payment_intent.succeeded', async (event) => {\n * console.log('Payment received:', event.payload)\n * })\n *\n * // Handle incoming webhook\n * const result = await receiver.handle('stripe', body, headers)\n * ```\n */\nexport class WebhookReceiver {\n private providers = new Map<string, { provider: WebhookProvider; secret: string }>()\n private handlers = new Map<string, Map<string, WebhookHandler[]>>()\n private globalHandlers = new Map<string, WebhookHandler[]>()\n\n constructor() {\n // Register built-in providers\n this.registerProviderType('generic', GenericProvider as ProviderClass)\n this.registerProviderType('stripe', StripeProvider as ProviderClass)\n this.registerProviderType('github', GitHubProvider as ProviderClass)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private providerTypes = new Map<string, ProviderClass>()\n\n /**\n * Register a custom provider type\n */\n registerProviderType(name: string, ProviderCls: ProviderClass): this {\n this.providerTypes.set(name, ProviderCls)\n return this\n }\n\n /**\n * Register a provider with its secret\n */\n registerProvider(\n name: string,\n secret: string,\n options?: { type?: string; tolerance?: number }\n ): this {\n const type = options?.type ?? name\n const ProviderClass = this.providerTypes.get(type)\n\n if (!ProviderClass) {\n throw new Error(`Unknown provider type: ${type}`)\n }\n\n const provider = new ProviderClass({ tolerance: options?.tolerance })\n this.providers.set(name, { provider, secret })\n return this\n }\n\n /**\n * Register an event handler\n */\n on<T = unknown>(providerName: string, eventType: string, handler: WebhookHandler<T>): this {\n if (!this.handlers.has(providerName)) {\n this.handlers.set(providerName, new Map())\n }\n\n const providerHandlers = this.handlers.get(providerName)!\n if (!providerHandlers.has(eventType)) {\n providerHandlers.set(eventType, [])\n }\n\n providerHandlers.get(eventType)?.push(handler as WebhookHandler)\n return this\n }\n\n /**\n * Register a handler for all events from a provider\n */\n onAll<T = unknown>(providerName: string, handler: WebhookHandler<T>): this {\n if (!this.globalHandlers.has(providerName)) {\n this.globalHandlers.set(providerName, [])\n }\n\n this.globalHandlers.get(providerName)?.push(handler as WebhookHandler)\n return this\n }\n\n /**\n * Handle an incoming webhook\n */\n async handle(\n providerName: string,\n body: string | Buffer,\n headers: Record<string, string | string[] | undefined>\n ): Promise<WebhookVerificationResult & { handled: boolean }> {\n const config = this.providers.get(providerName)\n if (!config) {\n return {\n valid: false,\n error: `Provider not registered: ${providerName}`,\n handled: false,\n }\n }\n\n const { provider, secret } = config\n\n // Verify webhook\n const result = await provider.verify(body, headers, secret)\n if (!result.valid) {\n return { ...result, handled: false }\n }\n\n // Create event object\n const event: WebhookEvent = {\n provider: providerName,\n type: result.eventType ?? 'unknown',\n payload: result.payload,\n headers,\n rawBody: typeof body === 'string' ? body : body.toString('utf-8'),\n receivedAt: new Date(),\n id: result.webhookId,\n }\n\n // Call handlers\n let handled = false\n\n // Call event-specific handlers\n const providerHandlers = this.handlers.get(providerName)\n if (providerHandlers) {\n const eventHandlers = providerHandlers.get(event.type)\n if (eventHandlers) {\n for (const handler of eventHandlers) {\n await handler(event)\n handled = true\n }\n }\n }\n\n // Call global handlers\n const globalHandlers = this.globalHandlers.get(providerName)\n if (globalHandlers) {\n for (const handler of globalHandlers) {\n await handler(event)\n handled = true\n }\n }\n\n return { ...result, handled }\n }\n\n /**\n * Verify a webhook without handling\n */\n async verify(\n providerName: string,\n body: string | Buffer,\n headers: Record<string, string | string[] | undefined>\n ): Promise<WebhookVerificationResult> {\n const config = this.providers.get(providerName)\n if (!config) {\n return {\n valid: false,\n error: `Provider not registered: ${providerName}`,\n }\n }\n\n return config.provider.verify(body, headers, config.secret)\n }\n}\n",
10
- "/**\n * @fileoverview Webhook Dispatcher\n *\n * Reliably sends webhooks to external services with retry support.\n *\n * @module @gravito/echo/send\n */\n\nimport { computeHmacSha256 } from '../receive/SignatureValidator'\nimport type {\n RetryConfig,\n WebhookDeliveryResult,\n WebhookDispatcherConfig,\n WebhookPayload,\n} from '../types'\n\n/**\n * Default retry configuration\n */\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxAttempts: 3,\n initialDelay: 1000,\n backoffMultiplier: 2,\n maxDelay: 300000, // 5 minutes\n retryableStatuses: [408, 429, 500, 502, 503, 504],\n}\n\n/**\n * Webhook Dispatcher\n *\n * Sends webhooks with signature and retry support.\n *\n * @example\n * ```typescript\n * const dispatcher = new WebhookDispatcher({\n * secret: 'my-webhook-secret',\n * retry: { maxAttempts: 5 }\n * })\n *\n * const result = await dispatcher.dispatch({\n * url: 'https://example.com/webhook',\n * event: 'order.created',\n * data: { orderId: 123 }\n * })\n * ```\n */\nexport class WebhookDispatcher {\n private secret: string\n private retryConfig: Required<RetryConfig>\n private timeout: number\n private userAgent: string\n\n constructor(config: WebhookDispatcherConfig) {\n this.secret = config.secret\n this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retry }\n this.timeout = config.timeout ?? 30000\n this.userAgent = config.userAgent ?? 'Gravito-Echo/1.0'\n }\n\n /**\n * Dispatch a webhook with retries\n */\n async dispatch<T = unknown>(payload: WebhookPayload<T>): Promise<WebhookDeliveryResult> {\n let lastResult: WebhookDeliveryResult | null = null\n\n for (let attempt = 1; attempt <= this.retryConfig.maxAttempts; attempt++) {\n const result = await this.attemptDelivery(payload, attempt)\n lastResult = result\n\n if (result.success) {\n return result\n }\n\n // Check if we should retry\n if (attempt < this.retryConfig.maxAttempts) {\n const shouldRetry = this.shouldRetry(result)\n if (shouldRetry) {\n const delay = this.calculateDelay(attempt)\n await this.sleep(delay)\n continue\n }\n }\n\n // Don't retry if status is not retryable\n return result\n }\n\n return lastResult!\n }\n\n /**\n * Attempt a single delivery\n */\n private async attemptDelivery<T = unknown>(\n payload: WebhookPayload<T>,\n attempt: number\n ): Promise<WebhookDeliveryResult> {\n const startTime = Date.now()\n const timestamp = Math.floor(Date.now() / 1000)\n const webhookId = payload.id ?? crypto.randomUUID()\n\n try {\n // Build request body\n const body = JSON.stringify({\n id: webhookId,\n type: payload.event,\n timestamp,\n data: payload.data,\n })\n\n // Compute signature\n const signedPayload = `${timestamp}.${body}`\n const signature = await computeHmacSha256(signedPayload, this.secret)\n\n // Create abort controller for timeout\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(payload.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': this.userAgent,\n 'X-Webhook-ID': webhookId,\n 'X-Webhook-Timestamp': String(timestamp),\n 'X-Webhook-Signature': `t=${timestamp},v1=${signature}`,\n },\n body,\n signal: controller.signal,\n })\n\n clearTimeout(timeoutId)\n\n const duration = Date.now() - startTime\n const responseBody = await response.text()\n\n return {\n success: response.ok,\n statusCode: response.status,\n body: responseBody,\n attempt,\n duration,\n deliveredAt: new Date(),\n error: response.ok ? undefined : `HTTP ${response.status}`,\n }\n } finally {\n clearTimeout(timeoutId)\n }\n } catch (error) {\n const duration = Date.now() - startTime\n\n return {\n success: false,\n attempt,\n duration,\n deliveredAt: new Date(),\n error: error instanceof Error ? error.message : 'Unknown error',\n }\n }\n }\n\n /**\n * Check if we should retry based on result\n */\n private shouldRetry(result: WebhookDeliveryResult): boolean {\n if (!result.statusCode) {\n // Network error, retry\n return true\n }\n\n return this.retryConfig.retryableStatuses.includes(result.statusCode)\n }\n\n /**\n * Calculate delay for exponential backoff\n */\n private calculateDelay(attempt: number): number {\n const delay =\n this.retryConfig.initialDelay * this.retryConfig.backoffMultiplier ** (attempt - 1)\n\n return Math.min(delay, this.retryConfig.maxDelay)\n }\n\n /**\n * Sleep helper\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n }\n}\n",
11
- "/**\n * @fileoverview OrbitEcho Module\n *\n * Gravito integration for webhook handling.\n *\n * @module @gravito/echo\n */\n\nimport { WebhookReceiver } from './receive/WebhookReceiver'\nimport { WebhookDispatcher } from './send/WebhookDispatcher'\nimport type { EchoConfig } from './types'\n\n/**\n * Simple module interface for PlanetCore integration\n */\ninterface ModuleConfig {\n singleton?: boolean\n}\n\n/**\n * Minimal ServiceProvider interface\n */\ninterface ServiceProvider {\n register?(): void | Promise<void>\n boot?(): void | Promise<void>\n}\n\n/**\n * Minimal PlanetCore interface\n */\ninterface PlanetCore {\n container: {\n instance<T>(key: string, value: T): void\n }\n hooks: {\n addAction(hook: string, callback: () => void | Promise<void>): void\n }\n adapter: {\n use(middleware: unknown): void\n }\n router: {\n post(path: string, handler: unknown): void\n }\n}\n\n/**\n * OrbitEcho - Gravito Webhook Module\n *\n * Provides secure webhook receiving and reliable webhook sending.\n *\n * @example\n * ```typescript\n * const core = new PlanetCore()\n *\n * core.install(new OrbitEcho({\n * providers: {\n * stripe: { name: 'stripe', secret: process.env.STRIPE_WEBHOOK_SECRET! },\n * github: { name: 'github', secret: process.env.GITHUB_WEBHOOK_SECRET! }\n * },\n * dispatcher: {\n * secret: process.env.OUTGOING_WEBHOOK_SECRET!\n * }\n * }))\n *\n * // Get receiver to add handlers\n * const receiver = core.container.make<WebhookReceiver>('echo.receiver')\n * receiver.on('stripe', 'payment_intent.succeeded', async (event) => {\n * console.log('Payment received:', event.payload)\n * })\n * ```\n */\nexport class OrbitEcho {\n static config: ModuleConfig = { singleton: true }\n\n private receiver: WebhookReceiver\n private dispatcher?: WebhookDispatcher\n private echoConfig: EchoConfig\n\n /**\n * Create a new OrbitEcho instance.\n *\n * @param config - The configuration object for providers and dispatcher.\n */\n constructor(config: EchoConfig = {}) {\n this.echoConfig = config\n this.receiver = new WebhookReceiver()\n\n // Register providers\n if (config.providers) {\n for (const [name, providerConfig] of Object.entries(config.providers)) {\n this.receiver.registerProvider(name, providerConfig.secret, {\n type: providerConfig.name,\n tolerance: providerConfig.tolerance,\n })\n }\n }\n\n // Create dispatcher\n if (config.dispatcher) {\n this.dispatcher = new WebhookDispatcher(config.dispatcher)\n }\n }\n\n /**\n * Install into PlanetCore\n *\n * Registers the OrbitEcho instance and its components into the service container.\n *\n * @param core - The PlanetCore instance.\n */\n install(core: PlanetCore): void {\n // Bind instances\n core.container.instance('echo', this)\n core.container.instance('echo.receiver', this.receiver)\n if (this.dispatcher) {\n core.container.instance('echo.dispatcher', this.dispatcher)\n }\n }\n\n /**\n * Get webhook receiver\n *\n * @returns The WebhookReceiver instance.\n */\n getReceiver(): WebhookReceiver {\n return this.receiver\n }\n\n /**\n * Get webhook dispatcher\n *\n * @returns The WebhookDispatcher instance, or undefined if not configured.\n */\n getDispatcher(): WebhookDispatcher | undefined {\n return this.dispatcher\n }\n\n /**\n * Get configuration\n *\n * @returns The EchoConfig object.\n */\n getConfig(): EchoConfig {\n return this.echoConfig\n }\n}\n"
5
+ "import type { DeadLetterEvent, DeadLetterQueue } from './DeadLetterQueue'\n\n/**\n * An in-memory implementation of {@link DeadLetterQueue}.\n * Suitable for development, testing, or small-scale applications where persistence is not required.\n *\n * @example\n * ```typescript\n * const dlq = new MemoryDeadLetterQueue();\n * await dlq.enqueue(failedEvent);\n * const size = await dlq.size();\n * ```\n */\nexport class MemoryDeadLetterQueue implements DeadLetterQueue {\n private queue = new Map<string, DeadLetterEvent>()\n\n /**\n * Stores the event in an internal Map.\n * Generates a UUID if the event does not have an ID.\n */\n async enqueue(event: DeadLetterEvent): Promise<string> {\n const id = event.id ?? crypto.randomUUID()\n this.queue.set(id, { ...event, id })\n return id\n }\n\n /**\n * Returns events sorted by failure timestamp.\n */\n async peek(limit = 10): Promise<DeadLetterEvent[]> {\n return Array.from(this.queue.values())\n .sort((a, b) => a.failedAt.getTime() - b.failedAt.getTime())\n .slice(0, limit)\n }\n\n /**\n * Removes the event from the internal Map.\n */\n async dequeue(id: string): Promise<void> {\n this.queue.delete(id)\n }\n\n /**\n * Returns the number of items in the internal Map.\n */\n async size(): Promise<number> {\n return this.queue.size\n }\n\n /**\n * Clears the internal Map.\n */\n async clear(): Promise<void> {\n this.queue.clear()\n }\n}\n",
6
+ "/**\n * Request Buffer Middleware\n *\n * 在驗證前緩存原始 Request Body,防止框架自動解析 JSON 導致簽章驗證失敗。\n * 這個中介軟體會在請求處理鏈的早期階段攔截並緩存原始內容。\n *\n * @module @gravito/echo/middleware\n * @since v1.1\n */\n\nimport type { GravitoContext } from '@gravito/core'\nimport type { BufferedRequest, RequestBufferConfig } from '../types'\n\n/**\n * 預設配置\n */\nconst DEFAULT_CONFIG: Required<RequestBufferConfig> = {\n enabled: true,\n maxBodySize: 10 * 1024 * 1024, // 10MB\n skipContentTypes: ['multipart/form-data', 'application/octet-stream'],\n}\n\n/**\n * Request Buffer 中介軟體類別\n *\n * 提供原始 Body 緩存功能,確保簽章驗證使用正確的未解析內容。\n *\n * @example\n * ```typescript\n * const middleware = new RequestBufferMiddleware({\n * maxBodySize: 5 * 1024 * 1024, // 5MB\n * })\n *\n * core.adapter.use('*', middleware.handler())\n * ```\n */\nexport class RequestBufferMiddleware {\n private config: Required<RequestBufferConfig>\n\n constructor(config: RequestBufferConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n }\n\n /**\n * 建立中介軟體處理函式\n *\n * @returns 中介軟體處理函式\n */\n handler() {\n return async (c: GravitoContext, next: () => Promise<Response | undefined>) => {\n if (!this.config.enabled) {\n return await next()\n }\n\n const contentType = c.req.header('content-type') ?? ''\n\n // 跳過排除的 content type\n if (this.config.skipContentTypes.some((type) => contentType.includes(type))) {\n return await next()\n }\n\n // 讀取原始 body\n const rawBody = await this.readRawBody(c)\n\n // 檢查大小限制\n const bodySize =\n typeof rawBody === 'string' ? Buffer.byteLength(rawBody, 'utf-8') : rawBody.length\n\n if (bodySize > this.config.maxBodySize) {\n return c.json({ error: 'Request body too large' }, 413)\n }\n\n // 儲存緩存的請求到 context\n const buffered: BufferedRequest = {\n rawBody,\n headers: c.req.header(),\n bufferedAt: new Date(),\n }\n\n c.set('bufferedRequest', buffered)\n\n return await next()\n }\n }\n\n /**\n * 從請求中讀取原始 body\n *\n * @param c - Gravito Context\n * @returns 原始 body(string 或 Buffer)\n */\n private async readRawBody(c: GravitoContext): Promise<string | Buffer> {\n // 檢查是否已被框架緩存\n const existing = c.get('bufferedRequest') as BufferedRequest | undefined\n if (existing) {\n return existing.rawBody\n }\n\n // 從請求流中讀取\n const body = await c.req.text()\n return body\n }\n}\n\n/**\n * 便捷工廠函式,用於建立 Request Buffer 中介軟體\n *\n * @param config - 中介軟體配置\n * @returns 中介軟體處理函式\n *\n * @example\n * ```typescript\n * core.adapter.use('*', createRequestBufferMiddleware({\n * maxBodySize: 5 * 1024 * 1024\n * }))\n * ```\n */\nexport function createRequestBufferMiddleware(config?: RequestBufferConfig) {\n return new RequestBufferMiddleware(config).handler()\n}\n\n// Module augmentation for GravitoVariables\ndeclare module '@gravito/core' {\n interface GravitoVariables {\n /** Buffered request for signature verification */\n bufferedRequest?: BufferedRequest\n }\n}\n",
7
+ "import type { EchoLogger } from './EchoLogger'\n\n/**\n * A basic implementation of {@link EchoLogger} that outputs logs to the system console.\n * Logs are formatted as JSON strings to facilitate integration with log aggregators.\n *\n * @example\n * ```typescript\n * const logger = new ConsoleEchoLogger();\n * logger.info('Service started');\n * ```\n */\nexport class ConsoleEchoLogger implements EchoLogger {\n /**\n * Enriches the log context with default module information and timestamps.\n *\n * @param base - The base context object.\n * @param extra - Additional metadata to include.\n * @returns A merged context object.\n */\n private formatContext(\n base: Record<string, unknown>,\n extra?: Record<string, unknown>\n ): Record<string, unknown> {\n return {\n module: 'echo',\n timestamp: new Date().toISOString(),\n ...base,\n ...extra,\n }\n }\n\n /**\n * Outputs a debug-level log entry.\n */\n debug(message: string, context?: Record<string, unknown>): void {\n console.debug(\n JSON.stringify({\n level: 'debug',\n message,\n ...this.formatContext({}, context),\n })\n )\n }\n\n /**\n * Outputs an info-level log entry.\n */\n info(message: string, context?: Record<string, unknown>): void {\n console.info(\n JSON.stringify({\n level: 'info',\n message,\n ...this.formatContext({}, context),\n })\n )\n }\n\n /**\n * Outputs a warn-level log entry.\n */\n warn(message: string, context?: Record<string, unknown>): void {\n console.warn(\n JSON.stringify({\n level: 'warn',\n message,\n ...this.formatContext({}, context),\n })\n )\n }\n\n /**\n * Outputs an error-level log entry.\n */\n error(message: string, context?: Record<string, unknown>): void {\n console.error(\n JSON.stringify({\n level: 'error',\n message,\n ...this.formatContext({}, context),\n })\n )\n }\n}\n",
8
+ "/**\n * Defines the interface for collecting application metrics.\n * Implementations can bridge to Prometheus, StatsD, or other monitoring systems.\n *\n * @example\n * ```typescript\n * const metrics: MetricsProvider = getMetrics();\n * metrics.increment(EchoMetrics.INCOMING_TOTAL, { provider: 'stripe' });\n * ```\n */\nexport interface MetricsProvider {\n /**\n * Increments a counter by 1.\n * Counters are used for values that only increase (e.g., total requests).\n */\n increment(name: string, labels?: Record<string, string>): void\n\n /**\n * Records a value in a histogram.\n * Histograms are used to track the distribution of values (e.g., request latency).\n */\n histogram(name: string, value: number, labels?: Record<string, string>): void\n\n /**\n * Sets a gauge to a specific value.\n * Gauges are used for values that can go up and down (e.g., current queue size).\n */\n gauge(name: string, value: number, labels?: Record<string, string>): void\n}\n\n/**\n * Common labels used for webhook-related metrics.\n */\nexport interface WebhookMetricLabels {\n /** The webhook provider name (e.g., 'stripe', 'github'). */\n provider?: string\n /** The type of event received or sent. */\n event_type?: string\n /** The outcome of the operation. */\n status?: 'success' | 'failure'\n /** The HTTP status code returned by the remote server. */\n status_code?: string\n /** A category for the error if the operation failed. */\n error_type?: string\n [key: string]: string | undefined\n}\n\n/**\n * Standard metric names used across the Echo module.\n * Use these constants to ensure consistency in dashboards and alerts.\n */\nexport const EchoMetrics = {\n /** Total number of incoming webhooks received. */\n INCOMING_TOTAL: 'echo_incoming_webhooks_total',\n /** Time taken to process an incoming webhook. */\n INCOMING_DURATION: 'echo_incoming_duration_seconds',\n /** Total number of incoming webhooks that failed signature verification. */\n INCOMING_VERIFICATION_FAILURES: 'echo_incoming_verification_failures_total',\n\n /** Total number of outgoing webhooks dispatched. */\n OUTGOING_TOTAL: 'echo_outgoing_webhooks_total',\n /** Time taken to deliver an outgoing webhook. */\n OUTGOING_DURATION: 'echo_outgoing_duration_seconds',\n /** Total number of retry attempts for outgoing webhooks. */\n OUTGOING_RETRIES: 'echo_outgoing_retries_total',\n /** Total number of outgoing webhooks that failed after all retries. */\n OUTGOING_FAILURES: 'echo_outgoing_failures_total',\n\n /** Current number of items in the Dead Letter Queue. */\n DLQ_SIZE: 'echo_dlq_size',\n /** Total number of items added to the DLQ. */\n DLQ_ENQUEUED: 'echo_dlq_enqueued_total',\n /** Total number of items successfully processed from the DLQ. */\n DLQ_PROCESSED: 'echo_dlq_processed_total',\n} as const\n",
9
+ "import type { MetricsProvider } from './MetricsProvider'\n\n/**\n * A non-operational implementation of {@link MetricsProvider}.\n * Used as the default provider to ensure the application remains functional\n * even if no monitoring system is configured.\n *\n * @example\n * ```typescript\n * const metrics = new NoopMetricsProvider();\n * metrics.increment('any_metric'); // Does nothing\n * ```\n */\nexport class NoopMetricsProvider implements MetricsProvider {\n increment(): void {\n // No-op\n }\n histogram(): void {\n // No-op\n }\n gauge(): void {\n // No-op\n }\n}\n",
10
+ "import type { MetricsProvider } from './MetricsProvider'\n\n/**\n * A Prometheus-compatible metrics provider.\n * Collects and formats metrics in the Prometheus text-based format.\n *\n * @example\n * ```typescript\n * const provider = new PrometheusMetricsProvider();\n * provider.increment('http_requests_total', { method: 'POST' });\n * console.log(provider.export());\n * ```\n */\nexport class PrometheusMetricsProvider implements MetricsProvider {\n private counters = new Map<string, Map<string, number>>()\n private histograms = new Map<string, number[]>()\n private gauges = new Map<string, number>()\n\n /**\n * Increments a counter for the given name and labels.\n */\n increment(name: string, labels: Record<string, string> = {}): void {\n const key = this.buildKey(name, labels)\n const counterMap = this.counters.get(name) ?? new Map()\n counterMap.set(key, (counterMap.get(key) ?? 0) + 1)\n this.counters.set(name, counterMap)\n }\n\n /**\n * Records a value in a histogram for the given name and labels.\n */\n histogram(name: string, value: number, labels: Record<string, string> = {}): void {\n const key = this.buildKey(name, labels)\n const values = this.histograms.get(key) ?? []\n values.push(value)\n this.histograms.set(key, values)\n }\n\n /**\n * Sets a gauge to a specific value for the given name and labels.\n */\n gauge(name: string, value: number, labels: Record<string, string> = {}): void {\n const key = this.buildKey(name, labels)\n this.gauges.set(key, value)\n }\n\n /**\n * Exports all collected metrics in Prometheus text format.\n *\n * @returns A string containing the formatted metrics.\n */\n export(): string {\n const lines: string[] = []\n\n // Export counters\n for (const [name, counterMap] of this.counters) {\n lines.push(`# TYPE ${name} counter`)\n for (const [key, value] of counterMap) {\n lines.push(`${key} ${value}`)\n }\n }\n\n // Export Gauges\n for (const [key, value] of this.gauges) {\n lines.push(`${key} ${value}`)\n }\n\n return lines.join('\\n')\n }\n\n /**\n * Builds a Prometheus-compatible metric key with labels.\n */\n private buildKey(name: string, labels: Record<string, string>): string {\n if (Object.keys(labels).length === 0) {\n return name\n }\n const labelStr = Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',')\n return `${name}{${labelStr}}`\n }\n}\n",
11
+ "import type { Span, Tracer } from './Tracer'\n\n/**\n * A non-operational implementation of {@link Span}.\n * Used as a fallback when tracing is disabled to avoid null checks.\n */\nexport class NoopSpan implements Span {\n setAttribute(): this {\n return this\n }\n setAttributes(): this {\n return this\n }\n addEvent(): this {\n return this\n }\n setStatus(): this {\n return this\n }\n end(): void {\n // No-op\n }\n}\n\n/**\n * A non-operational implementation of {@link Tracer}.\n * Ensures the application can run without a tracing backend.\n *\n * @example\n * ```typescript\n * const tracer = new NoopTracer();\n * const span = tracer.startSpan('test');\n * span.end();\n * ```\n */\nexport class NoopTracer implements Tracer {\n /**\n * Returns a {@link NoopSpan} that does nothing.\n */\n startSpan(): Span {\n return new NoopSpan()\n }\n\n /**\n * Executes the function with a {@link NoopSpan}.\n */\n async withSpan<T>(_name: string, fn: (span: Span) => T | Promise<T>): Promise<T> {\n return fn(new NoopSpan())\n }\n}\n",
12
+ "/**\n * Represents a single unit of work in a trace.\n * Compatible with OpenTelemetry Span interface to allow seamless integration.\n */\nexport interface Span {\n /**\n * Sets a single attribute on the span.\n * Attributes provide additional metadata for the operation.\n */\n setAttribute(key: string, value: string | number | boolean): this\n /**\n * Sets multiple attributes on the span at once.\n */\n setAttributes(attributes: Record<string, string | number | boolean>): this\n /**\n * Records a specific event that occurred during the span's lifetime.\n */\n addEvent(name: string, attributes?: Record<string, string | number>): this\n /**\n * Sets the final status of the span.\n */\n setStatus(status: { code: SpanStatusCode; message?: string }): this\n /**\n * Marks the end of the span, making it ready for export.\n */\n end(): void\n}\n\n/**\n * Standard status codes for a {@link Span}.\n */\nexport enum SpanStatusCode {\n /** Default status. */\n UNSET = 0,\n /** Operation completed successfully. */\n OK = 1,\n /** Operation failed. */\n ERROR = 2,\n}\n\n/**\n * Defines the tracing interface for the Echo module.\n * Used to track the lifecycle of webhook requests and deliveries.\n *\n * @example\n * ```typescript\n * const tracer: Tracer = getTracer();\n * await tracer.withSpan('process-webhook', async (span) => {\n * span.setAttribute('provider', 'stripe');\n * // ... logic\n * });\n * ```\n */\nexport interface Tracer {\n /**\n * Starts a new span without making it active.\n * The caller is responsible for ending the span.\n */\n startSpan(name: string, options?: SpanOptions): Span\n /**\n * Executes a function within the context of a new span.\n * Automatically ends the span when the function completes.\n */\n withSpan<T>(name: string, fn: (span: Span) => T | Promise<T>): Promise<T>\n}\n\n/**\n * Configuration options for starting a new {@link Span}.\n */\nexport interface SpanOptions {\n /** The relationship between the span and its neighbors. */\n kind?: 'client' | 'server' | 'producer' | 'consumer' | 'internal'\n /** Initial attributes to set on the span. */\n attributes?: Record<string, string | number | boolean>\n}\n",
13
+ "/**\n * @fileoverview Signature validation utilities\n *\n * Provides HMAC-based signature verification for webhook payloads.\n *\n * @module @gravito/echo/receive\n */\n\n/**\n * Compute HMAC-SHA256 signature\n */\nexport async function computeHmacSha256(payload: string | Buffer, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('hex')\n}\n\n/**\n * Computes an HMAC-SHA256 signature and returns it as a base64 encoded string.\n *\n * Used by providers that require base64 encoding for their signatures (e.g., Shopify).\n *\n * @param payload - The raw data to sign.\n * @param secret - The shared secret key.\n * @returns The base64 encoded HMAC-SHA256 signature.\n * @throws Error if the crypto operations fail.\n *\n * @example\n * ```typescript\n * const sig = await computeHmacSha256Base64('data', 'secret');\n * ```\n */\nexport async function computeHmacSha256Base64(\n payload: string | Buffer,\n secret: string\n): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('base64')\n}\n\n/**\n * Compute HMAC-SHA1 signature (for legacy providers)\n */\nexport async function computeHmacSha1(payload: string | Buffer, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-1' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('hex')\n}\n\n/**\n * Computes an HMAC-SHA1 signature and returns it as a base64 encoded string.\n *\n * Primarily used for legacy services or specific providers like Twilio that\n * still rely on SHA1-based HMAC for their webhook verification.\n *\n * @param payload - The raw data to sign.\n * @param secret - The shared secret key.\n * @returns The base64 encoded HMAC-SHA1 signature.\n * @throws Error if the crypto operations fail.\n *\n * @example\n * ```typescript\n * const sig = await computeHmacSha1Base64('data', 'secret');\n * ```\n */\nexport async function computeHmacSha1Base64(\n payload: string | Buffer,\n secret: string\n): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-1' },\n false,\n ['sign']\n )\n\n const payloadBuffer =\n typeof payload === 'string'\n ? new TextEncoder().encode(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength)\n\n const signature = await crypto.subtle.sign('HMAC', key, payloadBuffer as BufferSource)\n return Buffer.from(signature).toString('base64')\n}\n\n/**\n * Timing-safe string comparison to prevent timing attacks\n */\nexport function timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n const aBytes = new TextEncoder().encode(a)\n const bBytes = new TextEncoder().encode(b)\n\n let result = 0\n for (let i = 0; i < aBytes.length; i++) {\n result |= (aBytes[i] ?? 0) ^ (bBytes[i] ?? 0)\n }\n\n return result === 0\n}\n\n/**\n * Validate timestamp is within tolerance\n *\n * @param timestamp - Unix timestamp in seconds\n * @param tolerance - Tolerance in seconds (default: 300 = 5 minutes)\n */\nexport function validateTimestamp(timestamp: number, tolerance = 300): boolean {\n const now = Math.floor(Date.now() / 1000)\n return Math.abs(now - timestamp) <= tolerance\n}\n\n/**\n * Parse Stripe-style signature header\n * Format: t=timestamp,v1=signature,v1=signature2\n */\nexport function parseStripeSignature(\n header: string\n): { timestamp: number; signatures: string[] } | null {\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 if (key === 't' && value !== undefined) {\n timestamp = parseInt(value, 10)\n } else if (key === 'v1' && value !== undefined) {\n signatures.push(value)\n }\n }\n\n if (timestamp === undefined || signatures.length === 0) {\n return null\n }\n\n return { timestamp, signatures }\n}\n",
14
+ "/**\n * Utilities for handling webhook headers.\n * @module @gravito/echo/providers/base\n */\n\n/**\n * Retrieves a header value from a headers object.\n * Supports case-insensitive lookup by checking the original name and its lowercase version.\n *\n * @param headers - The headers object from the request.\n * @param name - The name of the header to retrieve.\n * @returns The first value of the header if found, otherwise undefined.\n *\n * @example\n * ```typescript\n * const sig = getHeader(headers, 'X-Webhook-Signature');\n * ```\n */\nexport function getHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | undefined {\n const value = headers[name] ?? headers[name.toLowerCase()]\n return Array.isArray(value) ? value[0] : value\n}\n\n/**\n * Retrieves multiple header values at once.\n *\n * @param headers - The headers object from the request.\n * @param names - An array of header names to retrieve.\n * @returns A record mapping each requested name to its value or undefined.\n */\nexport function getHeaders(\n headers: Record<string, string | string[] | undefined>,\n names: string[]\n): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {}\n for (const name of names) {\n result[name] = getHeader(headers, name)\n }\n return result\n}\n\n/**\n * Checks if a specific header exists in the headers object.\n *\n * @param headers - The headers object from the request.\n * @param name - The name of the header to check.\n * @returns True if the header exists and is not undefined.\n */\nexport function hasHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): boolean {\n return getHeader(headers, name) !== undefined\n}\n",
15
+ "/**\n * Abstract base class for webhook providers.\n * @module @gravito/echo/providers/base\n */\n\nimport type { WebhookProvider, WebhookVerificationResult } from '../../types'\nimport { getHeader, hasHeader } from './HeaderUtils'\n\n/**\n * Configuration options for webhook providers.\n */\nexport interface ProviderOptions {\n /**\n * Maximum allowed age of the webhook request in seconds to prevent replay attacks.\n * @defaultValue 300\n */\n tolerance?: number\n}\n\n/**\n * Base implementation for all webhook providers.\n * Handles common header extraction, payload conversion, and result formatting.\n *\n * @example\n * ```typescript\n * class MyProvider extends BaseProvider {\n * readonly name = 'my-provider';\n * async verify(payload, headers, secret) {\n * // Implementation logic\n * return this.createSuccess(JSON.parse(payload));\n * }\n * }\n * ```\n */\nexport abstract class BaseProvider implements WebhookProvider {\n /** Unique identifier for the provider. */\n abstract readonly name: string\n\n /** Time tolerance for timestamp validation. */\n protected tolerance: number\n\n constructor(options: ProviderOptions = {}) {\n this.tolerance = options.tolerance ?? 300\n }\n\n /**\n * Verifies the authenticity of a webhook request.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Provider-specific secret key.\n * @returns Verification result containing the parsed payload or error message.\n * @throws Error if verification logic encounters an unrecoverable failure.\n */\n abstract verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult>\n\n /**\n * Extracts the event type from the verified payload.\n *\n * @param payload - The parsed webhook payload.\n * @returns The event type string if found.\n */\n parseEventType?(payload: unknown): string | undefined\n\n // ─────────────────────────────────────────────\n // Protected Helpers\n // ─────────────────────────────────────────────\n\n /**\n * Retrieves a header value in a case-insensitive manner.\n */\n protected getHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n ): string | undefined {\n return getHeader(headers, name)\n }\n\n /**\n * Checks if a specific header exists.\n */\n protected hasHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n ): boolean {\n return hasHeader(headers, name)\n }\n\n /**\n * Creates a failed verification result.\n */\n protected createFailure(error: string): WebhookVerificationResult {\n return { valid: false, error }\n }\n\n /**\n * Creates a successful verification result.\n */\n protected createSuccess(\n payload: unknown,\n options: { eventType?: string; webhookId?: string } = {}\n ): WebhookVerificationResult {\n return {\n valid: true,\n payload,\n eventType: options.eventType,\n webhookId: options.webhookId,\n }\n }\n\n /**\n * Ensures the payload is a string.\n */\n protected payloadToString(payload: string | Buffer): string {\n return typeof payload === 'string' ? payload : payload.toString('utf-8')\n }\n\n /**\n * Safely parses a JSON string without throwing.\n */\n protected safeParseJson(\n str: string\n ): { success: true; data: unknown } | { success: false; error: string } {\n try {\n return { success: true, data: JSON.parse(str) }\n } catch {\n return { success: false, error: 'Failed to parse webhook payload' }\n }\n }\n}\n",
16
+ "/**\n * Generic webhook provider.\n * @module @gravito/echo/providers\n */\n\nimport {\n computeHmacSha256,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider, type ProviderOptions } from './base/BaseProvider'\n\n/**\n * Configuration options for the generic provider.\n */\nexport interface GenericProviderOptions extends ProviderOptions {\n /**\n * Custom header name for the signature.\n * @defaultValue 'x-webhook-signature'\n */\n signatureHeader?: string\n /**\n * Custom header name for the timestamp.\n * @defaultValue 'x-webhook-timestamp'\n */\n timestampHeader?: string\n}\n\n/**\n * Generic webhook provider using HMAC-SHA256 for signature verification.\n *\n * Expected headers:\n * - X-Webhook-Signature: HMAC-SHA256 hex signature.\n * - X-Webhook-Timestamp: Unix timestamp (optional, used for replay protection).\n *\n * @example\n * ```typescript\n * const provider = new GenericProvider({\n * signatureHeader: 'X-Custom-Sig',\n * tolerance: 600\n * });\n * const result = await provider.verify(body, headers, secret);\n * ```\n */\nexport class GenericProvider extends BaseProvider {\n readonly name = 'generic'\n\n private signatureHeader: string\n private timestampHeader: string\n\n constructor(options: GenericProviderOptions = {}) {\n super(options)\n this.signatureHeader = options.signatureHeader ?? 'x-webhook-signature'\n this.timestampHeader = options.timestampHeader ?? 'x-webhook-timestamp'\n }\n\n /**\n * Verifies the webhook using HMAC-SHA256.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Secret key for HMAC computation.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, this.signatureHeader)\n if (!signature) {\n return this.createFailure(`Missing signature header: ${this.signatureHeader}`)\n }\n\n const timestampStr = this.getHeader(headers, this.timestampHeader)\n if (timestampStr) {\n const timestamp = parseInt(timestampStr, 10)\n if (Number.isNaN(timestamp) || !validateTimestamp(timestamp, this.tolerance)) {\n return this.createFailure('Timestamp validation failed')\n }\n }\n\n const payloadStr = this.payloadToString(payload)\n const expectedSignature = await computeHmacSha256(payloadStr, secret)\n\n if (!timingSafeEqual(signature.toLowerCase(), expectedSignature.toLowerCase())) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createSuccess(payloadStr)\n }\n\n const parsed = parseResult.data as Record<string, unknown>\n return this.createSuccess(parsed, {\n eventType: (parsed.type ?? parsed.event ?? parsed.eventType) as string | undefined,\n webhookId: (parsed.id ?? parsed.webhookId) as string | undefined,\n })\n }\n}\n",
17
+ "/**\n * GitHub webhook provider.\n * @module @gravito/echo/providers\n */\n\nimport { computeHmacSha256, timingSafeEqual } from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * GitHub webhook provider.\n *\n * Verifies GitHub webhook signatures using the `X-Hub-Signature-256` header.\n * @see {@link https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries | GitHub Webhook Validation}\n *\n * @example\n * ```typescript\n * const provider = new GitHubProvider();\n * const result = await provider.verify(body, headers, process.env.GITHUB_WEBHOOK_SECRET);\n * ```\n */\nexport class GitHubProvider extends BaseProvider {\n readonly name = 'github'\n\n /**\n * Verifies the GitHub webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - GitHub webhook secret.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, 'x-hub-signature-256')\n if (!signature) {\n return this.createFailure('Missing X-Hub-Signature-256 header')\n }\n\n if (!signature.startsWith('sha256=')) {\n return this.createFailure('Invalid signature format (expected sha256=...)')\n }\n\n const signatureValue = signature.slice(7)\n\n const payloadStr = this.payloadToString(payload)\n const expectedSignature = await computeHmacSha256(payloadStr, secret)\n\n if (!timingSafeEqual(signatureValue.toLowerCase(), expectedSignature.toLowerCase())) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure('Failed to parse webhook payload')\n }\n\n const event = parseResult.data as Record<string, unknown>\n const eventType = this.getHeader(headers, 'x-github-event')\n const deliveryId = this.getHeader(headers, 'x-github-delivery')\n\n return this.createSuccess(event, {\n eventType: eventType ?? undefined,\n webhookId: deliveryId ?? undefined,\n })\n }\n\n /**\n * Extracts the action from the GitHub payload if available.\n */\n override parseEventType(payload: unknown): string | undefined {\n if (typeof payload === 'object' && payload !== null && 'action' in payload) {\n return (payload as { action: string }).action\n }\n return undefined\n }\n}\n",
18
+ "import { computeHmacSha256, timingSafeEqual } from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * Linear webhook provider.\n *\n * Verifies Linear webhook signatures using the `Linear-Signature` header.\n * @see {@link https://developers.linear.app/docs/graphql/webhooks#signature-verification | Linear Webhook Verification}\n *\n * @example\n * ```typescript\n * const provider = new LinearProvider();\n * const result = await provider.verify(body, headers, process.env.LINEAR_WEBHOOK_SECRET);\n * ```\n */\nexport class LinearProvider extends BaseProvider {\n readonly name = 'linear'\n\n /**\n * Verifies the Linear webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Linear webhook secret.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, 'linear-signature')\n if (!signature) {\n return this.createFailure('Missing Linear-Signature header')\n }\n\n const payloadStr = this.payloadToString(payload)\n const expectedSignature = await computeHmacSha256(payloadStr, secret)\n\n if (!timingSafeEqual(signature, expectedSignature)) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure(parseResult.error)\n }\n\n const data = parseResult.data as Record<string, unknown>\n return this.createSuccess(data, {\n eventType: (data.type ?? data.action) as string | undefined,\n webhookId: this.getHeader(headers, 'linear-delivery'),\n })\n }\n}\n",
19
+ "import {\n computeHmacSha256,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * Paddle webhook provider.\n *\n * Verifies Paddle webhook signatures using the `Paddle-Signature` header.\n * @see {@link https://developer.paddle.com/webhooks/signature-verification | Paddle Signature Verification}\n *\n * @example\n * ```typescript\n * const provider = new PaddleProvider();\n * const result = await provider.verify(body, headers, process.env.PADDLE_WEBHOOK_SECRET);\n * ```\n */\nexport class PaddleProvider extends BaseProvider {\n readonly name = 'paddle'\n\n /**\n * Verifies the Paddle webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Paddle webhook secret.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signatureHeader = this.getHeader(headers, 'paddle-signature')\n if (!signatureHeader) {\n return this.createFailure('Missing Paddle-Signature header')\n }\n\n const parsed = this.parsePaddleSignature(signatureHeader)\n if (!parsed) {\n return this.createFailure('Invalid Paddle-Signature format')\n }\n\n const { timestamp, signature } = parsed\n\n if (!validateTimestamp(timestamp, this.tolerance)) {\n return this.createFailure(`Timestamp outside tolerance window (${this.tolerance}s)`)\n }\n\n const payloadStr = this.payloadToString(payload)\n const signedPayload = `${timestamp}:${payloadStr}`\n const expectedSignature = await computeHmacSha256(signedPayload, secret)\n\n if (!timingSafeEqual(signature, expectedSignature)) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure(parseResult.error)\n }\n\n const data = parseResult.data as Record<string, unknown>\n return this.createSuccess(data, {\n eventType: data.event_type as string | undefined,\n webhookId: data.event_id as string | undefined,\n })\n }\n\n /**\n * Parses the Paddle-Signature header into timestamp and signature components.\n */\n private parsePaddleSignature(header: string): { timestamp: number; signature: string } | null {\n const parts = header.split(';')\n let timestamp: number | undefined\n let signature: string | undefined\n\n for (const part of parts) {\n const [key, value] = part.split('=')\n if (key === 'ts' && value) {\n timestamp = parseInt(value, 10)\n } else if (key === 'h1' && value) {\n signature = value\n }\n }\n\n if (timestamp === undefined || !signature) {\n return null\n }\n\n return { timestamp, signature }\n }\n}\n",
20
+ "import { computeHmacSha256Base64, timingSafeEqual } from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * Shopify webhook provider.\n *\n * Verifies Shopify webhook signatures using the `X-Shopify-Hmac-Sha256` header.\n * @see {@link https://shopify.dev/docs/apps/webhooks/configuration/https#verify-webhook | Shopify Webhook Verification}\n *\n * @example\n * ```typescript\n * const provider = new ShopifyProvider();\n * const result = await provider.verify(body, headers, process.env.SHOPIFY_WEBHOOK_SECRET);\n * ```\n */\nexport class ShopifyProvider extends BaseProvider {\n readonly name = 'shopify'\n\n /**\n * Verifies the Shopify webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Shopify webhook secret.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, 'x-shopify-hmac-sha256')\n if (!signature) {\n return this.createFailure('Missing X-Shopify-Hmac-Sha256 header')\n }\n\n const payloadStr = this.payloadToString(payload)\n const expectedSignature = await computeHmacSha256Base64(payloadStr, secret)\n\n if (!timingSafeEqual(signature, expectedSignature)) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure(parseResult.error)\n }\n\n return this.createSuccess(parseResult.data, {\n eventType: this.getHeader(headers, 'x-shopify-topic'),\n webhookId: this.getHeader(headers, 'x-shopify-webhook-id'),\n })\n }\n}\n",
21
+ "import {\n computeHmacSha256,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * Slack webhook provider.\n *\n * Verifies Slack webhook signatures using the `X-Slack-Signature` and `X-Slack-Request-Timestamp` headers.\n * @see {@link https://api.slack.com/authentication/verifying-requests-from-slack | Slack Request Verification}\n *\n * @example\n * ```typescript\n * const provider = new SlackProvider();\n * const result = await provider.verify(body, headers, process.env.SLACK_SIGNING_SECRET);\n * ```\n */\nexport class SlackProvider extends BaseProvider {\n readonly name = 'slack'\n\n /**\n * Verifies the Slack webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Slack signing secret.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, 'x-slack-signature')\n const timestampStr = this.getHeader(headers, 'x-slack-request-timestamp')\n\n if (!signature) {\n return this.createFailure('Missing X-Slack-Signature header')\n }\n if (!timestampStr) {\n return this.createFailure('Missing X-Slack-Request-Timestamp header')\n }\n\n if (!signature.startsWith('v0=')) {\n return this.createFailure('Invalid signature format (expected v0=...)')\n }\n\n const timestamp = parseInt(timestampStr, 10)\n if (!validateTimestamp(timestamp, this.tolerance)) {\n return this.createFailure(`Timestamp outside tolerance window (${this.tolerance}s)`)\n }\n\n const payloadStr = this.payloadToString(payload)\n const sigBasestring = `v0:${timestamp}:${payloadStr}`\n const expectedSignature = await computeHmacSha256(sigBasestring, secret)\n\n if (!timingSafeEqual(signature.slice(3), expectedSignature)) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure(parseResult.error)\n }\n\n const data = parseResult.data as Record<string, unknown>\n return this.createSuccess(data, {\n eventType: data.type as string | undefined,\n webhookId: data.event_id as string | undefined,\n })\n }\n}\n",
22
+ "/**\n * Stripe webhook provider.\n * @module @gravito/echo/providers\n */\n\nimport {\n computeHmacSha256,\n parseStripeSignature,\n timingSafeEqual,\n validateTimestamp,\n} from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider } from './base/BaseProvider'\n\n/**\n * Stripe webhook provider.\n *\n * Verifies Stripe webhook signatures using their standard format.\n * @see {@link https://stripe.com/docs/webhooks/signatures | Stripe Webhook Signatures}\n *\n * @example\n * ```typescript\n * const provider = new StripeProvider();\n * const result = await provider.verify(body, headers, process.env.STRIPE_WEBHOOK_SECRET);\n * ```\n */\nexport class StripeProvider extends BaseProvider {\n readonly name = 'stripe'\n\n constructor(options: { tolerance?: number } = {}) {\n super(options)\n }\n\n /**\n * Verifies the Stripe webhook signature.\n *\n * @param payload - Raw request body.\n * @param headers - Request headers.\n * @param secret - Stripe webhook secret (signing secret).\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signatureHeader = this.getHeader(headers, 'stripe-signature')\n if (!signatureHeader) {\n return this.createFailure('Missing Stripe-Signature header')\n }\n\n const parsed = parseStripeSignature(signatureHeader)\n if (!parsed) {\n return this.createFailure('Invalid Stripe-Signature header format')\n }\n\n const { timestamp, signatures } = parsed\n\n if (!validateTimestamp(timestamp, this.tolerance)) {\n return this.createFailure(`Timestamp outside tolerance window (${this.tolerance}s)`)\n }\n\n const payloadStr = this.payloadToString(payload)\n const signedPayload = `${timestamp}.${payloadStr}`\n const expectedSignature = await computeHmacSha256(signedPayload, secret)\n\n const signatureValid = signatures.some((sig) =>\n timingSafeEqual(sig.toLowerCase(), expectedSignature.toLowerCase())\n )\n\n if (!signatureValid) {\n return this.createFailure('Signature verification failed')\n }\n\n const parseResult = this.safeParseJson(payloadStr)\n if (!parseResult.success) {\n return this.createFailure('Failed to parse webhook payload')\n }\n\n const event = parseResult.data as Record<string, unknown>\n return this.createSuccess(event, {\n eventType: event.type as string | undefined,\n webhookId: event.id as string | undefined,\n })\n }\n\n /**\n * Extracts the event type from the Stripe payload.\n */\n override parseEventType(payload: unknown): string | undefined {\n if (typeof payload === 'object' && payload !== null && 'type' in payload) {\n return (payload as { type: string }).type\n }\n return undefined\n }\n}\n",
23
+ "import { computeHmacSha1Base64, timingSafeEqual } from '../receive/SignatureValidator'\nimport type { WebhookVerificationResult } from '../types'\nimport { BaseProvider, type ProviderOptions } from './base/BaseProvider'\n\n/**\n * Twilio webhook provider.\n *\n * Verifies Twilio webhook signatures using the `X-Twilio-Signature` header.\n * @see {@link https://www.twilio.com/docs/usage/security#validating-requests | Twilio Request Validation}\n *\n * @example\n * ```typescript\n * const provider = new TwilioProvider({ baseUrl: 'https://api.example.com/webhooks/twilio' });\n * const result = await provider.verify(body, headers, process.env.TWILIO_AUTH_TOKEN);\n * ```\n */\nexport class TwilioProvider extends BaseProvider {\n readonly name = 'twilio'\n\n private baseUrl?: string\n\n constructor(options: ProviderOptions & { baseUrl?: string } = {}) {\n super(options)\n this.baseUrl = options.baseUrl\n }\n\n /**\n * Verifies the Twilio webhook signature.\n *\n * @param payload - Raw request body (URL-encoded).\n * @param headers - Request headers.\n * @param secret - Twilio Auth Token.\n * @returns Verification result.\n * @throws Error if signature computation fails.\n */\n async verify(\n payload: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n secret: string\n ): Promise<WebhookVerificationResult> {\n const signature = this.getHeader(headers, 'x-twilio-signature')\n if (!signature) {\n return this.createFailure('Missing X-Twilio-Signature header')\n }\n\n const url = this.baseUrl ?? ''\n const payloadStr = this.payloadToString(payload)\n\n const params = new URLSearchParams(payloadStr)\n const sortedParams = Array.from(params.entries())\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => `${key}${value}`)\n .join('')\n\n const signaturePayload = url + sortedParams\n const expectedSignature = await computeHmacSha1Base64(signaturePayload, secret)\n\n if (!timingSafeEqual(signature, expectedSignature)) {\n return this.createFailure('Signature verification failed')\n }\n\n return this.createSuccess(Object.fromEntries(params), {\n eventType: params.get('EventType') ?? undefined,\n })\n }\n}\n",
24
+ "/**\n * @fileoverview Webhook Receiver\n *\n * Handles incoming webhooks with signature verification.\n *\n * @module @gravito/echo/receive\n */\n\nimport type { GravitoContext } from '@gravito/core'\nimport { ConsoleEchoLogger, type EchoLogger } from '../observability/logging'\nimport {\n EchoMetrics,\n type MetricsProvider,\n NoopMetricsProvider,\n type WebhookMetricLabels,\n} from '../observability/metrics'\nimport { NoopTracer, SpanStatusCode, type Tracer } from '../observability/tracing'\nimport { GenericProvider } from '../providers/GenericProvider'\nimport { GitHubProvider } from '../providers/GitHubProvider'\nimport { LinearProvider } from '../providers/LinearProvider'\nimport { PaddleProvider } from '../providers/PaddleProvider'\nimport { ShopifyProvider } from '../providers/ShopifyProvider'\nimport { SlackProvider } from '../providers/SlackProvider'\nimport { StripeProvider } from '../providers/StripeProvider'\nimport { TwilioProvider } from '../providers/TwilioProvider'\nimport type { KeyRotationManager } from '../rotation/KeyRotationManager'\nimport type { WebhookStore } from '../storage/WebhookStore'\nimport type {\n BufferedRequest,\n ProviderKeyEntry,\n WebhookEvent,\n WebhookHandler,\n WebhookProvider,\n WebhookVerificationResult,\n} from '../types'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ProviderClass = new (options?: Record<string, unknown>) => WebhookProvider\n\n/**\n * WebhookReceiver orchestrates the end-to-end lifecycle of incoming webhooks.\n *\n * It acts as the central intake for all incoming requests, managing provider-specific\n * verification logic, multi-key rotation checks, persistent storage for auditing,\n * and routing validated events to their respective application-level handlers.\n *\n * @example Basic usage with Stripe\n * ```typescript\n * const receiver = new WebhookReceiver();\n *\n * // Register Stripe with its signing secret\n * receiver.registerProvider('stripe', 'whsec_...');\n *\n * // Listen for payment success events\n * receiver.on('stripe', 'payment_intent.succeeded', async (event) => {\n * const payment = event.payload;\n * await processPayment(payment.id);\n * });\n * ```\n *\n * @public\n */\nexport class WebhookReceiver {\n private providers = new Map<string, { provider: WebhookProvider; secret: string }>()\n private handlers = new Map<string, Map<string, WebhookHandler[]>>()\n private globalHandlers = new Map<string, WebhookHandler[]>()\n private store?: WebhookStore\n private metrics: MetricsProvider = new NoopMetricsProvider()\n private tracer: Tracer = new NoopTracer()\n private logger: EchoLogger = new ConsoleEchoLogger()\n private keyRotationManager?: KeyRotationManager\n\n /**\n * Initializes the receiver and registers the suite of built-in providers.\n * Built-in providers include Stripe, GitHub, Shopify, Twilio, Slack, and others.\n */\n constructor() {\n // Register built-in providers\n this.registerProviderType('generic', GenericProvider as ProviderClass)\n this.registerProviderType('stripe', StripeProvider as ProviderClass)\n this.registerProviderType('github', GitHubProvider as ProviderClass)\n this.registerProviderType('shopify', ShopifyProvider as ProviderClass)\n this.registerProviderType('twilio', TwilioProvider as ProviderClass)\n this.registerProviderType('slack', SlackProvider as ProviderClass)\n this.registerProviderType('paddle', PaddleProvider as ProviderClass)\n this.registerProviderType('linear', LinearProvider as ProviderClass)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private providerTypes = new Map<string, ProviderClass>()\n\n /**\n * Assigns a storage engine for persisting and auditing incoming webhook data.\n *\n * @param store - Implementation of the WebhookStore interface.\n * @returns The current instance for method chaining.\n */\n setStore(store: WebhookStore): this {\n this.store = store\n return this\n }\n\n /**\n * Configures the metrics provider for performance and error monitoring.\n *\n * @param metrics - Implementation of the MetricsProvider interface.\n * @returns The current instance for method chaining.\n */\n setMetrics(metrics: MetricsProvider): this {\n this.metrics = metrics\n return this\n }\n\n /**\n * Configures the tracer for end-to-end request observability.\n *\n * @param tracer - Implementation of the Tracer interface.\n * @returns The current instance for method chaining.\n */\n setTracer(tracer: Tracer): this {\n this.tracer = tracer\n return this\n }\n\n /**\n * Configures the logger for diagnostic and security audit logging.\n *\n * @param logger - Implementation of the EchoLogger interface.\n * @returns The current instance for method chaining.\n */\n setLogger(logger: EchoLogger): this {\n this.logger = logger\n return this\n }\n\n /**\n * Attaches a key rotation manager for handling dynamic secret updates.\n *\n * @param manager - Instance of KeyRotationManager.\n * @returns The current instance for method chaining.\n */\n setKeyRotationManager(manager: KeyRotationManager): this {\n this.keyRotationManager = manager\n return this\n }\n\n /**\n * Extends the receiver with a custom webhook provider implementation.\n *\n * Use this to add support for services not included in the built-in provider set.\n *\n * @param name - Unique identifier for the provider type (e.g., 'custom-crm').\n * @param ProviderCls - Constructor for the class implementing WebhookProvider.\n * @returns The current instance for method chaining.\n */\n registerProviderType(name: string, ProviderCls: ProviderClass): this {\n this.providerTypes.set(name, ProviderCls)\n return this\n }\n\n /**\n * Configures a named provider instance with its security credentials.\n *\n * @param name - Unique identifier for this provider instance (used in routing).\n * @param secret - The shared secret used to verify incoming request signatures.\n * @param options - Settings like the provider type and signature time tolerance.\n * @returns The current instance for method chaining.\n * @throws {Error} If the specified provider type has not been registered.\n */\n registerProvider(\n name: string,\n secret: string,\n options?: { type?: string; tolerance?: number }\n ): this {\n const type = options?.type ?? name\n const ProviderClass = this.providerTypes.get(type)\n\n if (!ProviderClass) {\n throw new Error(`Unknown provider type: ${type}`)\n }\n\n const provider = new ProviderClass({ tolerance: options?.tolerance })\n this.providers.set(name, { provider, secret })\n return this\n }\n\n /**\n * Registers a provider instance with support for multiple secrets and rotation.\n *\n * This is the preferred registration method for high-availability environments\n * where zero-downtime key rotation is required.\n *\n * @param name - Unique identifier for this provider instance.\n * @param keys - A list of valid keys (active and pending) for this provider.\n * @param options - Settings like the provider type and signature time tolerance.\n * @returns The current instance for method chaining.\n * @throws {Error} If KeyRotationManager is not set or the provider type is unknown.\n */\n registerProviderWithRotation(\n name: string,\n keys: ProviderKeyEntry[],\n options?: { type?: string; tolerance?: number }\n ): this {\n if (!this.keyRotationManager) {\n throw new Error('KeyRotationManager must be set before using key rotation')\n }\n\n const type = options?.type ?? name\n const ProviderClass = this.providerTypes.get(type)\n\n if (!ProviderClass) {\n throw new Error(`Unknown provider type: ${type}`)\n }\n\n // Register keys with rotation manager\n this.keyRotationManager.registerKeys(name, keys)\n\n // Get primary key for initial registration\n const primaryKey = this.keyRotationManager.getPrimaryKey(name)\n if (!primaryKey) {\n throw new Error(`No primary key found for provider ${name}`)\n }\n\n const provider = new ProviderClass({ tolerance: options?.tolerance })\n this.providers.set(name, { provider, secret: primaryKey.key })\n\n return this\n }\n\n /**\n * Subscribes a handler function to a specific event type from a provider.\n *\n * @param providerName - The name of the registered provider instance.\n * @param eventType - The exact semantic type of the event (e.g., 'order.placed').\n * @param handler - The asynchronous function to execute when a matching event arrives.\n * @returns The current instance for method chaining.\n */\n on<T = unknown>(providerName: string, eventType: string, handler: WebhookHandler<T>): this {\n if (!this.handlers.has(providerName)) {\n this.handlers.set(providerName, new Map())\n }\n\n const providerHandlers = this.handlers.get(providerName)\n if (!providerHandlers) {\n const newHandlers = new Map()\n this.handlers.set(providerName, newHandlers)\n return this.on(providerName, eventType, handler)\n }\n\n if (!providerHandlers.has(eventType)) {\n providerHandlers.set(eventType, [])\n }\n\n providerHandlers.get(eventType)?.push(handler as WebhookHandler)\n return this\n }\n\n /**\n * Subscribes a catch-all handler for all valid events from a specific provider.\n *\n * @param providerName - The name of the registered provider instance.\n * @param handler - Function to execute for every authenticated event from this provider.\n * @returns The current instance for method chaining.\n */\n onAll<T = unknown>(providerName: string, handler: WebhookHandler<T>): this {\n if (!this.globalHandlers.has(providerName)) {\n this.globalHandlers.set(providerName, [])\n }\n\n this.globalHandlers.get(providerName)?.push(handler as WebhookHandler)\n return this\n }\n\n /**\n * Orchestrates the verification and asynchronous processing of an incoming webhook.\n *\n * This is the main entry point for requests. It performs the following:\n * 1. Signature validation (supporting multi-key fallback if rotation is enabled).\n * 2. Event persistence to storage for audit trails.\n * 3. Execution of all matching event-specific and global handlers.\n * 4. Automatic instrumentation for metrics and tracing.\n *\n * @param providerName - The name of the provider instance targeted by the request.\n * @param body - The raw request body as received from the socket.\n * @param headers - Complete set of HTTP headers for signature extraction.\n * @param context - Optional Gravito context for accessing buffered requests.\n * @returns Verification status, event metadata, and processing result.\n * @throws {Error} If handler execution or event storage fails.\n */\n async handle(\n providerName: string,\n body: string | Buffer,\n headers: Record<string, string | string[] | undefined>,\n context?: GravitoContext\n ): Promise<WebhookVerificationResult & { handled: boolean; eventId?: string }> {\n // Prefer buffered body from middleware if available\n const buffered = context?.get('bufferedRequest') as BufferedRequest | undefined\n const actualBody = buffered?.rawBody ?? body\n const actualHeaders = buffered?.headers ?? headers\n\n return this.tracer.withSpan('echo.receive_webhook', async (span) => {\n const startTime = performance.now()\n const labels: WebhookMetricLabels = { provider: providerName }\n\n span.setAttributes({\n 'echo.provider': providerName,\n 'echo.direction': 'incoming',\n 'echo.buffered': buffered !== undefined,\n })\n\n this.logger.debug('Webhook received', {\n component: 'receiver',\n provider: providerName,\n buffered: buffered !== undefined,\n })\n\n try {\n const config = this.providers.get(providerName)\n if (!config) {\n const error = `Provider not registered: ${providerName}`\n this.logger.warn('Webhook provider not registered', {\n component: 'receiver',\n provider: providerName,\n })\n span.setStatus({ code: SpanStatusCode.ERROR, message: error })\n return {\n valid: false,\n error,\n handled: false,\n }\n }\n\n const { provider, secret } = config\n\n // Verify webhook using buffered body if available\n span.addEvent('verification_start')\n\n // Try multi-key verification if rotation is enabled\n let result: WebhookVerificationResult = {\n valid: false,\n error: 'No verification performed',\n }\n\n if (this.keyRotationManager?.hasProvider(providerName)) {\n const activeKeys = this.keyRotationManager.getActiveKeys(providerName)\n\n // Try each active key until one succeeds\n let verified = false\n for (const keyEntry of activeKeys) {\n const attemptResult = await provider.verify(actualBody, actualHeaders, keyEntry.key)\n if (attemptResult.valid) {\n result = attemptResult\n verified = true\n\n // Log if using non-primary key\n if (!keyEntry.isPrimary) {\n this.logger.info('Webhook verified with non-primary key', {\n component: 'receiver',\n provider: providerName,\n keyVersion: keyEntry.version,\n })\n }\n break\n }\n }\n\n if (!verified) {\n result = {\n valid: false,\n error: 'Signature verification failed with all active keys',\n }\n }\n } else {\n // Fallback to single key verification\n result = await provider.verify(actualBody, actualHeaders, secret)\n }\n\n if (!result.valid) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: result.error })\n span.setAttribute('echo.error', result.error ?? 'unknown')\n\n this.metrics.increment(EchoMetrics.INCOMING_VERIFICATION_FAILURES, {\n provider: providerName,\n error_type: this.categorizeError(result.error),\n })\n\n this.logger.warn('Webhook verification failed', {\n component: 'receiver',\n provider: providerName,\n error: result.error,\n })\n\n return { ...result, handled: false }\n }\n\n span.addEvent('verification_success')\n span.setAttributes({\n 'echo.event_type': result.eventType ?? 'unknown',\n 'echo.webhook_id': result.webhookId ?? '',\n })\n\n this.logger.info('Webhook verified successfully', {\n component: 'receiver',\n provider: providerName,\n eventType: result.eventType,\n webhookId: result.webhookId,\n })\n\n labels.event_type = result.eventType\n labels.status = 'success'\n\n // Store event\n let eventId: string | undefined\n if (this.store) {\n eventId = await this.store.saveIncomingEvent({\n provider: providerName,\n eventType: result.eventType ?? 'unknown',\n payload: result.payload,\n headers: Object.fromEntries(\n Object.entries(actualHeaders).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])\n ),\n rawBody: typeof actualBody === 'string' ? actualBody : actualBody.toString('utf-8'),\n receivedAt: new Date(),\n status: 'pending',\n })\n }\n\n // Create event object\n const event: WebhookEvent = {\n provider: providerName,\n type: result.eventType ?? 'unknown',\n payload: result.payload,\n headers: actualHeaders,\n rawBody: typeof actualBody === 'string' ? actualBody : actualBody.toString('utf-8'),\n receivedAt: new Date(),\n id: result.webhookId,\n }\n\n try {\n // Call handlers\n let handled = false\n let handlerCount = 0\n\n span.addEvent('handlers_start')\n\n // Call event-specific handlers\n const providerHandlers = this.handlers.get(providerName)\n if (providerHandlers) {\n const eventHandlers = providerHandlers.get(event.type)\n if (eventHandlers) {\n for (const handler of eventHandlers) {\n await handler(event)\n handled = true\n handlerCount++\n }\n }\n }\n\n // Call global handlers\n const globalHandlers = this.globalHandlers.get(providerName)\n if (globalHandlers) {\n for (const handler of globalHandlers) {\n await handler(event)\n handled = true\n handlerCount++\n }\n }\n\n span.addEvent('handlers_complete', { handler_count: handlerCount })\n\n if (this.store && eventId) {\n await this.store.markProcessed(eventId)\n }\n\n this.logger.debug('Webhook processing complete', {\n component: 'receiver',\n provider: providerName,\n eventType: result.eventType,\n handlersInvoked: handlerCount,\n })\n\n span.setStatus({ code: SpanStatusCode.OK })\n return { ...result, handled, eventId }\n } catch (error) {\n if (this.store && eventId) {\n await this.store.markFailed(eventId, String(error))\n }\n throw error\n }\n } catch (error) {\n labels.status = 'failure'\n labels.error_type = error instanceof Error ? error.name : 'unknown'\n span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) })\n throw error\n } finally {\n const duration = (performance.now() - startTime) / 1000\n this.metrics.increment(EchoMetrics.INCOMING_TOTAL, labels as Record<string, string>)\n this.metrics.histogram(\n EchoMetrics.INCOMING_DURATION,\n duration,\n labels as Record<string, string>\n )\n }\n })\n }\n\n /**\n * Internal utility to categorize verification errors for metrics reporting.\n *\n * @param error - The raw error message from the provider or rotation manager.\n * @returns A semantic error category string (e.g., 'missing_header', 'signature_invalid').\n */\n private categorizeError(error?: string): string {\n if (!error) {\n return 'unknown'\n }\n if (error.includes('Missing')) {\n return 'missing_header'\n }\n if (error.includes('Signature')) {\n return 'signature_invalid'\n }\n if (error.includes('Timestamp')) {\n return 'timestamp_invalid'\n }\n return 'other'\n }\n\n /**\n * Performs a standalone signature verification without triggering side-effects.\n *\n * This method verifies the authenticity of a webhook request without persisting it\n * to storage or executing any registered handlers. Useful for pre-validation logic.\n *\n * @param providerName - The identifier of the provider instance to use for verification.\n * @param body - The raw request body.\n * @param headers - The incoming HTTP headers.\n * @returns A promise resolving to the verification result.\n */\n async verify(\n providerName: string,\n body: string | Buffer,\n headers: Record<string, string | string[] | undefined>\n ): Promise<WebhookVerificationResult> {\n const config = this.providers.get(providerName)\n if (!config) {\n return {\n valid: false,\n error: `Provider not registered: ${providerName}`,\n }\n }\n\n return config.provider.verify(body, headers, config.secret)\n }\n}\n",
25
+ "/**\n * @fileoverview Key Rotation Manager\n *\n * Manages the lifecycle of webhook provider secrets, including multi-version\n * support, automatic cleanup, and grace periods for smooth transitions.\n *\n * @module @gravito/echo/rotation\n * @since v1.2\n */\n\nimport type { KeyRotationConfig, ProviderKeyEntry } from '../types'\n\n/**\n * Default internal configuration for key rotation.\n */\nconst DEFAULT_CONFIG: Required<KeyRotationConfig> = {\n enabled: false,\n autoCleanup: true,\n gracePeriod: 24 * 60 * 60 * 1000, // 24 hours\n keyProvider: async () => [],\n onRotate: () => {\n /* Noop by default */\n },\n}\n\n/**\n * KeyRotationManager orchestrates the lifecycle of webhook provider secrets.\n *\n * It provides a central hub for managing multiple concurrent versions of signing\n * secrets, enabling zero-downtime rotation. By maintaining a set of \"active\"\n * keys (including those in a grace period), it ensures that webhooks signed\n * with either an old or new secret are successfully verified during transition.\n *\n * Key features:\n * - Multi-version secret management.\n * - Automatic background cleanup of expired keys.\n * - Grace period support for smooth cut-overs.\n * - Promotion of new primary keys.\n *\n * @example Managing zero-downtime rotation\n * ```typescript\n * const manager = new KeyRotationManager({\n * gracePeriod: 86400000, // 24 hours\n * autoCleanup: true,\n * });\n *\n * // Register initial keys\n * manager.registerKeys('stripe', [\n * {\n * key: 'whsec_primary',\n * version: 'v2',\n * isPrimary: true,\n * activeFrom: new Date(),\n * }\n * ]);\n *\n * // Rotate to a new secret\n * await manager.rotatePrimaryKey('stripe', {\n * key: 'whsec_new_secret',\n * version: 'v3',\n * activeFrom: new Date(),\n * });\n * ```\n *\n * @public\n */\nexport class KeyRotationManager {\n private providerKeys = new Map<string, ProviderKeyEntry[]>()\n private cleanupTimer?: Timer\n private config: Required<KeyRotationConfig>\n\n /**\n * Constructs a new KeyRotationManager with the specified policy.\n *\n * @param config - Configuration for auto-cleanup, grace periods, and rotation hooks.\n */\n constructor(config: KeyRotationConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n\n if (this.config.enabled && this.config.autoCleanup) {\n this.startAutoCleanup()\n }\n }\n\n /**\n * Registers a collection of keys for a specific provider.\n *\n * Validation ensures that exactly one primary key is specified for the provider.\n *\n * @param providerName - Canonical name of the provider instance.\n * @param keys - Array of valid key entries with metadata.\n * @throws {Error} If no primary key is provided or if multiple primary keys are detected.\n */\n registerKeys(providerName: string, keys: ProviderKeyEntry[]): void {\n // Validate primary key presence and uniqueness\n const primaryKeys = keys.filter((k) => k.isPrimary)\n if (primaryKeys.length !== 1) {\n throw new Error(`Provider ${providerName} must have exactly one primary key`)\n }\n\n // Sort by activation date descending (newest first)\n const sorted = [...keys].sort((a, b) => b.activeFrom.getTime() - a.activeFrom.getTime())\n\n this.providerKeys.set(providerName, sorted)\n }\n\n /**\n * Retrieves all currently valid keys for a provider to attempt verification.\n *\n * A key is considered active if the current time is after its `activeFrom` date\n * and before its `expiresAt` date (if defined).\n *\n * @param providerName - Canonical name of the provider instance.\n * @returns An array of currently active key entries.\n */\n getActiveKeys(providerName: string): ProviderKeyEntry[] {\n const keys = this.providerKeys.get(providerName) ?? []\n const now = new Date()\n\n return keys.filter((key) => {\n const isActive = key.activeFrom <= now\n const notExpired = !key.expiresAt || key.expiresAt > now\n return isActive && notExpired\n })\n }\n\n /**\n * Retrieves the current primary key used for signature generation.\n *\n * @param providerName - Canonical name of the provider instance.\n * @returns The primary key entry, or null if no active primary key exists.\n */\n getPrimaryKey(providerName: string): ProviderKeyEntry | null {\n const keys = this.getActiveKeys(providerName)\n return keys.find((k) => k.isPrimary) ?? null\n }\n\n /**\n * Promotes a new primary key for the provider and retires the old one.\n *\n * The previous primary key is automatically assigned an expiration date based on\n * the configured `gracePeriod`, allowing it to remain valid for incoming requests\n * that were signed before the rotation propagated.\n *\n * @param providerName - Canonical name of the provider instance.\n * @param newKey - Metadata and secret for the new primary key.\n */\n async rotatePrimaryKey(\n providerName: string,\n newKey: Omit<ProviderKeyEntry, 'isPrimary'>\n ): Promise<void> {\n const existingKeys = this.providerKeys.get(providerName) ?? []\n\n // Mark old primary key as inactive and set expiration based on grace period\n const updatedKeys: ProviderKeyEntry[] = existingKeys.map((key) => ({\n ...key,\n isPrimary: false,\n expiresAt: key.isPrimary ? new Date(Date.now() + this.config.gracePeriod) : key.expiresAt,\n }))\n\n // Add the new primary key to the front of the list\n const primaryKey: ProviderKeyEntry = {\n ...newKey,\n isPrimary: true,\n }\n\n updatedKeys.unshift(primaryKey)\n this.providerKeys.set(providerName, updatedKeys)\n\n this.config.onRotate(providerName, primaryKey)\n }\n\n /**\n * Manually triggers a purge of all expired keys across all providers.\n *\n * @returns The total number of keys removed during this cycle.\n */\n cleanupExpiredKeys(): number {\n const now = new Date()\n let cleaned = 0\n\n for (const [providerName, keys] of this.providerKeys.entries()) {\n const active = keys.filter((key) => !key.expiresAt || key.expiresAt > now)\n\n if (active.length !== keys.length) {\n cleaned += keys.length - active.length\n this.providerKeys.set(providerName, active)\n }\n }\n\n return cleaned\n }\n\n /**\n * Initializes the background timer for periodic key purging.\n */\n private startAutoCleanup(): void {\n // Execute cleanup once per hour\n this.cleanupTimer = setInterval(\n () => {\n const cleaned = this.cleanupExpiredKeys()\n if (cleaned > 0) {\n console.log(`[KeyRotationManager] Cleaned up ${cleaned} expired keys`)\n }\n },\n 60 * 60 * 1000\n )\n }\n\n /**\n * Stops the auto-cleanup background process.\n */\n destroy(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer)\n }\n }\n\n /**\n * Provides a read-only snapshot of all keys across all providers.\n *\n * @returns A map of provider names to their complete key history.\n */\n getAllProviderKeys(): Map<string, ProviderKeyEntry[]> {\n return new Map(this.providerKeys)\n }\n\n /**\n * Checks if a specific provider has any keys registered in the manager.\n *\n * @param providerName - Canonical name of the provider instance.\n * @returns True if the provider is tracked.\n */\n hasProvider(providerName: string): boolean {\n return this.providerKeys.has(providerName)\n }\n}\n",
26
+ "/**\n * Implementation of the Circuit Breaker pattern.\n *\n * Protects downstream services from cascading failures by monitoring error rates\n * and temporarily \"tripping\" the circuit when thresholds are exceeded. This\n * prevents unnecessary load on struggling services and allows them time to recover.\n *\n * @module @gravito/echo/resilience\n * @since 1.1.0\n */\n\nimport type { CircuitBreakerConfig, CircuitBreakerMetrics, CircuitBreakerState } from '../types'\n\n/**\n * Default internal configuration for the circuit breaker.\n */\nconst DEFAULT_CONFIG: Required<CircuitBreakerConfig> = {\n enabled: true,\n failureThreshold: 5,\n successThreshold: 2,\n windowSize: 60000, // 1 minute\n openTimeout: 30000, // 30 seconds\n onOpen: () => {\n /* Noop by default */\n },\n onHalfOpen: () => {\n /* Noop by default */\n },\n onClose: () => {\n /* Noop by default */\n },\n}\n\n/**\n * State machine for managing downstream service availability via the Circuit Breaker pattern.\n *\n * This implementation tracks failures and successes to determine one of three states:\n * - `CLOSED`: Healthy state. All requests are executed normally.\n * - `OPEN`: Failing state. Trip thresholds exceeded; requests are rejected immediately to\n * prevent cascading failure and give the target system time to recover.\n * - `HALF_OPEN`: Recovery phase. Allows a limited number of test requests to determine\n * if the downstream service has restored functionality.\n *\n * @example Protecting a fragile API call\n * ```typescript\n * const breaker = new CircuitBreaker('inventory-service', {\n * failureThreshold: 5,\n * openTimeout: 60000 // Stay open for 1 minute before testing recovery\n * });\n *\n * try {\n * const stock = await breaker.execute(async () => {\n * return await apiClient.getInventory();\n * });\n * } catch (error) {\n * if (error.message.includes('Circuit breaker is OPEN')) {\n * // Redirect to fallback or return cached data\n * }\n * }\n * ```\n *\n * @public\n */\nexport class CircuitBreaker {\n private state: CircuitBreakerState = 'CLOSED'\n private failures = 0\n private successes = 0\n private lastFailureAt?: Date\n private lastSuccessAt?: Date\n private openedAt?: Date\n private halfOpenAttempts = 0\n\n private config: Required<CircuitBreakerConfig>\n\n /**\n * Constructs a new CircuitBreaker for a specific resource, host, or service.\n *\n * @param name - A semantic identifier for the target being protected.\n * @param config - Policy settings for failure thresholds, recovery timeouts, and callbacks.\n */\n constructor(\n private readonly name: string,\n config: CircuitBreakerConfig = {}\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n }\n\n /**\n * Executes an asynchronous operation within the safety window of the circuit breaker.\n *\n * This method will proactively check the circuit state. If the state is `OPEN`, it will\n * throw an error immediately without invoking the provided function.\n *\n * @param fn - The asynchronous operation to be protected.\n * @returns A promise resolving to the result of the protected operation.\n * @throws {Error} If the circuit is currently `OPEN` or if the underlying operation fails.\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n if (!this.config.enabled) {\n return await fn()\n }\n\n this.checkStateTransition()\n\n if (this.state === 'OPEN') {\n throw new Error(`Circuit breaker is OPEN for ${this.name}`)\n }\n\n try {\n const result = await fn()\n this.onSuccess()\n return result\n } catch (error) {\n this.onFailure()\n throw error\n }\n }\n\n /**\n * Records a successful operation and updates the state machine.\n * In `HALF_OPEN` state, this contributes to the success threshold for closing the circuit.\n */\n private onSuccess(): void {\n this.lastSuccessAt = new Date()\n this.successes++\n\n if (this.state === 'HALF_OPEN') {\n this.halfOpenAttempts++\n if (this.halfOpenAttempts >= this.config.successThreshold) {\n this.transitionTo('CLOSED')\n this.reset()\n }\n } else if (this.state === 'CLOSED') {\n // Reset failure count on success when in CLOSED state to ensure fresh window\n this.failures = 0\n }\n }\n\n /**\n * Records a failed operation and determines if the circuit should trip to `OPEN`.\n * Any failure in `HALF_OPEN` state immediately trips the circuit back to `OPEN`.\n */\n private onFailure(): void {\n this.lastFailureAt = new Date()\n this.failures++\n\n if (this.state === 'HALF_OPEN') {\n // Any failure in HALF_OPEN immediately trips back to OPEN\n this.transitionTo('OPEN')\n this.openedAt = new Date()\n } else if (this.state === 'CLOSED') {\n // Trip to OPEN if failure threshold is reached\n if (this.failures >= this.config.failureThreshold) {\n this.transitionTo('OPEN')\n this.openedAt = new Date()\n }\n }\n }\n\n /**\n * Evaluates and performs automatic state transitions based on elapsed time and thresholds.\n */\n private checkStateTransition(): void {\n if (this.state === 'OPEN' && this.openedAt) {\n const elapsed = Date.now() - this.openedAt.getTime()\n if (elapsed >= this.config.openTimeout) {\n this.transitionTo('HALF_OPEN')\n this.halfOpenAttempts = 0\n }\n }\n\n // Reset failure counter if the sliding window has expired\n if (this.lastFailureAt) {\n const elapsed = Date.now() - this.lastFailureAt.getTime()\n if (elapsed >= this.config.windowSize) {\n this.failures = 0\n }\n }\n }\n\n /**\n * Transitions the circuit to a new state and executes configured lifecycle callbacks.\n *\n * @param newState - The target state to transition into.\n */\n private transitionTo(newState: CircuitBreakerState): void {\n this.state = newState\n\n switch (newState) {\n case 'OPEN':\n this.config.onOpen(this.name)\n break\n case 'HALF_OPEN':\n this.config.onHalfOpen(this.name)\n break\n case 'CLOSED':\n this.config.onClose(this.name)\n break\n }\n }\n\n /**\n * Resets all internal counters and timers to their initial baseline state.\n */\n private reset(): void {\n this.failures = 0\n this.successes = 0\n this.halfOpenAttempts = 0\n this.openedAt = undefined\n }\n\n /**\n * Retrieves a snapshot of the current health and performance metrics of the circuit.\n *\n * @returns An object containing state, failure counts, and activity timestamps.\n */\n getMetrics(): CircuitBreakerMetrics {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n lastFailureAt: this.lastFailureAt,\n lastSuccessAt: this.lastSuccessAt,\n openedAt: this.openedAt,\n }\n }\n\n /**\n * Forcefully resets the circuit breaker to the `CLOSED` state.\n * Useful for manual recovery scenarios after a service has been verified healthy.\n */\n manualReset(): void {\n this.transitionTo('CLOSED')\n this.reset()\n }\n\n /**\n * Returns the current operational state of the circuit breaker.\n *\n * @returns The current state identifier.\n */\n getState(): CircuitBreakerState {\n return this.state\n }\n\n /**\n * Returns the semantic name assigned to this circuit breaker instance.\n *\n * @returns The name identifier.\n */\n getName(): string {\n return this.name\n }\n}\n",
27
+ "/**\n * @fileoverview Webhook Dispatcher\n *\n * Reliably sends webhooks to external services with retry support.\n *\n * @module @gravito/echo/send\n */\n\nimport type { DeadLetterQueue } from '../dlq/DeadLetterQueue'\nimport type { EchoLogger } from '../observability/logging'\nimport {\n EchoMetrics,\n type MetricsProvider,\n NoopMetricsProvider,\n type WebhookMetricLabels,\n} from '../observability/metrics'\nimport { NoopTracer, SpanStatusCode, type Tracer } from '../observability/tracing'\nimport { computeHmacSha256 } from '../receive/SignatureValidator'\nimport { CircuitBreaker } from '../resilience/CircuitBreaker'\nimport type { OutgoingWebhookRecord } from '../storage/WebhookStore'\nimport type {\n BatchDispatchOptions,\n BatchDispatchResult,\n CircuitBreakerConfig,\n CircuitBreakerMetrics,\n RetryConfig,\n WebhookDeliveryResult,\n WebhookDispatcherConfig,\n WebhookPayload,\n} from '../types'\n\n/**\n * Default retry configuration for outgoing webhooks.\n */\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxAttempts: 3,\n initialDelay: 1000,\n backoffMultiplier: 2,\n maxDelay: 300000, // 5 minutes\n retryableStatuses: [408, 429, 500, 502, 503, 504],\n}\n\n/**\n * WebhookDispatcher manages the secure and reliable delivery of events to external targets.\n *\n * It provides a robust engine for sending signed webhook payloads to third-party\n * consumers, incorporating enterprise-grade reliability features such as:\n * - Exponential backoff retries for transient network/server errors.\n * - Per-host Circuit Breaking to prevent cascading failures.\n * - Dead Letter Queue (DLQ) integration for capturing permanently failed events.\n * - HMAC-SHA256 payload signing for authenticity.\n *\n * @example Dispatching a signed event\n * ```typescript\n * const dispatcher = new WebhookDispatcher({\n * secret: 'app-outbound-secret',\n * retry: { maxAttempts: 5 }\n * });\n *\n * const result = await dispatcher.dispatch({\n * url: 'https://consumer.com/webhooks',\n * event: 'order.shipped',\n * data: { orderId: 'ORD-123' }\n * });\n *\n * if (result.success) {\n * console.log('Webhook delivered successfully');\n * }\n * ```\n *\n * @public\n */\nexport class WebhookDispatcher {\n private secret: string\n private retryConfig: Required<RetryConfig>\n private timeout: number\n private userAgent: string\n private dlq?: DeadLetterQueue\n private metrics: MetricsProvider = new NoopMetricsProvider()\n private tracer: Tracer = new NoopTracer()\n private logger?: EchoLogger\n private circuitBreakers = new Map<string, CircuitBreaker>()\n private circuitBreakerConfig?: CircuitBreakerConfig\n\n /**\n * Initializes the dispatcher with security and reliability policies.\n *\n * @param config - The configuration for payload signing, retry logic, and timeouts.\n */\n constructor(config: WebhookDispatcherConfig) {\n this.secret = config.secret\n this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retry }\n this.timeout = config.timeout ?? 30000\n this.userAgent = config.userAgent ?? 'Gravito-Echo/1.0'\n this.circuitBreakerConfig = config.circuitBreaker\n }\n\n /**\n * Attaches a Dead Letter Queue for capturing events that fail all delivery attempts.\n *\n * @param dlq - Implementation of the DeadLetterQueue interface.\n * @returns The current instance for method chaining.\n */\n setDeadLetterQueue(dlq: DeadLetterQueue): this {\n this.dlq = dlq\n return this\n }\n\n /**\n * Configures the metrics provider for delivery and failure tracking.\n *\n * @param metrics - Implementation of the MetricsProvider interface.\n * @returns The current instance for method chaining.\n */\n setMetrics(metrics: MetricsProvider): this {\n this.metrics = metrics\n return this\n }\n\n /**\n * Configures the distributed tracer for end-to-end request visibility.\n *\n * @param tracer - Implementation of the Tracer interface.\n * @returns The current instance for method chaining.\n */\n setTracer(tracer: Tracer): this {\n this.tracer = tracer\n return this\n }\n\n /**\n * Configures the logger for diagnostic and delivery audit logging.\n *\n * @param logger - Implementation of the EchoLogger interface.\n * @returns The current instance for method chaining.\n */\n setLogger(logger: EchoLogger): this {\n this.logger = logger\n return this\n }\n\n /**\n * Resolves or creates a dedicated circuit breaker instance for a specific host.\n *\n * Using per-host isolation ensures that an outage at one consumer does not\n * block or slow down deliveries to other healthy consumers.\n *\n * @param url - Destination URL used to derive the target host.\n * @returns The active circuit breaker instance, or undefined if disabled.\n */\n private getCircuitBreaker(url: string): CircuitBreaker | undefined {\n if (!this.circuitBreakerConfig?.enabled) {\n return undefined\n }\n\n const host = new URL(url).host\n\n if (!this.circuitBreakers.has(host)) {\n const breaker = new CircuitBreaker(host, {\n ...this.circuitBreakerConfig,\n onOpen: (name) => {\n this.logger?.warn(`Circuit breaker OPEN for ${name}`, {\n component: 'dispatcher',\n host: name,\n })\n this.circuitBreakerConfig?.onOpen?.(name)\n },\n onHalfOpen: (name) => {\n this.logger?.info(`Circuit breaker HALF_OPEN for ${name}`, {\n component: 'dispatcher',\n host: name,\n })\n this.circuitBreakerConfig?.onHalfOpen?.(name)\n },\n onClose: (name) => {\n this.logger?.info(`Circuit breaker CLOSED for ${name}`, {\n component: 'dispatcher',\n host: name,\n })\n this.circuitBreakerConfig?.onClose?.(name)\n },\n })\n this.circuitBreakers.set(host, breaker)\n }\n\n return this.circuitBreakers.get(host)\n }\n\n /**\n * Retrieves the current health metrics for a specific target's circuit breaker.\n *\n * @param url - The target URL whose host metrics are requested.\n * @returns Current metrics or null if circuit breaking is not active for the host.\n */\n getCircuitBreakerMetrics(url: string): CircuitBreakerMetrics | null {\n const host = new URL(url).host\n const breaker = this.circuitBreakers.get(host)\n return breaker ? breaker.getMetrics() : null\n }\n\n /**\n * Manually resets a tripped circuit breaker to its CLOSED state for a specific target.\n *\n * @param url - The target URL whose host circuit should be reset.\n */\n resetCircuitBreaker(url: string): void {\n const host = new URL(url).host\n const breaker = this.circuitBreakers.get(host)\n breaker?.manualReset()\n }\n\n /**\n * Executes the end-to-end delivery of a signed webhook event.\n *\n * This method performs the following:\n * 1. Wraps the payload with an authenticity signature (HMAC-SHA256).\n * 2. Checks the state of the target's circuit breaker.\n * 3. Executes the HTTP POST request.\n * 4. Manages the retry lifecycle if errors occur.\n * 5. Enqueues failed events to the DLQ if configured.\n *\n * @param payload - Data and destination parameters for the dispatch.\n * @returns Final delivery outcome including success status and attempt count.\n * @throws {Error} If critical internal operations (like signing) fail.\n */\n async dispatch<T = unknown>(payload: WebhookPayload<T>): Promise<WebhookDeliveryResult> {\n return this.tracer.withSpan('echo.dispatch_webhook', async (span) => {\n const startTime = performance.now()\n const labels: WebhookMetricLabels = { event_type: payload.event }\n\n span.setAttributes({\n 'echo.direction': 'outgoing',\n 'echo.event': payload.event,\n 'echo.url': payload.url,\n 'http.method': 'POST',\n 'http.url': payload.url,\n })\n\n const result = await this.dispatchInternal(payload)\n\n const duration = (performance.now() - startTime) / 1000\n labels.status = result.success ? 'success' : 'failure'\n labels.status_code = result.statusCode?.toString()\n\n this.metrics.increment(EchoMetrics.OUTGOING_TOTAL, labels as Record<string, string>)\n this.metrics.histogram(\n EchoMetrics.OUTGOING_DURATION,\n duration,\n labels as Record<string, string>\n )\n\n if (result.attempt > 1) {\n this.metrics.increment(EchoMetrics.OUTGOING_RETRIES, {\n event_type: payload.event,\n })\n }\n\n span.setAttributes({\n 'echo.success': result.success,\n 'echo.attempt': result.attempt,\n 'echo.duration_ms': result.duration,\n })\n\n if (result.statusCode) {\n span.setAttribute('http.status_code', result.statusCode)\n }\n\n if (result.success) {\n span.setStatus({ code: SpanStatusCode.OK })\n } else {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: result.error,\n })\n\n this.metrics.increment(EchoMetrics.OUTGOING_FAILURES, {\n event_type: payload.event,\n error_type: this.categorizeError(result),\n })\n }\n\n return result\n })\n }\n\n /**\n * Internal orchestration for the delivery retry loop.\n *\n * @param payload - The webhook payload.\n * @returns Final delivery result after all retry attempts.\n */\n private async dispatchInternal<T = unknown>(\n payload: WebhookPayload<T>\n ): Promise<WebhookDeliveryResult> {\n let lastResult: WebhookDeliveryResult | null = null\n\n for (let attempt = 1; attempt <= this.retryConfig.maxAttempts; attempt++) {\n const result = await this.attemptDelivery(payload, attempt)\n lastResult = result\n\n if (result.success) {\n return result\n }\n\n // Check if we should retry\n if (attempt < this.retryConfig.maxAttempts) {\n const shouldRetry = this.shouldRetry(result)\n if (shouldRetry) {\n const delay = this.calculateDelay(attempt)\n await this.sleep(delay)\n continue\n }\n }\n\n // Don't retry if status is not retryable\n break\n }\n\n // If we exhausted retries or hit non-retryable error, check DLQ\n if (this.dlq && lastResult && !lastResult.success) {\n await this.dlq.enqueue({\n type: 'outgoing',\n originalEvent: {\n url: payload.url,\n event: payload.event,\n payload: payload.data,\n createdAt: new Date(),\n status: 'failed',\n attempts: [], // Store will track attempts separately, or we can add this attempt here\n } as OutgoingWebhookRecord,\n failureReason: lastResult.error ?? 'Unknown error',\n failedAt: new Date(),\n retryCount: lastResult.attempt,\n })\n }\n\n if (!lastResult) {\n throw new Error('No delivery attempts were made')\n }\n\n return lastResult\n }\n\n /**\n * Dispatches a batch of webhooks concurrently using an optimized worker pool.\n *\n * This method balances high throughput with source/target resource constraints\n * by allowing you to tune concurrency and error propagation policies.\n *\n * @param payloads - Collection of payloads to deliver.\n * @param options - Tuning parameters for concurrency and failure handling.\n * @returns A summary result of all dispatch attempts in the batch.\n *\n * @example Batch dispatch with concurrency control\n * ```typescript\n * const results = await dispatcher.dispatchBatch(payloads, {\n * concurrency: 10,\n * stopOnFirstFailure: false\n * });\n * console.log(`Batch complete. Succeeded: ${results.succeeded}, Failed: ${results.failed}`);\n * ```\n */\n async dispatchBatch<T = unknown>(\n payloads: WebhookPayload<T>[],\n options: BatchDispatchOptions = {}\n ): Promise<BatchDispatchResult> {\n const concurrency = options.concurrency ?? 5\n const stopOnFirstFailure = options.stopOnFirstFailure ?? false\n\n const results: BatchDispatchResult['results'] = []\n let succeeded = 0\n let failed = 0\n let stopped = false\n\n // Process in chunks\n for (let i = 0; i < payloads.length && !stopped; i += concurrency) {\n const chunk = payloads.slice(i, i + concurrency)\n\n const chunkResults = await Promise.all(\n chunk.map(async (payload) => {\n if (stopped) {\n return {\n payload,\n result: {\n success: false,\n attempt: 0,\n duration: 0,\n deliveredAt: new Date(),\n error: 'Batch dispatch stopped',\n } as WebhookDeliveryResult,\n }\n }\n\n const result = await this.dispatch(payload)\n\n if (result.success) {\n succeeded++\n } else {\n failed++\n if (stopOnFirstFailure) {\n stopped = true\n }\n }\n\n return { payload, result }\n })\n )\n\n results.push(...chunkResults)\n }\n\n return {\n total: payloads.length,\n succeeded,\n failed,\n results,\n }\n }\n\n /**\n * Re-attempts the delivery of a previously failed event from the Dead Letter Queue.\n *\n * If the delivery succeeds, the event is automatically removed from the DLQ.\n *\n * @param id - The unique identifier of the event in the DLQ.\n * @returns Result of the retry attempt, or null if the event ID is invalid.\n */\n async retryFromDlq(id: string): Promise<WebhookDeliveryResult | null> {\n if (!this.dlq) {\n return null\n }\n\n const events = await this.dlq.peek(100)\n const event = events.find((e) => e.id === id)\n\n if (!event || event.type !== 'outgoing') {\n return null\n }\n\n const outgoing = event.originalEvent as OutgoingWebhookRecord\n\n const result = await this.dispatch({\n url: outgoing.url,\n event: outgoing.event,\n data: outgoing.payload,\n })\n\n if (result.success) {\n await this.dlq.dequeue(id)\n } else {\n event.retryCount++\n event.lastRetryAt = new Date()\n }\n\n return result\n }\n\n /**\n * Executes a single delivery attempt including signing and circuit breaker check.\n *\n * @param payload - The webhook payload.\n * @param attempt - The current attempt number.\n * @returns Detailed result of the single attempt.\n */\n private async attemptDelivery<T = unknown>(\n payload: WebhookPayload<T>,\n attempt: number\n ): Promise<WebhookDeliveryResult> {\n const breaker = this.getCircuitBreaker(payload.url)\n\n const deliveryFn = async () => {\n const startTime = Date.now()\n const timestamp = Math.floor(Date.now() / 1000)\n const webhookId = payload.id ?? crypto.randomUUID()\n\n try {\n // Build request body\n const body = JSON.stringify({\n id: webhookId,\n type: payload.event,\n timestamp,\n data: payload.data,\n })\n\n // Compute signature\n const signedPayload = `${timestamp}.${body}`\n const signature = await computeHmacSha256(signedPayload, this.secret)\n\n // Create abort controller for timeout\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(payload.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': this.userAgent,\n 'X-Webhook-ID': webhookId,\n 'X-Webhook-Timestamp': String(timestamp),\n 'X-Webhook-Signature': `t=${timestamp},v1=${signature}`,\n },\n body,\n signal: controller.signal,\n })\n\n clearTimeout(timeoutId)\n\n const duration = Date.now() - startTime\n const responseBody = await response.text()\n\n return {\n success: response.ok,\n statusCode: response.status,\n body: responseBody,\n attempt,\n duration,\n deliveredAt: new Date(),\n error: response.ok ? undefined : `HTTP ${response.status}`,\n }\n } finally {\n clearTimeout(timeoutId)\n }\n } catch (error) {\n const duration = Date.now() - startTime\n\n return {\n success: false,\n attempt,\n duration,\n deliveredAt: new Date(),\n error: error instanceof Error ? error.message : 'Unknown error',\n }\n }\n }\n\n // Use circuit breaker if enabled\n if (breaker) {\n try {\n return await breaker.execute(deliveryFn)\n } catch (error) {\n if (error instanceof Error && error.message.includes('Circuit breaker is OPEN')) {\n return {\n success: false,\n attempt,\n duration: 0,\n deliveredAt: new Date(),\n error: error.message,\n }\n }\n throw error\n }\n }\n\n // Fallback to direct execution if circuit breaker is disabled\n return await deliveryFn()\n }\n\n /**\n * Internal logic to decide if an attempt should be retried.\n *\n * @param result - The delivery result to evaluate.\n * @returns True if retry is eligible.\n */\n private shouldRetry(result: WebhookDeliveryResult): boolean {\n if (!result.statusCode) {\n // Network error, retry\n return true\n }\n\n return this.retryConfig.retryableStatuses.includes(result.statusCode)\n }\n\n /**\n * Calculates the exponential backoff delay for the next attempt.\n *\n * @param attempt - The current attempt number.\n * @returns Delay in milliseconds.\n */\n private calculateDelay(attempt: number): number {\n const delay =\n this.retryConfig.initialDelay * this.retryConfig.backoffMultiplier ** (attempt - 1)\n\n return Math.min(delay, this.retryConfig.maxDelay)\n }\n\n /**\n * Standardized categorization of delivery errors for metrics.\n *\n * @param result - The delivery result to categorize.\n * @returns Category string.\n */\n private categorizeError(result: WebhookDeliveryResult): string {\n if (!result.statusCode) {\n return 'network_error'\n }\n if (result.statusCode >= 500) {\n return 'server_error'\n }\n if (result.statusCode >= 400) {\n return 'client_error'\n }\n return 'other'\n }\n\n /**\n * Utility for asynchronous sleep.\n *\n * @param ms - Duration to sleep in ms.\n * @returns Promise that resolves after delay.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n }\n}\n",
28
+ "import type { GravitoOrbit, PlanetCore } from '@gravito/core'\nimport { createRequestBufferMiddleware } from './middleware'\nimport { WebhookReceiver } from './receive/WebhookReceiver'\nimport { KeyRotationManager } from './rotation/KeyRotationManager'\nimport { WebhookDispatcher } from './send/WebhookDispatcher'\nimport type { EchoConfig, ProviderKeyEntry, WebhookProviderConfigWithRotation } from './types'\n\n/**\n * OrbitEcho is the official webhook orchestration module for the Gravito ecosystem.\n *\n * It serves as a comprehensive hub for managing the entire webhook lifecycle,\n * including secure reception, signature verification across multiple providers,\n * persistent storage for auditing, and reliable outgoing dispatch with\n * exponential backoff and circuit breaking.\n *\n * @example Basic integration with PlanetCore\n * ```typescript\n * import { PlanetCore } from '@gravito/core';\n * import { OrbitEcho } from '@gravito/echo';\n *\n * const core = new PlanetCore();\n * const echo = new OrbitEcho({\n * providers: {\n * stripe: { name: 'stripe', secret: process.env.STRIPE_SECRET }\n * },\n * dispatcher: {\n * secret: process.env.APP_WEBHOOK_SECRET\n * }\n * });\n *\n * core.install(echo);\n * ```\n *\n * @public\n */\nexport class OrbitEcho implements GravitoOrbit {\n private receiver: WebhookReceiver\n private dispatcher?: WebhookDispatcher\n private echoConfig: EchoConfig\n private keyRotationManager?: KeyRotationManager\n\n /**\n * Constructs a new OrbitEcho instance with the specified configuration.\n *\n * This constructor initializes the core receiver component, sets up key rotation\n * orchestration if enabled, registers defined providers, and connects the\n * observability stack (metrics, tracing, logging).\n *\n * @param config - The global configuration defining providers, dispatchers, and infrastructure.\n */\n constructor(config: EchoConfig = {}) {\n this.echoConfig = config\n this.receiver = new WebhookReceiver()\n\n // Initialize key rotation if enabled\n if (config.keyRotation?.enabled) {\n this.keyRotationManager = new KeyRotationManager(config.keyRotation)\n this.receiver.setKeyRotationManager(this.keyRotationManager)\n }\n\n // Register providers\n if (config.providers) {\n for (const [name, providerConfig] of Object.entries(config.providers)) {\n const rotationConfig = providerConfig as WebhookProviderConfigWithRotation\n\n // Check if provider has key rotation configured\n if (rotationConfig.keys && rotationConfig.keys.length > 0 && this.keyRotationManager) {\n this.receiver.registerProviderWithRotation(name, rotationConfig.keys, {\n type: providerConfig.name,\n tolerance: providerConfig.tolerance,\n })\n } else {\n // Fallback to single key registration\n this.receiver.registerProvider(name, providerConfig.secret, {\n type: providerConfig.name,\n tolerance: providerConfig.tolerance,\n })\n }\n }\n }\n\n // Create dispatcher\n if (config.dispatcher) {\n this.dispatcher = new WebhookDispatcher(config.dispatcher)\n if (config.deadLetterQueue) {\n this.dispatcher.setDeadLetterQueue(config.deadLetterQueue)\n }\n }\n\n // Set storage\n if (config.store) {\n this.receiver.setStore(config.store)\n }\n\n // Set observability\n if (config.observability) {\n const { metrics, tracer, logger } = config.observability\n if (metrics) {\n this.receiver.setMetrics(metrics)\n this.dispatcher?.setMetrics(metrics)\n }\n if (tracer) {\n this.receiver.setTracer(tracer)\n this.dispatcher?.setTracer(tracer)\n }\n if (logger) {\n this.receiver.setLogger(logger)\n }\n }\n }\n\n /**\n * Integrates the Echo module into the Gravito application lifecycle.\n *\n * This method performs the following setup tasks:\n * 1. Installs request buffering middleware (if enabled) to preserve raw bodies.\n * 2. Binds Echo components to the service container (`echo`, `echo.receiver`).\n * 3. Injects the Echo instance into the request context for easy access in handlers.\n *\n * @param core - The PlanetCore instance managing the application.\n * @throws {Error} If the core adapter is missing or improperly configured.\n */\n install(core: PlanetCore): void {\n // Install request buffer middleware if enabled\n if (this.echoConfig.requestBuffer?.enabled !== false) {\n const bufferMiddleware = createRequestBufferMiddleware(this.echoConfig.requestBuffer)\n core.adapter.use('*', bufferMiddleware)\n core.logger.info('[OrbitEcho] Request buffer middleware installed')\n }\n\n // Bind instances to container\n core.container.instance('echo', this)\n core.container.instance('echo.receiver', this.receiver)\n if (this.dispatcher) {\n core.container.instance('echo.dispatcher', this.dispatcher)\n }\n\n // Inject into context via middleware\n core.adapter.use('*', async (c, next) => {\n c.set('echo', this)\n return await next()\n })\n\n core.logger.info('[OrbitEcho] Webhook receiver and dispatcher registered')\n }\n\n /**\n * Retrieves the underlying receiver instance for manual webhook processing.\n *\n * Use this when you need fine-grained control over how incoming webhooks\n * are routed or verified outside of the standard middleware flow.\n *\n * @returns The active WebhookReceiver instance.\n */\n getReceiver(): WebhookReceiver {\n return this.receiver\n }\n\n /**\n * Retrieves the dispatcher instance for sending outgoing webhooks.\n *\n * @returns The configured WebhookDispatcher, or undefined if dispatch is disabled.\n */\n getDispatcher(): WebhookDispatcher | undefined {\n return this.dispatcher\n }\n\n /**\n * Accesses the active configuration used by this OrbitEcho instance.\n *\n * @returns The immutable EchoConfig object.\n */\n getConfig(): EchoConfig {\n return this.echoConfig\n }\n\n /**\n * Retrieves the key rotation manager responsible for secret lifecycle.\n *\n * @returns The manager instance, or undefined if key rotation is disabled.\n */\n getKeyRotationManager(): KeyRotationManager | undefined {\n return this.keyRotationManager\n }\n\n /**\n * Initiates a zero-downtime primary key rotation for a specific provider.\n *\n * This method promotes a new key to primary status while maintaining valid old keys\n * for a grace period, ensuring that webhooks signed with either key are accepted\n * during the transition.\n *\n * @param providerName - The identifier of the provider to update.\n * @param newKey - Metadata and value for the replacement key.\n * @throws {Error} If key rotation is not enabled in the global configuration.\n *\n * @example\n * ```typescript\n * await echo.rotateProviderKey('stripe', {\n * key: 'whsec_new_secret',\n * version: 'v2',\n * activeFrom: new Date()\n * });\n * ```\n */\n async rotateProviderKey(\n providerName: string,\n newKey: Omit<ProviderKeyEntry, 'isPrimary'>\n ): Promise<void> {\n if (!this.keyRotationManager) {\n throw new Error('Key rotation is not enabled')\n }\n\n await this.keyRotationManager.rotatePrimaryKey(providerName, newKey)\n }\n}\n\n// Module augmentation for GravitoVariables\ndeclare module '@gravito/core' {\n interface GravitoVariables {\n /** Webhook receiver and dispatcher */\n echo?: OrbitEcho\n }\n}\n",
29
+ "import type { WebhookDispatcher } from '../send/WebhookDispatcher'\nimport type { OutgoingWebhookRecord, WebhookRecord, WebhookStore } from '../storage/WebhookStore'\nimport type { ReplayOptions, ReplayResult } from '../types'\n\n/**\n * Service responsible for re-sending previously dispatched webhook events.\n * This is useful for recovering from downstream outages or re-syncing data.\n *\n * @example\n * ```typescript\n * const replayService = new WebhookReplayService(store, dispatcher);\n * const result = await replayService.replay({\n * timeRange: { from: new Date('2023-01-01'), to: new Date('2023-01-02') },\n * provider: 'stripe'\n * });\n * ```\n */\nexport class WebhookReplayService {\n /**\n * Creates an instance of WebhookReplayService.\n *\n * @param store - The storage backend to query historical events.\n * @param dispatcher - The dispatcher used to re-send events.\n */\n constructor(\n private store: WebhookStore,\n private dispatcher: WebhookDispatcher\n ) {}\n\n /**\n * Replays webhook events based on the provided options.\n *\n * @param options - Criteria for selecting events and execution mode (e.g., dry run).\n * @returns A summary of the replay operation, including success and failure counts.\n * @throws {Error} If the storage query fails.\n */\n async replay(options: ReplayOptions): Promise<ReplayResult> {\n // Query events matching the criteria\n const events = await this.store.queryEvents({\n direction: 'outgoing',\n provider: options.provider,\n eventType: options.eventType,\n from: options.timeRange?.from,\n to: options.timeRange?.to,\n })\n\n // Filter by specific IDs if provided\n const targetEvents = options.eventIds\n ? events.filter((e: WebhookRecord) => options.eventIds?.includes(e.id ?? ''))\n : events\n\n const result: ReplayResult = {\n total: targetEvents.length,\n replayed: 0,\n skipped: 0,\n failed: 0,\n events: [],\n }\n\n for (const event of targetEvents) {\n if (event.direction !== 'outgoing') {\n result.skipped++\n result.events.push({\n eventId: event.id ?? 'unknown',\n status: 'skipped',\n error: 'Not an outgoing event',\n })\n continue\n }\n\n const outgoing = event as OutgoingWebhookRecord\n\n if (options.dryRun) {\n result.replayed++\n result.events.push({\n eventId: event.id ?? 'unknown',\n status: 'replayed',\n })\n continue\n }\n\n try {\n const dispatchResult = await this.dispatcher.dispatch({\n url: options.targetUrl ?? outgoing.url,\n event: outgoing.event,\n data: outgoing.payload,\n })\n\n if (dispatchResult.success) {\n result.replayed++\n result.events.push({\n eventId: event.id ?? 'unknown',\n status: 'replayed',\n result: dispatchResult,\n })\n } else {\n result.failed++\n result.events.push({\n eventId: event.id ?? 'unknown',\n status: 'failed',\n result: dispatchResult,\n error: dispatchResult.error,\n })\n }\n } catch (error) {\n result.failed++\n result.events.push({\n eventId: event.id ?? 'unknown',\n status: 'failed',\n error: String(error),\n })\n }\n }\n\n return result\n }\n}\n"
12
30
  ],
13
- "mappings": "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",
14
- "debugId": "B1111F963DAFCE1264756E2164756E21",
31
+ "mappings": "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",
32
+ "debugId": "58FA12C7769E147864756E2164756E21",
15
33
  "names": []
16
34
  }