@temporalio/common 1.7.4 → 1.8.1

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.
Files changed (52) hide show
  1. package/lib/activity-options.d.ts +18 -10
  2. package/lib/activity-options.js.map +1 -1
  3. package/lib/converter/failure-converter.d.ts +5 -3
  4. package/lib/converter/failure-converter.js +10 -10
  5. package/lib/converter/failure-converter.js.map +1 -1
  6. package/lib/converter/payload-converter.js +5 -3
  7. package/lib/converter/payload-converter.js.map +1 -1
  8. package/lib/converter/protobuf-payload-converters.js +3 -1
  9. package/lib/converter/protobuf-payload-converters.js.map +1 -1
  10. package/lib/deprecated-time.d.ts +5 -5
  11. package/lib/deprecated-time.js.map +1 -1
  12. package/lib/errors.d.ts +18 -0
  13. package/lib/errors.js +26 -1
  14. package/lib/errors.js.map +1 -1
  15. package/lib/failure.d.ts +73 -0
  16. package/lib/failure.js +100 -3
  17. package/lib/failure.js.map +1 -1
  18. package/lib/index.d.ts +3 -1
  19. package/lib/index.js +2 -0
  20. package/lib/index.js.map +1 -1
  21. package/lib/logger.d.ts +13 -0
  22. package/lib/logger.js +3 -0
  23. package/lib/logger.js.map +1 -0
  24. package/lib/retry-policy.d.ts +3 -2
  25. package/lib/retry-policy.js.map +1 -1
  26. package/lib/time.d.ts +10 -4
  27. package/lib/time.js +9 -5
  28. package/lib/time.js.map +1 -1
  29. package/lib/type-helpers.d.ts +8 -0
  30. package/lib/type-helpers.js +8 -1
  31. package/lib/type-helpers.js.map +1 -1
  32. package/lib/versioning-intent.d.ts +18 -0
  33. package/lib/versioning-intent.js +3 -0
  34. package/lib/versioning-intent.js.map +1 -0
  35. package/lib/workflow-options.d.ts +5 -3
  36. package/lib/workflow-options.js +12 -1
  37. package/lib/workflow-options.js.map +1 -1
  38. package/package.json +4 -4
  39. package/src/activity-options.ts +19 -10
  40. package/src/converter/failure-converter.ts +15 -13
  41. package/src/converter/payload-converter.ts +9 -4
  42. package/src/converter/protobuf-payload-converters.ts +3 -1
  43. package/src/deprecated-time.ts +5 -5
  44. package/src/errors.ts +28 -0
  45. package/src/failure.ts +115 -3
  46. package/src/index.ts +3 -1
  47. package/src/logger.ts +15 -0
  48. package/src/retry-policy.ts +3 -3
  49. package/src/time.ts +22 -10
  50. package/src/type-helpers.ts +12 -0
  51. package/src/versioning-intent.ts +18 -0
  52. package/src/workflow-options.ts +15 -4
@@ -1,6 +1,8 @@
1
1
  import type { coresdk } from '@temporalio/proto';
2
2
  import { RetryPolicy } from './retry-policy';
3
3
  import { checkExtends } from './type-helpers';
4
+ import { Duration } from './time';
5
+ import { VersioningIntent } from './versioning-intent';
4
6
 
5
7
  // Avoid importing the proto implementation to reduce workflow bundle size
6
8
  // Copied from coresdk.workflow_commands.ActivityCancellationType
@@ -37,7 +39,7 @@ export interface ActivityOptions {
37
39
  * Heartbeat interval. Activity must heartbeat before this interval passes after a last heartbeat or activity start.
38
40
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
39
41
  */
40
- heartbeatTimeout?: string | number;
42
+ heartbeatTimeout?: Duration;
41
43
 
42
44
  /**
43
45
  * RetryPolicy that define how activity is retried in case of failure. If this is not set, then the server-defined default activity retry policy will be used. To ensure zero retries, set maximum attempts to 1.
@@ -56,7 +58,7 @@ export interface ActivityOptions {
56
58
  * @default `scheduleToCloseTimeout` or unlimited
57
59
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
58
60
  */
59
- startToCloseTimeout?: string | number;
61
+ startToCloseTimeout?: Duration;
60
62
 
61
63
  /**
62
64
  * Time that the Activity Task can stay in the Task Queue before it is picked up by a Worker. Do not specify this timeout unless using host specific Task Queues for Activity Tasks are being used for routing.
@@ -65,7 +67,7 @@ export interface ActivityOptions {
65
67
  * @default `scheduleToCloseTimeout` or unlimited
66
68
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
67
69
  */
68
- scheduleToStartTimeout?: string | number;
70
+ scheduleToStartTimeout?: Duration;
69
71
 
70
72
  /**
71
73
  * Total time that a workflow is willing to wait for Activity to complete.
@@ -76,7 +78,7 @@ export interface ActivityOptions {
76
78
  * @default unlimited
77
79
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
78
80
  */
79
- scheduleToCloseTimeout?: string | number;
81
+ scheduleToCloseTimeout?: Duration;
80
82
 
81
83
  /**
82
84
  * Determines what the SDK does when the Activity is cancelled.
@@ -99,6 +101,14 @@ export interface ActivityOptions {
99
101
  * @default true
100
102
  */
101
103
  allowEagerDispatch?: boolean;
104
+
105
+ /**
106
+ * When using the Worker Versioning feature, specifies whether this Activity should run on a
107
+ * worker with a compatible Build Id or not. See {@link VersioningIntent}.
108
+ *
109
+ * @experimental
110
+ */
111
+ versioningIntent?: VersioningIntent;
102
112
  }
103
113
 
104
114
  /**
@@ -120,7 +130,7 @@ export interface LocalActivityOptions {
120
130
  *
121
131
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
122
132
  */
123
- startToCloseTimeout?: string | number;
133
+ startToCloseTimeout?: Duration;
124
134
 
125
135
  /**
126
136
  * Limits time the local activity can idle internally before being executed. That can happen if
@@ -132,19 +142,18 @@ export interface LocalActivityOptions {
132
142
  * @default unlimited
133
143
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
134
144
  */
135
- scheduleToStartTimeout?: string | number;
145
+ scheduleToStartTimeout?: Duration;
136
146
 
137
147
  /**
138
148
  * Indicates how long the caller is willing to wait for local activity completion. Limits how
139
- * long retries will be attempted. When not specified defaults to the workflow execution
140
- * timeout (which may be unset).
149
+ * long retries will be attempted.
141
150
  *
142
151
  * Either this option or {@link startToCloseTimeout} is required.
143
152
  *
144
153
  * @default unlimited
145
154
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
146
155
  */
147
- scheduleToCloseTimeout?: string | number;
156
+ scheduleToCloseTimeout?: Duration;
148
157
 
149
158
  /**
150
159
  * If the activity is retrying and backoff would exceed this value, a server side timer will be scheduled for the next attempt.
@@ -153,7 +162,7 @@ export interface LocalActivityOptions {
153
162
  * @default 1 minute
154
163
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
155
164
  **/
156
- localRetryThreshold?: string | number;
165
+ localRetryThreshold?: Duration;
157
166
 
158
167
  /**
159
168
  * Determines what the SDK does when the Activity is cancelled.
@@ -57,8 +57,10 @@ export interface FailureConverter {
57
57
  errorToFailure(err: unknown, payloadConverter: PayloadConverter): ProtoFailure;
58
58
  /**
59
59
  * Converts a Failure proto message to a JS Error object.
60
+ *
61
+ * The returned error must be an instance of `TemporalFailure`.
60
62
  */
61
- failureToError(err: ProtoFailure, payloadConverter: PayloadConverter): Error;
63
+ failureToError(err: ProtoFailure, payloadConverter: PayloadConverter): TemporalFailure;
62
64
  }
63
65
 
64
66
  /**
@@ -183,7 +185,7 @@ export class DefaultFailureConverter implements FailureConverter {
183
185
  );
184
186
  }
185
187
 
186
- failureToError(failure: ProtoFailure, payloadConverter: PayloadConverter): Error {
188
+ failureToError(failure: ProtoFailure, payloadConverter: PayloadConverter): TemporalFailure {
187
189
  if (failure.encodedAttributes) {
188
190
  const attrs = payloadConverter.fromPayload<DefaultEncodedFailureAttributes>(failure.encodedAttributes);
189
191
  // Don't apply encodedAttributes unless they conform to an expected schema
@@ -217,7 +219,7 @@ export class DefaultFailureConverter implements FailureConverter {
217
219
  }
218
220
 
219
221
  errorToFailureInner(err: unknown, payloadConverter: PayloadConverter): ProtoFailure {
220
- if (err instanceof TemporalFailure) {
222
+ if (TemporalFailure.is(err)) {
221
223
  if (err.failure) return err.failure;
222
224
  const base = {
223
225
  message: err.message,
@@ -226,7 +228,7 @@ export class DefaultFailureConverter implements FailureConverter {
226
228
  source: FAILURE_SOURCE,
227
229
  };
228
230
 
229
- if (err instanceof ActivityFailure) {
231
+ if (ActivityFailure.is(err)) {
230
232
  return {
231
233
  ...base,
232
234
  activityFailureInfo: {
@@ -235,7 +237,7 @@ export class DefaultFailureConverter implements FailureConverter {
235
237
  },
236
238
  };
237
239
  }
238
- if (err instanceof ChildWorkflowFailure) {
240
+ if (ChildWorkflowFailure.is(err)) {
239
241
  return {
240
242
  ...base,
241
243
  childWorkflowExecutionFailureInfo: {
@@ -245,7 +247,7 @@ export class DefaultFailureConverter implements FailureConverter {
245
247
  },
246
248
  };
247
249
  }
248
- if (err instanceof ApplicationFailure) {
250
+ if (ApplicationFailure.is(err)) {
249
251
  return {
250
252
  ...base,
251
253
  applicationFailureInfo: {
@@ -258,7 +260,7 @@ export class DefaultFailureConverter implements FailureConverter {
258
260
  },
259
261
  };
260
262
  }
261
- if (err instanceof CancelledFailure) {
263
+ if (CancelledFailure.is(err)) {
262
264
  return {
263
265
  ...base,
264
266
  canceledFailureInfo: {
@@ -269,7 +271,7 @@ export class DefaultFailureConverter implements FailureConverter {
269
271
  },
270
272
  };
271
273
  }
272
- if (err instanceof TimeoutFailure) {
274
+ if (TimeoutFailure.is(err)) {
273
275
  return {
274
276
  ...base,
275
277
  timeoutFailureInfo: {
@@ -280,16 +282,16 @@ export class DefaultFailureConverter implements FailureConverter {
280
282
  },
281
283
  };
282
284
  }
283
- if (err instanceof TerminatedFailure) {
285
+ if (ServerFailure.is(err)) {
284
286
  return {
285
287
  ...base,
286
- terminatedFailureInfo: {},
288
+ serverFailureInfo: { nonRetryable: err.nonRetryable },
287
289
  };
288
290
  }
289
- if (err instanceof ServerFailure) {
291
+ if (TerminatedFailure.is(err)) {
290
292
  return {
291
293
  ...base,
292
- serverFailureInfo: { nonRetryable: err.nonRetryable },
294
+ terminatedFailureInfo: {},
293
295
  };
294
296
  }
295
297
  // Just a TemporalFailure
@@ -333,7 +335,7 @@ export class DefaultFailureConverter implements FailureConverter {
333
335
  optionalFailureToOptionalError(
334
336
  failure: ProtoFailure | undefined | null,
335
337
  payloadConverter: PayloadConverter
336
- ): Error | undefined {
338
+ ): TemporalFailure | undefined {
337
339
  return failure ? this.failureToError(failure, payloadConverter) : undefined;
338
340
  }
339
341
 
@@ -1,5 +1,5 @@
1
1
  import { decode, encode } from '../encoding';
2
- import { IllegalStateError, PayloadConverterError, ValueError } from '../errors';
2
+ import { PayloadConverterError, ValueError } from '../errors';
3
3
  import { Payload } from '../interfaces';
4
4
  import { encodingKeys, encodingTypes, METADATA_ENCODING_KEY } from './types';
5
5
 
@@ -209,7 +209,12 @@ export class BinaryPayloadConverter implements PayloadConverterWithEncoding {
209
209
  }
210
210
 
211
211
  public fromPayload<T>(content: Payload): T {
212
- return content.data as any;
212
+ return (
213
+ // Wrap with Uint8Array from this context to ensure `instanceof` works
214
+ (
215
+ content.data ? new Uint8Array(content.data.buffer, content.data.byteOffset, content.data.length) : content.data
216
+ ) as any
217
+ );
213
218
  }
214
219
  }
215
220
 
@@ -227,7 +232,7 @@ export class JsonPayloadConverter implements PayloadConverterWithEncoding {
227
232
  let json;
228
233
  try {
229
234
  json = JSON.stringify(value);
230
- } catch (e) {
235
+ } catch (err) {
231
236
  return undefined;
232
237
  }
233
238
 
@@ -290,7 +295,7 @@ export class SearchAttributePayloadConverter implements PayloadConverter {
290
295
  // JSON.stringify takes care of converting Dates to ISO strings
291
296
  const ret = this.jsonConverter.toPayload(values);
292
297
  if (ret === undefined) {
293
- throw new IllegalStateError('Could not convert search attributes to payloads');
298
+ throw new ValueError('Could not convert search attributes to payloads');
294
299
  }
295
300
  return ret;
296
301
  }
@@ -97,7 +97,9 @@ export class ProtobufBinaryPayloadConverter extends ProtobufPayloadConverter {
97
97
 
98
98
  public fromPayload<T>(content: Payload): T {
99
99
  const { messageType, data } = this.validatePayload(content);
100
- return messageType.decode(data) as unknown as T;
100
+ // Wrap with Uint8Array from this context to ensure `instanceof` works
101
+ const localData = data ? new Uint8Array(data.buffer, data.byteOffset, data.length) : data;
102
+ return messageType.decode(localData) as unknown as T;
101
103
  }
102
104
  }
103
105
 
@@ -1,5 +1,5 @@
1
1
  import * as time from './time';
2
- import { Timestamp } from './time';
2
+ import { type Timestamp, Duration } from './time';
3
3
 
4
4
  /**
5
5
  * Lossy conversion function from Timestamp to number due to possible overflow.
@@ -35,7 +35,7 @@ export function msNumberToTs(millis: number): Timestamp {
35
35
  * @hidden
36
36
  * @deprecated - meant for internal use only
37
37
  */
38
- export function msToTs(str: string | number): Timestamp {
38
+ export function msToTs(str: Duration): Timestamp {
39
39
  return time.msToTs(str);
40
40
  }
41
41
 
@@ -43,7 +43,7 @@ export function msToTs(str: string | number): Timestamp {
43
43
  * @hidden
44
44
  * @deprecated - meant for internal use only
45
45
  */
46
- export function msOptionalToTs(str: string | number | undefined): Timestamp | undefined {
46
+ export function msOptionalToTs(str: Duration | undefined): Timestamp | undefined {
47
47
  return time.msOptionalToTs(str);
48
48
  }
49
49
 
@@ -51,7 +51,7 @@ export function msOptionalToTs(str: string | number | undefined): Timestamp | un
51
51
  * @hidden
52
52
  * @deprecated - meant for internal use only
53
53
  */
54
- export function msOptionalToNumber(val: string | number | undefined): number | undefined {
54
+ export function msOptionalToNumber(val: Duration | undefined): number | undefined {
55
55
  return time.msOptionalToNumber(val);
56
56
  }
57
57
 
@@ -59,7 +59,7 @@ export function msOptionalToNumber(val: string | number | undefined): number | u
59
59
  * @hidden
60
60
  * @deprecated - meant for internal use only
61
61
  */
62
- export function msToNumber(val: string | number): number {
62
+ export function msToNumber(val: Duration): number {
63
63
  return time.msToNumber(val);
64
64
  }
65
65
 
package/src/errors.ts CHANGED
@@ -25,6 +25,8 @@ export class IllegalStateError extends Error {
25
25
  public readonly name: string = 'IllegalStateError';
26
26
  }
27
27
 
28
+ const isWorkflowExecutionAlreadyStartedError = Symbol.for('__temporal_isWorkflowExecutionAlreadyStartedError');
29
+
28
30
  /**
29
31
  * This exception is thrown in the following cases:
30
32
  * - Workflow with the same Workflow Id is currently running
@@ -39,6 +41,21 @@ export class WorkflowExecutionAlreadyStartedError extends TemporalFailure {
39
41
  constructor(message: string, public readonly workflowId: string, public readonly workflowType: string) {
40
42
  super(message);
41
43
  }
44
+
45
+ /**
46
+ * Marker to determine whether an error is an instance of WorkflowExecutionAlreadyStartedError.
47
+ */
48
+ protected readonly [isWorkflowExecutionAlreadyStartedError] = true;
49
+
50
+ /**
51
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
52
+ */
53
+ static is(error: unknown): error is WorkflowExecutionAlreadyStartedError {
54
+ return (
55
+ error instanceof WorkflowExecutionAlreadyStartedError ||
56
+ (error instanceof Error && (error as any)[isWorkflowExecutionAlreadyStartedError])
57
+ );
58
+ }
42
59
  }
43
60
 
44
61
  /**
@@ -55,3 +72,14 @@ export class WorkflowNotFoundError extends Error {
55
72
  super(message);
56
73
  }
57
74
  }
75
+
76
+ /**
77
+ * Thrown when the specified namespace is not known to Temporal Server.
78
+ */
79
+ export class NamespaceNotFoundError extends Error {
80
+ public readonly name: string = 'NamespaceNotFoundError';
81
+
82
+ constructor(public readonly namespace: string) {
83
+ super(`Namespace not found: '${namespace}'`);
84
+ }
85
+ }
package/src/failure.ts CHANGED
@@ -35,6 +35,8 @@ checkExtends<RetryState, temporal.api.enums.v1.RetryState>();
35
35
 
36
36
  export type WorkflowExecution = temporal.api.common.v1.IWorkflowExecution;
37
37
 
38
+ const isTemporalFailure = Symbol.for('__temporal_isTemporalFailure');
39
+
38
40
  /**
39
41
  * Represents failures that can cross Workflow and Activity boundaries.
40
42
  *
@@ -54,8 +56,22 @@ export class TemporalFailure extends Error {
54
56
  constructor(message?: string | undefined | null, public readonly cause?: Error) {
55
57
  super(message ?? undefined);
56
58
  }
59
+
60
+ /**
61
+ * Marker to determine whether an error is an instance of TemporalFailure.
62
+ */
63
+ protected readonly [isTemporalFailure] = true;
64
+
65
+ /**
66
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
67
+ */
68
+ static is(error: unknown): error is TemporalFailure {
69
+ return error instanceof TemporalFailure || (error as any)?.[isTemporalFailure] === true;
70
+ }
57
71
  }
58
72
 
73
+ const isServerFailure = Symbol.for('__temporal_isServerFailure');
74
+
59
75
  /** Exceptions originated at the Temporal service. */
60
76
  export class ServerFailure extends TemporalFailure {
61
77
  public readonly name: string = 'ServerFailure';
@@ -63,8 +79,22 @@ export class ServerFailure extends TemporalFailure {
63
79
  constructor(message: string | undefined, public readonly nonRetryable: boolean, cause?: Error) {
64
80
  super(message, cause);
65
81
  }
82
+
83
+ /**
84
+ * Marker to determine whether an error is an instance of ServerFailure.
85
+ */
86
+ protected readonly [isServerFailure] = true;
87
+
88
+ /**
89
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
90
+ */
91
+ static is(error: unknown): error is ServerFailure {
92
+ return error instanceof ServerFailure || (error as any)?.[isServerFailure] === true;
93
+ }
66
94
  }
67
95
 
96
+ const isApplicationFailure = Symbol.for('__temporal_isApplicationFailure');
97
+
68
98
  /**
69
99
  * `ApplicationFailure`s are used to communicate application-specific failures in Workflows and Activities.
70
100
  *
@@ -103,6 +133,18 @@ export class ApplicationFailure extends TemporalFailure {
103
133
  super(message, cause);
104
134
  }
105
135
 
136
+ /**
137
+ * Marker to determine whether an error is an instance of ApplicationFailure.
138
+ */
139
+ protected readonly [isApplicationFailure] = true;
140
+
141
+ /**
142
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
143
+ */
144
+ static is(error: unknown): error is ApplicationFailure {
145
+ return error instanceof ApplicationFailure || (error as any)?.[isApplicationFailure] === true;
146
+ }
147
+
106
148
  /**
107
149
  * Create a new `ApplicationFailure` from an Error object.
108
150
  *
@@ -181,6 +223,8 @@ export interface ApplicationFailureOptions {
181
223
  cause?: Error;
182
224
  }
183
225
 
226
+ const isCancelledFailure = Symbol.for('__temporal_isCancelledFailure');
227
+
184
228
  /**
185
229
  * This error is thrown when Cancellation has been requested. To allow Cancellation to happen, let it propagate. To
186
230
  * ignore Cancellation, catch it and continue executing. Note that Cancellation can only be requested a single time, so
@@ -194,8 +238,22 @@ export class CancelledFailure extends TemporalFailure {
194
238
  constructor(message: string | undefined, public readonly details: unknown[] = [], cause?: Error) {
195
239
  super(message, cause);
196
240
  }
241
+
242
+ /**
243
+ * Marker to determine whether an error is an instance of CancelledFailure.
244
+ */
245
+ protected readonly [isCancelledFailure] = true;
246
+
247
+ /**
248
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
249
+ */
250
+ static is(error: unknown): error is CancelledFailure {
251
+ return error instanceof CancelledFailure || (error as any)?.[isCancelledFailure] === true;
252
+ }
197
253
  }
198
254
 
255
+ const isTerminatedFailure = Symbol.for('__temporal_isTerminatedFailure');
256
+
199
257
  /**
200
258
  * Used as the `cause` when a Workflow has been terminated
201
259
  */
@@ -205,8 +263,22 @@ export class TerminatedFailure extends TemporalFailure {
205
263
  constructor(message: string | undefined, cause?: Error) {
206
264
  super(message, cause);
207
265
  }
266
+
267
+ /**
268
+ * Marker to determine whether an error is an instance of TerminatedFailure.
269
+ */
270
+ protected readonly [isTerminatedFailure] = true;
271
+
272
+ /**
273
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
274
+ */
275
+ static is(error: unknown): error is TerminatedFailure {
276
+ return error instanceof TerminatedFailure || (error as any)?.[isTerminatedFailure] === true;
277
+ }
208
278
  }
209
279
 
280
+ const isTimeoutFailure = Symbol.for('__temporal_isTimeoutFailure');
281
+
210
282
  /**
211
283
  * Used to represent timeouts of Activities and Workflows
212
284
  */
@@ -220,8 +292,22 @@ export class TimeoutFailure extends TemporalFailure {
220
292
  ) {
221
293
  super(message);
222
294
  }
295
+
296
+ /**
297
+ * Marker to determine whether an error is an instance of TimeoutFailure.
298
+ */
299
+ protected readonly [isTimeoutFailure] = true;
300
+
301
+ /**
302
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
303
+ */
304
+ static is(error: unknown): error is TimeoutFailure {
305
+ return error instanceof TimeoutFailure || (error as any)?.[isTimeoutFailure] === true;
306
+ }
223
307
  }
224
308
 
309
+ const isActivityFailure = Symbol.for('__temporal_isActivityFailure');
310
+
225
311
  /**
226
312
  * Contains information about an Activity failure. Always contains the original reason for the failure as its `cause`.
227
313
  * For example, if an Activity timed out, the cause will be a {@link TimeoutFailure}.
@@ -241,8 +327,22 @@ export class ActivityFailure extends TemporalFailure {
241
327
  ) {
242
328
  super(message, cause);
243
329
  }
330
+
331
+ /**
332
+ * Marker to determine whether an error is an instance of ActivityFailure.
333
+ */
334
+ protected readonly [isActivityFailure] = true;
335
+
336
+ /**
337
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
338
+ */
339
+ static is(error: unknown): error is ActivityFailure {
340
+ return error instanceof ActivityFailure || (error as any)?.[isActivityFailure] === true;
341
+ }
244
342
  }
245
343
 
344
+ const isChildWorkflowFailure = Symbol.for('__temporal_isChildWorkflowFailure');
345
+
246
346
  /**
247
347
  * Contains information about a Child Workflow failure. Always contains the reason for the failure as its {@link cause}.
248
348
  * For example, if the Child was Terminated, the `cause` is a {@link TerminatedFailure}.
@@ -261,6 +361,18 @@ export class ChildWorkflowFailure extends TemporalFailure {
261
361
  ) {
262
362
  super('Child Workflow execution failed', cause);
263
363
  }
364
+
365
+ /**
366
+ * Marker to determine whether an error is an instance of ChildWorkflowFailure.
367
+ */
368
+ protected readonly [isChildWorkflowFailure] = true;
369
+
370
+ /**
371
+ * Instanceof check that works when multiple versions of @temporalio/common are installed.
372
+ */
373
+ static is(error: unknown): error is ChildWorkflowFailure {
374
+ return error instanceof ChildWorkflowFailure || (error as any)?.[isChildWorkflowFailure] === true;
375
+ }
264
376
  }
265
377
 
266
378
  /**
@@ -273,7 +385,7 @@ export class ChildWorkflowFailure extends TemporalFailure {
273
385
  * - `stack`: `error.stack` or `''`
274
386
  */
275
387
  export function ensureApplicationFailure(error: unknown): ApplicationFailure {
276
- if (error instanceof ApplicationFailure) {
388
+ if (ApplicationFailure.is(error)) {
277
389
  return error;
278
390
  }
279
391
 
@@ -292,7 +404,7 @@ export function ensureApplicationFailure(error: unknown): ApplicationFailure {
292
404
  * Otherwise returns an `ApplicationFailure` with `String(err)` as the message.
293
405
  */
294
406
  export function ensureTemporalFailure(err: unknown): TemporalFailure {
295
- if (err instanceof TemporalFailure) {
407
+ if (TemporalFailure.is(err)) {
296
408
  return err;
297
409
  }
298
410
  return ensureApplicationFailure(err);
@@ -305,7 +417,7 @@ export function ensureTemporalFailure(err: unknown): TemporalFailure {
305
417
  * Otherwise, return `error.message`.
306
418
  */
307
419
  export function rootCause(error: unknown): string | undefined {
308
- if (error instanceof TemporalFailure) {
420
+ if (TemporalFailure.is(error)) {
309
421
  return error.cause ? rootCause(error.cause) : error.message;
310
422
  }
311
423
  if (error instanceof Error) {
package/src/index.ts CHANGED
@@ -18,10 +18,12 @@ export * from './errors';
18
18
  export * from './failure';
19
19
  export { Headers, Next } from './interceptors';
20
20
  export * from './interfaces';
21
+ export * from './logger';
21
22
  export * from './retry-policy';
22
- export { Timestamp } from './time';
23
+ export { type Timestamp, Duration, StringValue } from './time';
23
24
  export * from './workflow-handle';
24
25
  export * from './workflow-options';
26
+ export * from './versioning-intent';
25
27
 
26
28
  /**
27
29
  * Encode a UTF-8 string into a Uint8Array
package/src/logger.ts ADDED
@@ -0,0 +1,15 @@
1
+ export type LogLevel = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
2
+
3
+ export type LogMetadata = Record<string | symbol, any>;
4
+
5
+ /**
6
+ * Implement this interface in order to customize worker logging
7
+ */
8
+ export interface Logger {
9
+ log(level: LogLevel, message: string, meta?: LogMetadata): any;
10
+ trace(message: string, meta?: LogMetadata): any;
11
+ debug(message: string, meta?: LogMetadata): any;
12
+ info(message: string, meta?: LogMetadata): any;
13
+ warn(message: string, meta?: LogMetadata): any;
14
+ error(message: string, meta?: LogMetadata): any;
15
+ }
@@ -1,6 +1,6 @@
1
1
  import type { temporal } from '@temporalio/proto';
2
2
  import { ValueError } from './errors';
3
- import { msOptionalToNumber, msOptionalToTs, msToNumber, msToTs, optionalTsToMs } from './time';
3
+ import { Duration, msOptionalToNumber, msOptionalToTs, msToNumber, msToTs, optionalTsToMs } from './time';
4
4
 
5
5
  /**
6
6
  * Options for retrying Workflows and Activities
@@ -19,7 +19,7 @@ export interface RetryPolicy {
19
19
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
20
20
  * @default 1 second
21
21
  */
22
- initialInterval?: string | number;
22
+ initialInterval?: Duration;
23
23
  /**
24
24
  * Maximum number of attempts. When exceeded, retries stop (even if {@link ActivityOptions.scheduleToCloseTimeout}
25
25
  * hasn't been reached).
@@ -35,7 +35,7 @@ export interface RetryPolicy {
35
35
  * @default 100x of {@link initialInterval}
36
36
  * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
37
37
  */
38
- maximumInterval?: string | number;
38
+ maximumInterval?: Duration;
39
39
 
40
40
  /**
41
41
  * List of application failures types to not retry.
package/src/time.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // eslint-disable-next-line import/no-named-as-default
2
2
  import Long from 'long';
3
- import ms from 'ms';
3
+ import ms, { StringValue } from 'ms';
4
4
  import type { google } from '@temporalio/proto';
5
5
  import { ValueError } from './errors';
6
6
 
@@ -11,6 +11,13 @@ import { ValueError } from './errors';
11
11
 
12
12
  export type Timestamp = google.protobuf.ITimestamp;
13
13
 
14
+ /**
15
+ * A duration, expressed either as a number of milliseconds, or as a {@link https://www.npmjs.com/package/ms | ms-formatted string}.
16
+ */
17
+ export type Duration = StringValue | number;
18
+
19
+ export type { StringValue } from 'ms';
20
+
14
21
  /**
15
22
  * Lossy conversion function from Timestamp to number due to possible overflow.
16
23
  * If ts is null or undefined returns undefined.
@@ -45,27 +52,32 @@ export function msNumberToTs(millis: number): Timestamp {
45
52
  return { seconds: Long.fromNumber(seconds), nanos };
46
53
  }
47
54
 
48
- export function msToTs(str: string | number): Timestamp {
49
- if (typeof str === 'number') {
50
- return msNumberToTs(str);
51
- }
52
- return msNumberToTs(ms(str));
55
+ export function msToTs(str: Duration): Timestamp {
56
+ return msNumberToTs(msToNumber(str));
53
57
  }
54
58
 
55
- export function msOptionalToTs(str: string | number | undefined): Timestamp | undefined {
59
+ export function msOptionalToTs(str: Duration | undefined): Timestamp | undefined {
56
60
  return str ? msToTs(str) : undefined;
57
61
  }
58
62
 
59
- export function msOptionalToNumber(val: string | number | undefined): number | undefined {
63
+ export function msOptionalToNumber(val: Duration | undefined): number | undefined {
60
64
  if (val === undefined) return undefined;
61
65
  return msToNumber(val);
62
66
  }
63
67
 
64
- export function msToNumber(val: string | number): number {
68
+ export function msToNumber(val: Duration): number {
65
69
  if (typeof val === 'number') {
66
70
  return val;
67
71
  }
68
- return ms(val);
72
+ return msWithValidation(val);
73
+ }
74
+
75
+ function msWithValidation(str: StringValue): number {
76
+ const millis = ms(str);
77
+ if (millis == null || isNaN(millis)) {
78
+ throw new TypeError(`Invalid duration string: '${str}'`);
79
+ }
80
+ return millis;
69
81
  }
70
82
 
71
83
  export function tsToDate(ts: Timestamp): Date {