@temporal-contract/client 1.0.0 → 2.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.cjs +87 -91
- package/dist/index.d.cts +60 -60
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +60 -60
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +87 -91
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -12
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypedSearchAttributes, WorkflowNotFoundError as WorkflowNotFoundError$1, defineSearchAttributeKey } from "@temporalio/common";
|
|
2
|
-
import {
|
|
2
|
+
import { ResultAsync, err, ok } from "neverthrow";
|
|
3
3
|
import { WorkflowExecutionAlreadyStartedError, WorkflowFailedError as WorkflowFailedError$1 } from "@temporalio/client";
|
|
4
4
|
//#region src/errors.ts
|
|
5
5
|
/**
|
|
@@ -191,21 +191,19 @@ var UpdateValidationError = class extends TypedClientError {
|
|
|
191
191
|
* In-package modules and tests import it directly via relative path.
|
|
192
192
|
*/
|
|
193
193
|
/**
|
|
194
|
-
* Wrap an async result-producing function in a `
|
|
194
|
+
* Wrap an async result-producing function in a `ResultAsync`, catching any
|
|
195
195
|
* unhandled rejection as a `RuntimeClientError("unexpected", error)`.
|
|
196
196
|
*
|
|
197
197
|
* The work function is expected to handle its own domain errors and return
|
|
198
|
-
*
|
|
199
|
-
*
|
|
198
|
+
* an `err(...)` for them; the catch here is a safety net for thrown
|
|
199
|
+
* exceptions the work didn't anticipate.
|
|
200
200
|
*
|
|
201
201
|
* Used by `client.ts` (workflow operations) and `schedule.ts` (schedule
|
|
202
202
|
* operations) so the unexpected-rejection shape is identical across the
|
|
203
203
|
* typed client surface.
|
|
204
204
|
*/
|
|
205
|
-
function
|
|
206
|
-
return
|
|
207
|
-
work().then(resolve).catch((e) => resolve(Result.Error(new RuntimeClientError("unexpected", e))));
|
|
208
|
-
});
|
|
205
|
+
function makeResultAsync(work) {
|
|
206
|
+
return new ResultAsync(work().catch((e) => err(new RuntimeClientError("unexpected", e))));
|
|
209
207
|
}
|
|
210
208
|
/**
|
|
211
209
|
* Map a thrown error from `client.workflow.start` / `signalWithStart` into
|
|
@@ -274,9 +272,9 @@ var TypedScheduleClient = class {
|
|
|
274
272
|
create(workflowName, options) {
|
|
275
273
|
const work = async () => {
|
|
276
274
|
const definition = this.contract.workflows[workflowName];
|
|
277
|
-
if (!definition) return
|
|
275
|
+
if (!definition) return err(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows)));
|
|
278
276
|
const inputResult = await definition.input["~standard"].validate(options.args);
|
|
279
|
-
if (inputResult.issues) return
|
|
277
|
+
if (inputResult.issues) return err(new WorkflowValidationError(String(workflowName), "input", inputResult.issues));
|
|
280
278
|
try {
|
|
281
279
|
const overrides = options.action ?? {};
|
|
282
280
|
const action = {
|
|
@@ -293,20 +291,19 @@ var TypedScheduleClient = class {
|
|
|
293
291
|
...overrides.staticDetails !== void 0 ? { staticDetails: overrides.staticDetails } : {},
|
|
294
292
|
...overrides.staticSummary !== void 0 ? { staticSummary: overrides.staticSummary } : {}
|
|
295
293
|
};
|
|
296
|
-
|
|
294
|
+
return ok(wrapScheduleHandle(await this.scheduleClient.create({
|
|
297
295
|
scheduleId: options.scheduleId,
|
|
298
296
|
spec: options.spec,
|
|
299
297
|
action,
|
|
300
298
|
...options.policies !== void 0 ? { policies: options.policies } : {},
|
|
301
299
|
...options.state !== void 0 ? { state: options.state } : {},
|
|
302
300
|
...options.memo !== void 0 ? { memo: options.memo } : {}
|
|
303
|
-
});
|
|
304
|
-
return Result.Ok(wrapScheduleHandle(handle));
|
|
301
|
+
})));
|
|
305
302
|
} catch (error) {
|
|
306
|
-
return
|
|
303
|
+
return err(new RuntimeClientError("schedule.create", error));
|
|
307
304
|
}
|
|
308
305
|
};
|
|
309
|
-
return
|
|
306
|
+
return makeResultAsync(work);
|
|
310
307
|
}
|
|
311
308
|
/**
|
|
312
309
|
* Get a typed handle to an existing schedule. Does not validate that the
|
|
@@ -320,11 +317,11 @@ var TypedScheduleClient = class {
|
|
|
320
317
|
function wrapScheduleHandle(handle) {
|
|
321
318
|
return {
|
|
322
319
|
scheduleId: handle.scheduleId,
|
|
323
|
-
pause: (note) =>
|
|
324
|
-
unpause: (note) =>
|
|
325
|
-
trigger: (overlap) =>
|
|
326
|
-
delete: () =>
|
|
327
|
-
describe: () =>
|
|
320
|
+
pause: (note) => ResultAsync.fromPromise(handle.pause(note), (error) => new RuntimeClientError("schedule.pause", error)).map(() => void 0),
|
|
321
|
+
unpause: (note) => ResultAsync.fromPromise(handle.unpause(note), (error) => new RuntimeClientError("schedule.unpause", error)).map(() => void 0),
|
|
322
|
+
trigger: (overlap) => ResultAsync.fromPromise(handle.trigger(overlap), (error) => new RuntimeClientError("schedule.trigger", error)).map(() => void 0),
|
|
323
|
+
delete: () => ResultAsync.fromPromise(handle.delete(), (error) => new RuntimeClientError("schedule.delete", error)).map(() => void 0),
|
|
324
|
+
describe: () => ResultAsync.fromPromise(handle.describe(), (error) => new RuntimeClientError("schedule.describe", error))
|
|
328
325
|
};
|
|
329
326
|
}
|
|
330
327
|
//#endregion
|
|
@@ -354,7 +351,7 @@ function toTypedSearchAttributes(workflowDef, values) {
|
|
|
354
351
|
return pairs.length > 0 ? new TypedSearchAttributes(pairs) : void 0;
|
|
355
352
|
}
|
|
356
353
|
/**
|
|
357
|
-
* Typed Temporal client with Result/
|
|
354
|
+
* Typed Temporal client with neverthrow Result/ResultAsync pattern based on a contract
|
|
358
355
|
*
|
|
359
356
|
* Provides type-safe methods to start and execute workflows
|
|
360
357
|
* defined in the contract, with explicit error handling using Result pattern.
|
|
@@ -378,10 +375,10 @@ var TypedClient = class TypedClient {
|
|
|
378
375
|
* args: { orderId: "sweep" },
|
|
379
376
|
* });
|
|
380
377
|
*
|
|
381
|
-
* result.match(
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
378
|
+
* result.match(
|
|
379
|
+
* async (handle) => { await handle.pause("maintenance"); },
|
|
380
|
+
* (error) => console.error("schedule create failed", error),
|
|
381
|
+
* );
|
|
385
382
|
* ```
|
|
386
383
|
*/
|
|
387
384
|
schedule;
|
|
@@ -392,7 +389,7 @@ var TypedClient = class TypedClient {
|
|
|
392
389
|
this.schedule = new TypedScheduleClient(contract, client.schedule);
|
|
393
390
|
}
|
|
394
391
|
/**
|
|
395
|
-
* Create a typed Temporal client with
|
|
392
|
+
* Create a typed Temporal client with neverthrow pattern from a contract
|
|
396
393
|
*
|
|
397
394
|
* @example
|
|
398
395
|
* ```ts
|
|
@@ -405,17 +402,17 @@ var TypedClient = class TypedClient {
|
|
|
405
402
|
* args: { ... },
|
|
406
403
|
* });
|
|
407
404
|
*
|
|
408
|
-
* result.match(
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
405
|
+
* result.match(
|
|
406
|
+
* (output) => console.log('Success:', output),
|
|
407
|
+
* (error) => console.error('Failed:', error),
|
|
408
|
+
* );
|
|
412
409
|
* ```
|
|
413
410
|
*/
|
|
414
411
|
static create(contract, client) {
|
|
415
412
|
return new TypedClient(contract, client);
|
|
416
413
|
}
|
|
417
414
|
/**
|
|
418
|
-
* Start a workflow and return a typed handle with
|
|
415
|
+
* Start a workflow and return a typed handle with ResultAsync pattern
|
|
419
416
|
*
|
|
420
417
|
* @example
|
|
421
418
|
* ```ts
|
|
@@ -426,21 +423,21 @@ var TypedClient = class TypedClient {
|
|
|
426
423
|
* retry: { maximumAttempts: 3 },
|
|
427
424
|
* });
|
|
428
425
|
*
|
|
429
|
-
* handleResult.match(
|
|
430
|
-
*
|
|
426
|
+
* handleResult.match(
|
|
427
|
+
* async (handle) => {
|
|
431
428
|
* const result = await handle.result();
|
|
432
429
|
* // ... handle result
|
|
433
430
|
* },
|
|
434
|
-
*
|
|
435
|
-
*
|
|
431
|
+
* (error) => console.error('Failed to start:', error),
|
|
432
|
+
* );
|
|
436
433
|
* ```
|
|
437
434
|
*/
|
|
438
435
|
startWorkflow(workflowName, { args, searchAttributes, ...temporalOptions }) {
|
|
439
436
|
const work = async () => {
|
|
440
437
|
const definition = this.contract.workflows[workflowName];
|
|
441
|
-
if (!definition) return
|
|
438
|
+
if (!definition) return err(createWorkflowNotFoundError(workflowName, this.contract));
|
|
442
439
|
const inputResult = await definition.input["~standard"].validate(args);
|
|
443
|
-
if (inputResult.issues) return
|
|
440
|
+
if (inputResult.issues) return err(createWorkflowValidationError(workflowName, "input", inputResult.issues));
|
|
444
441
|
const typedSearchAttributes = toTypedSearchAttributes(definition, searchAttributes);
|
|
445
442
|
try {
|
|
446
443
|
const handle = await this.client.workflow.start(workflowName, {
|
|
@@ -449,12 +446,12 @@ var TypedClient = class TypedClient {
|
|
|
449
446
|
args: [inputResult.value],
|
|
450
447
|
...typedSearchAttributes ? { typedSearchAttributes } : {}
|
|
451
448
|
});
|
|
452
|
-
return
|
|
449
|
+
return ok(this.createTypedHandle(handle, definition));
|
|
453
450
|
} catch (error) {
|
|
454
|
-
return
|
|
451
|
+
return err(classifyStartError("startWorkflow", error));
|
|
455
452
|
}
|
|
456
453
|
};
|
|
457
|
-
return
|
|
454
|
+
return makeResultAsync(work);
|
|
458
455
|
}
|
|
459
456
|
/**
|
|
460
457
|
* Send a signal to a workflow, starting it first if it doesn't already exist.
|
|
@@ -476,22 +473,22 @@ var TypedClient = class TypedClient {
|
|
|
476
473
|
* signalArgs: { reason: 'duplicate' },
|
|
477
474
|
* });
|
|
478
475
|
*
|
|
479
|
-
* result.match(
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
476
|
+
* result.match(
|
|
477
|
+
* (handle) => console.log('signaled run', handle.signaledRunId),
|
|
478
|
+
* (error) => console.error('signalWithStart failed', error),
|
|
479
|
+
* );
|
|
483
480
|
* ```
|
|
484
481
|
*/
|
|
485
482
|
signalWithStart(workflowName, { args, signalName, signalArgs, searchAttributes, ...temporalOptions }) {
|
|
486
483
|
const work = async () => {
|
|
487
484
|
const definition = this.contract.workflows[workflowName];
|
|
488
|
-
if (!definition) return
|
|
485
|
+
if (!definition) return err(createWorkflowNotFoundError(workflowName, this.contract));
|
|
489
486
|
const inputResult = await definition.input["~standard"].validate(args);
|
|
490
|
-
if (inputResult.issues) return
|
|
487
|
+
if (inputResult.issues) return err(createWorkflowValidationError(workflowName, "input", inputResult.issues));
|
|
491
488
|
const signalDef = definition.signals?.[signalName];
|
|
492
|
-
if (!signalDef) return
|
|
489
|
+
if (!signalDef) return err(new SignalValidationError(signalName, [{ message: `Signal "${signalName}" is not declared on workflow "${String(workflowName)}".` }]));
|
|
493
490
|
const signalInputResult = await signalDef.input["~standard"].validate(signalArgs);
|
|
494
|
-
if (signalInputResult.issues) return
|
|
491
|
+
if (signalInputResult.issues) return err(new SignalValidationError(signalName, signalInputResult.issues));
|
|
495
492
|
const typedSearchAttributes = toTypedSearchAttributes(definition, searchAttributes);
|
|
496
493
|
try {
|
|
497
494
|
const handle = await this.client.workflow.signalWithStart(workflowName, {
|
|
@@ -502,19 +499,18 @@ var TypedClient = class TypedClient {
|
|
|
502
499
|
signalArgs: [signalInputResult.value],
|
|
503
500
|
...typedSearchAttributes ? { typedSearchAttributes } : {}
|
|
504
501
|
});
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
...typed,
|
|
502
|
+
return ok({
|
|
503
|
+
...this.createTypedHandle(handle, definition),
|
|
508
504
|
signaledRunId: handle.signaledRunId
|
|
509
505
|
});
|
|
510
506
|
} catch (error) {
|
|
511
|
-
return
|
|
507
|
+
return err(classifyStartError("signalWithStart", error));
|
|
512
508
|
}
|
|
513
509
|
};
|
|
514
|
-
return
|
|
510
|
+
return makeResultAsync(work);
|
|
515
511
|
}
|
|
516
512
|
/**
|
|
517
|
-
* Execute a workflow (start and wait for result) with
|
|
513
|
+
* Execute a workflow (start and wait for result) with ResultAsync pattern
|
|
518
514
|
*
|
|
519
515
|
* @example
|
|
520
516
|
* ```ts
|
|
@@ -525,18 +521,18 @@ var TypedClient = class TypedClient {
|
|
|
525
521
|
* retry: { maximumAttempts: 3 },
|
|
526
522
|
* });
|
|
527
523
|
*
|
|
528
|
-
* result.match(
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
524
|
+
* result.match(
|
|
525
|
+
* (output) => console.log('Order processed:', output.status),
|
|
526
|
+
* (error) => console.error('Processing failed:', error),
|
|
527
|
+
* );
|
|
532
528
|
* ```
|
|
533
529
|
*/
|
|
534
530
|
executeWorkflow(workflowName, { args, searchAttributes, ...temporalOptions }) {
|
|
535
531
|
const work = async () => {
|
|
536
532
|
const definition = this.contract.workflows[workflowName];
|
|
537
|
-
if (!definition) return
|
|
533
|
+
if (!definition) return err(createWorkflowNotFoundError(workflowName, this.contract));
|
|
538
534
|
const inputResult = await definition.input["~standard"].validate(args);
|
|
539
|
-
if (inputResult.issues) return
|
|
535
|
+
if (inputResult.issues) return err(createWorkflowValidationError(workflowName, "input", inputResult.issues));
|
|
540
536
|
const typedSearchAttributes = toTypedSearchAttributes(definition, searchAttributes);
|
|
541
537
|
try {
|
|
542
538
|
const result = await this.client.workflow.execute(workflowName, {
|
|
@@ -546,44 +542,44 @@ var TypedClient = class TypedClient {
|
|
|
546
542
|
...typedSearchAttributes ? { typedSearchAttributes } : {}
|
|
547
543
|
});
|
|
548
544
|
const outputResult = await definition.output["~standard"].validate(result);
|
|
549
|
-
if (outputResult.issues) return
|
|
550
|
-
return
|
|
545
|
+
if (outputResult.issues) return err(createWorkflowValidationError(workflowName, "output", outputResult.issues));
|
|
546
|
+
return ok(outputResult.value);
|
|
551
547
|
} catch (error) {
|
|
552
|
-
if (error instanceof WorkflowExecutionAlreadyStartedError) return
|
|
553
|
-
if (error instanceof WorkflowFailedError$1) return
|
|
554
|
-
if (error instanceof WorkflowNotFoundError$1) return
|
|
555
|
-
return
|
|
548
|
+
if (error instanceof WorkflowExecutionAlreadyStartedError) return err(new WorkflowAlreadyStartedError(error.workflowType, error.workflowId, error));
|
|
549
|
+
if (error instanceof WorkflowFailedError$1) return err(new WorkflowFailedError(temporalOptions.workflowId, error.cause));
|
|
550
|
+
if (error instanceof WorkflowNotFoundError$1) return err(new WorkflowExecutionNotFoundError(error.workflowId || temporalOptions.workflowId, error.runId, error));
|
|
551
|
+
return err(createRuntimeClientError("executeWorkflow", error));
|
|
556
552
|
}
|
|
557
553
|
};
|
|
558
|
-
return
|
|
554
|
+
return makeResultAsync(work);
|
|
559
555
|
}
|
|
560
556
|
/**
|
|
561
|
-
* Get a handle to an existing workflow with
|
|
557
|
+
* Get a handle to an existing workflow with ResultAsync pattern
|
|
562
558
|
*
|
|
563
559
|
* @example
|
|
564
560
|
* ```ts
|
|
565
561
|
* const handleResult = await client.getHandle('processOrder', 'order-123');
|
|
566
|
-
* handleResult.match(
|
|
567
|
-
*
|
|
562
|
+
* handleResult.match(
|
|
563
|
+
* async (handle) => {
|
|
568
564
|
* const result = await handle.result();
|
|
569
565
|
* // ... handle result
|
|
570
566
|
* },
|
|
571
|
-
*
|
|
572
|
-
*
|
|
567
|
+
* (error) => console.error('Failed to get handle:', error),
|
|
568
|
+
* );
|
|
573
569
|
* ```
|
|
574
570
|
*/
|
|
575
571
|
getHandle(workflowName, workflowId) {
|
|
576
572
|
const work = async () => {
|
|
577
573
|
const definition = this.contract.workflows[workflowName];
|
|
578
|
-
if (!definition) return
|
|
574
|
+
if (!definition) return err(createWorkflowNotFoundError(workflowName, this.contract));
|
|
579
575
|
try {
|
|
580
576
|
const handle = this.client.workflow.getHandle(workflowId);
|
|
581
|
-
return
|
|
577
|
+
return ok(this.createTypedHandle(handle, definition));
|
|
582
578
|
} catch (error) {
|
|
583
|
-
return
|
|
579
|
+
return err(createRuntimeClientError("getHandle", error));
|
|
584
580
|
}
|
|
585
581
|
};
|
|
586
|
-
return
|
|
582
|
+
return makeResultAsync(work);
|
|
587
583
|
}
|
|
588
584
|
createTypedHandle(workflowHandle, definition) {
|
|
589
585
|
const queries = buildValidatedProxy({
|
|
@@ -622,18 +618,18 @@ var TypedClient = class TypedClient {
|
|
|
622
618
|
try {
|
|
623
619
|
const result = await workflowHandle.result();
|
|
624
620
|
const outputResult = await definition.output["~standard"].validate(result);
|
|
625
|
-
if (outputResult.issues) return
|
|
626
|
-
return
|
|
621
|
+
if (outputResult.issues) return err(new WorkflowValidationError(workflowHandle.workflowId, "output", outputResult.issues));
|
|
622
|
+
return ok(outputResult.value);
|
|
627
623
|
} catch (error) {
|
|
628
|
-
return
|
|
624
|
+
return err(classifyResultError("result", error, workflowHandle.workflowId));
|
|
629
625
|
}
|
|
630
626
|
};
|
|
631
|
-
return
|
|
627
|
+
return makeResultAsync(work);
|
|
632
628
|
},
|
|
633
|
-
terminate: (reason) =>
|
|
634
|
-
cancel: () =>
|
|
635
|
-
describe: () =>
|
|
636
|
-
fetchHistory: () =>
|
|
629
|
+
terminate: (reason) => ResultAsync.fromPromise(workflowHandle.terminate(reason), (error) => classifyHandleError("terminate", error, workflowHandle.workflowId)).map(() => void 0),
|
|
630
|
+
cancel: () => ResultAsync.fromPromise(workflowHandle.cancel(), (error) => classifyHandleError("cancel", error, workflowHandle.workflowId)).map(() => void 0),
|
|
631
|
+
describe: () => ResultAsync.fromPromise(workflowHandle.describe(), (error) => classifyHandleError("describe", error, workflowHandle.workflowId)),
|
|
632
|
+
fetchHistory: () => ResultAsync.fromPromise(workflowHandle.fetchHistory(), (error) => classifyHandleError("fetchHistory", error, workflowHandle.workflowId))
|
|
637
633
|
};
|
|
638
634
|
}
|
|
639
635
|
};
|
|
@@ -647,7 +643,7 @@ function createWorkflowValidationError(workflowName, direction, issues) {
|
|
|
647
643
|
return new WorkflowValidationError(String(workflowName), direction, issues);
|
|
648
644
|
}
|
|
649
645
|
/**
|
|
650
|
-
* Build a `{ name: (args) =>
|
|
646
|
+
* Build a `{ name: (args) => ResultAsync<...> }` proxy for a contract's
|
|
651
647
|
* queries/signals/updates. The three call sites differ only in how they
|
|
652
648
|
* invoke Temporal and whether they validate output, so the shared
|
|
653
649
|
* input-validate → invoke → output-validate → wrap-Result pipeline lives
|
|
@@ -659,19 +655,19 @@ function buildValidatedProxy({ defs, operation, workflowId, makeValidationError,
|
|
|
659
655
|
for (const [name, def] of Object.entries(defs)) proxy[name] = (args) => {
|
|
660
656
|
const work = async () => {
|
|
661
657
|
const inputResult = await def.input["~standard"].validate(args);
|
|
662
|
-
if (inputResult.issues) return
|
|
658
|
+
if (inputResult.issues) return err(makeValidationError(name, "input", inputResult.issues));
|
|
663
659
|
try {
|
|
664
660
|
const result = await invoke(name, inputResult.value);
|
|
665
661
|
const outputSchema = validateOutput(def);
|
|
666
|
-
if (!outputSchema) return
|
|
662
|
+
if (!outputSchema) return ok(result);
|
|
667
663
|
const outputResult = await outputSchema["~standard"].validate(result);
|
|
668
|
-
if (outputResult.issues) return
|
|
669
|
-
return
|
|
664
|
+
if (outputResult.issues) return err(makeValidationError(name, "output", outputResult.issues));
|
|
665
|
+
return ok(outputResult.value);
|
|
670
666
|
} catch (error) {
|
|
671
|
-
return
|
|
667
|
+
return err(classifyHandleError(operation, error, workflowId));
|
|
672
668
|
}
|
|
673
669
|
};
|
|
674
|
-
return
|
|
670
|
+
return makeResultAsync(work);
|
|
675
671
|
};
|
|
676
672
|
return proxy;
|
|
677
673
|
}
|