UNPKG

@temporalio/common

Version:

Common library for code that's used across the Client, Worker, and/or Workflow

155 lines 6.81 kB
"use strict"; 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.fixBuffers = fixBuffers; 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) { const protoJson = (0, proto3_json_serializer_1.toProto3JSON)(proto.temporal.api.history.v1.History.fromObject(history)); return JSON.stringify(fixBuffers(protoJson), null, 2); } /** * 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 (e instanceof Uint8Array) return Buffer.from(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; } /** * Convert from protobuf payload to JSON */ function payloadToJSON(payload) { return fixBuffers((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