@temporalio/nexus 1.17.3 → 1.17.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.
package/lib/context.d.ts CHANGED
@@ -15,6 +15,7 @@ export interface HandlerContext {
15
15
  client: Client;
16
16
  namespace: string;
17
17
  taskQueue: string;
18
+ endpoint: string;
18
19
  }
19
20
  /**
20
21
  * Holds information about the current Nexus Operation Execution.
@@ -30,6 +31,11 @@ export interface OperationInfo {
30
31
  * Task Queue this Nexus Operation is executing on
31
32
  */
32
33
  readonly taskQueue: string;
34
+ /**
35
+ * Nexus Endpoint this Operation was routed through.
36
+ * Only available with server version 1.30.0 or later.
37
+ */
38
+ readonly endpoint: string;
33
39
  }
34
40
  /**
35
41
  * A logger for use in Nexus Handler scope.
package/lib/context.js CHANGED
@@ -96,6 +96,7 @@ function operationInfo() {
96
96
  return {
97
97
  namespace: ctx.namespace,
98
98
  taskQueue: ctx.taskQueue,
99
+ endpoint: ctx.endpoint,
99
100
  };
100
101
  }
101
102
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temporalio/nexus",
3
- "version": "1.17.3",
3
+ "version": "1.17.4",
4
4
  "description": "Temporal.io SDK Nexus sub-package",
5
5
  "main": "lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -17,15 +17,15 @@
17
17
  "concurrency": 1,
18
18
  "workerThreads": false
19
19
  },
20
+ "devDependencies": {
21
+ "ava": "^5.3.1"
22
+ },
20
23
  "dependencies": {
21
24
  "long": "^5.2.3",
22
25
  "nexus-rpc": "^0.0.2",
23
- "@temporalio/proto": "1.17.3",
24
- "@temporalio/common": "1.17.3",
25
- "@temporalio/client": "1.17.3"
26
- },
27
- "devDependencies": {
28
- "ava": "^5.3.1"
26
+ "@temporalio/client": "1.17.4",
27
+ "@temporalio/common": "1.17.4",
28
+ "@temporalio/proto": "1.17.4"
29
29
  },
30
30
  "bugs": {
31
31
  "url": "https://github.com/temporalio/sdk-typescript/issues"
package/src/context.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
- import type * as nexus from 'nexus-rpc';
3
2
  import type { Logger, LogLevel, LogMetadata, MetricMeter } from '@temporalio/common';
4
3
  import type { Client } from '@temporalio/client';
5
4
 
@@ -58,24 +57,6 @@ export interface OperationInfo {
58
57
  readonly endpoint: string;
59
58
  }
60
59
 
61
- /**
62
- * Context received by a {@link TemporalOperationHandler}'s start handler when a Nexus Operation is
63
- * started.
64
- *
65
- * @experimental Nexus support in Temporal SDK is experimental.
66
- */
67
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
68
- export interface TemporalStartOperationContext extends nexus.StartOperationContext {}
69
-
70
- /**
71
- * Context received by a {@link TemporalOperationHandler}'s cancel handler when a Nexus Operation is
72
- * canceled.
73
- *
74
- * @experimental Nexus support in Temporal SDK is experimental.
75
- */
76
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
77
- export interface TemporalCancelOperationContext extends nexus.CancelOperationContext {}
78
-
79
60
  // Basic APIs //////////////////////////////////////////////////////////////////////////////////////
80
61
 
81
62
  /**
package/src/index.ts CHANGED
@@ -11,18 +11,10 @@ export {
11
11
  metricMeter,
12
12
  operationInfo,
13
13
  type OperationInfo,
14
- type TemporalCancelOperationContext,
15
- type TemporalStartOperationContext,
16
14
  } from './context';
17
15
 
18
16
  export {
19
17
  startWorkflow,
20
- type CancelWorkflowRunOptions,
21
- type TemporalOperationHandlerOptions,
22
- TemporalOperationHandler,
23
- TemporalOperationResult,
24
- type TemporalNexusClient,
25
- type TemporalOperationStartHandler,
26
18
  WorkflowHandle,
27
19
  WorkflowRunOperationHandler,
28
20
  WorkflowRunOperationStartHandler,
@@ -3,9 +3,7 @@ import type { Link as NexusLink } from 'nexus-rpc';
3
3
  import { temporal } from '@temporalio/proto';
4
4
 
5
5
  const { EventType } = temporal.api.enums.v1;
6
- type TemporalLink = temporal.api.common.v1.ILink;
7
6
  type WorkflowEventLink = temporal.api.common.v1.Link.IWorkflowEvent;
8
- type NexusOperationLink = temporal.api.common.v1.Link.INexusOperation;
9
7
  type EventReference = temporal.api.common.v1.Link.WorkflowEvent.IEventReference;
10
8
  type RequestIdReference = temporal.api.common.v1.Link.WorkflowEvent.IRequestIdReference;
11
9
 
@@ -13,46 +11,12 @@ const LINK_EVENT_ID_PARAM = 'eventID';
13
11
  const LINK_EVENT_TYPE_PARAM = 'eventType';
14
12
  const LINK_REQUEST_ID_PARAM = 'requestID';
15
13
  const LINK_REFERENCE_TYPE_KEY = 'referenceType';
16
- const LINK_RUN_ID_KEY = 'runID';
17
14
 
18
15
  const EVENT_REFERENCE_TYPE = 'EventReference';
19
16
  const REQUEST_ID_REFERENCE_TYPE = 'RequestIdReference';
20
17
 
21
18
  // fullName isn't part of the generated typed unfortunately.
22
19
  const WORKFLOW_EVENT_TYPE: string = (temporal.api.common.v1.Link.WorkflowEvent as any).fullName.slice(1);
23
- const NEXUS_OPERATION_TYPE: string = (temporal.api.common.v1.Link.NexusOperation as any).fullName.slice(1);
24
-
25
- export function convertTemporalLinkToNexusLink(link: TemporalLink): NexusLink {
26
- if (link.workflowEvent != null) {
27
- return convertWorkflowEventLinkToNexusLink(link.workflowEvent);
28
- }
29
-
30
- if (link.nexusOperation != null) {
31
- return convertNexusOperationLinkToNexusLink(link.nexusOperation);
32
- }
33
-
34
- throw new TypeError('Invalid Temporal link: unknown variant');
35
- }
36
-
37
- export function convertNexusLinkToTemporalLink(link: NexusLink): TemporalLink {
38
- if (link.url.protocol !== 'temporal:') {
39
- throw new TypeError(`Invalid URL scheme: ${link.url}, expected 'temporal:', got '${link.url.protocol}'`);
40
- }
41
- switch (link.type) {
42
- case WORKFLOW_EVENT_TYPE:
43
- return {
44
- workflowEvent: convertNexusLinkToWorkflowEventLink(link),
45
- };
46
-
47
- case NEXUS_OPERATION_TYPE:
48
- return {
49
- nexusOperation: convertNexusLinkToNexusOperationLink(link),
50
- };
51
-
52
- default:
53
- throw new TypeError(`Unknown link type: ${link.type}`);
54
- }
55
- }
56
20
 
57
21
  export function convertWorkflowEventLinkToNexusLink(we: WorkflowEventLink): NexusLink {
58
22
  if (!we.namespace || !we.workflowId || !we.runId) {
@@ -76,30 +40,11 @@ export function convertWorkflowEventLinkToNexusLink(we: WorkflowEventLink): Nexu
76
40
  };
77
41
  }
78
42
 
79
- export function convertNexusOperationLinkToNexusLink(opLink: NexusOperationLink): NexusLink {
80
- if (!opLink.namespace || !opLink.operationId) {
81
- throw new TypeError('Missing required fields: namespace, or operationId');
82
- }
83
-
84
- const url = new URL(
85
- `temporal:///namespaces/${encodeURIComponent(opLink.namespace)}/nexus-operations/${encodeURIComponent(
86
- opLink.operationId
87
- )}`
88
- );
89
-
90
- if (opLink.runId != null) {
91
- const searchParams = new URLSearchParams();
92
- searchParams.set(LINK_RUN_ID_KEY, opLink.runId);
93
- url.search = searchParams.toString();
43
+ export function convertNexusLinkToWorkflowEventLink(link: NexusLink): WorkflowEventLink {
44
+ if (link.url.protocol !== 'temporal:') {
45
+ throw new TypeError(`Invalid URL scheme: ${link.url}, expected 'temporal:', got '${link.url.protocol}'`);
94
46
  }
95
47
 
96
- return {
97
- url,
98
- type: NEXUS_OPERATION_TYPE,
99
- };
100
- }
101
-
102
- export function convertNexusLinkToWorkflowEventLink(link: NexusLink): WorkflowEventLink {
103
48
  // /namespaces/:namespace/workflows/:workflowId/:runId/history
104
49
  const parts = link.url.pathname.split('/');
105
50
  if (parts.length !== 7 || parts[1] !== 'namespaces' || parts[3] !== 'workflows' || parts[6] !== 'history') {
@@ -131,25 +76,6 @@ export function convertNexusLinkToWorkflowEventLink(link: NexusLink): WorkflowEv
131
76
  return workflowEventLink;
132
77
  }
133
78
 
134
- function convertNexusLinkToNexusOperationLink(link: NexusLink): NexusOperationLink {
135
- // /namespaces/:namespace/nexus-operations/:operationId?runId=:runId
136
- const parts = link.url.pathname.split('/');
137
- if (parts.length !== 5 || parts[1] !== 'namespaces' || parts[3] !== 'nexus-operations') {
138
- throw new TypeError(`Invalid URL path: ${link.url}`);
139
- }
140
- const namespace = decodeURIComponent(parts[2]!);
141
- const operationId = decodeURIComponent(parts[4]!);
142
-
143
- const query = link.url.searchParams;
144
- const runId = query.get(LINK_RUN_ID_KEY);
145
-
146
- return {
147
- namespace,
148
- operationId,
149
- runId,
150
- };
151
- }
152
-
153
79
  function convertLinkWorkflowEventEventReferenceToURLQuery(eventRef: EventReference): string {
154
80
  const params = new URLSearchParams();
155
81
  params.set(LINK_REFERENCE_TYPE_KEY, EVENT_REFERENCE_TYPE);
package/src/token.ts CHANGED
@@ -1,57 +1,39 @@
1
1
  /**
2
- * Serializable token identifying a Nexus operation target.
2
+ * OperationTokenType is used to identify the type of Operation token.
3
+ * Currently, we only have one type of Operation token: WorkflowRun.
3
4
  *
4
5
  * @internal
5
6
  * @hidden
6
7
  */
7
- export interface OperationToken {
8
+ export interface WorkflowRunOperationToken {
8
9
  /**
9
- * Version of the token, by default we assume we're on version 0, this field is not emitted as part of the output,
10
+ * Version of the token, by default we assume we're on version 1, this field is not emitted as part of the output,
10
11
  * it's only used to reject newer token versions on load.
11
12
  */
12
13
  v?: number;
13
14
 
14
15
  /**
15
- * Type of the Operation.
16
+ * Type of the Operation. Must be OPERATION_TOKEN_TYPE_WORKFLOW_RUN.
16
17
  */
17
18
  t: OperationTokenType;
18
19
 
19
20
  /**
20
- * Namespace of the operation.
21
+ * Namespace of the workflow.
21
22
  */
22
23
  ns: string;
23
24
 
24
25
  /**
25
26
  * ID of the workflow.
26
27
  */
27
- wid?: string;
28
- }
29
-
30
- /**
31
- * An OperationToken that identifies a WorkflowRun operation.
32
- *
33
- * @internal
34
- * @hidden
35
- */
36
- export interface WorkflowRunOperationToken extends OperationToken {
37
- t: typeof OperationTokenType.WORKFLOW_RUN;
38
28
  wid: string;
39
29
  }
40
-
41
- /**
42
- * OperationTokenType is used to identify the type of Operation token.
43
- * Currently, we only have one type of Operation token: WorkflowRun.
44
- *
45
- * @internal
46
- * @hidden
47
- */
48
- export type OperationTokenType = (typeof OperationTokenType)[keyof typeof OperationTokenType];
30
+ type OperationTokenType = (typeof OperationTokenType)[keyof typeof OperationTokenType];
49
31
 
50
32
  /**
51
33
  * @internal
52
34
  * @hidden
53
35
  */
54
- export const OperationTokenType = {
36
+ const OperationTokenType = {
55
37
  WORKFLOW_RUN: 1,
56
38
  } as const;
57
39
 
@@ -68,11 +50,11 @@ export function generateWorkflowRunOperationToken(namespace: string, workflowId:
68
50
  }
69
51
 
70
52
  /**
71
- * Load and validate the common fields of an Operation token.
53
+ * Load and validate a workflow run Operation token.
72
54
  */
73
- export function loadOperationToken(data: string): OperationToken {
55
+ export function loadWorkflowRunOperationToken(data: string): WorkflowRunOperationToken {
74
56
  if (!data) {
75
- throw new TypeError('invalid operation token: token is empty');
57
+ throw new TypeError('invalid workflow run token: token is empty');
76
58
  }
77
59
 
78
60
  let decoded: string;
@@ -82,55 +64,24 @@ export function loadOperationToken(data: string): OperationToken {
82
64
  throw new TypeError('failed to decode token', { cause: err });
83
65
  }
84
66
 
85
- let token: OperationToken;
67
+ let token: WorkflowRunOperationToken;
86
68
  try {
87
69
  token = JSON.parse(decoded);
88
70
  } catch (err) {
89
- throw new TypeError('failed to unmarshal Operation token', { cause: err });
90
- }
91
-
92
- if (typeof token !== 'object' || token == null) {
93
- throw new TypeError(`invalid operation token: expected object, got ${typeof token}`);
94
- }
95
- if (token.v !== undefined && token.v !== 0) {
96
- throw new TypeError('invalid operation token: "v" field should not be present');
97
- }
98
- if (typeof token.t !== 'number') {
99
- throw new TypeError(`invalid operation token: expected token type to be a number, got ${typeof token.t}`);
100
- }
101
- if (!isOperationTokenType(token.t)) {
102
- throw new TypeError(`invalid operation token: unknown token type: ${token.t}`);
103
- }
104
- if (typeof token.ns !== 'string') {
105
- throw new TypeError(`invalid operation token: expected namespace to be a string, got ${typeof token.ns}`);
71
+ throw new TypeError('failed to unmarshal workflow run Operation token', { cause: err });
106
72
  }
107
73
 
108
- return token;
109
- }
110
-
111
- /**
112
- * Load and validate a workflow run Operation token.
113
- */
114
- export function loadWorkflowRunOperationToken(data: string): WorkflowRunOperationToken {
115
- const token = loadOperationToken(data);
116
- assertWorkflowRunOperationToken(token);
117
- return token;
118
- }
119
-
120
- /**
121
- * Assert that an OperationToken identifies a workflow run.
122
- */
123
- export function assertWorkflowRunOperationToken(token: OperationToken): asserts token is WorkflowRunOperationToken {
124
74
  if (token.t !== OperationTokenType.WORKFLOW_RUN) {
125
75
  throw new TypeError(`invalid workflow token type: ${token.t}, expected: ${OperationTokenType.WORKFLOW_RUN}`);
126
76
  }
127
- if (!token.wid || typeof token.wid !== 'string') {
77
+ if (token.v !== undefined && token.v !== 0) {
78
+ throw new TypeError('invalid workflow run token: "v" field should not be present');
79
+ }
80
+ if (!token.wid) {
128
81
  throw new TypeError('invalid workflow run token: missing workflow ID (wid)');
129
82
  }
130
- }
131
83
 
132
- function isOperationTokenType(value: number): value is OperationTokenType {
133
- return Object.values(OperationTokenType).includes(value as OperationTokenType);
84
+ return token;
134
85
  }
135
86
 
136
87
  // Exported for use in tests.
@@ -1,25 +1,13 @@
1
1
  import * as nexus from 'nexus-rpc';
2
2
  import type { Workflow, WorkflowResultType } from '@temporalio/common';
3
3
  import type { Replace } from '@temporalio/common/lib/type-helpers';
4
- import type { Client, WorkflowStartOptions as ClientWorkflowStartOptions } from '@temporalio/client';
4
+ import type { WorkflowStartOptions as ClientWorkflowStartOptions } from '@temporalio/client';
5
5
  import { type temporal } from '@temporalio/proto';
6
6
  import type { InternalWorkflowStartOptions } from '@temporalio/client/lib/internal';
7
7
  import { InternalWorkflowStartOptionsSymbol } from '@temporalio/client/lib/internal';
8
- import { convertNexusLinkToTemporalLink, convertTemporalLinkToNexusLink } from './link-converter';
9
- import {
10
- assertWorkflowRunOperationToken,
11
- generateWorkflowRunOperationToken,
12
- loadOperationToken,
13
- loadWorkflowRunOperationToken,
14
- OperationTokenType,
15
- } from './token';
16
- import {
17
- getClient,
18
- getHandlerContext,
19
- log,
20
- type TemporalCancelOperationContext,
21
- type TemporalStartOperationContext,
22
- } from './context';
8
+ import { generateWorkflowRunOperationToken, loadWorkflowRunOperationToken } from './token';
9
+ import { convertNexusLinkToWorkflowEventLink, convertWorkflowEventLinkToNexusLink } from './link-converter';
10
+ import { getClient, getHandlerContext, log } from './context';
23
11
 
24
12
  declare const isNexusWorkflowHandle: unique symbol;
25
13
  declare const workflowResultType: unique symbol;
@@ -89,7 +77,9 @@ export async function startWorkflow<T extends Workflow>(
89
77
  if (ctx.inboundLinks?.length > 0) {
90
78
  for (const l of ctx.inboundLinks) {
91
79
  try {
92
- links.push(convertNexusLinkToTemporalLink(l));
80
+ links.push({
81
+ workflowEvent: convertNexusLinkToWorkflowEventLink(l),
82
+ });
93
83
  } catch (error) {
94
84
  log.warn('failed to convert Nexus link to Workflow event link', { error });
95
85
  }
@@ -106,17 +96,10 @@ export async function startWorkflow<T extends Workflow>(
106
96
  attachRequestId: true,
107
97
  };
108
98
 
109
- // Add nexus-operation-token header to solve for race between Workflow completion
110
- // and Nexus Operation start recording
111
- const callbackHeaders = {
112
- ...ctx.callbackHeaders,
113
- 'nexus-operation-token': generateWorkflowRunOperationToken(client.options.namespace, workflowOptions.workflowId),
114
- };
115
-
116
99
  if (ctx.callbackUrl) {
117
100
  internalOptions.completionCallbacks = [
118
101
  {
119
- nexus: { url: ctx.callbackUrl, header: callbackHeaders },
102
+ nexus: { url: ctx.callbackUrl, header: ctx.callbackHeaders },
120
103
  links, // pass in links here as well for older servers, newer servers dedupe them.
121
104
  },
122
105
  ];
@@ -130,11 +113,11 @@ export async function startWorkflow<T extends Workflow>(
130
113
  };
131
114
 
132
115
  const handle = await client.workflow.start(workflowTypeOrFunc, startOptions);
133
- if (internalOptions.backLink != null) {
116
+ if (internalOptions.backLink?.workflowEvent != null) {
134
117
  try {
135
- ctx.outboundLinks.push(convertTemporalLinkToNexusLink(internalOptions.backLink));
118
+ ctx.outboundLinks.push(convertWorkflowEventLinkToNexusLink(internalOptions.backLink.workflowEvent));
136
119
  } catch (error) {
137
- log.warn('failed to convert temporal link to Nexus link', { error });
120
+ log.warn('failed to convert Workflow event link to Nexus link', { error });
138
121
  }
139
122
  }
140
123
 
@@ -173,188 +156,3 @@ export class WorkflowRunOperationHandler<I, O> implements nexus.OperationHandler
173
156
  await getClient().workflow.getHandle(decoded.wid).cancel();
174
157
  }
175
158
  }
176
-
177
- /**
178
- * Module-private brand and payload key for {@link TemporalOperationResult}.
179
- */
180
- const operationResult: unique symbol = Symbol('temporal_nexus_TemporalOperationResult');
181
-
182
- /**
183
- * A result produced by a {@link TemporalOperationHandler}. Construct via
184
- * {@link TemporalOperationResult.sync} or {@link TemporalOperationResult.async}.
185
-
186
- * @experimental Nexus support in Temporal SDK is experimental.
187
- */
188
- export interface TemporalOperationResult<T> {
189
- readonly [operationResult]: nexus.HandlerStartOperationResult<T>;
190
- }
191
-
192
- export const TemporalOperationResult = {
193
- sync<T>(value: T): TemporalOperationResult<T> {
194
- return {
195
- [operationResult]: nexus.HandlerStartOperationResult.sync(value),
196
- };
197
- },
198
-
199
- async<T = unknown>(token: string): TemporalOperationResult<T> {
200
- return {
201
- [operationResult]: nexus.HandlerStartOperationResult.async(token),
202
- };
203
- },
204
- };
205
-
206
- /**
207
- * A Nexus-aware Temporal Client for use inside {@link TemporalOperationHandler} implementations.
208
- *
209
- * @experimental Nexus support in Temporal SDK is experimental.
210
- */
211
- export interface TemporalNexusClient {
212
- /**
213
- * The Temporal Client for the active Nexus Operation.
214
- *
215
- * @experimental Nexus support in Temporal SDK is experimental.
216
- */
217
- readonly client: Client;
218
-
219
- /**
220
- * Starts a workflow run as the asynchronous backing operation for the current Nexus Operation.
221
- *
222
- * @experimental Nexus support in Temporal SDK is experimental.
223
- */
224
- startWorkflow<T extends Workflow>(
225
- workflowTypeOrFunc: string | T,
226
- workflowOptions: WorkflowStartOptions<T>
227
- ): Promise<TemporalOperationResult<WorkflowResultType<T>>>;
228
- }
229
-
230
- class TemporalNexusClientImpl implements TemporalNexusClient {
231
- private asyncOperationStarted = false;
232
-
233
- constructor(private readonly startOperationContext: TemporalStartOperationContext) {}
234
-
235
- /**
236
- * The Temporal Client for the active Nexus Operation.
237
- *
238
- * @experimental Nexus support in Temporal SDK is experimental.
239
- */
240
- public get client(): Client {
241
- return getClient();
242
- }
243
-
244
- /**
245
- * Starts a workflow run as the asynchronous backing operation for the current Nexus Operation.
246
- *
247
- * @experimental Nexus support in Temporal SDK is experimental.
248
- */
249
- public async startWorkflow<T extends Workflow>(
250
- workflowTypeOrFunc: string | T,
251
- workflowOptions: WorkflowStartOptions<T>
252
- ): Promise<TemporalOperationResult<WorkflowResultType<T>>> {
253
- return await this.withAsyncOperationStartReservation(async () => {
254
- const handle = await startWorkflow(this.startOperationContext, workflowTypeOrFunc, workflowOptions);
255
- const { namespace } = getHandlerContext();
256
- return TemporalOperationResult.async(generateWorkflowRunOperationToken(namespace, handle.workflowId));
257
- });
258
- }
259
-
260
- private async withAsyncOperationStartReservation<T>(fn: () => Promise<T>): Promise<T> {
261
- if (this.asyncOperationStarted) {
262
- throw new nexus.HandlerError(
263
- 'BAD_REQUEST',
264
- 'Only one async operation can be started per operation handler invocation. Use TemporalNexusClient.client for additional workflow interactions'
265
- );
266
- }
267
-
268
- this.asyncOperationStarted = true;
269
- try {
270
- return await fn();
271
- } catch (err) {
272
- this.asyncOperationStarted = false;
273
- throw err;
274
- }
275
- }
276
- }
277
-
278
- /**
279
- * A handler function for the {@link TemporalOperationHandler} constructor.
280
- *
281
- * @experimental Nexus support in Temporal SDK is experimental.
282
- */
283
- export type TemporalOperationStartHandler<I, O> = (
284
- ctx: TemporalStartOperationContext,
285
- client: TemporalNexusClient,
286
- input: I
287
- ) => Promise<TemporalOperationResult<O>>;
288
-
289
- /**
290
- * Options passed to a {@link TemporalOperationHandlerOptions.cancelWorkflowRun} handler describing
291
- * the workflow run to cancel.
292
- *
293
- * @experimental Nexus support in Temporal SDK is experimental.
294
- */
295
- export interface CancelWorkflowRunOptions {
296
- /**
297
- * The ID of the workflow backing the Nexus Operation that is being canceled.
298
- */
299
- readonly workflowId: string;
300
- }
301
-
302
- /**
303
- * Options for customizing a {@link TemporalOperationHandler}.
304
- *
305
- * @experimental Nexus support in Temporal SDK is experimental.
306
- */
307
- export interface TemporalOperationHandlerOptions {
308
- cancelWorkflowRun?: (ctx: TemporalCancelOperationContext, options: CancelWorkflowRunOptions) => Promise<void>;
309
- }
310
-
311
- /**
312
- * A Nexus Operation implementation for operations that interact with Temporal.
313
- *
314
- * @experimental Nexus support in Temporal SDK is experimental.
315
- */
316
- export class TemporalOperationHandler<I, O> implements nexus.OperationHandler<I, O> {
317
- private readonly startHandler: TemporalOperationStartHandler<I, O>;
318
- private readonly cancelWorkflowRunHandler: NonNullable<TemporalOperationHandlerOptions['cancelWorkflowRun']>;
319
-
320
- constructor(options: { start: TemporalOperationStartHandler<I, O> } & TemporalOperationHandlerOptions) {
321
- this.startHandler = options.start;
322
- this.cancelWorkflowRunHandler = options.cancelWorkflowRun ?? defaultCancelWorkflowRun;
323
- }
324
-
325
- async start(ctx: nexus.StartOperationContext, input: I): Promise<nexus.HandlerStartOperationResult<O>> {
326
- const result = await this.startHandler(ctx, new TemporalNexusClientImpl(ctx), input);
327
- return result[operationResult];
328
- }
329
-
330
- async cancel(ctx: nexus.CancelOperationContext, token: string): Promise<void> {
331
- let opToken;
332
- try {
333
- opToken = loadOperationToken(token);
334
- } catch (err) {
335
- throw new nexus.HandlerError(nexus.HandlerErrorType.BAD_REQUEST, 'invalid operation token', { cause: err });
336
- }
337
-
338
- switch (opToken.t) {
339
- case OperationTokenType.WORKFLOW_RUN:
340
- try {
341
- assertWorkflowRunOperationToken(opToken);
342
- } catch (err) {
343
- throw new nexus.HandlerError(nexus.HandlerErrorType.BAD_REQUEST, 'invalid workflow run operation token', {
344
- cause: err,
345
- });
346
- }
347
- await this.cancelWorkflowRunHandler(ctx, { workflowId: opToken.wid });
348
- return;
349
- default:
350
- throw new nexus.HandlerError(
351
- nexus.HandlerErrorType.BAD_REQUEST,
352
- `Unsupported operation token type: ${opToken.t}`
353
- );
354
- }
355
- }
356
- }
357
-
358
- async function defaultCancelWorkflowRun(_ctx: TemporalCancelOperationContext, options: CancelWorkflowRunOptions) {
359
- await getClient().workflow.getHandle(options.workflowId).cancel();
360
- }