UNPKG

@deno/kv

Version:

A Deno KV client library optimized for Node.js.

179 lines (178 loc) 6.23 kB
"use strict"; // Copyright 2023 the Deno authors. All rights reserved. MIT license. Object.defineProperty(exports, "__esModule", { value: true }); exports.UnknownV8 = exports.encodeV8 = exports.decodeV8 = exports.makeLimitedV8Serializer = void 0; // https://chromium.googlesource.com/v8/v8/+/refs/heads/main/src/objects/value-serializer.cc const bytes_js_1 = require("./bytes.js"); /** * Returns encodeV8, decodeV8 functions that support V8-compatible serialization for limited set of types (strings, null, undefined, boolean). * * Consider using JSON.parse/stringify to marshall values to save when using this serializer. * * All other values will throw during encode/decode. */ function makeLimitedV8Serializer() { return { encodeV8, decodeV8 }; } exports.makeLimitedV8Serializer = makeLimitedV8Serializer; function decodeV8(bytes, { wrapUnknownValues = false } = {}) { if (bytes.length === 0) throw new Error(`decode error: empty input`); let pos = 0; const kVersion = bytes[pos++]; if (kVersion !== SerializationTag.kVersion && wrapUnknownValues) { return new UnknownV8(bytes); } if (kVersion !== SerializationTag.kVersion) { throw new Error(`decode error: Unsupported kVersion ${kVersion} [${[...bytes].join(", ")}]`); } const version = bytes[pos++]; if (version !== kLatestVersion) { throw new Error(`decode error: Unsupported version ${version}`); } const tag = bytes[pos++]; if (tag === SerializationTag.kOneByteString) { const len = bytes[pos++]; const arr = bytes.subarray(pos, pos + len); const rt = new TextDecoder().decode(arr); pos += len; (0, bytes_js_1.checkEnd)(bytes, pos); return rt; } else if (tag === SerializationTag.kTwoByteString) { const len = bytes[pos++]; const arr = bytes.subarray(pos, pos + len); const rt = new TextDecoder("utf-16").decode(arr); pos += len; (0, bytes_js_1.checkEnd)(bytes, pos); return rt; } else if (tag === SerializationTag.kNull) { (0, bytes_js_1.checkEnd)(bytes, pos); return null; } else if (tag === SerializationTag.kUndefined) { (0, bytes_js_1.checkEnd)(bytes, pos); return undefined; } else if (tag === SerializationTag.kTrue) { (0, bytes_js_1.checkEnd)(bytes, pos); return true; } else if (tag === SerializationTag.kFalse) { (0, bytes_js_1.checkEnd)(bytes, pos); return false; } else if (tag === SerializationTag.kBigInt && bytes.length === 4 && bytes[3] === 0) { return 0n; } else if (wrapUnknownValues) { return new UnknownV8(bytes); } else { throw new Error(`decode error: Unsupported v8 tag ${tag} ('${String.fromCharCode(tag)}') at ${pos} in [${bytes.join(", ")}]`); } } exports.decodeV8 = decodeV8; function encodeV8(value) { if (value instanceof UnknownV8) { return value.bytes; } else if (typeof value === "string") { const chars = [...value]; if (chars.every(isOneByteChar)) { const charCodes = chars.map((v) => v.charCodeAt(0)); return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kOneByteString, charCodes.length, ...charCodes, ]); } const bytes = []; for (let i = 0; i < value.length; i++) { const charCode = value.charCodeAt(i); const msb = (charCode & 0xff00) >> 8; const lsb = charCode & 0x00ff; bytes.push(lsb); bytes.push(msb); } return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kTwoByteString, value.length * 2, ...bytes, ]); } else if (value === null) { return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kNull, ]); } else if (value === undefined) { return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kUndefined, ]); } else if (value === true) { return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kTrue, ]); } else if (value === false) { return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kFalse, ]); } else if (value === 0n) { return new Uint8Array([ SerializationTag.kVersion, kLatestVersion, SerializationTag.kBigInt, 0, ]); } throw new Error(`encode error: Unsupported v8 value ${typeof value} ${value}`); } exports.encodeV8 = encodeV8; // const kLatestVersion = 15; var SerializationTag; (function (SerializationTag) { SerializationTag[SerializationTag["kVersion"] = 255] = "kVersion"; SerializationTag[SerializationTag["kOneByteString"] = '"'.charCodeAt(0)] = "kOneByteString"; SerializationTag[SerializationTag["kTwoByteString"] = "c".charCodeAt(0)] = "kTwoByteString"; SerializationTag[SerializationTag["kNull"] = "0".charCodeAt(0)] = "kNull"; SerializationTag[SerializationTag["kUndefined"] = "_".charCodeAt(0)] = "kUndefined"; SerializationTag[SerializationTag["kTrue"] = "T".charCodeAt(0)] = "kTrue"; SerializationTag[SerializationTag["kFalse"] = "F".charCodeAt(0)] = "kFalse"; SerializationTag[SerializationTag["kBigInt"] = "Z".charCodeAt(0)] = "kBigInt"; })(SerializationTag || (SerializationTag = {})); function isOneByteChar(char) { const cp = char.codePointAt(0); return cp >= 0 && cp <= 0xff; } // /** Raw V8-serialized bytes */ class UnknownV8 { constructor(bytes) { Object.defineProperty(this, "bytes", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.bytes = bytes; } } exports.UnknownV8 = UnknownV8;