@temporalio/common
Version:
Common library for code that's used across the Client, Worker, and/or Workflow
150 lines • 6.73 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.historyFromJSON = historyFromJSON;
exports.historyToJSON = historyToJSON;
exports.payloadToJSON = payloadToJSON;
exports.JSONToPayload = JSONToPayload;
const proto3_json_serializer_1 = require("proto3-json-serializer");
const proto = __importStar(require("@temporalio/proto"));
const patch_protobuf_root_1 = require("@temporalio/proto/lib/patch-protobuf-root");
// Cast to any because the generated proto module types are missing the lookupType method
const patched = (0, patch_protobuf_root_1.patchProtobufRoot)(proto);
const historyType = patched.lookupType('temporal.api.history.v1.History');
const payloadType = patched.lookupType('temporal.api.common.v1.Payload');
/**
* Convert a proto JSON representation of History to a valid History object
*/
function historyFromJSON(history) {
function pascalCaseToConstantCase(s) {
return s.replace(/[^\b][A-Z]/g, (m) => `${m[0]}_${m[1]}`).toUpperCase();
}
function fixEnumValue(obj, attr, prefix) {
return (obj[attr] && {
[attr]: obj[attr].startsWith(prefix) ? obj[attr] : `${prefix}_${pascalCaseToConstantCase(obj[attr])}`,
});
}
// fromProto3JSON doesn't allow null values on 'bytes' fields. This turns out to be a problem for payloads.
// Recursively descend on objects and array, and fix in-place any payload that has a null data field
function fixPayloads(e) {
function isPayload(p) {
return p && typeof p === 'object' && 'metadata' in p && 'data' in p;
}
if (e && typeof e === 'object') {
if (isPayload(e)) {
if (e.data === null) {
const { data: _data, ...rest } = e;
return rest;
}
return e;
}
if (Array.isArray(e))
return e.map(fixPayloads);
return Object.fromEntries(Object.entries(e).map(([k, v]) => [k, fixPayloads(v)]));
}
return e;
}
function fixHistoryEvent(e) {
const type = Object.keys(e).find((k) => k.endsWith('EventAttributes'));
if (!type) {
throw new TypeError(`Missing attributes in history event: ${JSON.stringify(e)}`);
}
// Fix payloads with null data
e = fixPayloads(e);
return {
...e,
...fixEnumValue(e, 'eventType', 'EVENT_TYPE'),
[type]: {
...e[type],
...(e[type].taskQueue && {
taskQueue: { ...e[type].taskQueue, ...fixEnumValue(e[type].taskQueue, 'kind', 'TASK_QUEUE_KIND') },
}),
...fixEnumValue(e[type], 'parentClosePolicy', 'PARENT_CLOSE_POLICY'),
...fixEnumValue(e[type], 'workflowIdReusePolicy', 'WORKFLOW_ID_REUSE_POLICY'),
...fixEnumValue(e[type], 'initiator', 'CONTINUE_AS_NEW_INITIATOR'),
...fixEnumValue(e[type], 'retryState', 'RETRY_STATE'),
...(e[type].childWorkflowExecutionFailureInfo && {
childWorkflowExecutionFailureInfo: {
...e[type].childWorkflowExecutionFailureInfo,
...fixEnumValue(e[type].childWorkflowExecutionFailureInfo, 'retryState', 'RETRY_STATE'),
},
}),
},
};
}
function fixHistory(h) {
return {
events: h.events.map(fixHistoryEvent),
};
}
if (typeof history !== 'object' || history == null || !Array.isArray(history.events)) {
throw new TypeError('Invalid history, expected an object with an array of events');
}
const loaded = (0, proto3_json_serializer_1.fromProto3JSON)(historyType, fixHistory(history));
if (loaded === null) {
throw new TypeError('Invalid history');
}
return loaded;
}
/**
* Convert an History object, e.g. as returned by `WorkflowClient.list().withHistory()`, to a JSON
* string that adheres to the same norm as JSON history files produced by other Temporal tools.
*/
function historyToJSON(history) {
// toProto3JSON doesn't correctly handle some of our "bytes" fields, passing them untouched to the
// output, after which JSON.stringify() would convert them to an array of numbers. As a workaround,
// recursively walk the object and convert all Buffer instances to base64 strings. Note this only
// works on proto3-json-serializer v2.0.0. v2.0.2 throws an error before we even get the chance
// to fix the buffers. See https://github.com/googleapis/proto3-json-serializer-nodejs/issues/103.
function fixBuffers(e) {
if (e && typeof e === 'object') {
if (e instanceof Buffer)
return e.toString('base64');
if (Array.isArray(e))
return e.map(fixBuffers);
return Object.fromEntries(Object.entries(e).map(([k, v]) => [k, fixBuffers(v)]));
}
return e;
}
const protoJson = (0, proto3_json_serializer_1.toProto3JSON)(proto.temporal.api.history.v1.History.fromObject(history));
return JSON.stringify(fixBuffers(protoJson), null, 2);
}
/**
* Convert from protobuf payload to JSON
*/
function payloadToJSON(payload) {
return (0, proto3_json_serializer_1.toProto3JSON)(patched.temporal.api.common.v1.Payload.create(payload));
}
/**
* Convert from JSON to protobuf payload
*/
function JSONToPayload(json) {
const loaded = (0, proto3_json_serializer_1.fromProto3JSON)(payloadType, json);
if (loaded === null) {
throw new TypeError('Invalid payload');
}
return loaded;
}
//# sourceMappingURL=proto-utils.js.map