@temporalio/workflow 1.4.4 → 1.5.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/lib/internals.js CHANGED
@@ -1,23 +1,10 @@
1
1
  "use strict";
2
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
- };
7
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
- if (kind === "m") throw new TypeError("Private method is not writable");
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
- };
13
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
4
  };
16
- var _State_now;
17
5
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.consumeCompletion = exports.maybeConsumeCompletion = exports.handleWorkflowFailure = exports.state = exports.State = exports.Activator = exports.LocalActivityDoBackoff = void 0;
6
+ exports.getActivator = exports.Activator = exports.LATEST_INTERNAL_PATCH_NUMBER = exports.LocalActivityDoBackoff = void 0;
19
7
  const common_1 = require("@temporalio/common");
20
- const common_2 = require("@temporalio/common");
21
8
  const interceptors_1 = require("@temporalio/common/lib/interceptors");
22
9
  const type_helpers_1 = require("@temporalio/common/lib/type-helpers");
23
10
  const alea_1 = require("./alea");
@@ -43,14 +30,214 @@ class LocalActivityDoBackoff {
43
30
  }
44
31
  }
45
32
  exports.LocalActivityDoBackoff = LocalActivityDoBackoff;
33
+ /**
34
+ * SDK Internal Patches are created by the SDK to avoid breaking history when behaviour
35
+ * of existing API need to be modified. This is the patch number supported by the current
36
+ * version of the SDK.
37
+ *
38
+ * History:
39
+ * 1: Fix `condition(..., 0)` is not the same as `condition(..., undefined)`
40
+ */
41
+ exports.LATEST_INTERNAL_PATCH_NUMBER = 1;
42
+ /**
43
+ * Keeps all of the Workflow runtime state like pending completions for activities and timers.
44
+ *
45
+ * Implements handlers for all workflow activation jobs.
46
+ */
46
47
  class Activator {
47
- constructor() {
48
+ constructor({ info, now, showStackTraceSources, sourceMap, randomnessSeed, patches, }) {
49
+ /**
50
+ * Map of task sequence to a Completion
51
+ */
52
+ this.completions = {
53
+ timer: new Map(),
54
+ activity: new Map(),
55
+ childWorkflowStart: new Map(),
56
+ childWorkflowComplete: new Map(),
57
+ signalWorkflow: new Map(),
58
+ cancelWorkflow: new Map(),
59
+ };
60
+ /**
61
+ * Holds buffered signal calls until a handler is registered
62
+ */
63
+ this.bufferedSignals = new Map();
64
+ /**
65
+ * Holds buffered query calls until a handler is registered.
66
+ *
67
+ * **IMPORTANT** queries are only buffered until workflow is started.
68
+ * This is required because async interceptors might block workflow function invocation
69
+ * which delays query handler registration.
70
+ */
71
+ this.bufferedQueries = Array();
72
+ /**
73
+ * Mapping of signal name to handler
74
+ */
75
+ this.signalHandlers = new Map();
76
+ this.promiseStackStore = {
77
+ promiseToStack: new Map(),
78
+ childToParent: new Map(),
79
+ };
80
+ this.rootScope = new cancellation_scope_1.RootCancellationScope();
81
+ /**
82
+ * Mapping of query name to handler
83
+ */
84
+ this.queryHandlers = new Map([
85
+ [
86
+ '__stack_trace',
87
+ () => {
88
+ return this.getStackTraces()
89
+ .map((s) => s.formatted)
90
+ .join('\n\n');
91
+ },
92
+ ],
93
+ [
94
+ '__enhanced_stack_trace',
95
+ () => {
96
+ const { sourceMap } = this;
97
+ const sdk = { name: 'typescript', version: pkg_1.default.version };
98
+ const stacks = this.getStackTraces().map(({ structured: locations }) => ({ locations }));
99
+ const sources = {};
100
+ if (this.showStackTraceSources) {
101
+ for (const { locations } of stacks) {
102
+ for (const { filePath } of locations) {
103
+ if (!filePath)
104
+ continue;
105
+ const content = sourceMap?.sourcesContent?.[sourceMap?.sources.indexOf(filePath)];
106
+ if (!content)
107
+ continue;
108
+ sources[filePath] = [
109
+ {
110
+ content,
111
+ lineOffset: 0,
112
+ },
113
+ ];
114
+ }
115
+ }
116
+ }
117
+ return { sdk, stacks, sources };
118
+ },
119
+ ],
120
+ ]);
121
+ /**
122
+ * Loaded in {@link initRuntime}
123
+ */
124
+ this.interceptors = { inbound: [], outbound: [], internals: [] };
125
+ /**
126
+ * Buffer that stores all generated commands, reset after each activation
127
+ */
128
+ this.commands = [];
129
+ /**
130
+ * Stores all {@link condition}s that haven't been unblocked yet
131
+ */
132
+ this.blockedConditions = new Map();
133
+ /**
134
+ * Is this Workflow completed?
135
+ *
136
+ * A Workflow will be considered completed if it generates a command that the
137
+ * system considers as a final Workflow command (e.g.
138
+ * completeWorkflowExecution or failWorkflowExecution).
139
+ */
140
+ this.completed = false;
141
+ /**
142
+ * Was this Workflow cancelled?
143
+ */
144
+ this.cancelled = false;
145
+ /**
146
+ * This is tracked to allow buffering queries until a workflow function is called.
147
+ * TODO(bergundy): I don't think this makes sense since queries run last in an activation and must be responded to in
148
+ * the same activation.
149
+ */
48
150
  this.workflowFunctionWasCalled = false;
151
+ /**
152
+ * The next (incremental) sequence to assign when generating completable commands
153
+ */
154
+ this.nextSeqs = {
155
+ timer: 1,
156
+ activity: 1,
157
+ childWorkflow: 1,
158
+ signalWorkflow: 1,
159
+ cancelWorkflow: 1,
160
+ condition: 1,
161
+ // Used internally to keep track of active stack traces
162
+ stack: 1,
163
+ };
164
+ this.payloadConverter = common_1.defaultPayloadConverter;
165
+ this.failureConverter = common_1.defaultFailureConverter;
166
+ /**
167
+ * Patches we know the status of for this workflow, as in {@link patched}
168
+ */
169
+ this.knownPresentPatches = new Set();
170
+ /**
171
+ * Patches we sent to core {@link patched}
172
+ */
173
+ this.sentPatches = new Set();
174
+ /**
175
+ * SDK Internal Patches are created by the SDK to avoid breaking history when behaviour
176
+ * of existing API need to be modified.
177
+ */
178
+ this.internalPatchNumber = 0;
179
+ this.sinkCalls = Array();
180
+ this.info = info;
181
+ this.now = now;
182
+ this.showStackTraceSources = showStackTraceSources;
183
+ this.sourceMap = sourceMap;
184
+ this.random = (0, alea_1.alea)(randomnessSeed);
185
+ if (info.unsafe.isReplaying) {
186
+ for (const patch of patches) {
187
+ this.knownPresentPatches.add(patch);
188
+ }
189
+ }
190
+ }
191
+ getStackTraces() {
192
+ const { childToParent, promiseToStack } = this.promiseStackStore;
193
+ const internalNodes = [...childToParent.values()].reduce((acc, curr) => {
194
+ for (const p of curr) {
195
+ acc.add(p);
196
+ }
197
+ return acc;
198
+ }, new Set());
199
+ const stacks = new Map();
200
+ for (const child of childToParent.keys()) {
201
+ if (!internalNodes.has(child)) {
202
+ const stack = promiseToStack.get(child);
203
+ if (!stack || !stack.formatted)
204
+ continue;
205
+ stacks.set(stack.formatted, stack);
206
+ }
207
+ }
208
+ // Not 100% sure where this comes from, just filter it out
209
+ stacks.delete(' at Promise.then (<anonymous>)');
210
+ stacks.delete(' at Promise.then (<anonymous>)\n');
211
+ return [...stacks].map(([_, stack]) => stack);
212
+ }
213
+ getAndResetSinkCalls() {
214
+ const { sinkCalls } = this;
215
+ this.sinkCalls = [];
216
+ return sinkCalls;
217
+ }
218
+ /**
219
+ * Buffer a Workflow command to be collected at the end of the current activation.
220
+ *
221
+ * Prevents commands from being added after Workflow completion.
222
+ */
223
+ pushCommand(cmd, complete = false) {
224
+ // Only query responses may be sent after completion
225
+ if (this.completed && !cmd.respondToQuery)
226
+ return;
227
+ this.commands.push(cmd);
228
+ if (complete) {
229
+ this.completed = true;
230
+ }
231
+ }
232
+ getAndResetCommands() {
233
+ const commands = this.commands;
234
+ this.commands = [];
235
+ return commands;
49
236
  }
50
237
  async startWorkflowNextHandler({ args }) {
51
- const { workflow } = exports.state;
238
+ const { workflow } = this;
52
239
  if (workflow === undefined) {
53
- throw new common_2.IllegalStateError('Workflow uninitialized');
240
+ throw new common_1.IllegalStateError('Workflow uninitialized');
54
241
  }
55
242
  let promise;
56
243
  try {
@@ -61,7 +248,7 @@ class Activator {
61
248
  // Otherwise this Workflow will now be queryable.
62
249
  this.workflowFunctionWasCalled = true;
63
250
  // Empty the buffer
64
- const buffer = exports.state.bufferedQueries.splice(0);
251
+ const buffer = this.bufferedQueries.splice(0);
65
252
  for (const activation of buffer) {
66
253
  this.queryWorkflow(activation);
67
254
  }
@@ -69,44 +256,40 @@ class Activator {
69
256
  return await promise;
70
257
  }
71
258
  startWorkflow(activation) {
72
- const { info } = exports.state;
73
- if (info === undefined) {
74
- throw new common_2.IllegalStateError('Workflow has not been initialized');
75
- }
76
- const execute = (0, interceptors_1.composeInterceptors)(exports.state.interceptors.inbound, 'execute', this.startWorkflowNextHandler.bind(this));
259
+ const execute = (0, interceptors_1.composeInterceptors)(this.interceptors.inbound, 'execute', this.startWorkflowNextHandler.bind(this));
77
260
  (0, stack_helpers_1.untrackPromise)(execute({
78
261
  headers: activation.headers ?? {},
79
- args: (0, common_2.arrayFromPayloads)(exports.state.payloadConverter, activation.arguments),
80
- }).then(completeWorkflow, handleWorkflowFailure));
262
+ args: (0, common_1.arrayFromPayloads)(this.payloadConverter, activation.arguments),
263
+ }).then(this.completeWorkflow.bind(this), this.handleWorkflowFailure.bind(this)));
81
264
  }
82
265
  cancelWorkflow(_activation) {
83
- exports.state.cancelled = true;
84
- cancellation_scope_1.ROOT_SCOPE.cancel();
266
+ this.cancelled = true;
267
+ this.rootScope.cancel();
85
268
  }
86
269
  fireTimer(activation) {
87
270
  // Timers are a special case where their completion might not be in Workflow state,
88
271
  // this is due to immediate timer cancellation that doesn't go wait for Core.
89
- const completion = maybeConsumeCompletion('timer', getSeq(activation));
272
+ const completion = this.maybeConsumeCompletion('timer', getSeq(activation));
90
273
  completion?.resolve(undefined);
91
274
  }
92
275
  resolveActivity(activation) {
93
276
  if (!activation.result) {
94
277
  throw new TypeError('Got ResolveActivity activation with no result');
95
278
  }
96
- const { resolve, reject } = consumeCompletion('activity', getSeq(activation));
279
+ const { resolve, reject } = this.consumeCompletion('activity', getSeq(activation));
97
280
  if (activation.result.completed) {
98
281
  const completed = activation.result.completed;
99
- const result = completed.result ? exports.state.payloadConverter.fromPayload(completed.result) : undefined;
282
+ const result = completed.result ? this.payloadConverter.fromPayload(completed.result) : undefined;
100
283
  resolve(result);
101
284
  }
102
285
  else if (activation.result.failed) {
103
286
  const { failure } = activation.result.failed;
104
- const err = failure ? exports.state.failureConverter.failureToError(failure) : undefined;
287
+ const err = failure ? this.failureToError(failure) : undefined;
105
288
  reject(err);
106
289
  }
107
290
  else if (activation.result.cancelled) {
108
291
  const { failure } = activation.result.cancelled;
109
- const err = failure ? exports.state.failureConverter.failureToError(failure) : undefined;
292
+ const err = failure ? this.failureToError(failure) : undefined;
110
293
  reject(err);
111
294
  }
112
295
  else if (activation.result.backoff) {
@@ -114,25 +297,25 @@ class Activator {
114
297
  }
115
298
  }
116
299
  resolveChildWorkflowExecutionStart(activation) {
117
- const { resolve, reject } = consumeCompletion('childWorkflowStart', getSeq(activation));
300
+ const { resolve, reject } = this.consumeCompletion('childWorkflowStart', getSeq(activation));
118
301
  if (activation.succeeded) {
119
302
  resolve(activation.succeeded.runId);
120
303
  }
121
304
  else if (activation.failed) {
122
305
  if (activation.failed.cause !==
123
306
  StartChildWorkflowExecutionFailedCause.START_CHILD_WORKFLOW_EXECUTION_FAILED_CAUSE_WORKFLOW_ALREADY_EXISTS) {
124
- throw new common_2.IllegalStateError('Got unknown StartChildWorkflowExecutionFailedCause');
307
+ throw new common_1.IllegalStateError('Got unknown StartChildWorkflowExecutionFailedCause');
125
308
  }
126
309
  if (!(activation.seq && activation.failed.workflowId && activation.failed.workflowType)) {
127
310
  throw new TypeError('Missing attributes in activation job');
128
311
  }
129
- reject(new errors_1.WorkflowExecutionAlreadyStartedError('Workflow execution already started', activation.failed.workflowId, activation.failed.workflowType));
312
+ reject(new common_1.WorkflowExecutionAlreadyStartedError('Workflow execution already started', activation.failed.workflowId, activation.failed.workflowType));
130
313
  }
131
314
  else if (activation.cancelled) {
132
315
  if (!activation.cancelled.failure) {
133
316
  throw new TypeError('Got no failure in cancelled variant');
134
317
  }
135
- reject(exports.state.failureConverter.failureToError(activation.cancelled.failure));
318
+ reject(this.failureToError(activation.cancelled.failure));
136
319
  }
137
320
  else {
138
321
  throw new TypeError('Got ResolveChildWorkflowExecutionStart with no status');
@@ -142,10 +325,10 @@ class Activator {
142
325
  if (!activation.result) {
143
326
  throw new TypeError('Got ResolveChildWorkflowExecution activation with no result');
144
327
  }
145
- const { resolve, reject } = consumeCompletion('childWorkflowComplete', getSeq(activation));
328
+ const { resolve, reject } = this.consumeCompletion('childWorkflowComplete', getSeq(activation));
146
329
  if (activation.result.completed) {
147
330
  const completed = activation.result.completed;
148
- const result = completed.result ? exports.state.payloadConverter.fromPayload(completed.result) : undefined;
331
+ const result = completed.result ? this.payloadConverter.fromPayload(completed.result) : undefined;
149
332
  resolve(result);
150
333
  }
151
334
  else if (activation.result.failed) {
@@ -153,23 +336,23 @@ class Activator {
153
336
  if (failure === undefined || failure === null) {
154
337
  throw new TypeError('Got failed result with no failure attribute');
155
338
  }
156
- reject(exports.state.failureConverter.failureToError(failure));
339
+ reject(this.failureToError(failure));
157
340
  }
158
341
  else if (activation.result.cancelled) {
159
342
  const { failure } = activation.result.cancelled;
160
343
  if (failure === undefined || failure === null) {
161
344
  throw new TypeError('Got cancelled result with no failure attribute');
162
345
  }
163
- reject(exports.state.failureConverter.failureToError(failure));
346
+ reject(this.failureToError(failure));
164
347
  }
165
348
  }
166
349
  // Intentionally not made function async so this handler doesn't show up in the stack trace
167
350
  queryWorkflowNextHandler({ queryName, args }) {
168
- const fn = exports.state.queryHandlers.get(queryName);
351
+ const fn = this.queryHandlers.get(queryName);
169
352
  if (fn === undefined) {
170
- const knownQueryTypes = [...exports.state.queryHandlers.keys()].join(' ');
353
+ const knownQueryTypes = [...this.queryHandlers.keys()].join(' ');
171
354
  // Fail the query
172
- throw new ReferenceError(`Workflow did not register a handler for ${queryName}. Registered queries: [${knownQueryTypes}]`);
355
+ return Promise.reject(new ReferenceError(`Workflow did not register a handler for ${queryName}. Registered queries: [${knownQueryTypes}]`));
173
356
  }
174
357
  try {
175
358
  const ret = fn(...args);
@@ -184,25 +367,25 @@ class Activator {
184
367
  }
185
368
  queryWorkflow(activation) {
186
369
  if (!this.workflowFunctionWasCalled) {
187
- exports.state.bufferedQueries.push(activation);
370
+ this.bufferedQueries.push(activation);
188
371
  return;
189
372
  }
190
373
  const { queryType, queryId, headers } = activation;
191
374
  if (!(queryType && queryId)) {
192
375
  throw new TypeError('Missing query activation attributes');
193
376
  }
194
- const execute = (0, interceptors_1.composeInterceptors)(exports.state.interceptors.inbound, 'handleQuery', this.queryWorkflowNextHandler.bind(this));
377
+ const execute = (0, interceptors_1.composeInterceptors)(this.interceptors.inbound, 'handleQuery', this.queryWorkflowNextHandler.bind(this));
195
378
  execute({
196
379
  queryName: queryType,
197
- args: (0, common_2.arrayFromPayloads)(exports.state.payloadConverter, activation.arguments),
380
+ args: (0, common_1.arrayFromPayloads)(this.payloadConverter, activation.arguments),
198
381
  queryId,
199
382
  headers: headers ?? {},
200
- }).then((result) => completeQuery(queryId, result), (reason) => failQuery(queryId, reason));
383
+ }).then((result) => this.completeQuery(queryId, result), (reason) => this.failQuery(queryId, reason));
201
384
  }
202
385
  async signalWorkflowNextHandler({ signalName, args }) {
203
- const fn = exports.state.signalHandlers.get(signalName);
386
+ const fn = this.signalHandlers.get(signalName);
204
387
  if (fn === undefined) {
205
- throw new common_2.IllegalStateError(`No registered signal handler for signal ${signalName}`);
388
+ throw new common_1.IllegalStateError(`No registered signal handler for signal ${signalName}`);
206
389
  }
207
390
  return await fn(...args);
208
391
  }
@@ -211,36 +394,36 @@ class Activator {
211
394
  if (!signalName) {
212
395
  throw new TypeError('Missing activation signalName');
213
396
  }
214
- const fn = exports.state.signalHandlers.get(signalName);
397
+ const fn = this.signalHandlers.get(signalName);
215
398
  if (fn === undefined) {
216
- let buffer = exports.state.bufferedSignals.get(signalName);
399
+ let buffer = this.bufferedSignals.get(signalName);
217
400
  if (buffer === undefined) {
218
401
  buffer = [];
219
- exports.state.bufferedSignals.set(signalName, buffer);
402
+ this.bufferedSignals.set(signalName, buffer);
220
403
  }
221
404
  buffer.push(activation);
222
405
  return;
223
406
  }
224
- const execute = (0, interceptors_1.composeInterceptors)(exports.state.interceptors.inbound, 'handleSignal', this.signalWorkflowNextHandler.bind(this));
407
+ const execute = (0, interceptors_1.composeInterceptors)(this.interceptors.inbound, 'handleSignal', this.signalWorkflowNextHandler.bind(this));
225
408
  execute({
226
- args: (0, common_2.arrayFromPayloads)(exports.state.payloadConverter, activation.input),
409
+ args: (0, common_1.arrayFromPayloads)(this.payloadConverter, activation.input),
227
410
  signalName,
228
411
  headers: headers ?? {},
229
- }).catch(handleWorkflowFailure);
412
+ }).catch(this.handleWorkflowFailure.bind(this));
230
413
  }
231
414
  resolveSignalExternalWorkflow(activation) {
232
- const { resolve, reject } = consumeCompletion('signalWorkflow', getSeq(activation));
415
+ const { resolve, reject } = this.consumeCompletion('signalWorkflow', getSeq(activation));
233
416
  if (activation.failure) {
234
- reject(exports.state.failureConverter.failureToError(activation.failure));
417
+ reject(this.failureToError(activation.failure));
235
418
  }
236
419
  else {
237
420
  resolve(undefined);
238
421
  }
239
422
  }
240
423
  resolveRequestCancelExternalWorkflow(activation) {
241
- const { resolve, reject } = consumeCompletion('cancelWorkflow', getSeq(activation));
424
+ const { resolve, reject } = this.consumeCompletion('cancelWorkflow', getSeq(activation));
242
425
  if (activation.failure) {
243
- reject(exports.state.failureConverter.failureToError(activation.failure));
426
+ reject(this.failureToError(activation.failure));
244
427
  }
245
428
  else {
246
429
  resolve(undefined);
@@ -250,274 +433,114 @@ class Activator {
250
433
  if (!activation.randomnessSeed) {
251
434
  throw new TypeError('Expected activation with randomnessSeed attribute');
252
435
  }
253
- exports.state.random = (0, alea_1.alea)(activation.randomnessSeed.toBytes());
436
+ this.random = (0, alea_1.alea)(activation.randomnessSeed.toBytes());
254
437
  }
255
438
  notifyHasPatch(activation) {
256
439
  if (!activation.patchId) {
257
440
  throw new TypeError('Notify has patch missing patch name');
258
441
  }
259
- exports.state.knownPresentPatches.add(activation.patchId);
442
+ if (activation.patchId.startsWith('__sdk_internal_patch_number:')) {
443
+ const internalPatchNumber = parseInt(activation.patchId.substring('__sdk_internal_patch_number:'.length));
444
+ if (internalPatchNumber > exports.LATEST_INTERNAL_PATCH_NUMBER)
445
+ throw new common_1.IllegalStateError(`Unsupported internal patch number: ${internalPatchNumber} > ${exports.LATEST_INTERNAL_PATCH_NUMBER}`);
446
+ if (this.internalPatchNumber < internalPatchNumber)
447
+ this.internalPatchNumber = internalPatchNumber;
448
+ }
449
+ else {
450
+ this.knownPresentPatches.add(activation.patchId);
451
+ }
260
452
  }
261
- removeFromCache() {
262
- throw new common_2.IllegalStateError('removeFromCache activation job should not reach workflow');
453
+ checkInternalPatchAtLeast(minimumPatchNumber) {
454
+ if (this.internalPatchNumber >= minimumPatchNumber)
455
+ return true;
456
+ if (!this.info.unsafe.isReplaying) {
457
+ this.internalPatchNumber = minimumPatchNumber;
458
+ this.pushCommand({
459
+ setPatchMarker: { patchId: `__sdk_internal_patch_number:${exports.LATEST_INTERNAL_PATCH_NUMBER}`, deprecated: false },
460
+ });
461
+ return true;
462
+ }
463
+ return false;
263
464
  }
264
- }
265
- exports.Activator = Activator;
266
- /**
267
- * Keeps all of the Workflow runtime state like pending completions for activities and timers and the scope stack.
268
- *
269
- * State mutates each time the Workflow is activated.
270
- */
271
- class State {
272
- constructor() {
273
- /**
274
- * Activator executes activation jobs
275
- */
276
- this.activator = new Activator();
277
- /**
278
- * Map of task sequence to a Completion
279
- */
280
- this.completions = {
281
- timer: new Map(),
282
- activity: new Map(),
283
- childWorkflowStart: new Map(),
284
- childWorkflowComplete: new Map(),
285
- signalWorkflow: new Map(),
286
- cancelWorkflow: new Map(),
287
- };
288
- /**
289
- * Holds buffered signal calls until a handler is registered
290
- */
291
- this.bufferedSignals = new Map();
292
- /**
293
- * Holds buffered query calls until a handler is registered.
294
- *
295
- * **IMPORTANT** queries are only buffered until workflow is started.
296
- * This is required because async interceptors might block workflow function invocation
297
- * which delays query handler registration.
298
- */
299
- this.bufferedQueries = Array();
300
- /**
301
- * Mapping of signal name to handler
302
- */
303
- this.signalHandlers = new Map();
304
- /**
305
- * Whether or not to send the sources in enhanced stack trace query responses
306
- */
307
- this.showStackTraceSources = false;
308
- /**
309
- * Mapping of query name to handler
310
- */
311
- this.queryHandlers = new Map([
312
- [
313
- '__stack_trace',
314
- () => {
315
- return this.getStackTraces()
316
- .map((s) => s.formatted)
317
- .join('\n\n');
318
- },
319
- ],
320
- [
321
- '__enhanced_stack_trace',
322
- () => {
323
- const { sourceMap } = this;
324
- const sdk = { name: 'typescript', version: pkg_1.default.version };
325
- const stacks = this.getStackTraces().map(({ structured: locations }) => ({ locations }));
326
- const sources = {};
327
- if (this.showStackTraceSources) {
328
- for (const { locations } of stacks) {
329
- for (const { filePath } of locations) {
330
- if (!filePath)
331
- continue;
332
- const content = sourceMap?.sourcesContent?.[sourceMap?.sources.indexOf(filePath)];
333
- if (!content)
334
- continue;
335
- sources[filePath] = [
336
- {
337
- content,
338
- lineOffset: 0,
339
- },
340
- ];
341
- }
342
- }
343
- }
344
- return { sdk, stacks, sources };
345
- },
346
- ],
347
- ]);
348
- /**
349
- * Loaded in {@link initRuntime}
350
- */
351
- this.interceptors = { inbound: [], outbound: [], internals: [] };
352
- /**
353
- * Buffer that stores all generated commands, reset after each activation
354
- */
355
- this.commands = [];
356
- /**
357
- * Stores all {@link condition}s that haven't been unblocked yet
358
- */
359
- this.blockedConditions = new Map();
360
- /**
361
- * Is this Workflow completed?
362
- *
363
- * A Workflow will be considered completed if it generates a command that the
364
- * system considers as a final Workflow command (e.g.
365
- * completeWorkflowExecution or failWorkflowExecution).
366
- */
367
- this.completed = false;
368
- /**
369
- * Was this Workflow cancelled?
370
- */
371
- this.cancelled = false;
372
- /**
373
- * The next (incremental) sequence to assign when generating completable commands
374
- */
375
- this.nextSeqs = {
376
- timer: 1,
377
- activity: 1,
378
- childWorkflow: 1,
379
- signalWorkflow: 1,
380
- cancelWorkflow: 1,
381
- condition: 1,
382
- // Used internally to keep track of active stack traces
383
- stack: 1,
384
- };
385
- /**
386
- * This is set every time the workflow executes an activation
387
- */
388
- _State_now.set(this, void 0);
389
- /**
390
- * A deterministic RNG, used by the isolate's overridden Math.random
391
- */
392
- this.random = function () {
393
- throw new common_2.IllegalStateError('Tried to use Math.random before Workflow has been initialized');
394
- };
395
- this.payloadConverter = common_2.defaultPayloadConverter;
396
- this.failureConverter = common_1.defaultFailureConverter;
397
- /**
398
- * Patches we know the status of for this workflow, as in {@link patched}
399
- */
400
- this.knownPresentPatches = new Set();
401
- /**
402
- * Patches we sent to core {@link patched}
403
- */
404
- this.sentPatches = new Set();
405
- this.sinkCalls = Array();
465
+ removeFromCache() {
466
+ throw new common_1.IllegalStateError('removeFromCache activation job should not reach workflow');
406
467
  }
407
- getStackTraces() {
408
- const { childToParent, promiseToStack } = globalThis.__TEMPORAL__.promiseStackStore;
409
- const internalNodes = [...childToParent.values()].reduce((acc, curr) => {
410
- for (const p of curr) {
411
- acc.add(p);
412
- }
413
- return acc;
414
- }, new Set());
415
- const stacks = new Map();
416
- for (const child of childToParent.keys()) {
417
- if (!internalNodes.has(child)) {
418
- const stack = promiseToStack.get(child);
419
- if (!stack || !stack.formatted)
420
- continue;
421
- stacks.set(stack.formatted, stack);
468
+ /**
469
+ * Transforms failures into a command to be sent to the server.
470
+ * Used to handle any failure emitted by the Workflow.
471
+ */
472
+ async handleWorkflowFailure(error) {
473
+ if (this.cancelled && (0, errors_1.isCancellation)(error)) {
474
+ this.pushCommand({ cancelWorkflowExecution: {} }, true);
475
+ }
476
+ else if (error instanceof interfaces_1.ContinueAsNew) {
477
+ this.pushCommand({ continueAsNewWorkflowExecution: error.command }, true);
478
+ }
479
+ else {
480
+ if (!(error instanceof common_1.TemporalFailure)) {
481
+ // This results in an unhandled rejection which will fail the activation
482
+ // preventing it from completing.
483
+ throw error;
422
484
  }
485
+ this.pushCommand({
486
+ failWorkflowExecution: {
487
+ failure: this.errorToFailure(error),
488
+ },
489
+ }, true);
423
490
  }
424
- // Not 100% sure where this comes from, just filter it out
425
- stacks.delete(' at Promise.then (<anonymous>)');
426
- stacks.delete(' at Promise.then (<anonymous>)\n');
427
- return [...stacks].map(([_, stack]) => stack);
428
491
  }
429
- get now() {
430
- if (__classPrivateFieldGet(this, _State_now, "f") === undefined) {
431
- throw new common_2.IllegalStateError('Tried to get Date before Workflow has been initialized');
432
- }
433
- return __classPrivateFieldGet(this, _State_now, "f");
492
+ completeQuery(queryId, result) {
493
+ this.pushCommand({
494
+ respondToQuery: { queryId, succeeded: { response: this.payloadConverter.toPayload(result) } },
495
+ });
434
496
  }
435
- set now(value) {
436
- __classPrivateFieldSet(this, _State_now, value, "f");
497
+ failQuery(queryId, error) {
498
+ this.pushCommand({
499
+ respondToQuery: {
500
+ queryId,
501
+ failed: this.errorToFailure((0, common_1.ensureTemporalFailure)(error)),
502
+ },
503
+ });
437
504
  }
438
- getAndResetSinkCalls() {
439
- const { sinkCalls } = this;
440
- this.sinkCalls = [];
441
- return sinkCalls;
505
+ /** Consume a completion if it exists in Workflow state */
506
+ maybeConsumeCompletion(type, taskSeq) {
507
+ const completion = this.completions[type].get(taskSeq);
508
+ if (completion !== undefined) {
509
+ this.completions[type].delete(taskSeq);
510
+ }
511
+ return completion;
442
512
  }
443
- /**
444
- * Buffer a Workflow command to be collected at the end of the current activation.
445
- *
446
- * Prevents commands from being added after Workflow completion.
447
- */
448
- pushCommand(cmd, complete = false) {
449
- // Only query responses may be sent after completion
450
- if (this.completed && !cmd.respondToQuery)
451
- return;
452
- this.commands.push(cmd);
453
- if (complete) {
454
- this.completed = true;
513
+ /** Consume a completion if it exists in Workflow state, throws if it doesn't */
514
+ consumeCompletion(type, taskSeq) {
515
+ const completion = this.maybeConsumeCompletion(type, taskSeq);
516
+ if (completion === undefined) {
517
+ throw new common_1.IllegalStateError(`No completion for taskSeq ${taskSeq}`);
455
518
  }
519
+ return completion;
456
520
  }
457
- }
458
- exports.State = State;
459
- _State_now = new WeakMap();
460
- exports.state = new State();
461
- function completeWorkflow(result) {
462
- exports.state.pushCommand({
463
- completeWorkflowExecution: {
464
- result: exports.state.payloadConverter.toPayload(result),
465
- },
466
- }, true);
467
- }
468
- /**
469
- * Transforms failures into a command to be sent to the server.
470
- * Used to handle any failure emitted by the Workflow.
471
- */
472
- async function handleWorkflowFailure(error) {
473
- if (exports.state.cancelled && (0, errors_1.isCancellation)(error)) {
474
- exports.state.pushCommand({ cancelWorkflowExecution: {} }, true);
475
- }
476
- else if (error instanceof interfaces_1.ContinueAsNew) {
477
- exports.state.pushCommand({ continueAsNewWorkflowExecution: error.command }, true);
478
- }
479
- else {
480
- if (!(error instanceof common_2.TemporalFailure)) {
481
- // This results in an unhandled rejection which will fail the activation
482
- // preventing it from completing.
483
- throw error;
484
- }
485
- exports.state.pushCommand({
486
- failWorkflowExecution: {
487
- failure: exports.state.failureConverter.errorToFailure(error),
521
+ completeWorkflow(result) {
522
+ this.pushCommand({
523
+ completeWorkflowExecution: {
524
+ result: this.payloadConverter.toPayload(result),
488
525
  },
489
526
  }, true);
490
527
  }
491
- }
492
- exports.handleWorkflowFailure = handleWorkflowFailure;
493
- function completeQuery(queryId, result) {
494
- exports.state.pushCommand({
495
- respondToQuery: { queryId, succeeded: { response: exports.state.payloadConverter.toPayload(result) } },
496
- });
497
- }
498
- async function failQuery(queryId, error) {
499
- exports.state.pushCommand({
500
- respondToQuery: { queryId, failed: exports.state.failureConverter.errorToFailure((0, common_2.ensureTemporalFailure)(error)) },
501
- });
502
- }
503
- /** Consume a completion if it exists in Workflow state */
504
- function maybeConsumeCompletion(type, taskSeq) {
505
- const completion = exports.state.completions[type].get(taskSeq);
506
- if (completion !== undefined) {
507
- exports.state.completions[type].delete(taskSeq);
528
+ errorToFailure(err) {
529
+ return this.failureConverter.errorToFailure(err, this.payloadConverter);
530
+ }
531
+ failureToError(failure) {
532
+ return this.failureConverter.failureToError(failure, this.payloadConverter);
508
533
  }
509
- return completion;
510
534
  }
511
- exports.maybeConsumeCompletion = maybeConsumeCompletion;
512
- /** Consume a completion if it exists in Workflow state, throws if it doesn't */
513
- function consumeCompletion(type, taskSeq) {
514
- const completion = maybeConsumeCompletion(type, taskSeq);
515
- if (completion === undefined) {
516
- throw new common_2.IllegalStateError(`No completion for taskSeq ${taskSeq}`);
517
- }
518
- return completion;
535
+ exports.Activator = Activator;
536
+ function getActivator() {
537
+ const activator = globalThis.__TEMPORAL__?.activator;
538
+ if (activator === undefined) {
539
+ throw new common_1.IllegalStateError('Workflow uninitialized');
540
+ }
541
+ return activator;
519
542
  }
520
- exports.consumeCompletion = consumeCompletion;
543
+ exports.getActivator = getActivator;
521
544
  function getSeq(activation) {
522
545
  const seq = activation.seq;
523
546
  if (seq === undefined || seq === null) {