@temporalio/client 1.12.3 → 1.13.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.
package/src/types.ts CHANGED
@@ -74,7 +74,7 @@ export type WorkflowExecutionDescription = Replace<
74
74
  * General fixed details for this workflow execution that may appear in UI/CLI.
75
75
  * This can be in Temporal markdown format and can span multiple lines.
76
76
  *
77
- * @experimental User metadata is a new API and suspectible to change.
77
+ * @experimental User metadata is a new API and susceptible to change.
78
78
  */
79
79
  staticDetails: () => Promise<string | undefined>;
80
80
 
@@ -82,7 +82,7 @@ export type WorkflowExecutionDescription = Replace<
82
82
  * A single-line fixed summary for this workflow execution that may appear in the UI/CLI.
83
83
  * This can be in single-line Temporal markdown format.
84
84
  *
85
- * @experimental User metadata is a new API and suspectible to change.
85
+ * @experimental User metadata is a new API and susceptible to change.
86
86
  */
87
87
  staticSummary: () => Promise<string | undefined>;
88
88
  };
@@ -91,6 +91,8 @@ export type WorkflowService = proto.temporal.api.workflowservice.v1.WorkflowServ
91
91
  export const { WorkflowService } = proto.temporal.api.workflowservice.v1;
92
92
  export type OperatorService = proto.temporal.api.operatorservice.v1.OperatorService;
93
93
  export const { OperatorService } = proto.temporal.api.operatorservice.v1;
94
+ export type TestService = proto.temporal.api.testservice.v1.TestService;
95
+ export const { TestService } = proto.temporal.api.testservice.v1;
94
96
  export type HealthService = proto.grpc.health.v1.Health;
95
97
  export const { Health: HealthService } = proto.grpc.health.v1;
96
98
 
@@ -117,9 +119,6 @@ export interface CallContext {
117
119
 
118
120
  /**
119
121
  * Connection interface used by high level SDK clients.
120
- *
121
- * NOTE: Currently the SDK only supports grpc-js based connection but in the future
122
- * we might support grpc-web and native Rust connections.
123
122
  */
124
123
  export interface ConnectionLike {
125
124
  workflowService: WorkflowService;
@@ -165,6 +164,17 @@ export interface ConnectionLike {
165
164
  withAbortSignal<R>(abortSignal: AbortSignal, fn: () => Promise<R>): Promise<R>;
166
165
  }
167
166
 
167
+ export const InternalConnectionLikeSymbol = Symbol('__temporal_internal_connection_like');
168
+ export type InternalConnectionLike = ConnectionLike & {
169
+ [InternalConnectionLikeSymbol]?: {
170
+ /**
171
+ * Capability flag that determines whether the connection supports eager workflow start.
172
+ * This will only be true if the underlying connection is a {@link NativeConnection}.
173
+ */
174
+ readonly supportsEagerStart?: boolean;
175
+ };
176
+ };
177
+
168
178
  export const QueryRejectCondition = {
169
179
  NONE: 'NONE',
170
180
  NOT_OPEN: 'NOT_OPEN',
@@ -61,12 +61,15 @@ import {
61
61
  WorkflowStartUpdateOutput,
62
62
  WorkflowStartUpdateWithStartInput,
63
63
  WorkflowStartUpdateWithStartOutput,
64
+ WorkflowStartOutput,
64
65
  } from './interceptors';
65
66
  import {
66
67
  CountWorkflowExecution,
67
68
  DescribeWorkflowExecutionResponse,
68
69
  encodeQueryRejectCondition,
69
70
  GetWorkflowExecutionHistoryRequest,
71
+ InternalConnectionLike,
72
+ InternalConnectionLikeSymbol,
70
73
  QueryRejectCondition,
71
74
  RequestCancelWorkflowExecutionResponse,
72
75
  StartWorkflowExecutionRequest,
@@ -93,6 +96,8 @@ import {
93
96
  } from './base-client';
94
97
  import { mapAsyncIterable } from './iterators-utils';
95
98
  import { WorkflowUpdateStage, encodeWorkflowUpdateStage } from './workflow-update-stage';
99
+ import { InternalWorkflowStartOptionsSymbol, InternalWorkflowStartOptions } from './internal';
100
+ import { adaptWorkflowClientInterceptor } from './interceptor-adapters';
96
101
 
97
102
  const UpdateWorkflowExecutionLifecycleStage = temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage;
98
103
 
@@ -262,6 +267,15 @@ export interface WorkflowHandleWithFirstExecutionRunId<T extends Workflow = Work
262
267
  readonly firstExecutionRunId: string;
263
268
  }
264
269
 
270
+ /**
271
+ * This interface is exactly the same as {@link WorkflowHandleWithFirstExecutionRunId} except it
272
+ * includes the `eagerlyStarted` returned from {@link WorkflowClient.start}.
273
+ */
274
+ export interface WorkflowHandleWithStartDetails<T extends Workflow = Workflow>
275
+ extends WorkflowHandleWithFirstExecutionRunId<T> {
276
+ readonly eagerlyStarted: boolean;
277
+ }
278
+
265
279
  /**
266
280
  * This interface is exactly the same as {@link WorkflowHandle} except it
267
281
  * includes the `signaledRunId` returned from `signalWithStart`.
@@ -513,14 +527,19 @@ export class WorkflowClient extends BaseClient {
513
527
  workflowTypeOrFunc: string | T,
514
528
  options: WorkflowStartOptions<T>,
515
529
  interceptors: WorkflowClientInterceptor[]
516
- ): Promise<string> {
530
+ ): Promise<WorkflowStartOutput> {
517
531
  const workflowType = extractWorkflowType(workflowTypeOrFunc);
518
532
  assertRequiredWorkflowOptions(options);
519
533
  const compiledOptions = compileWorkflowOptions(ensureArgs(options));
534
+ const adaptedInterceptors = interceptors.map((i) => adaptWorkflowClientInterceptor(i));
520
535
 
521
- const start = composeInterceptors(interceptors, 'start', this._startWorkflowHandler.bind(this));
536
+ const startWithDetails = composeInterceptors(
537
+ adaptedInterceptors,
538
+ 'startWithDetails',
539
+ this._startWorkflowHandler.bind(this)
540
+ );
522
541
 
523
- return start({
542
+ return startWithDetails({
524
543
  options: compiledOptions,
525
544
  headers: {},
526
545
  workflowType,
@@ -536,7 +555,6 @@ export class WorkflowClient extends BaseClient {
536
555
  const { signal, signalArgs, ...rest } = options;
537
556
  assertRequiredWorkflowOptions(rest);
538
557
  const compiledOptions = compileWorkflowOptions(ensureArgs(rest));
539
-
540
558
  const signalWithStart = composeInterceptors(
541
559
  interceptors,
542
560
  'signalWithStart',
@@ -560,22 +578,25 @@ export class WorkflowClient extends BaseClient {
560
578
  public async start<T extends Workflow>(
561
579
  workflowTypeOrFunc: string | T,
562
580
  options: WorkflowStartOptions<T>
563
- ): Promise<WorkflowHandleWithFirstExecutionRunId<T>> {
581
+ ): Promise<WorkflowHandleWithStartDetails<T>> {
564
582
  const { workflowId } = options;
565
583
  const interceptors = this.getOrMakeInterceptors(workflowId);
566
- const runId = await this._start(workflowTypeOrFunc, { ...options, workflowId }, interceptors);
584
+ const wfStartOutput = await this._start(workflowTypeOrFunc, { ...options, workflowId }, interceptors);
567
585
  // runId is not used in handles created with `start*` calls because these
568
586
  // handles should allow interacting with the workflow if it continues as new.
569
- const handle = this._createWorkflowHandle({
587
+ const baseHandle = this._createWorkflowHandle({
570
588
  workflowId,
571
589
  runId: undefined,
572
- firstExecutionRunId: runId,
573
- runIdForResult: runId,
590
+ firstExecutionRunId: wfStartOutput.runId,
591
+ runIdForResult: wfStartOutput.runId,
574
592
  interceptors,
575
593
  followRuns: options.followRuns ?? true,
576
- }) as WorkflowHandleWithFirstExecutionRunId<T>; // Cast is safe because we know we add the firstExecutionRunId below
577
- (handle as any) /* readonly */.firstExecutionRunId = runId;
578
- return handle;
594
+ });
595
+ return {
596
+ ...baseHandle,
597
+ firstExecutionRunId: wfStartOutput.runId,
598
+ eagerlyStarted: wfStartOutput.eagerlyStarted,
599
+ };
579
600
  }
580
601
 
581
602
  /**
@@ -1245,11 +1266,19 @@ export class WorkflowClient extends BaseClient {
1245
1266
  *
1246
1267
  * Used as the final function of the start interceptor chain
1247
1268
  */
1248
- protected async _startWorkflowHandler(input: WorkflowStartInput): Promise<string> {
1269
+ protected async _startWorkflowHandler(input: WorkflowStartInput): Promise<WorkflowStartOutput> {
1249
1270
  const req = await this.createStartWorkflowRequest(input);
1250
1271
  const { options: opts, workflowType } = input;
1272
+ const internalOptions = (opts as InternalWorkflowStartOptions)[InternalWorkflowStartOptionsSymbol];
1251
1273
  try {
1252
- return (await this.workflowService.startWorkflowExecution(req)).runId;
1274
+ const response = await this.workflowService.startWorkflowExecution(req);
1275
+ if (internalOptions != null) {
1276
+ internalOptions.backLink = response.link ?? undefined;
1277
+ }
1278
+ return {
1279
+ runId: response.runId,
1280
+ eagerlyStarted: response.eagerWorkflowTask != null,
1281
+ };
1253
1282
  } catch (err: any) {
1254
1283
  if (err.code === grpcStatus.ALREADY_EXISTS) {
1255
1284
  throw new WorkflowExecutionAlreadyStartedError(
@@ -1265,10 +1294,21 @@ export class WorkflowClient extends BaseClient {
1265
1294
  protected async createStartWorkflowRequest(input: WorkflowStartInput): Promise<StartWorkflowExecutionRequest> {
1266
1295
  const { options: opts, workflowType, headers } = input;
1267
1296
  const { identity, namespace } = this.options;
1297
+ const internalOptions = (opts as InternalWorkflowStartOptions)[InternalWorkflowStartOptionsSymbol];
1298
+ const supportsEagerStart = (this.connection as InternalConnectionLike)?.[InternalConnectionLikeSymbol]
1299
+ ?.supportsEagerStart;
1300
+
1301
+ if (opts.requestEagerStart && !supportsEagerStart) {
1302
+ throw new Error(
1303
+ 'Eager workflow start requires a NativeConnection shared between client and worker. ' +
1304
+ 'Pass a NativeConnection via ClientOptions.connection, or disable requestEagerStart.'
1305
+ );
1306
+ }
1307
+
1268
1308
  return {
1269
1309
  namespace,
1270
1310
  identity,
1271
- requestId: uuid4(),
1311
+ requestId: internalOptions?.requestId ?? uuid4(),
1272
1312
  workflowId: opts.workflowId,
1273
1313
  workflowIdReusePolicy: encodeWorkflowIdReusePolicy(opts.workflowIdReusePolicy),
1274
1314
  workflowIdConflictPolicy: encodeWorkflowIdConflictPolicy(opts.workflowIdConflictPolicy),
@@ -1295,6 +1335,8 @@ export class WorkflowClient extends BaseClient {
1295
1335
  userMetadata: await encodeUserMetadata(this.dataConverter, opts.staticSummary, opts.staticDetails),
1296
1336
  priority: opts.priority ? compilePriority(opts.priority) : undefined,
1297
1337
  versioningOverride: opts.versioningOverride ?? undefined,
1338
+ requestEagerExecution: opts.requestEagerStart,
1339
+ ...filterNullAndUndefined(internalOptions ?? {}),
1298
1340
  };
1299
1341
  }
1300
1342
 
@@ -54,6 +54,12 @@ export interface WorkflowOptions extends CommonWorkflowOptions {
54
54
  * @experimental Deployment based versioning is experimental and may change in the future.
55
55
  */
56
56
  versioningOverride?: VersioningOverride;
57
+
58
+ /**
59
+ * Potentially reduce the latency to start this workflow by requesting that the server
60
+ * start it on a local worker running with this same client.
61
+ */
62
+ requestEagerStart?: boolean;
57
63
  }
58
64
 
59
65
  export type WithCompiledWorkflowOptions<T extends WorkflowOptions> = Replace<
@@ -97,7 +103,8 @@ export type WorkflowSignalWithStartOptions<SignalArgs extends any[] = []> = Sign
97
103
  ? WorkflowSignalWithStartOptionsWithArgs<SignalArgs>
98
104
  : WorkflowSignalWithStartOptionsWithoutArgs<SignalArgs>;
99
105
 
100
- export interface WorkflowSignalWithStartOptionsWithoutArgs<SignalArgs extends any[]> extends WorkflowOptions {
106
+ export interface WorkflowSignalWithStartOptionsWithoutArgs<SignalArgs extends any[]>
107
+ extends Omit<WorkflowOptions, 'requestEagerStart'> {
101
108
  /**
102
109
  * SignalDefinition or name of signal
103
110
  */
@@ -109,7 +116,8 @@ export interface WorkflowSignalWithStartOptionsWithoutArgs<SignalArgs extends an
109
116
  signalArgs?: SignalArgs;
110
117
  }
111
118
 
112
- export interface WorkflowSignalWithStartOptionsWithArgs<SignalArgs extends any[]> extends WorkflowOptions {
119
+ export interface WorkflowSignalWithStartOptionsWithArgs<SignalArgs extends any[]>
120
+ extends Omit<WorkflowOptions, 'requestEagerStart'> {
113
121
  /**
114
122
  * SignalDefinition or name of signal
115
123
  */