awaitly 1.0.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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1278 -0
  3. package/dist/batch.cjs +2 -0
  4. package/dist/batch.cjs.map +1 -0
  5. package/dist/batch.d.cts +197 -0
  6. package/dist/batch.d.ts +197 -0
  7. package/dist/batch.js +2 -0
  8. package/dist/batch.js.map +1 -0
  9. package/dist/circuit-breaker.cjs +2 -0
  10. package/dist/circuit-breaker.cjs.map +1 -0
  11. package/dist/circuit-breaker.d.cts +208 -0
  12. package/dist/circuit-breaker.d.ts +208 -0
  13. package/dist/circuit-breaker.js +2 -0
  14. package/dist/circuit-breaker.js.map +1 -0
  15. package/dist/conditional.cjs +2 -0
  16. package/dist/conditional.cjs.map +1 -0
  17. package/dist/conditional.d.cts +249 -0
  18. package/dist/conditional.d.ts +249 -0
  19. package/dist/conditional.js +2 -0
  20. package/dist/conditional.js.map +1 -0
  21. package/dist/core-BuTBsR0x.d.cts +2325 -0
  22. package/dist/core-BuTBsR0x.d.ts +2325 -0
  23. package/dist/core.cjs +2 -0
  24. package/dist/core.cjs.map +1 -0
  25. package/dist/core.d.cts +3 -0
  26. package/dist/core.d.ts +3 -0
  27. package/dist/core.js +2 -0
  28. package/dist/core.js.map +1 -0
  29. package/dist/devtools.cjs +11 -0
  30. package/dist/devtools.cjs.map +1 -0
  31. package/dist/devtools.d.cts +176 -0
  32. package/dist/devtools.d.ts +176 -0
  33. package/dist/devtools.js +11 -0
  34. package/dist/devtools.js.map +1 -0
  35. package/dist/duration.cjs +2 -0
  36. package/dist/duration.cjs.map +1 -0
  37. package/dist/duration.d.cts +246 -0
  38. package/dist/duration.d.ts +246 -0
  39. package/dist/duration.js +2 -0
  40. package/dist/duration.js.map +1 -0
  41. package/dist/hitl.cjs +2 -0
  42. package/dist/hitl.cjs.map +1 -0
  43. package/dist/hitl.d.cts +337 -0
  44. package/dist/hitl.d.ts +337 -0
  45. package/dist/hitl.js +2 -0
  46. package/dist/hitl.js.map +1 -0
  47. package/dist/index.cjs +2 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.cts +4 -0
  50. package/dist/index.d.ts +4 -0
  51. package/dist/index.js +2 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/match.cjs +2 -0
  54. package/dist/match.cjs.map +1 -0
  55. package/dist/match.d.cts +209 -0
  56. package/dist/match.d.ts +209 -0
  57. package/dist/match.js +2 -0
  58. package/dist/match.js.map +1 -0
  59. package/dist/otel.cjs +2 -0
  60. package/dist/otel.cjs.map +1 -0
  61. package/dist/otel.d.cts +185 -0
  62. package/dist/otel.d.ts +185 -0
  63. package/dist/otel.js +2 -0
  64. package/dist/otel.js.map +1 -0
  65. package/dist/persistence.cjs +2 -0
  66. package/dist/persistence.cjs.map +1 -0
  67. package/dist/persistence.d.cts +572 -0
  68. package/dist/persistence.d.ts +572 -0
  69. package/dist/persistence.js +2 -0
  70. package/dist/persistence.js.map +1 -0
  71. package/dist/policies.cjs +2 -0
  72. package/dist/policies.cjs.map +1 -0
  73. package/dist/policies.d.cts +378 -0
  74. package/dist/policies.d.ts +378 -0
  75. package/dist/policies.js +2 -0
  76. package/dist/policies.js.map +1 -0
  77. package/dist/ratelimit.cjs +2 -0
  78. package/dist/ratelimit.cjs.map +1 -0
  79. package/dist/ratelimit.d.cts +279 -0
  80. package/dist/ratelimit.d.ts +279 -0
  81. package/dist/ratelimit.js +2 -0
  82. package/dist/ratelimit.js.map +1 -0
  83. package/dist/reliability.cjs +2 -0
  84. package/dist/reliability.cjs.map +1 -0
  85. package/dist/reliability.d.cts +5 -0
  86. package/dist/reliability.d.ts +5 -0
  87. package/dist/reliability.js +2 -0
  88. package/dist/reliability.js.map +1 -0
  89. package/dist/resource.cjs +2 -0
  90. package/dist/resource.cjs.map +1 -0
  91. package/dist/resource.d.cts +171 -0
  92. package/dist/resource.d.ts +171 -0
  93. package/dist/resource.js +2 -0
  94. package/dist/resource.js.map +1 -0
  95. package/dist/retry.cjs +2 -0
  96. package/dist/retry.cjs.map +1 -0
  97. package/dist/retry.d.cts +2 -0
  98. package/dist/retry.d.ts +2 -0
  99. package/dist/retry.js +2 -0
  100. package/dist/retry.js.map +1 -0
  101. package/dist/saga.cjs +2 -0
  102. package/dist/saga.cjs.map +1 -0
  103. package/dist/saga.d.cts +231 -0
  104. package/dist/saga.d.ts +231 -0
  105. package/dist/saga.js +2 -0
  106. package/dist/saga.js.map +1 -0
  107. package/dist/schedule.cjs +2 -0
  108. package/dist/schedule.cjs.map +1 -0
  109. package/dist/schedule.d.cts +387 -0
  110. package/dist/schedule.d.ts +387 -0
  111. package/dist/schedule.js +2 -0
  112. package/dist/schedule.js.map +1 -0
  113. package/dist/tagged-error.cjs +2 -0
  114. package/dist/tagged-error.cjs.map +1 -0
  115. package/dist/tagged-error.d.cts +252 -0
  116. package/dist/tagged-error.d.ts +252 -0
  117. package/dist/tagged-error.js +2 -0
  118. package/dist/tagged-error.js.map +1 -0
  119. package/dist/testing.cjs +2 -0
  120. package/dist/testing.cjs.map +1 -0
  121. package/dist/testing.d.cts +228 -0
  122. package/dist/testing.d.ts +228 -0
  123. package/dist/testing.js +2 -0
  124. package/dist/testing.js.map +1 -0
  125. package/dist/visualize.cjs +1573 -0
  126. package/dist/visualize.cjs.map +1 -0
  127. package/dist/visualize.d.cts +1415 -0
  128. package/dist/visualize.d.ts +1415 -0
  129. package/dist/visualize.js +1573 -0
  130. package/dist/visualize.js.map +1 -0
  131. package/dist/webhook.cjs +2 -0
  132. package/dist/webhook.cjs.map +1 -0
  133. package/dist/webhook.d.cts +469 -0
  134. package/dist/webhook.d.ts +469 -0
  135. package/dist/webhook.js +2 -0
  136. package/dist/webhook.js.map +1 -0
  137. package/dist/workflow-entry-C6nH8ByN.d.ts +858 -0
  138. package/dist/workflow-entry-RRTlSg_4.d.cts +858 -0
  139. package/dist/workflow.cjs +2 -0
  140. package/dist/workflow.cjs.map +1 -0
  141. package/dist/workflow.d.cts +2 -0
  142. package/dist/workflow.d.ts +2 -0
  143. package/dist/workflow.js +2 -0
  144. package/dist/workflow.js.map +1 -0
  145. package/docs/advanced.md +1548 -0
  146. package/docs/api.md +513 -0
  147. package/docs/coming-from-neverthrow.md +1013 -0
  148. package/docs/match.md +417 -0
  149. package/docs/pino-logging-example.md +396 -0
  150. package/docs/policies.md +508 -0
  151. package/docs/resource-management.md +509 -0
  152. package/docs/schedule.md +467 -0
  153. package/docs/tagged-error.md +785 -0
  154. package/docs/visualization.md +430 -0
  155. package/docs/visualize-examples.md +330 -0
  156. package/package.json +227 -0
@@ -0,0 +1,469 @@
1
+ import { R as Result, U as UnexpectedError, A as AsyncResult } from './core-BuTBsR0x.js';
2
+ import { b as Workflow, c as WorkflowStrict } from './workflow-entry-C6nH8ByN.js';
3
+
4
+ /**
5
+ * awaitly/webhook
6
+ *
7
+ * Webhook and event trigger adapters for exposing workflows as HTTP endpoints.
8
+ * Framework-agnostic handlers that work with Express, Hono, Fastify, etc.
9
+ */
10
+
11
+ /**
12
+ * Generic HTTP request representation.
13
+ * Abstracts away framework-specific request objects.
14
+ */
15
+ interface WebhookRequest<Body = unknown> {
16
+ /** HTTP method (GET, POST, PUT, DELETE, etc.) */
17
+ method: string;
18
+ /** Request path (e.g., "/api/checkout") */
19
+ path: string;
20
+ /** Request headers */
21
+ headers: Record<string, string | string[] | undefined>;
22
+ /** Parsed request body (JSON) */
23
+ body: Body;
24
+ /** Query parameters */
25
+ query: Record<string, string | string[] | undefined>;
26
+ /** Path parameters (e.g., { id: "123" }) */
27
+ params: Record<string, string>;
28
+ /** Raw request object from framework (for advanced use cases) */
29
+ raw?: unknown;
30
+ }
31
+ /**
32
+ * Generic HTTP response representation.
33
+ */
34
+ interface WebhookResponse<T = unknown> {
35
+ /** HTTP status code */
36
+ status: number;
37
+ /** Response headers */
38
+ headers?: Record<string, string>;
39
+ /** Response body (will be JSON serialized) */
40
+ body: T;
41
+ }
42
+ /**
43
+ * Error response body structure.
44
+ */
45
+ interface ErrorResponseBody {
46
+ error: {
47
+ type: string;
48
+ message?: string;
49
+ details?: unknown;
50
+ };
51
+ }
52
+ /**
53
+ * Input validation result.
54
+ */
55
+ type ValidationResult<T, E = string> = Result<T, E>;
56
+ /**
57
+ * Standard validation error type.
58
+ */
59
+ interface ValidationError {
60
+ type: "VALIDATION_ERROR";
61
+ message: string;
62
+ field?: string;
63
+ details?: unknown;
64
+ }
65
+ /**
66
+ * Type guard for ValidationError.
67
+ */
68
+ declare function isValidationError(e: unknown): e is ValidationError;
69
+ /**
70
+ * Configuration for creating a webhook handler.
71
+ *
72
+ * @template TInput - The validated input type
73
+ * @template TOutput - The workflow output type
74
+ * @template TError - The workflow error type
75
+ * @template TBody - The raw request body type
76
+ */
77
+ interface WebhookHandlerConfig<TInput, TOutput, TError, TBody = unknown> {
78
+ /**
79
+ * Validate and transform the incoming request.
80
+ * Return ok(input) to proceed, or err(validationError) to reject.
81
+ *
82
+ * @param req - The incoming request
83
+ * @returns Validated input or validation error
84
+ */
85
+ validateInput: (req: WebhookRequest<TBody>) => ValidationResult<TInput, ValidationError> | Promise<ValidationResult<TInput, ValidationError>>;
86
+ /**
87
+ * Map workflow result to HTTP response.
88
+ * Called for both success and error cases.
89
+ *
90
+ * @param result - The workflow result
91
+ * @param req - The original request (for context)
92
+ * @returns HTTP response
93
+ */
94
+ mapResult: (result: Result<TOutput, TError | UnexpectedError>, req: WebhookRequest<TBody>) => WebhookResponse;
95
+ /**
96
+ * Optional: Map validation errors to HTTP response.
97
+ * Defaults to 400 Bad Request with error details.
98
+ *
99
+ * @param error - The validation error
100
+ * @param req - The original request
101
+ * @returns HTTP response
102
+ */
103
+ mapValidationError?: (error: ValidationError, req: WebhookRequest<TBody>) => WebhookResponse<ErrorResponseBody>;
104
+ /**
105
+ * Optional: Handle unexpected errors during request processing.
106
+ * Defaults to 500 Internal Server Error.
107
+ *
108
+ * @param error - The unexpected error
109
+ * @param req - The original request
110
+ * @returns HTTP response
111
+ */
112
+ mapUnexpectedError?: (error: unknown, req: WebhookRequest<TBody>) => WebhookResponse<ErrorResponseBody>;
113
+ /**
114
+ * Optional: Request middleware.
115
+ * Transform or enrich the request before validation.
116
+ *
117
+ * @param req - The incoming request
118
+ * @returns Transformed request
119
+ */
120
+ beforeValidation?: (req: WebhookRequest<TBody>) => WebhookRequest<TBody> | Promise<WebhookRequest<TBody>>;
121
+ /**
122
+ * Optional: Response middleware.
123
+ * Transform the response before sending.
124
+ *
125
+ * @param response - The response to send
126
+ * @param req - The original request
127
+ * @returns Transformed response
128
+ */
129
+ afterResponse?: (response: WebhookResponse, req: WebhookRequest<TBody>) => WebhookResponse | Promise<WebhookResponse>;
130
+ }
131
+ /**
132
+ * A webhook handler function that processes requests.
133
+ */
134
+ type WebhookHandler<TBody = unknown> = (req: WebhookRequest<TBody>) => Promise<WebhookResponse>;
135
+ /**
136
+ * Default validation error mapper.
137
+ * Returns 400 Bad Request with error details.
138
+ */
139
+ declare function defaultValidationErrorMapper(error: ValidationError): WebhookResponse<ErrorResponseBody>;
140
+ /**
141
+ * Default unexpected error mapper.
142
+ * Returns 500 Internal Server Error.
143
+ */
144
+ declare function defaultUnexpectedErrorMapper(_error: unknown): WebhookResponse<ErrorResponseBody>;
145
+ /**
146
+ * Create a webhook handler for a workflow.
147
+ *
148
+ * This factory creates an HTTP handler function that:
149
+ * 1. Validates the incoming request
150
+ * 2. Executes the workflow with the validated input
151
+ * 3. Maps the result to an HTTP response
152
+ *
153
+ * The handler is framework-agnostic and returns a standard response object.
154
+ * Use framework adapters (createExpressHandler, createHonoHandler, etc.) to
155
+ * integrate with specific frameworks.
156
+ *
157
+ * @template TInput - The validated input type passed to the workflow
158
+ * @template TOutput - The workflow output type
159
+ * @template TError - The workflow error type
160
+ * @template TBody - The raw request body type
161
+ * @template TDeps - The workflow dependencies type
162
+ *
163
+ * @param workflow - The workflow function to execute
164
+ * @param workflowFn - The workflow body function (step, deps, input) => output
165
+ * @param config - Handler configuration
166
+ * @returns A webhook handler function
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * const checkoutWorkflow = createWorkflow({ chargeCard, sendEmail });
171
+ *
172
+ * const handler = createWebhookHandler(
173
+ * checkoutWorkflow,
174
+ * async (step, deps, input: CheckoutInput) => {
175
+ * const charge = await step(() => deps.chargeCard(input.amount));
176
+ * await step(() => deps.sendEmail(input.email, charge.receiptUrl));
177
+ * return { chargeId: charge.id };
178
+ * },
179
+ * {
180
+ * validateInput: (req) => {
181
+ * const { amount, email } = req.body;
182
+ * if (!amount || !email) {
183
+ * return err({ type: 'VALIDATION_ERROR', message: 'Missing required fields' });
184
+ * }
185
+ * return ok({ amount, email });
186
+ * },
187
+ * mapResult: (result) => {
188
+ * if (result.ok) {
189
+ * return { status: 200, body: result.value };
190
+ * }
191
+ * if (result.error === 'CARD_DECLINED') {
192
+ * return { status: 402, body: { error: { type: 'CARD_DECLINED' } } };
193
+ * }
194
+ * return { status: 500, body: { error: { type: 'UNKNOWN' } } };
195
+ * },
196
+ * }
197
+ * );
198
+ *
199
+ * // Use with Express
200
+ * app.post('/checkout', async (req, res) => {
201
+ * const response = await handler(toWebhookRequest(req));
202
+ * res.status(response.status).json(response.body);
203
+ * });
204
+ * ```
205
+ */
206
+ declare function createWebhookHandler<TInput, TOutput, TError, TBody = unknown, TDeps = unknown>(workflow: Workflow<TError, TDeps> | WorkflowStrict<TError, unknown, TDeps>, workflowFn: (step: Parameters<Parameters<Workflow<TError, TDeps>>[1]>[0], deps: TDeps, input: TInput) => TOutput | Promise<TOutput>, config: WebhookHandlerConfig<TInput, TOutput, TError, TBody>): WebhookHandler<TBody>;
207
+ /**
208
+ * Configuration for a simple webhook handler without workflow.
209
+ */
210
+ interface SimpleHandlerConfig<TInput, TOutput, TError, TBody = unknown> {
211
+ validateInput: (req: WebhookRequest<TBody>) => ValidationResult<TInput, ValidationError> | Promise<ValidationResult<TInput, ValidationError>>;
212
+ handler: (input: TInput, req: WebhookRequest<TBody>) => AsyncResult<TOutput, TError>;
213
+ mapResult: (result: Result<TOutput, TError>, req: WebhookRequest<TBody>) => WebhookResponse;
214
+ mapValidationError?: (error: ValidationError, req: WebhookRequest<TBody>) => WebhookResponse<ErrorResponseBody>;
215
+ mapUnexpectedError?: (error: unknown, req: WebhookRequest<TBody>) => WebhookResponse<ErrorResponseBody>;
216
+ }
217
+ /**
218
+ * Create a simple webhook handler without workflow orchestration.
219
+ * Useful for simple endpoints that don't need step-based error handling.
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * const handler = createSimpleHandler({
224
+ * validateInput: (req) => {
225
+ * const { id } = req.params;
226
+ * if (!id) return err({ type: 'VALIDATION_ERROR', message: 'Missing id' });
227
+ * return ok({ id });
228
+ * },
229
+ * handler: async ({ id }) => {
230
+ * const user = await db.findUser(id);
231
+ * return user ? ok(user) : err('NOT_FOUND' as const);
232
+ * },
233
+ * mapResult: (result) => {
234
+ * if (result.ok) return { status: 200, body: result.value };
235
+ * return { status: 404, body: { error: { type: 'NOT_FOUND' } } };
236
+ * },
237
+ * });
238
+ * ```
239
+ */
240
+ declare function createSimpleHandler<TInput, TOutput, TError, TBody = unknown>(config: SimpleHandlerConfig<TInput, TOutput, TError, TBody>): WebhookHandler<TBody>;
241
+ /**
242
+ * Standard error mapping configuration.
243
+ */
244
+ interface ErrorMapping<TError> {
245
+ /** The error value to match */
246
+ error: TError;
247
+ /** HTTP status code for this error */
248
+ status: number;
249
+ /** Optional custom message */
250
+ message?: string;
251
+ }
252
+ /**
253
+ * Create a result mapper from error mappings.
254
+ * Provides a declarative way to map workflow errors to HTTP responses.
255
+ *
256
+ * @param mappings - Array of error mappings
257
+ * @param defaultStatus - Default status for unmapped errors (default: 500)
258
+ * @returns A mapResult function for use in handler config
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * const mapResult = createResultMapper<CheckoutOutput, CheckoutError>([
263
+ * { error: 'NOT_FOUND', status: 404, message: 'Resource not found' },
264
+ * { error: 'CARD_DECLINED', status: 402, message: 'Payment failed' },
265
+ * { error: 'RATE_LIMITED', status: 429, message: 'Too many requests' },
266
+ * ]);
267
+ *
268
+ * const handler = createWebhookHandler(workflow, workflowFn, {
269
+ * validateInput,
270
+ * mapResult,
271
+ * });
272
+ * ```
273
+ */
274
+ declare function createResultMapper<TOutput, TError>(mappings: ErrorMapping<TError>[], options?: {
275
+ defaultStatus?: number;
276
+ successStatus?: number;
277
+ }): (result: Result<TOutput, TError | UnexpectedError>) => WebhookResponse;
278
+ /**
279
+ * Express-style request object (minimal interface).
280
+ */
281
+ interface ExpressLikeRequest {
282
+ method: string;
283
+ path: string;
284
+ headers: Record<string, string | string[] | undefined>;
285
+ body: unknown;
286
+ query: Record<string, string | string[] | undefined>;
287
+ params: Record<string, string>;
288
+ }
289
+ /**
290
+ * Express-style response object (minimal interface).
291
+ */
292
+ interface ExpressLikeResponse {
293
+ status(code: number): ExpressLikeResponse;
294
+ set(headers: Record<string, string>): ExpressLikeResponse;
295
+ json(body: unknown): void;
296
+ }
297
+ /**
298
+ * Convert an Express-like request to WebhookRequest.
299
+ *
300
+ * @param req - Express-like request object
301
+ * @returns WebhookRequest
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * app.post('/checkout', async (req, res) => {
306
+ * const webhookReq = toWebhookRequest(req);
307
+ * const response = await handler(webhookReq);
308
+ * res.status(response.status).json(response.body);
309
+ * });
310
+ * ```
311
+ */
312
+ declare function toWebhookRequest<TBody = unknown>(req: ExpressLikeRequest): WebhookRequest<TBody>;
313
+ /**
314
+ * Send a WebhookResponse using an Express-like response object.
315
+ *
316
+ * @param res - Express-like response object
317
+ * @param response - WebhookResponse to send
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * app.post('/checkout', async (req, res) => {
322
+ * const response = await handler(toWebhookRequest(req));
323
+ * sendWebhookResponse(res, response);
324
+ * });
325
+ * ```
326
+ */
327
+ declare function sendWebhookResponse(res: ExpressLikeResponse, response: WebhookResponse): void;
328
+ /**
329
+ * Create an Express-compatible middleware from a webhook handler.
330
+ *
331
+ * @param handler - Webhook handler function
332
+ * @returns Express middleware function
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * const handler = createWebhookHandler(workflow, workflowFn, config);
337
+ * const middleware = createExpressHandler(handler);
338
+ * app.post('/checkout', middleware);
339
+ * ```
340
+ */
341
+ declare function createExpressHandler<TBody = unknown>(handler: WebhookHandler<TBody>): (req: ExpressLikeRequest, res: ExpressLikeResponse) => Promise<void>;
342
+ /**
343
+ * Create a validation error.
344
+ *
345
+ * @param message - Error message
346
+ * @param field - Optional field name
347
+ * @param details - Optional additional details
348
+ * @returns ValidationError
349
+ */
350
+ declare function validationError(message: string, field?: string, details?: unknown): ValidationError;
351
+ /**
352
+ * Create a required field validator.
353
+ *
354
+ * @param fields - Field names to validate
355
+ * @returns Validation function
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * const validateRequired = requireFields(['email', 'password']);
360
+ *
361
+ * const validateInput = (req) => {
362
+ * const result = validateRequired(req.body);
363
+ * if (!result.ok) return result;
364
+ * return ok(req.body as LoginInput);
365
+ * };
366
+ * ```
367
+ */
368
+ declare function requireFields(fields: string[]): (body: Record<string, unknown>) => ValidationResult<void, ValidationError>;
369
+ /**
370
+ * Compose multiple validators into a single validator.
371
+ *
372
+ * @param validators - Validators to compose
373
+ * @returns Combined validator function
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * const validate = composeValidators(
378
+ * requireFields(['email', 'password']),
379
+ * validateEmailFormat,
380
+ * validatePasswordStrength
381
+ * );
382
+ * ```
383
+ */
384
+ declare function composeValidators<T>(...validators: Array<(input: T) => ValidationResult<void, ValidationError>>): (input: T) => ValidationResult<void, ValidationError>;
385
+ /**
386
+ * Generic event message for queue-based triggers.
387
+ */
388
+ interface EventMessage<T = unknown> {
389
+ /** Unique message ID */
390
+ id: string;
391
+ /** Event type/name */
392
+ type: string;
393
+ /** Event payload */
394
+ payload: T;
395
+ /** Event metadata */
396
+ metadata?: {
397
+ timestamp?: number;
398
+ source?: string;
399
+ correlationId?: string;
400
+ [key: string]: unknown;
401
+ };
402
+ }
403
+ /**
404
+ * Result of processing an event.
405
+ */
406
+ interface EventProcessingResult {
407
+ /** Whether the event was processed successfully */
408
+ success: boolean;
409
+ /** Should the message be acknowledged (removed from queue)? */
410
+ ack: boolean;
411
+ /** Optional error details */
412
+ error?: {
413
+ type: string;
414
+ message?: string;
415
+ retryable?: boolean;
416
+ };
417
+ }
418
+ /**
419
+ * Configuration for event trigger handlers.
420
+ */
421
+ interface EventTriggerConfig<TPayload, TOutput, TError> {
422
+ /** Validate the event payload */
423
+ validatePayload: (event: EventMessage<TPayload>) => ValidationResult<TPayload, ValidationError>;
424
+ /** Map workflow result to processing result */
425
+ mapResult: (result: Result<TOutput, TError | UnexpectedError>, event: EventMessage<TPayload>) => EventProcessingResult;
426
+ /** Optional: Determine if error is retryable */
427
+ isRetryable?: (error: TError | UnexpectedError) => boolean;
428
+ }
429
+ /**
430
+ * Event handler function type.
431
+ */
432
+ type EventHandler<TPayload = unknown> = (event: EventMessage<TPayload>) => Promise<EventProcessingResult>;
433
+ /**
434
+ * Create an event handler for queue-based triggers.
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * const handler = createEventHandler(
439
+ * checkoutWorkflow,
440
+ * async (step, deps, payload: CheckoutPayload) => {
441
+ * const charge = await step(() => deps.chargeCard(payload.amount));
442
+ * return { chargeId: charge.id };
443
+ * },
444
+ * {
445
+ * validatePayload: (event) => {
446
+ * if (!event.payload.amount) {
447
+ * return err({ type: 'VALIDATION_ERROR', message: 'Missing amount' });
448
+ * }
449
+ * return ok(event.payload);
450
+ * },
451
+ * mapResult: (result) => ({
452
+ * success: result.ok,
453
+ * ack: result.ok || !isRetryableError(result.error),
454
+ * error: result.ok ? undefined : { type: String(result.error) },
455
+ * }),
456
+ * }
457
+ * );
458
+ *
459
+ * // Use with SQS, RabbitMQ, etc.
460
+ * queue.consume(async (message) => {
461
+ * const result = await handler(message);
462
+ * if (result.ack) await message.ack();
463
+ * else await message.nack();
464
+ * });
465
+ * ```
466
+ */
467
+ declare function createEventHandler<TPayload, TOutput, TError, TDeps = unknown>(workflow: Workflow<TError, TDeps> | WorkflowStrict<TError, unknown, TDeps>, workflowFn: (step: Parameters<Parameters<Workflow<TError, TDeps>>[1]>[0], deps: TDeps, payload: TPayload) => TOutput | Promise<TOutput>, config: EventTriggerConfig<TPayload, TOutput, TError>): EventHandler<TPayload>;
468
+
469
+ export { type ErrorMapping, type ErrorResponseBody, type EventHandler, type EventMessage, type EventProcessingResult, type EventTriggerConfig, type ExpressLikeRequest, type ExpressLikeResponse, type SimpleHandlerConfig, type ValidationError, type ValidationResult, type WebhookHandler, type WebhookHandlerConfig, type WebhookRequest, type WebhookResponse, composeValidators, createEventHandler, createExpressHandler, createResultMapper, createSimpleHandler, createWebhookHandler, defaultUnexpectedErrorMapper, defaultValidationErrorMapper, isValidationError, requireFields, sendWebhookResponse, toWebhookRequest, validationError };
@@ -0,0 +1,2 @@
1
+ var B=e=>({ok:!0,value:e}),M=(e,n)=>({ok:!1,error:e,...n?.cause!==void 0?{cause:n.cause}:{}}),X=e=>e.ok;var le=e=>typeof e=="object"&&e!==null&&e.type==="UNEXPECTED_ERROR",j=Symbol.for("step_timeout_marker");function ee(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:j in e}function ce(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let n=e;return{timeoutMs:n.timeoutMs,stepName:n.stepName,stepKey:n.stepKey,attempt:n.attempt}}if(j in e)return e[j]}}var re=Symbol("early-exit");function Ee(e,n){return{[re]:!0,error:e,meta:n}}function ye(e){return typeof e=="object"&&e!==null&&e[re]===!0}var oe=Symbol("mapper-exception");function de(e){return{[oe]:!0,thrown:e}}function Te(e){return typeof e=="object"&&e!==null&&e[oe]===!0}function ke(e){return typeof e=="string"?{name:e}:e??{}}function G(e,n){let{backoff:a,initialDelay:w,maxDelay:g,jitter:R}=n,r;switch(a){case"fixed":r=w;break;case"linear":r=w*e;break;case"exponential":r=w*Math.pow(2,e-1);break}if(r=Math.min(r,g),R){let t=r*.25*Math.random();r=r+t}return Math.floor(r)}function z(e){return new Promise(n=>setTimeout(n,e))}var te=Symbol("timeout");async function me(e,n,a){let w=new AbortController,g=n.error??{type:"STEP_TIMEOUT",stepName:a.name,stepKey:a.key,timeoutMs:n.ms,attempt:a.attempt},R,r=new Promise((b,d)=>{R=setTimeout(()=>{w.abort(),d({[te]:!0,error:g})},n.ms)}),t;n.signal?t=Promise.resolve(e(w.signal)):t=Promise.resolve(e());try{return await Promise.race([t,r])}catch(b){if(typeof b=="object"&&b!==null&&b[te]===!0){let d=b.error;if(typeof d=="object"&&d!==null&&d.type!=="STEP_TIMEOUT"){let v={timeoutMs:n.ms,stepName:a.name,stepKey:a.key,attempt:a.attempt};j in d?d[j]=v:Object.defineProperty(d,j,{value:v,enumerable:!1,writable:!0,configurable:!1})}throw d}throw b}finally{clearTimeout(R)}}var F={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,retryOn:()=>!0,onRetry:()=>{}};async function ne(e,n){let{onError:a,onEvent:w,catchUnexpected:g,workflowId:R,context:r}=n&&typeof n=="object"?n:{},t=R??crypto.randomUUID(),b=!a&&!g,d=[],v=0,_=s=>s??`step_${++v}`,l=s=>{let h=s.context!==void 0||r===void 0?s:{...s,context:r};if(h.type==="step_success"){let U=h.stepId;for(let V=d.length-1;V>=0;V--){let q=d[V];if(q.type==="race"&&!q.winnerId){q.winnerId=U;break}}}w?.(h,r)},I=Ee,W=s=>ye(s),N=(s,h)=>b?h?.origin==="result"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:s,...h.resultCause!==void 0?{cause:h.resultCause}:{}}}:h?.origin==="throw"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"throw",error:s,thrown:h.thrown}}:{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:s}}:s,ie=s=>({type:"UNEXPECTED_ERROR",cause:s.meta.origin==="result"?{type:"STEP_FAILURE",origin:"result",error:s.error,...s.meta.resultCause!==void 0?{cause:s.meta.resultCause}:{}}:{type:"STEP_FAILURE",origin:"throw",error:s.error,thrown:s.meta.thrown}});try{let h=function(T,p){let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let o=performance.now(),u=!1;d.push({scopeId:i,type:"parallel"});let x=()=>{if(u)return;u=!0;let E=d.findIndex(c=>c.scopeId===i);E!==-1&&d.splice(E,1),l({type:"scope_end",workflowId:t,scopeId:i,ts:Date.now(),durationMs:performance.now()-o})};l({type:"scope_start",workflowId:t,scopeId:i,scopeType:"parallel",name:T,ts:Date.now()});try{let E=await p();if(x(),!E.ok)throw a?.(E.error,T,r),I(E.error,{origin:"result",resultCause:E.cause});return E.value}catch(E){throw x(),E}})()},U=function(T,p){let i=Object.keys(T),o=p.name??`Parallel(${i.join(", ")})`,u=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let x=performance.now(),E=!1;d.push({scopeId:u,type:"parallel"});let c=()=>{if(E)return;E=!0;let k=d.findIndex(f=>f.scopeId===u);k!==-1&&d.splice(k,1),l({type:"scope_end",workflowId:t,scopeId:u,ts:Date.now(),durationMs:performance.now()-x})};l({type:"scope_start",workflowId:t,scopeId:u,scopeType:"parallel",name:o,ts:Date.now()});try{let k=await new Promise(P=>{if(i.length===0){P([]);return}let A=!1,C=i.length,L=new Array(i.length);for(let O=0;O<i.length;O++){let K=i[O],$=O;Promise.resolve(T[K]()).catch(m=>M({type:"PROMISE_REJECTED",cause:m},{cause:{type:"PROMISE_REJECTION",reason:m}})).then(m=>{if(!A){if(!m.ok){A=!0,P([{key:K,result:m}]);return}L[$]={key:K,result:m},C--,C===0&&P(L)}})}});c();let f={};for(let{key:P,result:A}of k){if(!A.ok)throw a?.(A.error,P,r),I(A.error,{origin:"result",resultCause:A.cause});f[P]=A.value}return f}catch(k){throw c(),k}})()};var Se=h,Pe=U;let s=(T,p)=>(async()=>{let i=ke(p),{name:o,key:u,retry:x,timeout:E}=i,c=_(u),k=w,f=k?performance.now():0;if(!(typeof T=="function")){if(x&&x.attempts>1)throw new Error("step: retry options require a function operation. Direct Promise/Result values cannot be re-executed on retry. Wrap your operation in a function: step(() => yourOperation, { retry: {...} })");if(E)throw new Error("step: timeout options require a function operation. Direct Promise/Result values cannot be wrapped with timeout after they've started. Wrap your operation in a function: step(() => yourOperation, { timeout: {...} })")}let C={attempts:Math.max(1,x?.attempts??1),backoff:x?.backoff??F.backoff,initialDelay:x?.initialDelay??F.initialDelay,maxDelay:x?.maxDelay??F.maxDelay,jitter:x?.jitter??F.jitter,retryOn:x?.retryOn??F.retryOn,onRetry:x?.onRetry??F.onRetry};w&&l({type:"step_start",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now()});let L;for(let m=1;m<=C.attempts;m++){let pe=k?performance.now():0;try{let y;if(typeof T=="function"?E?y=await me(T,E,{name:o,key:u,attempt:m}):y=await T():y=await T,y.ok){let D=performance.now()-f;return l({type:"step_success",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:D}),u&&l({type:"step_complete",workflowId:t,stepKey:u,name:o,ts:Date.now(),durationMs:D,result:y}),y.value}if(L=y,m<C.attempts&&C.retryOn(y.error,m)){let D=G(m,C);l({type:"step_retry",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),attempt:m+1,maxAttempts:C.attempts,delayMs:D,error:y.error}),C.onRetry(y.error,m,D),await z(D);continue}C.attempts>1&&l({type:"step_retries_exhausted",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-f,attempts:m,lastError:y.error});break}catch(y){let D=performance.now()-pe;if(W(y))throw l({type:"step_aborted",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:D}),y;if(ee(y)){let S=ce(y),Y=E?.ms??S?.timeoutMs??0;if(l({type:"step_timeout",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),timeoutMs:Y,attempt:m}),m<C.attempts&&C.retryOn(y,m)){let J=G(m,C);l({type:"step_retry",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),attempt:m+1,maxAttempts:C.attempts,delayMs:J,error:y}),C.onRetry(y,m,J),await z(J);continue}C.attempts>1&&l({type:"step_retries_exhausted",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-f,attempts:m,lastError:y})}if(m<C.attempts&&C.retryOn(y,m)){let S=G(m,C);l({type:"step_retry",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),attempt:m+1,maxAttempts:C.attempts,delayMs:S,error:y}),C.onRetry(y,m,S),await z(S);continue}C.attempts>1&&!ee(y)&&l({type:"step_retries_exhausted",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-f,attempts:m,lastError:y});let H=performance.now()-f;if(g){let S;try{S=g(y)}catch(Y){throw de(Y)}throw l({type:"step_error",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:H,error:S}),u&&l({type:"step_complete",workflowId:t,stepKey:u,name:o,ts:Date.now(),durationMs:H,result:M(S,{cause:y}),meta:{origin:"throw",thrown:y}}),a?.(S,o,r),I(S,{origin:"throw",thrown:y})}else{let S={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:y}};throw l({type:"step_error",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:H,error:S}),u&&l({type:"step_complete",workflowId:t,stepKey:u,name:o,ts:Date.now(),durationMs:H,result:M(S,{cause:y}),meta:{origin:"throw",thrown:y}}),y}}}let O=L,K=performance.now()-f,$=N(O.error,{origin:"result",resultCause:O.cause});throw l({type:"step_error",workflowId:t,stepId:c,stepKey:u,name:o,ts:Date.now(),durationMs:K,error:$}),u&&l({type:"step_complete",workflowId:t,stepKey:u,name:o,ts:Date.now(),durationMs:K,result:O,meta:{origin:"result",resultCause:O.cause}}),a?.(O.error,o,r),I(O.error,{origin:"result",resultCause:O.cause})})();s.try=(T,p)=>{let i=p.name,o=p.key,u=_(o),x="error"in p?()=>p.error:p.onError,E=w;return(async()=>{let c=E?performance.now():0;w&&l({type:"step_start",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now()});try{let k=await T(),f=performance.now()-c;return l({type:"step_success",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now(),durationMs:f}),o&&l({type:"step_complete",workflowId:t,stepKey:o,name:i,ts:Date.now(),durationMs:f,result:B(k)}),k}catch(k){let f=x(k),P=performance.now()-c,A=N(f,{origin:"throw",thrown:k});throw l({type:"step_error",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now(),durationMs:P,error:A}),o&&l({type:"step_complete",workflowId:t,stepKey:o,name:i,ts:Date.now(),durationMs:P,result:M(f,{cause:k}),meta:{origin:"throw",thrown:k}}),a?.(f,i,r),I(f,{origin:"throw",thrown:k})}})()},s.fromResult=(T,p)=>{let i=p.name,o=p.key,u=_(o),x="error"in p?()=>p.error:p.onError,E=w;return(async()=>{let c=E?performance.now():0;w&&l({type:"step_start",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now()});let k=await T();if(k.ok){let f=performance.now()-c;return l({type:"step_success",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now(),durationMs:f}),o&&l({type:"step_complete",workflowId:t,stepKey:o,name:i,ts:Date.now(),durationMs:f,result:B(k.value)}),k.value}else{let f=x(k.error),P=performance.now()-c,A=N(f,{origin:"result",resultCause:k.error});throw l({type:"step_error",workflowId:t,stepId:u,stepKey:o,name:i,ts:Date.now(),durationMs:P,error:A}),o&&l({type:"step_complete",workflowId:t,stepKey:o,name:i,ts:Date.now(),durationMs:P,result:M(f,{cause:k.error}),meta:{origin:"result",resultCause:k.error}}),a?.(f,i,r),I(f,{origin:"result",resultCause:k.error})}})()},s.retry=(T,p)=>s(T,{name:p.name,key:p.key,retry:{attempts:p.attempts,backoff:p.backoff,initialDelay:p.initialDelay,maxDelay:p.maxDelay,jitter:p.jitter,retryOn:p.retryOn,onRetry:p.onRetry},timeout:p.timeout}),s.withTimeout=(T,p)=>s(T,{name:p.name,key:p.key,timeout:p}),s.parallel=((...T)=>{if(typeof T[0]=="string"){let p=T[0],i=T[1];return h(p,i)}else{let p=T[0],i=T[1]??{};return U(p,i)}}),s.race=(T,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let o=performance.now(),u=!1,x={scopeId:i,type:"race",winnerId:void 0};d.push(x);let E=()=>{if(u)return;u=!0;let c=d.findIndex(k=>k.scopeId===i);c!==-1&&d.splice(c,1),l({type:"scope_end",workflowId:t,scopeId:i,ts:Date.now(),durationMs:performance.now()-o,winnerId:x.winnerId})};l({type:"scope_start",workflowId:t,scopeId:i,scopeType:"race",name:T,ts:Date.now()});try{let c=await p();if(E(),!c.ok)throw a?.(c.error,T,r),I(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw E(),c}})()},s.allSettled=(T,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let o=performance.now(),u=!1;d.push({scopeId:i,type:"allSettled"});let x=()=>{if(u)return;u=!0;let E=d.findIndex(c=>c.scopeId===i);E!==-1&&d.splice(E,1),l({type:"scope_end",workflowId:t,scopeId:i,ts:Date.now(),durationMs:performance.now()-o})};l({type:"scope_start",workflowId:t,scopeId:i,scopeType:"allSettled",name:T,ts:Date.now()});try{let E=await p();if(x(),!E.ok)throw a?.(E.error,T,r),I(E.error,{origin:"result",resultCause:E.cause});return E.value}catch(E){throw x(),E}})()};let q=await e(s);return B(q)}catch(s){if(Te(s))throw s.thrown;if(W(s)){let U=s.meta.origin==="throw"?s.meta.thrown:s.meta.resultCause;if(g||a)return M(s.error,{cause:U});if(le(s.error))return M(s.error,{cause:U});let V=ie(s);return M(V,{cause:U})}if(g){let U=g(s);return a?.(U,"unexpected",r),M(U,{cause:s})}let h={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:s}};return a?.(h,"unexpected",r),M(h,{cause:s})}}ne.strict=(e,n)=>ne(e,n);function we(e){return typeof e=="object"&&e!==null&&e.type==="VALIDATION_ERROR"}function Q(e){return{status:400,body:{error:{type:e.type,message:e.message,details:e.field?{field:e.field}:e.details}}}}function Z(e){return{status:500,body:{error:{type:"INTERNAL_ERROR",message:"An unexpected error occurred"}}}}function fe(e,n,a){let{validateInput:w,mapResult:g,mapValidationError:R=Q,mapUnexpectedError:r=Z,beforeValidation:t,afterResponse:b}=a;return async d=>{try{let v=t?await t(d):d,_=await w(v);if(!X(_)){let W=R(_.error,v);return b?await b(W,v):W}let l=await e(_.value,(W,N)=>n(W,N,_.value)),I=g(l,v);return b?await b(I,v):I}catch(v){let _=r(v,d);return b?await b(_,d):_}}}function Re(e){let{validateInput:n,handler:a,mapResult:w,mapValidationError:g=Q,mapUnexpectedError:R=Z}=e;return async r=>{try{let t=await n(r);if(!X(t))return g(t.error,r);let b=await a(t.value,r);return w(b,r)}catch(t){return R(t,r)}}}function xe(e,n={}){let{defaultStatus:a=500,successStatus:w=200}=n,g=new Map;for(let R of e)g.set(R.error,R);return R=>{if(R.ok)return{status:w,body:R.value};if(typeof R.error=="object"&&R.error!==null&&R.error.type==="UNEXPECTED_ERROR")return{status:500,body:{error:{type:"INTERNAL_ERROR",message:"An unexpected error occurred"}}};let r=g.get(R.error);return r?{status:r.status,body:{error:{type:String(r.error),message:r.message}}}:{status:a,body:{error:{type:String(R.error)}}}}}function se(e){return{method:e.method,path:e.path,headers:e.headers,body:e.body,query:e.query,params:e.params,raw:e}}function ue(e,n){n.headers&&e.set(n.headers),e.status(n.status).json(n.body)}function Ce(e){return async(n,a)=>{let w=se(n),g=await e(w);ue(a,g)}}function ae(e,n,a){return{type:"VALIDATION_ERROR",message:e,field:n,details:a}}function ge(e){return n=>{for(let a of e)if(n[a]===void 0||n[a]===null||n[a]==="")return M(ae(`Missing required field: ${a}`,a));return B(void 0)}}function be(...e){return n=>{for(let a of e){let w=a(n);if(!w.ok)return w}return B(void 0)}}function he(e,n,a){let{validatePayload:w,mapResult:g}=a;return async R=>{try{let r=w(R);if(!X(r))return{success:!1,ack:!0,error:{type:r.error.type,message:r.error.message,retryable:!1}};let t=await e(r.value,(b,d)=>n(b,d,r.value));return g(t,R)}catch(r){return{success:!1,ack:!1,error:{type:"UNEXPECTED_ERROR",message:r instanceof Error?r.message:String(r),retryable:!0}}}}}export{be as composeValidators,he as createEventHandler,Ce as createExpressHandler,xe as createResultMapper,Re as createSimpleHandler,fe as createWebhookHandler,Z as defaultUnexpectedErrorMapper,Q as defaultValidationErrorMapper,we as isValidationError,ge as requireFields,ue as sendWebhookResponse,se as toWebhookRequest,ae as validationError};
2
+ //# sourceMappingURL=webhook.js.map