@temporal-contract/contract 0.0.1
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/.turbo/turbo-build.log +17 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/index.cjs +190 -0
- package/dist/index.d.cts +351 -0
- package/dist/index.d.mts +351 -0
- package/dist/index.mjs +185 -0
- package/package.json +55 -0
- package/src/builder.spec.ts +625 -0
- package/src/builder.ts +262 -0
- package/src/helpers.spec.ts +122 -0
- package/src/index.ts +55 -0
- package/src/types.spec.ts +637 -0
- package/src/types.ts +420 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
> @temporal-contract/contract@0.0.1 build /home/runner/work/temporal-contract/temporal-contract/packages/contract
|
|
3
|
+
> tsdown src/index.ts --format cjs,esm --dts --clean
|
|
4
|
+
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.17.2[22m powered by rolldown [2mv1.0.0-beta.53[22m
|
|
6
|
+
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
7
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
8
|
+
[34mℹ[39m Build start
|
|
9
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mindex.cjs[22m [2m5.96 kB[22m [2m│ gzip: 1.51 kB[22m
|
|
10
|
+
[34mℹ[39m [33m[CJS][39m 1 files, total: 5.96 kB
|
|
11
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mindex.d.cts[22m[39m [2m15.50 kB[22m [2m│ gzip: 2.50 kB[22m
|
|
12
|
+
[34mℹ[39m [33m[CJS][39m 1 files, total: 15.50 kB
|
|
13
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mindex.mjs[22m [2m 5.69 kB[22m [2m│ gzip: 1.49 kB[22m
|
|
14
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m15.50 kB[22m [2m│ gzip: 2.50 kB[22m
|
|
15
|
+
[34mℹ[39m [34m[ESM][39m 2 files, total: 21.19 kB
|
|
16
|
+
[32m✔[39m Build complete in [32m2205ms[39m
|
|
17
|
+
[32m✔[39m Build complete in [32m2206ms[39m
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Benoit TRAVERS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# @temporal-contract/contract
|
|
2
|
+
|
|
3
|
+
> Contract builder and type definitions for Temporal workflows and activities
|
|
4
|
+
|
|
5
|
+
**Core package** for defining type-safe contracts with Zod schemas.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @temporal-contract/contract zod
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What's Included
|
|
14
|
+
|
|
15
|
+
- **Contract builder** — `defineContract()` for creating type-safe contracts
|
|
16
|
+
- **Type utilities** — Helper types for cleaner implementations
|
|
17
|
+
- **Helper functions** — Optional helpers for standalone definitions
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
import { defineContract } from '@temporal-contract/contract';
|
|
24
|
+
|
|
25
|
+
export const myContract = defineContract({
|
|
26
|
+
taskQueue: 'my-service',
|
|
27
|
+
workflows: {
|
|
28
|
+
processOrder: {
|
|
29
|
+
input: z.object({
|
|
30
|
+
orderId: z.string(),
|
|
31
|
+
items: z.array(z.object({
|
|
32
|
+
productId: z.string(),
|
|
33
|
+
quantity: z.number(),
|
|
34
|
+
})),
|
|
35
|
+
}),
|
|
36
|
+
output: z.object({
|
|
37
|
+
status: z.enum(['success', 'failed']),
|
|
38
|
+
totalAmount: z.number(),
|
|
39
|
+
}),
|
|
40
|
+
activities: {
|
|
41
|
+
processPayment: {
|
|
42
|
+
input: z.object({ amount: z.number() }),
|
|
43
|
+
output: z.object({ transactionId: z.string() }),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### Define a Contract
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { defineContract } from '@temporal-contract/contract';
|
|
57
|
+
import { z } from 'zod';
|
|
58
|
+
|
|
59
|
+
export const myContract = defineContract({
|
|
60
|
+
taskQueue: 'my-service',
|
|
61
|
+
|
|
62
|
+
// Global activities (available in all workflows)
|
|
63
|
+
activities: {
|
|
64
|
+
sendEmail: {
|
|
65
|
+
input: z.object({ to: z.string(), subject: z.string() }),
|
|
66
|
+
output: z.object({ sent: z.boolean() }),
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Workflows
|
|
71
|
+
workflows: {
|
|
72
|
+
processOrder: {
|
|
73
|
+
input: z.object({ orderId: z.string() }),
|
|
74
|
+
output: z.object({ status: z.string() }),
|
|
75
|
+
|
|
76
|
+
// Workflow-specific activities
|
|
77
|
+
activities: {
|
|
78
|
+
processPayment: {
|
|
79
|
+
input: z.object({ amount: z.number() }),
|
|
80
|
+
output: z.object({ transactionId: z.string() }),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Helper Functions (Optional)
|
|
89
|
+
|
|
90
|
+
For standalone definitions outside a contract:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { defineActivity, defineSignal, defineQuery, defineUpdate } from '@temporal-contract/contract';
|
|
94
|
+
|
|
95
|
+
// Standalone activity
|
|
96
|
+
const sendEmail = defineActivity({
|
|
97
|
+
input: z.object({ to: z.string() }),
|
|
98
|
+
output: z.object({ sent: z.boolean() }),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Signal, query, update
|
|
102
|
+
const cancelOrder = defineSignal({ input: z.object({ reason: z.string() }) });
|
|
103
|
+
const getStatus = defineQuery({ input: z.void(), output: z.object({ status: z.string() }) });
|
|
104
|
+
const updateAmount = defineUpdate({ input: z.number(), output: z.boolean() });
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Type Utilities\n\nHelper types for implementing activities with full type inference:\n\n### Activity Handlers\n\n`typescript\nimport type { ActivityHandler, WorkflowActivityHandler } from '@temporal-contract/contract';\n\n// Global activity\nconst sendEmail: ActivityHandler<typeof myContract, 'sendEmail'> = \n async ({ to, subject }) => {\n await emailService.send({ to, subject });\n return { sent: true };\n };\n\n// Workflow-specific activity\nconst processPayment: WorkflowActivityHandler<typeof myContract, 'processOrder', 'processPayment'> = \n async ({ amount }) => {\n const txId = await paymentGateway.charge(amount);\n return { transactionId: txId };\n };\n`\n\n### Contract Introspection\n\n`typescript\nimport type { InferWorkflowNames, InferActivityNames } from '@temporal-contract/contract';\n\ntype Workflows = InferWorkflowNames<typeof myContract>; // \"processOrder\" | ...\ntype Activities = InferActivityNames<typeof myContract>; // \"sendEmail\" | ...\n`\n\nSee [Activity Handlers documentation](../../docs/ACTIVITY_HANDLERS.md) for details.\n\n---\n\n## Learn More\n\n- [Main README](../../README.md) \u2014 Quick start guide\n- [Worker Implementation](../../docs/CONTRACT_HANDLER.md) \u2014 Implementing workers\n- [Activity Handlers](../../docs/ACTIVITY_HANDLERS.md) \u2014 Type utility details\n\n## License\n\nMIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
let zod = require("zod");
|
|
2
|
+
|
|
3
|
+
//#region src/builder.ts
|
|
4
|
+
/**
|
|
5
|
+
* Schema for validating JavaScript identifiers (workflow names, activity names, etc.)
|
|
6
|
+
* Allows: letters, digits, underscore, dollar sign
|
|
7
|
+
* Must start with: letter, underscore, or dollar sign
|
|
8
|
+
*/
|
|
9
|
+
const identifierSchema = zod.z.string().min(1).regex(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/, "must be a valid JavaScript identifier");
|
|
10
|
+
/**
|
|
11
|
+
* Extract clean error message from Zod validation error
|
|
12
|
+
*/
|
|
13
|
+
const getCleanErrorMessage = (error) => {
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(error.message);
|
|
16
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
17
|
+
const firstError = parsed[0];
|
|
18
|
+
if (firstError?.code === "invalid_key" && firstError?.issues && firstError.issues.length > 0) {
|
|
19
|
+
const nestedError = firstError.issues[0];
|
|
20
|
+
if (nestedError?.message) return nestedError.message;
|
|
21
|
+
}
|
|
22
|
+
if (firstError?.message) return firstError.message;
|
|
23
|
+
}
|
|
24
|
+
} catch {}
|
|
25
|
+
return error.message;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Schema for validating activity definitions
|
|
29
|
+
* Checks that input and output are Zod schemas
|
|
30
|
+
*/
|
|
31
|
+
const activityDefinitionSchema = zod.z.object({
|
|
32
|
+
input: zod.z.instanceof(zod.z.ZodType, { message: "input must be a Zod schema" }),
|
|
33
|
+
output: zod.z.instanceof(zod.z.ZodType, { message: "output must be a Zod schema" })
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Schema for validating signal definitions
|
|
37
|
+
*/
|
|
38
|
+
const signalDefinitionSchema = zod.z.object({ input: zod.z.instanceof(zod.z.ZodType, { message: "input must be a Zod schema" }) });
|
|
39
|
+
/**
|
|
40
|
+
* Schema for validating query definitions
|
|
41
|
+
*/
|
|
42
|
+
const queryDefinitionSchema = zod.z.object({
|
|
43
|
+
input: zod.z.instanceof(zod.z.ZodType, { message: "input must be a Zod schema" }),
|
|
44
|
+
output: zod.z.instanceof(zod.z.ZodType, { message: "output must be a Zod schema" })
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Schema for validating update definitions
|
|
48
|
+
*/
|
|
49
|
+
const updateDefinitionSchema = zod.z.object({
|
|
50
|
+
input: zod.z.instanceof(zod.z.ZodType, { message: "input must be a Zod schema" }),
|
|
51
|
+
output: zod.z.instanceof(zod.z.ZodType, { message: "output must be a Zod schema" })
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Schema for validating workflow definitions
|
|
55
|
+
*/
|
|
56
|
+
const workflowDefinitionSchema = zod.z.object({
|
|
57
|
+
input: zod.z.instanceof(zod.z.ZodType, { message: "input must be a Zod schema" }),
|
|
58
|
+
output: zod.z.instanceof(zod.z.ZodType, { message: "output must be a Zod schema" }),
|
|
59
|
+
activities: zod.z.record(identifierSchema, activityDefinitionSchema).optional(),
|
|
60
|
+
signals: zod.z.record(identifierSchema, signalDefinitionSchema).optional(),
|
|
61
|
+
queries: zod.z.record(identifierSchema, queryDefinitionSchema).optional(),
|
|
62
|
+
updates: zod.z.record(identifierSchema, updateDefinitionSchema).optional()
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Schema for validating a contract definition structure
|
|
66
|
+
*/
|
|
67
|
+
const contractValidationSchema = zod.z.object({
|
|
68
|
+
taskQueue: zod.z.string().trim().min(1, "taskQueue cannot be empty"),
|
|
69
|
+
workflows: zod.z.record(identifierSchema, workflowDefinitionSchema).refine((workflows) => Object.keys(workflows).length > 0, { message: "at least one workflow is required" }),
|
|
70
|
+
activities: zod.z.record(identifierSchema, activityDefinitionSchema).optional()
|
|
71
|
+
}).superRefine((contract, ctx) => {
|
|
72
|
+
if (!contract.activities) return;
|
|
73
|
+
for (const [workflowName, workflow] of Object.entries(contract.workflows)) if (workflow.activities) {
|
|
74
|
+
for (const activityName of Object.keys(workflow.activities)) if (activityName in contract.activities) {
|
|
75
|
+
ctx.addIssue({
|
|
76
|
+
code: zod.z.ZodIssueCode.custom,
|
|
77
|
+
message: `workflow "${workflowName}" has activity "${activityName}" that conflicts with a global activity. Consider renaming the workflow-specific activity or removing the global activity "${activityName}".`
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Builder for creating activity definitions
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* const myActivity = defineActivity({
|
|
89
|
+
* input: z.tuple([z.object({ name: z.string() })]),
|
|
90
|
+
* output: z.object({ greeting: z.string() }),
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
const defineActivity = (definition) => {
|
|
95
|
+
return definition;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Builder for creating signal definitions
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const mySignal = defineSignal({
|
|
103
|
+
* input: z.object({ message: z.string() }),
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
const defineSignal = (definition) => {
|
|
108
|
+
return definition;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Builder for creating query definitions
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* const myQuery = defineQuery({
|
|
116
|
+
* input: z.object({ id: z.string() }),
|
|
117
|
+
* output: z.object({ status: z.string() }),
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
const defineQuery = (definition) => {
|
|
122
|
+
return definition;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Builder for creating update definitions
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const myUpdate = defineUpdate({
|
|
130
|
+
* input: z.object({ value: z.number() }),
|
|
131
|
+
* output: z.object({ newValue: z.number() }),
|
|
132
|
+
* });
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
const defineUpdate = (definition) => {
|
|
136
|
+
return definition;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Builder for creating workflow definitions
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* const myWorkflow = defineWorkflow({
|
|
144
|
+
* input: z.tuple([z.object({ orderId: z.string() })]),
|
|
145
|
+
* output: z.object({ status: z.string() }),
|
|
146
|
+
* activities: {
|
|
147
|
+
* processPayment: defineActivity({
|
|
148
|
+
* input: z.tuple([z.object({ amount: z.number() })]),
|
|
149
|
+
* output: z.object({ success: z.boolean() }),
|
|
150
|
+
* }),
|
|
151
|
+
* },
|
|
152
|
+
* });
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
const defineWorkflow = (definition) => {
|
|
156
|
+
return definition;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Builder for creating a complete contract
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const myContract = defineContract({
|
|
164
|
+
* taskQueue: 'my-service',
|
|
165
|
+
* workflows: {
|
|
166
|
+
* processOrder: defineWorkflow({ ... }),
|
|
167
|
+
* sendNotification: defineWorkflow({ ... }),
|
|
168
|
+
* },
|
|
169
|
+
* activities: {
|
|
170
|
+
* sendEmail: defineActivity({ ... }),
|
|
171
|
+
* },
|
|
172
|
+
* });
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
const defineContract = (definition) => {
|
|
176
|
+
const validationResult = contractValidationSchema.safeParse(definition);
|
|
177
|
+
if (!validationResult.success) {
|
|
178
|
+
const cleanMessage = getCleanErrorMessage(validationResult.error);
|
|
179
|
+
throw new Error(`Contract error: ${cleanMessage}`);
|
|
180
|
+
}
|
|
181
|
+
return definition;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
exports.defineActivity = defineActivity;
|
|
186
|
+
exports.defineContract = defineContract;
|
|
187
|
+
exports.defineQuery = defineQuery;
|
|
188
|
+
exports.defineSignal = defineSignal;
|
|
189
|
+
exports.defineUpdate = defineUpdate;
|
|
190
|
+
exports.defineWorkflow = defineWorkflow;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Base types for validation schemas
|
|
7
|
+
* Constrained to avoid implicit any types
|
|
8
|
+
*/
|
|
9
|
+
type AnyZodSchema = z.ZodType<unknown, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Definition of an activity
|
|
12
|
+
*/
|
|
13
|
+
interface ActivityDefinition<TInput extends AnyZodSchema = AnyZodSchema, TOutput extends AnyZodSchema = AnyZodSchema> {
|
|
14
|
+
readonly input: TInput;
|
|
15
|
+
readonly output: TOutput;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Definition of a signal
|
|
19
|
+
*/
|
|
20
|
+
interface SignalDefinition<TInput extends AnyZodSchema = AnyZodSchema> {
|
|
21
|
+
readonly input: TInput;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Definition of a query
|
|
25
|
+
*/
|
|
26
|
+
interface QueryDefinition<TInput extends AnyZodSchema = AnyZodSchema, TOutput extends AnyZodSchema = AnyZodSchema> {
|
|
27
|
+
readonly input: TInput;
|
|
28
|
+
readonly output: TOutput;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Definition of an update
|
|
32
|
+
*/
|
|
33
|
+
interface UpdateDefinition<TInput extends AnyZodSchema = AnyZodSchema, TOutput extends AnyZodSchema = AnyZodSchema> {
|
|
34
|
+
readonly input: TInput;
|
|
35
|
+
readonly output: TOutput;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Definition of a workflow
|
|
39
|
+
*/
|
|
40
|
+
interface WorkflowDefinition<TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>, TSignals extends Record<string, SignalDefinition> = Record<string, SignalDefinition>, TQueries extends Record<string, QueryDefinition> = Record<string, QueryDefinition>, TUpdates extends Record<string, UpdateDefinition> = Record<string, UpdateDefinition>> {
|
|
41
|
+
readonly input: AnyZodSchema;
|
|
42
|
+
readonly output: AnyZodSchema;
|
|
43
|
+
readonly activities?: TActivities;
|
|
44
|
+
readonly signals?: TSignals;
|
|
45
|
+
readonly queries?: TQueries;
|
|
46
|
+
readonly updates?: TUpdates;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Contract definition containing workflows and optional global activities
|
|
50
|
+
*/
|
|
51
|
+
interface ContractDefinition<TWorkflows extends Record<string, WorkflowDefinition> = Record<string, WorkflowDefinition>, TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>> {
|
|
52
|
+
readonly taskQueue: string;
|
|
53
|
+
readonly workflows: TWorkflows;
|
|
54
|
+
readonly activities?: TActivities;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Infer input type from a definition (worker perspective)
|
|
58
|
+
* Worker receives z.output (after input schema parsing/transformation)
|
|
59
|
+
*/
|
|
60
|
+
type WorkerInferInput<T extends {
|
|
61
|
+
input: AnyZodSchema;
|
|
62
|
+
}> = z.output<T["input"]>;
|
|
63
|
+
/**
|
|
64
|
+
* Infer output type from a definition (worker perspective)
|
|
65
|
+
* Worker returns z.input (before output schema parsing/transformation)
|
|
66
|
+
*/
|
|
67
|
+
type WorkerInferOutput<T extends {
|
|
68
|
+
output: AnyZodSchema;
|
|
69
|
+
}> = z.input<T["output"]>;
|
|
70
|
+
/**
|
|
71
|
+
* Infer input type from a definition (client perspective)
|
|
72
|
+
* Client sends z.input (before input schema parsing/transformation)
|
|
73
|
+
*/
|
|
74
|
+
type ClientInferInput<T extends {
|
|
75
|
+
input: AnyZodSchema;
|
|
76
|
+
}> = z.input<T["input"]>;
|
|
77
|
+
/**
|
|
78
|
+
* Infer output type from a definition (client perspective)
|
|
79
|
+
* Client receives z.output (after output schema parsing/transformation)
|
|
80
|
+
*/
|
|
81
|
+
type ClientInferOutput<T extends {
|
|
82
|
+
output: AnyZodSchema;
|
|
83
|
+
}> = z.output<T["output"]>;
|
|
84
|
+
/**
|
|
85
|
+
* WORKER PERSPECTIVE
|
|
86
|
+
* Worker receives z.output of input (parsed data) and returns z.input of output (raw data)
|
|
87
|
+
*/
|
|
88
|
+
/**
|
|
89
|
+
* Infer workflow function signature from worker perspective
|
|
90
|
+
* Worker receives z.input and returns z.output
|
|
91
|
+
*/
|
|
92
|
+
type WorkerInferWorkflow<TWorkflow extends WorkflowDefinition> = (args: WorkerInferInput<TWorkflow>) => Promise<WorkerInferOutput<TWorkflow>>;
|
|
93
|
+
/**
|
|
94
|
+
* Infer activity function signature from worker perspective
|
|
95
|
+
* Worker receives z.input and returns z.output
|
|
96
|
+
*/
|
|
97
|
+
type WorkerInferActivity<TActivity extends ActivityDefinition> = (args: WorkerInferInput<TActivity>) => Promise<WorkerInferOutput<TActivity>>;
|
|
98
|
+
/**
|
|
99
|
+
* Infer signal handler signature from worker perspective
|
|
100
|
+
* Worker receives z.input
|
|
101
|
+
*/
|
|
102
|
+
type WorkerInferSignal<TSignal extends SignalDefinition> = (args: WorkerInferInput<TSignal>) => Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Infer query handler signature from worker perspective
|
|
105
|
+
* Worker receives z.input and returns z.output
|
|
106
|
+
*/
|
|
107
|
+
type WorkerInferQuery<TQuery extends QueryDefinition> = (args: WorkerInferInput<TQuery>) => Promise<WorkerInferOutput<TQuery>>;
|
|
108
|
+
/**
|
|
109
|
+
* Infer update handler signature from worker perspective
|
|
110
|
+
* Worker receives z.input and returns z.output
|
|
111
|
+
*/
|
|
112
|
+
type WorkerInferUpdate<TUpdate extends UpdateDefinition> = (args: WorkerInferInput<TUpdate>) => Promise<WorkerInferOutput<TUpdate>>;
|
|
113
|
+
/**
|
|
114
|
+
* CLIENT PERSPECTIVE
|
|
115
|
+
* Client sends z.output and receives z.input
|
|
116
|
+
*/
|
|
117
|
+
/**
|
|
118
|
+
* Infer workflow function signature from client perspective
|
|
119
|
+
* Client sends z.output and receives z.input
|
|
120
|
+
*/
|
|
121
|
+
type ClientInferWorkflow<TWorkflow extends WorkflowDefinition> = (args: ClientInferInput<TWorkflow>) => Promise<ClientInferOutput<TWorkflow>>;
|
|
122
|
+
/**
|
|
123
|
+
* Infer activity function signature from client perspective
|
|
124
|
+
* Client sends z.output and receives z.input
|
|
125
|
+
*/
|
|
126
|
+
type ClientInferActivity<TActivity extends ActivityDefinition> = (args: ClientInferInput<TActivity>) => Promise<ClientInferOutput<TActivity>>;
|
|
127
|
+
/**
|
|
128
|
+
* Infer signal handler signature from client perspective
|
|
129
|
+
* Client sends z.output
|
|
130
|
+
*/
|
|
131
|
+
type ClientInferSignal<TSignal extends SignalDefinition> = (args: ClientInferInput<TSignal>) => Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Infer query handler signature from client perspective
|
|
134
|
+
* Client sends z.output and receives z.input
|
|
135
|
+
*/
|
|
136
|
+
type ClientInferQuery<TQuery extends QueryDefinition> = (args: ClientInferInput<TQuery>) => Promise<ClientInferOutput<TQuery>>;
|
|
137
|
+
/**
|
|
138
|
+
* Infer update handler signature from client perspective
|
|
139
|
+
* Client sends z.output and receives z.input
|
|
140
|
+
*/
|
|
141
|
+
type ClientInferUpdate<TUpdate extends UpdateDefinition> = (args: ClientInferInput<TUpdate>) => Promise<ClientInferOutput<TUpdate>>;
|
|
142
|
+
/**
|
|
143
|
+
* WORKER PERSPECTIVE - Contract-level types
|
|
144
|
+
*/
|
|
145
|
+
/**
|
|
146
|
+
* Infer all workflows from a contract (worker perspective)
|
|
147
|
+
*/
|
|
148
|
+
type WorkerInferWorkflows<TContract extends ContractDefinition> = { [K in keyof TContract["workflows"]]: WorkerInferWorkflow<TContract["workflows"][K]> };
|
|
149
|
+
/**
|
|
150
|
+
* Infer all activities from a contract (worker perspective)
|
|
151
|
+
*/
|
|
152
|
+
type WorkerInferActivities<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof TContract["activities"]]: WorkerInferActivity<TContract["activities"][K]> } : {};
|
|
153
|
+
/**
|
|
154
|
+
* Infer activities from a workflow definition (worker perspective)
|
|
155
|
+
*/
|
|
156
|
+
type WorkerInferWorkflowActivities<T extends WorkflowDefinition> = T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: WorkerInferActivity<T["activities"][K]> } : {};
|
|
157
|
+
/**
|
|
158
|
+
* Infer signals from a workflow definition (worker perspective)
|
|
159
|
+
*/
|
|
160
|
+
type WorkerInferWorkflowSignals<T extends WorkflowDefinition> = T["signals"] extends Record<string, SignalDefinition> ? { [K in keyof T["signals"]]: WorkerInferSignal<T["signals"][K]> } : {};
|
|
161
|
+
/**
|
|
162
|
+
* Infer queries from a workflow definition (worker perspective)
|
|
163
|
+
*/
|
|
164
|
+
type WorkerInferWorkflowQueries<T extends WorkflowDefinition> = T["queries"] extends Record<string, QueryDefinition> ? { [K in keyof T["queries"]]: WorkerInferQuery<T["queries"][K]> } : {};
|
|
165
|
+
/**
|
|
166
|
+
* Infer updates from a workflow definition (worker perspective)
|
|
167
|
+
*/
|
|
168
|
+
type WorkerInferWorkflowUpdates<T extends WorkflowDefinition> = T["updates"] extends Record<string, UpdateDefinition> ? { [K in keyof T["updates"]]: WorkerInferUpdate<T["updates"][K]> } : {};
|
|
169
|
+
/**
|
|
170
|
+
* Infer all activities available in a workflow context (worker perspective)
|
|
171
|
+
* Combines workflow-specific activities with global activities
|
|
172
|
+
*/
|
|
173
|
+
type WorkerInferWorkflowContextActivities<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = WorkerInferWorkflowActivities<TContract["workflows"][TWorkflowName]> & WorkerInferActivities<TContract>;
|
|
174
|
+
/**
|
|
175
|
+
* CLIENT PERSPECTIVE - Contract-level types
|
|
176
|
+
*/
|
|
177
|
+
/**
|
|
178
|
+
* Infer all workflows from a contract (client perspective)
|
|
179
|
+
*/
|
|
180
|
+
type ClientInferWorkflows<TContract extends ContractDefinition> = { [K in keyof TContract["workflows"]]: ClientInferWorkflow<TContract["workflows"][K]> };
|
|
181
|
+
/**
|
|
182
|
+
* Infer all activities from a contract (client perspective)
|
|
183
|
+
*/
|
|
184
|
+
type ClientInferActivities<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof TContract["activities"]]: ClientInferActivity<TContract["activities"][K]> } : {};
|
|
185
|
+
/**
|
|
186
|
+
* Infer activities from a workflow definition (client perspective)
|
|
187
|
+
*/
|
|
188
|
+
type ClientInferWorkflowActivities<T extends WorkflowDefinition> = T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: ClientInferActivity<T["activities"][K]> } : {};
|
|
189
|
+
/**
|
|
190
|
+
* Infer signals from a workflow definition (client perspective)
|
|
191
|
+
*/
|
|
192
|
+
type ClientInferWorkflowSignals<T extends WorkflowDefinition> = T["signals"] extends Record<string, SignalDefinition> ? { [K in keyof T["signals"]]: ClientInferSignal<T["signals"][K]> } : {};
|
|
193
|
+
/**
|
|
194
|
+
* Infer queries from a workflow definition (client perspective)
|
|
195
|
+
*/
|
|
196
|
+
type ClientInferWorkflowQueries<T extends WorkflowDefinition> = T["queries"] extends Record<string, QueryDefinition> ? { [K in keyof T["queries"]]: ClientInferQuery<T["queries"][K]> } : {};
|
|
197
|
+
/**
|
|
198
|
+
* Infer updates from a workflow definition (client perspective)
|
|
199
|
+
*/
|
|
200
|
+
type ClientInferWorkflowUpdates<T extends WorkflowDefinition> = T["updates"] extends Record<string, UpdateDefinition> ? { [K in keyof T["updates"]]: ClientInferUpdate<T["updates"][K]> } : {};
|
|
201
|
+
/**
|
|
202
|
+
* Infer all activities available in a workflow context (client perspective)
|
|
203
|
+
* Combines workflow-specific activities with global activities
|
|
204
|
+
*/
|
|
205
|
+
type ClientInferWorkflowContextActivities<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = ClientInferWorkflowActivities<TContract["workflows"][TWorkflowName]> & ClientInferActivities<TContract>;
|
|
206
|
+
/**
|
|
207
|
+
* UTILITY TYPES FOR ACTIVITY HANDLERS
|
|
208
|
+
*/
|
|
209
|
+
/**
|
|
210
|
+
* Extract workflow names from a contract as a union type
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* type MyWorkflowNames = InferWorkflowNames<typeof myContract>;
|
|
215
|
+
* // "processOrder" | "sendNotification"
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
type InferWorkflowNames<TContract extends ContractDefinition> = keyof TContract["workflows"] & string;
|
|
219
|
+
/**
|
|
220
|
+
* Extract activity names from a contract (global activities) as a union type
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* type MyActivityNames = InferActivityNames<typeof myContract>;
|
|
225
|
+
* // "log" | "sendEmail"
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
type InferActivityNames<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? keyof TContract["activities"] & string : never;
|
|
229
|
+
/**
|
|
230
|
+
* Extract all workflows from a contract with their definitions
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* type MyWorkflows = InferContractWorkflows<typeof myContract>;
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
type InferContractWorkflows<TContract extends ContractDefinition> = TContract["workflows"];
|
|
238
|
+
/**
|
|
239
|
+
* Infer the handler type for a global activity from a contract
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const log: ActivityHandler<typeof myContract, "log"> = async ({ level, message }) => {
|
|
244
|
+
* logger[level](message);
|
|
245
|
+
* };
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
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;
|
|
249
|
+
/**
|
|
250
|
+
* Infer the handler type for a workflow-specific activity from a contract
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* const processPayment: WorkflowActivityHandler<
|
|
255
|
+
* typeof myContract,
|
|
256
|
+
* "processOrder",
|
|
257
|
+
* "processPayment"
|
|
258
|
+
* > = async ({ customerId, amount }) => {
|
|
259
|
+
* // Implementation
|
|
260
|
+
* return { transactionId, status: "success" as const, paidAmount: amount };
|
|
261
|
+
* };
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
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;
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/builder.d.ts
|
|
267
|
+
/**
|
|
268
|
+
* Builder for creating activity definitions
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```ts
|
|
272
|
+
* const myActivity = defineActivity({
|
|
273
|
+
* input: z.tuple([z.object({ name: z.string() })]),
|
|
274
|
+
* output: z.object({ greeting: z.string() }),
|
|
275
|
+
* });
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
declare const defineActivity: <TActivity extends ActivityDefinition>(definition: TActivity) => TActivity;
|
|
279
|
+
/**
|
|
280
|
+
* Builder for creating signal definitions
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* const mySignal = defineSignal({
|
|
285
|
+
* input: z.object({ message: z.string() }),
|
|
286
|
+
* });
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
declare const defineSignal: <TSignal extends SignalDefinition>(definition: TSignal) => TSignal;
|
|
290
|
+
/**
|
|
291
|
+
* Builder for creating query definitions
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* const myQuery = defineQuery({
|
|
296
|
+
* input: z.object({ id: z.string() }),
|
|
297
|
+
* output: z.object({ status: z.string() }),
|
|
298
|
+
* });
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
declare const defineQuery: <TQuery extends QueryDefinition>(definition: TQuery) => TQuery;
|
|
302
|
+
/**
|
|
303
|
+
* Builder for creating update definitions
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```ts
|
|
307
|
+
* const myUpdate = defineUpdate({
|
|
308
|
+
* input: z.object({ value: z.number() }),
|
|
309
|
+
* output: z.object({ newValue: z.number() }),
|
|
310
|
+
* });
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
declare const defineUpdate: <TUpdate extends UpdateDefinition>(definition: TUpdate) => TUpdate;
|
|
314
|
+
/**
|
|
315
|
+
* Builder for creating workflow definitions
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* const myWorkflow = defineWorkflow({
|
|
320
|
+
* input: z.tuple([z.object({ orderId: z.string() })]),
|
|
321
|
+
* output: z.object({ status: z.string() }),
|
|
322
|
+
* activities: {
|
|
323
|
+
* processPayment: defineActivity({
|
|
324
|
+
* input: z.tuple([z.object({ amount: z.number() })]),
|
|
325
|
+
* output: z.object({ success: z.boolean() }),
|
|
326
|
+
* }),
|
|
327
|
+
* },
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
declare const defineWorkflow: <TWorkflow extends WorkflowDefinition>(definition: TWorkflow) => TWorkflow;
|
|
332
|
+
/**
|
|
333
|
+
* Builder for creating a complete contract
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* const myContract = defineContract({
|
|
338
|
+
* taskQueue: 'my-service',
|
|
339
|
+
* workflows: {
|
|
340
|
+
* processOrder: defineWorkflow({ ... }),
|
|
341
|
+
* sendNotification: defineWorkflow({ ... }),
|
|
342
|
+
* },
|
|
343
|
+
* activities: {
|
|
344
|
+
* sendEmail: defineActivity({ ... }),
|
|
345
|
+
* },
|
|
346
|
+
* });
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
declare const defineContract: <TContract extends ContractDefinition>(definition: TContract) => TContract;
|
|
350
|
+
//#endregion
|
|
351
|
+
export { type ActivityDefinition, type ActivityHandler, type AnyZodSchema, type ClientInferActivities, type ClientInferActivity, type ClientInferInput, type ClientInferOutput, type ClientInferQuery, type ClientInferSignal, type ClientInferUpdate, type ClientInferWorkflow, type ClientInferWorkflowActivities, type ClientInferWorkflowContextActivities, type ClientInferWorkflowQueries, type ClientInferWorkflowSignals, type ClientInferWorkflowUpdates, type ClientInferWorkflows, type ContractDefinition, type InferActivityNames, type InferContractWorkflows, type InferWorkflowNames, type QueryDefinition, type SignalDefinition, type UpdateDefinition, type WorkerInferActivities, type WorkerInferActivity, type WorkerInferInput, type WorkerInferOutput, type WorkerInferQuery, type WorkerInferSignal, type WorkerInferUpdate, type WorkerInferWorkflow, type WorkerInferWorkflowActivities, type WorkerInferWorkflowContextActivities, type WorkerInferWorkflowQueries, type WorkerInferWorkflowSignals, type WorkerInferWorkflowUpdates, type WorkerInferWorkflows, type WorkflowActivityHandler, type WorkflowDefinition, defineActivity, defineContract, defineQuery, defineSignal, defineUpdate, defineWorkflow };
|