@temporal-contract/client 2.4.0 → 3.0.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.mjs CHANGED
@@ -1,41 +1,31 @@
1
1
  import { TypedSearchAttributes, WorkflowNotFoundError as WorkflowNotFoundError$1, defineSearchAttributeKey } from "@temporalio/common";
2
- import { ResultAsync, err, ok } from "neverthrow";
2
+ import { TaggedError, err, fromPromise, ok } from "unthrown";
3
3
  import { summarizeIssues } from "@temporal-contract/contract";
4
4
  import { WorkflowExecutionAlreadyStartedError, WorkflowFailedError as WorkflowFailedError$1 } from "@temporalio/client";
5
- import { _internal_makeResultAsync } from "@temporal-contract/contract/result-async";
5
+ import { _internal_assertNoDefect as assertNoDefect, _internal_makeAsyncResult } from "@temporal-contract/contract/result-async";
6
6
  //#region src/errors.ts
7
7
  /**
8
- * Base class for all typed client errors.
9
- */
10
- var TypedClientError = class extends Error {
11
- constructor(message) {
12
- super(message);
13
- this.name = this.constructor.name;
14
- if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
15
- }
16
- };
17
- /**
18
8
  * Generic runtime failure wrapper when no specific error type applies
19
9
  */
20
- var RuntimeClientError = class extends TypedClientError {
21
- operation;
22
- cause;
10
+ var RuntimeClientError = class extends TaggedError("@temporal-contract/RuntimeClientError", { name: "RuntimeClientError" }) {
23
11
  constructor(operation, cause) {
24
- super(`Operation "${operation}" failed: ${cause instanceof Error ? cause.message : String(cause ?? "unknown error")}`);
25
- this.operation = operation;
26
- this.cause = cause;
12
+ super({
13
+ operation,
14
+ cause,
15
+ message: `Operation "${operation}" failed: ${cause instanceof Error ? cause.message : String(cause ?? "unknown error")}`
16
+ });
27
17
  }
28
18
  };
29
19
  /**
30
20
  * Thrown when a workflow is not found in the contract
31
21
  */
32
- var WorkflowNotFoundError = class extends TypedClientError {
33
- workflowName;
34
- availableWorkflows;
22
+ var WorkflowNotFoundError = class extends TaggedError("@temporal-contract/WorkflowNotFoundError", { name: "WorkflowNotFoundError" }) {
35
23
  constructor(workflowName, availableWorkflows) {
36
- super(`Workflow "${workflowName}" not found in contract. Available workflows: ${availableWorkflows.join(", ")}`);
37
- this.workflowName = workflowName;
38
- this.availableWorkflows = availableWorkflows;
24
+ super({
25
+ workflowName,
26
+ availableWorkflows,
27
+ message: `Workflow "${workflowName}" not found in contract. Available workflows: ${availableWorkflows.join(", ")}`
28
+ });
39
29
  }
40
30
  };
41
31
  /**
@@ -49,15 +39,14 @@ var WorkflowNotFoundError = class extends TypedClientError {
49
39
  * branch on it explicitly (e.g. fetch the existing handle and continue)
50
40
  * without inspecting `error.cause` against a Temporal SDK class.
51
41
  */
52
- var WorkflowAlreadyStartedError = class extends TypedClientError {
53
- workflowType;
54
- workflowId;
55
- cause;
42
+ var WorkflowAlreadyStartedError = class extends TaggedError("@temporal-contract/WorkflowAlreadyStartedError", { name: "WorkflowAlreadyStartedError" }) {
56
43
  constructor(workflowType, workflowId, cause) {
57
- super(`Workflow "${workflowType}" with ID "${workflowId}" is already started or in retention.`);
58
- this.workflowType = workflowType;
59
- this.workflowId = workflowId;
60
- this.cause = cause;
44
+ super({
45
+ workflowType,
46
+ workflowId,
47
+ cause,
48
+ message: `Workflow "${workflowType}" with ID "${workflowId}" is already started or in retention.`
49
+ });
61
50
  }
62
51
  };
63
52
  /**
@@ -72,15 +61,14 @@ var WorkflowAlreadyStartedError = class extends TypedClientError {
72
61
  * - `executeWorkflow` (when the underlying execute call hits a missing
73
62
  * execution mid-flight)
74
63
  */
75
- var WorkflowExecutionNotFoundError = class extends TypedClientError {
76
- workflowId;
77
- runId;
78
- cause;
64
+ var WorkflowExecutionNotFoundError = class extends TaggedError("@temporal-contract/WorkflowExecutionNotFoundError", { name: "WorkflowExecutionNotFoundError" }) {
79
65
  constructor(workflowId, runId, cause) {
80
- super(`Workflow execution "${workflowId}"${runId ? ` (run "${runId}")` : ""} not found in namespace.`);
81
- this.workflowId = workflowId;
82
- this.runId = runId;
83
- this.cause = cause;
66
+ super({
67
+ workflowId,
68
+ runId,
69
+ cause,
70
+ message: `Workflow execution "${workflowId}"${runId ? ` (run "${runId}")` : ""} not found in namespace.`
71
+ });
84
72
  }
85
73
  };
86
74
  /**
@@ -102,68 +90,65 @@ var WorkflowExecutionNotFoundError = class extends TypedClientError {
102
90
  *
103
91
  * Returned from `executeWorkflow` and `handle.result()`.
104
92
  */
105
- var WorkflowFailedError = class extends TypedClientError {
106
- workflowId;
107
- cause;
93
+ var WorkflowFailedError = class extends TaggedError("@temporal-contract/WorkflowFailedError", { name: "WorkflowFailedError" }) {
108
94
  constructor(workflowId, cause) {
109
95
  const causeMessage = cause instanceof Error ? cause.message : String(cause ?? "unknown failure");
110
- super(`Workflow "${workflowId}" completed with failure: ${causeMessage}`);
111
- this.workflowId = workflowId;
112
- this.cause = cause;
96
+ super({
97
+ workflowId,
98
+ cause,
99
+ message: `Workflow "${workflowId}" completed with failure: ${causeMessage}`
100
+ });
113
101
  }
114
102
  };
115
103
  /**
116
104
  * Thrown when workflow input or output validation fails
117
105
  */
118
- var WorkflowValidationError = class extends TypedClientError {
119
- workflowName;
120
- direction;
121
- issues;
106
+ var WorkflowValidationError = class extends TaggedError("@temporal-contract/WorkflowValidationError", { name: "WorkflowValidationError" }) {
122
107
  constructor(workflowName, direction, issues) {
123
- super(`Validation failed for workflow "${workflowName}" ${direction}: ${summarizeIssues(issues)}`);
124
- this.workflowName = workflowName;
125
- this.direction = direction;
126
- this.issues = issues;
108
+ super({
109
+ workflowName,
110
+ direction,
111
+ issues,
112
+ message: `Validation failed for workflow "${workflowName}" ${direction}: ${summarizeIssues(issues)}`
113
+ });
127
114
  }
128
115
  };
129
116
  /**
130
117
  * Thrown when query input or output validation fails
131
118
  */
132
- var QueryValidationError = class extends TypedClientError {
133
- queryName;
134
- direction;
135
- issues;
119
+ var QueryValidationError = class extends TaggedError("@temporal-contract/QueryValidationError", { name: "QueryValidationError" }) {
136
120
  constructor(queryName, direction, issues) {
137
- super(`Validation failed for query "${queryName}" ${direction}: ${summarizeIssues(issues)}`);
138
- this.queryName = queryName;
139
- this.direction = direction;
140
- this.issues = issues;
121
+ super({
122
+ queryName,
123
+ direction,
124
+ issues,
125
+ message: `Validation failed for query "${queryName}" ${direction}: ${summarizeIssues(issues)}`
126
+ });
141
127
  }
142
128
  };
143
129
  /**
144
130
  * Thrown when signal input validation fails
145
131
  */
146
- var SignalValidationError = class extends TypedClientError {
147
- signalName;
148
- issues;
132
+ var SignalValidationError = class extends TaggedError("@temporal-contract/SignalValidationError", { name: "SignalValidationError" }) {
149
133
  constructor(signalName, issues) {
150
- super(`Validation failed for signal "${signalName}": ${summarizeIssues(issues)}`);
151
- this.signalName = signalName;
152
- this.issues = issues;
134
+ super({
135
+ signalName,
136
+ issues,
137
+ message: `Validation failed for signal "${signalName}": ${summarizeIssues(issues)}`
138
+ });
153
139
  }
154
140
  };
155
141
  /**
156
142
  * Thrown when update input or output validation fails
157
143
  */
158
- var UpdateValidationError = class extends TypedClientError {
159
- updateName;
160
- direction;
161
- issues;
144
+ var UpdateValidationError = class extends TaggedError("@temporal-contract/UpdateValidationError", { name: "UpdateValidationError" }) {
162
145
  constructor(updateName, direction, issues) {
163
- super(`Validation failed for update "${updateName}" ${direction}: ${summarizeIssues(issues)}`);
164
- this.updateName = updateName;
165
- this.direction = direction;
166
- this.issues = issues;
146
+ super({
147
+ updateName,
148
+ direction,
149
+ issues,
150
+ message: `Validation failed for update "${updateName}" ${direction}: ${summarizeIssues(issues)}`
151
+ });
167
152
  }
168
153
  };
169
154
  //#endregion
@@ -207,21 +192,23 @@ function toTypedSearchAttributes(workflowDef, workflowName, values) {
207
192
  return ok(pairs.length > 0 ? new TypedSearchAttributes(pairs) : void 0);
208
193
  }
209
194
  /**
210
- * Wrap an async result-producing function in a `ResultAsync`, catching any
211
- * unhandled rejection as a `RuntimeClientError("unexpected", error)`.
195
+ * Wrap an async result-producing function in an `AsyncResult`, routing any
196
+ * unanticipated rejection through unthrown's `defect` channel.
212
197
  *
213
198
  * The work function is expected to handle its own domain errors and return
214
- * an `err(...)` for them; the catch here is a safety net for thrown
215
- * exceptions the work didn't anticipate.
199
+ * an `err(...)` for them; a thrown exception the work didn't anticipate is an
200
+ * *unmodeled* failure and surfaces as a defect (inspectable via
201
+ * `result.isDefect()` / `result.cause`, re-thrown at the edge) rather than a
202
+ * manufactured `RuntimeClientError`.
216
203
  *
217
204
  * Used by `client.ts` (workflow operations) and `schedule.ts` (schedule
218
205
  * operations) so the unexpected-rejection shape is identical across the
219
- * typed client surface. Delegates to `_internal_makeResultAsync` from
206
+ * typed client surface. Delegates to `_internal_makeAsyncResult` from
220
207
  * `@temporal-contract/contract` so the same wrapper is shared between the
221
208
  * client and worker packages.
222
209
  */
223
- function makeResultAsync(work) {
224
- return _internal_makeResultAsync(work, (e) => new RuntimeClientError("unexpected", e));
210
+ function makeAsyncResult(work) {
211
+ return _internal_makeAsyncResult(work);
225
212
  }
226
213
  /**
227
214
  * Map a thrown error from `client.workflow.start` / `signalWithStart` into
@@ -296,6 +283,7 @@ var TypedScheduleClient = class {
296
283
  const inputResult = await definition.input["~standard"].validate(options.args);
297
284
  if (inputResult.issues) return err(new WorkflowValidationError(workflowName, "input", inputResult.issues));
298
285
  const searchAttributesResult = toTypedSearchAttributes(definition, workflowName, options.searchAttributes);
286
+ assertNoDefect(searchAttributesResult);
299
287
  if (searchAttributesResult.isErr()) return err(searchAttributesResult.error);
300
288
  const typedSearchAttributes = searchAttributesResult.value;
301
289
  try {
@@ -327,7 +315,7 @@ var TypedScheduleClient = class {
327
315
  return err(new RuntimeClientError("schedule.create", error));
328
316
  }
329
317
  };
330
- return makeResultAsync(work);
318
+ return makeAsyncResult(work);
331
319
  }
332
320
  /**
333
321
  * Get a typed handle to an existing schedule. Does not validate that the
@@ -341,11 +329,11 @@ var TypedScheduleClient = class {
341
329
  function wrapScheduleHandle(handle) {
342
330
  return {
343
331
  scheduleId: handle.scheduleId,
344
- pause: (note) => ResultAsync.fromPromise(handle.pause(note), (error) => new RuntimeClientError("schedule.pause", error)).map(() => void 0),
345
- unpause: (note) => ResultAsync.fromPromise(handle.unpause(note), (error) => new RuntimeClientError("schedule.unpause", error)).map(() => void 0),
346
- trigger: (overlap) => ResultAsync.fromPromise(handle.trigger(overlap), (error) => new RuntimeClientError("schedule.trigger", error)).map(() => void 0),
347
- delete: () => ResultAsync.fromPromise(handle.delete(), (error) => new RuntimeClientError("schedule.delete", error)).map(() => void 0),
348
- describe: () => ResultAsync.fromPromise(handle.describe(), (error) => new RuntimeClientError("schedule.describe", error))
332
+ pause: (note) => fromPromise(handle.pause(note), (error) => new RuntimeClientError("schedule.pause", error)).map(() => void 0),
333
+ unpause: (note) => fromPromise(handle.unpause(note), (error) => new RuntimeClientError("schedule.unpause", error)).map(() => void 0),
334
+ trigger: (overlap) => fromPromise(handle.trigger(overlap), (error) => new RuntimeClientError("schedule.trigger", error)).map(() => void 0),
335
+ delete: () => fromPromise(handle.delete(), (error) => new RuntimeClientError("schedule.delete", error)).map(() => void 0),
336
+ describe: () => fromPromise(handle.describe(), (error) => new RuntimeClientError("schedule.describe", error))
349
337
  };
350
338
  }
351
339
  //#endregion
@@ -414,6 +402,7 @@ async function resolveDefinitionAndValidateInput(contract, workflowName, args, s
414
402
  const inputResult = await definition.input["~standard"].validate(args);
415
403
  if (inputResult.issues) return err(createWorkflowValidationError(workflowName, "input", inputResult.issues));
416
404
  const searchAttributesResult = toTypedSearchAttributes(definition, workflowName, searchAttributes);
405
+ assertNoDefect(searchAttributesResult);
417
406
  if (searchAttributesResult.isErr()) return err(searchAttributesResult.error);
418
407
  const typedSearchAttributes = searchAttributesResult.value;
419
408
  return ok({
@@ -423,7 +412,7 @@ async function resolveDefinitionAndValidateInput(contract, workflowName, args, s
423
412
  });
424
413
  }
425
414
  /**
426
- * Typed Temporal client with neverthrow Result/ResultAsync pattern based on a contract
415
+ * Typed Temporal client with unthrown Result/AsyncResult pattern based on a contract
427
416
  *
428
417
  * Provides type-safe methods to start and execute workflows
429
418
  * defined in the contract, with explicit error handling using Result pattern.
@@ -451,10 +440,11 @@ var TypedClient = class TypedClient {
451
440
  * args: { orderId: "sweep" },
452
441
  * });
453
442
  *
454
- * result.match(
455
- * async (handle) => { await handle.pause("maintenance"); },
456
- * (error) => console.error("schedule create failed", error),
457
- * );
443
+ * await result.match({
444
+ * ok: async (handle) => { await handle.pause("maintenance"); },
445
+ * err: (error) => console.error("schedule create failed", error),
446
+ * defect: (cause) => console.error("unexpected failure", cause),
447
+ * });
458
448
  * ```
459
449
  */
460
450
  schedule;
@@ -465,7 +455,7 @@ var TypedClient = class TypedClient {
465
455
  this.schedule = new TypedScheduleClient(contract, client.schedule);
466
456
  }
467
457
  /**
468
- * Create a typed Temporal client with neverthrow pattern from a contract
458
+ * Create a typed Temporal client with unthrown pattern from a contract
469
459
  *
470
460
  * @example
471
461
  * ```ts
@@ -478,17 +468,18 @@ var TypedClient = class TypedClient {
478
468
  * args: { ... },
479
469
  * });
480
470
  *
481
- * result.match(
482
- * (output) => console.log('Success:', output),
483
- * (error) => console.error('Failed:', error),
484
- * );
471
+ * await result.match({
472
+ * ok: (output) => console.log('Success:', output),
473
+ * err: (error) => console.error('Failed:', error),
474
+ * defect: (cause) => console.error('Unexpected failure:', cause),
475
+ * });
485
476
  * ```
486
477
  */
487
478
  static create(contract, client) {
488
479
  return new TypedClient(contract, client);
489
480
  }
490
481
  /**
491
- * Start a workflow and return a typed handle with ResultAsync pattern
482
+ * Start a workflow and return a typed handle with AsyncResult pattern
492
483
  *
493
484
  * @example
494
485
  * ```ts
@@ -499,18 +490,20 @@ var TypedClient = class TypedClient {
499
490
  * retry: { maximumAttempts: 3 },
500
491
  * });
501
492
  *
502
- * handleResult.match(
503
- * async (handle) => {
493
+ * await handleResult.match({
494
+ * ok: async (handle) => {
504
495
  * const result = await handle.result();
505
496
  * // ... handle result
506
497
  * },
507
- * (error) => console.error('Failed to start:', error),
508
- * );
498
+ * err: (error) => console.error('Failed to start:', error),
499
+ * defect: (cause) => console.error('Unexpected failure:', cause),
500
+ * });
509
501
  * ```
510
502
  */
511
503
  startWorkflow(workflowName, { args, searchAttributes, ...temporalOptions }) {
512
504
  const work = async () => {
513
505
  const resolved = await resolveDefinitionAndValidateInput(this.contract, workflowName, args, searchAttributes);
506
+ assertNoDefect(resolved);
514
507
  if (resolved.isErr()) return err(resolved.error);
515
508
  const { definition, validatedInput, typedSearchAttributes } = resolved.value;
516
509
  try {
@@ -525,7 +518,7 @@ var TypedClient = class TypedClient {
525
518
  return err(classifyStartError("startWorkflow", error));
526
519
  }
527
520
  };
528
- return makeResultAsync(work);
521
+ return makeAsyncResult(work);
529
522
  }
530
523
  /**
531
524
  * Send a signal to a workflow, starting it first if it doesn't already exist.
@@ -547,15 +540,17 @@ var TypedClient = class TypedClient {
547
540
  * signalArgs: { reason: 'duplicate' },
548
541
  * });
549
542
  *
550
- * result.match(
551
- * (handle) => console.log('signaled run', handle.signaledRunId),
552
- * (error) => console.error('signalWithStart failed', error),
553
- * );
543
+ * await result.match({
544
+ * ok: (handle) => console.log('signaled run', handle.signaledRunId),
545
+ * err: (error) => console.error('signalWithStart failed', error),
546
+ * defect: (cause) => console.error('unexpected failure', cause),
547
+ * });
554
548
  * ```
555
549
  */
556
550
  signalWithStart(workflowName, { args, signalName, signalArgs, searchAttributes, ...temporalOptions }) {
557
551
  const work = async () => {
558
552
  const resolved = await resolveDefinitionAndValidateInput(this.contract, workflowName, args, searchAttributes);
553
+ assertNoDefect(resolved);
559
554
  if (resolved.isErr()) return err(resolved.error);
560
555
  const { definition, validatedInput, typedSearchAttributes } = resolved.value;
561
556
  const signalDef = definition.signals?.[signalName];
@@ -579,10 +574,10 @@ var TypedClient = class TypedClient {
579
574
  return err(classifyStartError("signalWithStart", error));
580
575
  }
581
576
  };
582
- return makeResultAsync(work);
577
+ return makeAsyncResult(work);
583
578
  }
584
579
  /**
585
- * Execute a workflow (start and wait for result) with ResultAsync pattern
580
+ * Execute a workflow (start and wait for result) with AsyncResult pattern
586
581
  *
587
582
  * @example
588
583
  * ```ts
@@ -593,15 +588,17 @@ var TypedClient = class TypedClient {
593
588
  * retry: { maximumAttempts: 3 },
594
589
  * });
595
590
  *
596
- * result.match(
597
- * (output) => console.log('Order processed:', output.status),
598
- * (error) => console.error('Processing failed:', error),
599
- * );
591
+ * await result.match({
592
+ * ok: (output) => console.log('Order processed:', output.status),
593
+ * err: (error) => console.error('Processing failed:', error),
594
+ * defect: (cause) => console.error('Unexpected failure:', cause),
595
+ * });
600
596
  * ```
601
597
  */
602
598
  executeWorkflow(workflowName, { args, searchAttributes, ...temporalOptions }) {
603
599
  const work = async () => {
604
600
  const resolved = await resolveDefinitionAndValidateInput(this.contract, workflowName, args, searchAttributes);
601
+ assertNoDefect(resolved);
605
602
  if (resolved.isErr()) return err(resolved.error);
606
603
  const { definition, validatedInput, typedSearchAttributes } = resolved.value;
607
604
  try {
@@ -621,10 +618,10 @@ var TypedClient = class TypedClient {
621
618
  return err(createRuntimeClientError("executeWorkflow", error));
622
619
  }
623
620
  };
624
- return makeResultAsync(work);
621
+ return makeAsyncResult(work);
625
622
  }
626
623
  /**
627
- * Get a handle to an existing workflow with ResultAsync pattern
624
+ * Get a handle to an existing workflow with AsyncResult pattern
628
625
  *
629
626
  * @example
630
627
  * ```ts
@@ -649,7 +646,7 @@ var TypedClient = class TypedClient {
649
646
  return err(createRuntimeClientError("getHandle", error));
650
647
  }
651
648
  };
652
- return makeResultAsync(work);
649
+ return makeAsyncResult(work);
653
650
  }
654
651
  createTypedHandle(workflowHandle, definition) {
655
652
  const queries = buildValidatedProxy({
@@ -694,12 +691,12 @@ var TypedClient = class TypedClient {
694
691
  return err(classifyResultError("result", error, workflowHandle.workflowId));
695
692
  }
696
693
  };
697
- return makeResultAsync(work);
694
+ return makeAsyncResult(work);
698
695
  },
699
- terminate: (reason) => ResultAsync.fromPromise(workflowHandle.terminate(reason), (error) => classifyHandleError("terminate", error, workflowHandle.workflowId)).map(() => void 0),
700
- cancel: () => ResultAsync.fromPromise(workflowHandle.cancel(), (error) => classifyHandleError("cancel", error, workflowHandle.workflowId)).map(() => void 0),
701
- describe: () => ResultAsync.fromPromise(workflowHandle.describe(), (error) => classifyHandleError("describe", error, workflowHandle.workflowId)),
702
- fetchHistory: () => ResultAsync.fromPromise(workflowHandle.fetchHistory(), (error) => classifyHandleError("fetchHistory", error, workflowHandle.workflowId))
696
+ terminate: (reason) => fromPromise(workflowHandle.terminate(reason), (error) => classifyHandleError("terminate", error, workflowHandle.workflowId)).map(() => void 0),
697
+ cancel: () => fromPromise(workflowHandle.cancel(), (error) => classifyHandleError("cancel", error, workflowHandle.workflowId)).map(() => void 0),
698
+ describe: () => fromPromise(workflowHandle.describe(), (error) => classifyHandleError("describe", error, workflowHandle.workflowId)),
699
+ fetchHistory: () => fromPromise(workflowHandle.fetchHistory(), (error) => classifyHandleError("fetchHistory", error, workflowHandle.workflowId))
703
700
  };
704
701
  }
705
702
  };
@@ -713,7 +710,7 @@ function createWorkflowValidationError(workflowName, direction, issues) {
713
710
  return new WorkflowValidationError(String(workflowName), direction, issues);
714
711
  }
715
712
  /**
716
- * Build a `{ name: (args) => ResultAsync<...> }` proxy for a contract's
713
+ * Build a `{ name: (args) => AsyncResult<...> }` proxy for a contract's
717
714
  * queries/signals/updates. The three call sites differ only in how they
718
715
  * invoke Temporal and whether they validate output, so the shared
719
716
  * input-validate → invoke → output-validate → wrap-Result pipeline lives
@@ -737,7 +734,7 @@ function buildValidatedProxy({ defs, operation, workflowId, makeValidationError,
737
734
  return err(classifyHandleError(operation, error, workflowId));
738
735
  }
739
736
  };
740
- return makeResultAsync(work);
737
+ return makeAsyncResult(work);
741
738
  };
742
739
  return proxy;
743
740
  }