Skip to content

Commit ed28cf0

Browse files
authored
fix: Fix null payload data in historyFromJSON (#1109)
* fix: Fix null payload data in historyFromJSON * Address review comments + general improvement
1 parent c553b61 commit ed28cf0

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/common/src/proto-utils.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,36 @@ function fixEnumValue<O extends Record<string, any>>(obj: O, attr: keyof O, pref
2222
);
2323
}
2424

25+
// fromProto3JSON doesn't allow null values on 'bytes' fields. This turns out to be a problem for payloads.
26+
// Recursively descend on objects and array, and fix in-place any payload that has a null data field
27+
function fixPayloads<T>(e: T): T {
28+
function isPayload(p: any): p is JSONPayload {
29+
return p && typeof p === 'object' && 'metadata' in p && 'data' in p;
30+
}
31+
32+
if (e && typeof e === 'object') {
33+
if (isPayload(e)) {
34+
if (e.data === null) {
35+
const { data: _data, ...rest } = e;
36+
return rest as T;
37+
}
38+
return e;
39+
}
40+
if (Array.isArray(e)) return e.map(fixPayloads) as T;
41+
return Object.fromEntries(Object.entries(e as object).map(([k, v]) => [k, fixPayloads(v)])) as T;
42+
}
43+
return e;
44+
}
45+
2546
function fixHistoryEvent(e: Record<string, any>) {
2647
const type = Object.keys(e).find((k) => k.endsWith('EventAttributes'));
2748
if (!type) {
2849
throw new TypeError(`Missing attributes in history event: ${JSON.stringify(e)}`);
2950
}
3051

52+
// Fix payloads with null data
53+
e = fixPayloads(e);
54+
3155
return {
3256
...e,
3357
...fixEnumValue(e, 'eventType', 'EVENT_TYPE'),

packages/test/src/test-proto-utils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,35 @@ test('cancel-fake-progress-replay', async (t) => {
2222
);
2323
t.is(hist.events?.[0].workflowExecutionStartedEventAttributes?.taskQueue?.kind, TaskQueueKind.TASK_QUEUE_KIND_NORMAL);
2424
});
25+
26+
test('null payload data doesnt crash', async (t) => {
27+
const historyJson = {
28+
events: [
29+
{
30+
eventId: '16',
31+
eventTime: '2022-07-06T00:33:18.000Z',
32+
eventType: 'WorkflowExecutionCompleted',
33+
version: '0',
34+
taskId: '1057236',
35+
workflowExecutionCompletedEventAttributes: {
36+
result: { payloads: [{ metadata: { encoding: 'YmluYXJ5L251bGw=' }, data: null }] },
37+
workflowTaskCompletedEventId: '15',
38+
newExecutionRunId: '',
39+
},
40+
},
41+
],
42+
};
43+
44+
// This would throw an error if payload data was still null
45+
const history = historyFromJSON(historyJson);
46+
47+
// Make sure that other history properties were not corrupted
48+
t.is(
49+
Buffer.from(
50+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
51+
history.events?.[0].workflowExecutionCompletedEventAttributes?.result?.payloads?.[0].metadata!
52+
.encoding as Uint8Array
53+
).toString(),
54+
'binary/null'
55+
);
56+
});

0 commit comments

Comments
 (0)