@temporalio/client 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/client.ts ADDED
@@ -0,0 +1,151 @@
1
+ import { DataConverter, LoadedDataConverter } from '@temporalio/common';
2
+ import { filterNullAndUndefined, loadDataConverter } from '@temporalio/common/lib/internal-non-workflow';
3
+ import { Replace } from '@temporalio/common/lib/type-helpers';
4
+ import { temporal } from '@temporalio/proto';
5
+ import os from 'os';
6
+ import { AsyncCompletionClient } from './async-completion-client';
7
+ import { Connection } from './connection';
8
+ import { ClientInterceptors } from './interceptors';
9
+ import { ConnectionLike, Metadata, WorkflowService } from './types';
10
+ import { WorkflowClient } from './workflow-client';
11
+
12
+ export interface ClientOptions {
13
+ /**
14
+ * {@link DataConverter} to use for serializing and deserializing payloads
15
+ */
16
+ dataConverter?: DataConverter;
17
+
18
+ /**
19
+ * Used to override and extend default Connection functionality
20
+ *
21
+ * Useful for injecting auth headers and tracing Workflow executions
22
+ */
23
+ interceptors?: ClientInterceptors;
24
+
25
+ /**
26
+ * Identity to report to the server
27
+ *
28
+ * @default `${process.pid}@${os.hostname()}`
29
+ */
30
+ identity?: string;
31
+
32
+ /**
33
+ * Connection to use to communicate with the server.
34
+ *
35
+ * By default `WorkflowClient` connects to localhost.
36
+ *
37
+ * Connections are expensive to construct and should be reused.
38
+ */
39
+ connection?: ConnectionLike;
40
+
41
+ /**
42
+ * Server namespace
43
+ *
44
+ * @default default
45
+ */
46
+ namespace?: string;
47
+
48
+ workflow?: {
49
+ /**
50
+ * Should a query be rejected by closed and failed workflows
51
+ *
52
+ * @default QUERY_REJECT_CONDITION_UNSPECIFIED which means that closed and failed workflows are still queryable
53
+ */
54
+ queryRejectCondition?: temporal.api.enums.v1.QueryRejectCondition;
55
+ };
56
+ }
57
+
58
+ export type ClientOptionsWithDefaults = Replace<
59
+ Required<ClientOptions>,
60
+ {
61
+ connection?: ConnectionLike;
62
+ }
63
+ >;
64
+
65
+ export type LoadedClientOptions = ClientOptionsWithDefaults & {
66
+ loadedDataConverter: LoadedDataConverter;
67
+ };
68
+
69
+ export function defaultClientOptions(): ClientOptionsWithDefaults {
70
+ return {
71
+ dataConverter: {},
72
+ identity: `${process.pid}@${os.hostname()}`,
73
+ interceptors: {},
74
+ namespace: 'default',
75
+ workflow: {
76
+ queryRejectCondition: temporal.api.enums.v1.QueryRejectCondition.QUERY_REJECT_CONDITION_UNSPECIFIED,
77
+ },
78
+ };
79
+ }
80
+
81
+ /**
82
+ * High level SDK client.
83
+ */
84
+ export class Client {
85
+ /**
86
+ * Underlying gRPC connection to the Temporal service
87
+ */
88
+ public readonly connection: ConnectionLike;
89
+ public readonly options: LoadedClientOptions;
90
+ /**
91
+ * Workflow sub-client - use to start and interact with Workflows
92
+ */
93
+ public readonly workflow: WorkflowClient;
94
+ /**
95
+ * (Async) Activity completion sub-client - use to manually manage Activities
96
+ */
97
+ public readonly activity: AsyncCompletionClient;
98
+
99
+ constructor(options?: ClientOptions) {
100
+ this.connection = options?.connection ?? Connection.lazy();
101
+ this.options = {
102
+ ...defaultClientOptions(),
103
+ ...filterNullAndUndefined(options ?? {}),
104
+ loadedDataConverter: loadDataConverter(options?.dataConverter),
105
+ };
106
+
107
+ const { workflow, loadedDataConverter, interceptors, ...base } = this.options;
108
+
109
+ this.workflow = new WorkflowClient({
110
+ ...base,
111
+ ...workflow,
112
+ connection: this.connection,
113
+ dataConverter: loadedDataConverter,
114
+ interceptors: interceptors.workflow,
115
+ });
116
+
117
+ this.activity = new AsyncCompletionClient({
118
+ ...base,
119
+ connection: this.connection,
120
+ dataConverter: loadedDataConverter,
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Raw gRPC access to the Temporal service.
126
+ *
127
+ * **NOTE**: The namespace provided in {@link options} is **not** automatically set on requests made via this service
128
+ * object.
129
+ */
130
+ get workflowService(): WorkflowService {
131
+ return this.connection.workflowService;
132
+ }
133
+
134
+ /**
135
+ * Set the deadline for any service requests executed in `fn`'s scope.
136
+ */
137
+ async withDeadline<R>(deadline: number | Date, fn: () => Promise<R>): Promise<R> {
138
+ return await this.connection.withDeadline(deadline, fn);
139
+ }
140
+
141
+ /**
142
+ * Set metadata for any service requests executed in `fn`'s scope.
143
+ *
144
+ * @returns returned value of `fn`
145
+ *
146
+ * @see {@link Connection.withMetadata}
147
+ */
148
+ async withMetadata<R>(metadata: Metadata, fn: () => Promise<R>): Promise<R> {
149
+ return await this.connection.withMetadata(metadata, fn);
150
+ }
151
+ }
package/src/connection.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as grpc from '@grpc/grpc-js';
2
- import { filterNullAndUndefined, normalizeTlsConfig, TLSConfig } from '@temporalio/internal-non-workflow-common';
2
+ import { filterNullAndUndefined, normalizeTlsConfig, TLSConfig } from '@temporalio/common/lib/internal-non-workflow';
3
3
  import { AsyncLocalStorage } from 'async_hooks';
4
4
  import type { RPCImpl } from 'protobufjs';
5
5
  import { isServerErrorResponse, ServiceError } from './errors';
6
6
  import { defaultGrpcRetryOptions, makeGrpcRetryInterceptor } from './grpc-retry';
7
7
  import pkg from './pkg';
8
- import { CallContext, Metadata, OperatorService, WorkflowService } from './types';
8
+ import { CallContext, HealthService, Metadata, OperatorService, WorkflowService } from './types';
9
9
 
10
10
  /**
11
11
  * gRPC and Temporal Server connection options
@@ -63,7 +63,7 @@ export interface ConnectionOptions {
63
63
  * Used either when connecting eagerly with {@link Connection.connect} or
64
64
  * calling {@link Connection.ensureConnected}.
65
65
  *
66
- * @format {@link https://www.npmjs.com/package/ms | ms} formatted string
66
+ * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
67
67
  * @default 10 seconds
68
68
  */
69
69
  connectTimeout?: number | string;
@@ -146,7 +146,14 @@ export interface ConnectionCtorOptions {
146
146
  * **NOTE**: The namespace provided in {@link options} is **not** automatically set on requests made to the service.
147
147
  */
148
148
  readonly workflowService: WorkflowService;
149
+ /**
150
+ * Raw gRPC access to the Temporal {@link https://github.com/temporalio/api/blob/ddf07ab9933e8230309850e3c579e1ff34b03f53/temporal/api/operatorservice/v1/service.proto | operator service}.
151
+ */
149
152
  readonly operatorService: OperatorService;
153
+ /**
154
+ * Raw gRPC access to the standard gRPC {@link https://github.com/grpc/grpc/blob/92f58c18a8da2728f571138c37760a721c8915a2/doc/health-checking.md | health service}.
155
+ */
156
+ readonly healthService: HealthService;
150
157
  readonly callContextStorage: AsyncLocalStorage<CallContext>;
151
158
  }
152
159
 
@@ -181,6 +188,7 @@ export class Connection {
181
188
  * {@link https://github.com/temporalio/api/blob/master/temporal/api/operatorservice/v1/service.proto | Operator service}
182
189
  */
183
190
  public readonly operatorService: OperatorService;
191
+ public readonly healthService: HealthService;
184
192
  readonly callContextStorage: AsyncLocalStorage<CallContext>;
185
193
 
186
194
  protected static createCtorOptions(options?: ConnectionOptions): ConnectionCtorOptions {
@@ -214,12 +222,20 @@ export class Connection {
214
222
  interceptors: optionsWithDefaults?.interceptors,
215
223
  });
216
224
  const operatorService = OperatorService.create(operatorRpcImpl, false, false);
225
+ const healthRpcImpl = this.generateRPCImplementation({
226
+ serviceName: 'grpc.health.v1.Health',
227
+ client,
228
+ callContextStorage,
229
+ interceptors: optionsWithDefaults?.interceptors,
230
+ });
231
+ const healthService = HealthService.create(healthRpcImpl, false, false);
217
232
 
218
233
  return {
219
234
  client,
220
235
  callContextStorage,
221
236
  workflowService,
222
237
  operatorService,
238
+ healthService,
223
239
  options: optionsWithDefaults,
224
240
  };
225
241
  }
@@ -282,12 +298,14 @@ export class Connection {
282
298
  client,
283
299
  workflowService,
284
300
  operatorService,
301
+ healthService,
285
302
  callContextStorage,
286
303
  }: ConnectionCtorOptions) {
287
304
  this.options = options;
288
305
  this.client = client;
289
306
  this.workflowService = workflowService;
290
307
  this.operatorService = operatorService;
308
+ this.healthService = healthService;
291
309
  this.callContextStorage = callContextStorage;
292
310
  }
293
311
 
package/src/grpc-retry.ts CHANGED
@@ -1,37 +1,102 @@
1
- import {
2
- InterceptingCall,
3
- Interceptor,
4
- ListenerBuilder,
5
- Metadata,
6
- RequesterBuilder,
7
- StatusObject,
8
- } from '@grpc/grpc-js';
1
+ import { InterceptingCall, Interceptor, ListenerBuilder, RequesterBuilder, StatusObject } from '@grpc/grpc-js';
9
2
  import * as grpc from '@grpc/grpc-js';
10
3
 
4
+ /**
5
+ * @experimental
6
+ */
11
7
  export interface GrpcRetryOptions {
12
- /** Maximum number of allowed retries. Defaults to 10. */
13
- maxRetries: number;
14
-
15
8
  /**
16
- * A function which accepts the current retry attempt (starts at 0) and returns the millisecond
9
+ * A function which accepts the current retry attempt (starts at 1) and returns the millisecond
17
10
  * delay that should be applied before the next retry.
18
11
  */
19
- delayFunction: (attempt: number) => number;
12
+ delayFunction: (attempt: number, status: StatusObject) => number;
20
13
 
21
14
  /**
22
15
  * A function which accepts a failed status object and returns true if the call should be retried
23
16
  */
24
- retryableDecider: (status: StatusObject) => boolean;
17
+ retryableDecider: (attempt: number, status: StatusObject) => boolean;
18
+ }
19
+
20
+ /**
21
+ * Options for the backoff formula: `factor ^ attempt * initialIntervalMs(status) * jitter(maxJitter)`
22
+ *
23
+ * @experimental
24
+ */
25
+ export interface BackoffOptions {
26
+ /**
27
+ * Exponential backoff factor
28
+ *
29
+ * @default 2
30
+ */
31
+ factor: number;
32
+
33
+ /**
34
+ * Maximum number of attempts
35
+ *
36
+ * @default 10
37
+ */
38
+ maxAttempts: number;
39
+ /**
40
+ * Maximum amount of jitter to apply
41
+ *
42
+ * @default 0.1
43
+ */
44
+ maxJitter: number;
45
+ /**
46
+ * Function that returns the "initial" backoff interval based on the returned status.
47
+ *
48
+ * The default is 1 second for RESOURCE_EXHAUSTED errors and 20 millis for other retryable errors.
49
+ */
50
+ initialIntervalMs(status: StatusObject): number;
51
+
52
+ /**
53
+ * Function that returns the "maximum" backoff interval based on the returned status.
54
+ *
55
+ * The default is 10 seconds regardless of the status.
56
+ */
57
+ maxIntervalMs(status: StatusObject): number;
25
58
  }
26
59
 
27
- export function defaultGrpcRetryOptions(): GrpcRetryOptions {
60
+ /**
61
+ * Add defaults as documented in {@link BackoffOptions}
62
+ */
63
+ function withDefaultBackoffOptions({
64
+ maxAttempts,
65
+ factor,
66
+ maxJitter,
67
+ initialIntervalMs,
68
+ }: Partial<BackoffOptions>): BackoffOptions {
28
69
  return {
29
- maxRetries: 10,
30
- delayFunction: backOffAmount,
31
- retryableDecider: isRetryableError,
70
+ maxAttempts: maxAttempts ?? 10,
71
+ factor: factor ?? 2,
72
+ maxJitter: maxJitter ?? 0.1,
73
+ initialIntervalMs: initialIntervalMs ?? defaultInitialIntervalMs,
74
+ maxIntervalMs() {
75
+ return 10_000;
76
+ },
32
77
  };
33
78
  }
34
79
 
80
+ /**
81
+ * Generates the default retry behavior based on given backoff options
82
+ *
83
+ * @experimental
84
+ */
85
+ export function defaultGrpcRetryOptions(options: Partial<BackoffOptions> = {}): GrpcRetryOptions {
86
+ const { maxAttempts, factor, maxJitter, initialIntervalMs, maxIntervalMs } = withDefaultBackoffOptions(options);
87
+ return {
88
+ delayFunction(attempt, status) {
89
+ return Math.min(maxIntervalMs(status), factor ** attempt * initialIntervalMs(status)) * jitter(maxJitter);
90
+ },
91
+ retryableDecider(attempt, status) {
92
+ return attempt < maxAttempts && isRetryableError(status);
93
+ },
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Set of retryable gRPC status codes
99
+ */
35
100
  const retryableCodes = new Set([
36
101
  grpc.status.UNKNOWN,
37
102
  grpc.status.RESOURCE_EXHAUSTED,
@@ -45,69 +110,77 @@ export function isRetryableError(status: StatusObject): boolean {
45
110
  return retryableCodes.has(status.code);
46
111
  }
47
112
 
48
- /** Return backoff amount in ms */
49
- export function backOffAmount(attempt: number): number {
50
- return 2 ** attempt * 20;
113
+ /**
114
+ * Calculates random amount of jitter between 0 and `max`
115
+ */
116
+ function jitter(max: number) {
117
+ return 1 - max + Math.random() * max * 2;
118
+ }
119
+
120
+ /**
121
+ * Default implementation - backs off more on RESOURCE_EXHAUSTED errors
122
+ */
123
+ function defaultInitialIntervalMs({ code }: StatusObject) {
124
+ // Backoff more on RESOURCE_EXHAUSTED
125
+ if (code === grpc.status.RESOURCE_EXHAUSTED) {
126
+ return 1000;
127
+ }
128
+ return 20;
51
129
  }
52
130
 
53
131
  /**
54
132
  * Returns a GRPC interceptor that will perform automatic retries for some types of failed calls
55
133
  *
56
134
  * @param retryOptions Options for the retry interceptor
135
+ *
136
+ * @experimental
57
137
  */
58
138
  export function makeGrpcRetryInterceptor(retryOptions: GrpcRetryOptions): Interceptor {
59
139
  return (options, nextCall) => {
60
- let savedMetadata: Metadata;
61
140
  let savedSendMessage: any;
62
141
  let savedReceiveMessage: any;
63
- let savedMessageNext: any;
142
+ let savedMessageNext: (message: any) => void;
143
+
64
144
  const requester = new RequesterBuilder()
65
145
  .withStart(function (metadata, _listener, next) {
66
- savedMetadata = metadata;
67
- const newListener = new ListenerBuilder()
146
+ // First attempt
147
+ let attempt = 1;
148
+
149
+ const listener = new ListenerBuilder()
68
150
  .withOnReceiveMessage((message, next) => {
69
151
  savedReceiveMessage = message;
70
152
  savedMessageNext = next;
71
153
  })
72
154
  .withOnReceiveStatus((status, next) => {
73
- let retries = 0;
74
- const retry = (message: any, metadata: Metadata) => {
75
- retries++;
76
- const newCall = nextCall(options);
77
- newCall.start(metadata, {
78
- onReceiveMessage: (message) => {
155
+ const retry = () => {
156
+ attempt++;
157
+ const call = nextCall(options);
158
+ call.start(metadata, {
159
+ onReceiveMessage(message) {
79
160
  savedReceiveMessage = message;
80
161
  },
81
- onReceiveStatus: (status) => {
82
- if (retryOptions.retryableDecider(status)) {
83
- if (retries <= retryOptions.maxRetries) {
84
- setTimeout(() => retry(message, metadata), retryOptions.delayFunction(retries));
85
- } else {
86
- savedMessageNext(savedReceiveMessage);
87
- next(status);
88
- }
89
- } else {
90
- savedMessageNext(savedReceiveMessage);
91
- // TODO: For reasons that are completely unclear to me, if you pass a handcrafted
92
- // status object here, node will magically just exit at the end of this line.
93
- // No warning, no nothing. Here be dragons.
94
- next(status);
95
- }
96
- },
162
+ onReceiveStatus,
97
163
  });
98
- newCall.sendMessage(message);
99
- newCall.halfClose();
164
+ call.sendMessage(savedSendMessage);
165
+ call.halfClose();
166
+ };
167
+
168
+ const onReceiveStatus = (status: StatusObject) => {
169
+ if (retryOptions.retryableDecider(attempt, status)) {
170
+ setTimeout(retry, retryOptions.delayFunction(attempt, status));
171
+ } else {
172
+ savedMessageNext(savedReceiveMessage);
173
+ // TODO: For reasons that are completely unclear to me, if you pass a handcrafted
174
+ // status object here, node will magically just exit at the end of this line.
175
+ // No warning, no nothing. Here be dragons.
176
+ next(status);
177
+ }
100
178
  };
101
179
 
102
- if (retryOptions.retryableDecider(status)) {
103
- setTimeout(() => retry(savedSendMessage, savedMetadata), backOffAmount(retries));
104
- } else {
105
- savedMessageNext(savedReceiveMessage);
106
- next(status);
107
- }
180
+ onReceiveStatus(status);
108
181
  })
109
182
  .build();
110
- next(metadata, newListener);
183
+ next(metadata, listener);
111
184
  })
112
185
  .withSendMessage((message, next) => {
113
186
  savedSendMessage = message;
package/src/index.ts CHANGED
@@ -17,17 +17,18 @@ export {
17
17
  DataConverter,
18
18
  defaultPayloadConverter,
19
19
  ProtoFailure,
20
+ RetryPolicy,
20
21
  ServerFailure,
21
22
  TemporalFailure,
22
23
  TerminatedFailure,
23
24
  TimeoutFailure,
24
25
  } from '@temporalio/common';
25
- export { TLSConfig } from '@temporalio/internal-non-workflow-common';
26
- export { RetryPolicy } from '@temporalio/internal-workflow-common';
27
- export * from '@temporalio/internal-workflow-common/lib/errors';
28
- export * from '@temporalio/internal-workflow-common/lib/interfaces';
29
- export * from '@temporalio/internal-workflow-common/lib/workflow-handle';
26
+ export { TLSConfig } from '@temporalio/common/lib/internal-non-workflow';
27
+ export * from '@temporalio/common/lib/errors';
28
+ export * from '@temporalio/common/lib/interfaces';
29
+ export * from '@temporalio/common/lib/workflow-handle';
30
30
  export * from './async-completion-client';
31
+ export * from './client';
31
32
  export { Connection, ConnectionOptions, ConnectionOptionsWithDefaults, LOCAL_TARGET } from './connection';
32
33
  export * from './errors';
33
34
  export * from './grpc-retry';
@@ -4,7 +4,7 @@
4
4
  * @module
5
5
  */
6
6
 
7
- import { Headers, Next } from '@temporalio/internal-workflow-common';
7
+ import { Headers, Next } from '@temporalio/common';
8
8
  import { temporal } from '@temporalio/proto';
9
9
  import {
10
10
  DescribeWorkflowExecutionResponse,
@@ -112,7 +112,7 @@ export interface WorkflowClientCallsInterceptor {
112
112
  describe?: (input: WorkflowDescribeInput, next: Next<this, 'describe'>) => Promise<DescribeWorkflowExecutionResponse>;
113
113
  }
114
114
 
115
- interface WorkflowClientCallsInterceptorFactoryInput {
115
+ export interface WorkflowClientCallsInterceptorFactoryInput {
116
116
  workflowId: string;
117
117
  runId?: string;
118
118
  }
@@ -130,3 +130,12 @@ export interface WorkflowClientCallsInterceptorFactory {
130
130
  export interface WorkflowClientInterceptors {
131
131
  calls?: WorkflowClientCallsInterceptorFactory[];
132
132
  }
133
+
134
+ /**
135
+ * Interceptors for any high-level SDK client.
136
+ *
137
+ * NOTE: Currently only for {@link WorkflowClient}. More will be added later as needed.
138
+ */
139
+ export interface ClientInterceptors {
140
+ workflow?: WorkflowClientInterceptors;
141
+ }
package/src/types.ts CHANGED
@@ -1,18 +1,20 @@
1
- import type { SearchAttributes } from '@temporalio/internal-workflow-common';
2
- import { temporal } from '@temporalio/proto';
1
+ import type { SearchAttributes } from '@temporalio/common';
2
+ import * as proto from '@temporalio/proto';
3
3
  import type * as grpc from '@grpc/grpc-js';
4
- import Long from 'long';
5
4
 
6
5
  export interface WorkflowExecution {
7
6
  workflowId: string;
8
7
  runId?: string;
9
8
  }
10
- export type StartWorkflowExecutionRequest = temporal.api.workflowservice.v1.IStartWorkflowExecutionRequest;
11
- export type GetWorkflowExecutionHistoryRequest = temporal.api.workflowservice.v1.IGetWorkflowExecutionHistoryRequest;
12
- export type DescribeWorkflowExecutionResponse = temporal.api.workflowservice.v1.IDescribeWorkflowExecutionResponse;
13
- export type TerminateWorkflowExecutionResponse = temporal.api.workflowservice.v1.ITerminateWorkflowExecutionResponse;
9
+ export type StartWorkflowExecutionRequest = proto.temporal.api.workflowservice.v1.IStartWorkflowExecutionRequest;
10
+ export type GetWorkflowExecutionHistoryRequest =
11
+ proto.temporal.api.workflowservice.v1.IGetWorkflowExecutionHistoryRequest;
12
+ export type DescribeWorkflowExecutionResponse =
13
+ proto.temporal.api.workflowservice.v1.IDescribeWorkflowExecutionResponse;
14
+ export type TerminateWorkflowExecutionResponse =
15
+ proto.temporal.api.workflowservice.v1.ITerminateWorkflowExecutionResponse;
14
16
  export type RequestCancelWorkflowExecutionResponse =
15
- temporal.api.workflowservice.v1.IRequestCancelWorkflowExecutionResponse;
17
+ proto.temporal.api.workflowservice.v1.IRequestCancelWorkflowExecutionResponse;
16
18
 
17
19
  export type WorkflowExecutionStatusName =
18
20
  | 'UNSPECIFIED'
@@ -30,21 +32,23 @@ export interface WorkflowExecutionDescription {
30
32
  workflowId: string;
31
33
  runId: string;
32
34
  taskQueue: string;
33
- status: { code: temporal.api.enums.v1.WorkflowExecutionStatus; name: WorkflowExecutionStatusName };
34
- historyLength: Long;
35
+ status: { code: proto.temporal.api.enums.v1.WorkflowExecutionStatus; name: WorkflowExecutionStatusName };
36
+ historyLength: number;
35
37
  startTime: Date;
36
38
  executionTime?: Date;
37
39
  closeTime?: Date;
38
40
  memo?: Record<string, unknown>;
39
41
  searchAttributes: SearchAttributes;
40
- parentExecution?: Required<temporal.api.common.v1.IWorkflowExecution>;
42
+ parentExecution?: Required<proto.temporal.api.common.v1.IWorkflowExecution>;
41
43
  raw: DescribeWorkflowExecutionResponse;
42
44
  }
43
45
 
44
- export type WorkflowService = temporal.api.workflowservice.v1.WorkflowService;
45
- export const { WorkflowService } = temporal.api.workflowservice.v1;
46
- export type OperatorService = temporal.api.operatorservice.v1.OperatorService;
47
- export const { OperatorService } = temporal.api.operatorservice.v1;
46
+ export type WorkflowService = proto.temporal.api.workflowservice.v1.WorkflowService;
47
+ export const { WorkflowService } = proto.temporal.api.workflowservice.v1;
48
+ export type OperatorService = proto.temporal.api.operatorservice.v1.OperatorService;
49
+ export const { OperatorService } = proto.temporal.api.operatorservice.v1;
50
+ export type HealthService = proto.grpc.health.v1.Health;
51
+ export const { Health: HealthService } = proto.grpc.health.v1;
48
52
 
49
53
  /**
50
54
  * Mapping of string to valid gRPC metadata value