@gravito/echo 3.0.1 → 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 (173) 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 +43 -17
  81. package/dist/core/src/CommandKernel.d.ts +33 -0
  82. package/dist/core/src/Container.d.ts +78 -14
  83. package/dist/core/src/HookManager.d.ts +422 -8
  84. package/dist/core/src/PlanetCore.d.ts +52 -7
  85. package/dist/core/src/Router.d.ts +41 -7
  86. package/dist/core/src/ServiceProvider.d.ts +14 -8
  87. package/dist/core/src/adapters/GravitoEngineAdapter.d.ts +1 -0
  88. package/dist/core/src/adapters/PhotonAdapter.d.ts +1 -0
  89. package/dist/core/src/adapters/bun/BunNativeAdapter.d.ts +1 -0
  90. package/dist/core/src/adapters/types.d.ts +39 -0
  91. package/dist/core/src/engine/AOTRouter.d.ts +1 -11
  92. package/dist/core/src/engine/FastContext.d.ts +4 -2
  93. package/dist/core/src/engine/Gravito.d.ts +1 -1
  94. package/dist/core/src/engine/MinimalContext.d.ts +4 -2
  95. package/dist/core/src/engine/types.d.ts +6 -1
  96. package/dist/core/src/events/CircuitBreaker.d.ts +229 -0
  97. package/dist/core/src/events/DeadLetterQueue.d.ts +145 -0
  98. package/dist/core/src/events/EventBackend.d.ts +11 -0
  99. package/dist/core/src/events/EventOptions.d.ts +109 -0
  100. package/dist/core/src/events/EventPriorityQueue.d.ts +202 -0
  101. package/dist/core/src/events/IdempotencyCache.d.ts +60 -0
  102. package/dist/core/src/events/index.d.ts +14 -0
  103. package/dist/core/src/events/observability/EventMetrics.d.ts +132 -0
  104. package/dist/core/src/events/observability/EventTracer.d.ts +68 -0
  105. package/dist/core/src/events/observability/EventTracing.d.ts +161 -0
  106. package/dist/core/src/events/observability/OTelEventMetrics.d.ts +240 -0
  107. package/dist/core/src/events/observability/ObservableHookManager.d.ts +108 -0
  108. package/dist/core/src/events/observability/index.d.ts +20 -0
  109. package/dist/core/src/events/observability/metrics-types.d.ts +16 -0
  110. package/dist/core/src/events/types.d.ts +75 -0
  111. package/dist/core/src/exceptions/CircularDependencyException.d.ts +9 -0
  112. package/dist/core/src/exceptions/index.d.ts +1 -0
  113. package/dist/core/src/http/cookie.d.ts +29 -0
  114. package/dist/core/src/http/types.d.ts +21 -0
  115. package/dist/core/src/index.d.ts +13 -3
  116. package/dist/core/src/instrumentation/index.d.ts +35 -0
  117. package/dist/core/src/instrumentation/opentelemetry.d.ts +178 -0
  118. package/dist/core/src/instrumentation/types.d.ts +182 -0
  119. package/dist/core/src/reliability/DeadLetterQueueManager.d.ts +316 -0
  120. package/dist/core/src/reliability/RetryPolicy.d.ts +217 -0
  121. package/dist/core/src/reliability/index.d.ts +6 -0
  122. package/dist/core/src/router/ControllerDispatcher.d.ts +12 -0
  123. package/dist/core/src/router/RequestValidator.d.ts +20 -0
  124. package/dist/echo/src/OrbitEcho.d.ts +71 -16
  125. package/dist/echo/src/dlq/DeadLetterQueue.d.ts +94 -0
  126. package/dist/echo/src/dlq/MemoryDeadLetterQueue.d.ts +36 -0
  127. package/dist/echo/src/dlq/index.d.ts +2 -0
  128. package/dist/echo/src/index.d.ts +31 -15
  129. package/dist/echo/src/middleware/RequestBufferMiddleware.d.ts +62 -0
  130. package/dist/echo/src/middleware/index.d.ts +8 -0
  131. package/dist/echo/src/observability/index.d.ts +3 -0
  132. package/dist/echo/src/observability/logging/ConsoleEchoLogger.d.ts +37 -0
  133. package/dist/echo/src/observability/logging/EchoLogger.d.ts +38 -0
  134. package/dist/echo/src/observability/logging/index.d.ts +2 -0
  135. package/dist/echo/src/observability/metrics/MetricsProvider.d.ts +69 -0
  136. package/dist/echo/src/observability/metrics/NoopMetricsProvider.d.ts +17 -0
  137. package/dist/echo/src/observability/metrics/PrometheusMetricsProvider.d.ts +39 -0
  138. package/dist/echo/src/observability/metrics/index.d.ts +3 -0
  139. package/dist/echo/src/observability/tracing/NoopTracer.d.ts +33 -0
  140. package/dist/echo/src/observability/tracing/Tracer.d.ts +75 -0
  141. package/dist/echo/src/observability/tracing/index.d.ts +2 -0
  142. package/dist/echo/src/providers/GenericProvider.d.ts +37 -18
  143. package/dist/echo/src/providers/GitHubProvider.d.ts +21 -12
  144. package/dist/echo/src/providers/LinearProvider.d.ts +27 -0
  145. package/dist/echo/src/providers/PaddleProvider.d.ts +31 -0
  146. package/dist/echo/src/providers/ShopifyProvider.d.ts +27 -0
  147. package/dist/echo/src/providers/SlackProvider.d.ts +27 -0
  148. package/dist/echo/src/providers/StripeProvider.d.ts +20 -12
  149. package/dist/echo/src/providers/TwilioProvider.d.ts +31 -0
  150. package/dist/echo/src/providers/base/BaseProvider.d.ts +87 -0
  151. package/dist/echo/src/providers/base/HeaderUtils.d.ts +34 -0
  152. package/dist/echo/src/providers/index.d.ts +14 -3
  153. package/dist/echo/src/receive/SignatureValidator.d.ts +33 -0
  154. package/dist/echo/src/receive/WebhookReceiver.d.ts +139 -21
  155. package/dist/echo/src/replay/WebhookReplayService.d.ts +35 -0
  156. package/dist/echo/src/replay/index.d.ts +1 -0
  157. package/dist/echo/src/resilience/CircuitBreaker.d.ts +117 -0
  158. package/dist/echo/src/resilience/index.d.ts +10 -0
  159. package/dist/echo/src/rotation/KeyRotationManager.d.ts +127 -0
  160. package/dist/echo/src/rotation/index.d.ts +10 -0
  161. package/dist/echo/src/send/WebhookDispatcher.d.ts +159 -15
  162. package/dist/echo/src/storage/MemoryWebhookStore.d.ts +14 -0
  163. package/dist/echo/src/storage/WebhookStore.d.ts +236 -0
  164. package/dist/echo/src/storage/index.d.ts +2 -0
  165. package/dist/echo/src/types.d.ts +656 -64
  166. package/dist/index.js +1327 -189
  167. package/dist/index.js.map +28 -10
  168. package/dist/photon/src/index.d.ts +69 -5
  169. package/dist/photon/src/middleware/binary.d.ts +12 -15
  170. package/dist/photon/src/middleware/htmx.d.ts +39 -0
  171. package/dist/photon/src/middleware/ratelimit.d.ts +157 -0
  172. package/dist/photon/src/openapi.d.ts +19 -0
  173. package/package.json +7 -5
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Abstract base class for webhook providers.
3
+ * @module @gravito/echo/providers/base
4
+ */
5
+ import type { WebhookProvider, WebhookVerificationResult } from '../../types';
6
+ /**
7
+ * Configuration options for webhook providers.
8
+ */
9
+ export interface ProviderOptions {
10
+ /**
11
+ * Maximum allowed age of the webhook request in seconds to prevent replay attacks.
12
+ * @defaultValue 300
13
+ */
14
+ tolerance?: number;
15
+ }
16
+ /**
17
+ * Base implementation for all webhook providers.
18
+ * Handles common header extraction, payload conversion, and result formatting.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * class MyProvider extends BaseProvider {
23
+ * readonly name = 'my-provider';
24
+ * async verify(payload, headers, secret) {
25
+ * // Implementation logic
26
+ * return this.createSuccess(JSON.parse(payload));
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ export declare abstract class BaseProvider implements WebhookProvider {
32
+ /** Unique identifier for the provider. */
33
+ abstract readonly name: string;
34
+ /** Time tolerance for timestamp validation. */
35
+ protected tolerance: number;
36
+ constructor(options?: ProviderOptions);
37
+ /**
38
+ * Verifies the authenticity of a webhook request.
39
+ *
40
+ * @param payload - Raw request body.
41
+ * @param headers - Request headers.
42
+ * @param secret - Provider-specific secret key.
43
+ * @returns Verification result containing the parsed payload or error message.
44
+ * @throws Error if verification logic encounters an unrecoverable failure.
45
+ */
46
+ abstract verify(payload: string | Buffer, headers: Record<string, string | string[] | undefined>, secret: string): Promise<WebhookVerificationResult>;
47
+ /**
48
+ * Extracts the event type from the verified payload.
49
+ *
50
+ * @param payload - The parsed webhook payload.
51
+ * @returns The event type string if found.
52
+ */
53
+ parseEventType?(payload: unknown): string | undefined;
54
+ /**
55
+ * Retrieves a header value in a case-insensitive manner.
56
+ */
57
+ protected getHeader(headers: Record<string, string | string[] | undefined>, name: string): string | undefined;
58
+ /**
59
+ * Checks if a specific header exists.
60
+ */
61
+ protected hasHeader(headers: Record<string, string | string[] | undefined>, name: string): boolean;
62
+ /**
63
+ * Creates a failed verification result.
64
+ */
65
+ protected createFailure(error: string): WebhookVerificationResult;
66
+ /**
67
+ * Creates a successful verification result.
68
+ */
69
+ protected createSuccess(payload: unknown, options?: {
70
+ eventType?: string;
71
+ webhookId?: string;
72
+ }): WebhookVerificationResult;
73
+ /**
74
+ * Ensures the payload is a string.
75
+ */
76
+ protected payloadToString(payload: string | Buffer): string;
77
+ /**
78
+ * Safely parses a JSON string without throwing.
79
+ */
80
+ protected safeParseJson(str: string): {
81
+ success: true;
82
+ data: unknown;
83
+ } | {
84
+ success: false;
85
+ error: string;
86
+ };
87
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Utilities for handling webhook headers.
3
+ * @module @gravito/echo/providers/base
4
+ */
5
+ /**
6
+ * Retrieves a header value from a headers object.
7
+ * Supports case-insensitive lookup by checking the original name and its lowercase version.
8
+ *
9
+ * @param headers - The headers object from the request.
10
+ * @param name - The name of the header to retrieve.
11
+ * @returns The first value of the header if found, otherwise undefined.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const sig = getHeader(headers, 'X-Webhook-Signature');
16
+ * ```
17
+ */
18
+ export declare function getHeader(headers: Record<string, string | string[] | undefined>, name: string): string | undefined;
19
+ /**
20
+ * Retrieves multiple header values at once.
21
+ *
22
+ * @param headers - The headers object from the request.
23
+ * @param names - An array of header names to retrieve.
24
+ * @returns A record mapping each requested name to its value or undefined.
25
+ */
26
+ export declare function getHeaders(headers: Record<string, string | string[] | undefined>, names: string[]): Record<string, string | undefined>;
27
+ /**
28
+ * Checks if a specific header exists in the headers object.
29
+ *
30
+ * @param headers - The headers object from the request.
31
+ * @param name - The name of the header to check.
32
+ * @returns True if the header exists and is not undefined.
33
+ */
34
+ export declare function hasHeader(headers: Record<string, string | string[] | undefined>, name: string): boolean;
@@ -1,3 +1,14 @@
1
- export * from './GenericProvider';
2
- export * from './GitHubProvider';
3
- export * from './StripeProvider';
1
+ /**
2
+ * Webhook providers for various services.
3
+ * @module @gravito/echo/providers
4
+ */
5
+ export { BaseProvider, type ProviderOptions } from './base/BaseProvider';
6
+ export { getHeader, getHeaders, hasHeader } from './base/HeaderUtils';
7
+ export { GenericProvider } from './GenericProvider';
8
+ export { GitHubProvider } from './GitHubProvider';
9
+ export { LinearProvider } from './LinearProvider';
10
+ export { PaddleProvider } from './PaddleProvider';
11
+ export { ShopifyProvider } from './ShopifyProvider';
12
+ export { SlackProvider } from './SlackProvider';
13
+ export { StripeProvider } from './StripeProvider';
14
+ export { TwilioProvider } from './TwilioProvider';
@@ -9,10 +9,43 @@
9
9
  * Compute HMAC-SHA256 signature
10
10
  */
11
11
  export declare function computeHmacSha256(payload: string | Buffer, secret: string): Promise<string>;
12
+ /**
13
+ * Computes an HMAC-SHA256 signature and returns it as a base64 encoded string.
14
+ *
15
+ * Used by providers that require base64 encoding for their signatures (e.g., Shopify).
16
+ *
17
+ * @param payload - The raw data to sign.
18
+ * @param secret - The shared secret key.
19
+ * @returns The base64 encoded HMAC-SHA256 signature.
20
+ * @throws Error if the crypto operations fail.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const sig = await computeHmacSha256Base64('data', 'secret');
25
+ * ```
26
+ */
27
+ export declare function computeHmacSha256Base64(payload: string | Buffer, secret: string): Promise<string>;
12
28
  /**
13
29
  * Compute HMAC-SHA1 signature (for legacy providers)
14
30
  */
15
31
  export declare function computeHmacSha1(payload: string | Buffer, secret: string): Promise<string>;
32
+ /**
33
+ * Computes an HMAC-SHA1 signature and returns it as a base64 encoded string.
34
+ *
35
+ * Primarily used for legacy services or specific providers like Twilio that
36
+ * still rely on SHA1-based HMAC for their webhook verification.
37
+ *
38
+ * @param payload - The raw data to sign.
39
+ * @param secret - The shared secret key.
40
+ * @returns The base64 encoded HMAC-SHA1 signature.
41
+ * @throws Error if the crypto operations fail.
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const sig = await computeHmacSha1Base64('data', 'secret');
46
+ * ```
47
+ */
48
+ export declare function computeHmacSha1Base64(payload: string | Buffer, secret: string): Promise<string>;
16
49
  /**
17
50
  * Timing-safe string comparison to prevent timing attacks
18
51
  */
@@ -5,62 +5,180 @@
5
5
  *
6
6
  * @module @gravito/echo/receive
7
7
  */
8
- import type { WebhookHandler, WebhookProvider, WebhookVerificationResult } from '../types';
9
- type ProviderClass = new (options?: any) => WebhookProvider;
8
+ import type { GravitoContext } from '@gravito/core';
9
+ import { type EchoLogger } from '../observability/logging';
10
+ import { type MetricsProvider } from '../observability/metrics';
11
+ import { type Tracer } from '../observability/tracing';
12
+ import type { KeyRotationManager } from '../rotation/KeyRotationManager';
13
+ import type { WebhookStore } from '../storage/WebhookStore';
14
+ import type { ProviderKeyEntry, WebhookHandler, WebhookProvider, WebhookVerificationResult } from '../types';
15
+ type ProviderClass = new (options?: Record<string, unknown>) => WebhookProvider;
10
16
  /**
11
- * Webhook Receiver
17
+ * WebhookReceiver orchestrates the end-to-end lifecycle of incoming webhooks.
12
18
  *
13
- * Manages webhook providers and routes incoming webhooks to handlers.
19
+ * It acts as the central intake for all incoming requests, managing provider-specific
20
+ * verification logic, multi-key rotation checks, persistent storage for auditing,
21
+ * and routing validated events to their respective application-level handlers.
14
22
  *
15
- * @example
23
+ * @example Basic usage with Stripe
16
24
  * ```typescript
17
- * const receiver = new WebhookReceiver()
25
+ * const receiver = new WebhookReceiver();
18
26
  *
19
- * // Register provider
20
- * receiver.registerProvider('stripe', process.env.STRIPE_WEBHOOK_SECRET!)
27
+ * // Register Stripe with its signing secret
28
+ * receiver.registerProvider('stripe', 'whsec_...');
21
29
  *
22
- * // Register handler
30
+ * // Listen for payment success events
23
31
  * receiver.on('stripe', 'payment_intent.succeeded', async (event) => {
24
- * console.log('Payment received:', event.payload)
25
- * })
26
- *
27
- * // Handle incoming webhook
28
- * const result = await receiver.handle('stripe', body, headers)
32
+ * const payment = event.payload;
33
+ * await processPayment(payment.id);
34
+ * });
29
35
  * ```
36
+ *
37
+ * @public
30
38
  */
31
39
  export declare class WebhookReceiver {
32
40
  private providers;
33
41
  private handlers;
34
42
  private globalHandlers;
43
+ private store?;
44
+ private metrics;
45
+ private tracer;
46
+ private logger;
47
+ private keyRotationManager?;
48
+ /**
49
+ * Initializes the receiver and registers the suite of built-in providers.
50
+ * Built-in providers include Stripe, GitHub, Shopify, Twilio, Slack, and others.
51
+ */
35
52
  constructor();
36
53
  private providerTypes;
37
54
  /**
38
- * Register a custom provider type
55
+ * Assigns a storage engine for persisting and auditing incoming webhook data.
56
+ *
57
+ * @param store - Implementation of the WebhookStore interface.
58
+ * @returns The current instance for method chaining.
59
+ */
60
+ setStore(store: WebhookStore): this;
61
+ /**
62
+ * Configures the metrics provider for performance and error monitoring.
63
+ *
64
+ * @param metrics - Implementation of the MetricsProvider interface.
65
+ * @returns The current instance for method chaining.
66
+ */
67
+ setMetrics(metrics: MetricsProvider): this;
68
+ /**
69
+ * Configures the tracer for end-to-end request observability.
70
+ *
71
+ * @param tracer - Implementation of the Tracer interface.
72
+ * @returns The current instance for method chaining.
73
+ */
74
+ setTracer(tracer: Tracer): this;
75
+ /**
76
+ * Configures the logger for diagnostic and security audit logging.
77
+ *
78
+ * @param logger - Implementation of the EchoLogger interface.
79
+ * @returns The current instance for method chaining.
80
+ */
81
+ setLogger(logger: EchoLogger): this;
82
+ /**
83
+ * Attaches a key rotation manager for handling dynamic secret updates.
84
+ *
85
+ * @param manager - Instance of KeyRotationManager.
86
+ * @returns The current instance for method chaining.
87
+ */
88
+ setKeyRotationManager(manager: KeyRotationManager): this;
89
+ /**
90
+ * Extends the receiver with a custom webhook provider implementation.
91
+ *
92
+ * Use this to add support for services not included in the built-in provider set.
93
+ *
94
+ * @param name - Unique identifier for the provider type (e.g., 'custom-crm').
95
+ * @param ProviderCls - Constructor for the class implementing WebhookProvider.
96
+ * @returns The current instance for method chaining.
39
97
  */
40
98
  registerProviderType(name: string, ProviderCls: ProviderClass): this;
41
99
  /**
42
- * Register a provider with its secret
100
+ * Configures a named provider instance with its security credentials.
101
+ *
102
+ * @param name - Unique identifier for this provider instance (used in routing).
103
+ * @param secret - The shared secret used to verify incoming request signatures.
104
+ * @param options - Settings like the provider type and signature time tolerance.
105
+ * @returns The current instance for method chaining.
106
+ * @throws {Error} If the specified provider type has not been registered.
43
107
  */
44
108
  registerProvider(name: string, secret: string, options?: {
45
109
  type?: string;
46
110
  tolerance?: number;
47
111
  }): this;
48
112
  /**
49
- * Register an event handler
113
+ * Registers a provider instance with support for multiple secrets and rotation.
114
+ *
115
+ * This is the preferred registration method for high-availability environments
116
+ * where zero-downtime key rotation is required.
117
+ *
118
+ * @param name - Unique identifier for this provider instance.
119
+ * @param keys - A list of valid keys (active and pending) for this provider.
120
+ * @param options - Settings like the provider type and signature time tolerance.
121
+ * @returns The current instance for method chaining.
122
+ * @throws {Error} If KeyRotationManager is not set or the provider type is unknown.
123
+ */
124
+ registerProviderWithRotation(name: string, keys: ProviderKeyEntry[], options?: {
125
+ type?: string;
126
+ tolerance?: number;
127
+ }): this;
128
+ /**
129
+ * Subscribes a handler function to a specific event type from a provider.
130
+ *
131
+ * @param providerName - The name of the registered provider instance.
132
+ * @param eventType - The exact semantic type of the event (e.g., 'order.placed').
133
+ * @param handler - The asynchronous function to execute when a matching event arrives.
134
+ * @returns The current instance for method chaining.
50
135
  */
51
136
  on<T = unknown>(providerName: string, eventType: string, handler: WebhookHandler<T>): this;
52
137
  /**
53
- * Register a handler for all events from a provider
138
+ * Subscribes a catch-all handler for all valid events from a specific provider.
139
+ *
140
+ * @param providerName - The name of the registered provider instance.
141
+ * @param handler - Function to execute for every authenticated event from this provider.
142
+ * @returns The current instance for method chaining.
54
143
  */
55
144
  onAll<T = unknown>(providerName: string, handler: WebhookHandler<T>): this;
56
145
  /**
57
- * Handle an incoming webhook
146
+ * Orchestrates the verification and asynchronous processing of an incoming webhook.
147
+ *
148
+ * This is the main entry point for requests. It performs the following:
149
+ * 1. Signature validation (supporting multi-key fallback if rotation is enabled).
150
+ * 2. Event persistence to storage for audit trails.
151
+ * 3. Execution of all matching event-specific and global handlers.
152
+ * 4. Automatic instrumentation for metrics and tracing.
153
+ *
154
+ * @param providerName - The name of the provider instance targeted by the request.
155
+ * @param body - The raw request body as received from the socket.
156
+ * @param headers - Complete set of HTTP headers for signature extraction.
157
+ * @param context - Optional Gravito context for accessing buffered requests.
158
+ * @returns Verification status, event metadata, and processing result.
159
+ * @throws {Error} If handler execution or event storage fails.
58
160
  */
59
- handle(providerName: string, body: string | Buffer, headers: Record<string, string | string[] | undefined>): Promise<WebhookVerificationResult & {
161
+ handle(providerName: string, body: string | Buffer, headers: Record<string, string | string[] | undefined>, context?: GravitoContext): Promise<WebhookVerificationResult & {
60
162
  handled: boolean;
163
+ eventId?: string;
61
164
  }>;
62
165
  /**
63
- * Verify a webhook without handling
166
+ * Internal utility to categorize verification errors for metrics reporting.
167
+ *
168
+ * @param error - The raw error message from the provider or rotation manager.
169
+ * @returns A semantic error category string (e.g., 'missing_header', 'signature_invalid').
170
+ */
171
+ private categorizeError;
172
+ /**
173
+ * Performs a standalone signature verification without triggering side-effects.
174
+ *
175
+ * This method verifies the authenticity of a webhook request without persisting it
176
+ * to storage or executing any registered handlers. Useful for pre-validation logic.
177
+ *
178
+ * @param providerName - The identifier of the provider instance to use for verification.
179
+ * @param body - The raw request body.
180
+ * @param headers - The incoming HTTP headers.
181
+ * @returns A promise resolving to the verification result.
64
182
  */
65
183
  verify(providerName: string, body: string | Buffer, headers: Record<string, string | string[] | undefined>): Promise<WebhookVerificationResult>;
66
184
  }
@@ -0,0 +1,35 @@
1
+ import type { WebhookDispatcher } from '../send/WebhookDispatcher';
2
+ import type { WebhookStore } from '../storage/WebhookStore';
3
+ import type { ReplayOptions, ReplayResult } from '../types';
4
+ /**
5
+ * Service responsible for re-sending previously dispatched webhook events.
6
+ * This is useful for recovering from downstream outages or re-syncing data.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const replayService = new WebhookReplayService(store, dispatcher);
11
+ * const result = await replayService.replay({
12
+ * timeRange: { from: new Date('2023-01-01'), to: new Date('2023-01-02') },
13
+ * provider: 'stripe'
14
+ * });
15
+ * ```
16
+ */
17
+ export declare class WebhookReplayService {
18
+ private store;
19
+ private dispatcher;
20
+ /**
21
+ * Creates an instance of WebhookReplayService.
22
+ *
23
+ * @param store - The storage backend to query historical events.
24
+ * @param dispatcher - The dispatcher used to re-send events.
25
+ */
26
+ constructor(store: WebhookStore, dispatcher: WebhookDispatcher);
27
+ /**
28
+ * Replays webhook events based on the provided options.
29
+ *
30
+ * @param options - Criteria for selecting events and execution mode (e.g., dry run).
31
+ * @returns A summary of the replay operation, including success and failure counts.
32
+ * @throws {Error} If the storage query fails.
33
+ */
34
+ replay(options: ReplayOptions): Promise<ReplayResult>;
35
+ }
@@ -0,0 +1 @@
1
+ export * from './WebhookReplayService';
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Implementation of the Circuit Breaker pattern.
3
+ *
4
+ * Protects downstream services from cascading failures by monitoring error rates
5
+ * and temporarily "tripping" the circuit when thresholds are exceeded. This
6
+ * prevents unnecessary load on struggling services and allows them time to recover.
7
+ *
8
+ * @module @gravito/echo/resilience
9
+ * @since 1.1.0
10
+ */
11
+ import type { CircuitBreakerConfig, CircuitBreakerMetrics, CircuitBreakerState } from '../types';
12
+ /**
13
+ * State machine for managing downstream service availability via the Circuit Breaker pattern.
14
+ *
15
+ * This implementation tracks failures and successes to determine one of three states:
16
+ * - `CLOSED`: Healthy state. All requests are executed normally.
17
+ * - `OPEN`: Failing state. Trip thresholds exceeded; requests are rejected immediately to
18
+ * prevent cascading failure and give the target system time to recover.
19
+ * - `HALF_OPEN`: Recovery phase. Allows a limited number of test requests to determine
20
+ * if the downstream service has restored functionality.
21
+ *
22
+ * @example Protecting a fragile API call
23
+ * ```typescript
24
+ * const breaker = new CircuitBreaker('inventory-service', {
25
+ * failureThreshold: 5,
26
+ * openTimeout: 60000 // Stay open for 1 minute before testing recovery
27
+ * });
28
+ *
29
+ * try {
30
+ * const stock = await breaker.execute(async () => {
31
+ * return await apiClient.getInventory();
32
+ * });
33
+ * } catch (error) {
34
+ * if (error.message.includes('Circuit breaker is OPEN')) {
35
+ * // Redirect to fallback or return cached data
36
+ * }
37
+ * }
38
+ * ```
39
+ *
40
+ * @public
41
+ */
42
+ export declare class CircuitBreaker {
43
+ private readonly name;
44
+ private state;
45
+ private failures;
46
+ private successes;
47
+ private lastFailureAt?;
48
+ private lastSuccessAt?;
49
+ private openedAt?;
50
+ private halfOpenAttempts;
51
+ private config;
52
+ /**
53
+ * Constructs a new CircuitBreaker for a specific resource, host, or service.
54
+ *
55
+ * @param name - A semantic identifier for the target being protected.
56
+ * @param config - Policy settings for failure thresholds, recovery timeouts, and callbacks.
57
+ */
58
+ constructor(name: string, config?: CircuitBreakerConfig);
59
+ /**
60
+ * Executes an asynchronous operation within the safety window of the circuit breaker.
61
+ *
62
+ * This method will proactively check the circuit state. If the state is `OPEN`, it will
63
+ * throw an error immediately without invoking the provided function.
64
+ *
65
+ * @param fn - The asynchronous operation to be protected.
66
+ * @returns A promise resolving to the result of the protected operation.
67
+ * @throws {Error} If the circuit is currently `OPEN` or if the underlying operation fails.
68
+ */
69
+ execute<T>(fn: () => Promise<T>): Promise<T>;
70
+ /**
71
+ * Records a successful operation and updates the state machine.
72
+ * In `HALF_OPEN` state, this contributes to the success threshold for closing the circuit.
73
+ */
74
+ private onSuccess;
75
+ /**
76
+ * Records a failed operation and determines if the circuit should trip to `OPEN`.
77
+ * Any failure in `HALF_OPEN` state immediately trips the circuit back to `OPEN`.
78
+ */
79
+ private onFailure;
80
+ /**
81
+ * Evaluates and performs automatic state transitions based on elapsed time and thresholds.
82
+ */
83
+ private checkStateTransition;
84
+ /**
85
+ * Transitions the circuit to a new state and executes configured lifecycle callbacks.
86
+ *
87
+ * @param newState - The target state to transition into.
88
+ */
89
+ private transitionTo;
90
+ /**
91
+ * Resets all internal counters and timers to their initial baseline state.
92
+ */
93
+ private reset;
94
+ /**
95
+ * Retrieves a snapshot of the current health and performance metrics of the circuit.
96
+ *
97
+ * @returns An object containing state, failure counts, and activity timestamps.
98
+ */
99
+ getMetrics(): CircuitBreakerMetrics;
100
+ /**
101
+ * Forcefully resets the circuit breaker to the `CLOSED` state.
102
+ * Useful for manual recovery scenarios after a service has been verified healthy.
103
+ */
104
+ manualReset(): void;
105
+ /**
106
+ * Returns the current operational state of the circuit breaker.
107
+ *
108
+ * @returns The current state identifier.
109
+ */
110
+ getState(): CircuitBreakerState;
111
+ /**
112
+ * Returns the semantic name assigned to this circuit breaker instance.
113
+ *
114
+ * @returns The name identifier.
115
+ */
116
+ getName(): string;
117
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Echo Resilience
3
+ *
4
+ * 提供彈性與容錯機制
5
+ *
6
+ * @module @gravito/echo/resilience
7
+ * @since v1.1
8
+ */
9
+ export type { CircuitBreakerConfig, CircuitBreakerMetrics, CircuitBreakerState } from '../types';
10
+ export { CircuitBreaker } from './CircuitBreaker';
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @fileoverview Key Rotation Manager
3
+ *
4
+ * Manages the lifecycle of webhook provider secrets, including multi-version
5
+ * support, automatic cleanup, and grace periods for smooth transitions.
6
+ *
7
+ * @module @gravito/echo/rotation
8
+ * @since v1.2
9
+ */
10
+ import type { KeyRotationConfig, ProviderKeyEntry } from '../types';
11
+ /**
12
+ * KeyRotationManager orchestrates the lifecycle of webhook provider secrets.
13
+ *
14
+ * It provides a central hub for managing multiple concurrent versions of signing
15
+ * secrets, enabling zero-downtime rotation. By maintaining a set of "active"
16
+ * keys (including those in a grace period), it ensures that webhooks signed
17
+ * with either an old or new secret are successfully verified during transition.
18
+ *
19
+ * Key features:
20
+ * - Multi-version secret management.
21
+ * - Automatic background cleanup of expired keys.
22
+ * - Grace period support for smooth cut-overs.
23
+ * - Promotion of new primary keys.
24
+ *
25
+ * @example Managing zero-downtime rotation
26
+ * ```typescript
27
+ * const manager = new KeyRotationManager({
28
+ * gracePeriod: 86400000, // 24 hours
29
+ * autoCleanup: true,
30
+ * });
31
+ *
32
+ * // Register initial keys
33
+ * manager.registerKeys('stripe', [
34
+ * {
35
+ * key: 'whsec_primary',
36
+ * version: 'v2',
37
+ * isPrimary: true,
38
+ * activeFrom: new Date(),
39
+ * }
40
+ * ]);
41
+ *
42
+ * // Rotate to a new secret
43
+ * await manager.rotatePrimaryKey('stripe', {
44
+ * key: 'whsec_new_secret',
45
+ * version: 'v3',
46
+ * activeFrom: new Date(),
47
+ * });
48
+ * ```
49
+ *
50
+ * @public
51
+ */
52
+ export declare class KeyRotationManager {
53
+ private providerKeys;
54
+ private cleanupTimer?;
55
+ private config;
56
+ /**
57
+ * Constructs a new KeyRotationManager with the specified policy.
58
+ *
59
+ * @param config - Configuration for auto-cleanup, grace periods, and rotation hooks.
60
+ */
61
+ constructor(config?: KeyRotationConfig);
62
+ /**
63
+ * Registers a collection of keys for a specific provider.
64
+ *
65
+ * Validation ensures that exactly one primary key is specified for the provider.
66
+ *
67
+ * @param providerName - Canonical name of the provider instance.
68
+ * @param keys - Array of valid key entries with metadata.
69
+ * @throws {Error} If no primary key is provided or if multiple primary keys are detected.
70
+ */
71
+ registerKeys(providerName: string, keys: ProviderKeyEntry[]): void;
72
+ /**
73
+ * Retrieves all currently valid keys for a provider to attempt verification.
74
+ *
75
+ * A key is considered active if the current time is after its `activeFrom` date
76
+ * and before its `expiresAt` date (if defined).
77
+ *
78
+ * @param providerName - Canonical name of the provider instance.
79
+ * @returns An array of currently active key entries.
80
+ */
81
+ getActiveKeys(providerName: string): ProviderKeyEntry[];
82
+ /**
83
+ * Retrieves the current primary key used for signature generation.
84
+ *
85
+ * @param providerName - Canonical name of the provider instance.
86
+ * @returns The primary key entry, or null if no active primary key exists.
87
+ */
88
+ getPrimaryKey(providerName: string): ProviderKeyEntry | null;
89
+ /**
90
+ * Promotes a new primary key for the provider and retires the old one.
91
+ *
92
+ * The previous primary key is automatically assigned an expiration date based on
93
+ * the configured `gracePeriod`, allowing it to remain valid for incoming requests
94
+ * that were signed before the rotation propagated.
95
+ *
96
+ * @param providerName - Canonical name of the provider instance.
97
+ * @param newKey - Metadata and secret for the new primary key.
98
+ */
99
+ rotatePrimaryKey(providerName: string, newKey: Omit<ProviderKeyEntry, 'isPrimary'>): Promise<void>;
100
+ /**
101
+ * Manually triggers a purge of all expired keys across all providers.
102
+ *
103
+ * @returns The total number of keys removed during this cycle.
104
+ */
105
+ cleanupExpiredKeys(): number;
106
+ /**
107
+ * Initializes the background timer for periodic key purging.
108
+ */
109
+ private startAutoCleanup;
110
+ /**
111
+ * Stops the auto-cleanup background process.
112
+ */
113
+ destroy(): void;
114
+ /**
115
+ * Provides a read-only snapshot of all keys across all providers.
116
+ *
117
+ * @returns A map of provider names to their complete key history.
118
+ */
119
+ getAllProviderKeys(): Map<string, ProviderKeyEntry[]>;
120
+ /**
121
+ * Checks if a specific provider has any keys registered in the manager.
122
+ *
123
+ * @param providerName - Canonical name of the provider instance.
124
+ * @returns True if the provider is tracked.
125
+ */
126
+ hasProvider(providerName: string): boolean;
127
+ }