@temporal-contract/worker 0.0.1 → 0.0.3
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 +14 -93
- package/dist/activity.cjs +1 -1
- package/dist/activity.d.cts +1 -1
- package/dist/activity.d.mts +1 -1
- package/dist/activity.mjs +1 -1
- package/dist/{errors-CqX81ysy.d.cts → errors-B50uht6a.d.cts} +19 -19
- package/dist/{errors-oc-Iiwmu.d.mts → errors-DgUMRes-.d.mts} +19 -19
- package/dist/{handler-aA2RFdV7.mjs → handler-BP9xAycT.mjs} +73 -106
- package/dist/{handler-B3KY0uDx.cjs → handler-Cc951VQp.cjs} +73 -106
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.d.cts +1 -1
- package/dist/workflow.d.mts +1 -1
- package/dist/workflow.mjs +1 -1
- package/package.json +9 -5
- package/.turbo/turbo-build.log +0 -25
- package/src/activity.ts +0 -15
- package/src/errors.ts +0 -164
- package/src/handler.spec.ts +0 -525
- package/src/handler.ts +0 -621
- package/src/workflow.ts +0 -20
- package/tsconfig.json +0 -9
package/src/handler.ts
DELETED
|
@@ -1,621 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ActivityOptions,
|
|
3
|
-
WorkflowInfo,
|
|
4
|
-
defineQuery,
|
|
5
|
-
defineSignal,
|
|
6
|
-
defineUpdate,
|
|
7
|
-
proxyActivities,
|
|
8
|
-
setHandler,
|
|
9
|
-
workflowInfo,
|
|
10
|
-
} from "@temporalio/workflow";
|
|
11
|
-
import { ZodError } from "zod";
|
|
12
|
-
import type {
|
|
13
|
-
ActivityDefinition,
|
|
14
|
-
ContractDefinition,
|
|
15
|
-
QueryDefinition,
|
|
16
|
-
SignalDefinition,
|
|
17
|
-
UpdateDefinition,
|
|
18
|
-
WorkerInferInput,
|
|
19
|
-
WorkerInferOutput,
|
|
20
|
-
WorkerInferWorkflowContextActivities,
|
|
21
|
-
WorkflowDefinition,
|
|
22
|
-
} from "@temporal-contract/contract";
|
|
23
|
-
import {
|
|
24
|
-
ActivityImplementationNotFoundError,
|
|
25
|
-
ActivityDefinitionNotFoundError,
|
|
26
|
-
ActivityInputValidationError,
|
|
27
|
-
ActivityOutputValidationError,
|
|
28
|
-
WorkflowInputValidationError,
|
|
29
|
-
WorkflowOutputValidationError,
|
|
30
|
-
SignalInputValidationError,
|
|
31
|
-
QueryInputValidationError,
|
|
32
|
-
QueryOutputValidationError,
|
|
33
|
-
UpdateInputValidationError,
|
|
34
|
-
UpdateOutputValidationError,
|
|
35
|
-
} from "./errors.js";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Workflow context with typed activities (workflow + global) and workflow info
|
|
39
|
-
* Note: activities is typed as 'any' to work around TypeScript generic type inference limitations with Zod tuples
|
|
40
|
-
*/
|
|
41
|
-
export interface WorkflowContext<
|
|
42
|
-
TContract extends ContractDefinition,
|
|
43
|
-
TWorkflowName extends keyof TContract["workflows"],
|
|
44
|
-
> {
|
|
45
|
-
activities: WorkerInferWorkflowContextActivities<TContract, TWorkflowName>;
|
|
46
|
-
info: WorkflowInfo;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Workflow implementation function (receives context + typed args as tuple)
|
|
51
|
-
* Note: We use 'any' for args to work around TypeScript limitations with generic Zod tuple inference
|
|
52
|
-
* The actual type will be enforced at runtime by Zod validation
|
|
53
|
-
*/
|
|
54
|
-
export type WorkflowImplementation<
|
|
55
|
-
TContract extends ContractDefinition,
|
|
56
|
-
TWorkflowName extends keyof TContract["workflows"],
|
|
57
|
-
> = (
|
|
58
|
-
context: WorkflowContext<TContract, TWorkflowName>,
|
|
59
|
-
args: WorkerInferInput<TContract["workflows"][TWorkflowName]>,
|
|
60
|
-
) => Promise<WorkerInferOutput<TContract["workflows"][TWorkflowName]>>;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Raw activity implementation function (receives typed args as tuple)
|
|
64
|
-
* Note: We use 'any' for args/return to work around TypeScript limitations with generic Zod tuple inference
|
|
65
|
-
* The actual types will be enforced at runtime by Zod validation
|
|
66
|
-
*/
|
|
67
|
-
export type RawActivityImplementation<TActivity extends ActivityDefinition> = (
|
|
68
|
-
args: WorkerInferInput<TActivity>,
|
|
69
|
-
) => Promise<WorkerInferOutput<TActivity>>;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Signal handler implementation
|
|
73
|
-
*/
|
|
74
|
-
export type SignalHandlerImplementation<TSignal extends SignalDefinition> = (
|
|
75
|
-
args: WorkerInferInput<TSignal>,
|
|
76
|
-
) => void | Promise<void>;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Query handler implementation
|
|
80
|
-
*/
|
|
81
|
-
export type QueryHandlerImplementation<TQuery extends QueryDefinition> = (
|
|
82
|
-
args: WorkerInferInput<TQuery>,
|
|
83
|
-
) => WorkerInferOutput<TQuery>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Update handler implementation
|
|
87
|
-
*/
|
|
88
|
-
export type UpdateHandlerImplementation<TUpdate extends UpdateDefinition> = (
|
|
89
|
-
args: WorkerInferInput<TUpdate>,
|
|
90
|
-
) => Promise<WorkerInferOutput<TUpdate>>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Map of all activity implementations for a contract (global + all workflow-specific)
|
|
94
|
-
*/
|
|
95
|
-
export type ActivityImplementations<T extends ContractDefinition> =
|
|
96
|
-
// Global activities
|
|
97
|
-
(T["activities"] extends Record<string, ActivityDefinition>
|
|
98
|
-
? {
|
|
99
|
-
[K in keyof T["activities"]]: RawActivityImplementation<T["activities"][K]>;
|
|
100
|
-
}
|
|
101
|
-
: {}) &
|
|
102
|
-
// All workflow-specific activities merged
|
|
103
|
-
UnionToIntersection<
|
|
104
|
-
{
|
|
105
|
-
[K in keyof T["workflows"]]: T["workflows"][K]["activities"] extends Record<
|
|
106
|
-
string,
|
|
107
|
-
ActivityDefinition
|
|
108
|
-
>
|
|
109
|
-
? {
|
|
110
|
-
[A in keyof T["workflows"][K]["activities"]]: RawActivityImplementation<
|
|
111
|
-
T["workflows"][K]["activities"][A]
|
|
112
|
-
>;
|
|
113
|
-
}
|
|
114
|
-
: {};
|
|
115
|
-
}[keyof T["workflows"]]
|
|
116
|
-
>;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Utility type to convert union to intersection
|
|
120
|
-
*/
|
|
121
|
-
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (
|
|
122
|
-
k: infer I,
|
|
123
|
-
) => void
|
|
124
|
-
? I
|
|
125
|
-
: never;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Options for creating activities handler
|
|
129
|
-
*/
|
|
130
|
-
export interface DeclareActivitiesHandlerOptions<T extends ContractDefinition> {
|
|
131
|
-
contract: T;
|
|
132
|
-
activities: ActivityImplementations<T>;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Activities handler ready for Temporal Worker
|
|
137
|
-
*/
|
|
138
|
-
export interface ActivitiesHandler<T extends ContractDefinition> {
|
|
139
|
-
contract: T;
|
|
140
|
-
activities: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Options for declaring a workflow implementation
|
|
145
|
-
*/
|
|
146
|
-
export interface DeclareWorkflowOptions<
|
|
147
|
-
TContract extends ContractDefinition,
|
|
148
|
-
TWorkflowName extends keyof TContract["workflows"],
|
|
149
|
-
> {
|
|
150
|
-
workflowName: TWorkflowName;
|
|
151
|
-
contract: TContract;
|
|
152
|
-
implementation: WorkflowImplementation<TContract, TWorkflowName>;
|
|
153
|
-
/**
|
|
154
|
-
* Default activity options applied to all activities in this workflow.
|
|
155
|
-
* These will be merged with the default startToCloseTimeout of 60 seconds.
|
|
156
|
-
* For more control, you can override specific Temporal ActivityOptions like:
|
|
157
|
-
* - startToCloseTimeout: Maximum time for activity execution
|
|
158
|
-
* - scheduleToCloseTimeout: End-to-end timeout including queuing
|
|
159
|
-
* - scheduleToStartTimeout: Maximum time activity can wait in queue
|
|
160
|
-
* - heartbeatTimeout: Time between heartbeats before considering activity dead
|
|
161
|
-
* - retry: Retry policy for failed activities
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* ```ts
|
|
165
|
-
* activityOptions: {
|
|
166
|
-
* startToCloseTimeout: '5m',
|
|
167
|
-
* retry: { maximumAttempts: 3 }
|
|
168
|
-
* }
|
|
169
|
-
* ```
|
|
170
|
-
*/
|
|
171
|
-
activityOptions?: ActivityOptions;
|
|
172
|
-
/**
|
|
173
|
-
* Signal handlers (if defined in workflow)
|
|
174
|
-
*/
|
|
175
|
-
signals?: TContract["workflows"][TWorkflowName]["signals"] extends Record<
|
|
176
|
-
string,
|
|
177
|
-
SignalDefinition
|
|
178
|
-
>
|
|
179
|
-
? {
|
|
180
|
-
[K in keyof TContract["workflows"][TWorkflowName]["signals"]]: SignalHandlerImplementation<
|
|
181
|
-
TContract["workflows"][TWorkflowName]["signals"][K]
|
|
182
|
-
>;
|
|
183
|
-
}
|
|
184
|
-
: never;
|
|
185
|
-
/**
|
|
186
|
-
* Query handlers (if defined in workflow)
|
|
187
|
-
*/
|
|
188
|
-
queries?: TContract["workflows"][TWorkflowName]["queries"] extends Record<string, QueryDefinition>
|
|
189
|
-
? {
|
|
190
|
-
[K in keyof TContract["workflows"][TWorkflowName]["queries"]]: QueryHandlerImplementation<
|
|
191
|
-
TContract["workflows"][TWorkflowName]["queries"][K]
|
|
192
|
-
>;
|
|
193
|
-
}
|
|
194
|
-
: never;
|
|
195
|
-
/**
|
|
196
|
-
* Update handlers (if defined in workflow)
|
|
197
|
-
*/
|
|
198
|
-
updates?: TContract["workflows"][TWorkflowName]["updates"] extends Record<
|
|
199
|
-
string,
|
|
200
|
-
UpdateDefinition
|
|
201
|
-
>
|
|
202
|
-
? {
|
|
203
|
-
[K in keyof TContract["workflows"][TWorkflowName]["updates"]]: UpdateHandlerImplementation<
|
|
204
|
-
TContract["workflows"][TWorkflowName]["updates"][K]
|
|
205
|
-
>;
|
|
206
|
-
}
|
|
207
|
-
: never;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Create a validated activities proxy that parses inputs and outputs
|
|
212
|
-
*
|
|
213
|
-
* This wrapper ensures data integrity across the network boundary between
|
|
214
|
-
* workflow and activity execution.
|
|
215
|
-
*/
|
|
216
|
-
function createValidatedActivities<
|
|
217
|
-
TContract extends ContractDefinition,
|
|
218
|
-
TWorkflowName extends keyof TContract["workflows"],
|
|
219
|
-
>(
|
|
220
|
-
rawActivities: Record<string, (...args: unknown[]) => Promise<unknown>>,
|
|
221
|
-
workflowActivitiesDefinition: Record<string, ActivityDefinition> | undefined,
|
|
222
|
-
contractActivitiesDefinition: Record<string, ActivityDefinition> | undefined,
|
|
223
|
-
): WorkerInferWorkflowContextActivities<TContract, TWorkflowName> {
|
|
224
|
-
const validatedActivities = {} as WorkerInferWorkflowContextActivities<TContract, TWorkflowName>;
|
|
225
|
-
|
|
226
|
-
// Merge workflow activities and global contract activities
|
|
227
|
-
const allActivitiesDefinition = {
|
|
228
|
-
...contractActivitiesDefinition,
|
|
229
|
-
...workflowActivitiesDefinition, // Workflow activities override global ones
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
for (const [activityName, activityDef] of Object.entries(allActivitiesDefinition)) {
|
|
233
|
-
const rawActivity = rawActivities[activityName];
|
|
234
|
-
|
|
235
|
-
if (!rawActivity) {
|
|
236
|
-
throw new ActivityImplementationNotFoundError(activityName, Object.keys(rawActivities));
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// @ts-expect-error fixme later
|
|
240
|
-
validatedActivities[activityName] = async (input: unknown) => {
|
|
241
|
-
// Validate input before sending over network
|
|
242
|
-
let validatedInput: unknown;
|
|
243
|
-
try {
|
|
244
|
-
validatedInput = activityDef.input.parse(input);
|
|
245
|
-
} catch (error) {
|
|
246
|
-
if (error instanceof ZodError) {
|
|
247
|
-
throw new ActivityInputValidationError(activityName, error);
|
|
248
|
-
}
|
|
249
|
-
throw error;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Call the actual activity (pass the single parameter directly)
|
|
253
|
-
const result = await rawActivity(validatedInput);
|
|
254
|
-
|
|
255
|
-
// Validate output after receiving from network
|
|
256
|
-
try {
|
|
257
|
-
return activityDef.output.parse(result);
|
|
258
|
-
} catch (error) {
|
|
259
|
-
if (error instanceof ZodError) {
|
|
260
|
-
throw new ActivityOutputValidationError(activityName, error);
|
|
261
|
-
}
|
|
262
|
-
throw error;
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return validatedActivities;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Create a typed activities handler with automatic validation
|
|
272
|
-
*
|
|
273
|
-
* This wraps all activity implementations with Zod validation at network boundaries.
|
|
274
|
-
* TypeScript ensures ALL activities (global + workflow-specific) are implemented.
|
|
275
|
-
*
|
|
276
|
-
* Use this to create the activities object for the Temporal Worker.
|
|
277
|
-
*
|
|
278
|
-
* @example
|
|
279
|
-
* ```ts
|
|
280
|
-
* import { declareActivitiesHandler } from '@temporal-contract/worker';
|
|
281
|
-
* import myContract from './contract';
|
|
282
|
-
*
|
|
283
|
-
* export const activitiesHandler = declareActivitiesHandler({
|
|
284
|
-
* contract: myContract,
|
|
285
|
-
* activities: {
|
|
286
|
-
* // Global activities
|
|
287
|
-
* sendEmail: async (to, subject, body) => {
|
|
288
|
-
* await emailService.send({ to, subject, body });
|
|
289
|
-
* return { sent: true };
|
|
290
|
-
* },
|
|
291
|
-
* // Workflow-specific activities
|
|
292
|
-
* validateInventory: async (orderId) => {
|
|
293
|
-
* const available = await inventory.check(orderId);
|
|
294
|
-
* return { available };
|
|
295
|
-
* },
|
|
296
|
-
* },
|
|
297
|
-
* });
|
|
298
|
-
*
|
|
299
|
-
* // Use with Temporal Worker
|
|
300
|
-
* import { Worker } from '@temporalio/worker';
|
|
301
|
-
*
|
|
302
|
-
* const worker = await Worker.create({
|
|
303
|
-
* workflowsPath: require.resolve('./workflows'),
|
|
304
|
-
* activities: activitiesHandler.activities,
|
|
305
|
-
* taskQueue: activitiesHandler.contract.taskQueue,
|
|
306
|
-
* });
|
|
307
|
-
* ```
|
|
308
|
-
*/
|
|
309
|
-
export function declareActivitiesHandler<T extends ContractDefinition>(
|
|
310
|
-
options: DeclareActivitiesHandlerOptions<T>,
|
|
311
|
-
): ActivitiesHandler<T> {
|
|
312
|
-
const { contract, activities } = options;
|
|
313
|
-
|
|
314
|
-
// Wrap activities with validation
|
|
315
|
-
const wrappedActivities: Record<string, (...args: unknown[]) => Promise<unknown>> = {};
|
|
316
|
-
|
|
317
|
-
// Collect all available activity definitions
|
|
318
|
-
const allDefinitions: string[] = [];
|
|
319
|
-
if (contract.activities) {
|
|
320
|
-
allDefinitions.push(...Object.keys(contract.activities));
|
|
321
|
-
}
|
|
322
|
-
for (const workflow of Object.values(contract.workflows) as WorkflowDefinition[]) {
|
|
323
|
-
if (workflow.activities) {
|
|
324
|
-
allDefinitions.push(...Object.keys(workflow.activities));
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
for (const [activityName, activityImpl] of Object.entries(activities)) {
|
|
329
|
-
// Find activity definition (global or workflow-specific)
|
|
330
|
-
let activityDef: ActivityDefinition | undefined;
|
|
331
|
-
|
|
332
|
-
// Check global activities
|
|
333
|
-
if (contract.activities?.[activityName]) {
|
|
334
|
-
activityDef = contract.activities[activityName];
|
|
335
|
-
} else {
|
|
336
|
-
// Check workflow-specific activities
|
|
337
|
-
for (const workflow of Object.values(contract.workflows) as WorkflowDefinition[]) {
|
|
338
|
-
if (workflow.activities?.[activityName]) {
|
|
339
|
-
activityDef = workflow.activities[activityName];
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (!activityDef) {
|
|
346
|
-
throw new ActivityDefinitionNotFoundError(activityName, allDefinitions);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
wrappedActivities[activityName] = async (input: unknown) => {
|
|
350
|
-
// Validate input
|
|
351
|
-
let validatedInput: unknown;
|
|
352
|
-
try {
|
|
353
|
-
validatedInput = activityDef.input.parse(input);
|
|
354
|
-
} catch (error) {
|
|
355
|
-
if (error instanceof ZodError) {
|
|
356
|
-
throw new ActivityInputValidationError(activityName, error);
|
|
357
|
-
}
|
|
358
|
-
throw error;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Execute activity
|
|
362
|
-
const result = await activityImpl(validatedInput);
|
|
363
|
-
|
|
364
|
-
// Validate output
|
|
365
|
-
try {
|
|
366
|
-
return activityDef.output.parse(result);
|
|
367
|
-
} catch (error) {
|
|
368
|
-
if (error instanceof ZodError) {
|
|
369
|
-
throw new ActivityOutputValidationError(activityName, error);
|
|
370
|
-
}
|
|
371
|
-
throw error;
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return {
|
|
377
|
-
contract,
|
|
378
|
-
activities: wrappedActivities,
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Create a typed workflow implementation with automatic validation
|
|
384
|
-
*
|
|
385
|
-
* This wraps a workflow implementation with:
|
|
386
|
-
* - Input/output validation
|
|
387
|
-
* - Typed workflow context with activities
|
|
388
|
-
* - Workflow info access
|
|
389
|
-
*
|
|
390
|
-
* Workflows must be defined in separate files and imported by the Temporal Worker
|
|
391
|
-
* via workflowsPath.
|
|
392
|
-
*
|
|
393
|
-
* @example
|
|
394
|
-
* ```ts
|
|
395
|
-
* // workflows/processOrder.ts
|
|
396
|
-
* import { declareWorkflow } from '@temporal-contract/worker';
|
|
397
|
-
* import myContract from '../contract';
|
|
398
|
-
*
|
|
399
|
-
* export const processOrder = declareWorkflow({
|
|
400
|
-
* workflowName: 'processOrder',
|
|
401
|
-
* contract: myContract,
|
|
402
|
-
* implementation: async (context, orderId, customerId) => {
|
|
403
|
-
* // context.activities: typed activities (workflow + global)
|
|
404
|
-
* // context.info: WorkflowInfo
|
|
405
|
-
*
|
|
406
|
-
* const inventory = await context.activities.validateInventory(orderId);
|
|
407
|
-
*
|
|
408
|
-
* if (!inventory.available) {
|
|
409
|
-
* throw new Error('Out of stock');
|
|
410
|
-
* }
|
|
411
|
-
*
|
|
412
|
-
* const payment = await context.activities.chargePayment(customerId, 100);
|
|
413
|
-
*
|
|
414
|
-
* // Global activity
|
|
415
|
-
* await context.activities.sendEmail(
|
|
416
|
-
* customerId,
|
|
417
|
-
* 'Order processed',
|
|
418
|
-
* 'Your order has been processed'
|
|
419
|
-
* );
|
|
420
|
-
*
|
|
421
|
-
* return {
|
|
422
|
-
* orderId,
|
|
423
|
-
* status: payment.success ? 'success' : 'failed',
|
|
424
|
-
* transactionId: payment.transactionId,
|
|
425
|
-
* };
|
|
426
|
-
* },
|
|
427
|
-
* activityOptions: {
|
|
428
|
-
* startToCloseTimeout: '1 minute',
|
|
429
|
-
* },
|
|
430
|
-
* });
|
|
431
|
-
* ```
|
|
432
|
-
*
|
|
433
|
-
* Then in your worker setup:
|
|
434
|
-
* ```ts
|
|
435
|
-
* // worker.ts
|
|
436
|
-
* import { Worker } from '@temporalio/worker';
|
|
437
|
-
* import { activitiesHandler } from './activities';
|
|
438
|
-
*
|
|
439
|
-
* const worker = await Worker.create({
|
|
440
|
-
* workflowsPath: require.resolve('./workflows'), // Imports processOrder
|
|
441
|
-
* activities: activitiesHandler.activities,
|
|
442
|
-
* taskQueue: activitiesHandler.contract.taskQueue,
|
|
443
|
-
* });
|
|
444
|
-
* ```
|
|
445
|
-
*/
|
|
446
|
-
export function declareWorkflow<
|
|
447
|
-
TContract extends ContractDefinition,
|
|
448
|
-
TWorkflowName extends keyof TContract["workflows"],
|
|
449
|
-
>(
|
|
450
|
-
options: DeclareWorkflowOptions<TContract, TWorkflowName>,
|
|
451
|
-
): (
|
|
452
|
-
args: WorkerInferInput<TContract["workflows"][TWorkflowName]>,
|
|
453
|
-
) => Promise<WorkerInferOutput<TContract["workflows"][TWorkflowName]>> {
|
|
454
|
-
const { workflowName, contract, implementation, activityOptions, signals, queries, updates } =
|
|
455
|
-
options;
|
|
456
|
-
|
|
457
|
-
// Get the workflow definition from the contract
|
|
458
|
-
const definition = contract.workflows[
|
|
459
|
-
workflowName as string
|
|
460
|
-
] as TContract["workflows"][TWorkflowName];
|
|
461
|
-
|
|
462
|
-
return async (args) => {
|
|
463
|
-
// Temporal passes args as array, extract first element which is our single parameter
|
|
464
|
-
const singleArg = Array.isArray(args) ? args[0] : args;
|
|
465
|
-
|
|
466
|
-
// Validate workflow input
|
|
467
|
-
let validatedInput: WorkerInferInput<TContract["workflows"][TWorkflowName]>;
|
|
468
|
-
try {
|
|
469
|
-
validatedInput = definition.input.parse(singleArg) as WorkerInferInput<
|
|
470
|
-
TContract["workflows"][TWorkflowName]
|
|
471
|
-
>;
|
|
472
|
-
} catch (error) {
|
|
473
|
-
if (error instanceof ZodError) {
|
|
474
|
-
throw new WorkflowInputValidationError(String(workflowName), error);
|
|
475
|
-
}
|
|
476
|
-
throw error;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Register signal handlers
|
|
480
|
-
if (definition.signals && signals) {
|
|
481
|
-
const signalDefs = definition.signals as Record<string, SignalDefinition>;
|
|
482
|
-
const signalHandlers = signals as Record<string, unknown>;
|
|
483
|
-
|
|
484
|
-
for (const [signalName, signalDef] of Object.entries(signalDefs)) {
|
|
485
|
-
const handler = signalHandlers[signalName];
|
|
486
|
-
if (handler) {
|
|
487
|
-
const signal = defineSignal(signalName);
|
|
488
|
-
setHandler(signal, async (...args: unknown[]) => {
|
|
489
|
-
// Extract single parameter (Temporal passes as args array)
|
|
490
|
-
const input = args.length === 1 ? args[0] : args;
|
|
491
|
-
let validatedInput: unknown;
|
|
492
|
-
try {
|
|
493
|
-
validatedInput = signalDef.input.parse(input);
|
|
494
|
-
} catch (error) {
|
|
495
|
-
if (error instanceof ZodError) {
|
|
496
|
-
throw new SignalInputValidationError(signalName, error);
|
|
497
|
-
}
|
|
498
|
-
throw error;
|
|
499
|
-
}
|
|
500
|
-
await (handler as SignalHandlerImplementation<SignalDefinition>)(validatedInput);
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Register query handlers
|
|
507
|
-
if (definition.queries && queries) {
|
|
508
|
-
const queryDefs = definition.queries as Record<string, QueryDefinition>;
|
|
509
|
-
const queryHandlers = queries as Record<string, unknown>;
|
|
510
|
-
|
|
511
|
-
for (const [queryName, queryDef] of Object.entries(queryDefs)) {
|
|
512
|
-
const handler = queryHandlers[queryName];
|
|
513
|
-
if (handler) {
|
|
514
|
-
const query = defineQuery(queryName);
|
|
515
|
-
setHandler(query, (...args: unknown[]) => {
|
|
516
|
-
// Extract single parameter (Temporal passes as args array)
|
|
517
|
-
const input = args.length === 1 ? args[0] : args;
|
|
518
|
-
let validatedInput: unknown;
|
|
519
|
-
try {
|
|
520
|
-
validatedInput = queryDef.input.parse(input);
|
|
521
|
-
} catch (error) {
|
|
522
|
-
if (error instanceof ZodError) {
|
|
523
|
-
throw new QueryInputValidationError(queryName, error);
|
|
524
|
-
}
|
|
525
|
-
throw error;
|
|
526
|
-
}
|
|
527
|
-
const result = (handler as QueryHandlerImplementation<QueryDefinition>)(validatedInput);
|
|
528
|
-
try {
|
|
529
|
-
return queryDef.output.parse(result);
|
|
530
|
-
} catch (error) {
|
|
531
|
-
if (error instanceof ZodError) {
|
|
532
|
-
throw new QueryOutputValidationError(queryName, error);
|
|
533
|
-
}
|
|
534
|
-
throw error;
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Register update handlers
|
|
542
|
-
if (definition.updates && updates) {
|
|
543
|
-
const updateDefs = definition.updates as Record<string, UpdateDefinition>;
|
|
544
|
-
const updateHandlers = updates as Record<string, unknown>;
|
|
545
|
-
|
|
546
|
-
for (const [updateName, updateDef] of Object.entries(updateDefs)) {
|
|
547
|
-
const handler = updateHandlers[updateName];
|
|
548
|
-
if (handler) {
|
|
549
|
-
const update = defineUpdate(updateName);
|
|
550
|
-
setHandler(update, async (...args: unknown[]) => {
|
|
551
|
-
// Extract single parameter (Temporal passes as args array)
|
|
552
|
-
const input = args.length === 1 ? args[0] : args;
|
|
553
|
-
let validatedInput: unknown;
|
|
554
|
-
try {
|
|
555
|
-
validatedInput = updateDef.input.parse(input);
|
|
556
|
-
} catch (error) {
|
|
557
|
-
if (error instanceof ZodError) {
|
|
558
|
-
throw new UpdateInputValidationError(updateName, error);
|
|
559
|
-
}
|
|
560
|
-
throw error;
|
|
561
|
-
}
|
|
562
|
-
const result = await (handler as UpdateHandlerImplementation<UpdateDefinition>)(
|
|
563
|
-
validatedInput,
|
|
564
|
-
);
|
|
565
|
-
try {
|
|
566
|
-
return updateDef.output.parse(result);
|
|
567
|
-
} catch (error) {
|
|
568
|
-
if (error instanceof ZodError) {
|
|
569
|
-
throw new UpdateOutputValidationError(updateName, error);
|
|
570
|
-
}
|
|
571
|
-
throw error;
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// Create activities proxy if activities are defined
|
|
579
|
-
let contextActivities: unknown = {};
|
|
580
|
-
|
|
581
|
-
if (definition.activities || contract.activities) {
|
|
582
|
-
const rawActivities = proxyActivities<
|
|
583
|
-
Record<string, (...args: unknown[]) => Promise<unknown>>
|
|
584
|
-
>({
|
|
585
|
-
// Default to 1 minute if no timeout specified
|
|
586
|
-
startToCloseTimeout: activityOptions?.startToCloseTimeout ?? 60_000,
|
|
587
|
-
...activityOptions,
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
contextActivities = createValidatedActivities(
|
|
591
|
-
rawActivities,
|
|
592
|
-
definition.activities,
|
|
593
|
-
contract.activities,
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Create workflow context
|
|
598
|
-
const context: WorkflowContext<TContract, TWorkflowName> = {
|
|
599
|
-
activities: contextActivities as WorkerInferWorkflowContextActivities<
|
|
600
|
-
TContract,
|
|
601
|
-
TWorkflowName
|
|
602
|
-
>,
|
|
603
|
-
info: workflowInfo(),
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
// Execute workflow (pass validated input as tuple)
|
|
607
|
-
const result = await implementation(context, validatedInput);
|
|
608
|
-
|
|
609
|
-
// Validate workflow output
|
|
610
|
-
try {
|
|
611
|
-
return definition.output.parse(result) as WorkerInferOutput<
|
|
612
|
-
TContract["workflows"][TWorkflowName]
|
|
613
|
-
>;
|
|
614
|
-
} catch (error) {
|
|
615
|
-
if (error instanceof ZodError) {
|
|
616
|
-
throw new WorkflowOutputValidationError(String(workflowName), error);
|
|
617
|
-
}
|
|
618
|
-
throw error;
|
|
619
|
-
}
|
|
620
|
-
};
|
|
621
|
-
}
|
package/src/workflow.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// Entry point for workflows
|
|
2
|
-
export { declareWorkflow } from "./handler.js";
|
|
3
|
-
export type {
|
|
4
|
-
WorkflowContext,
|
|
5
|
-
WorkflowImplementation,
|
|
6
|
-
SignalHandlerImplementation,
|
|
7
|
-
QueryHandlerImplementation,
|
|
8
|
-
UpdateHandlerImplementation,
|
|
9
|
-
DeclareWorkflowOptions,
|
|
10
|
-
} from "./handler.js";
|
|
11
|
-
export {
|
|
12
|
-
WorkerError,
|
|
13
|
-
WorkflowInputValidationError,
|
|
14
|
-
WorkflowOutputValidationError,
|
|
15
|
-
SignalInputValidationError,
|
|
16
|
-
QueryInputValidationError,
|
|
17
|
-
QueryOutputValidationError,
|
|
18
|
-
UpdateInputValidationError,
|
|
19
|
-
UpdateOutputValidationError,
|
|
20
|
-
} from "./errors.js";
|