@temporal-contract/contract 0.0.2 → 0.0.4
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/dist/index.cjs +116 -0
- package/dist/index.d.cts +225 -1
- package/dist/index.d.mts +225 -1
- package/dist/index.mjs +115 -1
- package/package.json +19 -16
- package/.turbo/turbo-build.log +0 -17
- package/CHANGELOG.md +0 -7
- package/src/builder.spec.ts +0 -717
- package/src/builder.ts +0 -286
- package/src/helpers.spec.ts +0 -122
- package/src/index.ts +0 -55
- package/src/types.spec.ts +0 -637
- package/src/types.ts +0 -429
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -12
package/src/builder.spec.ts
DELETED
|
@@ -1,717 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { defineContract } from "./builder.js";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
|
|
5
|
-
describe("Contract Builder", () => {
|
|
6
|
-
describe("defineContract", () => {
|
|
7
|
-
it("should create a contract with workflows", () => {
|
|
8
|
-
const contract = defineContract({
|
|
9
|
-
taskQueue: "test-queue",
|
|
10
|
-
workflows: {
|
|
11
|
-
processOrder: {
|
|
12
|
-
input: z.object({ orderId: z.string() }),
|
|
13
|
-
output: z.object({ status: z.string() }),
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
expect(contract.taskQueue).toBe("test-queue");
|
|
19
|
-
expect(contract.workflows.processOrder).toBeDefined();
|
|
20
|
-
expect(contract.workflows.processOrder.input).toBeDefined();
|
|
21
|
-
expect(contract.workflows.processOrder.output).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("should create a contract with global activities", () => {
|
|
25
|
-
const contract = defineContract({
|
|
26
|
-
taskQueue: "test-queue",
|
|
27
|
-
workflows: {
|
|
28
|
-
simpleWorkflow: {
|
|
29
|
-
input: z.object({ value: z.string() }),
|
|
30
|
-
output: z.object({ result: z.string() }),
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
activities: {
|
|
34
|
-
sendEmail: {
|
|
35
|
-
input: z.object({ to: z.string(), subject: z.string(), body: z.string() }),
|
|
36
|
-
output: z.object({ sent: z.boolean() }),
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
expect(contract.activities).toBeDefined();
|
|
42
|
-
expect(contract.activities?.sendEmail).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should create a contract with workflow-specific activities", () => {
|
|
46
|
-
const contract = defineContract({
|
|
47
|
-
taskQueue: "test-queue",
|
|
48
|
-
workflows: {
|
|
49
|
-
processOrder: {
|
|
50
|
-
input: z.object({ orderId: z.string() }),
|
|
51
|
-
output: z.object({ status: z.string() }),
|
|
52
|
-
activities: {
|
|
53
|
-
validateInventory: {
|
|
54
|
-
input: z.object({ orderId: z.string() }),
|
|
55
|
-
output: z.object({ available: z.boolean() }),
|
|
56
|
-
},
|
|
57
|
-
processPayment: {
|
|
58
|
-
input: z.object({ amount: z.number() }),
|
|
59
|
-
output: z.object({ transactionId: z.string() }),
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
expect(contract.workflows.processOrder.activities).toBeDefined();
|
|
67
|
-
expect(contract.workflows.processOrder.activities?.validateInventory).toBeDefined();
|
|
68
|
-
expect(contract.workflows.processOrder.activities?.processPayment).toBeDefined();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("should support signals in workflow definitions", () => {
|
|
72
|
-
const contract = defineContract({
|
|
73
|
-
taskQueue: "test-queue",
|
|
74
|
-
workflows: {
|
|
75
|
-
processOrder: {
|
|
76
|
-
input: z.object({ orderId: z.string() }),
|
|
77
|
-
output: z.object({ status: z.string() }),
|
|
78
|
-
signals: {
|
|
79
|
-
cancel: {
|
|
80
|
-
input: z.object({ reason: z.string() }),
|
|
81
|
-
},
|
|
82
|
-
addItem: {
|
|
83
|
-
input: z.object({ itemId: z.string(), quantity: z.number() }),
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
expect(contract.workflows.processOrder.signals).toBeDefined();
|
|
91
|
-
expect(contract.workflows.processOrder.signals?.cancel).toBeDefined();
|
|
92
|
-
expect(contract.workflows.processOrder.signals?.addItem).toBeDefined();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("should support queries in workflow definitions", () => {
|
|
96
|
-
const contract = defineContract({
|
|
97
|
-
taskQueue: "test-queue",
|
|
98
|
-
workflows: {
|
|
99
|
-
processOrder: {
|
|
100
|
-
input: z.object({ orderId: z.string() }),
|
|
101
|
-
output: z.object({ status: z.string() }),
|
|
102
|
-
queries: {
|
|
103
|
-
getStatus: {
|
|
104
|
-
input: z.object({}),
|
|
105
|
-
output: z.object({ status: z.string(), progress: z.number() }),
|
|
106
|
-
},
|
|
107
|
-
getTotal: {
|
|
108
|
-
input: z.object({}),
|
|
109
|
-
output: z.object({ amount: z.number() }),
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(contract.workflows.processOrder.queries).toBeDefined();
|
|
117
|
-
expect(contract.workflows.processOrder.queries?.getStatus).toBeDefined();
|
|
118
|
-
expect(contract.workflows.processOrder.queries?.getTotal).toBeDefined();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("should support updates in workflow definitions", () => {
|
|
122
|
-
const contract = defineContract({
|
|
123
|
-
taskQueue: "test-queue",
|
|
124
|
-
workflows: {
|
|
125
|
-
processOrder: {
|
|
126
|
-
input: z.object({ orderId: z.string() }),
|
|
127
|
-
output: z.object({ status: z.string() }),
|
|
128
|
-
updates: {
|
|
129
|
-
updateDiscount: {
|
|
130
|
-
input: z.object({ percentage: z.number() }),
|
|
131
|
-
output: z.object({ newTotal: z.number() }),
|
|
132
|
-
},
|
|
133
|
-
updateShippingAddress: {
|
|
134
|
-
input: z.object({ address: z.string() }),
|
|
135
|
-
output: z.object({ updated: z.boolean() }),
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
expect(contract.workflows.processOrder.updates).toBeDefined();
|
|
143
|
-
expect(contract.workflows.processOrder.updates?.updateDiscount).toBeDefined();
|
|
144
|
-
expect(contract.workflows.processOrder.updates?.updateShippingAddress).toBeDefined();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("should support multiple workflows", () => {
|
|
148
|
-
const contract = defineContract({
|
|
149
|
-
taskQueue: "test-queue",
|
|
150
|
-
workflows: {
|
|
151
|
-
processOrder: {
|
|
152
|
-
input: z.object({ orderId: z.string() }),
|
|
153
|
-
output: z.object({ status: z.string() }),
|
|
154
|
-
},
|
|
155
|
-
cancelOrder: {
|
|
156
|
-
input: z.object({ orderId: z.string(), reason: z.string() }),
|
|
157
|
-
output: z.object({ cancelled: z.boolean() }),
|
|
158
|
-
},
|
|
159
|
-
refundOrder: {
|
|
160
|
-
input: z.object({ orderId: z.string(), amount: z.number() }),
|
|
161
|
-
output: z.object({ refunded: z.boolean(), transactionId: z.string() }),
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
expect(Object.keys(contract.workflows)).toHaveLength(3);
|
|
167
|
-
expect(contract.workflows.processOrder).toBeDefined();
|
|
168
|
-
expect(contract.workflows.cancelOrder).toBeDefined();
|
|
169
|
-
expect(contract.workflows.refundOrder).toBeDefined();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should validate single parameter pattern", () => {
|
|
173
|
-
const contract = defineContract({
|
|
174
|
-
taskQueue: "test-queue",
|
|
175
|
-
workflows: {
|
|
176
|
-
simpleWorkflow: {
|
|
177
|
-
input: z.string(), // Single primitive
|
|
178
|
-
output: z.object({ result: z.string() }),
|
|
179
|
-
},
|
|
180
|
-
complexWorkflow: {
|
|
181
|
-
input: z.object({
|
|
182
|
-
// Object with multiple properties
|
|
183
|
-
orderId: z.string(),
|
|
184
|
-
customerId: z.string(),
|
|
185
|
-
amount: z.number(),
|
|
186
|
-
}),
|
|
187
|
-
output: z.object({ success: z.boolean() }),
|
|
188
|
-
},
|
|
189
|
-
arrayWorkflow: {
|
|
190
|
-
input: z.array(
|
|
191
|
-
z.object({
|
|
192
|
-
// Array of objects
|
|
193
|
-
id: z.string(),
|
|
194
|
-
value: z.number(),
|
|
195
|
-
}),
|
|
196
|
-
),
|
|
197
|
-
output: z.object({ processed: z.number() }),
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(contract.workflows.simpleWorkflow.input).toBeDefined();
|
|
203
|
-
expect(contract.workflows.complexWorkflow.input).toBeDefined();
|
|
204
|
-
expect(contract.workflows.arrayWorkflow.input).toBeDefined();
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it("should preserve type information", () => {
|
|
208
|
-
const contract = defineContract({
|
|
209
|
-
taskQueue: "my-queue",
|
|
210
|
-
workflows: {
|
|
211
|
-
myWorkflow: {
|
|
212
|
-
input: z.object({ id: z.string() }),
|
|
213
|
-
output: z.object({ success: z.boolean() }),
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// Type assertions to verify inference works
|
|
219
|
-
const taskQueue: string = contract.taskQueue;
|
|
220
|
-
expect(taskQueue).toBe("my-queue");
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe("defineContract validation", () => {
|
|
225
|
-
it("should throw when taskQueue is empty", () => {
|
|
226
|
-
expect(() =>
|
|
227
|
-
defineContract({
|
|
228
|
-
taskQueue: "",
|
|
229
|
-
workflows: {
|
|
230
|
-
test: {
|
|
231
|
-
input: z.object({}),
|
|
232
|
-
output: z.object({}),
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
}),
|
|
236
|
-
).toThrow("taskQueue cannot be empty");
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("should throw when taskQueue is only whitespace", () => {
|
|
240
|
-
expect(() =>
|
|
241
|
-
defineContract({
|
|
242
|
-
taskQueue: " ",
|
|
243
|
-
workflows: {
|
|
244
|
-
test: {
|
|
245
|
-
input: z.object({}),
|
|
246
|
-
output: z.object({}),
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
}),
|
|
250
|
-
).toThrow("Contract error");
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it("should throw when no workflows are defined", () => {
|
|
254
|
-
expect(() =>
|
|
255
|
-
defineContract({
|
|
256
|
-
taskQueue: "test",
|
|
257
|
-
workflows: {},
|
|
258
|
-
}),
|
|
259
|
-
).toThrow("at least one workflow is required");
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("should throw when workflow name is invalid", () => {
|
|
263
|
-
expect(() =>
|
|
264
|
-
defineContract({
|
|
265
|
-
taskQueue: "test",
|
|
266
|
-
workflows: {
|
|
267
|
-
"invalid-name": {
|
|
268
|
-
input: z.object({}),
|
|
269
|
-
output: z.object({}),
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
}),
|
|
273
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
it("should throw when global activity name is invalid", () => {
|
|
277
|
-
expect(() =>
|
|
278
|
-
defineContract({
|
|
279
|
-
taskQueue: "test",
|
|
280
|
-
workflows: {
|
|
281
|
-
test: {
|
|
282
|
-
input: z.object({}),
|
|
283
|
-
output: z.object({}),
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
activities: {
|
|
287
|
-
"send-email": {
|
|
288
|
-
input: z.object({}),
|
|
289
|
-
output: z.object({}),
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
}),
|
|
293
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it("should throw when workflow activity conflicts with global activity", () => {
|
|
297
|
-
expect(() =>
|
|
298
|
-
defineContract({
|
|
299
|
-
taskQueue: "test",
|
|
300
|
-
workflows: {
|
|
301
|
-
processOrder: {
|
|
302
|
-
input: z.object({}),
|
|
303
|
-
output: z.object({}),
|
|
304
|
-
activities: {
|
|
305
|
-
sendEmail: {
|
|
306
|
-
input: z.object({}),
|
|
307
|
-
output: z.object({}),
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
activities: {
|
|
313
|
-
sendEmail: {
|
|
314
|
-
input: z.object({}),
|
|
315
|
-
output: z.object({}),
|
|
316
|
-
},
|
|
317
|
-
},
|
|
318
|
-
}),
|
|
319
|
-
).toThrow(
|
|
320
|
-
'workflow "processOrder" has activity "sendEmail" that conflicts with a global activity. Consider renaming the workflow-specific activity or removing the global activity "sendEmail".',
|
|
321
|
-
);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it("should throw when signal name is invalid", () => {
|
|
325
|
-
expect(() =>
|
|
326
|
-
defineContract({
|
|
327
|
-
taskQueue: "test",
|
|
328
|
-
workflows: {
|
|
329
|
-
test: {
|
|
330
|
-
input: z.object({}),
|
|
331
|
-
output: z.object({}),
|
|
332
|
-
signals: {
|
|
333
|
-
"cancel-order": {
|
|
334
|
-
input: z.object({}),
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
}),
|
|
340
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
it("should throw when query name is invalid", () => {
|
|
344
|
-
expect(() =>
|
|
345
|
-
defineContract({
|
|
346
|
-
taskQueue: "test",
|
|
347
|
-
workflows: {
|
|
348
|
-
test: {
|
|
349
|
-
input: z.object({}),
|
|
350
|
-
output: z.object({}),
|
|
351
|
-
queries: {
|
|
352
|
-
"get-status": {
|
|
353
|
-
input: z.object({}),
|
|
354
|
-
output: z.object({}),
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
}),
|
|
360
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it("should throw when update name is invalid", () => {
|
|
364
|
-
expect(() =>
|
|
365
|
-
defineContract({
|
|
366
|
-
taskQueue: "test",
|
|
367
|
-
workflows: {
|
|
368
|
-
test: {
|
|
369
|
-
input: z.object({}),
|
|
370
|
-
output: z.object({}),
|
|
371
|
-
updates: {
|
|
372
|
-
"update-amount": {
|
|
373
|
-
input: z.object({}),
|
|
374
|
-
output: z.object({}),
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
},
|
|
378
|
-
},
|
|
379
|
-
}),
|
|
380
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it("should allow valid camelCase names", () => {
|
|
384
|
-
expect(() =>
|
|
385
|
-
defineContract({
|
|
386
|
-
taskQueue: "test-queue",
|
|
387
|
-
workflows: {
|
|
388
|
-
processOrder: {
|
|
389
|
-
input: z.object({}),
|
|
390
|
-
output: z.object({}),
|
|
391
|
-
activities: {
|
|
392
|
-
sendEmail: {
|
|
393
|
-
input: z.object({}),
|
|
394
|
-
output: z.object({}),
|
|
395
|
-
},
|
|
396
|
-
},
|
|
397
|
-
signals: {
|
|
398
|
-
cancelOrder: {
|
|
399
|
-
input: z.object({}),
|
|
400
|
-
},
|
|
401
|
-
},
|
|
402
|
-
queries: {
|
|
403
|
-
getStatus: {
|
|
404
|
-
input: z.object({}),
|
|
405
|
-
output: z.object({}),
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
updates: {
|
|
409
|
-
updateAmount: {
|
|
410
|
-
input: z.object({}),
|
|
411
|
-
output: z.object({}),
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
}),
|
|
417
|
-
).not.toThrow();
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it("should allow names with underscores and dollar signs", () => {
|
|
421
|
-
expect(() =>
|
|
422
|
-
defineContract({
|
|
423
|
-
taskQueue: "test",
|
|
424
|
-
workflows: {
|
|
425
|
-
process_order: {
|
|
426
|
-
input: z.object({}),
|
|
427
|
-
output: z.object({}),
|
|
428
|
-
},
|
|
429
|
-
$process: {
|
|
430
|
-
input: z.object({}),
|
|
431
|
-
output: z.object({}),
|
|
432
|
-
},
|
|
433
|
-
},
|
|
434
|
-
activities: {
|
|
435
|
-
send_email: {
|
|
436
|
-
input: z.object({}),
|
|
437
|
-
output: z.object({}),
|
|
438
|
-
},
|
|
439
|
-
$send: {
|
|
440
|
-
input: z.object({}),
|
|
441
|
-
output: z.object({}),
|
|
442
|
-
},
|
|
443
|
-
},
|
|
444
|
-
}),
|
|
445
|
-
).not.toThrow();
|
|
446
|
-
});
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
describe("Edge Cases", () => {
|
|
450
|
-
it("should handle empty object schemas", () => {
|
|
451
|
-
const contract = defineContract({
|
|
452
|
-
taskQueue: "test",
|
|
453
|
-
workflows: {
|
|
454
|
-
empty: {
|
|
455
|
-
input: z.object({}),
|
|
456
|
-
output: z.object({}),
|
|
457
|
-
},
|
|
458
|
-
},
|
|
459
|
-
});
|
|
460
|
-
expect(contract).toBeDefined();
|
|
461
|
-
expect(contract.workflows.empty.input).toBeDefined();
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it("should handle void input", () => {
|
|
465
|
-
const contract = defineContract({
|
|
466
|
-
taskQueue: "test",
|
|
467
|
-
workflows: {
|
|
468
|
-
noInput: {
|
|
469
|
-
input: z.void(),
|
|
470
|
-
output: z.object({ result: z.string() }),
|
|
471
|
-
},
|
|
472
|
-
},
|
|
473
|
-
});
|
|
474
|
-
expect(contract).toBeDefined();
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it("should handle workflows without activities, signals, queries, or updates", () => {
|
|
478
|
-
const contract = defineContract({
|
|
479
|
-
taskQueue: "test",
|
|
480
|
-
workflows: {
|
|
481
|
-
simple: {
|
|
482
|
-
input: z.string(),
|
|
483
|
-
output: z.string(),
|
|
484
|
-
},
|
|
485
|
-
},
|
|
486
|
-
});
|
|
487
|
-
const workflow = contract.workflows.simple;
|
|
488
|
-
expect("activities" in workflow).toBe(false);
|
|
489
|
-
expect("signals" in workflow).toBe(false);
|
|
490
|
-
expect("queries" in workflow).toBe(false);
|
|
491
|
-
expect("updates" in workflow).toBe(false);
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
it("should handle contract without global activities", () => {
|
|
495
|
-
const contract = defineContract({
|
|
496
|
-
taskQueue: "test",
|
|
497
|
-
workflows: {
|
|
498
|
-
test: {
|
|
499
|
-
input: z.object({}),
|
|
500
|
-
output: z.object({}),
|
|
501
|
-
},
|
|
502
|
-
},
|
|
503
|
-
});
|
|
504
|
-
expect("activities" in contract).toBe(false);
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it("should throw when workflow is missing input", () => {
|
|
508
|
-
expect(() =>
|
|
509
|
-
defineContract({
|
|
510
|
-
taskQueue: "test",
|
|
511
|
-
workflows: {
|
|
512
|
-
// @ts-expect-error - Testing validation with missing input
|
|
513
|
-
test: {
|
|
514
|
-
output: z.object({}),
|
|
515
|
-
},
|
|
516
|
-
},
|
|
517
|
-
}),
|
|
518
|
-
).toThrow("Contract error");
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
it("should throw when workflow is missing output", () => {
|
|
522
|
-
expect(() =>
|
|
523
|
-
defineContract({
|
|
524
|
-
taskQueue: "test",
|
|
525
|
-
workflows: {
|
|
526
|
-
// @ts-expect-error - Testing validation with missing output
|
|
527
|
-
test: {
|
|
528
|
-
input: z.object({}),
|
|
529
|
-
},
|
|
530
|
-
},
|
|
531
|
-
}),
|
|
532
|
-
).toThrow("Contract error");
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
it("should throw when activity is missing input", () => {
|
|
536
|
-
expect(() =>
|
|
537
|
-
defineContract({
|
|
538
|
-
taskQueue: "test",
|
|
539
|
-
workflows: {
|
|
540
|
-
test: {
|
|
541
|
-
input: z.object({}),
|
|
542
|
-
output: z.object({}),
|
|
543
|
-
},
|
|
544
|
-
},
|
|
545
|
-
activities: {
|
|
546
|
-
// @ts-expect-error - Testing validation with missing input
|
|
547
|
-
test: {
|
|
548
|
-
output: z.object({}),
|
|
549
|
-
},
|
|
550
|
-
},
|
|
551
|
-
}),
|
|
552
|
-
).toThrow("Contract error");
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
it("should throw when activity is missing output", () => {
|
|
556
|
-
expect(() =>
|
|
557
|
-
defineContract({
|
|
558
|
-
taskQueue: "test",
|
|
559
|
-
workflows: {
|
|
560
|
-
test: {
|
|
561
|
-
input: z.object({}),
|
|
562
|
-
output: z.object({}),
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
activities: {
|
|
566
|
-
// @ts-expect-error - Testing validation with missing output
|
|
567
|
-
test: {
|
|
568
|
-
input: z.object({}),
|
|
569
|
-
},
|
|
570
|
-
},
|
|
571
|
-
}),
|
|
572
|
-
).toThrow("Contract error");
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
it("should throw when workflow activity name is invalid", () => {
|
|
576
|
-
expect(() =>
|
|
577
|
-
defineContract({
|
|
578
|
-
taskQueue: "test",
|
|
579
|
-
workflows: {
|
|
580
|
-
test: {
|
|
581
|
-
input: z.object({}),
|
|
582
|
-
output: z.object({}),
|
|
583
|
-
activities: {
|
|
584
|
-
"invalid-name": {
|
|
585
|
-
input: z.object({}),
|
|
586
|
-
output: z.object({}),
|
|
587
|
-
},
|
|
588
|
-
},
|
|
589
|
-
},
|
|
590
|
-
},
|
|
591
|
-
}),
|
|
592
|
-
).toThrow("must be a valid JavaScript identifier");
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
it("should throw when input is not a Zod schema", () => {
|
|
596
|
-
expect(() =>
|
|
597
|
-
defineContract({
|
|
598
|
-
taskQueue: "test",
|
|
599
|
-
workflows: {
|
|
600
|
-
test: {
|
|
601
|
-
// @ts-expect-error - Testing validation with invalid input type
|
|
602
|
-
input: "not a schema",
|
|
603
|
-
output: z.object({}),
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
}),
|
|
607
|
-
).toThrow("Contract error");
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
it("should throw when output is not a Zod schema", () => {
|
|
611
|
-
expect(() =>
|
|
612
|
-
defineContract({
|
|
613
|
-
taskQueue: "test",
|
|
614
|
-
workflows: {
|
|
615
|
-
test: {
|
|
616
|
-
input: z.object({}),
|
|
617
|
-
// @ts-expect-error - Testing validation with invalid output type
|
|
618
|
-
output: { invalid: true },
|
|
619
|
-
},
|
|
620
|
-
},
|
|
621
|
-
}),
|
|
622
|
-
).toThrow("Contract error");
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
describe("Standard Schema compatibility", () => {
|
|
627
|
-
it("should work with Valibot schemas", async () => {
|
|
628
|
-
const v = await import("valibot");
|
|
629
|
-
|
|
630
|
-
const contract = defineContract({
|
|
631
|
-
taskQueue: "test-queue",
|
|
632
|
-
workflows: {
|
|
633
|
-
processOrder: {
|
|
634
|
-
input: v.object({ orderId: v.string() }),
|
|
635
|
-
output: v.object({ status: v.string() }),
|
|
636
|
-
},
|
|
637
|
-
},
|
|
638
|
-
activities: {
|
|
639
|
-
sendEmail: {
|
|
640
|
-
input: v.object({ to: v.string(), subject: v.string() }),
|
|
641
|
-
output: v.object({ sent: v.boolean() }),
|
|
642
|
-
},
|
|
643
|
-
},
|
|
644
|
-
});
|
|
645
|
-
|
|
646
|
-
expect(contract.taskQueue).toBe("test-queue");
|
|
647
|
-
expect(contract.workflows.processOrder).toBeDefined();
|
|
648
|
-
expect(contract.activities?.sendEmail).toBeDefined();
|
|
649
|
-
|
|
650
|
-
// Verify Standard Schema properties exist
|
|
651
|
-
expect(contract.workflows.processOrder.input["~standard"]).toBeDefined();
|
|
652
|
-
expect(contract.workflows.processOrder.input["~standard"].version).toBe(1);
|
|
653
|
-
expect(contract.workflows.processOrder.input["~standard"].vendor).toBe("valibot");
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
it("should work with ArkType schemas", async () => {
|
|
657
|
-
const { type } = await import("arktype");
|
|
658
|
-
|
|
659
|
-
const contract = defineContract({
|
|
660
|
-
taskQueue: "test-queue",
|
|
661
|
-
workflows: {
|
|
662
|
-
processOrder: {
|
|
663
|
-
input: type({ orderId: "string" }),
|
|
664
|
-
output: type({ status: "string" }),
|
|
665
|
-
},
|
|
666
|
-
},
|
|
667
|
-
activities: {
|
|
668
|
-
validatePayment: {
|
|
669
|
-
input: type({ amount: "number" }),
|
|
670
|
-
output: type({ valid: "boolean" }),
|
|
671
|
-
},
|
|
672
|
-
},
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
expect(contract.taskQueue).toBe("test-queue");
|
|
676
|
-
expect(contract.workflows.processOrder).toBeDefined();
|
|
677
|
-
expect(contract.activities?.validatePayment).toBeDefined();
|
|
678
|
-
|
|
679
|
-
// Verify Standard Schema properties exist
|
|
680
|
-
expect(contract.workflows.processOrder.input["~standard"]).toBeDefined();
|
|
681
|
-
expect(contract.workflows.processOrder.input["~standard"].version).toBe(1);
|
|
682
|
-
expect(contract.workflows.processOrder.input["~standard"].vendor).toBe("arktype");
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
it("should work with mixed validation libraries", async () => {
|
|
686
|
-
const v = await import("valibot");
|
|
687
|
-
const { type } = await import("arktype");
|
|
688
|
-
|
|
689
|
-
const contract = defineContract({
|
|
690
|
-
taskQueue: "test-queue",
|
|
691
|
-
workflows: {
|
|
692
|
-
processZod: {
|
|
693
|
-
input: z.object({ id: z.string() }),
|
|
694
|
-
output: z.object({ result: z.string() }),
|
|
695
|
-
},
|
|
696
|
-
processValibot: {
|
|
697
|
-
input: v.object({ id: v.string() }),
|
|
698
|
-
output: v.object({ result: v.string() }),
|
|
699
|
-
},
|
|
700
|
-
processArkType: {
|
|
701
|
-
input: type({ id: "string" }),
|
|
702
|
-
output: type({ result: "string" }),
|
|
703
|
-
},
|
|
704
|
-
},
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
expect(contract.workflows.processZod).toBeDefined();
|
|
708
|
-
expect(contract.workflows.processValibot).toBeDefined();
|
|
709
|
-
expect(contract.workflows.processArkType).toBeDefined();
|
|
710
|
-
|
|
711
|
-
// Verify each has correct vendor
|
|
712
|
-
expect(contract.workflows.processZod.input["~standard"].vendor).toBe("zod");
|
|
713
|
-
expect(contract.workflows.processValibot.input["~standard"].vendor).toBe("valibot");
|
|
714
|
-
expect(contract.workflows.processArkType.input["~standard"].vendor).toBe("arktype");
|
|
715
|
-
});
|
|
716
|
-
});
|
|
717
|
-
});
|