@temporalio/client 1.11.2 → 1.11.4

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 (60) hide show
  1. package/lib/async-completion-client.js +4 -4
  2. package/lib/async-completion-client.js.map +1 -1
  3. package/lib/base-client.d.ts +30 -7
  4. package/lib/base-client.js +26 -8
  5. package/lib/base-client.js.map +1 -1
  6. package/lib/build-id-types.js +1 -2
  7. package/lib/build-id-types.js.map +1 -1
  8. package/lib/client.d.ts +3 -4
  9. package/lib/client.js +1 -0
  10. package/lib/client.js.map +1 -1
  11. package/lib/connection.d.ts +26 -9
  12. package/lib/connection.js +35 -12
  13. package/lib/connection.js.map +1 -1
  14. package/lib/errors.d.ts +15 -0
  15. package/lib/errors.js +36 -2
  16. package/lib/errors.js.map +1 -1
  17. package/lib/grpc-retry.js +4 -5
  18. package/lib/grpc-retry.js.map +1 -1
  19. package/lib/helpers.js +2 -3
  20. package/lib/helpers.js.map +1 -1
  21. package/lib/iterators-utils.js +1 -2
  22. package/lib/iterators-utils.js.map +1 -1
  23. package/lib/schedule-client.d.ts +4 -0
  24. package/lib/schedule-client.js +8 -5
  25. package/lib/schedule-client.js.map +1 -1
  26. package/lib/schedule-helpers.d.ts +1 -3
  27. package/lib/schedule-helpers.js +14 -27
  28. package/lib/schedule-helpers.js.map +1 -1
  29. package/lib/schedule-types.d.ts +17 -14
  30. package/lib/schedule-types.js +27 -18
  31. package/lib/schedule-types.js.map +1 -1
  32. package/lib/task-queue-client.d.ts +12 -1
  33. package/lib/task-queue-client.js +23 -38
  34. package/lib/task-queue-client.js.map +1 -1
  35. package/lib/types.d.ts +36 -4
  36. package/lib/types.js +22 -1
  37. package/lib/types.js.map +1 -1
  38. package/lib/workflow-client.d.ts +6 -6
  39. package/lib/workflow-client.js +20 -36
  40. package/lib/workflow-client.js.map +1 -1
  41. package/lib/workflow-options.d.ts +2 -1
  42. package/lib/workflow-options.js +1 -2
  43. package/lib/workflow-options.js.map +1 -1
  44. package/lib/workflow-update-stage.d.ts +12 -8
  45. package/lib/workflow-update-stage.js +18 -17
  46. package/lib/workflow-update-stage.js.map +1 -1
  47. package/package.json +4 -4
  48. package/src/async-completion-client.ts +4 -5
  49. package/src/base-client.ts +32 -6
  50. package/src/client.ts +4 -4
  51. package/src/connection.ts +42 -10
  52. package/src/errors.ts +34 -1
  53. package/src/schedule-client.ts +12 -6
  54. package/src/schedule-helpers.ts +2 -17
  55. package/src/schedule-types.ts +35 -22
  56. package/src/task-queue-client.ts +37 -38
  57. package/src/types.ts +58 -3
  58. package/src/workflow-client.ts +36 -29
  59. package/src/workflow-options.ts +2 -1
  60. package/src/workflow-update-stage.ts +29 -21
@@ -1,28 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toProtoEnum = exports.WorkflowUpdateStage = void 0;
4
- const proto_1 = require("@temporalio/proto");
5
- const type_helpers_1 = require("@temporalio/common/lib/type-helpers");
6
- var WorkflowUpdateStage;
7
- (function (WorkflowUpdateStage) {
8
- /** This is not an allowed value. */
9
- WorkflowUpdateStage[WorkflowUpdateStage["UNSPECIFIED"] = 0] = "UNSPECIFIED";
3
+ exports.encodeWorkflowUpdateStage = exports.WorkflowUpdateStage = void 0;
4
+ const internal_workflow_1 = require("@temporalio/common/lib/internal-workflow");
5
+ exports.WorkflowUpdateStage = {
10
6
  /** Admitted stage. This stage is reached when the server accepts the update request. It is not
11
7
  * allowed to wait for this stage when using startUpdate, since the update request has not yet
12
8
  * been durably persisted at this stage. */
13
- WorkflowUpdateStage[WorkflowUpdateStage["ADMITTED"] = 1] = "ADMITTED";
9
+ ADMITTED: 'ADMITTED',
14
10
  /** Accepted stage. This stage is reached when a workflow has received the update and either
15
11
  * accepted it (i.e. it has passed validation, or there was no validator configured on the update
16
12
  * handler) or rejected it. This is currently the only allowed value when using startUpdate. */
17
- WorkflowUpdateStage[WorkflowUpdateStage["ACCEPTED"] = 2] = "ACCEPTED";
13
+ ACCEPTED: 'ACCEPTED',
18
14
  /** Completed stage. This stage is reached when a workflow has completed processing the
19
15
  * update with either a success or failure. */
20
- WorkflowUpdateStage[WorkflowUpdateStage["COMPLETED"] = 3] = "COMPLETED";
21
- })(WorkflowUpdateStage || (exports.WorkflowUpdateStage = WorkflowUpdateStage = {}));
22
- (0, type_helpers_1.checkExtends)();
23
- (0, type_helpers_1.checkExtends)();
24
- function toProtoEnum(stage) {
25
- return proto_1.temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage[`UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_${WorkflowUpdateStage[stage]}`];
26
- }
27
- exports.toProtoEnum = toProtoEnum;
16
+ COMPLETED: 'COMPLETED',
17
+ /**
18
+ * This is not an allowed value.
19
+ * @deprecated
20
+ */
21
+ UNSPECIFIED: undefined, // eslint-disable-line deprecation/deprecation
22
+ };
23
+ exports.encodeWorkflowUpdateStage = (0, internal_workflow_1.makeProtoEnumConverters)({
24
+ [exports.WorkflowUpdateStage.ADMITTED]: 1,
25
+ [exports.WorkflowUpdateStage.ACCEPTED]: 2,
26
+ [exports.WorkflowUpdateStage.COMPLETED]: 3,
27
+ UNSPECIFIED: 0,
28
+ }, 'UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_')[0];
28
29
  //# sourceMappingURL=workflow-update-stage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-update-stage.js","sourceRoot":"","sources":["../src/workflow-update-stage.ts"],"names":[],"mappings":";;;AAAA,6CAA6C;AAC7C,sEAAmE;AAEnE,IAAY,mBAcX;AAdD,WAAY,mBAAmB;IAC7B,oCAAoC;IACpC,2EAAe,CAAA;IACf;;+CAE2C;IAC3C,qEAAY,CAAA;IACZ;;mGAE+F;IAC/F,qEAAY,CAAA;IACZ;kDAC8C;IAC9C,uEAAa,CAAA;AACf,CAAC,EAdW,mBAAmB,mCAAnB,mBAAmB,QAc9B;AAED,IAAA,2BAAY,GAGT,CAAC;AACJ,IAAA,2BAAY,GAGT,CAAC;AAEJ,SAAgB,WAAW,CAAC,KAA0B;IACpD,OAAO,gBAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,qCAAqC,CAChE,6CAA6C,mBAAmB,CAAC,KAAK,CAAqC,EAAE,CAC9G,CAAC;AACJ,CAAC;AAJD,kCAIC"}
1
+ {"version":3,"file":"workflow-update-stage.js","sourceRoot":"","sources":["../src/workflow-update-stage.ts"],"names":[],"mappings":";;;AACA,gFAAmF;AAEtE,QAAA,mBAAmB,GAAG;IACjC;;+CAE2C;IAC3C,QAAQ,EAAE,UAAU;IAEpB;;mGAE+F;IAC/F,QAAQ,EAAE,UAAU;IAEpB;kDAC8C;IAC9C,SAAS,EAAE,WAAW;IAEtB;;;OAGG;IACH,WAAW,EAAE,SAAS,EAAE,8CAA8C;CAC9D,CAAC;AAGG,iCAAyB,GAAI,IAAA,2CAAuB,EAOhE;IACE,CAAC,2BAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACjC,CAAC,2BAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACjC,CAAC,2BAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;IAClC,WAAW,EAAE,CAAC;CACN,EACV,4CAA4C,CAC7C,IAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporalio/client",
3
- "version": "1.11.2",
3
+ "version": "1.11.4",
4
4
  "description": "Temporal.io SDK Client sub-package",
5
5
  "main": "lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -14,8 +14,8 @@
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
16
  "@grpc/grpc-js": "^1.10.7",
17
- "@temporalio/common": "1.11.2",
18
- "@temporalio/proto": "1.11.2",
17
+ "@temporalio/common": "^1.11.4",
18
+ "@temporalio/proto": "^1.11.4",
19
19
  "abort-controller": "^3.0.0",
20
20
  "long": "^5.2.3",
21
21
  "uuid": "^9.0.1"
@@ -39,5 +39,5 @@
39
39
  "src",
40
40
  "lib"
41
41
  ],
42
- "gitHead": "e78b4f71236ccd3227e674bad68439e961fec639"
42
+ "gitHead": "6a7e2d527c9f7078ee78abd9d59ca0d318bb70dd"
43
43
  }
@@ -1,6 +1,5 @@
1
1
  import { status as grpcStatus } from '@grpc/grpc-js';
2
2
  import { ensureTemporalFailure } from '@temporalio/common';
3
- import type { temporal } from '@temporalio/proto';
4
3
  import {
5
4
  encodeErrorToFailure,
6
5
  encodeToPayloads,
@@ -216,23 +215,23 @@ export class AsyncCompletionClient extends BaseClient {
216
215
  const payloads = await encodeToPayloads(this.dataConverter, details);
217
216
  let cancelRequested = false;
218
217
  try {
219
- let response: temporal.api.workflowservice.v1.RecordActivityTaskHeartbeatResponse;
220
218
  if (taskTokenOrFullActivityId instanceof Uint8Array) {
221
- response = await this.workflowService.recordActivityTaskHeartbeat({
219
+ const response = await this.workflowService.recordActivityTaskHeartbeat({
222
220
  identity: this.options.identity,
223
221
  namespace: this.options.namespace,
224
222
  taskToken: taskTokenOrFullActivityId,
225
223
  details: { payloads },
226
224
  });
225
+ cancelRequested = !!response.cancelRequested;
227
226
  } else {
228
- response = await this.workflowService.recordActivityTaskHeartbeatById({
227
+ const response = await this.workflowService.recordActivityTaskHeartbeatById({
229
228
  identity: this.options.identity,
230
229
  namespace: this.options.namespace,
231
230
  ...taskTokenOrFullActivityId,
232
231
  details: { payloads },
233
232
  });
233
+ cancelRequested = !!response.cancelRequested;
234
234
  }
235
- cancelRequested = !!response.cancelRequested;
236
235
  } catch (err) {
237
236
  this.handleError(err);
238
237
  }
@@ -1,4 +1,5 @@
1
1
  import os from 'node:os';
2
+ import type * as _grpc from '@grpc/grpc-js'; // For JSDoc only
2
3
  import { DataConverter, LoadedDataConverter } from '@temporalio/common';
3
4
  import { isLoadedDataConverter, loadDataConverter } from '@temporalio/common/lib/internal-non-workflow';
4
5
  import { Connection } from './connection';
@@ -51,7 +52,14 @@ export function defaultBaseClientOptions(): WithDefaults<BaseClientOptions> {
51
52
  }
52
53
 
53
54
  export class BaseClient {
55
+ /**
56
+ * The underlying {@link Connection | connection} used by this client.
57
+ *
58
+ * Clients are cheap to create, but connections are expensive. Where that make sense,
59
+ * a single connection may and should be reused by multiple `Client`.
60
+ */
54
61
  public readonly connection: ConnectionLike;
62
+
55
63
  private readonly loadedDataConverter: LoadedDataConverter;
56
64
 
57
65
  protected constructor(options?: BaseClientOptions) {
@@ -61,19 +69,37 @@ export class BaseClient {
61
69
  }
62
70
 
63
71
  /**
64
- * Set the deadline for any service requests executed in `fn`'s scope.
72
+ * Set a deadline for any service requests executed in `fn`'s scope.
73
+ *
74
+ * The deadline is a point in time after which any pending gRPC request will be considered as failed;
75
+ * this will locally result in the request call throwing a {@link _grpc.ServiceError|ServiceError}
76
+ * with code {@link _grpc.status.DEADLINE_EXCEEDED|DEADLINE_EXCEEDED}; see {@link isGrpcDeadlineError}.
77
+ *
78
+ * It is stronly recommended to explicitly set deadlines. If no deadline is set, then it is
79
+ * possible for the client to end up waiting forever for a response.
80
+ *
81
+ * This method is only a convenience wrapper around {@link Connection.withDeadline}.
82
+ *
83
+ * @param deadline a point in time after which the request will be considered as failed; either a
84
+ * Date object, or a number of milliseconds since the Unix epoch (UTC).
85
+ * @returns the value returned from `fn`
86
+ *
87
+ * @see https://grpc.io/docs/guides/deadlines/
65
88
  */
66
89
  public async withDeadline<R>(deadline: number | Date, fn: () => Promise<R>): Promise<R> {
67
90
  return await this.connection.withDeadline(deadline, fn);
68
91
  }
69
92
 
70
93
  /**
71
- * Set an {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} that, when aborted,
72
- * cancels any ongoing service requests executed in `fn`'s scope.
94
+ * Set an {@link AbortSignal} that, when aborted, cancels any ongoing service requests executed in
95
+ * `fn`'s scope. This will locally result in the request call throwing a {@link _grpc.ServiceError|ServiceError}
96
+ * with code {@link _grpc.status.CANCELLED|CANCELLED}; see {@link isGrpcCancelledError}.
97
+ *
98
+ * This method is only a convenience wrapper around {@link Connection.withAbortSignal}.
73
99
  *
74
100
  * @returns value returned from `fn`
75
101
  *
76
- * @see {@link Connection.withAbortSignal}
102
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal
77
103
  */
78
104
  async withAbortSignal<R>(abortSignal: AbortSignal, fn: () => Promise<R>): Promise<R> {
79
105
  return await this.connection.withAbortSignal(abortSignal, fn);
@@ -82,9 +108,9 @@ export class BaseClient {
82
108
  /**
83
109
  * Set metadata for any service requests executed in `fn`'s scope.
84
110
  *
85
- * @returns returned value of `fn`
111
+ * This method is only a convenience wrapper around {@link Connection.withMetadata}.
86
112
  *
87
- * @see {@link Connection.withMetadata}
113
+ * @returns returned value of `fn`
88
114
  */
89
115
  public async withMetadata<R>(metadata: Metadata, fn: () => Promise<R>): Promise<R> {
90
116
  return await this.connection.withMetadata(metadata, fn);
package/src/client.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { filterNullAndUndefined } from '@temporalio/common/lib/internal-non-workflow';
2
- import { temporal } from '@temporalio/proto';
3
2
  import { AsyncCompletionClient } from './async-completion-client';
4
3
  import { BaseClient, BaseClientOptions, defaultBaseClientOptions, LoadedWithDefaults } from './base-client';
5
4
  import { ClientInterceptors } from './interceptors';
6
5
  import { ScheduleClient } from './schedule-client';
7
- import { WorkflowService } from './types';
6
+ import { QueryRejectCondition, WorkflowService } from './types';
8
7
  import { WorkflowClient } from './workflow-client';
9
8
  import { TaskQueueClient } from './task-queue-client';
10
9
 
@@ -20,9 +19,9 @@ export interface ClientOptions extends BaseClientOptions {
20
19
  /**
21
20
  * Should a query be rejected by closed and failed workflows
22
21
  *
23
- * @default QUERY_REJECT_CONDITION_UNSPECIFIED which means that closed and failed workflows are still queryable
22
+ * @default `undefined`, which means that closed and failed workflows are still queryable
24
23
  */
25
- queryRejectCondition?: temporal.api.enums.v1.QueryRejectCondition;
24
+ queryRejectCondition?: QueryRejectCondition;
26
25
  };
27
26
  }
28
27
 
@@ -63,6 +62,7 @@ export class Client extends BaseClient {
63
62
  connection: this.connection,
64
63
  dataConverter: this.dataConverter,
65
64
  interceptors: interceptors?.workflow,
65
+ queryRejectCondition: workflow?.queryRejectCondition,
66
66
  });
67
67
 
68
68
  this.activity = new AsyncCompletionClient({
package/src/connection.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  filterNullAndUndefined,
6
6
  normalizeTlsConfig,
7
7
  TLSConfig,
8
- normalizeTemporalGrpcEndpointAddress,
8
+ normalizeGrpcEndpointAddress,
9
9
  } from '@temporalio/common/lib/internal-non-workflow';
10
10
  import { Duration, msOptionalToNumber } from '@temporalio/common/lib/time';
11
11
  import { isGrpcServiceError, ServiceError } from './errors';
@@ -13,6 +13,11 @@ import { defaultGrpcRetryOptions, makeGrpcRetryInterceptor } from './grpc-retry'
13
13
  import pkg from './pkg';
14
14
  import { CallContext, HealthService, Metadata, OperatorService, WorkflowService } from './types';
15
15
 
16
+ /**
17
+ * The default Temporal Server's TCP port for public gRPC connections.
18
+ */
19
+ const DEFAULT_TEMPORAL_GRPC_PORT = 7233;
20
+
16
21
  /**
17
22
  * gRPC and Temporal Server connection options
18
23
  */
@@ -174,7 +179,7 @@ function normalizeGRPCConfig(options?: ConnectionOptions): ConnectionOptions {
174
179
  }
175
180
  }
176
181
  if (rest.address) {
177
- rest.address = normalizeTemporalGrpcEndpointAddress(rest.address);
182
+ rest.address = normalizeGrpcEndpointAddress(rest.address, DEFAULT_TEMPORAL_GRPC_PORT);
178
183
  }
179
184
  const tls = normalizeTlsConfig(tlsFromConfig);
180
185
  if (tls) {
@@ -220,20 +225,24 @@ export interface RPCImplOptions {
220
225
  export interface ConnectionCtorOptions {
221
226
  readonly options: ConnectionOptionsWithDefaults;
222
227
  readonly client: grpc.Client;
228
+
223
229
  /**
224
230
  * Raw gRPC access to the Temporal service.
225
231
  *
226
232
  * **NOTE**: The namespace provided in {@link options} is **not** automatically set on requests made to the service.
227
233
  */
228
234
  readonly workflowService: WorkflowService;
235
+
229
236
  /**
230
237
  * Raw gRPC access to the Temporal {@link https://github.com/temporalio/api/blob/ddf07ab9933e8230309850e3c579e1ff34b03f53/temporal/api/operatorservice/v1/service.proto | operator service}.
231
238
  */
232
239
  readonly operatorService: OperatorService;
240
+
233
241
  /**
234
242
  * Raw gRPC access to the standard gRPC {@link https://github.com/grpc/grpc/blob/92f58c18a8da2728f571138c37760a721c8915a2/doc/health-checking.md | health service}.
235
243
  */
236
244
  readonly healthService: HealthService;
245
+
237
246
  readonly callContextStorage: AsyncLocalStorage<CallContext>;
238
247
  readonly apiKeyFnRef: { fn?: () => string };
239
248
  }
@@ -241,8 +250,8 @@ export interface ConnectionCtorOptions {
241
250
  /**
242
251
  * Client connection to the Temporal Server
243
252
  *
244
- * ⚠️ Connections are expensive to construct and should be reused. Make sure to {@link close} any unused connections to
245
- * avoid leaking resources.
253
+ * ⚠️ Connections are expensive to construct and should be reused.
254
+ * Make sure to {@link close} any unused connections to avoid leaking resources.
246
255
  */
247
256
  export class Connection {
248
257
  /**
@@ -275,7 +284,12 @@ export class Connection {
275
284
  * Cloud namespace will result in gRPC `unauthorized` error.
276
285
  */
277
286
  public readonly operatorService: OperatorService;
287
+
288
+ /**
289
+ * Raw gRPC access to the standard gRPC {@link https://github.com/grpc/grpc/blob/92f58c18a8da2728f571138c37760a721c8915a2/doc/health-checking.md | health service}.
290
+ */
278
291
  public readonly healthService: HealthService;
292
+
279
293
  readonly callContextStorage: AsyncLocalStorage<CallContext>;
280
294
  private readonly apiKeyFnRef: { fn?: () => string };
281
295
 
@@ -424,7 +438,8 @@ export class Connection {
424
438
  const metadataContainer = new grpc.Metadata();
425
439
  const { metadata, deadline, abortSignal } = callContextStorage.getStore() ?? {};
426
440
  if (apiKeyFnRef.fn) {
427
- metadataContainer.set('Authorization', `Bearer ${apiKeyFnRef.fn()}`);
441
+ const apiKey = apiKeyFnRef.fn();
442
+ if (apiKey) metadataContainer.set('Authorization', `Bearer ${apiKey}`);
428
443
  }
429
444
  for (const [k, v] of Object.entries(staticMetadata)) {
430
445
  metadataContainer.set(k, v);
@@ -452,9 +467,20 @@ export class Connection {
452
467
  }
453
468
 
454
469
  /**
455
- * Set the deadline for any service requests executed in `fn`'s scope.
470
+ * Set a deadline for any service requests executed in `fn`'s scope.
456
471
  *
457
- * @returns value returned from `fn`
472
+ * The deadline is a point in time after which any pending gRPC request will be considered as failed;
473
+ * this will locally result in the request call throwing a {@link grpc.ServiceError|ServiceError}
474
+ * with code {@link grpc.status.DEADLINE_EXCEEDED|DEADLINE_EXCEEDED}; see {@link isGrpcDeadlineError}.
475
+ *
476
+ * It is stronly recommended to explicitly set deadlines. If no deadline is set, then it is
477
+ * possible for the client to end up waiting forever for a response.
478
+ *
479
+ * @param deadline a point in time after which the request will be considered as failed; either a
480
+ * Date object, or a number of milliseconds since the Unix epoch (UTC).
481
+ * @returns the value returned from `fn`
482
+ *
483
+ * @see https://grpc.io/docs/guides/deadlines/
458
484
  */
459
485
  async withDeadline<ReturnType>(deadline: number | Date, fn: () => Promise<ReturnType>): Promise<ReturnType> {
460
486
  const cc = this.callContextStorage.getStore();
@@ -462,10 +488,11 @@ export class Connection {
462
488
  }
463
489
 
464
490
  /**
465
- * Set an {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | `AbortSignal`} that, when aborted,
466
- * cancels any ongoing requests executed in `fn`'s scope.
491
+ * Set an {@link AbortSignal} that, when aborted, cancels any ongoing service requests executed in
492
+ * `fn`'s scope. This will locally result in the request call throwing a {@link grpc.ServiceError|ServiceError}
493
+ * with code {@link grpc.status.CANCELLED|CANCELLED}; see {@link isGrpcCancelledError}.
467
494
  *
468
- * @returns value returned from `fn`
495
+ * This method is only a convenience wrapper around {@link Connection.withAbortSignal}.
469
496
  *
470
497
  * @example
471
498
  *
@@ -475,6 +502,10 @@ export class Connection {
475
502
  * // 👇 throws if incomplete by the timeout.
476
503
  * await conn.withAbortSignal(ctrl.signal, () => client.workflow.execute(myWorkflow, options));
477
504
  * ```
505
+ *
506
+ * @returns value returned from `fn`
507
+ *
508
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal
478
509
  */
479
510
  async withAbortSignal<ReturnType>(abortSignal: AbortSignal, fn: () => Promise<ReturnType>): Promise<ReturnType> {
480
511
  const cc = this.callContextStorage.getStore();
@@ -572,5 +603,6 @@ export class Connection {
572
603
  */
573
604
  public async close(): Promise<void> {
574
605
  this.client.close();
606
+ this.callContextStorage.disable();
575
607
  }
576
608
  }
package/src/errors.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ServiceError as GrpcServiceError } from '@grpc/grpc-js';
1
+ import { ServiceError as GrpcServiceError, status } from '@grpc/grpc-js';
2
2
  import { RetryState, TemporalFailure } from '@temporalio/common';
3
3
  import { isError, isRecord, SymbolBasedInstanceOfError } from '@temporalio/common/lib/type-helpers';
4
4
 
@@ -79,6 +79,9 @@ export class WorkflowContinuedAsNewError extends Error {
79
79
  }
80
80
  }
81
81
 
82
+ /**
83
+ * Returns true if the provided error is a {@link GrpcServiceError}.
84
+ */
82
85
  export function isGrpcServiceError(err: unknown): err is GrpcServiceError {
83
86
  return (
84
87
  isError(err) &&
@@ -87,6 +90,36 @@ export function isGrpcServiceError(err: unknown): err is GrpcServiceError {
87
90
  );
88
91
  }
89
92
 
93
+ /**
94
+ * Returns true if the provided error or its cause is a {@link GrpcServiceError} with code DEADLINE_EXCEEDED.
95
+ *
96
+ * @see {@link Connection.withDeadline}
97
+ */
98
+ export function isGrpcDeadlineError(err: unknown): err is Error {
99
+ while (isError(err)) {
100
+ if (isGrpcServiceError(err) && (err as GrpcServiceError).code === status.DEADLINE_EXCEEDED) {
101
+ return true;
102
+ }
103
+ err = (err as any).cause;
104
+ }
105
+ return false;
106
+ }
107
+
108
+ /**
109
+ * Returns true if the provided error or its cause is a {@link GrpcServiceError} with code CANCELLED.
110
+ *
111
+ * @see {@link Connection.withAbortSignal}
112
+ */
113
+ export function isGrpcCancelledError(err: unknown): err is Error {
114
+ while (isError(err)) {
115
+ if (isGrpcServiceError(err) && (err as GrpcServiceError).code === status.CANCELLED) {
116
+ return true;
117
+ }
118
+ err = (err as any).cause;
119
+ }
120
+ return false;
121
+ }
122
+
90
123
  /**
91
124
  * @deprecated Use `isGrpcServiceError` instead
92
125
  */
@@ -29,17 +29,17 @@ import {
29
29
  ScheduleUpdateOptions,
30
30
  ScheduleOptionsAction,
31
31
  ScheduleOptionsStartWorkflowAction,
32
+ encodeScheduleOverlapPolicy,
33
+ decodeScheduleOverlapPolicy,
32
34
  } from './schedule-types';
33
35
  import {
34
36
  compileScheduleOptions,
35
37
  compileUpdatedScheduleOptions,
36
- decodeOverlapPolicy,
37
38
  decodeScheduleAction,
38
39
  decodeScheduleRecentActions,
39
40
  decodeScheduleRunningActions,
40
41
  decodeScheduleSpec,
41
42
  decodeSearchAttributes,
42
- encodeOverlapPolicy,
43
43
  encodeScheduleAction,
44
44
  encodeSchedulePolicies,
45
45
  encodeScheduleSpec,
@@ -162,6 +162,10 @@ export interface ListScheduleOptions {
162
162
  * @default 1000
163
163
  */
164
164
  pageSize?: number;
165
+ /**
166
+ * Filter schedules by a query string.
167
+ */
168
+ query?: string;
165
169
  }
166
170
 
167
171
  /**
@@ -247,7 +251,7 @@ export class ScheduleClient extends BaseClient {
247
251
  ? opts.state.backfill.map((x) => ({
248
252
  startTime: optionalDateToTs(x.start),
249
253
  endTime: optionalDateToTs(x.end),
250
- overlapPolicy: x.overlap ? encodeOverlapPolicy(x.overlap) : undefined,
254
+ overlapPolicy: x.overlap ? encodeScheduleOverlapPolicy(x.overlap) : undefined,
251
255
  }))
252
256
  : undefined,
253
257
  },
@@ -368,6 +372,7 @@ export class ScheduleClient extends BaseClient {
368
372
  nextPageToken,
369
373
  namespace: this.options.namespace,
370
374
  maximumPageSize: options?.pageSize,
375
+ query: options?.query,
371
376
  });
372
377
  } catch (e) {
373
378
  this.rethrowGrpcError(e, 'Failed to list schedules', undefined);
@@ -422,7 +427,8 @@ export class ScheduleClient extends BaseClient {
422
427
  memo: await decodeMapFromPayloads(this.client.dataConverter, raw.memo?.fields),
423
428
  searchAttributes: decodeSearchAttributes(raw.searchAttributes),
424
429
  policies: {
425
- overlap: decodeOverlapPolicy(raw.schedule.policies?.overlapPolicy),
430
+ // 'overlap' should never be missing on describe, as the server will replace UNSPECIFIED by an actual value
431
+ overlap: decodeScheduleOverlapPolicy(raw.schedule.policies?.overlapPolicy) ?? ScheduleOverlapPolicy.SKIP,
426
432
  catchupWindow: optionalTsToMs(raw.schedule.policies?.catchupWindow) ?? 60_000,
427
433
  pauseOnFailure: raw.schedule.policies?.pauseOnFailure === true,
428
434
  },
@@ -480,7 +486,7 @@ export class ScheduleClient extends BaseClient {
480
486
  await this.client._patchSchedule(this.scheduleId, {
481
487
  triggerImmediately: {
482
488
  overlapPolicy: overlap
483
- ? encodeOverlapPolicy(overlap)
489
+ ? encodeScheduleOverlapPolicy(overlap)
484
490
  : temporal.api.enums.v1.ScheduleOverlapPolicy.SCHEDULE_OVERLAP_POLICY_ALLOW_ALL,
485
491
  },
486
492
  });
@@ -492,7 +498,7 @@ export class ScheduleClient extends BaseClient {
492
498
  backfillRequest: backfills.map((x) => ({
493
499
  startTime: optionalDateToTs(x.start),
494
500
  endTime: optionalDateToTs(x.end),
495
- overlapPolicy: x.overlap ? encodeOverlapPolicy(x.overlap) : undefined,
501
+ overlapPolicy: x.overlap ? encodeScheduleOverlapPolicy(x.overlap) : undefined,
496
502
  })),
497
503
  });
498
504
  },
@@ -32,7 +32,6 @@ import {
32
32
  CompiledScheduleUpdateOptions,
33
33
  Range,
34
34
  ScheduleOptions,
35
- ScheduleOverlapPolicy,
36
35
  ScheduleUpdateOptions,
37
36
  DayOfWeek,
38
37
  DAYS_OF_WEEK,
@@ -47,6 +46,7 @@ import {
47
46
  ScheduleExecutionActionResult,
48
47
  ScheduleExecutionResult,
49
48
  ScheduleExecutionStartWorkflowActionResult,
49
+ encodeScheduleOverlapPolicy,
50
50
  } from './schedule-types';
51
51
 
52
52
  const [encodeSecond, decodeSecond] = makeCalendarSpecFieldCoders(
@@ -192,21 +192,6 @@ export function decodeOptionalStructuredCalendarSpecs(
192
192
  );
193
193
  }
194
194
 
195
- export function encodeOverlapPolicy(input: ScheduleOverlapPolicy): temporal.api.enums.v1.ScheduleOverlapPolicy {
196
- return temporal.api.enums.v1.ScheduleOverlapPolicy[
197
- `SCHEDULE_OVERLAP_POLICY_${ScheduleOverlapPolicy[input] as keyof typeof ScheduleOverlapPolicy}`
198
- ];
199
- }
200
-
201
- export function decodeOverlapPolicy(input?: temporal.api.enums.v1.ScheduleOverlapPolicy | null): ScheduleOverlapPolicy {
202
- if (!input) return ScheduleOverlapPolicy.UNSPECIFIED;
203
- const encodedPolicyName = temporal.api.enums.v1.ScheduleOverlapPolicy[input];
204
- const decodedPolicyName = encodedPolicyName.substring(
205
- 'SCHEDULE_OVERLAP_POLICY_'.length
206
- ) as keyof typeof ScheduleOverlapPolicy;
207
- return ScheduleOverlapPolicy[decodedPolicyName];
208
- }
209
-
210
195
  export function compileScheduleOptions(options: ScheduleOptions): CompiledScheduleOptions {
211
196
  const workflowTypeOrFunc = options.action.workflowType;
212
197
  const workflowType = extractWorkflowType(workflowTypeOrFunc);
@@ -290,7 +275,7 @@ export function encodeSchedulePolicies(
290
275
  ): temporal.api.schedule.v1.ISchedulePolicies {
291
276
  return {
292
277
  catchupWindow: msOptionalToTs(policies?.catchupWindow),
293
- overlapPolicy: policies?.overlap ? encodeOverlapPolicy(policies.overlap) : undefined,
278
+ overlapPolicy: policies?.overlap ? encodeScheduleOverlapPolicy(policies.overlap) : undefined,
294
279
  pauseOnFailure: policies?.pauseOnFailure,
295
280
  };
296
281
  }
@@ -1,5 +1,6 @@
1
1
  import { checkExtends, Replace } from '@temporalio/common/lib/type-helpers';
2
2
  import { Duration, SearchAttributes, Workflow } from '@temporalio/common';
3
+ import { makeProtoEnumConverters } from '@temporalio/common/lib/internal-workflow';
3
4
  import type { temporal } from '@temporalio/proto';
4
5
  import { WorkflowStartOptions } from './workflow-options';
5
6
 
@@ -795,57 +796,69 @@ export type CompiledScheduleAction = Replace<
795
796
  /**
796
797
  * Policy for overlapping Actions.
797
798
  */
798
- export enum ScheduleOverlapPolicy {
799
- /**
800
- * Use server default (currently SKIP).
801
- *
802
- * FIXME: remove this field if this issue is implemented: https://github.com/temporalio/temporal/issues/3240
803
- */
804
- UNSPECIFIED = 0,
805
-
799
+ export const ScheduleOverlapPolicy = {
806
800
  /**
807
801
  * Don't start a new Action.
802
+ * @default
808
803
  */
809
- SKIP,
804
+ SKIP: 'SKIP',
810
805
 
811
806
  /**
812
807
  * Start another Action as soon as the current Action completes, but only buffer one Action in this way. If another
813
808
  * Action is supposed to start, but one Action is running and one is already buffered, then only the buffered one will
814
809
  * be started after the running Action finishes.
815
810
  */
816
- BUFFER_ONE,
811
+ BUFFER_ONE: 'BUFFER_ONE',
817
812
 
818
813
  /**
819
814
  * Allows an unlimited number of Actions to buffer. They are started sequentially.
820
815
  */
821
- BUFFER_ALL,
816
+ BUFFER_ALL: 'BUFFER_ALL',
822
817
 
823
818
  /**
824
819
  * Cancels the running Action, and then starts the new Action once the cancelled one completes.
825
820
  */
826
- CANCEL_OTHER,
821
+ CANCEL_OTHER: 'CANCEL_OTHER',
827
822
 
828
823
  /**
829
824
  * Terminate the running Action and start the new Action immediately.
830
825
  */
831
- TERMINATE_OTHER,
826
+ TERMINATE_OTHER: 'TERMINATE_OTHER',
832
827
 
833
828
  /**
834
829
  * Allow any number of Actions to start immediately.
835
830
  *
836
831
  * This is the only policy under which multiple Actions can run concurrently.
837
832
  */
838
- ALLOW_ALL,
839
- }
833
+ ALLOW_ALL: 'ALLOW_ALL',
840
834
 
841
- checkExtends<
835
+ /**
836
+ * Use server default (currently SKIP).
837
+ *
838
+ * @deprecated Either leave property `undefined`, or use {@link SKIP} instead.
839
+ */
840
+ UNSPECIFIED: undefined, // eslint-disable-line deprecation/deprecation
841
+ } as const;
842
+ export type ScheduleOverlapPolicy = (typeof ScheduleOverlapPolicy)[keyof typeof ScheduleOverlapPolicy];
843
+
844
+ export const [encodeScheduleOverlapPolicy, decodeScheduleOverlapPolicy] = makeProtoEnumConverters<
845
+ temporal.api.enums.v1.ScheduleOverlapPolicy,
846
+ typeof temporal.api.enums.v1.ScheduleOverlapPolicy,
842
847
  keyof typeof temporal.api.enums.v1.ScheduleOverlapPolicy,
843
- `SCHEDULE_OVERLAP_POLICY_${keyof typeof ScheduleOverlapPolicy}`
844
- >();
845
- checkExtends<
846
- `SCHEDULE_OVERLAP_POLICY_${keyof typeof ScheduleOverlapPolicy}`,
847
- keyof typeof temporal.api.enums.v1.ScheduleOverlapPolicy
848
- >();
848
+ typeof ScheduleOverlapPolicy,
849
+ 'SCHEDULE_OVERLAP_POLICY_'
850
+ >(
851
+ {
852
+ [ScheduleOverlapPolicy.SKIP]: 1,
853
+ [ScheduleOverlapPolicy.BUFFER_ONE]: 2,
854
+ [ScheduleOverlapPolicy.BUFFER_ALL]: 3,
855
+ [ScheduleOverlapPolicy.CANCEL_OTHER]: 4,
856
+ [ScheduleOverlapPolicy.TERMINATE_OTHER]: 5,
857
+ [ScheduleOverlapPolicy.ALLOW_ALL]: 6,
858
+ UNSPECIFIED: 0,
859
+ } as const,
860
+ 'SCHEDULE_OVERLAP_POLICY_'
861
+ );
849
862
 
850
863
  export interface Backfill {
851
864
  /**