UNPKG

bebop

Version:

The TypeScript runtime for Bebop, a schema-based binary serialization format.

1,766 lines (1,763 loc) 62.6 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var TypeScript_exports = {}; __export(TypeScript_exports, { BebopJson: () => BebopJson, BebopRuntimeError: () => BebopRuntimeError, BebopTypeGuard: () => BebopTypeGuard, BebopView: () => BebopView, BinarySchema: () => BinarySchema, Guid: () => Guid, GuidMap: () => GuidMap }); module.exports = __toCommonJS(TypeScript_exports); // binary.ts var decoder = new TextDecoder(); var RecordReader = class { /** * @param schema - BinarySchema object containing metadata about Bebop schemas. * @private */ constructor(schema) { this.schema = schema; } /** * Reads a Bebop encoded record from a buffer. * * @param definitionName - Name of the definition in the schema for the record to read. * @param data - The buffer to read the record from. * @returns - The read record as a Record object. * @throws - Throws an error if the record cannot be decoded directly. * @public */ read(definitionName, data) { const definition = this.schema.getDefinition(definitionName); if (definition.kind === 4 /* Enum */) { throw new BebopRuntimeError("Cannot decode enum directly"); } const view = BebopView.getInstance(); view.startReading(data); return this.readDefinition(definition, view); } readDefinition(definition, view) { switch (definition.kind) { case 4 /* Enum */: return this.readEnumDefinition(definition, view); case 3 /* Union */: return this.readUnionDefinition(definition, view); case 1 /* Struct */: return this.readStructDefinition(definition, view); case 2 /* Message */: return this.readMessageDefinition(definition, view); default: throw new BebopRuntimeError(`Unknown type kind: ${definition.kind}`); } } readStructDefinition(definition, view) { const record = {}; Object.values(definition.fields).forEach((field) => { record[field.name] = this.readField(field, view); if (!(field.name in record) || record[field.name] === void 0) { throw new BebopRuntimeError(`Missing field ${field.name}`); } }); if (!definition.isMutable) { Object.freeze(record); } return record; } readMessageDefinition(definition, view) { const record = {}; const length = view.readMessageLength(); const end = view.index + length; const fields = Object.values(definition.fields); while (true) { const discriminator = view.readByte(); if (discriminator === 0) { return record; } const field = fields.find((f) => f.constantValue === discriminator); if (field === void 0) { view.index = end; return record; } record[field.name] = this.readField(field, view); } } readField(field, view) { if (field.typeId >= 0) { const definition = this.schema.getDefinition(field.typeId); return this.readDefinition(definition, view); } switch (field.fieldProperties.type) { case "scalar": return this.readScalar(field.typeId, view); case "array": return this.readArray( field.fieldProperties, field.fieldProperties.depth, view ); case "map": return this.readMap(field.fieldProperties, view); default: throw new BebopRuntimeError( `Unknown field type: ${field.fieldProperties}` ); } } readScalar(typeId, view) { switch (typeId) { case -1 /* Bool */: return !!view.readByte(); case -2 /* Byte */: return view.readByte(); case -3 /* UInt16 */: return view.readUint16(); case -4 /* Int16 */: return view.readInt16(); case -5 /* UInt32 */: return view.readUint32(); case -6 /* Int32 */: return view.readInt32(); case -7 /* UInt64 */: return view.readUint64(); case -8 /* Int64 */: return view.readInt64(); case -9 /* Float32 */: return view.readFloat32(); case -10 /* Float64 */: return view.readFloat64(); case -11 /* String */: return view.readString(); case -13 /* Date */: return view.readDate(); case -12 /* Guid */: return view.readGuid(); default: throw new BebopRuntimeError(`Unknown scalar type: ${typeId}`); } } readArray(field, depth, view) { if (field.type !== "array") { throw new BebopRuntimeError(`Expected array field, got ${field.type}`); } const memberType = field.memberTypeId; if (depth > 0) { const length2 = view.readUint32(); const array2 = new Array(length2); for (let i = 0; i < length2; i++) { array2[i] = this.readArray(field, depth - 1, view); } return array2; } if (memberType === -2 /* Byte */) { return view.readBytes(); } let definition; if (memberType >= 0) { definition = this.schema.getDefinition(memberType); } const length = view.readUint32(); const array = new Array(length); for (let i = 0; i < length; i++) { if (definition !== void 0) { array[i] = this.readDefinition(definition, view); } else { array[i] = this.readScalar(memberType, view); } } return array; } readMap(field, view) { if (field.type !== "map") { throw new BebopRuntimeError(`Expected map field, got ${field.type}`); } const keyType = field.keyTypeId; const valueType = field.valueTypeId; const map = field.keyTypeId === -12 /* Guid */ ? new GuidMap() : /* @__PURE__ */ new Map(); const size = view.readUint32(); let definition; if (valueType >= 0) { definition = this.schema.getDefinition(valueType); } for (let i = 0; i < size; i++) { const key = this.readScalar(keyType, view); let value; if (definition !== void 0) { value = this.readDefinition(definition, view); } else if (field.nestedType !== void 0) { const nested = field.nestedType; if (nested.type === "array") { value = this.readArray(nested, nested.depth, view); } else if (nested.type === "map") { value = this.readMap(nested, view); } } else { value = this.readScalar(valueType, view); } if (value === void 0) { throw new BebopRuntimeError(`Error decoding map value for key ${key}`); } map.set(key, value); } return map; } readEnumDefinition(definition, view) { switch (definition.baseType) { case -2 /* Byte */: return view.readByte(); case -3 /* UInt16 */: return view.readUint16(); case -4 /* Int16 */: return view.readInt16(); case -5 /* UInt32 */: return view.readUint32(); case -6 /* Int32 */: return view.readInt32(); case -7 /* UInt64 */: return view.readUint64(); case -8 /* Int64 */: return view.readInt64(); default: throw new BebopRuntimeError( `Unknown enum base type: ${definition.baseType}` ); } } readUnionDefinition(definition, view) { const length = view.readMessageLength(); const end = view.index + 1 + length; const discriminator = view.readByte(); const branch = definition.branches.find( (b) => b.discriminator === discriminator ); if (branch === void 0) { view.index = end; throw new BebopRuntimeError(`Unknown discriminator: ${discriminator}`); } return { discriminator, value: this.readDefinition( this.schema.getDefinition(branch.typeId), view ) }; } }; var RecordWriter = class { /** * @param schema Binary schema used for encoding the data. * @private */ constructor(schema) { this.schema = schema; } /** * Encodes a given record according to a provided definition name and returns it as a Uint8Array. * * @param definitionName Name of the definition to be used for encoding. * @param record The record to be encoded. * @returns Encoded record as a Uint8Array. */ write(definitionName, record) { const definition = this.schema.getDefinition(definitionName); const view = BebopView.getInstance(); view.startWriting(); this.writeDefinition(definition, view, record); return view.toArray(); } writeDefinition(definition, view, record) { switch (definition.kind) { case 4 /* Enum */: this.writeEnumDefinition(definition, view, record); break; case 3 /* Union */: this.writeUnionDefinition(definition, view, record); break; case 1 /* Struct */: this.writeStructDefinition(definition, view, record); break; case 2 /* Message */: this.writeMessageDefinition(definition, view, record); break; } } writeStructDefinition(definition, view, record) { if (!this.isRecord(record)) { throw new BebopRuntimeError(`Expected object, got ${typeof record}`); } const before = view.length; Object.values(definition.fields).forEach((field) => { if (!(field.name in record)) { throw new BebopRuntimeError(`Missing field: ${field.name}`); } if (record[field.name] === void 0) { throw new BebopRuntimeError(`Field ${field.name} is undefined`); } this.writeField(field, view, record[field.name]); }); const after = view.length; return after - before; } writeMessageDefinition(definition, view, record) { if (!this.isRecord(record)) { throw new BebopRuntimeError(`Expected object, got ${typeof record}`); } const before = view.length; const pos = view.reserveMessageLength(); const start = view.length; Object.values(definition.fields).forEach((field) => { if (field.constantValue === void 0 || field.constantValue === null) { throw new BebopRuntimeError( `Missing constant value for field: ${field.name}` ); } if (typeof field.constantValue !== "number") { throw new BebopRuntimeError( `Expected number, got ${typeof field.constantValue} for field: ${field.name}` ); } if (field.name in record && record[field.name] !== void 0) { view.writeByte(field.constantValue); this.writeField(field, view, record[field.name]); } }); view.writeByte(0); const end = view.length; view.fillMessageLength(pos, end - start); const after = view.length; return after - before; } writeEnumDefinition(definition, view, value) { if (typeof value !== "number" && typeof value !== "bigint") { throw new BebopRuntimeError( `Expected number or bigint, got ${typeof value}` ); } if ((definition.baseType === -8 /* Int64 */ || definition.baseType === -7 /* UInt64 */) && typeof value !== "bigint") { throw new BebopRuntimeError(`Expected bigint, got ${typeof value}`); } let valueFound = false; for (const member in definition.members) { if (definition.members[member].value === value) { valueFound = true; break; } } if (!valueFound) { throw new BebopRuntimeError( `Enum '${definition.name}' does not contain value: ${value}` ); } switch (definition.baseType) { case -2 /* Byte */: BebopTypeGuard.ensureUint8(value); view.writeByte(value); break; case -3 /* UInt16 */: BebopTypeGuard.ensureUint16(value); view.writeUint16(value); break; case -4 /* Int16 */: BebopTypeGuard.ensureInt16(value); view.writeInt16(value); break; case -5 /* UInt32 */: BebopTypeGuard.ensureUint32(value); view.writeUint32(value); break; case -6 /* Int32 */: BebopTypeGuard.ensureInt32(value); view.writeInt32(value); break; case -7 /* UInt64 */: BebopTypeGuard.ensureUint64(value); view.writeUint64(value); break; case -8 /* Int64 */: BebopTypeGuard.ensureInt64(value); view.writeInt64(value); break; default: throw new BebopRuntimeError( `Unknown enum base type: ${definition.baseType}` ); } } writeUnionDefinition(definition, view, record) { if (record === null || record === void 0 || typeof record !== "object") { throw new BebopRuntimeError(`Expected non-null object value`); } if (!("discriminator" in record && typeof record.discriminator === "number")) { throw new BebopRuntimeError(`Expected number 'discriminator' property`); } if (!("value" in record && record.value !== null && typeof record.value === "object")) { throw new BebopRuntimeError(`Expected 'value' property`); } const branch = definition.branches.find( (b) => b.discriminator === record.discriminator ); if (branch === void 0) { throw new BebopRuntimeError( `No branch found for discriminator: ${record.discriminator}` ); } const branchDefinition = this.schema.getDefinition(branch.typeId); const before = view.length; const pos = view.reserveMessageLength(); const start = view.length + 1; view.writeByte(record.discriminator); this.writeDefinition(branchDefinition, view, record.value); const end = view.length; view.fillMessageLength(pos, end - start); const after = view.length; return after - before; } writeField(field, view, value) { if (field.typeId >= 0) { const definition = this.schema.getDefinition(field.typeId); this.writeDefinition(definition, view, value); return; } switch (field.fieldProperties.type) { case "scalar": this.writeScalar(field.typeId, view, value); break; case "array": this.writeArray( field.fieldProperties, field.fieldProperties.depth, view, value ); break; case "map": this.writeMap(field.fieldProperties, view, value); break; default: throw new BebopRuntimeError( `Unknown field type: ${field.fieldProperties}` ); } } writeArray(field, depth, view, value) { if (field.type !== "array") { throw new BebopRuntimeError(`Expected array field, got ${field.type}`); } if (!Array.isArray(value) && !(value instanceof Uint8Array)) { throw new BebopRuntimeError(`Expected array, got ${typeof value}`); } if (field.memberTypeId === -2 /* Byte */ && !(value instanceof Uint8Array)) { throw new BebopRuntimeError(`Expected Uint8Array, got ${typeof value}`); } const memberType = field.memberTypeId; const length = value.length; if (depth > 0) { view.writeUint32(length); for (let i = 0; i < length; i++) { this.writeArray(field, depth - 1, view, value[i]); } return; } if (memberType === -2 /* Byte */) { view.writeBytes(value); } else { view.writeUint32(length); let definition; if (memberType >= 0) { definition = this.schema.getDefinition(memberType); } for (let i = 0; i < length; i++) { if (definition !== void 0) { this.writeDefinition(definition, view, value[i]); } else { this.writeScalar(memberType, view, value[i]); } } } } writeMap(field, view, value) { if (field.type !== "map") { throw new BebopRuntimeError(`Expected map field, got ${field.type}`); } if (!(value instanceof Map || value instanceof GuidMap)) { throw new BebopRuntimeError(`Expected Map, got ${typeof value}`); } const keyType = field.keyTypeId; const valueType = field.valueTypeId; const size = value.size; view.writeUint32(size); let definition; if (valueType >= 0) { definition = this.schema.getDefinition(valueType); } for (const [k, v] of value.entries()) { this.writeScalar(keyType, view, k); if (definition !== void 0) { this.writeDefinition(definition, view, v); } else if (field.nestedType !== void 0) { const nested = field.nestedType; if (nested.type === "array") { this.writeArray( nested, nested.depth, view, v ); } else if (nested.type === "map") { this.writeMap( nested, view, v ); } } else { this.writeScalar(valueType, view, v); } } } writeScalar(typeId, view, value) { switch (typeId) { case -1 /* Bool */: BebopTypeGuard.ensureBoolean(value); view.writeByte(Number(value)); break; case -2 /* Byte */: BebopTypeGuard.ensureUint8(value); view.writeByte(value); break; case -3 /* UInt16 */: BebopTypeGuard.ensureUint16(value); view.writeUint16(value); break; case -4 /* Int16 */: BebopTypeGuard.ensureInt16(value); view.writeInt16(value); break; case -5 /* UInt32 */: BebopTypeGuard.ensureUint32(value); view.writeUint32(value); break; case -6 /* Int32 */: BebopTypeGuard.ensureInt32(value); view.writeInt32(value); break; case -7 /* UInt64 */: BebopTypeGuard.ensureUint64(value); view.writeUint64(value); break; case -8 /* Int64 */: BebopTypeGuard.ensureInt64(value); view.writeInt64(value); break; case -9 /* Float32 */: BebopTypeGuard.ensureFloat(value); view.writeFloat32(value); break; case -10 /* Float64 */: BebopTypeGuard.ensureFloat(value); view.writeFloat64(value); break; case -11 /* String */: BebopTypeGuard.ensureString(value); view.writeString(value); break; case -12 /* Guid */: BebopTypeGuard.ensureGuid(value); view.writeGuid(value); break; case -13 /* Date */: BebopTypeGuard.ensureDate(value); view.writeDate(value); break; default: throw new BebopRuntimeError(`Unknown scalar type: ${typeId}`); } } isRecord(value) { return value !== null && typeof value === "object"; } }; var BinarySchema = class { /** * Create a new BinarySchema instance. * @param data - The binary data array. */ constructor(data) { this.data = data; this.view = new DataView(this.data.buffer); this.pos = 0; this.reader = new RecordReader(this); this.writer = new RecordWriter(this); this.dataProxy = new Proxy(this.data, { get: (target, prop) => { if (prop === "length") { return target.length; } if (typeof prop === "string" && !isNaN(Number(prop))) { return target[Number(prop)]; } if (typeof prop === "string" && typeof target[prop] === "function") { return target[prop].bind(target); } throw new BebopRuntimeError(`Cannot access property ${String(prop)}`); }, set: (_, __, ___) => { throw new BebopRuntimeError("Cannot modify schema data"); } }); } view; dataProxy; pos; ArrayType = -14; MapType = -15; parsedSchema; indexToDefinition = {}; nameToDefinition = {}; reader; writer; /** * Get the schema. * This method should only be called once per instance. */ get() { if (this.parsedSchema !== void 0) { return; } const schemaVersion = this.getUint8(); const numDefinedTypes = this.getUint32(); let definedTypes = {}; for (let i = 0; i < numDefinedTypes; i++) { const def = this.getDefinedType(i); definedTypes[def.name] = def; this.indexToDefinition[i] = def; this.nameToDefinition[def.name] = def; } const serviceCount = this.getUint32(); let services = {}; for (let i = 0; i < serviceCount; i++) { const service = this.getServiceDefinition(); services[service.name] = service; } this.parsedSchema = { bebopVersion: schemaVersion, definitions: definedTypes, services }; Object.freeze(this.parsedSchema); } /** * Returns the getd schema. */ get ast() { if (this.parsedSchema === void 0) { this.get(); } return this.parsedSchema; } /** * Returns the raw binary data of the schema wrapped in an immutable Uint8Array. */ get raw() { return this.dataProxy; } /** * Get a Definition by its index or name. * @param index - The index or name of the Definition. * @returns - The requested Definition. * @throws - Will throw an error if no Definition is found at the provided index. */ getDefinition(index) { const definition = typeof index === "number" ? this.indexToDefinition[index] : this.nameToDefinition[index]; if (!definition) { throw new BebopRuntimeError(`No definition found at index: ${index}`); } return definition; } getDefinedType(index) { const name = this.getString(); const kind = this.getUint8(); const decorators = this.getDecorators(); switch (kind) { case 4 /* Enum */: return this.getEnumDefinition(name, kind, decorators, index); case 3 /* Union */: return this.getUnionDefinition(name, kind, decorators, index); case 1 /* Struct */: return this.getStructDefinition(name, kind, decorators, index); case 2 /* Message */: return this.getMessageDefinition(name, kind, decorators, index); default: throw new BebopRuntimeError(`Unknown type kind: ${kind}`); } } getDecorators() { const decoratorCount = this.getUint8(); const decorators = []; for (let i = 0; i < decoratorCount; i++) { const identifier = this.getString(); decorators.push({ identifier, ...this.getDecorator() }); } return decorators; } getDecorator() { const argCount = this.getUint8(); const args = {}; for (let i = 0; i < argCount; i++) { const identifier = this.getString(); const typeId = this.getTypeId(); const argumentValue = this.getConstantValue(typeId); args[identifier] = { typeId, value: argumentValue }; } return { arguments: args }; } getEnumDefinition(name, kind, decorators, index) { const baseType = this.getTypeId(); const isBitFlags = this.getBool(); const minimalEncodeSize = this.getInt32(); const memberCount = this.getUint8(); const members = {}; for (let i = 0; i < memberCount; i++) { const member = this.getEnumMember(baseType); members[member.name] = member; } return { index, name, isBitFlags, kind, decorators, minimalEncodeSize, baseType, members }; } getEnumMember(baseType) { const name = this.getString(); const decorators = this.getDecorators(); const value = this.getConstantValue(baseType); return { name, decorators, value }; } getUnionDefinition(name, kind, decorators, index) { const minimalEncodeSize = this.getInt32(); const branchCount = this.getUint8(); const branches = new Array(branchCount).fill(null).map(() => this.getUnionBranch()); return { index, name, kind, decorators, minimalEncodeSize, branchCount, branches }; } getUnionBranch() { const discriminator = this.getUint8(); const typeId = this.getTypeId(); return { discriminator, typeId }; } getStructDefinition(name, kind, decorators, index) { const isMutable = this.getBool(); const minimalEncodeSize = this.getInt32(); const isFixedSize = this.getBool(); const fields = this.getFields(kind); return { index, name, kind, decorators, isMutable, minimalEncodeSize, isFixedSize, fields }; } getMessageDefinition(name, kind, decorators, index) { const minimalEncodeSize = this.getInt32(); const fields = this.getFields(kind); return { index, minimalEncodeSize, name, kind, decorators, fields }; } getFields(parentKind) { const numFields = this.getUint8(); const fields = {}; for (let i = 0; i < numFields; i++) { const field = this.getField(parentKind); fields[field.name] = field; } return fields; } getField(parentKind) { const fieldName = this.getString(); let fieldTypeId = this.getTypeId(); let fieldProperties; if (fieldTypeId === this.ArrayType || fieldTypeId === this.MapType) { fieldProperties = this.getNestedType( fieldTypeId === this.ArrayType ? "array" : "map" ); } else { fieldProperties = { type: "scalar" }; } const decorators = this.getDecorators(); const constantValue = parentKind === 2 /* Message */ ? this.getConstantValue(-2 /* Byte */) : null; return { name: fieldName, typeId: fieldTypeId, fieldProperties, decorators, constantValue }; } getNestedType(parentType) { if (parentType === "array") { const depth = this.getUint8(); const memberTypeId = this.getTypeId(); return { type: parentType, memberTypeId, depth }; } if (parentType === "map") { const keyTypeId = this.getTypeId(); const valueTypeId = this.getTypeId(); let nestedType; if (valueTypeId === this.ArrayType || valueTypeId === this.MapType) { nestedType = this.getNestedType( valueTypeId === this.ArrayType ? "array" : "map" ); } return { type: parentType, keyTypeId, valueTypeId, nestedType }; } throw new BebopRuntimeError("Invalid initial type"); } getConstantValue(typeId) { switch (typeId) { case -1 /* Bool */: return this.getBool() ? 1 : 0; case -2 /* Byte */: return this.getUint8(); case -3 /* UInt16 */: return this.getUint16(); case -4 /* Int16 */: return this.getInt16(); case -5 /* UInt32 */: return this.getUint32(); case -6 /* Int32 */: return this.getInt32(); case -7 /* UInt64 */: return BigInt(this.getUint64()); case -8 /* Int64 */: return BigInt(this.getInt64()); case -9 /* Float32 */: return this.getFloat32(); case -10 /* Float64 */: return this.getFloat64(); case -11 /* String */: return this.getString(); case -12 /* Guid */: return Guid.fromBytes(this.getGuid(), 0); default: throw new BebopRuntimeError(`Unsupported constant type ID: ${typeId}`); } } getServiceDefinition() { let name = this.getString(); let decorators = this.getDecorators(); let methods = {}; let methodCount = this.getUint32(); for (let i = 0; i < methodCount; i++) { let methodName = this.getString(); let methodDecorators = this.getDecorators(); let methodType = this.getUint8(); let requestTypeId = this.getTypeId(); let responseTypeId = this.getTypeId(); let id = this.getUint32(); methods[methodName] = { name: methodName, decorators: methodDecorators, methodType, requestTypeId, responseTypeId, id }; } return { name, decorators, methods }; } getString() { const start = this.pos; while (this.pos < this.data.length && this.data[this.pos] !== 0) { this.pos++; } const strBytes = this.data.subarray(start, this.pos); if (this.pos < this.data.length) { this.pos++; } return decoder.decode(strBytes); } getUint8() { let value = this.view.getUint8(this.pos); this.pos++; return value; } getUint16() { let value = this.view.getUint16(this.pos, true); this.pos += 2; return value; } getInt16() { let value = this.view.getInt16(this.pos, true); this.pos += 2; return value; } getUint32() { let value = this.view.getUint32(this.pos, true); this.pos += 4; return value; } getInt32() { let value = this.view.getInt32(this.pos, true); this.pos += 4; return value; } getUint64() { let value = this.view.getBigUint64(this.pos, true); this.pos += 8; return Number(value); } getInt64() { let value = this.view.getBigInt64(this.pos, true); this.pos += 8; return Number(value); } getFloat32() { let value = this.view.getFloat32(this.pos, true); this.pos += 4; return value; } getFloat64() { let value = this.view.getFloat64(this.pos, true); this.pos += 8; return value; } getBool() { return this.getUint8() !== 0; } getTypeId() { let typeId = this.view.getInt32(this.pos, true); this.pos += 4; return typeId; } getGuid() { let value = this.data.subarray(this.pos, this.pos + 16); this.pos += 16; return value; } }; // index.ts var hexDigits = "0123456789abcdef"; var asciiToHex = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var guidDelimiter = "-"; var ticksBetweenEpochs = 621355968000000000n; var dateMask = 0x3fffffffffffffffn; var emptyByteArray = new Uint8Array(0); var emptyString = ""; var byteToHex = []; for (const x of hexDigits) { for (const y of hexDigits) { byteToHex.push(x + y); } } var hasCryptoGetRandomValues = typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function"; var BebopRuntimeError = class extends Error { constructor(message) { super(message); this.name = "BebopRuntimeError"; } }; var Guid = class _Guid { /** * Constructs a new Guid object with the specified value. * @param value The value of the GUID. */ constructor(value) { this.value = value; } static empty = new _Guid("00000000-0000-0000-0000-000000000000"); /** * Gets the string value of the Guid. * @returns The string representation of the Guid. */ toString() { return this.value; } /** * Checks if the Guid is empty. * @returns true if the Guid is empty, false otherwise. */ isEmpty() { return this.value === _Guid.empty.value; } /** * Checks if a value is a Guid. * @param value The value to be checked. * @returns true if the value is a Guid, false otherwise. */ static isGuid(value) { return value instanceof _Guid; } /** * Parses a string into a Guid. * @param value The string to be parsed. * @returns A new Guid that represents the parsed value. * @throws {BebopRuntimeError} If the input string is not a valid Guid. */ static parseGuid(value) { let cleanedInput = ""; let count = 0; for (let i = 0; i < value.length; i++) { let ch = value[i].toLowerCase(); if (hexDigits.indexOf(ch) !== -1) { cleanedInput += ch; count++; } else if (ch !== "-") { throw new BebopRuntimeError(`Invalid GUID: ${value}`); } } if (count !== 32) { throw new BebopRuntimeError(`Invalid GUID: ${value}`); } const guidString = cleanedInput.slice(0, 8) + "-" + cleanedInput.slice(8, 12) + "-" + cleanedInput.slice(12, 16) + "-" + cleanedInput.slice(16, 20) + "-" + cleanedInput.slice(20); return new _Guid(guidString); } /** * Creates a an insecure new Guid using Math.random. * @returns A new Guid. */ static newGuid() { let guid = ""; const now = Date.now(); for (let i = 0; i < 36; i++) { if (i === 8 || i === 13 || i === 18 || i === 23) { guid += "-"; } else if (i === 14) { guid += "4"; } else if (i === 19) { guid += Math.random() > 0.5 ? "a" : "b"; } else { guid += hexDigits[(Math.random() * 16 + now) % 16 | 0]; } } return new _Guid(guid); } /** * Creates a new cryptographically secure Guid using Crypto.getRandomValues. * @returns A new secure Guid. * @throws {BebopRuntimeError} If Crypto.getRandomValues is not available. */ static newSecureGuid() { if (!hasCryptoGetRandomValues) { throw new BebopRuntimeError( "Crypto.getRandomValues is not available. Please include a polyfill or use in an environment that supports it." ); } const bytes = new Uint8Array(16); crypto.getRandomValues(bytes); bytes[6] = bytes[6] & 15 | 64; bytes[8] = bytes[8] & 63 | 128; return _Guid.fromBytes(bytes, 0); } /** * Checks if the Guid is equal to another Guid. * @param other The other Guid to be compared with. * @returns true if the Guids are equal, false otherwise. */ equals(other) { if (this === other) { return true; } if (!(other instanceof _Guid)) { return false; } for (let i = 0; i < this.value.length; i++) { if (this.value[i] !== other.value[i]) { return false; } } return true; } /** * Writes the Guid to a DataView. * @param view The DataView to write to. * @param length The position to start writing at. */ writeToView(view, length) { var p = 0, a = 0; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; p += this.value.charCodeAt(p) === 45; view.setUint32(length, a, true); a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; p += this.value.charCodeAt(p) === 45; view.setUint16(length + 4, a, true); a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; p += this.value.charCodeAt(p) === 45; view.setUint16(length + 6, a, true); a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; p += this.value.charCodeAt(p) === 45; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; view.setUint32(length + 8, a, false); a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; a = a << 4 | asciiToHex[this.value.charCodeAt(p++)]; view.setUint32(length + 12, a, false); } /** * Creates a Guid from a byte array. * @param buffer The byte array to create the Guid from. * @param index The position in the array to start reading from. * @returns A new Guid that represents the byte array. */ static fromBytes(buffer, index) { var s = byteToHex[buffer[index + 3]]; s += byteToHex[buffer[index + 2]]; s += byteToHex[buffer[index + 1]]; s += byteToHex[buffer[index]]; s += guidDelimiter; s += byteToHex[buffer[index + 5]]; s += byteToHex[buffer[index + 4]]; s += guidDelimiter; s += byteToHex[buffer[index + 7]]; s += byteToHex[buffer[index + 6]]; s += guidDelimiter; s += byteToHex[buffer[index + 8]]; s += byteToHex[buffer[index + 9]]; s += guidDelimiter; s += byteToHex[buffer[index + 10]]; s += byteToHex[buffer[index + 11]]; s += byteToHex[buffer[index + 12]]; s += byteToHex[buffer[index + 13]]; s += byteToHex[buffer[index + 14]]; s += byteToHex[buffer[index + 15]]; return new _Guid(s); } /** * Converts the Guid to a string when it's used as a primitive. * @returns The string representation of the Guid. */ [Symbol.toPrimitive](hint) { if (hint === "string" || hint === "default") { return this.toString(); } throw new Error(`Guid cannot be converted to ${hint}`); } }; var GuidMap = class _GuidMap { map; /** * Creates a new GuidMap instance. * @param entries - An optional array or iterable containing key-value pairs to initialize the map. */ constructor(entries) { if (entries instanceof Map) { this.map = new Map( entries ); } else if (entries && typeof entries[Symbol.iterator] === "function") { this.map = new Map( [...entries].map(([key, value]) => [key.toString(), value]) ); } else { this.map = /* @__PURE__ */ new Map(); } } /** * Sets the value associated with the specified `Guid` key in the map. * @param key The `Guid` key. * @param value The value to be set. * @returns The updated `GuidMap` instance. */ set(key, value) { this.map.set(key.toString(), value); return this; } /** * Retrieves the value associated with the specified `Guid` key from the map. * @param key The `Guid` key. * @returns The associated value, or `undefined` if the key is not found. */ get(key) { return this.map.get(key.toString()); } /** * Deletes the value associated with the specified `Guid` key from the map. * @param key The `Guid` key. * @returns `true` if the key was found and deleted, or `false` otherwise. */ delete(key) { return this.map.delete(key.toString()); } /** * Checks if the map contains the specified `Guid` key. * @param key The `Guid` key. * @returns `true` if the key is found, or `false` otherwise. */ has(key) { return this.map.has(key.toString()); } /** * Removes all entries from the map. */ clear() { this.map.clear(); } /** * Returns the number of entries in the map. * @returns The number of entries in the map. */ get size() { return this.map.size; } /** * Executes the provided callback function once for each key-value pair in the map. * @param callbackFn The callback function to execute. */ forEach(callbackFn) { this.map.forEach((value, keyString) => { callbackFn(value, Guid.parseGuid(keyString), this); }); } /** * Returns an iterator that yields key-value pairs in the map. * @returns An iterator for key-value pairs in the map. */ *entries() { for (const [keyString, value] of this.map.entries()) { yield [Guid.parseGuid(keyString), value]; } } /** * Returns an iterator that yields the keys of the map. * @returns An iterator for the keys of the map. */ *keys() { for (const keyString of this.map.keys()) { yield Guid.parseGuid(keyString); } } /** * Returns an iterator that yields the values in the map. * @returns An iterator for the values in the map. */ *values() { yield* this.map.values(); } /** * Returns an iterator that yields key-value pairs in the map. * This method is invoked when using the spread operator or destructuring the map. * @returns An iterator for key-value pairs in the map. */ [Symbol.iterator]() { return this.entries(); } /** * The constructor function used to create derived objects. */ get [Symbol.species]() { return _GuidMap; } }; var BebopView = class _BebopView { static textDecoder; static writeBuffer = new Uint8Array(256); static writeBufferView = new DataView(_BebopView.writeBuffer.buffer); static instance; static getInstance() { if (!_BebopView.instance) { _BebopView.instance = new _BebopView(); } return _BebopView.instance; } minimumTextDecoderLength = 300; buffer; view; index; // read pointer length; // write pointer constructor() { this.buffer = _BebopView.writeBuffer; this.view = _BebopView.writeBufferView; this.index = 0; this.length = 0; } startReading(buffer) { this.buffer = buffer; this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength); this.index = 0; this.length = buffer.length; } startWriting() { this.buffer = _BebopView.writeBuffer; this.view = _BebopView.writeBufferView; this.index = 0; this.length = 0; } guaranteeBufferLength(length) { if (length > this.buffer.length) { const data = new Uint8Array(length << 1); data.set(this.buffer); this.buffer = data; this.view = new DataView(data.buffer); } } growBy(amount) { this.length += amount; this.guaranteeBufferLength(this.length); } skip(amount) { this.index += amount; } toArray() { return this.buffer.subarray(0, this.length); } readByte() { return this.buffer[this.index++]; } readUint16() { const result = this.view.getUint16(this.index, true); this.index += 2; return result; } readInt16() { const result = this.view.getInt16(this.index, true); this.index += 2; return result; } readUint32() { const result = this.view.getUint32(this.index, true); this.index += 4; return result; } readInt32() { const result = this.view.getInt32(this.index, true); this.index += 4; return result; } readUint64() { const result = this.view.getBigUint64(this.index, true); this.index += 8; return result; } readInt64() { const result = this.view.getBigInt64(this.index, true); this.index += 8; return result; } readFloat32() { const result = this.view.getFloat32(this.index, true); this.index += 4; return result; } readFloat64() { const result = this.view.getFloat64(this.index, true); this.index += 8; return result; } writeByte(value) { const index = this.length; this.growBy(1); this.buffer[index] = value; } writeUint16(value) { const index = this.length; this.growBy(2); this.view.setUint16(index, value, true); } writeInt16(value) { const index = this.length; this.growBy(2); this.view.setInt16(index, value, true); } writeUint32(value) { const index = this.length; this.growBy(4); this.view.setUint32(index, value, true); } writeInt32(value) { const index = this.length; this.growBy(4); this.view.setInt32(index, value, true); } writeUint64(value) { const index = this.length; this.growBy(8); this.view.setBigUint64(index, value, true); } writeInt64(value) { const index = this.length; this.growBy(8); this.view.setBigInt64(index, value, true); } writeFloat32(value) { const index = this.length; this.growBy(4); this.view.setFloat32(index, value, true); } writeFloat64(value) { const index = this.length; this.growBy(8); this.view.setFloat64(index, value, true); } readBytes() { const length = this.readUint32(); if (length === 0) { return emptyByteArray; } const start = this.index, end = start + length; this.index = end; return this.buffer.subarray(start, end); } writeBytes(value) { const byteCount = value.length; this.writeUint32(byteCount); if (byteCount === 0) { return; } const index = this.length; this.growBy(byteCount); this.buffer.set(value, index); } /** * Reads a length-prefixed UTF-8-encoded string. */ readString() { const lengthBytes = this.readUint32(); if (lengthBytes === 0) { return emptyString; } if (lengthBytes >= this.minimumTextDecoderLength) { if (typeof require !== "undefined") { if (typeof TextDecoder === "undefined") { throw new BebopRuntimeError("TextDecoder is not defined on 'global'. Please include a polyfill."); } } if (_BebopView.textDecoder === void 0) { _BebopView.textDecoder = new TextDecoder(); } return _BebopView.textDecoder.decode(this.buffer.subarray(this.index, this.index += lengthBytes)); } const end = this.index + lengthBytes; let result = ""; let codePoint; while (this.index < end) { const a = this.buffer[this.index++]; if (a < 192) { codePoint = a; } else { const b = this.buffer[this.index++]; if (a < 224) { codePoint = (a & 31) << 6 | b & 63; } else { const c = this.buffer[this.index++]; if (a < 240) { codePoint = (a & 15) << 12 | (b & 63) << 6 | c & 63; } else { const d = this.buffer[this.index++]; codePoint = (a & 7) << 18 | (b & 63) << 12 | (c & 63) << 6 | d & 63; } } } if (codePoint < 65536) { result += String.fromCharCode(codePoint); } else { codePoint -= 65536; result += String.fromCharCode((codePoint >> 10) + 55296, (codePoint & (1 << 10) - 1) + 56320); } } this.index = end; return result; } /** * Writes a length-prefixed UTF-8-encoded string. */ writeString(value) { const stringLength = value.length; if (stringLength === 0) { this.writeUint32(0); return; } const maxBytes = 4 + stringLength * 3; this.guaranteeBufferLength(this.length + maxBytes); let w = this.length + 4; const start = w; let codePoint; for (let i = 0; i < stringLength; i++) { const a = value.charCodeAt(i); if (i + 1 === stringLength || a < 55296 || a >= 56320) { codePoint = a; } else { const b = value.charCodeAt(++i); codePoint = (a << 10) + b + (65536 - (55296 << 10) - 56320); } if (codePoint < 128) { this.buffer[w++] = codePoint; } else { if (codePoint < 2048) { this.buffer[w++] = codePoint >> 6 & 31 | 192; } else { if (codePoint < 65536) { this.buffer[w++] = codePoint >> 12 & 15 | 224; } else { this.buffer[w++] = codePoint >> 18 & 7 | 240; this.buffer[w++] = codePoint >> 12 & 63 | 128; } this.buffer[w++] = codePoint >> 6 & 63 | 128; } this.buffer[w++] = codePoint & 63 | 128; } } const written = w - start; this.view.setUint32(this.length, written, true); this.length += 4 + written; } readGuid() { const guid = Guid.fromBytes(this.buffer, this.index); this.index += 16; return guid; } writeGuid(value) { const i = this.length; this.growBy(16); value.writeToView(this.view, i); } // A note on these numbers: // 62135596800000 ms is the difference between the C# epoch (0001-01-01) and the Unix epoch (1970-01-01). // 0.0001 is the number of milliseconds per "tick" (a tick is 100 ns). // 429496.7296 is the number of milliseconds in 2^32 ticks. // 0x3fffffff is a mask to ignore the "Kind" bits of the Date.ToBinary value. // 0x40000000 is a mask to set the "Kind" bits to "DateTimeKind.Utc". readDate() { const ticks = this.readUint64() & dateMask; const ms = (ticks - ticksBetweenEpochs) / 10000n; return new Date(Number(ms)); } writeDate(date) { const ms = BigInt(date.getTime()); const ticks = ms * 10000n + ticksBetweenEpochs; this.writeUint64(ticks & dateMask); } /** * Reserve some space to write a message's length prefix, and return its index. * The length is stored as a little-endian fixed-width unsigned 32-bit integer, so 4 bytes are reserved. */ reserveMessageLength() { const i = this.length; this.growBy(4); return i; } /** * Fill in a message's length prefix. */ fillMessageLength(position, messageLength) { this.view.setUint32(position, messageLength, true); } /** * Read out a message's length prefix. */ readMessageLength() { const result = this.view.getUint32(this.index, true); this.index += 4; return result; } }; var typeMarker = "#btyp