@temporal-contract/contract 0.0.2 → 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/src/builder.ts DELETED
@@ -1,286 +0,0 @@
1
- import { z } from "zod";
2
- import type { StandardSchemaV1 } from "@standard-schema/spec";
3
- import type {
4
- ActivityDefinition,
5
- ContractDefinition,
6
- QueryDefinition,
7
- SignalDefinition,
8
- UpdateDefinition,
9
- WorkflowDefinition,
10
- } from "./types.js";
11
-
12
- /**
13
- * Check if a value is a Standard Schema compatible schema
14
- */
15
- function isStandardSchema(value: unknown): value is StandardSchemaV1 {
16
- // Standard Schema can be either an object or a function (e.g., ArkType)
17
- if (
18
- (typeof value !== "object" && typeof value !== "function") ||
19
- value === null ||
20
- !("~standard" in value)
21
- ) {
22
- return false;
23
- }
24
-
25
- const standard = (value as Record<string, unknown>)["~standard"];
26
-
27
- return (
28
- typeof standard === "object" &&
29
- standard !== null &&
30
- (standard as Record<string, unknown>)["version"] === 1 &&
31
- typeof (standard as Record<string, unknown>)["validate"] === "function"
32
- );
33
- }
34
-
35
- /**
36
- * Schema for validating JavaScript identifiers (workflow names, activity names, etc.)
37
- * Allows: letters, digits, underscore, dollar sign
38
- * Must start with: letter, underscore, or dollar sign
39
- */
40
- const identifierSchema = z
41
- .string()
42
- .min(1)
43
- .regex(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/, "must be a valid JavaScript identifier");
44
-
45
- /**
46
- * Extract clean error message from Zod validation error
47
- */
48
- const getCleanErrorMessage = (error: z.ZodError): string => {
49
- try {
50
- const parsed = JSON.parse(error.message);
51
- if (Array.isArray(parsed) && parsed.length > 0) {
52
- const firstError = parsed[0];
53
-
54
- // For record key validation errors, dive into nested issues
55
- if (
56
- firstError?.code === "invalid_key" &&
57
- firstError?.issues &&
58
- firstError.issues.length > 0
59
- ) {
60
- const nestedError = firstError.issues[0];
61
- if (nestedError?.message) {
62
- return nestedError.message;
63
- }
64
- }
65
-
66
- // For direct validation errors
67
- if (firstError?.message) {
68
- return firstError.message;
69
- }
70
- }
71
- } catch {
72
- // If parsing fails, return the raw message
73
- }
74
- return error.message;
75
- };
76
-
77
- /**
78
- * Schema for validating activity definitions
79
- * Checks that input and output are Standard Schema compatible schemas
80
- */
81
- const activityDefinitionSchema = z.object({
82
- input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
83
- message: "input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
84
- }),
85
- output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
86
- message: "output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
87
- }),
88
- });
89
-
90
- /**
91
- * Schema for validating signal definitions
92
- */
93
- const signalDefinitionSchema = z.object({
94
- input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
95
- message: "input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
96
- }),
97
- });
98
-
99
- /**
100
- * Schema for validating query definitions
101
- */
102
- const queryDefinitionSchema = z.object({
103
- input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
104
- message: "input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
105
- }),
106
- output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
107
- message: "output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
108
- }),
109
- });
110
-
111
- /**
112
- * Schema for validating update definitions
113
- */
114
- const updateDefinitionSchema = z.object({
115
- input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
116
- message: "input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
117
- }),
118
- output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
119
- message: "output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
120
- }),
121
- });
122
-
123
- /**
124
- * Schema for validating workflow definitions
125
- */
126
- const workflowDefinitionSchema = z.object({
127
- input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
128
- message: "input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
129
- }),
130
- output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {
131
- message: "output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)",
132
- }),
133
- activities: z.record(identifierSchema, activityDefinitionSchema).optional(),
134
- signals: z.record(identifierSchema, signalDefinitionSchema).optional(),
135
- queries: z.record(identifierSchema, queryDefinitionSchema).optional(),
136
- updates: z.record(identifierSchema, updateDefinitionSchema).optional(),
137
- });
138
-
139
- /**
140
- * Schema for validating a contract definition structure
141
- */
142
- const contractValidationSchema = z
143
- .object({
144
- taskQueue: z.string().trim().min(1, "taskQueue cannot be empty"),
145
- workflows: z
146
- .record(identifierSchema, workflowDefinitionSchema)
147
- .refine((workflows) => Object.keys(workflows).length > 0, {
148
- message: "at least one workflow is required",
149
- }),
150
- activities: z.record(identifierSchema, activityDefinitionSchema).optional(),
151
- })
152
- .superRefine((contract, ctx) => {
153
- // Check for conflicts between global and workflow-specific activities
154
- if (!contract.activities) {
155
- return;
156
- }
157
-
158
- for (const [workflowName, workflow] of Object.entries(contract.workflows)) {
159
- if (workflow.activities) {
160
- for (const activityName of Object.keys(workflow.activities)) {
161
- if (activityName in contract.activities) {
162
- ctx.addIssue({
163
- code: z.ZodIssueCode.custom,
164
- message: `workflow "${workflowName}" has activity "${activityName}" that conflicts with a global activity. Consider renaming the workflow-specific activity or removing the global activity "${activityName}".`,
165
- });
166
- return;
167
- }
168
- }
169
- }
170
- }
171
- });
172
-
173
- /**
174
- * Builder for creating activity definitions
175
- *
176
- * @example
177
- * ```ts
178
- * const myActivity = defineActivity({
179
- * input: z.tuple([z.object({ name: z.string() })]),
180
- * output: z.object({ greeting: z.string() }),
181
- * });
182
- * ```
183
- */
184
- export const defineActivity = <TActivity extends ActivityDefinition>(
185
- definition: TActivity,
186
- ): TActivity => {
187
- return definition;
188
- };
189
-
190
- /**
191
- * Builder for creating signal definitions
192
- *
193
- * @example
194
- * ```ts
195
- * const mySignal = defineSignal({
196
- * input: z.object({ message: z.string() }),
197
- * });
198
- * ```
199
- */
200
- export const defineSignal = <TSignal extends SignalDefinition>(definition: TSignal): TSignal => {
201
- return definition;
202
- };
203
-
204
- /**
205
- * Builder for creating query definitions
206
- *
207
- * @example
208
- * ```ts
209
- * const myQuery = defineQuery({
210
- * input: z.object({ id: z.string() }),
211
- * output: z.object({ status: z.string() }),
212
- * });
213
- * ```
214
- */
215
- export const defineQuery = <TQuery extends QueryDefinition>(definition: TQuery): TQuery => {
216
- return definition;
217
- };
218
-
219
- /**
220
- * Builder for creating update definitions
221
- *
222
- * @example
223
- * ```ts
224
- * const myUpdate = defineUpdate({
225
- * input: z.object({ value: z.number() }),
226
- * output: z.object({ newValue: z.number() }),
227
- * });
228
- * ```
229
- */
230
- export const defineUpdate = <TUpdate extends UpdateDefinition>(definition: TUpdate): TUpdate => {
231
- return definition;
232
- };
233
-
234
- /**
235
- * Builder for creating workflow definitions
236
- *
237
- * @example
238
- * ```ts
239
- * const myWorkflow = defineWorkflow({
240
- * input: z.tuple([z.object({ orderId: z.string() })]),
241
- * output: z.object({ status: z.string() }),
242
- * activities: {
243
- * processPayment: defineActivity({
244
- * input: z.tuple([z.object({ amount: z.number() })]),
245
- * output: z.object({ success: z.boolean() }),
246
- * }),
247
- * },
248
- * });
249
- * ```
250
- */
251
- export const defineWorkflow = <TWorkflow extends WorkflowDefinition>(
252
- definition: TWorkflow,
253
- ): TWorkflow => {
254
- return definition;
255
- };
256
-
257
- /**
258
- * Builder for creating a complete contract
259
- *
260
- * @example
261
- * ```ts
262
- * const myContract = defineContract({
263
- * taskQueue: 'my-service',
264
- * workflows: {
265
- * processOrder: defineWorkflow({ ... }),
266
- * sendNotification: defineWorkflow({ ... }),
267
- * },
268
- * activities: {
269
- * sendEmail: defineActivity({ ... }),
270
- * },
271
- * });
272
- * ```
273
- */
274
- export const defineContract = <TContract extends ContractDefinition>(
275
- definition: TContract,
276
- ): TContract => {
277
- // Validate entire contract structure with Zod (including activity conflicts)
278
- const validationResult = contractValidationSchema.safeParse(definition);
279
-
280
- if (!validationResult.success) {
281
- const cleanMessage = getCleanErrorMessage(validationResult.error);
282
- throw new Error(`Contract error: ${cleanMessage}`);
283
- }
284
-
285
- return definition;
286
- };
@@ -1,122 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- defineActivity,
4
- defineQuery,
5
- defineSignal,
6
- defineUpdate,
7
- defineWorkflow,
8
- } from "./builder.js";
9
- import { z } from "zod";
10
-
11
- describe("Helper Functions", () => {
12
- describe("defineActivity", () => {
13
- it("should create an activity definition", () => {
14
- const activity = defineActivity({
15
- input: z.object({ value: z.string() }),
16
- output: z.object({ result: z.string() }),
17
- });
18
-
19
- expect(activity.input).toBeDefined();
20
- expect(activity.output).toBeDefined();
21
- });
22
- });
23
-
24
- describe("defineSignal", () => {
25
- it("should create a signal definition", () => {
26
- const signal = defineSignal({
27
- input: z.object({ message: z.string() }),
28
- });
29
-
30
- expect(signal.input).toBeDefined();
31
- });
32
-
33
- it("should work with primitive types", () => {
34
- const signal = defineSignal({
35
- input: z.string(),
36
- });
37
-
38
- expect(signal.input).toBeDefined();
39
- });
40
- });
41
-
42
- describe("defineQuery", () => {
43
- it("should create a query definition", () => {
44
- const query = defineQuery({
45
- input: z.object({ id: z.string() }),
46
- output: z.object({ status: z.string() }),
47
- });
48
-
49
- expect(query.input).toBeDefined();
50
- expect(query.output).toBeDefined();
51
- });
52
-
53
- it("should work with void input", () => {
54
- const query = defineQuery({
55
- input: z.void(),
56
- output: z.object({ count: z.number() }),
57
- });
58
-
59
- expect(query.input).toBeDefined();
60
- expect(query.output).toBeDefined();
61
- });
62
- });
63
-
64
- describe("defineUpdate", () => {
65
- it("should create an update definition", () => {
66
- const update = defineUpdate({
67
- input: z.object({ value: z.number() }),
68
- output: z.object({ newValue: z.number() }),
69
- });
70
-
71
- expect(update.input).toBeDefined();
72
- expect(update.output).toBeDefined();
73
- });
74
- });
75
-
76
- describe("defineWorkflow", () => {
77
- it("should create a workflow definition", () => {
78
- const workflow = defineWorkflow({
79
- input: z.object({ orderId: z.string() }),
80
- output: z.object({ status: z.string() }),
81
- });
82
-
83
- expect(workflow.input).toBeDefined();
84
- expect(workflow.output).toBeDefined();
85
- });
86
-
87
- it("should support all interaction types", () => {
88
- const workflow = defineWorkflow({
89
- input: z.object({ orderId: z.string() }),
90
- output: z.object({ status: z.string() }),
91
- activities: {
92
- processPayment: {
93
- input: z.object({ amount: z.number() }),
94
- output: z.object({ success: z.boolean() }),
95
- },
96
- },
97
- signals: {
98
- cancelOrder: {
99
- input: z.object({ reason: z.string() }),
100
- },
101
- },
102
- queries: {
103
- getStatus: {
104
- input: z.void(),
105
- output: z.object({ status: z.string() }),
106
- },
107
- },
108
- updates: {
109
- updateAmount: {
110
- input: z.object({ newAmount: z.number() }),
111
- output: z.object({ updated: z.boolean() }),
112
- },
113
- },
114
- });
115
-
116
- expect(workflow.activities).toBeDefined();
117
- expect(workflow.signals).toBeDefined();
118
- expect(workflow.queries).toBeDefined();
119
- expect(workflow.updates).toBeDefined();
120
- });
121
- });
122
- });
package/src/index.ts DELETED
@@ -1,55 +0,0 @@
1
- export {
2
- defineActivity,
3
- defineContract,
4
- defineQuery,
5
- defineSignal,
6
- defineUpdate,
7
- defineWorkflow,
8
- } from "./builder.js";
9
-
10
- export type {
11
- AnySchema,
12
- ActivityDefinition,
13
- SignalDefinition,
14
- QueryDefinition,
15
- UpdateDefinition,
16
- WorkflowDefinition,
17
- ContractDefinition,
18
- // Worker perspective types
19
- WorkerInferInput,
20
- WorkerInferOutput,
21
- WorkerInferWorkflow,
22
- WorkerInferActivity,
23
- WorkerInferSignal,
24
- WorkerInferQuery,
25
- WorkerInferUpdate,
26
- WorkerInferWorkflows,
27
- WorkerInferActivities,
28
- WorkerInferWorkflowActivities,
29
- WorkerInferWorkflowSignals,
30
- WorkerInferWorkflowQueries,
31
- WorkerInferWorkflowUpdates,
32
- WorkerInferWorkflowContextActivities,
33
- // Client perspective types
34
- ClientInferInput,
35
- ClientInferOutput,
36
- ClientInferWorkflow,
37
- ClientInferActivity,
38
- ClientInferSignal,
39
- ClientInferQuery,
40
- ClientInferUpdate,
41
- ClientInferWorkflows,
42
- ClientInferActivities,
43
- ClientInferWorkflowActivities,
44
- ClientInferWorkflowSignals,
45
- ClientInferWorkflowQueries,
46
- ClientInferWorkflowUpdates,
47
- ClientInferWorkflowContextActivities,
48
- // Activity handler utility types
49
- ActivityHandler,
50
- WorkflowActivityHandler,
51
- // Contract utility types
52
- InferWorkflowNames,
53
- InferActivityNames,
54
- InferContractWorkflows,
55
- } from "./types.js";