@temporal-contract/client 0.0.4 → 0.0.6

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
@@ -1,5 +1,4 @@
1
- let __temporalio_client = require("@temporalio/client");
2
- let __swan_io_boxed = require("@swan-io/boxed");
1
+ let _temporal_contract_boxed = require("@temporal-contract/boxed");
3
2
 
4
3
  //#region src/errors.ts
5
4
  /**
@@ -13,6 +12,16 @@ var TypedClientError = class extends Error {
13
12
  }
14
13
  };
15
14
  /**
15
+ * Generic runtime failure wrapper when no specific error type applies
16
+ */
17
+ var RuntimeClientError = class extends TypedClientError {
18
+ constructor(operation, cause) {
19
+ super(`Operation "${operation}" failed: ${cause instanceof Error ? cause.message : String(cause ?? "unknown error")}`);
20
+ this.operation = operation;
21
+ this.cause = cause;
22
+ }
23
+ };
24
+ /**
16
25
  * Thrown when a workflow is not found in the contract
17
26
  */
18
27
  var WorkflowNotFoundError = class extends TypedClientError {
@@ -93,7 +102,7 @@ var TypedClient = class TypedClient {
93
102
  * const result = await client.executeWorkflow('processOrder', {
94
103
  * workflowId: 'order-123',
95
104
  * args: { ... },
96
- * }).toPromise();
105
+ * });
97
106
  *
98
107
  * result.match({
99
108
  * Ok: (output) => console.log('Success:', output),
@@ -101,8 +110,8 @@ var TypedClient = class TypedClient {
101
110
  * });
102
111
  * ```
103
112
  */
104
- static create(contract, options) {
105
- return new TypedClient(contract, new __temporalio_client.Client(options));
113
+ static create(contract, client) {
114
+ return new TypedClient(contract, client);
106
115
  }
107
116
  /**
108
117
  * Start a workflow and return a typed handle with Future pattern
@@ -114,11 +123,11 @@ var TypedClient = class TypedClient {
114
123
  * args: { orderId: 'ORD-123' },
115
124
  * workflowExecutionTimeout: '1 day',
116
125
  * retry: { maximumAttempts: 3 },
117
- * }).toPromise();
126
+ * });
118
127
  *
119
128
  * handleResult.match({
120
129
  * Ok: async (handle) => {
121
- * const result = await handle.result().toPromise();
130
+ * const result = await handle.result();
122
131
  * // ... handle result
123
132
  * },
124
133
  * Error: (error) => console.error('Failed to start:', error),
@@ -126,16 +135,16 @@ var TypedClient = class TypedClient {
126
135
  * ```
127
136
  */
128
137
  startWorkflow(workflowName, { args, ...temporalOptions }) {
129
- return __swan_io_boxed.Future.make((resolve) => {
130
- const definition = this.contract.workflows[workflowName];
131
- if (!definition) {
132
- resolve(__swan_io_boxed.Result.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
133
- return;
134
- }
138
+ return _temporal_contract_boxed.Future.make((resolve) => {
135
139
  (async () => {
140
+ const definition = this.contract.workflows[workflowName];
141
+ if (!definition) {
142
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
143
+ return;
144
+ }
136
145
  const inputResult = await definition.input["~standard"].validate(args);
137
146
  if (inputResult.issues) {
138
- resolve(__swan_io_boxed.Result.Error(new WorkflowValidationError(String(workflowName), "input", inputResult.issues)));
147
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowValidationError(workflowName, "input", inputResult.issues)));
139
148
  return;
140
149
  }
141
150
  const validatedInput = inputResult.value;
@@ -146,9 +155,9 @@ var TypedClient = class TypedClient {
146
155
  args: [validatedInput]
147
156
  });
148
157
  const typedHandle = this.createTypedHandle(handle, definition);
149
- resolve(__swan_io_boxed.Result.Ok(typedHandle));
158
+ resolve(_temporal_contract_boxed.Result.Ok(typedHandle));
150
159
  } catch (error) {
151
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Failed to start workflow: ${error instanceof Error ? error.message : String(error)}`)));
160
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("startWorkflow", error)));
152
161
  }
153
162
  })();
154
163
  });
@@ -163,7 +172,7 @@ var TypedClient = class TypedClient {
163
172
  * args: { orderId: 'ORD-123' },
164
173
  * workflowExecutionTimeout: '1 day',
165
174
  * retry: { maximumAttempts: 3 },
166
- * }).toPromise();
175
+ * });
167
176
  *
168
177
  * result.match({
169
178
  * Ok: (output) => console.log('Order processed:', output.status),
@@ -172,16 +181,16 @@ var TypedClient = class TypedClient {
172
181
  * ```
173
182
  */
174
183
  executeWorkflow(workflowName, { args, ...temporalOptions }) {
175
- return __swan_io_boxed.Future.make((resolve) => {
176
- const definition = this.contract.workflows[workflowName];
177
- if (!definition) {
178
- resolve(__swan_io_boxed.Result.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
179
- return;
180
- }
184
+ return _temporal_contract_boxed.Future.make((resolve) => {
181
185
  (async () => {
186
+ const definition = this.contract.workflows[workflowName];
187
+ if (!definition) {
188
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
189
+ return;
190
+ }
182
191
  const inputResult = await definition.input["~standard"].validate(args);
183
192
  if (inputResult.issues) {
184
- resolve(__swan_io_boxed.Result.Error(new WorkflowValidationError(String(workflowName), "input", inputResult.issues)));
193
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowValidationError(workflowName, "input", inputResult.issues)));
185
194
  return;
186
195
  }
187
196
  const validatedInput = inputResult.value;
@@ -193,12 +202,12 @@ var TypedClient = class TypedClient {
193
202
  });
194
203
  const outputResult = await definition.output["~standard"].validate(result);
195
204
  if (outputResult.issues) {
196
- resolve(__swan_io_boxed.Result.Error(new WorkflowValidationError(String(workflowName), "output", outputResult.issues)));
205
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowValidationError(workflowName, "output", outputResult.issues)));
197
206
  return;
198
207
  }
199
- resolve(__swan_io_boxed.Result.Ok(outputResult.value));
208
+ resolve(_temporal_contract_boxed.Result.Ok(outputResult.value));
200
209
  } catch (error) {
201
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Failed to execute workflow: ${error instanceof Error ? error.message : String(error)}`)));
210
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("executeWorkflow", error)));
202
211
  }
203
212
  })();
204
213
  });
@@ -208,10 +217,10 @@ var TypedClient = class TypedClient {
208
217
  *
209
218
  * @example
210
219
  * ```ts
211
- * const handleResult = await client.getHandle('processOrder', 'order-123').toPromise();
220
+ * const handleResult = await client.getHandle('processOrder', 'order-123');
212
221
  * handleResult.match({
213
222
  * Ok: async (handle) => {
214
- * const result = await handle.result().toPromise();
223
+ * const result = await handle.result();
215
224
  * // ... handle result
216
225
  * },
217
226
  * Error: (error) => console.error('Failed to get handle:', error),
@@ -219,178 +228,137 @@ var TypedClient = class TypedClient {
219
228
  * ```
220
229
  */
221
230
  getHandle(workflowName, workflowId) {
222
- return __swan_io_boxed.Future.make((resolve) => {
231
+ return _temporal_contract_boxed.Future.make((resolve) => {
223
232
  const definition = this.contract.workflows[workflowName];
224
233
  if (!definition) {
225
- resolve(__swan_io_boxed.Result.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
234
+ resolve(_temporal_contract_boxed.Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
226
235
  return;
227
236
  }
228
237
  try {
229
238
  const handle = this.client.workflow.getHandle(workflowId);
230
239
  const typedHandle = this.createTypedHandle(handle, definition);
231
- resolve(__swan_io_boxed.Result.Ok(typedHandle));
240
+ resolve(_temporal_contract_boxed.Result.Ok(typedHandle));
232
241
  } catch (error) {
233
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Failed to get workflow handle: ${error instanceof Error ? error.message : String(error)}`)));
242
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("getHandle", error)));
234
243
  }
235
244
  });
236
245
  }
237
- createTypedHandle(handle, definition) {
246
+ createTypedHandle(workflowHandle, definition) {
238
247
  const queries = {};
239
248
  for (const [queryName, queryDef] of Object.entries(definition.queries ?? {})) queries[queryName] = (args) => {
240
- return __swan_io_boxed.Future.make((resolve) => {
249
+ return _temporal_contract_boxed.Future.make((resolve) => {
241
250
  (async () => {
242
251
  const inputResult = await queryDef.input["~standard"].validate(args);
243
252
  if (inputResult.issues) {
244
- resolve(__swan_io_boxed.Result.Error(new QueryValidationError(queryName, "input", inputResult.issues)));
253
+ resolve(_temporal_contract_boxed.Result.Error(new QueryValidationError(queryName, "input", inputResult.issues)));
245
254
  return;
246
255
  }
247
256
  try {
248
- const result = await handle.query(queryName, inputResult.value);
257
+ const result = await workflowHandle.query(queryName, inputResult.value);
249
258
  const outputResult = await queryDef.output["~standard"].validate(result);
250
259
  if (outputResult.issues) {
251
- resolve(__swan_io_boxed.Result.Error(new QueryValidationError(queryName, "output", outputResult.issues)));
260
+ resolve(_temporal_contract_boxed.Result.Error(new QueryValidationError(queryName, "output", outputResult.issues)));
252
261
  return;
253
262
  }
254
- resolve(__swan_io_boxed.Result.Ok(outputResult.value));
263
+ resolve(_temporal_contract_boxed.Result.Ok(outputResult.value));
255
264
  } catch (error) {
256
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Query failed: ${error instanceof Error ? error.message : String(error)}`)));
265
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("query", error)));
257
266
  }
258
267
  })();
259
268
  });
260
269
  };
261
270
  const signals = {};
262
271
  for (const [signalName, signalDef] of Object.entries(definition.signals ?? {})) signals[signalName] = (args) => {
263
- return __swan_io_boxed.Future.make((resolve) => {
272
+ return _temporal_contract_boxed.Future.make((resolve) => {
264
273
  (async () => {
265
274
  const inputResult = await signalDef.input["~standard"].validate(args);
266
275
  if (inputResult.issues) {
267
- resolve(__swan_io_boxed.Result.Error(new SignalValidationError(signalName, inputResult.issues)));
276
+ resolve(_temporal_contract_boxed.Result.Error(new SignalValidationError(signalName, inputResult.issues)));
268
277
  return;
269
278
  }
270
279
  try {
271
- await handle.signal(signalName, inputResult.value);
272
- resolve(__swan_io_boxed.Result.Ok(void 0));
280
+ await workflowHandle.signal(signalName, inputResult.value);
281
+ resolve(_temporal_contract_boxed.Result.Ok(void 0));
273
282
  } catch (error) {
274
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Signal failed: ${error instanceof Error ? error.message : String(error)}`)));
283
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("signal", error)));
275
284
  }
276
285
  })();
277
286
  });
278
287
  };
279
288
  const updates = {};
280
289
  for (const [updateName, updateDef] of Object.entries(definition.updates ?? {})) updates[updateName] = (args) => {
281
- return __swan_io_boxed.Future.make((resolve) => {
290
+ return _temporal_contract_boxed.Future.make((resolve) => {
282
291
  (async () => {
283
292
  const inputResult = await updateDef.input["~standard"].validate(args);
284
293
  if (inputResult.issues) {
285
- resolve(__swan_io_boxed.Result.Error(new UpdateValidationError(updateName, "input", inputResult.issues)));
294
+ resolve(_temporal_contract_boxed.Result.Error(new UpdateValidationError(updateName, "input", inputResult.issues)));
286
295
  return;
287
296
  }
288
297
  try {
289
- const result = await handle.executeUpdate(updateName, { args: [inputResult.value] });
298
+ const result = await workflowHandle.executeUpdate(updateName, { args: [inputResult.value] });
290
299
  const outputResult = await updateDef.output["~standard"].validate(result);
291
300
  if (outputResult.issues) {
292
- resolve(__swan_io_boxed.Result.Error(new UpdateValidationError(updateName, "output", outputResult.issues)));
301
+ resolve(_temporal_contract_boxed.Result.Error(new UpdateValidationError(updateName, "output", outputResult.issues)));
293
302
  return;
294
303
  }
295
- resolve(__swan_io_boxed.Result.Ok(outputResult.value));
304
+ resolve(_temporal_contract_boxed.Result.Ok(outputResult.value));
296
305
  } catch (error) {
297
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Update failed: ${error instanceof Error ? error.message : String(error)}`)));
306
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("update", error)));
298
307
  }
299
308
  })();
300
309
  });
301
310
  };
302
311
  return {
303
- workflowId: handle.workflowId,
312
+ workflowId: workflowHandle.workflowId,
304
313
  queries,
305
314
  signals,
306
315
  updates,
307
316
  result: () => {
308
- return __swan_io_boxed.Future.make((resolve) => {
317
+ return _temporal_contract_boxed.Future.make((resolve) => {
309
318
  (async () => {
310
319
  try {
311
- const result = await handle.result();
320
+ const result = await workflowHandle.result();
312
321
  const outputResult = await definition.output["~standard"].validate(result);
313
322
  if (outputResult.issues) {
314
- resolve(__swan_io_boxed.Result.Error(new WorkflowValidationError(handle.workflowId, "output", outputResult.issues)));
323
+ resolve(_temporal_contract_boxed.Result.Error(new WorkflowValidationError(workflowHandle.workflowId, "output", outputResult.issues)));
315
324
  return;
316
325
  }
317
- resolve(__swan_io_boxed.Result.Ok(outputResult.value));
326
+ resolve(_temporal_contract_boxed.Result.Ok(outputResult.value));
318
327
  } catch (error) {
319
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Workflow execution failed: ${error instanceof Error ? error.message : String(error)}`)));
328
+ resolve(_temporal_contract_boxed.Result.Error(createRuntimeClientError("result", error)));
320
329
  }
321
330
  })();
322
331
  });
323
332
  },
324
333
  terminate: (reason) => {
325
- return __swan_io_boxed.Future.make((resolve) => {
326
- (async () => {
327
- try {
328
- await handle.terminate(reason);
329
- resolve(__swan_io_boxed.Result.Ok(void 0));
330
- } catch (error) {
331
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Terminate failed: ${error instanceof Error ? error.message : String(error)}`)));
332
- }
333
- })();
334
- });
334
+ return _temporal_contract_boxed.Future.fromPromise(workflowHandle.terminate(reason)).mapError((error) => createRuntimeClientError("terminate", error)).mapOk(() => void 0);
335
335
  },
336
336
  cancel: () => {
337
- return __swan_io_boxed.Future.make((resolve) => {
338
- (async () => {
339
- try {
340
- await handle.cancel();
341
- resolve(__swan_io_boxed.Result.Ok(void 0));
342
- } catch (error) {
343
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Cancel failed: ${error instanceof Error ? error.message : String(error)}`)));
344
- }
345
- })();
346
- });
337
+ return _temporal_contract_boxed.Future.fromPromise(workflowHandle.cancel()).mapError((error) => createRuntimeClientError("cancel", error)).mapOk(() => void 0);
347
338
  },
348
339
  describe: () => {
349
- return __swan_io_boxed.Future.make((resolve) => {
350
- (async () => {
351
- try {
352
- const description = await handle.describe();
353
- resolve(__swan_io_boxed.Result.Ok(description));
354
- } catch (error) {
355
- resolve(__swan_io_boxed.Result.Error(new TypedClientError(`Describe failed: ${error instanceof Error ? error.message : String(error)}`)));
356
- }
357
- })();
358
- });
340
+ return _temporal_contract_boxed.Future.fromPromise(workflowHandle.describe()).mapError((error) => createRuntimeClientError("describe", error));
359
341
  },
360
- fetchHistory: () => handle.fetchHistory()
342
+ fetchHistory: () => {
343
+ return _temporal_contract_boxed.Future.fromPromise(workflowHandle.fetchHistory()).mapError((error) => createRuntimeClientError("fetchHistory", error));
344
+ }
361
345
  };
362
346
  }
363
347
  };
348
+ function createRuntimeClientError(operation, error) {
349
+ return new RuntimeClientError(operation, error);
350
+ }
351
+ function createWorkflowNotFoundError(workflowName, contract) {
352
+ return new WorkflowNotFoundError(String(workflowName), Object.keys(contract.workflows));
353
+ }
354
+ function createWorkflowValidationError(workflowName, direction, issues) {
355
+ return new WorkflowValidationError(String(workflowName), direction, issues);
356
+ }
364
357
 
365
358
  //#endregion
366
- Object.defineProperty(exports, 'AsyncData', {
367
- enumerable: true,
368
- get: function () {
369
- return __swan_io_boxed.AsyncData;
370
- }
371
- });
372
- Object.defineProperty(exports, 'Future', {
373
- enumerable: true,
374
- get: function () {
375
- return __swan_io_boxed.Future;
376
- }
377
- });
378
- Object.defineProperty(exports, 'Option', {
379
- enumerable: true,
380
- get: function () {
381
- return __swan_io_boxed.Option;
382
- }
383
- });
384
359
  exports.QueryValidationError = QueryValidationError;
385
- Object.defineProperty(exports, 'Result', {
386
- enumerable: true,
387
- get: function () {
388
- return __swan_io_boxed.Result;
389
- }
390
- });
391
360
  exports.SignalValidationError = SignalValidationError;
392
361
  exports.TypedClient = TypedClient;
393
- exports.TypedClientError = TypedClientError;
394
362
  exports.UpdateValidationError = UpdateValidationError;
395
363
  exports.WorkflowNotFoundError = WorkflowNotFoundError;
396
364
  exports.WorkflowValidationError = WorkflowValidationError;
package/dist/index.d.cts CHANGED
@@ -1,14 +1,100 @@
1
- import { ClientOptions, WorkflowHandle, WorkflowOptions, WorkflowStartOptions } from "@temporalio/client";
2
- import { ClientInferInput, ClientInferOutput, ClientInferWorkflowQueries, ClientInferWorkflowSignals, ClientInferWorkflowUpdates, ContractDefinition, WorkflowDefinition } from "@temporal-contract/contract";
3
- import { AsyncData, Future, Future as Future$1, Option, Result, Result as Result$1 } from "@swan-io/boxed";
1
+ import { Client, WorkflowHandle, WorkflowStartOptions } from "@temporalio/client";
2
+ import { ActivityDefinition, AnySchema, ContractDefinition, QueryDefinition, SignalDefinition, UpdateDefinition, WorkflowDefinition } from "@temporal-contract/contract";
4
3
  import { StandardSchemaV1 } from "@standard-schema/spec";
4
+ import { Future, Result } from "@temporal-contract/boxed";
5
5
 
6
+ //#region src/types.d.ts
7
+
8
+ /**
9
+ * Infer input type from a definition (client perspective)
10
+ * Client sends the input type (before input schema parsing/transformation)
11
+ */
12
+ type ClientInferInput<T extends {
13
+ input: AnySchema;
14
+ }> = StandardSchemaV1.InferInput<T["input"]>;
15
+ /**
16
+ * Infer output type from a definition (client perspective)
17
+ * Client receives the output type (after output schema parsing/transformation)
18
+ */
19
+ type ClientInferOutput<T extends {
20
+ output: AnySchema;
21
+ }> = StandardSchemaV1.InferOutput<T["output"]>;
22
+ /**
23
+ * CLIENT PERSPECTIVE
24
+ * Client sends z.output and receives z.input
25
+ */
26
+ /**
27
+ * Infer workflow function signature from client perspective
28
+ * Client sends z.output and receives z.input
29
+ */
30
+ type ClientInferWorkflow<TWorkflow extends WorkflowDefinition> = (args: ClientInferInput<TWorkflow>) => Promise<ClientInferOutput<TWorkflow>>;
31
+ /**
32
+ * Infer activity function signature from client perspective
33
+ * Client sends z.output and receives z.input
34
+ */
35
+ type ClientInferActivity<TActivity extends ActivityDefinition> = (args: ClientInferInput<TActivity>) => Promise<ClientInferOutput<TActivity>>;
36
+ /**
37
+ * Infer signal handler signature from client perspective
38
+ * Client sends z.output and returns Future<Result<void, Error>>
39
+ */
40
+ type ClientInferSignal<TSignal extends SignalDefinition> = (args: ClientInferInput<TSignal>) => Future<Result<void, Error>>;
41
+ /**
42
+ * Infer query handler signature from client perspective
43
+ * Client sends z.output and receives z.input wrapped in Future<Result<T, Error>>
44
+ */
45
+ type ClientInferQuery<TQuery extends QueryDefinition> = (args: ClientInferInput<TQuery>) => Future<Result<ClientInferOutput<TQuery>, Error>>;
46
+ /**
47
+ * Infer update handler signature from client perspective
48
+ * Client sends z.output and receives z.input wrapped in Future<Result<T, Error>>
49
+ */
50
+ type ClientInferUpdate<TUpdate extends UpdateDefinition> = (args: ClientInferInput<TUpdate>) => Future<Result<ClientInferOutput<TUpdate>, Error>>;
51
+ /**
52
+ * CLIENT PERSPECTIVE - Contract-level types
53
+ */
54
+ /**
55
+ * Infer all workflows from a contract (client perspective)
56
+ */
57
+ type ClientInferWorkflows<TContract extends ContractDefinition> = { [K in keyof TContract["workflows"]]: ClientInferWorkflow<TContract["workflows"][K]> };
58
+ /**
59
+ * Infer all activities from a contract (client perspective)
60
+ */
61
+ type ClientInferActivities<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof TContract["activities"]]: ClientInferActivity<TContract["activities"][K]> } : {};
62
+ /**
63
+ * Infer activities from a workflow definition (client perspective)
64
+ */
65
+ type ClientInferWorkflowActivities<T extends WorkflowDefinition> = T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: ClientInferActivity<T["activities"][K]> } : {};
66
+ /**
67
+ * Infer signals from a workflow definition (client perspective)
68
+ */
69
+ type ClientInferWorkflowSignals<T extends WorkflowDefinition> = T["signals"] extends Record<string, SignalDefinition> ? { [K in keyof T["signals"]]: ClientInferSignal<T["signals"][K]> } : {};
70
+ /**
71
+ * Infer queries from a workflow definition (client perspective)
72
+ */
73
+ type ClientInferWorkflowQueries<T extends WorkflowDefinition> = T["queries"] extends Record<string, QueryDefinition> ? { [K in keyof T["queries"]]: ClientInferQuery<T["queries"][K]> } : {};
74
+ /**
75
+ * Infer updates from a workflow definition (client perspective)
76
+ */
77
+ type ClientInferWorkflowUpdates<T extends WorkflowDefinition> = T["updates"] extends Record<string, UpdateDefinition> ? { [K in keyof T["updates"]]: ClientInferUpdate<T["updates"][K]> } : {};
78
+ /**
79
+ * Infer all activities available in a workflow context (client perspective)
80
+ * Combines workflow-specific activities with global activities
81
+ */
82
+ type ClientInferWorkflowContextActivities<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = ClientInferWorkflowActivities<TContract["workflows"][TWorkflowName]> & ClientInferActivities<TContract>;
83
+ //#endregion
6
84
  //#region src/errors.d.ts
7
85
  /**
8
86
  * Base class for all typed client errors with boxed pattern
9
87
  */
10
- declare class TypedClientError extends Error {
11
- constructor(message: string);
88
+ declare abstract class TypedClientError extends Error {
89
+ protected constructor(message: string);
90
+ }
91
+ /**
92
+ * Generic runtime failure wrapper when no specific error type applies
93
+ */
94
+ declare class RuntimeClientError extends TypedClientError {
95
+ readonly operation: string;
96
+ readonly cause?: unknown | undefined;
97
+ constructor(operation: string, cause?: unknown | undefined);
12
98
  }
13
99
  /**
14
100
  * Thrown when a workflow is not found in the contract
@@ -55,11 +141,9 @@ declare class UpdateValidationError extends TypedClientError {
55
141
  }
56
142
  //#endregion
57
143
  //#region src/client.d.ts
58
- /**
59
- * Extended options for starting workflows with Temporal-specific features
60
- * Combines required workflowId with optional Temporal workflow options
61
- */
62
- type TypedWorkflowStartOptions = Pick<WorkflowStartOptions, "workflowId" | "workflowIdReusePolicy" | "workflowExecutionTimeout" | "workflowRunTimeout" | "workflowTaskTimeout" | "retry" | "memo" | "searchAttributes" | "cronSchedule"> & Pick<WorkflowOptions, "workflowId">;
144
+ type TypedWorkflowStartOptions<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = Omit<WorkflowStartOptions, "taskQueue" | "args"> & {
145
+ args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
146
+ };
63
147
  /**
64
148
  * Typed workflow handle with validated results using Result/Future pattern
65
149
  */
@@ -69,37 +153,37 @@ interface TypedWorkflowHandle<TWorkflow extends WorkflowDefinition> {
69
153
  * Type-safe queries based on workflow definition with Result pattern
70
154
  * Each query returns Future<Result<T, Error>> instead of Promise<T>
71
155
  */
72
- queries: { [K in keyof ClientInferWorkflowQueries<TWorkflow>]: ClientInferWorkflowQueries<TWorkflow>[K] extends ((...args: infer Args) => Promise<infer R>) ? (...args: Args) => Future$1<Result$1<R, TypedClientError>> : never };
156
+ queries: { [K in keyof ClientInferWorkflowQueries<TWorkflow>]: ClientInferWorkflowQueries<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<infer R, Error>>) ? (...args: Args) => Future<Result<R, QueryValidationError | RuntimeClientError>> : never };
73
157
  /**
74
158
  * Type-safe signals based on workflow definition with Result pattern
75
159
  * Each signal returns Future<Result<void, Error>> instead of Promise<void>
76
160
  */
77
- signals: { [K in keyof ClientInferWorkflowSignals<TWorkflow>]: ClientInferWorkflowSignals<TWorkflow>[K] extends ((...args: infer Args) => Promise<void>) ? (...args: Args) => Future$1<Result$1<void, TypedClientError>> : never };
161
+ signals: { [K in keyof ClientInferWorkflowSignals<TWorkflow>]: ClientInferWorkflowSignals<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<void, Error>>) ? (...args: Args) => Future<Result<void, SignalValidationError | RuntimeClientError>> : never };
78
162
  /**
79
163
  * Type-safe updates based on workflow definition with Result pattern
80
164
  * Each update returns Future<Result<T, Error>> instead of Promise<T>
81
165
  */
82
- updates: { [K in keyof ClientInferWorkflowUpdates<TWorkflow>]: ClientInferWorkflowUpdates<TWorkflow>[K] extends ((...args: infer Args) => Promise<infer R>) ? (...args: Args) => Future$1<Result$1<R, TypedClientError>> : never };
166
+ updates: { [K in keyof ClientInferWorkflowUpdates<TWorkflow>]: ClientInferWorkflowUpdates<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<infer R, Error>>) ? (...args: Args) => Future<Result<R, UpdateValidationError | RuntimeClientError>> : never };
83
167
  /**
84
168
  * Get workflow result with Result pattern
85
169
  */
86
- result: () => Future$1<Result$1<ClientInferOutput<TWorkflow>, TypedClientError>>;
170
+ result: () => Future<Result<ClientInferOutput<TWorkflow>, WorkflowValidationError | RuntimeClientError>>;
87
171
  /**
88
172
  * Terminate workflow with Result pattern
89
173
  */
90
- terminate: (reason?: string) => Future$1<Result$1<void, TypedClientError>>;
174
+ terminate: (reason?: string) => Future<Result<void, RuntimeClientError>>;
91
175
  /**
92
176
  * Cancel workflow with Result pattern
93
177
  */
94
- cancel: () => Future$1<Result$1<void, TypedClientError>>;
178
+ cancel: () => Future<Result<void, RuntimeClientError>>;
95
179
  /**
96
180
  * Get workflow execution description including status and metadata
97
181
  */
98
- describe: () => Future$1<Result$1<Awaited<ReturnType<WorkflowHandle["describe"]>>, TypedClientError>>;
182
+ describe: () => Future<Result<Awaited<ReturnType<WorkflowHandle["describe"]>>, RuntimeClientError>>;
99
183
  /**
100
184
  * Fetch the workflow execution history
101
185
  */
102
- fetchHistory: () => ReturnType<WorkflowHandle["fetchHistory"]>;
186
+ fetchHistory: () => Future<Result<Awaited<ReturnType<WorkflowHandle["fetchHistory"]>>, RuntimeClientError>>;
103
187
  }
104
188
  /**
105
189
  * Typed Temporal client with Result/Future pattern based on a contract
@@ -125,7 +209,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
125
209
  * const result = await client.executeWorkflow('processOrder', {
126
210
  * workflowId: 'order-123',
127
211
  * args: { ... },
128
- * }).toPromise();
212
+ * });
129
213
  *
130
214
  * result.match({
131
215
  * Ok: (output) => console.log('Success:', output),
@@ -133,7 +217,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
133
217
  * });
134
218
  * ```
135
219
  */
136
- static create<TContract extends ContractDefinition>(contract: TContract, options: ClientOptions): TypedClient<TContract>;
220
+ static create<TContract extends ContractDefinition>(contract: TContract, client: Client): TypedClient<TContract>;
137
221
  /**
138
222
  * Start a workflow and return a typed handle with Future pattern
139
223
  *
@@ -144,11 +228,11 @@ declare class TypedClient<TContract extends ContractDefinition> {
144
228
  * args: { orderId: 'ORD-123' },
145
229
  * workflowExecutionTimeout: '1 day',
146
230
  * retry: { maximumAttempts: 3 },
147
- * }).toPromise();
231
+ * });
148
232
  *
149
233
  * handleResult.match({
150
234
  * Ok: async (handle) => {
151
- * const result = await handle.result().toPromise();
235
+ * const result = await handle.result();
152
236
  * // ... handle result
153
237
  * },
154
238
  * Error: (error) => console.error('Failed to start:', error),
@@ -158,9 +242,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
158
242
  startWorkflow<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, {
159
243
  args,
160
244
  ...temporalOptions
161
- }: TypedWorkflowStartOptions & {
162
- args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
163
- }): Future$1<Result$1<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
245
+ }: TypedWorkflowStartOptions<TContract, TWorkflowName>): Future<Result<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | WorkflowValidationError | RuntimeClientError>>;
164
246
  /**
165
247
  * Execute a workflow (start and wait for result) with Future/Result pattern
166
248
  *
@@ -171,7 +253,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
171
253
  * args: { orderId: 'ORD-123' },
172
254
  * workflowExecutionTimeout: '1 day',
173
255
  * retry: { maximumAttempts: 3 },
174
- * }).toPromise();
256
+ * });
175
257
  *
176
258
  * result.match({
177
259
  * Ok: (output) => console.log('Order processed:', output.status),
@@ -182,26 +264,24 @@ declare class TypedClient<TContract extends ContractDefinition> {
182
264
  executeWorkflow<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, {
183
265
  args,
184
266
  ...temporalOptions
185
- }: TypedWorkflowStartOptions & {
186
- args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
187
- }): Future$1<Result$1<ClientInferOutput<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
267
+ }: TypedWorkflowStartOptions<TContract, TWorkflowName>): Future<Result<ClientInferOutput<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | WorkflowValidationError | RuntimeClientError>>;
188
268
  /**
189
269
  * Get a handle to an existing workflow with Future/Result pattern
190
270
  *
191
271
  * @example
192
272
  * ```ts
193
- * const handleResult = await client.getHandle('processOrder', 'order-123').toPromise();
273
+ * const handleResult = await client.getHandle('processOrder', 'order-123');
194
274
  * handleResult.match({
195
275
  * Ok: async (handle) => {
196
- * const result = await handle.result().toPromise();
276
+ * const result = await handle.result();
197
277
  * // ... handle result
198
278
  * },
199
279
  * Error: (error) => console.error('Failed to get handle:', error),
200
280
  * });
201
281
  * ```
202
282
  */
203
- getHandle<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, workflowId: string): Future$1<Result$1<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
283
+ getHandle<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, workflowId: string): Future<Result<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | RuntimeClientError>>;
204
284
  private createTypedHandle;
205
285
  }
206
286
  //#endregion
207
- export { AsyncData, Future, Option, QueryValidationError, Result, SignalValidationError, TypedClient, TypedClientError, type TypedWorkflowHandle, type TypedWorkflowStartOptions, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
287
+ export { type ClientInferActivities, type ClientInferActivity, type ClientInferInput, type ClientInferOutput, type ClientInferQuery, type ClientInferSignal, type ClientInferUpdate, type ClientInferWorkflow, type ClientInferWorkflowActivities, type ClientInferWorkflowContextActivities, type ClientInferWorkflowQueries, type ClientInferWorkflowSignals, type ClientInferWorkflowUpdates, type ClientInferWorkflows, QueryValidationError, SignalValidationError, TypedClient, type TypedWorkflowHandle, type TypedWorkflowStartOptions, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
package/dist/index.d.mts CHANGED
@@ -1,14 +1,100 @@
1
- import { ClientOptions, WorkflowHandle, WorkflowOptions, WorkflowStartOptions } from "@temporalio/client";
2
- import { AsyncData, Future, Future as Future$1, Option, Result, Result as Result$1 } from "@swan-io/boxed";
3
- import { ClientInferInput, ClientInferOutput, ClientInferWorkflowQueries, ClientInferWorkflowSignals, ClientInferWorkflowUpdates, ContractDefinition, WorkflowDefinition } from "@temporal-contract/contract";
1
+ import { Future, Result } from "@temporal-contract/boxed";
2
+ import { Client, WorkflowHandle, WorkflowStartOptions } from "@temporalio/client";
3
+ import { ActivityDefinition, AnySchema, ContractDefinition, QueryDefinition, SignalDefinition, UpdateDefinition, WorkflowDefinition } from "@temporal-contract/contract";
4
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
5
5
 
6
+ //#region src/types.d.ts
7
+
8
+ /**
9
+ * Infer input type from a definition (client perspective)
10
+ * Client sends the input type (before input schema parsing/transformation)
11
+ */
12
+ type ClientInferInput<T extends {
13
+ input: AnySchema;
14
+ }> = StandardSchemaV1.InferInput<T["input"]>;
15
+ /**
16
+ * Infer output type from a definition (client perspective)
17
+ * Client receives the output type (after output schema parsing/transformation)
18
+ */
19
+ type ClientInferOutput<T extends {
20
+ output: AnySchema;
21
+ }> = StandardSchemaV1.InferOutput<T["output"]>;
22
+ /**
23
+ * CLIENT PERSPECTIVE
24
+ * Client sends z.output and receives z.input
25
+ */
26
+ /**
27
+ * Infer workflow function signature from client perspective
28
+ * Client sends z.output and receives z.input
29
+ */
30
+ type ClientInferWorkflow<TWorkflow extends WorkflowDefinition> = (args: ClientInferInput<TWorkflow>) => Promise<ClientInferOutput<TWorkflow>>;
31
+ /**
32
+ * Infer activity function signature from client perspective
33
+ * Client sends z.output and receives z.input
34
+ */
35
+ type ClientInferActivity<TActivity extends ActivityDefinition> = (args: ClientInferInput<TActivity>) => Promise<ClientInferOutput<TActivity>>;
36
+ /**
37
+ * Infer signal handler signature from client perspective
38
+ * Client sends z.output and returns Future<Result<void, Error>>
39
+ */
40
+ type ClientInferSignal<TSignal extends SignalDefinition> = (args: ClientInferInput<TSignal>) => Future<Result<void, Error>>;
41
+ /**
42
+ * Infer query handler signature from client perspective
43
+ * Client sends z.output and receives z.input wrapped in Future<Result<T, Error>>
44
+ */
45
+ type ClientInferQuery<TQuery extends QueryDefinition> = (args: ClientInferInput<TQuery>) => Future<Result<ClientInferOutput<TQuery>, Error>>;
46
+ /**
47
+ * Infer update handler signature from client perspective
48
+ * Client sends z.output and receives z.input wrapped in Future<Result<T, Error>>
49
+ */
50
+ type ClientInferUpdate<TUpdate extends UpdateDefinition> = (args: ClientInferInput<TUpdate>) => Future<Result<ClientInferOutput<TUpdate>, Error>>;
51
+ /**
52
+ * CLIENT PERSPECTIVE - Contract-level types
53
+ */
54
+ /**
55
+ * Infer all workflows from a contract (client perspective)
56
+ */
57
+ type ClientInferWorkflows<TContract extends ContractDefinition> = { [K in keyof TContract["workflows"]]: ClientInferWorkflow<TContract["workflows"][K]> };
58
+ /**
59
+ * Infer all activities from a contract (client perspective)
60
+ */
61
+ type ClientInferActivities<TContract extends ContractDefinition> = TContract["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof TContract["activities"]]: ClientInferActivity<TContract["activities"][K]> } : {};
62
+ /**
63
+ * Infer activities from a workflow definition (client perspective)
64
+ */
65
+ type ClientInferWorkflowActivities<T extends WorkflowDefinition> = T["activities"] extends Record<string, ActivityDefinition> ? { [K in keyof T["activities"]]: ClientInferActivity<T["activities"][K]> } : {};
66
+ /**
67
+ * Infer signals from a workflow definition (client perspective)
68
+ */
69
+ type ClientInferWorkflowSignals<T extends WorkflowDefinition> = T["signals"] extends Record<string, SignalDefinition> ? { [K in keyof T["signals"]]: ClientInferSignal<T["signals"][K]> } : {};
70
+ /**
71
+ * Infer queries from a workflow definition (client perspective)
72
+ */
73
+ type ClientInferWorkflowQueries<T extends WorkflowDefinition> = T["queries"] extends Record<string, QueryDefinition> ? { [K in keyof T["queries"]]: ClientInferQuery<T["queries"][K]> } : {};
74
+ /**
75
+ * Infer updates from a workflow definition (client perspective)
76
+ */
77
+ type ClientInferWorkflowUpdates<T extends WorkflowDefinition> = T["updates"] extends Record<string, UpdateDefinition> ? { [K in keyof T["updates"]]: ClientInferUpdate<T["updates"][K]> } : {};
78
+ /**
79
+ * Infer all activities available in a workflow context (client perspective)
80
+ * Combines workflow-specific activities with global activities
81
+ */
82
+ type ClientInferWorkflowContextActivities<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = ClientInferWorkflowActivities<TContract["workflows"][TWorkflowName]> & ClientInferActivities<TContract>;
83
+ //#endregion
6
84
  //#region src/errors.d.ts
7
85
  /**
8
86
  * Base class for all typed client errors with boxed pattern
9
87
  */
10
- declare class TypedClientError extends Error {
11
- constructor(message: string);
88
+ declare abstract class TypedClientError extends Error {
89
+ protected constructor(message: string);
90
+ }
91
+ /**
92
+ * Generic runtime failure wrapper when no specific error type applies
93
+ */
94
+ declare class RuntimeClientError extends TypedClientError {
95
+ readonly operation: string;
96
+ readonly cause?: unknown | undefined;
97
+ constructor(operation: string, cause?: unknown | undefined);
12
98
  }
13
99
  /**
14
100
  * Thrown when a workflow is not found in the contract
@@ -55,11 +141,9 @@ declare class UpdateValidationError extends TypedClientError {
55
141
  }
56
142
  //#endregion
57
143
  //#region src/client.d.ts
58
- /**
59
- * Extended options for starting workflows with Temporal-specific features
60
- * Combines required workflowId with optional Temporal workflow options
61
- */
62
- type TypedWorkflowStartOptions = Pick<WorkflowStartOptions, "workflowId" | "workflowIdReusePolicy" | "workflowExecutionTimeout" | "workflowRunTimeout" | "workflowTaskTimeout" | "retry" | "memo" | "searchAttributes" | "cronSchedule"> & Pick<WorkflowOptions, "workflowId">;
144
+ type TypedWorkflowStartOptions<TContract extends ContractDefinition, TWorkflowName extends keyof TContract["workflows"]> = Omit<WorkflowStartOptions, "taskQueue" | "args"> & {
145
+ args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
146
+ };
63
147
  /**
64
148
  * Typed workflow handle with validated results using Result/Future pattern
65
149
  */
@@ -69,37 +153,37 @@ interface TypedWorkflowHandle<TWorkflow extends WorkflowDefinition> {
69
153
  * Type-safe queries based on workflow definition with Result pattern
70
154
  * Each query returns Future<Result<T, Error>> instead of Promise<T>
71
155
  */
72
- queries: { [K in keyof ClientInferWorkflowQueries<TWorkflow>]: ClientInferWorkflowQueries<TWorkflow>[K] extends ((...args: infer Args) => Promise<infer R>) ? (...args: Args) => Future$1<Result$1<R, TypedClientError>> : never };
156
+ queries: { [K in keyof ClientInferWorkflowQueries<TWorkflow>]: ClientInferWorkflowQueries<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<infer R, Error>>) ? (...args: Args) => Future<Result<R, QueryValidationError | RuntimeClientError>> : never };
73
157
  /**
74
158
  * Type-safe signals based on workflow definition with Result pattern
75
159
  * Each signal returns Future<Result<void, Error>> instead of Promise<void>
76
160
  */
77
- signals: { [K in keyof ClientInferWorkflowSignals<TWorkflow>]: ClientInferWorkflowSignals<TWorkflow>[K] extends ((...args: infer Args) => Promise<void>) ? (...args: Args) => Future$1<Result$1<void, TypedClientError>> : never };
161
+ signals: { [K in keyof ClientInferWorkflowSignals<TWorkflow>]: ClientInferWorkflowSignals<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<void, Error>>) ? (...args: Args) => Future<Result<void, SignalValidationError | RuntimeClientError>> : never };
78
162
  /**
79
163
  * Type-safe updates based on workflow definition with Result pattern
80
164
  * Each update returns Future<Result<T, Error>> instead of Promise<T>
81
165
  */
82
- updates: { [K in keyof ClientInferWorkflowUpdates<TWorkflow>]: ClientInferWorkflowUpdates<TWorkflow>[K] extends ((...args: infer Args) => Promise<infer R>) ? (...args: Args) => Future$1<Result$1<R, TypedClientError>> : never };
166
+ updates: { [K in keyof ClientInferWorkflowUpdates<TWorkflow>]: ClientInferWorkflowUpdates<TWorkflow>[K] extends ((...args: infer Args) => Future<Result<infer R, Error>>) ? (...args: Args) => Future<Result<R, UpdateValidationError | RuntimeClientError>> : never };
83
167
  /**
84
168
  * Get workflow result with Result pattern
85
169
  */
86
- result: () => Future$1<Result$1<ClientInferOutput<TWorkflow>, TypedClientError>>;
170
+ result: () => Future<Result<ClientInferOutput<TWorkflow>, WorkflowValidationError | RuntimeClientError>>;
87
171
  /**
88
172
  * Terminate workflow with Result pattern
89
173
  */
90
- terminate: (reason?: string) => Future$1<Result$1<void, TypedClientError>>;
174
+ terminate: (reason?: string) => Future<Result<void, RuntimeClientError>>;
91
175
  /**
92
176
  * Cancel workflow with Result pattern
93
177
  */
94
- cancel: () => Future$1<Result$1<void, TypedClientError>>;
178
+ cancel: () => Future<Result<void, RuntimeClientError>>;
95
179
  /**
96
180
  * Get workflow execution description including status and metadata
97
181
  */
98
- describe: () => Future$1<Result$1<Awaited<ReturnType<WorkflowHandle["describe"]>>, TypedClientError>>;
182
+ describe: () => Future<Result<Awaited<ReturnType<WorkflowHandle["describe"]>>, RuntimeClientError>>;
99
183
  /**
100
184
  * Fetch the workflow execution history
101
185
  */
102
- fetchHistory: () => ReturnType<WorkflowHandle["fetchHistory"]>;
186
+ fetchHistory: () => Future<Result<Awaited<ReturnType<WorkflowHandle["fetchHistory"]>>, RuntimeClientError>>;
103
187
  }
104
188
  /**
105
189
  * Typed Temporal client with Result/Future pattern based on a contract
@@ -125,7 +209,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
125
209
  * const result = await client.executeWorkflow('processOrder', {
126
210
  * workflowId: 'order-123',
127
211
  * args: { ... },
128
- * }).toPromise();
212
+ * });
129
213
  *
130
214
  * result.match({
131
215
  * Ok: (output) => console.log('Success:', output),
@@ -133,7 +217,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
133
217
  * });
134
218
  * ```
135
219
  */
136
- static create<TContract extends ContractDefinition>(contract: TContract, options: ClientOptions): TypedClient<TContract>;
220
+ static create<TContract extends ContractDefinition>(contract: TContract, client: Client): TypedClient<TContract>;
137
221
  /**
138
222
  * Start a workflow and return a typed handle with Future pattern
139
223
  *
@@ -144,11 +228,11 @@ declare class TypedClient<TContract extends ContractDefinition> {
144
228
  * args: { orderId: 'ORD-123' },
145
229
  * workflowExecutionTimeout: '1 day',
146
230
  * retry: { maximumAttempts: 3 },
147
- * }).toPromise();
231
+ * });
148
232
  *
149
233
  * handleResult.match({
150
234
  * Ok: async (handle) => {
151
- * const result = await handle.result().toPromise();
235
+ * const result = await handle.result();
152
236
  * // ... handle result
153
237
  * },
154
238
  * Error: (error) => console.error('Failed to start:', error),
@@ -158,9 +242,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
158
242
  startWorkflow<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, {
159
243
  args,
160
244
  ...temporalOptions
161
- }: TypedWorkflowStartOptions & {
162
- args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
163
- }): Future$1<Result$1<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
245
+ }: TypedWorkflowStartOptions<TContract, TWorkflowName>): Future<Result<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | WorkflowValidationError | RuntimeClientError>>;
164
246
  /**
165
247
  * Execute a workflow (start and wait for result) with Future/Result pattern
166
248
  *
@@ -171,7 +253,7 @@ declare class TypedClient<TContract extends ContractDefinition> {
171
253
  * args: { orderId: 'ORD-123' },
172
254
  * workflowExecutionTimeout: '1 day',
173
255
  * retry: { maximumAttempts: 3 },
174
- * }).toPromise();
256
+ * });
175
257
  *
176
258
  * result.match({
177
259
  * Ok: (output) => console.log('Order processed:', output.status),
@@ -182,26 +264,24 @@ declare class TypedClient<TContract extends ContractDefinition> {
182
264
  executeWorkflow<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, {
183
265
  args,
184
266
  ...temporalOptions
185
- }: TypedWorkflowStartOptions & {
186
- args: ClientInferInput<TContract["workflows"][TWorkflowName]>;
187
- }): Future$1<Result$1<ClientInferOutput<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
267
+ }: TypedWorkflowStartOptions<TContract, TWorkflowName>): Future<Result<ClientInferOutput<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | WorkflowValidationError | RuntimeClientError>>;
188
268
  /**
189
269
  * Get a handle to an existing workflow with Future/Result pattern
190
270
  *
191
271
  * @example
192
272
  * ```ts
193
- * const handleResult = await client.getHandle('processOrder', 'order-123').toPromise();
273
+ * const handleResult = await client.getHandle('processOrder', 'order-123');
194
274
  * handleResult.match({
195
275
  * Ok: async (handle) => {
196
- * const result = await handle.result().toPromise();
276
+ * const result = await handle.result();
197
277
  * // ... handle result
198
278
  * },
199
279
  * Error: (error) => console.error('Failed to get handle:', error),
200
280
  * });
201
281
  * ```
202
282
  */
203
- getHandle<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, workflowId: string): Future$1<Result$1<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, TypedClientError>>;
283
+ getHandle<TWorkflowName extends keyof TContract["workflows"]>(workflowName: TWorkflowName, workflowId: string): Future<Result<TypedWorkflowHandle<TContract["workflows"][TWorkflowName]>, WorkflowNotFoundError | RuntimeClientError>>;
204
284
  private createTypedHandle;
205
285
  }
206
286
  //#endregion
207
- export { AsyncData, Future, Option, QueryValidationError, Result, SignalValidationError, TypedClient, TypedClientError, type TypedWorkflowHandle, type TypedWorkflowStartOptions, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
287
+ export { type ClientInferActivities, type ClientInferActivity, type ClientInferInput, type ClientInferOutput, type ClientInferQuery, type ClientInferSignal, type ClientInferUpdate, type ClientInferWorkflow, type ClientInferWorkflowActivities, type ClientInferWorkflowContextActivities, type ClientInferWorkflowQueries, type ClientInferWorkflowSignals, type ClientInferWorkflowUpdates, type ClientInferWorkflows, QueryValidationError, SignalValidationError, TypedClient, type TypedWorkflowHandle, type TypedWorkflowStartOptions, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { Client } from "@temporalio/client";
2
- import { AsyncData, Future, Future as Future$1, Option, Result, Result as Result$1 } from "@swan-io/boxed";
1
+ import { Future, Result } from "@temporal-contract/boxed";
3
2
 
4
3
  //#region src/errors.ts
5
4
  /**
@@ -13,6 +12,16 @@ var TypedClientError = class extends Error {
13
12
  }
14
13
  };
15
14
  /**
15
+ * Generic runtime failure wrapper when no specific error type applies
16
+ */
17
+ var RuntimeClientError = class extends TypedClientError {
18
+ constructor(operation, cause) {
19
+ super(`Operation "${operation}" failed: ${cause instanceof Error ? cause.message : String(cause ?? "unknown error")}`);
20
+ this.operation = operation;
21
+ this.cause = cause;
22
+ }
23
+ };
24
+ /**
16
25
  * Thrown when a workflow is not found in the contract
17
26
  */
18
27
  var WorkflowNotFoundError = class extends TypedClientError {
@@ -93,7 +102,7 @@ var TypedClient = class TypedClient {
93
102
  * const result = await client.executeWorkflow('processOrder', {
94
103
  * workflowId: 'order-123',
95
104
  * args: { ... },
96
- * }).toPromise();
105
+ * });
97
106
  *
98
107
  * result.match({
99
108
  * Ok: (output) => console.log('Success:', output),
@@ -101,8 +110,8 @@ var TypedClient = class TypedClient {
101
110
  * });
102
111
  * ```
103
112
  */
104
- static create(contract, options) {
105
- return new TypedClient(contract, new Client(options));
113
+ static create(contract, client) {
114
+ return new TypedClient(contract, client);
106
115
  }
107
116
  /**
108
117
  * Start a workflow and return a typed handle with Future pattern
@@ -114,11 +123,11 @@ var TypedClient = class TypedClient {
114
123
  * args: { orderId: 'ORD-123' },
115
124
  * workflowExecutionTimeout: '1 day',
116
125
  * retry: { maximumAttempts: 3 },
117
- * }).toPromise();
126
+ * });
118
127
  *
119
128
  * handleResult.match({
120
129
  * Ok: async (handle) => {
121
- * const result = await handle.result().toPromise();
130
+ * const result = await handle.result();
122
131
  * // ... handle result
123
132
  * },
124
133
  * Error: (error) => console.error('Failed to start:', error),
@@ -126,16 +135,16 @@ var TypedClient = class TypedClient {
126
135
  * ```
127
136
  */
128
137
  startWorkflow(workflowName, { args, ...temporalOptions }) {
129
- return Future$1.make((resolve) => {
130
- const definition = this.contract.workflows[workflowName];
131
- if (!definition) {
132
- resolve(Result$1.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
133
- return;
134
- }
138
+ return Future.make((resolve) => {
135
139
  (async () => {
140
+ const definition = this.contract.workflows[workflowName];
141
+ if (!definition) {
142
+ resolve(Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
143
+ return;
144
+ }
136
145
  const inputResult = await definition.input["~standard"].validate(args);
137
146
  if (inputResult.issues) {
138
- resolve(Result$1.Error(new WorkflowValidationError(String(workflowName), "input", inputResult.issues)));
147
+ resolve(Result.Error(createWorkflowValidationError(workflowName, "input", inputResult.issues)));
139
148
  return;
140
149
  }
141
150
  const validatedInput = inputResult.value;
@@ -146,9 +155,9 @@ var TypedClient = class TypedClient {
146
155
  args: [validatedInput]
147
156
  });
148
157
  const typedHandle = this.createTypedHandle(handle, definition);
149
- resolve(Result$1.Ok(typedHandle));
158
+ resolve(Result.Ok(typedHandle));
150
159
  } catch (error) {
151
- resolve(Result$1.Error(new TypedClientError(`Failed to start workflow: ${error instanceof Error ? error.message : String(error)}`)));
160
+ resolve(Result.Error(createRuntimeClientError("startWorkflow", error)));
152
161
  }
153
162
  })();
154
163
  });
@@ -163,7 +172,7 @@ var TypedClient = class TypedClient {
163
172
  * args: { orderId: 'ORD-123' },
164
173
  * workflowExecutionTimeout: '1 day',
165
174
  * retry: { maximumAttempts: 3 },
166
- * }).toPromise();
175
+ * });
167
176
  *
168
177
  * result.match({
169
178
  * Ok: (output) => console.log('Order processed:', output.status),
@@ -172,16 +181,16 @@ var TypedClient = class TypedClient {
172
181
  * ```
173
182
  */
174
183
  executeWorkflow(workflowName, { args, ...temporalOptions }) {
175
- return Future$1.make((resolve) => {
176
- const definition = this.contract.workflows[workflowName];
177
- if (!definition) {
178
- resolve(Result$1.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
179
- return;
180
- }
184
+ return Future.make((resolve) => {
181
185
  (async () => {
186
+ const definition = this.contract.workflows[workflowName];
187
+ if (!definition) {
188
+ resolve(Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
189
+ return;
190
+ }
182
191
  const inputResult = await definition.input["~standard"].validate(args);
183
192
  if (inputResult.issues) {
184
- resolve(Result$1.Error(new WorkflowValidationError(String(workflowName), "input", inputResult.issues)));
193
+ resolve(Result.Error(createWorkflowValidationError(workflowName, "input", inputResult.issues)));
185
194
  return;
186
195
  }
187
196
  const validatedInput = inputResult.value;
@@ -193,12 +202,12 @@ var TypedClient = class TypedClient {
193
202
  });
194
203
  const outputResult = await definition.output["~standard"].validate(result);
195
204
  if (outputResult.issues) {
196
- resolve(Result$1.Error(new WorkflowValidationError(String(workflowName), "output", outputResult.issues)));
205
+ resolve(Result.Error(createWorkflowValidationError(workflowName, "output", outputResult.issues)));
197
206
  return;
198
207
  }
199
- resolve(Result$1.Ok(outputResult.value));
208
+ resolve(Result.Ok(outputResult.value));
200
209
  } catch (error) {
201
- resolve(Result$1.Error(new TypedClientError(`Failed to execute workflow: ${error instanceof Error ? error.message : String(error)}`)));
210
+ resolve(Result.Error(createRuntimeClientError("executeWorkflow", error)));
202
211
  }
203
212
  })();
204
213
  });
@@ -208,10 +217,10 @@ var TypedClient = class TypedClient {
208
217
  *
209
218
  * @example
210
219
  * ```ts
211
- * const handleResult = await client.getHandle('processOrder', 'order-123').toPromise();
220
+ * const handleResult = await client.getHandle('processOrder', 'order-123');
212
221
  * handleResult.match({
213
222
  * Ok: async (handle) => {
214
- * const result = await handle.result().toPromise();
223
+ * const result = await handle.result();
215
224
  * // ... handle result
216
225
  * },
217
226
  * Error: (error) => console.error('Failed to get handle:', error),
@@ -219,148 +228,132 @@ var TypedClient = class TypedClient {
219
228
  * ```
220
229
  */
221
230
  getHandle(workflowName, workflowId) {
222
- return Future$1.make((resolve) => {
231
+ return Future.make((resolve) => {
223
232
  const definition = this.contract.workflows[workflowName];
224
233
  if (!definition) {
225
- resolve(Result$1.Error(new WorkflowNotFoundError(String(workflowName), Object.keys(this.contract.workflows))));
234
+ resolve(Result.Error(createWorkflowNotFoundError(workflowName, this.contract)));
226
235
  return;
227
236
  }
228
237
  try {
229
238
  const handle = this.client.workflow.getHandle(workflowId);
230
239
  const typedHandle = this.createTypedHandle(handle, definition);
231
- resolve(Result$1.Ok(typedHandle));
240
+ resolve(Result.Ok(typedHandle));
232
241
  } catch (error) {
233
- resolve(Result$1.Error(new TypedClientError(`Failed to get workflow handle: ${error instanceof Error ? error.message : String(error)}`)));
242
+ resolve(Result.Error(createRuntimeClientError("getHandle", error)));
234
243
  }
235
244
  });
236
245
  }
237
- createTypedHandle(handle, definition) {
246
+ createTypedHandle(workflowHandle, definition) {
238
247
  const queries = {};
239
248
  for (const [queryName, queryDef] of Object.entries(definition.queries ?? {})) queries[queryName] = (args) => {
240
- return Future$1.make((resolve) => {
249
+ return Future.make((resolve) => {
241
250
  (async () => {
242
251
  const inputResult = await queryDef.input["~standard"].validate(args);
243
252
  if (inputResult.issues) {
244
- resolve(Result$1.Error(new QueryValidationError(queryName, "input", inputResult.issues)));
253
+ resolve(Result.Error(new QueryValidationError(queryName, "input", inputResult.issues)));
245
254
  return;
246
255
  }
247
256
  try {
248
- const result = await handle.query(queryName, inputResult.value);
257
+ const result = await workflowHandle.query(queryName, inputResult.value);
249
258
  const outputResult = await queryDef.output["~standard"].validate(result);
250
259
  if (outputResult.issues) {
251
- resolve(Result$1.Error(new QueryValidationError(queryName, "output", outputResult.issues)));
260
+ resolve(Result.Error(new QueryValidationError(queryName, "output", outputResult.issues)));
252
261
  return;
253
262
  }
254
- resolve(Result$1.Ok(outputResult.value));
263
+ resolve(Result.Ok(outputResult.value));
255
264
  } catch (error) {
256
- resolve(Result$1.Error(new TypedClientError(`Query failed: ${error instanceof Error ? error.message : String(error)}`)));
265
+ resolve(Result.Error(createRuntimeClientError("query", error)));
257
266
  }
258
267
  })();
259
268
  });
260
269
  };
261
270
  const signals = {};
262
271
  for (const [signalName, signalDef] of Object.entries(definition.signals ?? {})) signals[signalName] = (args) => {
263
- return Future$1.make((resolve) => {
272
+ return Future.make((resolve) => {
264
273
  (async () => {
265
274
  const inputResult = await signalDef.input["~standard"].validate(args);
266
275
  if (inputResult.issues) {
267
- resolve(Result$1.Error(new SignalValidationError(signalName, inputResult.issues)));
276
+ resolve(Result.Error(new SignalValidationError(signalName, inputResult.issues)));
268
277
  return;
269
278
  }
270
279
  try {
271
- await handle.signal(signalName, inputResult.value);
272
- resolve(Result$1.Ok(void 0));
280
+ await workflowHandle.signal(signalName, inputResult.value);
281
+ resolve(Result.Ok(void 0));
273
282
  } catch (error) {
274
- resolve(Result$1.Error(new TypedClientError(`Signal failed: ${error instanceof Error ? error.message : String(error)}`)));
283
+ resolve(Result.Error(createRuntimeClientError("signal", error)));
275
284
  }
276
285
  })();
277
286
  });
278
287
  };
279
288
  const updates = {};
280
289
  for (const [updateName, updateDef] of Object.entries(definition.updates ?? {})) updates[updateName] = (args) => {
281
- return Future$1.make((resolve) => {
290
+ return Future.make((resolve) => {
282
291
  (async () => {
283
292
  const inputResult = await updateDef.input["~standard"].validate(args);
284
293
  if (inputResult.issues) {
285
- resolve(Result$1.Error(new UpdateValidationError(updateName, "input", inputResult.issues)));
294
+ resolve(Result.Error(new UpdateValidationError(updateName, "input", inputResult.issues)));
286
295
  return;
287
296
  }
288
297
  try {
289
- const result = await handle.executeUpdate(updateName, { args: [inputResult.value] });
298
+ const result = await workflowHandle.executeUpdate(updateName, { args: [inputResult.value] });
290
299
  const outputResult = await updateDef.output["~standard"].validate(result);
291
300
  if (outputResult.issues) {
292
- resolve(Result$1.Error(new UpdateValidationError(updateName, "output", outputResult.issues)));
301
+ resolve(Result.Error(new UpdateValidationError(updateName, "output", outputResult.issues)));
293
302
  return;
294
303
  }
295
- resolve(Result$1.Ok(outputResult.value));
304
+ resolve(Result.Ok(outputResult.value));
296
305
  } catch (error) {
297
- resolve(Result$1.Error(new TypedClientError(`Update failed: ${error instanceof Error ? error.message : String(error)}`)));
306
+ resolve(Result.Error(createRuntimeClientError("update", error)));
298
307
  }
299
308
  })();
300
309
  });
301
310
  };
302
311
  return {
303
- workflowId: handle.workflowId,
312
+ workflowId: workflowHandle.workflowId,
304
313
  queries,
305
314
  signals,
306
315
  updates,
307
316
  result: () => {
308
- return Future$1.make((resolve) => {
317
+ return Future.make((resolve) => {
309
318
  (async () => {
310
319
  try {
311
- const result = await handle.result();
320
+ const result = await workflowHandle.result();
312
321
  const outputResult = await definition.output["~standard"].validate(result);
313
322
  if (outputResult.issues) {
314
- resolve(Result$1.Error(new WorkflowValidationError(handle.workflowId, "output", outputResult.issues)));
323
+ resolve(Result.Error(new WorkflowValidationError(workflowHandle.workflowId, "output", outputResult.issues)));
315
324
  return;
316
325
  }
317
- resolve(Result$1.Ok(outputResult.value));
326
+ resolve(Result.Ok(outputResult.value));
318
327
  } catch (error) {
319
- resolve(Result$1.Error(new TypedClientError(`Workflow execution failed: ${error instanceof Error ? error.message : String(error)}`)));
328
+ resolve(Result.Error(createRuntimeClientError("result", error)));
320
329
  }
321
330
  })();
322
331
  });
323
332
  },
324
333
  terminate: (reason) => {
325
- return Future$1.make((resolve) => {
326
- (async () => {
327
- try {
328
- await handle.terminate(reason);
329
- resolve(Result$1.Ok(void 0));
330
- } catch (error) {
331
- resolve(Result$1.Error(new TypedClientError(`Terminate failed: ${error instanceof Error ? error.message : String(error)}`)));
332
- }
333
- })();
334
- });
334
+ return Future.fromPromise(workflowHandle.terminate(reason)).mapError((error) => createRuntimeClientError("terminate", error)).mapOk(() => void 0);
335
335
  },
336
336
  cancel: () => {
337
- return Future$1.make((resolve) => {
338
- (async () => {
339
- try {
340
- await handle.cancel();
341
- resolve(Result$1.Ok(void 0));
342
- } catch (error) {
343
- resolve(Result$1.Error(new TypedClientError(`Cancel failed: ${error instanceof Error ? error.message : String(error)}`)));
344
- }
345
- })();
346
- });
337
+ return Future.fromPromise(workflowHandle.cancel()).mapError((error) => createRuntimeClientError("cancel", error)).mapOk(() => void 0);
347
338
  },
348
339
  describe: () => {
349
- return Future$1.make((resolve) => {
350
- (async () => {
351
- try {
352
- const description = await handle.describe();
353
- resolve(Result$1.Ok(description));
354
- } catch (error) {
355
- resolve(Result$1.Error(new TypedClientError(`Describe failed: ${error instanceof Error ? error.message : String(error)}`)));
356
- }
357
- })();
358
- });
340
+ return Future.fromPromise(workflowHandle.describe()).mapError((error) => createRuntimeClientError("describe", error));
359
341
  },
360
- fetchHistory: () => handle.fetchHistory()
342
+ fetchHistory: () => {
343
+ return Future.fromPromise(workflowHandle.fetchHistory()).mapError((error) => createRuntimeClientError("fetchHistory", error));
344
+ }
361
345
  };
362
346
  }
363
347
  };
348
+ function createRuntimeClientError(operation, error) {
349
+ return new RuntimeClientError(operation, error);
350
+ }
351
+ function createWorkflowNotFoundError(workflowName, contract) {
352
+ return new WorkflowNotFoundError(String(workflowName), Object.keys(contract.workflows));
353
+ }
354
+ function createWorkflowValidationError(workflowName, direction, issues) {
355
+ return new WorkflowValidationError(String(workflowName), direction, issues);
356
+ }
364
357
 
365
358
  //#endregion
366
- export { AsyncData, Future, Option, QueryValidationError, Result, SignalValidationError, TypedClient, TypedClientError, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
359
+ export { QueryValidationError, SignalValidationError, TypedClient, UpdateValidationError, WorkflowNotFoundError, WorkflowValidationError };
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@temporal-contract/client",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Client utilities with Result/Future pattern for consuming temporal-contract workflows",
5
5
  "keywords": [
6
- "temporal",
7
- "typescript",
8
- "contract",
9
6
  "client",
7
+ "contract",
8
+ "future",
10
9
  "result",
11
- "future"
10
+ "temporal",
11
+ "typescript"
12
12
  ],
13
13
  "homepage": "https://github.com/btravers/temporal-contract#readme",
14
14
  "bugs": {
@@ -20,7 +20,7 @@
20
20
  "directory": "packages/client"
21
21
  },
22
22
  "license": "MIT",
23
- "author": "Benoit TRAVERS <benoit.travers.frgmail.com>",
23
+ "author": "Benoit TRAVERS <benoit.travers.fr@gmail.com>",
24
24
  "type": "module",
25
25
  "exports": {
26
26
  ".": {
@@ -42,28 +42,32 @@
42
42
  "dist"
43
43
  ],
44
44
  "dependencies": {
45
- "@standard-schema/spec": "1.0.0",
46
- "@swan-io/boxed": "3.2.1",
47
- "@temporal-contract/contract": "0.0.4"
45
+ "@standard-schema/spec": "1.1.0",
46
+ "@temporal-contract/boxed": "0.0.6",
47
+ "@temporal-contract/contract": "0.0.6"
48
48
  },
49
49
  "devDependencies": {
50
- "@temporalio/client": "1.13.2",
51
- "@types/node": "25.0.1",
52
- "@vitest/coverage-v8": "4.0.15",
53
- "tsdown": "0.17.3",
50
+ "@temporalio/client": "1.14.0",
51
+ "@temporalio/worker": "1.14.0",
52
+ "@temporalio/workflow": "1.14.0",
53
+ "@types/node": "25.0.3",
54
+ "@vitest/coverage-v8": "4.0.16",
55
+ "tsdown": "0.18.1",
54
56
  "typescript": "5.9.3",
55
- "vitest": "4.0.15",
56
- "zod": "4.1.13",
57
- "@temporal-contract/tsconfig": "0.0.4"
57
+ "vitest": "4.0.16",
58
+ "zod": "4.2.1",
59
+ "@temporal-contract/testing": "0.0.6",
60
+ "@temporal-contract/tsconfig": "0.0.6"
58
61
  },
59
62
  "peerDependencies": {
60
- "@temporalio/client": ">=1.13.0 <2.0.0"
63
+ "@temporalio/client": "^1"
61
64
  },
62
65
  "scripts": {
63
66
  "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
64
67
  "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
65
- "test": "vitest run",
66
- "test:watch": "vitest",
68
+ "test": "vitest run --project unit",
69
+ "test:integration": "vitest run --project integration",
70
+ "test:watch": "vitest --project unit",
67
71
  "typecheck": "tsc --noEmit"
68
72
  }
69
73
  }