@temporal-contract/worker 0.0.3 → 0.0.5
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/README.md +49 -0
- package/dist/activity.cjs +2 -2
- package/dist/activity.d.cts +2 -2
- package/dist/activity.d.mts +2 -2
- package/dist/activity.mjs +2 -2
- package/dist/{handler-Cc951VQp.cjs → handler-BAzNuAZz.cjs} +217 -79
- package/dist/handler-Cp9h_XCy.d.cts +560 -0
- package/dist/handler-DFFpSaGN.mjs +502 -0
- package/dist/handler-uAeIi9f0.d.mts +560 -0
- package/dist/workflow.cjs +3 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.mts +2 -2
- package/dist/workflow.mjs +2 -2
- package/package.json +36 -28
- package/dist/errors-B50uht6a.d.cts +0 -302
- package/dist/errors-DgUMRes-.d.mts +0 -302
- package/dist/handler-BP9xAycT.mjs +0 -376
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
import { Future, Result } from "@temporal-contract/boxed";
|
|
2
|
+
import { ActivityOptions, ChildWorkflowOptions, WorkflowInfo } from "@temporalio/workflow";
|
|
3
|
+
import { ActivityDefinition, AnySchema, ContractDefinition, QueryDefinition, SignalDefinition, UpdateDefinition, WorkflowDefinition } from "@temporal-contract/contract";
|
|
4
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
|
+
|
|
6
|
+
//#region src/types.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Infer input type from a definition (worker perspective)
|
|
9
|
+
* Worker receives the output type (after input schema parsing/transformation)
|
|
10
|
+
*/
|
|
11
|
+
type WorkerInferInput<T extends {
|
|
12
|
+
input: AnySchema;
|
|
13
|
+
}> = StandardSchemaV1.InferOutput<T["input"]>;
|
|
14
|
+
/**
|
|
15
|
+
* Infer output type from a definition (worker perspective)
|
|
16
|
+
* Worker returns the input type (before output schema parsing/transformation)
|
|
17
|
+
*/
|
|
18
|
+
type WorkerInferOutput<T extends {
|
|
19
|
+
output: AnySchema;
|
|
20
|
+
}> = StandardSchemaV1.InferInput<T["output"]>;
|
|
21
|
+
/**
|
|
22
|
+
* WORKER PERSPECTIVE
|
|
23
|
+
* Worker receives z.output of input (parsed data) and returns z.input of output (raw data)
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Infer workflow function signature from worker perspective
|
|
27
|
+
* Worker receives z.input and returns z.output
|
|
28
|
+
*/
|
|
29
|
+
type WorkerInferWorkflow<TWorkflow extends WorkflowDefinition> = (args: WorkerInferInput<TWorkflow>) => Promise<WorkerInferOutput<TWorkflow>>;
|
|
30
|
+
/**
|
|
31
|
+
* Infer activity function signature from worker perspective
|
|
32
|
+
* Worker receives z.input and returns z.output
|
|
33
|
+
*/
|
|
34
|
+
type WorkerInferActivity<TActivity extends ActivityDefinition> = (args: WorkerInferInput<TActivity>) => Promise<WorkerInferOutput<TActivity>>;
|
|
35
|
+
/**
|
|
36
|
+
* Infer signal handler signature from worker perspective
|
|
37
|
+
* Worker receives z.input
|
|
38
|
+
*/
|
|
39
|
+
type WorkerInferSignal<TSignal extends SignalDefinition> = (args: WorkerInferInput<TSignal>) => Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Infer query handler signature from worker perspective
|
|
42
|
+
* Worker receives z.input and returns z.output
|
|
43
|
+
*/
|
|
44
|
+
type WorkerInferQuery<TQuery extends QueryDefinition> = (args: WorkerInferInput<TQuery>) => Promise<WorkerInferOutput<TQuery>>;
|
|
45
|
+
/**
|
|
46
|
+
* Infer update handler signature from worker perspective
|
|
47
|
+
* Worker receives z.input and returns z.output
|
|
48
|
+
*/
|
|
49
|
+
type WorkerInferUpdate<TUpdate extends UpdateDefinition> = (args: WorkerInferInput<TUpdate>) => Promise<WorkerInferOutput<TUpdate>>;
|
|
50
|
+
/**
|
|
51
|
+
* WORKER PERSPECTIVE - Contract-level types
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Infer all workflows from a contract (worker perspective)
|
|
55
|
+
*/
|
|
56
|
+
type WorkerInferWorkflows<TContract extends ContractDefinition> = { [K in keyof TContract["workflows"]]: WorkerInferWorkflow<TContract["workflows"][K]> };
|
|
57
|
+
/**
|
|
58
|
+
* Infer all activities from a contract (worker perspective)
|
|
59
|
+
*/
|
|
60
|
+
type WorkerInferActivities<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof TContract["activities"]]: WorkerInferActivity<TContract["activities"][K]> } : {};
|
|
61
|
+
/**
|
|
62
|
+
* Infer activities from a workflow definition (worker perspective)
|
|
63
|
+
*/
|
|
64
|
+
type WorkerInferWorkflowActivities<T extends WorkflowDefinition> = T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: WorkerInferActivity<T["activities"][K]> } : {};
|
|
65
|
+
/**
|
|
66
|
+
* Infer signals from a workflow definition (worker perspective)
|
|
67
|
+
*/
|
|
68
|
+
type WorkerInferWorkflowSignals<T extends WorkflowDefinition> = T["signals"] extends Record<string, SignalDefinition> ? { [K in keyof T["signals"]]: WorkerInferSignal<T["signals"][K]> } : {};
|
|
69
|
+
/**
|
|
70
|
+
* Infer queries from a workflow definition (worker perspective)
|
|
71
|
+
*/
|
|
72
|
+
type WorkerInferWorkflowQueries<T extends WorkflowDefinition> = T["queries"] extends Record<string, QueryDefinition> ? { [K in keyof T["queries"]]: WorkerInferQuery<T["queries"][K]> } : {};
|
|
73
|
+
/**
|
|
74
|
+
* Infer updates from a workflow definition (worker perspective)
|
|
75
|
+
*/
|
|
76
|
+
type WorkerInferWorkflowUpdates<T extends WorkflowDefinition> = T["updates"] extends Record<string, UpdateDefinition> ? { [K in keyof T["updates"]]: WorkerInferUpdate<T["updates"][K]> } : {};
|
|
77
|
+
/**
|
|
78
|
+
* Infer all activities available in a workflow context (worker perspective)
|
|
79
|
+
* Combines workflow-specific activities with global activities
|
|
80
|
+
*/
|
|
81
|
+
type WorkerInferWorkflowContextActivities<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = WorkerInferWorkflowActivities<TContract["workflows"][TWorkflowName]> & WorkerInferActivities<TContract>;
|
|
82
|
+
/**
|
|
83
|
+
* UTILITY TYPES FOR ACTIVITY HANDLERS
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* Infer the handler type for a global activity from a contract
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const log: ActivityHandler<typeof myContract, "log"> = async ({ level, message }) => {
|
|
91
|
+
* logger[level](message);
|
|
92
|
+
* };
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
type ActivityHandler<TContract extends ContractDefinition, TActivityName extends keyof TContract["activities"]> = TContract["activities"] extends Record<string, ActivityDefinition> ? (args: WorkerInferInput<TContract["activities"][TActivityName]>) => Promise<WorkerInferOutput<TContract["activities"][TActivityName]>> : never;
|
|
96
|
+
/**
|
|
97
|
+
* Infer the handler type for a workflow-specific activity from a contract
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const processPayment: WorkflowActivityHandler<
|
|
102
|
+
* typeof myContract,
|
|
103
|
+
* "processOrder",
|
|
104
|
+
* "processPayment"
|
|
105
|
+
* > = async ({ customerId, amount }) => {
|
|
106
|
+
* // Implementation
|
|
107
|
+
* return { transactionId, status: "success" as const, paidAmount: amount };
|
|
108
|
+
* };
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
type WorkflowActivityHandler<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"], TActivityName extends keyof TContract["workflows"][TWorkflowName]["activities"]> = TContract["workflows"][TWorkflowName]["activities"] extends Record<string, ActivityDefinition> ? (args: WorkerInferInput<TContract["workflows"][TWorkflowName]["activities"][TActivityName]>) => Promise<WorkerInferOutput<TContract["workflows"][TWorkflowName]["activities"][TActivityName]>> : never;
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/errors.d.ts
|
|
114
|
+
/**
|
|
115
|
+
* Base error class for worker errors
|
|
116
|
+
*/
|
|
117
|
+
declare class WorkerError extends Error {
|
|
118
|
+
constructor(message: string, cause?: unknown);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Activity error class that should be used to wrap all technical exceptions
|
|
122
|
+
* Forces proper error handling and enables retry policies
|
|
123
|
+
*/
|
|
124
|
+
declare class ActivityError extends Error {
|
|
125
|
+
readonly code: string;
|
|
126
|
+
readonly cause?: unknown;
|
|
127
|
+
constructor(code: string, message: string, cause?: unknown);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Error thrown when an activity definition is not found in the contract
|
|
131
|
+
*/
|
|
132
|
+
declare class ActivityDefinitionNotFoundError extends WorkerError {
|
|
133
|
+
readonly activityName: string;
|
|
134
|
+
readonly availableDefinitions: readonly string[];
|
|
135
|
+
constructor(activityName: string, availableDefinitions?: readonly string[]);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Error thrown when activity input validation fails
|
|
139
|
+
*/
|
|
140
|
+
declare class ActivityInputValidationError extends WorkerError {
|
|
141
|
+
readonly activityName: string;
|
|
142
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
143
|
+
constructor(activityName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Error thrown when activity output validation fails
|
|
147
|
+
*/
|
|
148
|
+
declare class ActivityOutputValidationError extends WorkerError {
|
|
149
|
+
readonly activityName: string;
|
|
150
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
151
|
+
constructor(activityName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Error thrown when workflow input validation fails
|
|
155
|
+
*/
|
|
156
|
+
declare class WorkflowInputValidationError extends WorkerError {
|
|
157
|
+
readonly workflowName: string;
|
|
158
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
159
|
+
constructor(workflowName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Error thrown when workflow output validation fails
|
|
163
|
+
*/
|
|
164
|
+
declare class WorkflowOutputValidationError extends WorkerError {
|
|
165
|
+
readonly workflowName: string;
|
|
166
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
167
|
+
constructor(workflowName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Error thrown when signal input validation fails
|
|
171
|
+
*/
|
|
172
|
+
declare class SignalInputValidationError extends WorkerError {
|
|
173
|
+
readonly signalName: string;
|
|
174
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
175
|
+
constructor(signalName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Error thrown when query input validation fails
|
|
179
|
+
*/
|
|
180
|
+
declare class QueryInputValidationError extends WorkerError {
|
|
181
|
+
readonly queryName: string;
|
|
182
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
183
|
+
constructor(queryName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Error thrown when query output validation fails
|
|
187
|
+
*/
|
|
188
|
+
declare class QueryOutputValidationError extends WorkerError {
|
|
189
|
+
readonly queryName: string;
|
|
190
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
191
|
+
constructor(queryName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Error thrown when update input validation fails
|
|
195
|
+
*/
|
|
196
|
+
declare class UpdateInputValidationError extends WorkerError {
|
|
197
|
+
readonly updateName: string;
|
|
198
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
199
|
+
constructor(updateName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Error thrown when update output validation fails
|
|
203
|
+
*/
|
|
204
|
+
declare class UpdateOutputValidationError extends WorkerError {
|
|
205
|
+
readonly updateName: string;
|
|
206
|
+
readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
207
|
+
constructor(updateName: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Error thrown when a child workflow is not found in the contract
|
|
211
|
+
*/
|
|
212
|
+
declare class ChildWorkflowNotFoundError extends WorkerError {
|
|
213
|
+
readonly workflowName: string;
|
|
214
|
+
readonly availableWorkflows: readonly string[];
|
|
215
|
+
constructor(workflowName: string, availableWorkflows?: readonly string[]);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generic error for child workflow operations
|
|
219
|
+
*/
|
|
220
|
+
declare class ChildWorkflowError extends WorkerError {
|
|
221
|
+
constructor(message: string, cause?: unknown);
|
|
222
|
+
}
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/handler.d.ts
|
|
225
|
+
/**
|
|
226
|
+
* Typed handle for a child workflow with Future/Result pattern
|
|
227
|
+
*/
|
|
228
|
+
interface TypedChildWorkflowHandle<TWorkflow extends WorkflowDefinition> {
|
|
229
|
+
/**
|
|
230
|
+
* Get child workflow result with Result pattern
|
|
231
|
+
*/
|
|
232
|
+
result: () => Future<Result<WorkerInferOutput<TWorkflow>, ChildWorkflowError>>;
|
|
233
|
+
/**
|
|
234
|
+
* Child workflow ID
|
|
235
|
+
*/
|
|
236
|
+
workflowId: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Options for starting a child workflow
|
|
240
|
+
*/
|
|
241
|
+
type TypedChildWorkflowOptions = Pick<ChildWorkflowOptions, "workflowId" | "workflowIdReusePolicy" | "parentClosePolicy" | "workflowExecutionTimeout" | "workflowRunTimeout" | "workflowTaskTimeout" | "retry" | "memo" | "searchAttributes" | "cronSchedule" | "cancellationType">;
|
|
242
|
+
/**
|
|
243
|
+
* Workflow context with typed activities (workflow + global) and workflow info
|
|
244
|
+
* Note: activities is typed as 'any' to work around TypeScript generic type inference limitations with Zod tuples
|
|
245
|
+
*/
|
|
246
|
+
interface WorkflowContext<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> {
|
|
247
|
+
activities: WorkerInferWorkflowContextActivities<TContract, TWorkflowName>;
|
|
248
|
+
info: WorkflowInfo;
|
|
249
|
+
/**
|
|
250
|
+
* Define a signal handler within the workflow implementation
|
|
251
|
+
* Allows the signal handler to access workflow state
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* implementation: async (context, args) => {
|
|
256
|
+
* let currentValue = args.initialValue;
|
|
257
|
+
*
|
|
258
|
+
* context.defineSignal('increment', async (signalArgs) => {
|
|
259
|
+
* currentValue += signalArgs.amount;
|
|
260
|
+
* });
|
|
261
|
+
*
|
|
262
|
+
* // ... rest of workflow
|
|
263
|
+
* }
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
defineSignal: <K$1 extends keyof TContract["workflows"][TWorkflowName]["signals"]>(signalName: K$1, handler: SignalHandlerImplementation<TContract["workflows"][TWorkflowName]["signals"][K$1] extends SignalDefinition ? TContract["workflows"][TWorkflowName]["signals"][K$1] : never>) => void;
|
|
267
|
+
/**
|
|
268
|
+
* Define a query handler within the workflow implementation
|
|
269
|
+
* Allows the query handler to access workflow state
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```ts
|
|
273
|
+
* implementation: async (context, args) => {
|
|
274
|
+
* let currentValue = args.initialValue;
|
|
275
|
+
*
|
|
276
|
+
* context.defineQuery('getCurrentValue', () => {
|
|
277
|
+
* return { value: currentValue };
|
|
278
|
+
* });
|
|
279
|
+
*
|
|
280
|
+
* // ... rest of workflow
|
|
281
|
+
* }
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
defineQuery: <K$1 extends keyof TContract["workflows"][TWorkflowName]["queries"]>(queryName: K$1, handler: QueryHandlerImplementation<TContract["workflows"][TWorkflowName]["queries"][K$1] extends QueryDefinition ? TContract["workflows"][TWorkflowName]["queries"][K$1] : never>) => void;
|
|
285
|
+
/**
|
|
286
|
+
* Define an update handler within the workflow implementation
|
|
287
|
+
* Allows the update handler to access and modify workflow state
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* implementation: async (context, args) => {
|
|
292
|
+
* let currentValue = args.initialValue;
|
|
293
|
+
*
|
|
294
|
+
* context.defineUpdate('multiply', async (updateArgs) => {
|
|
295
|
+
* currentValue *= updateArgs.factor;
|
|
296
|
+
* return { newValue: currentValue };
|
|
297
|
+
* });
|
|
298
|
+
*
|
|
299
|
+
* // ... rest of workflow
|
|
300
|
+
* }
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
defineUpdate: <K$1 extends keyof TContract["workflows"][TWorkflowName]["updates"]>(updateName: K$1, handler: UpdateHandlerImplementation<TContract["workflows"][TWorkflowName]["updates"][K$1] extends UpdateDefinition ? TContract["workflows"][TWorkflowName]["updates"][K$1] : never>) => void;
|
|
304
|
+
/**
|
|
305
|
+
* Start a child workflow and return a typed handle with Future/Result pattern
|
|
306
|
+
*
|
|
307
|
+
* Supports both same-contract and cross-contract child workflows:
|
|
308
|
+
* - Same contract: Pass workflowName from current contract
|
|
309
|
+
* - Cross-contract: Pass contract and workflowName to invoke workflows from other workers
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* // Same contract child workflow
|
|
314
|
+
* const childResult = await context.startChildWorkflow(myContract, 'processPayment', {
|
|
315
|
+
* workflowId: 'payment-123',
|
|
316
|
+
* args: { amount: 100 }
|
|
317
|
+
* });
|
|
318
|
+
*
|
|
319
|
+
* // Cross-contract child workflow (from another worker)
|
|
320
|
+
* const otherResult = await context.startChildWorkflow(otherContract, 'sendNotification', {
|
|
321
|
+
* workflowId: 'notification-123',
|
|
322
|
+
* args: { message: 'Hello' }
|
|
323
|
+
* });
|
|
324
|
+
*
|
|
325
|
+
* childResult.match({
|
|
326
|
+
* Ok: async (handle) => {
|
|
327
|
+
* const result = await handle.result();
|
|
328
|
+
* // ... handle result
|
|
329
|
+
* },
|
|
330
|
+
* Error: (error) => console.error('Failed to start:', error),
|
|
331
|
+
* });
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
startChildWorkflow: <TChildContract extends ContractDefinition, TChildWorkflowName extends keyof TChildContract["workflows"]>(contract: TChildContract, workflowName: TChildWorkflowName, options: TypedChildWorkflowOptions & {
|
|
335
|
+
args: WorkerInferInput<TChildContract["workflows"][TChildWorkflowName]>;
|
|
336
|
+
}) => Future<Result<TypedChildWorkflowHandle<TChildContract["workflows"][TChildWorkflowName]>, ChildWorkflowError>>;
|
|
337
|
+
/**
|
|
338
|
+
* Execute a child workflow (start and wait for result) with Future/Result pattern
|
|
339
|
+
*
|
|
340
|
+
* Supports both same-contract and cross-contract child workflows:
|
|
341
|
+
* - Same contract: Pass workflowName from current contract
|
|
342
|
+
* - Cross-contract: Pass contract and workflowName to invoke workflows from other workers
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* // Same contract child workflow
|
|
347
|
+
* const result = await context.executeChildWorkflow(myContract, 'processPayment', {
|
|
348
|
+
* workflowId: 'payment-123',
|
|
349
|
+
* args: { amount: 100 }
|
|
350
|
+
* });
|
|
351
|
+
*
|
|
352
|
+
* // Cross-contract child workflow (from another worker)
|
|
353
|
+
* const otherResult = await context.executeChildWorkflow(otherContract, 'sendNotification', {
|
|
354
|
+
* workflowId: 'notification-123',
|
|
355
|
+
* args: { message: 'Hello' }
|
|
356
|
+
* });
|
|
357
|
+
*
|
|
358
|
+
* result.match({
|
|
359
|
+
* Ok: (output) => console.log('Payment processed:', output),
|
|
360
|
+
* Error: (error) => console.error('Processing failed:', error),
|
|
361
|
+
* });
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
executeChildWorkflow: <TChildContract extends ContractDefinition, TChildWorkflowName extends keyof TChildContract["workflows"]>(contract: TChildContract, workflowName: TChildWorkflowName, options: TypedChildWorkflowOptions & {
|
|
365
|
+
args: WorkerInferInput<TChildContract["workflows"][TChildWorkflowName]>;
|
|
366
|
+
}) => Future<Result<WorkerInferOutput<TChildContract["workflows"][TChildWorkflowName]>, ChildWorkflowError>>;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Workflow implementation function (receives context + typed args as tuple)
|
|
370
|
+
* Note: We use 'any' for args to work around TypeScript limitations with generic Zod tuple inference
|
|
371
|
+
* The actual type will be enforced at runtime by Zod validation
|
|
372
|
+
*/
|
|
373
|
+
type WorkflowImplementation<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = (context: WorkflowContext<TContract, TWorkflowName>, args: WorkerInferInput<TContract["workflows"][TWorkflowName]>) => Promise<WorkerInferOutput<TContract["workflows"][TWorkflowName]>>;
|
|
374
|
+
/**
|
|
375
|
+
* Activity implementation using Result pattern
|
|
376
|
+
* Returns Future<Result<Output, ActivityError>> instead of throwing exceptions
|
|
377
|
+
*/
|
|
378
|
+
type BoxedActivityImplementation<TActivity extends ActivityDefinition> = (args: WorkerInferInput<TActivity>) => Future<Result<WorkerInferOutput<TActivity>, ActivityError>>;
|
|
379
|
+
/**
|
|
380
|
+
* Signal handler implementation
|
|
381
|
+
*/
|
|
382
|
+
type SignalHandlerImplementation<TSignal extends SignalDefinition> = (args: WorkerInferInput<TSignal>) => void | Promise<void>;
|
|
383
|
+
/**
|
|
384
|
+
* Query handler implementation
|
|
385
|
+
*/
|
|
386
|
+
type QueryHandlerImplementation<TQuery extends QueryDefinition> = (args: WorkerInferInput<TQuery>) => WorkerInferOutput<TQuery>;
|
|
387
|
+
/**
|
|
388
|
+
* Update handler implementation
|
|
389
|
+
*/
|
|
390
|
+
type UpdateHandlerImplementation<TUpdate extends UpdateDefinition> = (args: WorkerInferInput<TUpdate>) => Promise<WorkerInferOutput<TUpdate>>;
|
|
391
|
+
/**
|
|
392
|
+
* Map of all activity implementations for a contract (global + all workflow-specific)
|
|
393
|
+
*/
|
|
394
|
+
type ActivityImplementations<T extends ContractDefinition> = (T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: BoxedActivityImplementation<T["activities"][K]> } : {}) & UnionToIntersection<{ [K in keyof T["workflows"]]: T["workflows"][K]["activities"] extends Record<string, ActivityDefinition> ? { [A in keyof T["workflows"][K]["activities"]]: BoxedActivityImplementation<T["workflows"][K]["activities"][A]> } : {} }[keyof T["workflows"]]>;
|
|
395
|
+
/**
|
|
396
|
+
* Utility type to convert union to intersection
|
|
397
|
+
*/
|
|
398
|
+
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
399
|
+
/**
|
|
400
|
+
* Options for creating activities handler
|
|
401
|
+
*/
|
|
402
|
+
interface DeclareActivitiesHandlerOptions<T extends ContractDefinition> {
|
|
403
|
+
contract: T;
|
|
404
|
+
activities: ActivityImplementations<T>;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Activities handler ready for Temporal Worker
|
|
408
|
+
*/
|
|
409
|
+
interface ActivitiesHandler<T extends ContractDefinition> {
|
|
410
|
+
contract: T;
|
|
411
|
+
activities: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Options for declaring a workflow implementation
|
|
415
|
+
*/
|
|
416
|
+
interface DeclareWorkflowOptions<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> {
|
|
417
|
+
workflowName: TWorkflowName;
|
|
418
|
+
contract: TContract;
|
|
419
|
+
implementation: WorkflowImplementation<TContract, TWorkflowName>;
|
|
420
|
+
/**
|
|
421
|
+
* Default activity options applied to all activities in this workflow.
|
|
422
|
+
* These will be merged with the default startToCloseTimeout of 60 seconds.
|
|
423
|
+
* For more control, you can override specific Temporal ActivityOptions like:
|
|
424
|
+
* - startToCloseTimeout: Maximum time for activity execution
|
|
425
|
+
* - scheduleToCloseTimeout: End-to-end timeout including queuing
|
|
426
|
+
* - scheduleToStartTimeout: Maximum time activity can wait in queue
|
|
427
|
+
* - heartbeatTimeout: Time between heartbeats before considering activity dead
|
|
428
|
+
* - retry: Retry policy for failed activities
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```ts
|
|
432
|
+
* activityOptions: {
|
|
433
|
+
* startToCloseTimeout: '5m',
|
|
434
|
+
* retry: { maximumAttempts: 3 }
|
|
435
|
+
* }
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
activityOptions?: ActivityOptions;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Create a typed activities handler with automatic validation and Result pattern
|
|
442
|
+
*
|
|
443
|
+
* This wraps all activity implementations with:
|
|
444
|
+
* - Validation at network boundaries
|
|
445
|
+
* - Result<T, ActivityError> pattern for explicit error handling
|
|
446
|
+
* - Automatic conversion from Result to Promise (throwing on Error)
|
|
447
|
+
*
|
|
448
|
+
* TypeScript ensures ALL activities (global + workflow-specific) are implemented.
|
|
449
|
+
*
|
|
450
|
+
* Use this to create the activities object for the Temporal Worker.
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```ts
|
|
454
|
+
* import { declareActivitiesHandler, ActivityError } from '@temporal-contract/worker/activity';
|
|
455
|
+
* import { Result, Future } from '@temporal-contract/boxed';
|
|
456
|
+
* import myContract from './contract';
|
|
457
|
+
*
|
|
458
|
+
* export const activitiesHandler = declareActivitiesHandler({
|
|
459
|
+
* contract: myContract,
|
|
460
|
+
* activities: {
|
|
461
|
+
* // Activity returns Result instead of throwing
|
|
462
|
+
* // All technical exceptions must be wrapped in ActivityError for retry policies
|
|
463
|
+
* sendEmail: (args) => {
|
|
464
|
+
* return Future.make(async resolve => {
|
|
465
|
+
* try {
|
|
466
|
+
* await emailService.send(args);
|
|
467
|
+
* resolve(Result.Ok({ sent: true }));
|
|
468
|
+
* } catch (error) {
|
|
469
|
+
* // Wrap technical errors in ActivityError to enable retries
|
|
470
|
+
* resolve(Result.Error(
|
|
471
|
+
* new ActivityError(
|
|
472
|
+
* 'EMAIL_SEND_FAILED',
|
|
473
|
+
* 'Failed to send email',
|
|
474
|
+
* error // Original error as cause for debugging
|
|
475
|
+
* )
|
|
476
|
+
* ));
|
|
477
|
+
* }
|
|
478
|
+
* });
|
|
479
|
+
* },
|
|
480
|
+
* },
|
|
481
|
+
* });
|
|
482
|
+
*
|
|
483
|
+
* // Use with Temporal Worker
|
|
484
|
+
* import { Worker } from '@temporalio/worker';
|
|
485
|
+
*
|
|
486
|
+
* const worker = await Worker.create({
|
|
487
|
+
* workflowsPath: require.resolve('./workflows'),
|
|
488
|
+
* activities: activitiesHandler.activities,
|
|
489
|
+
* taskQueue: activitiesHandler.contract.taskQueue,
|
|
490
|
+
* });
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
declare function declareActivitiesHandler<T extends ContractDefinition>(options: DeclareActivitiesHandlerOptions<T>): ActivitiesHandler<T>;
|
|
494
|
+
/**
|
|
495
|
+
* Create a typed workflow implementation with automatic validation
|
|
496
|
+
*
|
|
497
|
+
* This wraps a workflow implementation with:
|
|
498
|
+
* - Input/output validation
|
|
499
|
+
* - Typed workflow context with activities
|
|
500
|
+
* - Workflow info access
|
|
501
|
+
*
|
|
502
|
+
* Workflows must be defined in separate files and imported by the Temporal Worker
|
|
503
|
+
* via workflowsPath.
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* // workflows/processOrder.ts
|
|
508
|
+
* import { declareWorkflow } from '@temporal-contract/worker';
|
|
509
|
+
* import myContract from '../contract';
|
|
510
|
+
*
|
|
511
|
+
* export const processOrder = declareWorkflow({
|
|
512
|
+
* workflowName: 'processOrder',
|
|
513
|
+
* contract: myContract,
|
|
514
|
+
* implementation: async (context, orderId, customerId) => {
|
|
515
|
+
* // context.activities: typed activities (workflow + global)
|
|
516
|
+
* // context.info: WorkflowInfo
|
|
517
|
+
*
|
|
518
|
+
* const inventory = await context.activities.validateInventory(orderId);
|
|
519
|
+
*
|
|
520
|
+
* if (!inventory.available) {
|
|
521
|
+
* throw new Error('Out of stock');
|
|
522
|
+
* }
|
|
523
|
+
*
|
|
524
|
+
* const payment = await context.activities.chargePayment(customerId, 100);
|
|
525
|
+
*
|
|
526
|
+
* // Global activity
|
|
527
|
+
* await context.activities.sendEmail(
|
|
528
|
+
* customerId,
|
|
529
|
+
* 'Order processed',
|
|
530
|
+
* 'Your order has been processed'
|
|
531
|
+
* );
|
|
532
|
+
*
|
|
533
|
+
* return {
|
|
534
|
+
* orderId,
|
|
535
|
+
* status: payment.success ? 'success' : 'failed',
|
|
536
|
+
* transactionId: payment.transactionId,
|
|
537
|
+
* };
|
|
538
|
+
* },
|
|
539
|
+
* activityOptions: {
|
|
540
|
+
* startToCloseTimeout: '1 minute',
|
|
541
|
+
* },
|
|
542
|
+
* });
|
|
543
|
+
* ```
|
|
544
|
+
*
|
|
545
|
+
* Then in your worker setup:
|
|
546
|
+
* ```ts
|
|
547
|
+
* // worker.ts
|
|
548
|
+
* import { Worker } from '@temporalio/worker';
|
|
549
|
+
* import { activitiesHandler } from './activities';
|
|
550
|
+
*
|
|
551
|
+
* const worker = await Worker.create({
|
|
552
|
+
* workflowsPath: require.resolve('./workflows'), // Imports processOrder
|
|
553
|
+
* activities: activitiesHandler.activities,
|
|
554
|
+
* taskQueue: activitiesHandler.contract.taskQueue,
|
|
555
|
+
* });
|
|
556
|
+
* ```
|
|
557
|
+
*/
|
|
558
|
+
declare function declareWorkflow<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]>(options: DeclareWorkflowOptions<TContract, TWorkflowName>): (args: WorkerInferInput<TContract["workflows"][TWorkflowName]>) => Promise<WorkerInferOutput<TContract["workflows"][TWorkflowName]>>;
|
|
559
|
+
//#endregion
|
|
560
|
+
export { WorkerInferActivities as A, WorkerInferWorkflowQueries as B, SignalInputValidationError as C, WorkflowInputValidationError as D, WorkerError as E, WorkerInferSignal as F, WorkerInferWorkflowUpdates as H, WorkerInferUpdate as I, WorkerInferWorkflow as L, WorkerInferInput as M, WorkerInferOutput as N, WorkflowOutputValidationError as O, WorkerInferQuery as P, WorkerInferWorkflowActivities as R, QueryOutputValidationError as S, UpdateOutputValidationError as T, WorkerInferWorkflows as U, WorkerInferWorkflowSignals as V, WorkflowActivityHandler as W, ActivityInputValidationError as _, DeclareWorkflowOptions as a, ChildWorkflowNotFoundError as b, TypedChildWorkflowHandle as c, WorkflowContext as d, WorkflowImplementation as f, ActivityError as g, ActivityDefinitionNotFoundError as h, DeclareActivitiesHandlerOptions as i, WorkerInferActivity as j, ActivityHandler as k, TypedChildWorkflowOptions as l, declareWorkflow as m, ActivityImplementations as n, QueryHandlerImplementation as o, declareActivitiesHandler as p, BoxedActivityImplementation as r, SignalHandlerImplementation as s, ActivitiesHandler as t, UpdateHandlerImplementation as u, ActivityOutputValidationError as v, UpdateInputValidationError as w, QueryInputValidationError as x, ChildWorkflowError as y, WorkerInferWorkflowContextActivities as z };
|