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.
- package/LICENSE +21 -0
- package/README.md +1278 -0
- package/dist/batch.cjs +2 -0
- package/dist/batch.cjs.map +1 -0
- package/dist/batch.d.cts +197 -0
- package/dist/batch.d.ts +197 -0
- package/dist/batch.js +2 -0
- package/dist/batch.js.map +1 -0
- package/dist/circuit-breaker.cjs +2 -0
- package/dist/circuit-breaker.cjs.map +1 -0
- package/dist/circuit-breaker.d.cts +208 -0
- package/dist/circuit-breaker.d.ts +208 -0
- package/dist/circuit-breaker.js +2 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/conditional.cjs +2 -0
- package/dist/conditional.cjs.map +1 -0
- package/dist/conditional.d.cts +249 -0
- package/dist/conditional.d.ts +249 -0
- package/dist/conditional.js +2 -0
- package/dist/conditional.js.map +1 -0
- package/dist/core-BuTBsR0x.d.cts +2325 -0
- package/dist/core-BuTBsR0x.d.ts +2325 -0
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +2 -0
- package/dist/core.js.map +1 -0
- package/dist/devtools.cjs +11 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +176 -0
- package/dist/devtools.d.ts +176 -0
- package/dist/devtools.js +11 -0
- package/dist/devtools.js.map +1 -0
- package/dist/duration.cjs +2 -0
- package/dist/duration.cjs.map +1 -0
- package/dist/duration.d.cts +246 -0
- package/dist/duration.d.ts +246 -0
- package/dist/duration.js +2 -0
- package/dist/duration.js.map +1 -0
- package/dist/hitl.cjs +2 -0
- package/dist/hitl.cjs.map +1 -0
- package/dist/hitl.d.cts +337 -0
- package/dist/hitl.d.ts +337 -0
- package/dist/hitl.js +2 -0
- package/dist/hitl.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/match.cjs +2 -0
- package/dist/match.cjs.map +1 -0
- package/dist/match.d.cts +209 -0
- package/dist/match.d.ts +209 -0
- package/dist/match.js +2 -0
- package/dist/match.js.map +1 -0
- package/dist/otel.cjs +2 -0
- package/dist/otel.cjs.map +1 -0
- package/dist/otel.d.cts +185 -0
- package/dist/otel.d.ts +185 -0
- package/dist/otel.js +2 -0
- package/dist/otel.js.map +1 -0
- package/dist/persistence.cjs +2 -0
- package/dist/persistence.cjs.map +1 -0
- package/dist/persistence.d.cts +572 -0
- package/dist/persistence.d.ts +572 -0
- package/dist/persistence.js +2 -0
- package/dist/persistence.js.map +1 -0
- package/dist/policies.cjs +2 -0
- package/dist/policies.cjs.map +1 -0
- package/dist/policies.d.cts +378 -0
- package/dist/policies.d.ts +378 -0
- package/dist/policies.js +2 -0
- package/dist/policies.js.map +1 -0
- package/dist/ratelimit.cjs +2 -0
- package/dist/ratelimit.cjs.map +1 -0
- package/dist/ratelimit.d.cts +279 -0
- package/dist/ratelimit.d.ts +279 -0
- package/dist/ratelimit.js +2 -0
- package/dist/ratelimit.js.map +1 -0
- package/dist/reliability.cjs +2 -0
- package/dist/reliability.cjs.map +1 -0
- package/dist/reliability.d.cts +5 -0
- package/dist/reliability.d.ts +5 -0
- package/dist/reliability.js +2 -0
- package/dist/reliability.js.map +1 -0
- package/dist/resource.cjs +2 -0
- package/dist/resource.cjs.map +1 -0
- package/dist/resource.d.cts +171 -0
- package/dist/resource.d.ts +171 -0
- package/dist/resource.js +2 -0
- package/dist/resource.js.map +1 -0
- package/dist/retry.cjs +2 -0
- package/dist/retry.cjs.map +1 -0
- package/dist/retry.d.cts +2 -0
- package/dist/retry.d.ts +2 -0
- package/dist/retry.js +2 -0
- package/dist/retry.js.map +1 -0
- package/dist/saga.cjs +2 -0
- package/dist/saga.cjs.map +1 -0
- package/dist/saga.d.cts +231 -0
- package/dist/saga.d.ts +231 -0
- package/dist/saga.js +2 -0
- package/dist/saga.js.map +1 -0
- package/dist/schedule.cjs +2 -0
- package/dist/schedule.cjs.map +1 -0
- package/dist/schedule.d.cts +387 -0
- package/dist/schedule.d.ts +387 -0
- package/dist/schedule.js +2 -0
- package/dist/schedule.js.map +1 -0
- package/dist/tagged-error.cjs +2 -0
- package/dist/tagged-error.cjs.map +1 -0
- package/dist/tagged-error.d.cts +252 -0
- package/dist/tagged-error.d.ts +252 -0
- package/dist/tagged-error.js +2 -0
- package/dist/tagged-error.js.map +1 -0
- package/dist/testing.cjs +2 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +228 -0
- package/dist/testing.d.ts +228 -0
- package/dist/testing.js +2 -0
- package/dist/testing.js.map +1 -0
- package/dist/visualize.cjs +1573 -0
- package/dist/visualize.cjs.map +1 -0
- package/dist/visualize.d.cts +1415 -0
- package/dist/visualize.d.ts +1415 -0
- package/dist/visualize.js +1573 -0
- package/dist/visualize.js.map +1 -0
- package/dist/webhook.cjs +2 -0
- package/dist/webhook.cjs.map +1 -0
- package/dist/webhook.d.cts +469 -0
- package/dist/webhook.d.ts +469 -0
- package/dist/webhook.js +2 -0
- package/dist/webhook.js.map +1 -0
- package/dist/workflow-entry-C6nH8ByN.d.ts +858 -0
- package/dist/workflow-entry-RRTlSg_4.d.cts +858 -0
- package/dist/workflow.cjs +2 -0
- package/dist/workflow.cjs.map +1 -0
- package/dist/workflow.d.cts +2 -0
- package/dist/workflow.d.ts +2 -0
- package/dist/workflow.js +2 -0
- package/dist/workflow.js.map +1 -0
- package/docs/advanced.md +1548 -0
- package/docs/api.md +513 -0
- package/docs/coming-from-neverthrow.md +1013 -0
- package/docs/match.md +417 -0
- package/docs/pino-logging-example.md +396 -0
- package/docs/policies.md +508 -0
- package/docs/resource-management.md +509 -0
- package/docs/schedule.md +467 -0
- package/docs/tagged-error.md +785 -0
- package/docs/visualization.md +430 -0
- package/docs/visualize-examples.md +330 -0
- 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 };
|
package/dist/webhook.js
ADDED
|
@@ -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
|