@proompteng/temporal-bun-sdk 0.2.0 → 0.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/README.md +141 -10
- package/dist/src/bin/replay-command.d.ts.map +1 -1
- package/dist/src/bin/replay-command.js +6 -2
- package/dist/src/bin/replay-command.js.map +1 -1
- package/dist/src/bin/temporal-bun.d.ts +1 -1
- package/dist/src/bin/temporal-bun.d.ts.map +1 -1
- package/dist/src/bin/temporal-bun.js +74 -0
- package/dist/src/bin/temporal-bun.js.map +1 -1
- package/dist/src/client/layer.d.ts +2 -2
- package/dist/src/client/layer.d.ts.map +1 -1
- package/dist/src/client/retries.d.ts.map +1 -1
- package/dist/src/client/retries.js +27 -3
- package/dist/src/client/retries.js.map +1 -1
- package/dist/src/client/serialization.d.ts +34 -2
- package/dist/src/client/serialization.d.ts.map +1 -1
- package/dist/src/client/serialization.js +78 -5
- package/dist/src/client/serialization.js.map +1 -1
- package/dist/src/client/types.d.ts +26 -0
- package/dist/src/client/types.d.ts.map +1 -1
- package/dist/src/client.d.ts +22 -6
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +488 -39
- package/dist/src/client.js.map +1 -1
- package/dist/src/common/payloads/codecs.d.ts +38 -0
- package/dist/src/common/payloads/codecs.d.ts.map +1 -0
- package/dist/src/common/payloads/codecs.js +174 -0
- package/dist/src/common/payloads/codecs.js.map +1 -0
- package/dist/src/common/payloads/converter.d.ts +52 -3
- package/dist/src/common/payloads/converter.d.ts.map +1 -1
- package/dist/src/common/payloads/converter.js +340 -2
- package/dist/src/common/payloads/converter.js.map +1 -1
- package/dist/src/common/payloads/failure.d.ts +5 -6
- package/dist/src/common/payloads/failure.d.ts.map +1 -1
- package/dist/src/common/payloads/failure.js +3 -52
- package/dist/src/common/payloads/failure.js.map +1 -1
- package/dist/src/common/payloads/index.d.ts +1 -0
- package/dist/src/common/payloads/index.d.ts.map +1 -1
- package/dist/src/common/payloads/index.js +1 -0
- package/dist/src/common/payloads/index.js.map +1 -1
- package/dist/src/config.d.ts +9 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +62 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interceptors/client.d.ts +28 -0
- package/dist/src/interceptors/client.d.ts.map +1 -0
- package/dist/src/interceptors/client.js +169 -0
- package/dist/src/interceptors/client.js.map +1 -0
- package/dist/src/interceptors/types.d.ts +33 -0
- package/dist/src/interceptors/types.d.ts.map +1 -0
- package/dist/src/interceptors/types.js +44 -0
- package/dist/src/interceptors/types.js.map +1 -0
- package/dist/src/interceptors/worker.d.ts +22 -0
- package/dist/src/interceptors/worker.d.ts.map +1 -0
- package/dist/src/interceptors/worker.js +156 -0
- package/dist/src/interceptors/worker.js.map +1 -0
- package/dist/src/runtime/cli-layer.d.ts +4 -3
- package/dist/src/runtime/cli-layer.d.ts.map +1 -1
- package/dist/src/runtime/cli-layer.js +5 -2
- package/dist/src/runtime/cli-layer.js.map +1 -1
- package/dist/src/runtime/effect-layers.d.ts +9 -0
- package/dist/src/runtime/effect-layers.d.ts.map +1 -1
- package/dist/src/runtime/effect-layers.js +15 -0
- package/dist/src/runtime/effect-layers.js.map +1 -1
- package/dist/src/worker/concurrency.d.ts +8 -0
- package/dist/src/worker/concurrency.d.ts.map +1 -1
- package/dist/src/worker/concurrency.js +5 -9
- package/dist/src/worker/concurrency.js.map +1 -1
- package/dist/src/worker/runtime.d.ts +5 -0
- package/dist/src/worker/runtime.d.ts.map +1 -1
- package/dist/src/worker/runtime.js +509 -40
- package/dist/src/worker/runtime.js.map +1 -1
- package/dist/src/worker/sticky-cache.d.ts +5 -0
- package/dist/src/worker/sticky-cache.d.ts.map +1 -1
- package/dist/src/worker/sticky-cache.js +26 -0
- package/dist/src/worker/sticky-cache.js.map +1 -1
- package/dist/src/worker/update-protocol.d.ts +33 -0
- package/dist/src/worker/update-protocol.d.ts.map +1 -0
- package/dist/src/worker/update-protocol.js +243 -0
- package/dist/src/worker/update-protocol.js.map +1 -0
- package/dist/src/worker.js +1 -0
- package/dist/src/worker.js.map +1 -1
- package/dist/src/workflow/commands.d.ts +38 -2
- package/dist/src/workflow/commands.d.ts.map +1 -1
- package/dist/src/workflow/commands.js +153 -1
- package/dist/src/workflow/commands.js.map +1 -1
- package/dist/src/workflow/context.d.ts +111 -3
- package/dist/src/workflow/context.d.ts.map +1 -1
- package/dist/src/workflow/context.js +526 -6
- package/dist/src/workflow/context.js.map +1 -1
- package/dist/src/workflow/definition.d.ts +29 -3
- package/dist/src/workflow/definition.d.ts.map +1 -1
- package/dist/src/workflow/definition.js +30 -4
- package/dist/src/workflow/definition.js.map +1 -1
- package/dist/src/workflow/determinism.d.ts +64 -0
- package/dist/src/workflow/determinism.d.ts.map +1 -1
- package/dist/src/workflow/determinism.js +120 -3
- package/dist/src/workflow/determinism.js.map +1 -1
- package/dist/src/workflow/errors.d.ts +6 -0
- package/dist/src/workflow/errors.d.ts.map +1 -1
- package/dist/src/workflow/errors.js +12 -0
- package/dist/src/workflow/errors.js.map +1 -1
- package/dist/src/workflow/executor.d.ts +56 -0
- package/dist/src/workflow/executor.d.ts.map +1 -1
- package/dist/src/workflow/executor.js +300 -9
- package/dist/src/workflow/executor.js.map +1 -1
- package/dist/src/workflow/inbound.d.ts +84 -0
- package/dist/src/workflow/inbound.d.ts.map +1 -0
- package/dist/src/workflow/inbound.js +65 -0
- package/dist/src/workflow/inbound.js.map +1 -0
- package/dist/src/workflow/index.d.ts +1 -0
- package/dist/src/workflow/index.d.ts.map +1 -1
- package/dist/src/workflow/index.js +1 -0
- package/dist/src/workflow/index.js.map +1 -1
- package/dist/src/workflow/replay.d.ts +24 -2
- package/dist/src/workflow/replay.d.ts.map +1 -1
- package/dist/src/workflow/replay.js +679 -15
- package/dist/src/workflow/replay.js.map +1 -1
- package/dist/src/workflows/index.d.ts +1 -1
- package/dist/src/workflows/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@ import { create } from '@bufbuild/protobuf';
|
|
|
2
2
|
import { Effect } from 'effect';
|
|
3
3
|
import { durationToMillis } from '../common/duration';
|
|
4
4
|
import { decodePayloadsToValues, encodeValuesToPayloads } from '../common/payloads';
|
|
5
|
-
import { PayloadsSchema } from '../proto/temporal/api/common/v1/message_pb';
|
|
5
|
+
import { PayloadsSchema, } from '../proto/temporal/api/common/v1/message_pb';
|
|
6
6
|
import { EventType } from '../proto/temporal/api/enums/v1/event_type_pb';
|
|
7
7
|
import { ParentClosePolicy, TimeoutType, WorkflowIdReusePolicy } from '../proto/temporal/api/enums/v1/workflow_pb';
|
|
8
|
-
import { intentsEqual } from './determinism';
|
|
8
|
+
import { intentsEqual, stableStringify } from './determinism';
|
|
9
9
|
export const DETERMINISM_MARKER_NAME = 'temporal-bun-sdk/determinism';
|
|
10
10
|
const DETERMINISM_MARKER_SCHEMA_VERSION = 1;
|
|
11
11
|
const DETERMINISM_MARKER_DETAIL_KEY = 'snapshot';
|
|
@@ -58,6 +58,7 @@ export const ingestWorkflowHistory = (intake) => Effect.gen(function* () {
|
|
|
58
58
|
const events = sortHistoryEvents(intake.history ?? []);
|
|
59
59
|
const shouldUseDeterminismMarker = intake.ignoreDeterminismMarker !== true;
|
|
60
60
|
let markerSnapshot;
|
|
61
|
+
const updateEntries = collectWorkflowUpdateEntries(events);
|
|
61
62
|
if (shouldUseDeterminismMarker) {
|
|
62
63
|
for (const event of events) {
|
|
63
64
|
if (event.eventType !== EventType.MARKER_RECORDED) {
|
|
@@ -76,21 +77,31 @@ export const ingestWorkflowHistory = (intake) => Effect.gen(function* () {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
const extractedFailureMetadata = extractFailureMetadata(events);
|
|
80
|
+
const replayUpdateInvocations = yield* Effect.tryPromise(async () => collectWorkflowUpdateInvocations(events, intake.dataConverter));
|
|
79
81
|
if (shouldUseDeterminismMarker && markerSnapshot) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
...
|
|
84
|
-
|
|
82
|
+
let determinismState = cloneDeterminismState(markerSnapshot.determinismState);
|
|
83
|
+
if (!determinismState.failureMetadata && extractedFailureMetadata) {
|
|
84
|
+
determinismState = {
|
|
85
|
+
...determinismState,
|
|
86
|
+
failureMetadata: extractedFailureMetadata,
|
|
85
87
|
};
|
|
88
|
+
}
|
|
89
|
+
if ((!determinismState.updates || determinismState.updates.length === 0) && updateEntries.length > 0) {
|
|
90
|
+
determinismState = {
|
|
91
|
+
...determinismState,
|
|
92
|
+
updates: updateEntries,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
determinismState = mergePendingQueryRequests(determinismState, intake.queries);
|
|
86
96
|
const latestEventId = resolveHistoryLastEventId(events) ?? markerSnapshot.lastEventId ?? null;
|
|
87
97
|
return {
|
|
88
98
|
determinismState,
|
|
89
99
|
lastEventId: latestEventId,
|
|
90
100
|
hasDeterminismMarker: true,
|
|
101
|
+
...(replayUpdateInvocations.length > 0 ? { updates: replayUpdateInvocations } : {}),
|
|
91
102
|
};
|
|
92
103
|
}
|
|
93
|
-
return yield* reconstructDeterminismState(events, intake, extractedFailureMetadata);
|
|
104
|
+
return yield* reconstructDeterminismState(events, intake, extractedFailureMetadata, updateEntries, replayUpdateInvocations);
|
|
94
105
|
});
|
|
95
106
|
/**
|
|
96
107
|
* Diff determinism state against freshly emitted intents to produce rich
|
|
@@ -153,6 +164,36 @@ export const diffDeterminismState = (expected, actual) => Effect.sync(() => {
|
|
|
153
164
|
});
|
|
154
165
|
}
|
|
155
166
|
}
|
|
167
|
+
const expectedSignals = expected.signals ?? [];
|
|
168
|
+
const actualSignals = actual.signals ?? [];
|
|
169
|
+
const maxSignals = Math.max(expectedSignals.length, actualSignals.length);
|
|
170
|
+
for (let index = 0; index < maxSignals; index += 1) {
|
|
171
|
+
const expectedSignal = expectedSignals[index];
|
|
172
|
+
const actualSignal = actualSignals[index];
|
|
173
|
+
if (!recordsMatch(expectedSignal, actualSignal)) {
|
|
174
|
+
mismatches.push({ kind: 'signal', index, expected: expectedSignal, actual: actualSignal });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const expectedQueries = expected.queries ?? [];
|
|
178
|
+
const actualQueries = actual.queries ?? [];
|
|
179
|
+
const maxQueries = Math.max(expectedQueries.length, actualQueries.length);
|
|
180
|
+
for (let index = 0; index < maxQueries; index += 1) {
|
|
181
|
+
const expectedQuery = expectedQueries[index];
|
|
182
|
+
const actualQuery = actualQueries[index];
|
|
183
|
+
if (!recordsMatch(expectedQuery, actualQuery)) {
|
|
184
|
+
mismatches.push({ kind: 'query', index, expected: expectedQuery, actual: actualQuery });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const expectedUpdates = expected.updates ?? [];
|
|
188
|
+
const actualUpdates = actual.updates ?? [];
|
|
189
|
+
const maxUpdates = Math.max(expectedUpdates.length, actualUpdates.length);
|
|
190
|
+
for (let index = 0; index < maxUpdates; index += 1) {
|
|
191
|
+
const expectedEntry = expectedUpdates[index];
|
|
192
|
+
const actualEntry = actualUpdates[index];
|
|
193
|
+
if (!updatesEqual(expectedEntry, actualEntry)) {
|
|
194
|
+
mismatches.push({ kind: 'update', index, expected: expectedEntry, actual: actualEntry });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
156
197
|
return { mismatches };
|
|
157
198
|
});
|
|
158
199
|
export const resolveHistoryLastEventId = (events) => {
|
|
@@ -180,6 +221,9 @@ export const cloneDeterminismState = (state) => ({
|
|
|
180
221
|
randomValues: [...state.randomValues],
|
|
181
222
|
timeValues: [...state.timeValues],
|
|
182
223
|
failureMetadata: state.failureMetadata ? { ...state.failureMetadata } : undefined,
|
|
224
|
+
signals: state.signals ? state.signals.map((record) => ({ ...record })) : [],
|
|
225
|
+
queries: state.queries ? state.queries.map((record) => ({ ...record })) : [],
|
|
226
|
+
updates: state.updates ? state.updates.map((entry) => ({ ...entry })) : undefined,
|
|
183
227
|
});
|
|
184
228
|
const sortHistoryEvents = (events) => events.slice().sort((left, right) => {
|
|
185
229
|
const leftId = resolveEventIdForSort(left);
|
|
@@ -340,9 +384,14 @@ const resolveCommandMismatchMetadata = (expectedEntry, actualEntry) => {
|
|
|
340
384
|
eventType,
|
|
341
385
|
};
|
|
342
386
|
};
|
|
343
|
-
const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.gen(function* () {
|
|
387
|
+
const reconstructDeterminismState = (events, intake, failureMetadata, precomputedUpdates, replayUpdateInvocations = []) => Effect.gen(function* () {
|
|
344
388
|
let sequence = 0;
|
|
345
389
|
const commandHistory = [];
|
|
390
|
+
const signalRecords = [];
|
|
391
|
+
const queryRecords = [];
|
|
392
|
+
const updates = precomputedUpdates ?? collectWorkflowUpdateEntries(events);
|
|
393
|
+
const scheduledActivities = new Map();
|
|
394
|
+
const timersByStartEventId = new Map();
|
|
346
395
|
for (const event of events) {
|
|
347
396
|
switch (event.eventType) {
|
|
348
397
|
case EventType.ACTIVITY_TASK_SCHEDULED: {
|
|
@@ -355,6 +404,10 @@ const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.
|
|
|
355
404
|
intent,
|
|
356
405
|
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
357
406
|
});
|
|
407
|
+
const scheduledKey = normalizeEventId(event.eventId);
|
|
408
|
+
if (scheduledKey) {
|
|
409
|
+
scheduledActivities.set(scheduledKey, intent.activityId);
|
|
410
|
+
}
|
|
358
411
|
sequence += 1;
|
|
359
412
|
}
|
|
360
413
|
break;
|
|
@@ -369,6 +422,10 @@ const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.
|
|
|
369
422
|
intent,
|
|
370
423
|
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
371
424
|
});
|
|
425
|
+
const startKey = normalizeEventId(event.eventId);
|
|
426
|
+
if (startKey) {
|
|
427
|
+
timersByStartEventId.set(startKey, intent.timerId);
|
|
428
|
+
}
|
|
372
429
|
sequence += 1;
|
|
373
430
|
}
|
|
374
431
|
break;
|
|
@@ -387,6 +444,34 @@ const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.
|
|
|
387
444
|
}
|
|
388
445
|
break;
|
|
389
446
|
}
|
|
447
|
+
case EventType.ACTIVITY_TASK_CANCEL_REQUESTED: {
|
|
448
|
+
if (event.attributes?.case !== 'activityTaskCancelRequestedEventAttributes') {
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
const intent = fromActivityTaskCancelRequested(event.attributes.value, sequence, scheduledActivities);
|
|
452
|
+
if (intent) {
|
|
453
|
+
commandHistory.push({
|
|
454
|
+
intent,
|
|
455
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
456
|
+
});
|
|
457
|
+
sequence += 1;
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
case EventType.TIMER_CANCELED: {
|
|
462
|
+
if (event.attributes?.case !== 'timerCanceledEventAttributes') {
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
const intent = fromTimerCanceled(event.attributes.value, sequence, timersByStartEventId);
|
|
466
|
+
if (intent) {
|
|
467
|
+
commandHistory.push({
|
|
468
|
+
intent,
|
|
469
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
470
|
+
});
|
|
471
|
+
sequence += 1;
|
|
472
|
+
}
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
390
475
|
case EventType.SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: {
|
|
391
476
|
if (event.attributes?.case !== 'signalExternalWorkflowExecutionInitiatedEventAttributes') {
|
|
392
477
|
break;
|
|
@@ -401,6 +486,39 @@ const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.
|
|
|
401
486
|
}
|
|
402
487
|
break;
|
|
403
488
|
}
|
|
489
|
+
case EventType.REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: {
|
|
490
|
+
if (event.attributes?.case !== 'requestCancelExternalWorkflowExecutionInitiatedEventAttributes') {
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
const intent = fromRequestCancelExternalWorkflow(event.attributes.value, sequence, intake);
|
|
494
|
+
if (intent) {
|
|
495
|
+
commandHistory.push({
|
|
496
|
+
intent,
|
|
497
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
498
|
+
});
|
|
499
|
+
sequence += 1;
|
|
500
|
+
}
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
case EventType.WORKFLOW_EXECUTION_SIGNALED: {
|
|
504
|
+
if (event.attributes?.case !== 'workflowExecutionSignaledEventAttributes') {
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
const attributes = event.attributes.value;
|
|
508
|
+
const payloads = yield* decodePayloadArray(intake.dataConverter, attributes.input);
|
|
509
|
+
const workflowTaskCompletedEventId = 'workflowTaskCompletedEventId' in attributes
|
|
510
|
+
? normalizeEventId(attributes
|
|
511
|
+
.workflowTaskCompletedEventId)
|
|
512
|
+
: null;
|
|
513
|
+
signalRecords.push({
|
|
514
|
+
signalName: attributes.signalName ?? 'unknown',
|
|
515
|
+
payloadHash: stableStringify(payloads),
|
|
516
|
+
eventId: normalizeEventId(event.eventId),
|
|
517
|
+
workflowTaskCompletedEventId,
|
|
518
|
+
identity: attributes.identity ?? null,
|
|
519
|
+
});
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
404
522
|
case EventType.WORKFLOW_EXECUTION_CONTINUED_AS_NEW: {
|
|
405
523
|
if (event.attributes?.case !== 'workflowExecutionContinuedAsNewEventAttributes') {
|
|
406
524
|
break;
|
|
@@ -415,19 +533,70 @@ const reconstructDeterminismState = (events, intake, failureMetadata) => Effect.
|
|
|
415
533
|
}
|
|
416
534
|
break;
|
|
417
535
|
}
|
|
536
|
+
case EventType.MARKER_RECORDED: {
|
|
537
|
+
if (event.attributes?.case !== 'markerRecordedEventAttributes') {
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
if (event.attributes.value.markerName === DETERMINISM_MARKER_NAME) {
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
const intent = yield* fromMarkerRecorded(event.attributes.value, sequence, intake);
|
|
544
|
+
if (intent) {
|
|
545
|
+
commandHistory.push({
|
|
546
|
+
intent,
|
|
547
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
548
|
+
});
|
|
549
|
+
sequence += 1;
|
|
550
|
+
}
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case EventType.UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: {
|
|
554
|
+
if (event.attributes?.case !== 'upsertWorkflowSearchAttributesEventAttributes') {
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
const intent = yield* fromUpsertSearchAttributes(event.attributes.value, sequence, intake);
|
|
558
|
+
if (intent) {
|
|
559
|
+
commandHistory.push({
|
|
560
|
+
intent,
|
|
561
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
562
|
+
});
|
|
563
|
+
sequence += 1;
|
|
564
|
+
}
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
case EventType.WORKFLOW_PROPERTIES_MODIFIED: {
|
|
568
|
+
if (event.attributes?.case !== 'workflowPropertiesModifiedEventAttributes') {
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
const intent = yield* fromWorkflowPropertiesModified(event.attributes.value, sequence, intake);
|
|
572
|
+
if (intent) {
|
|
573
|
+
commandHistory.push({
|
|
574
|
+
intent,
|
|
575
|
+
metadata: buildCommandMetadata(event, event.attributes.value),
|
|
576
|
+
});
|
|
577
|
+
sequence += 1;
|
|
578
|
+
}
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
418
581
|
default:
|
|
419
582
|
break;
|
|
420
583
|
}
|
|
421
584
|
}
|
|
585
|
+
let determinismState = {
|
|
586
|
+
commandHistory,
|
|
587
|
+
randomValues: [],
|
|
588
|
+
timeValues: [],
|
|
589
|
+
...(failureMetadata ? { failureMetadata } : {}),
|
|
590
|
+
signals: signalRecords,
|
|
591
|
+
queries: queryRecords,
|
|
592
|
+
...(updates.length > 0 ? { updates } : {}),
|
|
593
|
+
};
|
|
594
|
+
determinismState = mergePendingQueryRequests(determinismState, intake.queries);
|
|
422
595
|
return {
|
|
423
|
-
determinismState
|
|
424
|
-
commandHistory,
|
|
425
|
-
randomValues: [],
|
|
426
|
-
timeValues: [],
|
|
427
|
-
...(failureMetadata ? { failureMetadata } : {}),
|
|
428
|
-
},
|
|
596
|
+
determinismState,
|
|
429
597
|
lastEventId: resolveHistoryLastEventId(events),
|
|
430
598
|
hasDeterminismMarker: false,
|
|
599
|
+
...(replayUpdateInvocations.length > 0 ? { updates: replayUpdateInvocations } : {}),
|
|
431
600
|
};
|
|
432
601
|
});
|
|
433
602
|
const fromActivityTaskScheduled = (attributes, sequence, intake) => Effect.gen(function* () {
|
|
@@ -550,7 +719,313 @@ const fromContinueAsNew = (attributes, sequence, intake) => Effect.gen(function*
|
|
|
550
719
|
};
|
|
551
720
|
return intent;
|
|
552
721
|
});
|
|
722
|
+
const fromActivityTaskCancelRequested = (attributes, sequence, scheduledActivities) => {
|
|
723
|
+
const scheduledEventId = normalizeBigintIdentifier(attributes.scheduledEventId);
|
|
724
|
+
if (!scheduledEventId) {
|
|
725
|
+
return undefined;
|
|
726
|
+
}
|
|
727
|
+
const activityId = scheduledActivities.get(scheduledEventId);
|
|
728
|
+
if (!activityId) {
|
|
729
|
+
return undefined;
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
id: `cancel-activity-${sequence}`,
|
|
733
|
+
kind: 'request-cancel-activity',
|
|
734
|
+
sequence,
|
|
735
|
+
activityId,
|
|
736
|
+
scheduledEventId,
|
|
737
|
+
};
|
|
738
|
+
};
|
|
739
|
+
const fromTimerCanceled = (attributes, sequence, timersByStartEventId) => {
|
|
740
|
+
const startedEventId = normalizeBigintIdentifier(attributes.startedEventId);
|
|
741
|
+
const timerId = attributes.timerId || (startedEventId ? timersByStartEventId.get(startedEventId) : undefined);
|
|
742
|
+
if (!timerId) {
|
|
743
|
+
return undefined;
|
|
744
|
+
}
|
|
745
|
+
return {
|
|
746
|
+
id: `cancel-timer-${sequence}`,
|
|
747
|
+
kind: 'cancel-timer',
|
|
748
|
+
sequence,
|
|
749
|
+
timerId,
|
|
750
|
+
startedEventId,
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
const fromRequestCancelExternalWorkflow = (attributes, sequence, intake) => {
|
|
754
|
+
const workflowId = attributes.workflowExecution?.workflowId ?? intake.info.workflowId;
|
|
755
|
+
if (!workflowId) {
|
|
756
|
+
return undefined;
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
id: `cancel-external-${sequence}`,
|
|
760
|
+
kind: 'request-cancel-external-workflow',
|
|
761
|
+
sequence,
|
|
762
|
+
namespace: attributes.namespace || intake.info.namespace,
|
|
763
|
+
workflowId,
|
|
764
|
+
runId: attributes.workflowExecution?.runId || undefined,
|
|
765
|
+
childWorkflowOnly: attributes.childWorkflowOnly ?? false,
|
|
766
|
+
reason: attributes.reason || undefined,
|
|
767
|
+
};
|
|
768
|
+
};
|
|
769
|
+
const fromMarkerRecorded = (attributes, sequence, intake) => Effect.gen(function* () {
|
|
770
|
+
const markerName = attributes.markerName || 'marker';
|
|
771
|
+
const details = yield* decodeMarkerDetails(intake.dataConverter, attributes.details);
|
|
772
|
+
return {
|
|
773
|
+
id: `record-marker-${sequence}`,
|
|
774
|
+
kind: 'record-marker',
|
|
775
|
+
sequence,
|
|
776
|
+
markerName,
|
|
777
|
+
details,
|
|
778
|
+
};
|
|
779
|
+
});
|
|
780
|
+
const fromUpsertSearchAttributes = (attributes, sequence, intake) => Effect.gen(function* () {
|
|
781
|
+
const searchAttributes = yield* decodeSearchAttributes(intake.dataConverter, attributes.searchAttributes);
|
|
782
|
+
if (!searchAttributes) {
|
|
783
|
+
return undefined;
|
|
784
|
+
}
|
|
785
|
+
return {
|
|
786
|
+
id: `upsert-search-attributes-${sequence}`,
|
|
787
|
+
kind: 'upsert-search-attributes',
|
|
788
|
+
sequence,
|
|
789
|
+
searchAttributes,
|
|
790
|
+
};
|
|
791
|
+
});
|
|
792
|
+
const fromWorkflowPropertiesModified = (attributes, sequence, intake) => Effect.gen(function* () {
|
|
793
|
+
const memo = yield* decodeMemo(intake.dataConverter, attributes.upsertedMemo);
|
|
794
|
+
return {
|
|
795
|
+
id: `modify-workflow-properties-${sequence}`,
|
|
796
|
+
kind: 'modify-workflow-properties',
|
|
797
|
+
sequence,
|
|
798
|
+
memo,
|
|
799
|
+
};
|
|
800
|
+
});
|
|
801
|
+
const collectWorkflowUpdateEntries = (events) => {
|
|
802
|
+
const updates = [];
|
|
803
|
+
for (const event of events) {
|
|
804
|
+
if (!event.attributes) {
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
const historyEventId = normalizeEventId(event.eventId) ?? undefined;
|
|
808
|
+
switch (event.eventType) {
|
|
809
|
+
case EventType.WORKFLOW_EXECUTION_UPDATE_ADMITTED: {
|
|
810
|
+
if (event.attributes.case !== 'workflowExecutionUpdateAdmittedEventAttributes') {
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
const attrs = event.attributes.value;
|
|
814
|
+
const updateId = normalizeUpdateId(attrs.request?.meta?.updateId);
|
|
815
|
+
if (!updateId) {
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
updates.push({
|
|
819
|
+
updateId,
|
|
820
|
+
stage: 'admitted',
|
|
821
|
+
handlerName: normalizeOptionalNonEmptyString(attrs.request?.input?.name),
|
|
822
|
+
identity: normalizeOptionalNonEmptyString(attrs.request?.meta?.identity),
|
|
823
|
+
historyEventId,
|
|
824
|
+
});
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
case EventType.WORKFLOW_EXECUTION_UPDATE_ACCEPTED: {
|
|
828
|
+
if (event.attributes.case !== 'workflowExecutionUpdateAcceptedEventAttributes') {
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
const attrs = event.attributes.value;
|
|
832
|
+
const updateId = normalizeUpdateId(attrs.acceptedRequest?.meta?.updateId);
|
|
833
|
+
if (!updateId) {
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
updates.push({
|
|
837
|
+
updateId,
|
|
838
|
+
stage: 'accepted',
|
|
839
|
+
handlerName: normalizeOptionalNonEmptyString(attrs.acceptedRequest?.input?.name),
|
|
840
|
+
identity: normalizeOptionalNonEmptyString(attrs.acceptedRequest?.meta?.identity),
|
|
841
|
+
messageId: normalizeOptionalNonEmptyString(attrs.acceptedRequestMessageId),
|
|
842
|
+
sequencingEventId: normalizeBigintIdentifier(attrs.acceptedRequestSequencingEventId),
|
|
843
|
+
historyEventId,
|
|
844
|
+
});
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
case EventType.WORKFLOW_EXECUTION_UPDATE_REJECTED: {
|
|
848
|
+
if (event.attributes.case !== 'workflowExecutionUpdateRejectedEventAttributes') {
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
const attrs = event.attributes.value;
|
|
852
|
+
const updateId = normalizeUpdateId(attrs.rejectedRequest?.meta?.updateId);
|
|
853
|
+
if (!updateId) {
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
updates.push({
|
|
857
|
+
updateId,
|
|
858
|
+
stage: 'rejected',
|
|
859
|
+
handlerName: normalizeOptionalNonEmptyString(attrs.rejectedRequest?.input?.name),
|
|
860
|
+
identity: normalizeOptionalNonEmptyString(attrs.rejectedRequest?.meta?.identity),
|
|
861
|
+
messageId: normalizeOptionalNonEmptyString(attrs.rejectedRequestMessageId),
|
|
862
|
+
sequencingEventId: normalizeBigintIdentifier(attrs.rejectedRequestSequencingEventId),
|
|
863
|
+
failureMessage: normalizeOptionalNonEmptyString(attrs.failure?.message),
|
|
864
|
+
historyEventId,
|
|
865
|
+
});
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
case EventType.WORKFLOW_EXECUTION_UPDATE_COMPLETED: {
|
|
869
|
+
if (event.attributes.case !== 'workflowExecutionUpdateCompletedEventAttributes') {
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
const attrs = event.attributes.value;
|
|
873
|
+
const updateId = normalizeUpdateId(attrs.meta?.updateId);
|
|
874
|
+
if (!updateId) {
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
877
|
+
updates.push({
|
|
878
|
+
updateId,
|
|
879
|
+
stage: 'completed',
|
|
880
|
+
identity: normalizeOptionalNonEmptyString(attrs.meta?.identity),
|
|
881
|
+
acceptedEventId: normalizeBigintIdentifier(attrs.acceptedEventId),
|
|
882
|
+
outcome: resolveOutcomeStatus(attrs.outcome),
|
|
883
|
+
historyEventId,
|
|
884
|
+
});
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
default:
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return updates;
|
|
892
|
+
};
|
|
893
|
+
const collectWorkflowUpdateInvocations = async (events, dataConverter) => {
|
|
894
|
+
const invocations = [];
|
|
895
|
+
for (const event of events) {
|
|
896
|
+
if (event.eventType === EventType.WORKFLOW_EXECUTION_UPDATE_ACCEPTED) {
|
|
897
|
+
if (event.attributes.case !== 'workflowExecutionUpdateAcceptedEventAttributes') {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
const attrs = event.attributes.value;
|
|
901
|
+
const invocation = await buildUpdateInvocationFromRequest({
|
|
902
|
+
request: attrs.acceptedRequest,
|
|
903
|
+
protocolInstanceId: attrs.protocolInstanceId,
|
|
904
|
+
requestMessageId: attrs.acceptedRequestMessageId,
|
|
905
|
+
sequencingEventId: attrs.acceptedRequestSequencingEventId,
|
|
906
|
+
fallbackEventId: event.eventId,
|
|
907
|
+
dataConverter,
|
|
908
|
+
});
|
|
909
|
+
if (invocation) {
|
|
910
|
+
invocations.push(invocation);
|
|
911
|
+
}
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
if (event.eventType === EventType.WORKFLOW_EXECUTION_UPDATE_REJECTED) {
|
|
915
|
+
if (event.attributes.case !== 'workflowExecutionUpdateRejectedEventAttributes') {
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
const attrs = event.attributes.value;
|
|
919
|
+
const invocation = await buildUpdateInvocationFromRequest({
|
|
920
|
+
request: attrs.rejectedRequest,
|
|
921
|
+
protocolInstanceId: attrs.protocolInstanceId,
|
|
922
|
+
requestMessageId: attrs.rejectedRequestMessageId,
|
|
923
|
+
sequencingEventId: attrs.rejectedRequestSequencingEventId,
|
|
924
|
+
fallbackEventId: event.eventId,
|
|
925
|
+
dataConverter,
|
|
926
|
+
});
|
|
927
|
+
if (invocation) {
|
|
928
|
+
invocations.push(invocation);
|
|
929
|
+
}
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
if (event.eventType === EventType.WORKFLOW_EXECUTION_UPDATE_ADMITTED) {
|
|
933
|
+
if (event.attributes.case !== 'workflowExecutionUpdateAdmittedEventAttributes') {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
const attrs = event.attributes.value;
|
|
937
|
+
const invocation = await buildUpdateInvocationFromRequest({
|
|
938
|
+
request: attrs.request,
|
|
939
|
+
protocolInstanceId: 'history-admitted',
|
|
940
|
+
requestMessageId: `history-${event.eventId ?? 'update-admitted'}`,
|
|
941
|
+
sequencingEventId: event.eventId ? BigInt(event.eventId) : undefined,
|
|
942
|
+
fallbackEventId: event.eventId,
|
|
943
|
+
dataConverter,
|
|
944
|
+
});
|
|
945
|
+
if (invocation) {
|
|
946
|
+
invocations.push(invocation);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return invocations;
|
|
951
|
+
};
|
|
952
|
+
const buildUpdateInvocationFromRequest = async (input) => {
|
|
953
|
+
const req = input.request;
|
|
954
|
+
const updateId = normalizeUpdateId(req?.meta?.updateId);
|
|
955
|
+
const updateName = req?.input?.name?.trim();
|
|
956
|
+
if (!updateId || !updateName) {
|
|
957
|
+
return undefined;
|
|
958
|
+
}
|
|
959
|
+
const values = (await decodePayloadsToValues(input.dataConverter, req?.input?.args?.payloads ?? []))?.map((value) => value) ?? [];
|
|
960
|
+
const payload = normalizeUpdateInvocationPayload(values);
|
|
961
|
+
const sequencing = input.sequencingEventId !== undefined
|
|
962
|
+
? input.sequencingEventId.toString()
|
|
963
|
+
: input.fallbackEventId !== undefined && input.fallbackEventId !== null
|
|
964
|
+
? String(input.fallbackEventId)
|
|
965
|
+
: undefined;
|
|
966
|
+
return {
|
|
967
|
+
protocolInstanceId: input.protocolInstanceId ?? 'history-replay',
|
|
968
|
+
requestMessageId: input.requestMessageId ?? updateId,
|
|
969
|
+
updateId,
|
|
970
|
+
name: updateName,
|
|
971
|
+
payload,
|
|
972
|
+
identity: req?.meta?.identity,
|
|
973
|
+
sequencingEventId: sequencing,
|
|
974
|
+
};
|
|
975
|
+
};
|
|
976
|
+
const normalizeUpdateInvocationPayload = (values) => {
|
|
977
|
+
if (!values || values.length === 0) {
|
|
978
|
+
return undefined;
|
|
979
|
+
}
|
|
980
|
+
if (values.length === 1) {
|
|
981
|
+
return values[0];
|
|
982
|
+
}
|
|
983
|
+
return values;
|
|
984
|
+
};
|
|
553
985
|
const decodePayloadArray = (converter, payloads) => Effect.tryPromise(async () => await decodePayloadsToValues(converter, payloads?.payloads ?? []));
|
|
986
|
+
const decodeMarkerDetails = (converter, details) => Effect.tryPromise(async () => {
|
|
987
|
+
if (!details || Object.keys(details).length === 0) {
|
|
988
|
+
return undefined;
|
|
989
|
+
}
|
|
990
|
+
const decoded = {};
|
|
991
|
+
for (const [key, payloads] of Object.entries(details)) {
|
|
992
|
+
const values = await decodePayloadsToValues(converter, payloads?.payloads ?? []);
|
|
993
|
+
if (values.length === 0) {
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
decoded[key] = values.length === 1 ? values[0] : values;
|
|
997
|
+
}
|
|
998
|
+
return Object.keys(decoded).length > 0 ? decoded : undefined;
|
|
999
|
+
});
|
|
1000
|
+
const decodeSearchAttributes = (converter, input) => Effect.tryPromise(async () => {
|
|
1001
|
+
const fields = input?.indexedFields;
|
|
1002
|
+
if (!fields || Object.keys(fields).length === 0) {
|
|
1003
|
+
return undefined;
|
|
1004
|
+
}
|
|
1005
|
+
const decoded = {};
|
|
1006
|
+
for (const [key, payload] of Object.entries(fields)) {
|
|
1007
|
+
const values = await decodePayloadsToValues(converter, payload ? [payload] : []);
|
|
1008
|
+
if (values.length === 0) {
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
decoded[key] = values.length === 1 ? values[0] : values;
|
|
1012
|
+
}
|
|
1013
|
+
return decoded;
|
|
1014
|
+
});
|
|
1015
|
+
const decodeMemo = (converter, memo) => Effect.tryPromise(async () => {
|
|
1016
|
+
const decoded = {};
|
|
1017
|
+
const fields = memo?.fields ?? {};
|
|
1018
|
+
for (const [key, payload] of Object.entries(fields)) {
|
|
1019
|
+
const values = await decodePayloadsToValues(converter, payload ? [payload] : []);
|
|
1020
|
+
if (values.length === 0) {
|
|
1021
|
+
decoded[key] = undefined;
|
|
1022
|
+
}
|
|
1023
|
+
else {
|
|
1024
|
+
decoded[key] = values.length === 1 ? values[0] : values;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return decoded;
|
|
1028
|
+
});
|
|
554
1029
|
const convertRetryPolicy = (policy) => {
|
|
555
1030
|
if (!policy) {
|
|
556
1031
|
return undefined;
|
|
@@ -575,6 +1050,45 @@ const convertRetryPolicy = (policy) => {
|
|
|
575
1050
|
...(nonRetryable !== undefined ? { nonRetryableErrorTypes: nonRetryable } : {}),
|
|
576
1051
|
};
|
|
577
1052
|
};
|
|
1053
|
+
const normalizeUpdateId = (value) => {
|
|
1054
|
+
if (typeof value !== 'string') {
|
|
1055
|
+
return undefined;
|
|
1056
|
+
}
|
|
1057
|
+
const trimmed = value.trim();
|
|
1058
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1059
|
+
};
|
|
1060
|
+
const normalizeOptionalNonEmptyString = (value) => {
|
|
1061
|
+
if (typeof value !== 'string') {
|
|
1062
|
+
return undefined;
|
|
1063
|
+
}
|
|
1064
|
+
const trimmed = value.trim();
|
|
1065
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1066
|
+
};
|
|
1067
|
+
const normalizeBigintIdentifier = (value) => {
|
|
1068
|
+
if (value === undefined || value === null) {
|
|
1069
|
+
return undefined;
|
|
1070
|
+
}
|
|
1071
|
+
if (typeof value === 'string') {
|
|
1072
|
+
return value.length > 0 ? value : undefined;
|
|
1073
|
+
}
|
|
1074
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1075
|
+
return value.toString();
|
|
1076
|
+
}
|
|
1077
|
+
if (typeof value === 'bigint') {
|
|
1078
|
+
return value.toString();
|
|
1079
|
+
}
|
|
1080
|
+
return undefined;
|
|
1081
|
+
};
|
|
1082
|
+
const resolveOutcomeStatus = (outcome) => {
|
|
1083
|
+
const caseName = outcome?.value?.case;
|
|
1084
|
+
if (caseName === 'success') {
|
|
1085
|
+
return 'success';
|
|
1086
|
+
}
|
|
1087
|
+
if (caseName === 'failure') {
|
|
1088
|
+
return 'failure';
|
|
1089
|
+
}
|
|
1090
|
+
return undefined;
|
|
1091
|
+
};
|
|
578
1092
|
const sanitizeDeterminismMarkerEnvelope = (input) => {
|
|
579
1093
|
const schemaVersion = input.schemaVersion;
|
|
580
1094
|
if (schemaVersion !== DETERMINISM_MARKER_SCHEMA_VERSION) {
|
|
@@ -611,6 +1125,9 @@ const sanitizeDeterminismState = (value) => {
|
|
|
611
1125
|
const commandHistoryRaw = value.commandHistory;
|
|
612
1126
|
const randomValuesRaw = value.randomValues;
|
|
613
1127
|
const timeValuesRaw = value.timeValues;
|
|
1128
|
+
const signalsRaw = Array.isArray(value.signals) ? value.signals : [];
|
|
1129
|
+
const queriesRaw = Array.isArray(value.queries) ? value.queries : [];
|
|
1130
|
+
const updatesRaw = value.updates;
|
|
614
1131
|
if (!Array.isArray(commandHistoryRaw) || !Array.isArray(randomValuesRaw) || !Array.isArray(timeValuesRaw)) {
|
|
615
1132
|
throw new Error('Determinism marker contained invalid determinism state shape');
|
|
616
1133
|
}
|
|
@@ -627,11 +1144,17 @@ const sanitizeDeterminismState = (value) => {
|
|
|
627
1144
|
const randomValues = randomValuesRaw.map((val, index) => coerceNumber(val, `determinism.randomValues[${index}]`));
|
|
628
1145
|
const timeValues = timeValuesRaw.map((val, index) => coerceNumber(val, `determinism.timeValues[${index}]`));
|
|
629
1146
|
const failureMetadata = sanitizeFailureMetadata(value.failureMetadata);
|
|
1147
|
+
const signals = signalsRaw.map((record, index) => sanitizeSignalRecord(record, index));
|
|
1148
|
+
const queries = queriesRaw.map((record, index) => sanitizeQueryRecord(record, index));
|
|
1149
|
+
const updates = sanitizeDeterminismUpdates(updatesRaw);
|
|
630
1150
|
return {
|
|
631
1151
|
commandHistory,
|
|
632
1152
|
randomValues,
|
|
633
1153
|
timeValues,
|
|
634
1154
|
...(failureMetadata ? { failureMetadata } : {}),
|
|
1155
|
+
signals,
|
|
1156
|
+
queries,
|
|
1157
|
+
...(updates ? { updates } : {}),
|
|
635
1158
|
};
|
|
636
1159
|
};
|
|
637
1160
|
const sanitizeCommandMetadata = (value, index) => {
|
|
@@ -678,6 +1201,81 @@ const sanitizeFailureMetadata = (value) => {
|
|
|
678
1201
|
...(retryState !== undefined ? { retryState } : {}),
|
|
679
1202
|
};
|
|
680
1203
|
};
|
|
1204
|
+
const sanitizeDeterminismUpdates = (value) => {
|
|
1205
|
+
if (value === undefined || value === null) {
|
|
1206
|
+
return undefined;
|
|
1207
|
+
}
|
|
1208
|
+
if (!Array.isArray(value)) {
|
|
1209
|
+
throw new Error('Determinism marker contained invalid updates list');
|
|
1210
|
+
}
|
|
1211
|
+
return value.map((entry, index) => {
|
|
1212
|
+
if (!isRecord(entry)) {
|
|
1213
|
+
throw new Error(`Determinism marker update entry ${index} is invalid`);
|
|
1214
|
+
}
|
|
1215
|
+
const updateId = coerceString(entry.updateId, `determinism.updates[${index}].updateId`);
|
|
1216
|
+
const stage = sanitizeUpdateStage(entry.stage, index);
|
|
1217
|
+
const handlerName = coerceOptionalTrimmedString(entry.handlerName, `determinism.updates[${index}].handlerName`);
|
|
1218
|
+
const identity = coerceOptionalTrimmedString(entry.identity, `determinism.updates[${index}].identity`);
|
|
1219
|
+
const sequencingEventId = coerceOptionalTrimmedString(entry.sequencingEventId, `determinism.updates[${index}].sequencingEventId`);
|
|
1220
|
+
const messageId = coerceOptionalTrimmedString(entry.messageId, `determinism.updates[${index}].messageId`);
|
|
1221
|
+
const acceptedEventId = coerceOptionalTrimmedString(entry.acceptedEventId, `determinism.updates[${index}].acceptedEventId`);
|
|
1222
|
+
const outcome = sanitizeUpdateOutcome(entry.outcome, index);
|
|
1223
|
+
const failureMessage = coerceOptionalTrimmedString(entry.failureMessage, `determinism.updates[${index}].failureMessage`);
|
|
1224
|
+
const historyEventId = coerceOptionalTrimmedString(entry.historyEventId, `determinism.updates[${index}].historyEventId`);
|
|
1225
|
+
return {
|
|
1226
|
+
updateId,
|
|
1227
|
+
stage,
|
|
1228
|
+
...(handlerName ? { handlerName } : {}),
|
|
1229
|
+
...(identity ? { identity } : {}),
|
|
1230
|
+
...(sequencingEventId ? { sequencingEventId } : {}),
|
|
1231
|
+
...(messageId ? { messageId } : {}),
|
|
1232
|
+
...(acceptedEventId ? { acceptedEventId } : {}),
|
|
1233
|
+
...(outcome ? { outcome } : {}),
|
|
1234
|
+
...(failureMessage ? { failureMessage } : {}),
|
|
1235
|
+
...(historyEventId ? { historyEventId } : {}),
|
|
1236
|
+
};
|
|
1237
|
+
});
|
|
1238
|
+
};
|
|
1239
|
+
const sanitizeSignalRecord = (value, index) => {
|
|
1240
|
+
if (!isRecord(value)) {
|
|
1241
|
+
throw new Error(`Determinism marker contained invalid signal entry at index ${index}`);
|
|
1242
|
+
}
|
|
1243
|
+
const signalName = coerceString(value.signalName, `determinism.signals[${index}].signalName`);
|
|
1244
|
+
const payloadHash = coerceString(value.payloadHash, `determinism.signals[${index}].payloadHash`);
|
|
1245
|
+
const handlerName = coerceOptionalString(value.handlerName, `determinism.signals[${index}].handlerName`);
|
|
1246
|
+
const eventId = normalizeOptionalEventId(value.eventId, `determinism.signals[${index}].eventId`);
|
|
1247
|
+
const workflowTaskCompletedEventId = normalizeOptionalEventId(value.workflowTaskCompletedEventId, `determinism.signals[${index}].workflowTaskCompletedEventId`);
|
|
1248
|
+
const identity = coerceOptionalString(value.identity, `determinism.signals[${index}].identity`);
|
|
1249
|
+
return {
|
|
1250
|
+
signalName,
|
|
1251
|
+
payloadHash,
|
|
1252
|
+
...(handlerName ? { handlerName } : {}),
|
|
1253
|
+
...(eventId ? { eventId } : {}),
|
|
1254
|
+
...(workflowTaskCompletedEventId ? { workflowTaskCompletedEventId } : {}),
|
|
1255
|
+
...(identity ? { identity } : {}),
|
|
1256
|
+
};
|
|
1257
|
+
};
|
|
1258
|
+
const sanitizeQueryRecord = (value, index) => {
|
|
1259
|
+
if (!isRecord(value)) {
|
|
1260
|
+
throw new Error(`Determinism marker contained invalid query entry at index ${index}`);
|
|
1261
|
+
}
|
|
1262
|
+
const queryName = coerceString(value.queryName, `determinism.queries[${index}].queryName`);
|
|
1263
|
+
const requestHash = coerceString(value.requestHash, `determinism.queries[${index}].requestHash`);
|
|
1264
|
+
const handlerName = coerceOptionalString(value.handlerName, `determinism.queries[${index}].handlerName`);
|
|
1265
|
+
const identity = coerceOptionalString(value.identity, `determinism.queries[${index}].identity`);
|
|
1266
|
+
const queryId = coerceOptionalString(value.queryId, `determinism.queries[${index}].queryId`);
|
|
1267
|
+
const resultHash = coerceOptionalString(value.resultHash, `determinism.queries[${index}].resultHash`);
|
|
1268
|
+
const failureHash = coerceOptionalString(value.failureHash, `determinism.queries[${index}].failureHash`);
|
|
1269
|
+
return {
|
|
1270
|
+
queryName,
|
|
1271
|
+
requestHash,
|
|
1272
|
+
...(handlerName ? { handlerName } : {}),
|
|
1273
|
+
...(identity ? { identity } : {}),
|
|
1274
|
+
...(queryId ? { queryId } : {}),
|
|
1275
|
+
...(resultHash ? { resultHash } : {}),
|
|
1276
|
+
...(failureHash ? { failureHash } : {}),
|
|
1277
|
+
};
|
|
1278
|
+
};
|
|
681
1279
|
const sanitizeRecordedAt = (value) => {
|
|
682
1280
|
if (typeof value === 'string' && value.length > 0) {
|
|
683
1281
|
return value;
|
|
@@ -717,6 +1315,14 @@ const coerceOptionalString = (value, label) => {
|
|
|
717
1315
|
}
|
|
718
1316
|
return value.length > 0 ? value : undefined;
|
|
719
1317
|
};
|
|
1318
|
+
const coerceOptionalTrimmedString = (value, label) => {
|
|
1319
|
+
const raw = coerceOptionalString(value, label);
|
|
1320
|
+
if (raw === undefined) {
|
|
1321
|
+
return undefined;
|
|
1322
|
+
}
|
|
1323
|
+
const trimmed = raw.trim();
|
|
1324
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1325
|
+
};
|
|
720
1326
|
const coerceNumber = (value, label) => {
|
|
721
1327
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
722
1328
|
return value;
|
|
@@ -746,6 +1352,21 @@ const normalizeOptionalEventId = (value, label) => {
|
|
|
746
1352
|
throw new Error(`Determinism marker contained invalid ${label}`);
|
|
747
1353
|
}
|
|
748
1354
|
};
|
|
1355
|
+
const sanitizeUpdateStage = (value, index) => {
|
|
1356
|
+
if (value === 'admitted' || value === 'accepted' || value === 'rejected' || value === 'completed') {
|
|
1357
|
+
return value;
|
|
1358
|
+
}
|
|
1359
|
+
throw new Error(`Determinism marker update entry ${index} contained invalid stage`);
|
|
1360
|
+
};
|
|
1361
|
+
const sanitizeUpdateOutcome = (value, index) => {
|
|
1362
|
+
if (value === undefined || value === null) {
|
|
1363
|
+
return undefined;
|
|
1364
|
+
}
|
|
1365
|
+
if (value === 'success' || value === 'failure') {
|
|
1366
|
+
return value;
|
|
1367
|
+
}
|
|
1368
|
+
throw new Error(`Determinism marker update entry ${index} contained invalid outcome`);
|
|
1369
|
+
};
|
|
749
1370
|
const valuesEqual = (expected, actual) => {
|
|
750
1371
|
if (expected === undefined && actual === undefined) {
|
|
751
1372
|
return true;
|
|
@@ -755,5 +1376,48 @@ const valuesEqual = (expected, actual) => {
|
|
|
755
1376
|
}
|
|
756
1377
|
return Object.is(expected, actual);
|
|
757
1378
|
};
|
|
1379
|
+
const updatesEqual = (expected, actual) => {
|
|
1380
|
+
if (!expected && !actual) {
|
|
1381
|
+
return true;
|
|
1382
|
+
}
|
|
1383
|
+
if (!expected || !actual) {
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
return (expected.updateId === actual.updateId &&
|
|
1387
|
+
expected.stage === actual.stage &&
|
|
1388
|
+
expected.handlerName === actual.handlerName &&
|
|
1389
|
+
expected.identity === actual.identity &&
|
|
1390
|
+
expected.sequencingEventId === actual.sequencingEventId &&
|
|
1391
|
+
expected.messageId === actual.messageId &&
|
|
1392
|
+
expected.outcome === actual.outcome &&
|
|
1393
|
+
expected.failureMessage === actual.failureMessage);
|
|
1394
|
+
};
|
|
1395
|
+
const recordsMatch = (expected, actual) => {
|
|
1396
|
+
if (expected === undefined && actual === undefined) {
|
|
1397
|
+
return true;
|
|
1398
|
+
}
|
|
1399
|
+
if (expected === undefined || actual === undefined) {
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
return stableStringify(expected) === stableStringify(actual);
|
|
1403
|
+
};
|
|
1404
|
+
const mergePendingQueryRequests = (state, requests) => {
|
|
1405
|
+
if (!requests || requests.length === 0) {
|
|
1406
|
+
return state;
|
|
1407
|
+
}
|
|
1408
|
+
const nextQueries = state.queries ? [...state.queries] : [];
|
|
1409
|
+
for (const request of requests) {
|
|
1410
|
+
nextQueries.push({
|
|
1411
|
+
queryName: request.name,
|
|
1412
|
+
requestHash: stableStringify(request.args ?? []),
|
|
1413
|
+
...(request.metadata?.identity ? { identity: request.metadata.identity } : {}),
|
|
1414
|
+
...(request.id ? { queryId: request.id } : {}),
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
return {
|
|
1418
|
+
...state,
|
|
1419
|
+
queries: nextQueries,
|
|
1420
|
+
};
|
|
1421
|
+
};
|
|
758
1422
|
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
759
1423
|
//# sourceMappingURL=replay.js.map
|