@temporalio/common
Version:
Common library for code that's used across the Client, Worker, and/or Workflow
218 lines • 8.81 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.DefaultPayloadConverterWithProtobufs = exports.ProtobufJsonPayloadConverter = exports.ProtobufBinaryPayloadConverter = void 0;
const protoJsonSerializer = __importStar(require("proto3-json-serializer"));
const encoding_1 = require("../encoding");
const errors_1 = require("../errors");
const type_helpers_1 = require("../type-helpers");
const payload_converter_1 = require("./payload-converter");
const types_1 = require("./types");
const GLOBAL_BUFFER = globalThis.constructor.constructor('return globalThis.Buffer')();
class ProtobufPayloadConverter {
root;
// Don't use type Root here because root.d.ts doesn't export Root, so users would have to type assert
constructor(root) {
if (root) {
if (!isRoot(root)) {
throw new TypeError('root must be an instance of a protobufjs Root');
}
this.root = root;
}
}
validatePayload(content) {
if (content.data === undefined || content.data === null) {
throw new errors_1.ValueError('Got payload with no data');
}
if (!content.metadata || !(types_1.METADATA_MESSAGE_TYPE_KEY in content.metadata)) {
throw new errors_1.ValueError(`Got protobuf payload without metadata.${types_1.METADATA_MESSAGE_TYPE_KEY}`);
}
if (!this.root) {
throw new errors_1.PayloadConverterError('Unable to deserialize protobuf message without `root` being provided');
}
const messageTypeName = (0, encoding_1.decode)(content.metadata[types_1.METADATA_MESSAGE_TYPE_KEY]);
let messageType;
try {
messageType = this.root.lookupType(messageTypeName);
}
catch (e) {
if ((0, type_helpers_1.errorMessage)(e)?.includes('no such type')) {
throw new errors_1.PayloadConverterError(`Got a \`${messageTypeName}\` protobuf message but cannot find corresponding message class in \`root\``);
}
throw e;
}
return { messageType, data: content.data };
}
constructPayload({ messageTypeName, message }) {
return {
metadata: {
[types_1.METADATA_ENCODING_KEY]: (0, encoding_1.encode)(this.encodingType),
[types_1.METADATA_MESSAGE_TYPE_KEY]: (0, encoding_1.encode)(messageTypeName),
},
data: message,
};
}
}
/**
* Converts between protobufjs Message instances and serialized Protobuf Payload
*/
class ProtobufBinaryPayloadConverter extends ProtobufPayloadConverter {
encodingType = types_1.encodingTypes.METADATA_ENCODING_PROTOBUF;
/**
* @param root The value returned from {@link patchProtobufRoot}
*/
constructor(root) {
super(root);
}
toPayload(value) {
if (!isProtobufMessage(value)) {
return undefined;
}
return this.constructPayload({
messageTypeName: getNamespacedTypeName(value.$type),
message: value.$type.encode(value).finish(),
});
}
fromPayload(content) {
const { messageType, data } = this.validatePayload(content);
// Wrap with Uint8Array from this context to ensure `instanceof` works
const localData = data ? new Uint8Array(data.buffer, data.byteOffset, data.length) : data;
return messageType.decode(localData);
}
}
exports.ProtobufBinaryPayloadConverter = ProtobufBinaryPayloadConverter;
/**
* Converts between protobufjs Message instances and serialized JSON Payload
*/
class ProtobufJsonPayloadConverter extends ProtobufPayloadConverter {
encodingType = types_1.encodingTypes.METADATA_ENCODING_PROTOBUF_JSON;
/**
* @param root The value returned from {@link patchProtobufRoot}
*/
constructor(root) {
super(root);
}
toPayload(value) {
if (!isProtobufMessage(value)) {
return undefined;
}
const hasBufferChanged = setBufferInGlobal();
try {
const jsonValue = protoJsonSerializer.toProto3JSON(value);
return this.constructPayload({
messageTypeName: getNamespacedTypeName(value.$type),
message: (0, encoding_1.encode)(JSON.stringify(jsonValue)),
});
}
finally {
resetBufferInGlobal(hasBufferChanged);
}
}
fromPayload(content) {
const hasBufferChanged = setBufferInGlobal();
try {
const { messageType, data } = this.validatePayload(content);
const res = protoJsonSerializer.fromProto3JSON(messageType, JSON.parse((0, encoding_1.decode)(data)));
if (Buffer.isBuffer(res)) {
return new Uint8Array(res);
}
replaceBuffers(res);
return res;
}
finally {
resetBufferInGlobal(hasBufferChanged);
}
}
}
exports.ProtobufJsonPayloadConverter = ProtobufJsonPayloadConverter;
function replaceBuffers(obj) {
const replaceBuffersImpl = (value, key, target) => {
if (Buffer.isBuffer(value)) {
target[key] = new Uint8Array(value);
}
else {
replaceBuffers(value);
}
};
if (obj != null && typeof obj === 'object') {
// Performance optimization for large arrays
if (Array.isArray(obj)) {
obj.forEach(replaceBuffersImpl);
}
else {
for (const [key, value] of Object.entries(obj)) {
replaceBuffersImpl(value, key, obj);
}
}
}
}
function setBufferInGlobal() {
if (typeof globalThis.Buffer === 'undefined') {
globalThis.Buffer = GLOBAL_BUFFER;
return true;
}
return false;
}
function resetBufferInGlobal(hasChanged) {
if (hasChanged) {
delete globalThis.Buffer;
}
}
function isProtobufType(type) {
return ((0, type_helpers_1.isRecord)(type) &&
// constructor.name may get mangled by minifiers; thanksfuly protobufjs also sets a className property
type.constructor.className === 'Type' &&
(0, type_helpers_1.hasOwnProperties)(type, ['parent', 'name', 'create', 'encode', 'decode']) &&
typeof type.name === 'string' &&
typeof type.create === 'function' &&
typeof type.encode === 'function' &&
typeof type.decode === 'function');
}
function isProtobufMessage(value) {
return (0, type_helpers_1.isRecord)(value) && (0, type_helpers_1.hasOwnProperty)(value, '$type') && isProtobufType(value.$type);
}
function getNamespacedTypeName(node) {
if (node.parent && !isRoot(node.parent)) {
return getNamespacedTypeName(node.parent) + '.' + node.name;
}
else {
return node.name;
}
}
function isRoot(root) {
// constructor.name may get mangled by minifiers; thanksfuly protobufjs also sets a className property
return (0, type_helpers_1.isRecord)(root) && root.constructor.className === 'Root';
}
class DefaultPayloadConverterWithProtobufs extends payload_converter_1.CompositePayloadConverter {
// Match the order used in other SDKs.
//
// Go SDK:
// https://github.com/temporalio/sdk-go/blob/5e5645f0c550dcf717c095ae32c76a7087d2e985/converter/default_data_converter.go#L28
constructor({ protobufRoot }) {
super(new payload_converter_1.UndefinedPayloadConverter(), new payload_converter_1.BinaryPayloadConverter(), new ProtobufJsonPayloadConverter(protobufRoot), new ProtobufBinaryPayloadConverter(protobufRoot), new payload_converter_1.JsonPayloadConverter());
}
}
exports.DefaultPayloadConverterWithProtobufs = DefaultPayloadConverterWithProtobufs;
//# sourceMappingURL=protobuf-payload-converters.js.map