@temporal-contract/contract 2.0.0 → 2.2.0

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 CHANGED
@@ -375,6 +375,56 @@ const contractValidationSchema = zod.z.object({
375
375
  }
376
376
  });
377
377
  //#endregion
378
+ //#region src/format.ts
379
+ /**
380
+ * Pattern for string keys safe to render with dot notation. A "safe" key is a
381
+ * JavaScript identifier (letters/digits/underscore/$, not starting with a
382
+ * digit). Anything else — keys containing dots, spaces, leading digits, the
383
+ * empty string, the literal string `"0"` etc. — gets bracket-quoted so the
384
+ * path is unambiguous. Reserved words are accepted: we are formatting a
385
+ * diagnostic, not generating runnable code.
386
+ */
387
+ const SAFE_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
388
+ /**
389
+ * Render a Standard Schema {@link StandardSchemaV1.Issue} into a human-readable
390
+ * string that includes the failing field's path.
391
+ *
392
+ * Example output:
393
+ * - `at items[0].quantity: Expected number, received undefined`
394
+ * - `at customerId: Expected string, received undefined`
395
+ * - `at user["first name"]: Expected string, received undefined`
396
+ * - `Validation error` *(no path)*
397
+ *
398
+ * Path segments come either as bare `PropertyKey` values or as
399
+ * `{ key: PropertyKey }` objects (per the spec); both are normalized.
400
+ * - Numeric keys → `[N]`
401
+ * - String keys that are valid JS identifiers → bare (first) or `.key`
402
+ * - String keys that aren't valid identifiers → `["..."]` with JSON-style
403
+ * escaping (handles dots, spaces, leading digits, the empty string, the
404
+ * literal string `"0"`, embedded quotes, etc.)
405
+ * - Symbol / other `PropertyKey` → `[Symbol(name)]`
406
+ */
407
+ function formatIssue(issue) {
408
+ if (issue.path === void 0 || issue.path.length === 0) return issue.message;
409
+ let path = "";
410
+ for (let i = 0; i < issue.path.length; i++) {
411
+ const segment = issue.path[i];
412
+ const key = segment !== null && typeof segment === "object" && "key" in segment ? segment.key : segment;
413
+ if (typeof key === "number") path += `[${key}]`;
414
+ else if (typeof key === "string" && SAFE_IDENTIFIER.test(key)) path += i === 0 ? key : `.${key}`;
415
+ else if (typeof key === "string") path += `[${JSON.stringify(key)}]`;
416
+ else path += `[${String(key)}]`;
417
+ }
418
+ return `at ${path}: ${issue.message}`;
419
+ }
420
+ /**
421
+ * Join a list of validation issues into a single message, with each issue
422
+ * rendered via {@link formatIssue} so field paths surface in the error text.
423
+ */
424
+ function summarizeIssues(issues) {
425
+ return issues.map(formatIssue).join("; ");
426
+ }
427
+ //#endregion
378
428
  exports.defineActivity = defineActivity;
379
429
  exports.defineContract = defineContract;
380
430
  exports.defineQuery = defineQuery;
@@ -382,3 +432,5 @@ exports.defineSearchAttribute = defineSearchAttribute;
382
432
  exports.defineSignal = defineSignal;
383
433
  exports.defineUpdate = defineUpdate;
384
434
  exports.defineWorkflow = defineWorkflow;
435
+ exports.formatIssue = formatIssue;
436
+ exports.summarizeIssues = summarizeIssues;
package/dist/index.d.cts CHANGED
@@ -66,21 +66,74 @@ type SearchAttributeDefinition<TKind extends SearchAttributeKind = SearchAttribu
66
66
  readonly kind: TKind;
67
67
  };
68
68
  /**
69
- * Definition of a workflow
69
+ * Definition of a workflow.
70
+ *
71
+ * Generic parameters preserve the schema literal types of `input`/`output`
72
+ * and the declared shape of activities/signals/queries/updates/search
73
+ * attributes through `defineWorkflow` so client and worker call sites can
74
+ * infer typed payloads. Empty-collection generics default to
75
+ * `Record<string, never>` so that, when no signals/queries/updates/etc. are
76
+ * declared, `keyof` resolves to `never` rather than `string` — turning typos
77
+ * in `signalName`/`queryName`/`updateName` into compile-time errors.
70
78
  */
71
- type 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>, TSearchAttributes extends Record<string, SearchAttributeDefinition> = Record<string, SearchAttributeDefinition>> = {
72
- readonly input: AnySchema;
73
- readonly output: AnySchema;
79
+ type WorkflowDefinition<TInput extends AnySchema = AnySchema, TOutput extends AnySchema = AnySchema, TActivities extends Record<string, ActivityDefinition> = Record<string, never>, TSignals extends Record<string, SignalDefinition> = Record<string, never>, TQueries extends Record<string, QueryDefinition> = Record<string, never>, TUpdates extends Record<string, UpdateDefinition> = Record<string, never>, TSearchAttributes extends Record<string, SearchAttributeDefinition> = Record<string, never>> = {
80
+ readonly input: TInput;
81
+ readonly output: TOutput;
74
82
  readonly activities?: TActivities;
75
83
  readonly signals?: TSignals;
76
84
  readonly queries?: TQueries;
77
85
  readonly updates?: TUpdates;
78
86
  readonly searchAttributes?: TSearchAttributes;
79
87
  };
88
+ /**
89
+ * Widened constraint variant of {@link WorkflowDefinition}.
90
+ *
91
+ * `WorkflowDefinition` (no args) resolves the empty-record generics to
92
+ * `Record<string, never>`, which is the right default for fresh callers but
93
+ * too narrow as a *constraint* — a Record-of-WorkflowDefinition constraint
94
+ * built from it would reject any literal whose `activities`, `signals`,
95
+ * `queries`, or `updates` block is non-empty. `AnyWorkflowDefinition`
96
+ * widens those generics back to their permissive bounds so it can act as
97
+ * the value of `Record<string, …>` in `ContractDefinition` without
98
+ * preventing real workflow definitions from satisfying the constraint.
99
+ */
100
+ type AnyWorkflowDefinition = WorkflowDefinition<AnySchema, AnySchema, Record<string, ActivityDefinition>, Record<string, SignalDefinition>, Record<string, QueryDefinition>, Record<string, UpdateDefinition>, Record<string, SearchAttributeDefinition>>;
101
+ /**
102
+ * Extract signal names declared on a workflow as a string union, or `never`
103
+ * if the workflow declares no signals. Used to constrain `signalName` call
104
+ * sites so typos surface at compile time instead of runtime.
105
+ *
106
+ * The conditional is intentionally distributive over `W` (rather than indexing
107
+ * `W["signals"]` directly) so that union workflow types — e.g. discriminated
108
+ * unions of workflow definitions — yield the *union* of their signal names
109
+ * rather than the intersection (`keyof (A | B)` is the intersection of keys,
110
+ * which usually collapses to `never`). Destructuring `signals` via
111
+ * `infer S` also tolerates the property being absent or `undefined` under
112
+ * `exactOptionalPropertyTypes`.
113
+ */
114
+ type SignalNamesOf<W extends AnyWorkflowDefinition> = W extends {
115
+ signals?: infer S;
116
+ } ? S extends Record<string, SignalDefinition> ? keyof S & string : never : never;
117
+ /**
118
+ * Extract query names declared on a workflow as a string union, or `never`
119
+ * if the workflow declares no queries. See {@link SignalNamesOf} for the
120
+ * rationale behind the distributive `infer`-based shape.
121
+ */
122
+ type QueryNamesOf<W extends AnyWorkflowDefinition> = W extends {
123
+ queries?: infer Q;
124
+ } ? Q extends Record<string, QueryDefinition> ? keyof Q & string : never : never;
125
+ /**
126
+ * Extract update names declared on a workflow as a string union, or `never`
127
+ * if the workflow declares no updates. See {@link SignalNamesOf} for the
128
+ * rationale behind the distributive `infer`-based shape.
129
+ */
130
+ type UpdateNamesOf<W extends AnyWorkflowDefinition> = W extends {
131
+ updates?: infer U;
132
+ } ? U extends Record<string, UpdateDefinition> ? keyof U & string : never : never;
80
133
  /**
81
134
  * Contract definition containing workflows and optional global activities
82
135
  */
83
- type ContractDefinition<TWorkflows extends Record<string, WorkflowDefinition> = Record<string, WorkflowDefinition>, TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>> = {
136
+ type ContractDefinition<TWorkflows extends Record<string, AnyWorkflowDefinition> = Record<string, AnyWorkflowDefinition>, TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>> = {
84
137
  readonly taskQueue: string;
85
138
  readonly workflows: TWorkflows;
86
139
  readonly activities?: TActivities;
@@ -305,7 +358,7 @@ declare function defineSearchAttribute<TKind extends SearchAttributeKind>(defini
305
358
  * });
306
359
  * ```
307
360
  */
308
- declare function defineWorkflow<TWorkflow extends WorkflowDefinition>(definition: TWorkflow): TWorkflow;
361
+ declare function defineWorkflow<TWorkflow extends AnyWorkflowDefinition>(definition: TWorkflow): TWorkflow;
309
362
  /**
310
363
  * Define a complete Temporal contract with type-safe workflows and activities.
311
364
  *
@@ -359,5 +412,32 @@ declare function defineWorkflow<TWorkflow extends WorkflowDefinition>(definition
359
412
  */
360
413
  declare function defineContract<TContract extends ContractDefinition>(definition: TContract): TContract;
361
414
  //#endregion
362
- export { type ActivityDefinition, type AnySchema, type ContractDefinition, type InferActivityNames, type InferContractWorkflows, type InferWorkflowNames, type QueryDefinition, type SearchAttributeDefinition, type SearchAttributeKind, type SearchAttributeKindToType, type SignalDefinition, type UpdateDefinition, type WorkflowDefinition, defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow };
415
+ //#region src/format.d.ts
416
+ /**
417
+ * Render a Standard Schema {@link StandardSchemaV1.Issue} into a human-readable
418
+ * string that includes the failing field's path.
419
+ *
420
+ * Example output:
421
+ * - `at items[0].quantity: Expected number, received undefined`
422
+ * - `at customerId: Expected string, received undefined`
423
+ * - `at user["first name"]: Expected string, received undefined`
424
+ * - `Validation error` *(no path)*
425
+ *
426
+ * Path segments come either as bare `PropertyKey` values or as
427
+ * `{ key: PropertyKey }` objects (per the spec); both are normalized.
428
+ * - Numeric keys → `[N]`
429
+ * - String keys that are valid JS identifiers → bare (first) or `.key`
430
+ * - String keys that aren't valid identifiers → `["..."]` with JSON-style
431
+ * escaping (handles dots, spaces, leading digits, the empty string, the
432
+ * literal string `"0"`, embedded quotes, etc.)
433
+ * - Symbol / other `PropertyKey` → `[Symbol(name)]`
434
+ */
435
+ declare function formatIssue(issue: StandardSchemaV1.Issue): string;
436
+ /**
437
+ * Join a list of validation issues into a single message, with each issue
438
+ * rendered via {@link formatIssue} so field paths surface in the error text.
439
+ */
440
+ declare function summarizeIssues(issues: ReadonlyArray<StandardSchemaV1.Issue>): string;
441
+ //#endregion
442
+ export { type ActivityDefinition, type AnySchema, type AnyWorkflowDefinition, type ContractDefinition, type InferActivityNames, type InferContractWorkflows, type InferWorkflowNames, type QueryDefinition, type QueryNamesOf, type SearchAttributeDefinition, type SearchAttributeKind, type SearchAttributeKindToType, type SignalDefinition, type SignalNamesOf, type UpdateDefinition, type UpdateNamesOf, type WorkflowDefinition, defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow, formatIssue, summarizeIssues };
363
443
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/builder.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/builder.ts","../src/format.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -66,21 +66,74 @@ type SearchAttributeDefinition<TKind extends SearchAttributeKind = SearchAttribu
66
66
  readonly kind: TKind;
67
67
  };
68
68
  /**
69
- * Definition of a workflow
69
+ * Definition of a workflow.
70
+ *
71
+ * Generic parameters preserve the schema literal types of `input`/`output`
72
+ * and the declared shape of activities/signals/queries/updates/search
73
+ * attributes through `defineWorkflow` so client and worker call sites can
74
+ * infer typed payloads. Empty-collection generics default to
75
+ * `Record<string, never>` so that, when no signals/queries/updates/etc. are
76
+ * declared, `keyof` resolves to `never` rather than `string` — turning typos
77
+ * in `signalName`/`queryName`/`updateName` into compile-time errors.
70
78
  */
71
- type 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>, TSearchAttributes extends Record<string, SearchAttributeDefinition> = Record<string, SearchAttributeDefinition>> = {
72
- readonly input: AnySchema;
73
- readonly output: AnySchema;
79
+ type WorkflowDefinition<TInput extends AnySchema = AnySchema, TOutput extends AnySchema = AnySchema, TActivities extends Record<string, ActivityDefinition> = Record<string, never>, TSignals extends Record<string, SignalDefinition> = Record<string, never>, TQueries extends Record<string, QueryDefinition> = Record<string, never>, TUpdates extends Record<string, UpdateDefinition> = Record<string, never>, TSearchAttributes extends Record<string, SearchAttributeDefinition> = Record<string, never>> = {
80
+ readonly input: TInput;
81
+ readonly output: TOutput;
74
82
  readonly activities?: TActivities;
75
83
  readonly signals?: TSignals;
76
84
  readonly queries?: TQueries;
77
85
  readonly updates?: TUpdates;
78
86
  readonly searchAttributes?: TSearchAttributes;
79
87
  };
88
+ /**
89
+ * Widened constraint variant of {@link WorkflowDefinition}.
90
+ *
91
+ * `WorkflowDefinition` (no args) resolves the empty-record generics to
92
+ * `Record<string, never>`, which is the right default for fresh callers but
93
+ * too narrow as a *constraint* — a Record-of-WorkflowDefinition constraint
94
+ * built from it would reject any literal whose `activities`, `signals`,
95
+ * `queries`, or `updates` block is non-empty. `AnyWorkflowDefinition`
96
+ * widens those generics back to their permissive bounds so it can act as
97
+ * the value of `Record<string, …>` in `ContractDefinition` without
98
+ * preventing real workflow definitions from satisfying the constraint.
99
+ */
100
+ type AnyWorkflowDefinition = WorkflowDefinition<AnySchema, AnySchema, Record<string, ActivityDefinition>, Record<string, SignalDefinition>, Record<string, QueryDefinition>, Record<string, UpdateDefinition>, Record<string, SearchAttributeDefinition>>;
101
+ /**
102
+ * Extract signal names declared on a workflow as a string union, or `never`
103
+ * if the workflow declares no signals. Used to constrain `signalName` call
104
+ * sites so typos surface at compile time instead of runtime.
105
+ *
106
+ * The conditional is intentionally distributive over `W` (rather than indexing
107
+ * `W["signals"]` directly) so that union workflow types — e.g. discriminated
108
+ * unions of workflow definitions — yield the *union* of their signal names
109
+ * rather than the intersection (`keyof (A | B)` is the intersection of keys,
110
+ * which usually collapses to `never`). Destructuring `signals` via
111
+ * `infer S` also tolerates the property being absent or `undefined` under
112
+ * `exactOptionalPropertyTypes`.
113
+ */
114
+ type SignalNamesOf<W extends AnyWorkflowDefinition> = W extends {
115
+ signals?: infer S;
116
+ } ? S extends Record<string, SignalDefinition> ? keyof S & string : never : never;
117
+ /**
118
+ * Extract query names declared on a workflow as a string union, or `never`
119
+ * if the workflow declares no queries. See {@link SignalNamesOf} for the
120
+ * rationale behind the distributive `infer`-based shape.
121
+ */
122
+ type QueryNamesOf<W extends AnyWorkflowDefinition> = W extends {
123
+ queries?: infer Q;
124
+ } ? Q extends Record<string, QueryDefinition> ? keyof Q & string : never : never;
125
+ /**
126
+ * Extract update names declared on a workflow as a string union, or `never`
127
+ * if the workflow declares no updates. See {@link SignalNamesOf} for the
128
+ * rationale behind the distributive `infer`-based shape.
129
+ */
130
+ type UpdateNamesOf<W extends AnyWorkflowDefinition> = W extends {
131
+ updates?: infer U;
132
+ } ? U extends Record<string, UpdateDefinition> ? keyof U & string : never : never;
80
133
  /**
81
134
  * Contract definition containing workflows and optional global activities
82
135
  */
83
- type ContractDefinition<TWorkflows extends Record<string, WorkflowDefinition> = Record<string, WorkflowDefinition>, TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>> = {
136
+ type ContractDefinition<TWorkflows extends Record<string, AnyWorkflowDefinition> = Record<string, AnyWorkflowDefinition>, TActivities extends Record<string, ActivityDefinition> = Record<string, ActivityDefinition>> = {
84
137
  readonly taskQueue: string;
85
138
  readonly workflows: TWorkflows;
86
139
  readonly activities?: TActivities;
@@ -305,7 +358,7 @@ declare function defineSearchAttribute<TKind extends SearchAttributeKind>(defini
305
358
  * });
306
359
  * ```
307
360
  */
308
- declare function defineWorkflow<TWorkflow extends WorkflowDefinition>(definition: TWorkflow): TWorkflow;
361
+ declare function defineWorkflow<TWorkflow extends AnyWorkflowDefinition>(definition: TWorkflow): TWorkflow;
309
362
  /**
310
363
  * Define a complete Temporal contract with type-safe workflows and activities.
311
364
  *
@@ -359,5 +412,32 @@ declare function defineWorkflow<TWorkflow extends WorkflowDefinition>(definition
359
412
  */
360
413
  declare function defineContract<TContract extends ContractDefinition>(definition: TContract): TContract;
361
414
  //#endregion
362
- export { type ActivityDefinition, type AnySchema, type ContractDefinition, type InferActivityNames, type InferContractWorkflows, type InferWorkflowNames, type QueryDefinition, type SearchAttributeDefinition, type SearchAttributeKind, type SearchAttributeKindToType, type SignalDefinition, type UpdateDefinition, type WorkflowDefinition, defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow };
415
+ //#region src/format.d.ts
416
+ /**
417
+ * Render a Standard Schema {@link StandardSchemaV1.Issue} into a human-readable
418
+ * string that includes the failing field's path.
419
+ *
420
+ * Example output:
421
+ * - `at items[0].quantity: Expected number, received undefined`
422
+ * - `at customerId: Expected string, received undefined`
423
+ * - `at user["first name"]: Expected string, received undefined`
424
+ * - `Validation error` *(no path)*
425
+ *
426
+ * Path segments come either as bare `PropertyKey` values or as
427
+ * `{ key: PropertyKey }` objects (per the spec); both are normalized.
428
+ * - Numeric keys → `[N]`
429
+ * - String keys that are valid JS identifiers → bare (first) or `.key`
430
+ * - String keys that aren't valid identifiers → `["..."]` with JSON-style
431
+ * escaping (handles dots, spaces, leading digits, the empty string, the
432
+ * literal string `"0"`, embedded quotes, etc.)
433
+ * - Symbol / other `PropertyKey` → `[Symbol(name)]`
434
+ */
435
+ declare function formatIssue(issue: StandardSchemaV1.Issue): string;
436
+ /**
437
+ * Join a list of validation issues into a single message, with each issue
438
+ * rendered via {@link formatIssue} so field paths surface in the error text.
439
+ */
440
+ declare function summarizeIssues(issues: ReadonlyArray<StandardSchemaV1.Issue>): string;
441
+ //#endregion
442
+ export { type ActivityDefinition, type AnySchema, type AnyWorkflowDefinition, type ContractDefinition, type InferActivityNames, type InferContractWorkflows, type InferWorkflowNames, type QueryDefinition, type QueryNamesOf, type SearchAttributeDefinition, type SearchAttributeKind, type SearchAttributeKindToType, type SignalDefinition, type SignalNamesOf, type UpdateDefinition, type UpdateNamesOf, type WorkflowDefinition, defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow, formatIssue, summarizeIssues };
363
443
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/builder.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/builder.ts","../src/format.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -374,6 +374,56 @@ const contractValidationSchema = z.object({
374
374
  }
375
375
  });
376
376
  //#endregion
377
- export { defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow };
377
+ //#region src/format.ts
378
+ /**
379
+ * Pattern for string keys safe to render with dot notation. A "safe" key is a
380
+ * JavaScript identifier (letters/digits/underscore/$, not starting with a
381
+ * digit). Anything else — keys containing dots, spaces, leading digits, the
382
+ * empty string, the literal string `"0"` etc. — gets bracket-quoted so the
383
+ * path is unambiguous. Reserved words are accepted: we are formatting a
384
+ * diagnostic, not generating runnable code.
385
+ */
386
+ const SAFE_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
387
+ /**
388
+ * Render a Standard Schema {@link StandardSchemaV1.Issue} into a human-readable
389
+ * string that includes the failing field's path.
390
+ *
391
+ * Example output:
392
+ * - `at items[0].quantity: Expected number, received undefined`
393
+ * - `at customerId: Expected string, received undefined`
394
+ * - `at user["first name"]: Expected string, received undefined`
395
+ * - `Validation error` *(no path)*
396
+ *
397
+ * Path segments come either as bare `PropertyKey` values or as
398
+ * `{ key: PropertyKey }` objects (per the spec); both are normalized.
399
+ * - Numeric keys → `[N]`
400
+ * - String keys that are valid JS identifiers → bare (first) or `.key`
401
+ * - String keys that aren't valid identifiers → `["..."]` with JSON-style
402
+ * escaping (handles dots, spaces, leading digits, the empty string, the
403
+ * literal string `"0"`, embedded quotes, etc.)
404
+ * - Symbol / other `PropertyKey` → `[Symbol(name)]`
405
+ */
406
+ function formatIssue(issue) {
407
+ if (issue.path === void 0 || issue.path.length === 0) return issue.message;
408
+ let path = "";
409
+ for (let i = 0; i < issue.path.length; i++) {
410
+ const segment = issue.path[i];
411
+ const key = segment !== null && typeof segment === "object" && "key" in segment ? segment.key : segment;
412
+ if (typeof key === "number") path += `[${key}]`;
413
+ else if (typeof key === "string" && SAFE_IDENTIFIER.test(key)) path += i === 0 ? key : `.${key}`;
414
+ else if (typeof key === "string") path += `[${JSON.stringify(key)}]`;
415
+ else path += `[${String(key)}]`;
416
+ }
417
+ return `at ${path}: ${issue.message}`;
418
+ }
419
+ /**
420
+ * Join a list of validation issues into a single message, with each issue
421
+ * rendered via {@link formatIssue} so field paths surface in the error text.
422
+ */
423
+ function summarizeIssues(issues) {
424
+ return issues.map(formatIssue).join("; ");
425
+ }
426
+ //#endregion
427
+ export { defineActivity, defineContract, defineQuery, defineSearchAttribute, defineSignal, defineUpdate, defineWorkflow, formatIssue, summarizeIssues };
378
428
 
379
429
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/builder.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type {\n ActivityDefinition,\n ContractDefinition,\n QueryDefinition,\n SearchAttributeDefinition,\n SearchAttributeKind,\n SignalDefinition,\n UpdateDefinition,\n WorkflowDefinition,\n} from \"./types.js\";\n\n// Exported builders first (classic functions for hoisting)\n\n/**\n * Define a Temporal activity with type-safe input and output schemas.\n *\n * Activities are the building blocks of Temporal workflows that execute business logic\n * and interact with external services. This function preserves TypeScript types while\n * providing a consistent structure for activity definitions.\n *\n * @template TActivity - The activity definition type with input/output schemas\n * @param definition - The activity definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineActivity } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const sendEmail = defineActivity({\n * input: z.object({\n * to: z.string().email(),\n * subject: z.string(),\n * body: z.string(),\n * }),\n * output: z.object({\n * messageId: z.string(),\n * sentAt: z.date(),\n * }),\n * });\n * ```\n */\nexport function defineActivity<TActivity extends ActivityDefinition>(\n definition: TActivity,\n): TActivity {\n return definition;\n}\n\n/**\n * Define a Temporal signal with type-safe input schema.\n *\n * Signals are asynchronous messages sent to running workflows to update their state\n * or trigger certain behaviors. This function ensures type safety for signal payloads.\n *\n * @template TSignal - The signal definition type with input schema\n * @param definition - The signal definition containing input schema\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineSignal } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const approveOrder = defineSignal({\n * input: z.object({\n * orderId: z.string(),\n * approvedBy: z.string(),\n * }),\n * });\n * ```\n */\nexport function defineSignal<TSignal extends SignalDefinition>(definition: TSignal): TSignal {\n return definition;\n}\n\n/**\n * Define a Temporal query with type-safe input and output schemas.\n *\n * Queries allow you to read the current state of a running workflow without\n * modifying it. They are synchronous and should not perform any mutations.\n *\n * **Synchronous validation required.** Temporal query handlers must complete\n * synchronously, so the input and output schemas you pass here must validate\n * synchronously. In practice this rules out async refinements (e.g. Zod's\n * `.refine(async (x) => …)`). Standard Schema doesn't expose the sync/async\n * distinction at the type level, so the worker checks at runtime and throws\n * if it ever receives a `Promise` from `~standard.validate`. Use plain Zod /\n * Valibot / ArkType object schemas without async refinements.\n *\n * @template TQuery - The query definition type with input/output schemas\n * @param definition - The query definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineQuery } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const getOrderStatus = defineQuery({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({\n * status: z.enum(['pending', 'processing', 'completed', 'failed']),\n * updatedAt: z.date(),\n * }),\n * });\n * ```\n */\nexport function defineQuery<TQuery extends QueryDefinition>(definition: TQuery): TQuery {\n return definition;\n}\n\n/**\n * Define a Temporal update with type-safe input and output schemas.\n *\n * Updates are similar to signals but return a value and wait for the workflow\n * to process them before completing. They provide a synchronous way to modify\n * workflow state and get immediate feedback.\n *\n * @template TUpdate - The update definition type with input/output schemas\n * @param definition - The update definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineUpdate } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const updateOrderQuantity = defineUpdate({\n * input: z.object({\n * orderId: z.string(),\n * newQuantity: z.number().positive(),\n * }),\n * output: z.object({\n * success: z.boolean(),\n * totalPrice: z.number(),\n * }),\n * });\n * ```\n */\nexport function defineUpdate<TUpdate extends UpdateDefinition>(definition: TUpdate): TUpdate {\n return definition;\n}\n\n/**\n * Define a typed search attribute on a workflow.\n *\n * Search attributes are indexed on Temporal's visibility store and let you\n * query / filter workflow executions by domain attributes. Declaring them on\n * the contract means the client's workflow-start options and (eventually)\n * the worker's search-attribute reader are constrained to declared keys\n * with the right value types.\n *\n * @example\n * ```typescript\n * import { defineSearchAttribute } from '@temporal-contract/contract';\n *\n * defineWorkflow({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ status: z.string() }),\n * searchAttributes: {\n * customerId: defineSearchAttribute({ kind: 'KEYWORD' }),\n * priority: defineSearchAttribute({ kind: 'INT' }),\n * placedAt: defineSearchAttribute({ kind: 'DATETIME' }),\n * },\n * });\n * ```\n *\n * The seven Temporal kinds map to TypeScript types like so:\n *\n * | kind | TS type |\n * | --------------- | --------- |\n * | `TEXT` | `string` |\n * | `KEYWORD` | `string` |\n * | `INT` | `number` |\n * | `DOUBLE` | `number` |\n * | `BOOL` | `boolean` |\n * | `DATETIME` | `Date` |\n * | `KEYWORD_LIST` | `string[]`|\n */\nexport function defineSearchAttribute<TKind extends SearchAttributeKind>(\n definition: SearchAttributeDefinition<TKind>,\n): SearchAttributeDefinition<TKind> {\n return definition;\n}\n\n/**\n * Define a Temporal workflow with type-safe input, output, and associated operations.\n *\n * Workflows are durable functions that orchestrate activities, handle timeouts,\n * and manage long-running processes. This function provides type safety for the\n * entire workflow definition including activities, signals, queries, and updates.\n *\n * @template TWorkflow - The workflow definition type with all associated schemas\n * @param definition - The workflow definition containing input, output, and operations\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineWorkflow, defineActivity, defineSignal } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const processOrder = defineWorkflow({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ success: z.boolean() }),\n * activities: {\n * validatePayment: defineActivity({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ valid: z.boolean() }),\n * }),\n * },\n * signals: {\n * cancel: defineSignal({\n * input: z.object({ reason: z.string() }),\n * }),\n * },\n * });\n * ```\n */\nexport function defineWorkflow<TWorkflow extends WorkflowDefinition>(\n definition: TWorkflow,\n): TWorkflow {\n return definition;\n}\n\n/**\n * Define a complete Temporal contract with type-safe workflows and activities.\n *\n * A contract is the central definition that ties together your Temporal application's\n * workflows and activities. It provides:\n * - Type safety across client, worker, and workflow code\n * - Automatic validation at runtime\n * - Compile-time verification of implementations\n * - Clear API boundaries and documentation\n *\n * The contract validates the structure and ensures:\n * - Task queue is specified\n * - At least one workflow is defined\n * - Valid JavaScript identifiers are used\n * - No conflicts between global and workflow-specific activities\n * - All schemas implement the Standard Schema specification\n *\n * @template TContract - The contract definition type\n * @param definition - The complete contract definition\n * @returns The same definition with preserved types for type inference\n * @throws {Error} If the contract structure is invalid\n *\n * @example\n * ```typescript\n * import { defineContract } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const myContract = defineContract({\n * taskQueue: 'orders',\n * workflows: {\n * processOrder: {\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ success: z.boolean() }),\n * activities: {\n * chargePayment: {\n * input: z.object({ amount: z.number() }),\n * output: z.object({ transactionId: z.string() }),\n * },\n * },\n * },\n * },\n * // Optional global activities shared across workflows\n * activities: {\n * logEvent: {\n * input: z.object({ message: z.string() }),\n * output: z.void(),\n * },\n * },\n * });\n * ```\n */\nexport function defineContract<TContract extends ContractDefinition>(\n definition: TContract,\n): TContract {\n // Validate entire contract structure with Zod (including activity conflicts)\n const validationResult = contractValidationSchema.safeParse(definition);\n\n if (!validationResult.success) {\n const cleanMessage = getCleanErrorMessage(validationResult.error);\n throw new Error(`Contract validation failed: ${cleanMessage}`);\n }\n\n return definition;\n}\n\n/**\n * Check if a value is a Standard Schema compatible schema\n */\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n // Standard Schema can be either an object or a function (e.g., ArkType)\n if (\n (typeof value !== \"object\" && typeof value !== \"function\") ||\n value === null ||\n !(\"~standard\" in value)\n ) {\n return false;\n }\n\n const standard = (value as Record<string, unknown>)[\"~standard\"];\n\n return (\n typeof standard === \"object\" &&\n standard !== null &&\n (standard as Record<string, unknown>)[\"version\"] === 1 &&\n typeof (standard as Record<string, unknown>)[\"validate\"] === \"function\"\n );\n}\n\n/**\n * Schema for validating JavaScript identifiers (workflow names, activity names, etc.)\n * Allows: letters, digits, underscore, dollar sign\n * Must start with: letter, underscore, or dollar sign\n */\nconst identifierSchema = z\n .string()\n .min(1)\n .regex(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/, \"must be a valid JavaScript identifier\");\n\n/**\n * Extract a clean, single-line error message from a Zod validation error.\n *\n * Uses `error.issues` directly (compatible with Zod v4+) rather than parsing\n * `error.message` as JSON, which was a Zod v3 implementation detail.\n */\nfunction getCleanErrorMessage(error: z.ZodError): string {\n const issues = error.issues;\n if (!issues || issues.length === 0) {\n return error.message;\n }\n\n const firstIssue = issues[0];\n if (!firstIssue) {\n return error.message;\n }\n\n // For record key validation errors (invalid_key), surface the nested issue message\n if (\n firstIssue.code === \"invalid_key\" &&\n \"issues\" in firstIssue &&\n Array.isArray((firstIssue as { issues?: unknown[] }).issues) &&\n (firstIssue as { issues: { message?: string }[] }).issues.length > 0\n ) {\n const nestedMessage = (firstIssue as { issues: { message?: string }[] }).issues[0]?.message;\n if (nestedMessage) {\n return nestedMessage;\n }\n }\n\n return firstIssue.message ?? error.message;\n}\n\n/**\n * Schema for validating activity definitions\n * Checks that input and output are Standard Schema compatible schemas\n */\nconst activityDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating signal definitions\n */\nconst signalDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating query definitions\n */\nconst queryDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating update definitions\n */\nconst updateDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating search attribute definitions\n */\nconst searchAttributeKindSchema = z.enum([\n \"TEXT\",\n \"KEYWORD\",\n \"INT\",\n \"DOUBLE\",\n \"BOOL\",\n \"DATETIME\",\n \"KEYWORD_LIST\",\n]);\n\nconst searchAttributeDefinitionSchema = z.object({\n kind: searchAttributeKindSchema,\n});\n\n/**\n * Schema for validating workflow definitions\n */\nconst workflowDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n activities: z.record(identifierSchema, activityDefinitionSchema).optional(),\n signals: z.record(identifierSchema, signalDefinitionSchema).optional(),\n queries: z.record(identifierSchema, queryDefinitionSchema).optional(),\n updates: z.record(identifierSchema, updateDefinitionSchema).optional(),\n searchAttributes: z.record(identifierSchema, searchAttributeDefinitionSchema).optional(),\n});\n\n/**\n * Schema for validating a contract definition structure\n */\nconst contractValidationSchema = z\n .object({\n taskQueue: z.string().trim().min(1, \"taskQueue cannot be empty\"),\n workflows: z\n .record(identifierSchema, workflowDefinitionSchema)\n .refine((workflows) => Object.keys(workflows).length > 0, {\n message: \"at least one workflow is required\",\n }),\n activities: z.record(identifierSchema, activityDefinitionSchema).optional(),\n })\n .superRefine((contract, ctx) => {\n // Activities are registered in a single flat namespace at runtime, so any\n // duplicate name silently clobbers another. Catch all collisions here:\n // 1. workflow-specific vs. global, and\n // 2. workflow-specific vs. other workflow-specific.\n //\n // The global owner is tracked with a Symbol rather than a sentinel string\n // because workflow names are only validated as JS identifiers — a user\n // could legitimately name a workflow \"global\", and a string sentinel would\n // misclassify those collisions.\n const GLOBAL_OWNER: unique symbol = Symbol(\"global\");\n type Owner = string | typeof GLOBAL_OWNER;\n const owners = new Map<string, Owner>();\n\n if (contract.activities) {\n for (const activityName of Object.keys(contract.activities)) {\n owners.set(activityName, GLOBAL_OWNER);\n }\n }\n\n for (const [workflowName, workflow] of Object.entries(contract.workflows)) {\n if (!workflow.activities) {\n continue;\n }\n for (const activityName of Object.keys(workflow.activities)) {\n const previousOwner = owners.get(activityName);\n if (previousOwner === GLOBAL_OWNER) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `workflow \"${workflowName}\" has activity \"${activityName}\" that conflicts with a global activity. Consider renaming the workflow-specific activity or removing the global activity \"${activityName}\".`,\n });\n continue;\n }\n if (typeof previousOwner === \"string\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `workflow \"${workflowName}\" has activity \"${activityName}\" that conflicts with the same-named activity in workflow \"${previousOwner}\". Activities share a single flat namespace at runtime — rename one of them.`,\n });\n continue;\n }\n owners.set(activityName, workflowName);\n }\n }\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/builder.ts","../src/format.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type {\n ActivityDefinition,\n AnyWorkflowDefinition,\n ContractDefinition,\n QueryDefinition,\n SearchAttributeDefinition,\n SearchAttributeKind,\n SignalDefinition,\n UpdateDefinition,\n} from \"./types.js\";\n\n// Exported builders first (classic functions for hoisting)\n\n/**\n * Define a Temporal activity with type-safe input and output schemas.\n *\n * Activities are the building blocks of Temporal workflows that execute business logic\n * and interact with external services. This function preserves TypeScript types while\n * providing a consistent structure for activity definitions.\n *\n * @template TActivity - The activity definition type with input/output schemas\n * @param definition - The activity definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineActivity } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const sendEmail = defineActivity({\n * input: z.object({\n * to: z.string().email(),\n * subject: z.string(),\n * body: z.string(),\n * }),\n * output: z.object({\n * messageId: z.string(),\n * sentAt: z.date(),\n * }),\n * });\n * ```\n */\nexport function defineActivity<TActivity extends ActivityDefinition>(\n definition: TActivity,\n): TActivity {\n return definition;\n}\n\n/**\n * Define a Temporal signal with type-safe input schema.\n *\n * Signals are asynchronous messages sent to running workflows to update their state\n * or trigger certain behaviors. This function ensures type safety for signal payloads.\n *\n * @template TSignal - The signal definition type with input schema\n * @param definition - The signal definition containing input schema\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineSignal } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const approveOrder = defineSignal({\n * input: z.object({\n * orderId: z.string(),\n * approvedBy: z.string(),\n * }),\n * });\n * ```\n */\nexport function defineSignal<TSignal extends SignalDefinition>(definition: TSignal): TSignal {\n return definition;\n}\n\n/**\n * Define a Temporal query with type-safe input and output schemas.\n *\n * Queries allow you to read the current state of a running workflow without\n * modifying it. They are synchronous and should not perform any mutations.\n *\n * **Synchronous validation required.** Temporal query handlers must complete\n * synchronously, so the input and output schemas you pass here must validate\n * synchronously. In practice this rules out async refinements (e.g. Zod's\n * `.refine(async (x) => …)`). Standard Schema doesn't expose the sync/async\n * distinction at the type level, so the worker checks at runtime and throws\n * if it ever receives a `Promise` from `~standard.validate`. Use plain Zod /\n * Valibot / ArkType object schemas without async refinements.\n *\n * @template TQuery - The query definition type with input/output schemas\n * @param definition - The query definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineQuery } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const getOrderStatus = defineQuery({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({\n * status: z.enum(['pending', 'processing', 'completed', 'failed']),\n * updatedAt: z.date(),\n * }),\n * });\n * ```\n */\nexport function defineQuery<TQuery extends QueryDefinition>(definition: TQuery): TQuery {\n return definition;\n}\n\n/**\n * Define a Temporal update with type-safe input and output schemas.\n *\n * Updates are similar to signals but return a value and wait for the workflow\n * to process them before completing. They provide a synchronous way to modify\n * workflow state and get immediate feedback.\n *\n * @template TUpdate - The update definition type with input/output schemas\n * @param definition - The update definition containing input and output schemas\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineUpdate } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const updateOrderQuantity = defineUpdate({\n * input: z.object({\n * orderId: z.string(),\n * newQuantity: z.number().positive(),\n * }),\n * output: z.object({\n * success: z.boolean(),\n * totalPrice: z.number(),\n * }),\n * });\n * ```\n */\nexport function defineUpdate<TUpdate extends UpdateDefinition>(definition: TUpdate): TUpdate {\n return definition;\n}\n\n/**\n * Define a typed search attribute on a workflow.\n *\n * Search attributes are indexed on Temporal's visibility store and let you\n * query / filter workflow executions by domain attributes. Declaring them on\n * the contract means the client's workflow-start options and (eventually)\n * the worker's search-attribute reader are constrained to declared keys\n * with the right value types.\n *\n * @example\n * ```typescript\n * import { defineSearchAttribute } from '@temporal-contract/contract';\n *\n * defineWorkflow({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ status: z.string() }),\n * searchAttributes: {\n * customerId: defineSearchAttribute({ kind: 'KEYWORD' }),\n * priority: defineSearchAttribute({ kind: 'INT' }),\n * placedAt: defineSearchAttribute({ kind: 'DATETIME' }),\n * },\n * });\n * ```\n *\n * The seven Temporal kinds map to TypeScript types like so:\n *\n * | kind | TS type |\n * | --------------- | --------- |\n * | `TEXT` | `string` |\n * | `KEYWORD` | `string` |\n * | `INT` | `number` |\n * | `DOUBLE` | `number` |\n * | `BOOL` | `boolean` |\n * | `DATETIME` | `Date` |\n * | `KEYWORD_LIST` | `string[]`|\n */\nexport function defineSearchAttribute<TKind extends SearchAttributeKind>(\n definition: SearchAttributeDefinition<TKind>,\n): SearchAttributeDefinition<TKind> {\n return definition;\n}\n\n/**\n * Define a Temporal workflow with type-safe input, output, and associated operations.\n *\n * Workflows are durable functions that orchestrate activities, handle timeouts,\n * and manage long-running processes. This function provides type safety for the\n * entire workflow definition including activities, signals, queries, and updates.\n *\n * @template TWorkflow - The workflow definition type with all associated schemas\n * @param definition - The workflow definition containing input, output, and operations\n * @returns The same definition with preserved types for type inference\n *\n * @example\n * ```typescript\n * import { defineWorkflow, defineActivity, defineSignal } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const processOrder = defineWorkflow({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ success: z.boolean() }),\n * activities: {\n * validatePayment: defineActivity({\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ valid: z.boolean() }),\n * }),\n * },\n * signals: {\n * cancel: defineSignal({\n * input: z.object({ reason: z.string() }),\n * }),\n * },\n * });\n * ```\n */\nexport function defineWorkflow<TWorkflow extends AnyWorkflowDefinition>(\n definition: TWorkflow,\n): TWorkflow {\n return definition;\n}\n\n/**\n * Define a complete Temporal contract with type-safe workflows and activities.\n *\n * A contract is the central definition that ties together your Temporal application's\n * workflows and activities. It provides:\n * - Type safety across client, worker, and workflow code\n * - Automatic validation at runtime\n * - Compile-time verification of implementations\n * - Clear API boundaries and documentation\n *\n * The contract validates the structure and ensures:\n * - Task queue is specified\n * - At least one workflow is defined\n * - Valid JavaScript identifiers are used\n * - No conflicts between global and workflow-specific activities\n * - All schemas implement the Standard Schema specification\n *\n * @template TContract - The contract definition type\n * @param definition - The complete contract definition\n * @returns The same definition with preserved types for type inference\n * @throws {Error} If the contract structure is invalid\n *\n * @example\n * ```typescript\n * import { defineContract } from '@temporal-contract/contract';\n * import { z } from 'zod';\n *\n * export const myContract = defineContract({\n * taskQueue: 'orders',\n * workflows: {\n * processOrder: {\n * input: z.object({ orderId: z.string() }),\n * output: z.object({ success: z.boolean() }),\n * activities: {\n * chargePayment: {\n * input: z.object({ amount: z.number() }),\n * output: z.object({ transactionId: z.string() }),\n * },\n * },\n * },\n * },\n * // Optional global activities shared across workflows\n * activities: {\n * logEvent: {\n * input: z.object({ message: z.string() }),\n * output: z.void(),\n * },\n * },\n * });\n * ```\n */\nexport function defineContract<TContract extends ContractDefinition>(\n definition: TContract,\n): TContract {\n // Validate entire contract structure with Zod (including activity conflicts)\n const validationResult = contractValidationSchema.safeParse(definition);\n\n if (!validationResult.success) {\n const cleanMessage = getCleanErrorMessage(validationResult.error);\n throw new Error(`Contract validation failed: ${cleanMessage}`);\n }\n\n return definition;\n}\n\n/**\n * Check if a value is a Standard Schema compatible schema\n */\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n // Standard Schema can be either an object or a function (e.g., ArkType)\n if (\n (typeof value !== \"object\" && typeof value !== \"function\") ||\n value === null ||\n !(\"~standard\" in value)\n ) {\n return false;\n }\n\n const standard = (value as Record<string, unknown>)[\"~standard\"];\n\n return (\n typeof standard === \"object\" &&\n standard !== null &&\n (standard as Record<string, unknown>)[\"version\"] === 1 &&\n typeof (standard as Record<string, unknown>)[\"validate\"] === \"function\"\n );\n}\n\n/**\n * Schema for validating JavaScript identifiers (workflow names, activity names, etc.)\n * Allows: letters, digits, underscore, dollar sign\n * Must start with: letter, underscore, or dollar sign\n */\nconst identifierSchema = z\n .string()\n .min(1)\n .regex(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/, \"must be a valid JavaScript identifier\");\n\n/**\n * Extract a clean, single-line error message from a Zod validation error.\n *\n * Uses `error.issues` directly (compatible with Zod v4+) rather than parsing\n * `error.message` as JSON, which was a Zod v3 implementation detail.\n */\nfunction getCleanErrorMessage(error: z.ZodError): string {\n const issues = error.issues;\n if (!issues || issues.length === 0) {\n return error.message;\n }\n\n const firstIssue = issues[0];\n if (!firstIssue) {\n return error.message;\n }\n\n // For record key validation errors (invalid_key), surface the nested issue message\n if (\n firstIssue.code === \"invalid_key\" &&\n \"issues\" in firstIssue &&\n Array.isArray((firstIssue as { issues?: unknown[] }).issues) &&\n (firstIssue as { issues: { message?: string }[] }).issues.length > 0\n ) {\n const nestedMessage = (firstIssue as { issues: { message?: string }[] }).issues[0]?.message;\n if (nestedMessage) {\n return nestedMessage;\n }\n }\n\n return firstIssue.message ?? error.message;\n}\n\n/**\n * Schema for validating activity definitions\n * Checks that input and output are Standard Schema compatible schemas\n */\nconst activityDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating signal definitions\n */\nconst signalDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating query definitions\n */\nconst queryDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating update definitions\n */\nconst updateDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n});\n\n/**\n * Schema for validating search attribute definitions\n */\nconst searchAttributeKindSchema = z.enum([\n \"TEXT\",\n \"KEYWORD\",\n \"INT\",\n \"DOUBLE\",\n \"BOOL\",\n \"DATETIME\",\n \"KEYWORD_LIST\",\n]);\n\nconst searchAttributeDefinitionSchema = z.object({\n kind: searchAttributeKindSchema,\n});\n\n/**\n * Schema for validating workflow definitions\n */\nconst workflowDefinitionSchema = z.object({\n input: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"input must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n output: z.custom<StandardSchemaV1>((val) => isStandardSchema(val), {\n message: \"output must be a Standard Schema compatible schema (e.g., Zod, Valibot, ArkType)\",\n }),\n activities: z.record(identifierSchema, activityDefinitionSchema).optional(),\n signals: z.record(identifierSchema, signalDefinitionSchema).optional(),\n queries: z.record(identifierSchema, queryDefinitionSchema).optional(),\n updates: z.record(identifierSchema, updateDefinitionSchema).optional(),\n searchAttributes: z.record(identifierSchema, searchAttributeDefinitionSchema).optional(),\n});\n\n/**\n * Schema for validating a contract definition structure\n */\nconst contractValidationSchema = z\n .object({\n taskQueue: z.string().trim().min(1, \"taskQueue cannot be empty\"),\n workflows: z\n .record(identifierSchema, workflowDefinitionSchema)\n .refine((workflows) => Object.keys(workflows).length > 0, {\n message: \"at least one workflow is required\",\n }),\n activities: z.record(identifierSchema, activityDefinitionSchema).optional(),\n })\n .superRefine((contract, ctx) => {\n // Activities are registered in a single flat namespace at runtime, so any\n // duplicate name silently clobbers another. Catch all collisions here:\n // 1. workflow-specific vs. global, and\n // 2. workflow-specific vs. other workflow-specific.\n //\n // The global owner is tracked with a Symbol rather than a sentinel string\n // because workflow names are only validated as JS identifiers — a user\n // could legitimately name a workflow \"global\", and a string sentinel would\n // misclassify those collisions.\n const GLOBAL_OWNER: unique symbol = Symbol(\"global\");\n type Owner = string | typeof GLOBAL_OWNER;\n const owners = new Map<string, Owner>();\n\n if (contract.activities) {\n for (const activityName of Object.keys(contract.activities)) {\n owners.set(activityName, GLOBAL_OWNER);\n }\n }\n\n for (const [workflowName, workflow] of Object.entries(contract.workflows)) {\n if (!workflow.activities) {\n continue;\n }\n for (const activityName of Object.keys(workflow.activities)) {\n const previousOwner = owners.get(activityName);\n if (previousOwner === GLOBAL_OWNER) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `workflow \"${workflowName}\" has activity \"${activityName}\" that conflicts with a global activity. Consider renaming the workflow-specific activity or removing the global activity \"${activityName}\".`,\n });\n continue;\n }\n if (typeof previousOwner === \"string\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `workflow \"${workflowName}\" has activity \"${activityName}\" that conflicts with the same-named activity in workflow \"${previousOwner}\". Activities share a single flat namespace at runtime — rename one of them.`,\n });\n continue;\n }\n owners.set(activityName, workflowName);\n }\n }\n });\n","/**\n * Standard Schema issue / validation-message formatters.\n *\n * Exposed from the contract package so client and worker share a single\n * source of truth for diagnostic rendering. Both used to carry their own\n * byte-identical copies and a comment promising the maintainers would\n * keep them in sync — that promise lives here now.\n */\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Pattern for string keys safe to render with dot notation. A \"safe\" key is a\n * JavaScript identifier (letters/digits/underscore/$, not starting with a\n * digit). Anything else — keys containing dots, spaces, leading digits, the\n * empty string, the literal string `\"0\"` etc. — gets bracket-quoted so the\n * path is unambiguous. Reserved words are accepted: we are formatting a\n * diagnostic, not generating runnable code.\n */\nconst SAFE_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * Render a Standard Schema {@link StandardSchemaV1.Issue} into a human-readable\n * string that includes the failing field's path.\n *\n * Example output:\n * - `at items[0].quantity: Expected number, received undefined`\n * - `at customerId: Expected string, received undefined`\n * - `at user[\"first name\"]: Expected string, received undefined`\n * - `Validation error` *(no path)*\n *\n * Path segments come either as bare `PropertyKey` values or as\n * `{ key: PropertyKey }` objects (per the spec); both are normalized.\n * - Numeric keys → `[N]`\n * - String keys that are valid JS identifiers → bare (first) or `.key`\n * - String keys that aren't valid identifiers → `[\"...\"]` with JSON-style\n * escaping (handles dots, spaces, leading digits, the empty string, the\n * literal string `\"0\"`, embedded quotes, etc.)\n * - Symbol / other `PropertyKey` → `[Symbol(name)]`\n */\nexport function formatIssue(issue: StandardSchemaV1.Issue): string {\n if (issue.path === undefined || issue.path.length === 0) {\n return issue.message;\n }\n let path = \"\";\n for (let i = 0; i < issue.path.length; i++) {\n const segment = issue.path[i];\n const key =\n segment !== null && typeof segment === \"object\" && \"key\" in segment ? segment.key : segment;\n if (typeof key === \"number\") {\n path += `[${key}]`;\n } else if (typeof key === \"string\" && SAFE_IDENTIFIER.test(key)) {\n path += i === 0 ? key : `.${key}`;\n } else if (typeof key === \"string\") {\n path += `[${JSON.stringify(key)}]`;\n } else {\n path += `[${String(key)}]`;\n }\n }\n return `at ${path}: ${issue.message}`;\n}\n\n/**\n * Join a list of validation issues into a single message, with each issue\n * rendered via {@link formatIssue} so field paths surface in the error text.\n */\nexport function summarizeIssues(issues: ReadonlyArray<StandardSchemaV1.Issue>): string {\n return issues.map(formatIssue).join(\"; \");\n}\n"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let neverthrow = require("neverthrow");
3
+ //#region src/result-async.ts
4
+ /**
5
+ * Internal helper shared across `@temporal-contract/client` and
6
+ * `@temporal-contract/worker` for wrapping a result-producing async function
7
+ * in a `ResultAsync` while routing any unhandled rejection through a typed
8
+ * mapper.
9
+ *
10
+ * Lives in `@temporal-contract/contract` so the two consuming packages don't
11
+ * each carry their own copy. Exported from the package's public surface
12
+ * under a deliberately-internal-looking name (`_internal_makeResultAsync`)
13
+ * so users don't import it by accident — there is no semver guarantee on
14
+ * this entry point.
15
+ */
16
+ /**
17
+ * Wrap an async function returning `Promise<Result<T, E>>` in a
18
+ * `ResultAsync<T, E>`, catching synchronous throws and rejected promises
19
+ * and routing them through `mapRejection` so they surface as typed
20
+ * `err(...)` instead of unhandled rejections.
21
+ *
22
+ * `new ResultAsync(promise)` does **not** catch rejections — the resulting
23
+ * `ResultAsync` rejects, escaping neverthrow's railway. This helper closes
24
+ * that gap. The work function is expected to handle its own domain errors
25
+ * and return `err(...)` for them; `mapRejection` is a safety net for
26
+ * thrown exceptions the work didn't anticipate.
27
+ *
28
+ * @internal — exported under `_internal_makeResultAsync` for use by the
29
+ * sibling client and worker packages. Not part of the public API.
30
+ */
31
+ function _internal_makeResultAsync(work, mapRejection) {
32
+ let promise;
33
+ try {
34
+ promise = work();
35
+ } catch (error) {
36
+ promise = Promise.resolve((0, neverthrow.err)(mapRejection(error)));
37
+ }
38
+ return new neverthrow.ResultAsync(promise.catch((e) => (0, neverthrow.err)(mapRejection(e))));
39
+ }
40
+ //#endregion
41
+ exports._internal_makeResultAsync = _internal_makeResultAsync;
@@ -0,0 +1,22 @@
1
+ import { Result, ResultAsync } from "neverthrow";
2
+
3
+ //#region src/result-async.d.ts
4
+ /**
5
+ * Wrap an async function returning `Promise<Result<T, E>>` in a
6
+ * `ResultAsync<T, E>`, catching synchronous throws and rejected promises
7
+ * and routing them through `mapRejection` so they surface as typed
8
+ * `err(...)` instead of unhandled rejections.
9
+ *
10
+ * `new ResultAsync(promise)` does **not** catch rejections — the resulting
11
+ * `ResultAsync` rejects, escaping neverthrow's railway. This helper closes
12
+ * that gap. The work function is expected to handle its own domain errors
13
+ * and return `err(...)` for them; `mapRejection` is a safety net for
14
+ * thrown exceptions the work didn't anticipate.
15
+ *
16
+ * @internal — exported under `_internal_makeResultAsync` for use by the
17
+ * sibling client and worker packages. Not part of the public API.
18
+ */
19
+ declare function _internal_makeResultAsync<T, E>(work: () => Promise<Result<T, E>>, mapRejection: (error: unknown) => E): ResultAsync<T, E>;
20
+ //#endregion
21
+ export { _internal_makeResultAsync };
22
+ //# sourceMappingURL=result-async.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-async.d.cts","names":[],"sources":["../src/result-async.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA6BgB,yBAAA,MAAA,CACd,IAAA,QAAY,OAAA,CAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAC9B,YAAA,GAAe,KAAA,cAAmB,CAAA,GACjC,WAAA,CAAY,CAAA,EAAG,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { Result, ResultAsync } from "neverthrow";
2
+
3
+ //#region src/result-async.d.ts
4
+ /**
5
+ * Wrap an async function returning `Promise<Result<T, E>>` in a
6
+ * `ResultAsync<T, E>`, catching synchronous throws and rejected promises
7
+ * and routing them through `mapRejection` so they surface as typed
8
+ * `err(...)` instead of unhandled rejections.
9
+ *
10
+ * `new ResultAsync(promise)` does **not** catch rejections — the resulting
11
+ * `ResultAsync` rejects, escaping neverthrow's railway. This helper closes
12
+ * that gap. The work function is expected to handle its own domain errors
13
+ * and return `err(...)` for them; `mapRejection` is a safety net for
14
+ * thrown exceptions the work didn't anticipate.
15
+ *
16
+ * @internal — exported under `_internal_makeResultAsync` for use by the
17
+ * sibling client and worker packages. Not part of the public API.
18
+ */
19
+ declare function _internal_makeResultAsync<T, E>(work: () => Promise<Result<T, E>>, mapRejection: (error: unknown) => E): ResultAsync<T, E>;
20
+ //#endregion
21
+ export { _internal_makeResultAsync };
22
+ //# sourceMappingURL=result-async.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-async.d.mts","names":[],"sources":["../src/result-async.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA6BgB,yBAAA,MAAA,CACd,IAAA,QAAY,OAAA,CAAQ,MAAA,CAAO,CAAA,EAAG,CAAA,IAC9B,YAAA,GAAe,KAAA,cAAmB,CAAA,GACjC,WAAA,CAAY,CAAA,EAAG,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { ResultAsync, err } from "neverthrow";
2
+ //#region src/result-async.ts
3
+ /**
4
+ * Internal helper shared across `@temporal-contract/client` and
5
+ * `@temporal-contract/worker` for wrapping a result-producing async function
6
+ * in a `ResultAsync` while routing any unhandled rejection through a typed
7
+ * mapper.
8
+ *
9
+ * Lives in `@temporal-contract/contract` so the two consuming packages don't
10
+ * each carry their own copy. Exported from the package's public surface
11
+ * under a deliberately-internal-looking name (`_internal_makeResultAsync`)
12
+ * so users don't import it by accident — there is no semver guarantee on
13
+ * this entry point.
14
+ */
15
+ /**
16
+ * Wrap an async function returning `Promise<Result<T, E>>` in a
17
+ * `ResultAsync<T, E>`, catching synchronous throws and rejected promises
18
+ * and routing them through `mapRejection` so they surface as typed
19
+ * `err(...)` instead of unhandled rejections.
20
+ *
21
+ * `new ResultAsync(promise)` does **not** catch rejections — the resulting
22
+ * `ResultAsync` rejects, escaping neverthrow's railway. This helper closes
23
+ * that gap. The work function is expected to handle its own domain errors
24
+ * and return `err(...)` for them; `mapRejection` is a safety net for
25
+ * thrown exceptions the work didn't anticipate.
26
+ *
27
+ * @internal — exported under `_internal_makeResultAsync` for use by the
28
+ * sibling client and worker packages. Not part of the public API.
29
+ */
30
+ function _internal_makeResultAsync(work, mapRejection) {
31
+ let promise;
32
+ try {
33
+ promise = work();
34
+ } catch (error) {
35
+ promise = Promise.resolve(err(mapRejection(error)));
36
+ }
37
+ return new ResultAsync(promise.catch((e) => err(mapRejection(e))));
38
+ }
39
+ //#endregion
40
+ export { _internal_makeResultAsync };
41
+
42
+ //# sourceMappingURL=result-async.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-async.mjs","names":[],"sources":["../src/result-async.ts"],"sourcesContent":["/**\n * Internal helper shared across `@temporal-contract/client` and\n * `@temporal-contract/worker` for wrapping a result-producing async function\n * in a `ResultAsync` while routing any unhandled rejection through a typed\n * mapper.\n *\n * Lives in `@temporal-contract/contract` so the two consuming packages don't\n * each carry their own copy. Exported from the package's public surface\n * under a deliberately-internal-looking name (`_internal_makeResultAsync`)\n * so users don't import it by accident — there is no semver guarantee on\n * this entry point.\n */\nimport { ResultAsync, type Result, err } from \"neverthrow\";\n\n/**\n * Wrap an async function returning `Promise<Result<T, E>>` in a\n * `ResultAsync<T, E>`, catching synchronous throws and rejected promises\n * and routing them through `mapRejection` so they surface as typed\n * `err(...)` instead of unhandled rejections.\n *\n * `new ResultAsync(promise)` does **not** catch rejections — the resulting\n * `ResultAsync` rejects, escaping neverthrow's railway. This helper closes\n * that gap. The work function is expected to handle its own domain errors\n * and return `err(...)` for them; `mapRejection` is a safety net for\n * thrown exceptions the work didn't anticipate.\n *\n * @internal — exported under `_internal_makeResultAsync` for use by the\n * sibling client and worker packages. Not part of the public API.\n */\nexport function _internal_makeResultAsync<T, E>(\n work: () => Promise<Result<T, E>>,\n mapRejection: (error: unknown) => E,\n): ResultAsync<T, E> {\n let promise: Promise<Result<T, E>>;\n try {\n promise = work();\n } catch (error) {\n // Synchronous throw before the function returned its promise. Without\n // this branch, `work()` blowing up synchronously would surface as a\n // thrown error from the constructor call rather than an `err(...)`.\n promise = Promise.resolve(err(mapRejection(error)));\n }\n return new ResultAsync<T, E>(promise.catch((e: unknown) => err(mapRejection(e))));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,0BACd,MACA,cACmB;CACnB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM;UACT,OAAO;AAId,YAAU,QAAQ,QAAQ,IAAI,aAAa,MAAM,CAAC,CAAC;;AAErD,QAAO,IAAI,YAAkB,QAAQ,OAAO,MAAe,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporal-contract/contract",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Contract builder for temporal-contract",
5
5
  "keywords": [
6
6
  "contract",
@@ -36,6 +36,16 @@
36
36
  "default": "./dist/index.cjs"
37
37
  }
38
38
  },
39
+ "./result-async": {
40
+ "import": {
41
+ "types": "./dist/result-async.d.mts",
42
+ "default": "./dist/result-async.mjs"
43
+ },
44
+ "require": {
45
+ "types": "./dist/result-async.d.cts",
46
+ "default": "./dist/result-async.cjs"
47
+ }
48
+ },
39
49
  "./package.json": "./package.json"
40
50
  },
41
51
  "dependencies": {
@@ -45,19 +55,28 @@
45
55
  "devDependencies": {
46
56
  "@vitest/coverage-v8": "4.1.5",
47
57
  "arktype": "2.2.0",
58
+ "neverthrow": "8.2.0",
48
59
  "tsdown": "0.21.10",
49
60
  "typedoc": "0.28.19",
50
61
  "typedoc-plugin-markdown": "4.11.0",
51
62
  "typescript": "6.0.3",
52
63
  "valibot": "1.3.1",
53
64
  "vitest": "4.1.5",
54
- "@temporal-contract/tsconfig": "1.0.0",
55
- "@temporal-contract/typedoc": "0.1.0"
65
+ "@temporal-contract/typedoc": "0.1.0",
66
+ "@temporal-contract/tsconfig": "1.0.0"
67
+ },
68
+ "peerDependencies": {
69
+ "neverthrow": "^8"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "neverthrow": {
73
+ "optional": true
74
+ }
56
75
  },
57
76
  "scripts": {
58
- "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
77
+ "build": "tsdown src/index.ts src/result-async.ts --format cjs,esm --dts --clean",
59
78
  "build:docs": "typedoc",
60
- "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
79
+ "dev": "tsdown src/index.ts src/result-async.ts --format cjs,esm --dts --watch",
61
80
  "test": "vitest run",
62
81
  "test:watch": "vitest",
63
82
  "typecheck": "tsc --noEmit"