@animo-id/mdoc
Version:
Animo Mdoc and MDL
1 lines • 320 kB
Source Map (JSON)
{"version":3,"sources":["../src/cbor/cbor-x/decode.js","../src/cbor/cbor-x/encode.js","../src/cbor/data-item.ts","../src/cbor/index.ts","../src/u-base64.ts","../src/u-uint8-array.ts","../src/cose/typed-map.ts","../src/cose/headers.ts","../src/cose/key/curve.ts","../src/cose/key/key-ops.ts","../src/cose/key/kty.ts","../src/cose/key/params.ts","../src/cose/key/cose-key.ts","../src/mdoc/errors.ts","../src/mdoc/check-callback.ts","../src/mdoc/issuer-signed-item.ts","../src/mdoc/items-request.ts","../src/mdoc/model/device-request.ts","../src/cose/cose-base.ts","../src/cose/e-cose.ts","../src/cose/validate-algorithms.ts","../src/cose/mac0.ts","../src/cose/signature-base.ts","../src/cose/sign1.ts","../src/mdoc/parser.ts","../src/mdoc/model/issuer-signed-document.ts","../src/mdoc/model/device-signed-document.ts","../src/mdoc/model/issuer-auth.ts","../src/mdoc/model/mdoc.ts","../src/mdoc/utils.ts","../src/mdoc/model/pex-limit-disclosure.ts","../src/mdoc/model/device-response.ts","../src/mdoc/model/document.ts","../src/mdoc/verifier.ts","../src/u-hex.ts"],"sourcesContent":["let decoder\ntry {\n decoder = new TextDecoder()\n} catch (error) {}\nlet src\nlet srcEnd\nlet position = 0\nlet alreadySet\nconst EMPTY_ARRAY = []\nconst LEGACY_RECORD_INLINE_ID = 105\nconst RECORD_DEFINITIONS_ID = 0xdffe\nconst RECORD_INLINE_ID = 0xdfff // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'\nconst BUNDLED_STRINGS_ID = 0xdff9\nconst PACKED_TABLE_TAG_ID = 51\nconst PACKED_REFERENCE_TAG_ID = 6\nconst STOP_CODE = {}\nlet maxArraySize = 112810000 // This is the maximum array size in V8. We would potentially detect and set it higher\n// for JSC, but this is pretty large and should be sufficient for most use cases\nlet maxMapSize = 16810000 // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,\n// so we don't need to\n\nlet maxObjectSize = 16710000 // This is the maximum number of keys in a Map. It takes over a minute to create this\n// many keys in an object, so also probably a reasonable choice there.\nlet strings = EMPTY_ARRAY\nlet stringPosition = 0\nlet currentDecoder = {}\nlet currentStructures\nlet srcString\nlet srcStringStart = 0\nlet srcStringEnd = 0\nlet bundledStrings\nlet referenceMap\nconst currentExtensions = []\nconst currentExtensionRanges = []\nlet packedValues\nlet dataView\nlet restoreMapsAsObject\nconst defaultOptions = {\n useRecords: false,\n mapsAsObjects: true,\n}\nlet sequentialMode = false\nlet inlineObjectReadThreshold = 2\nlet BlockedFunction // we use search and replace to change the next call to BlockedFunction to avoid CSP issues for\n// no-eval build\ntry {\n new Function('')\n} catch (error) {\n // if eval variants are not supported, do not create inline object readers ever\n inlineObjectReadThreshold = Number.POSITIVE_INFINITY\n}\n\nexport class Decoder {\n constructor(options) {\n if (options) {\n if ((options.keyMap || options._keyMap) && !options.useRecords) {\n options.useRecords = false\n options.mapsAsObjects = true\n }\n if (options.useRecords === false && options.mapsAsObjects === undefined) options.mapsAsObjects = true\n if (options.getStructures) options.getShared = options.getStructures\n if (options.getShared && !options.structures) (options.structures = []).uninitialized = true // this is what we use to denote an uninitialized structures\n if (options.keyMap) {\n this.mapKey = new Map()\n for (const [k, v] of Object.entries(options.keyMap)) this.mapKey.set(v, k)\n }\n }\n Object.assign(this, options)\n }\n /*\n\tdecodeKey(key) {\n\t\treturn this.keyMap\n\t\t\t? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key\n\t\t\t: key\n\t}\n\t*/\n decodeKey(key) {\n return this.keyMap ? this.mapKey.get(key) || key : key\n }\n\n encodeKey(key) {\n return this.keyMap?.hasOwnProperty(key) ? this.keyMap[key] : key\n }\n\n encodeKeys(rec) {\n if (!this._keyMap) return rec\n const map = new Map()\n for (const [k, v] of Object.entries(rec)) map.set(this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k, v)\n return map\n }\n\n decodeKeys(map) {\n if (!this._keyMap || map.constructor.name !== 'Map') return map\n if (!this._mapKey) {\n this._mapKey = new Map()\n for (const [k, v] of Object.entries(this._keyMap)) this._mapKey.set(v, k)\n }\n const res = {}\n //map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)\n map.forEach((v, k) => (res[safeKey(this._mapKey.has(k) ? this._mapKey.get(k) : k)] = v))\n return res\n }\n\n mapDecode(source, end) {\n const res = this.decode(source)\n if (this._keyMap) {\n //Experiemntal support for Optimised KeyMap decoding\n switch (res.constructor.name) {\n case 'Array':\n return res.map((r) => this.decodeKeys(r))\n //case 'Map': return this.decodeKeys(res)\n }\n }\n return res\n }\n\n decode(source, end) {\n if (src) {\n // re-entrant execution, save the state and restore it after we do this decode\n return saveState(() => {\n clearSource()\n return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)\n })\n }\n srcEnd = end > -1 ? end : source.length\n position = 0\n stringPosition = 0\n srcStringEnd = 0\n srcString = null\n strings = EMPTY_ARRAY\n bundledStrings = null\n src = source\n // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend\n // technique for getting data from a database where it can be copied into an existing buffer instead of creating\n // new ones\n try {\n dataView =\n source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))\n } catch (error) {\n // if it doesn't have a buffer, maybe it is the wrong type of object\n src = null\n if (source instanceof Uint8Array) throw error\n throw new Error(\n `Source must be a Uint8Array or Buffer but was a ${\n source && typeof source === 'object' ? source.constructor.name : typeof source\n }`\n )\n }\n if (this instanceof Decoder) {\n currentDecoder = this\n packedValues =\n this.sharedValues &&\n (this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) : this.sharedValues)\n if (this.structures) {\n currentStructures = this.structures\n return checkedRead()\n }\n if (!currentStructures || currentStructures.length > 0) {\n currentStructures = []\n }\n } else {\n currentDecoder = defaultOptions\n if (!currentStructures || currentStructures.length > 0) currentStructures = []\n packedValues = null\n }\n return checkedRead()\n }\n decodeMultiple(source, forEach) {\n let values\n let lastPosition = 0\n try {\n const size = source.length\n sequentialMode = true\n const value = this ? this.decode(source, size) : defaultDecoder.decode(source, size)\n if (forEach) {\n if (forEach(value) === false) {\n return\n }\n while (position < size) {\n lastPosition = position\n if (forEach(checkedRead()) === false) {\n return\n }\n }\n } else {\n values = [value]\n while (position < size) {\n lastPosition = position\n values.push(checkedRead())\n }\n return values\n }\n } catch (error) {\n error.lastPosition = lastPosition\n error.values = values\n throw error\n } finally {\n sequentialMode = false\n clearSource()\n }\n }\n}\nexport function getPosition() {\n return position\n}\nexport function checkedRead() {\n try {\n const result = read()\n if (bundledStrings) {\n if (position >= bundledStrings.postBundlePosition) {\n const error = new Error('Unexpected bundle position')\n error.incomplete = true\n throw error\n }\n // bundled strings to skip past\n position = bundledStrings.postBundlePosition\n bundledStrings = null\n }\n\n if (position === srcEnd) {\n // finished reading this source, cleanup references\n currentStructures = null\n src = null\n if (referenceMap) referenceMap = null\n } else if (position > srcEnd) {\n // over read\n const error = new Error('Unexpected end of CBOR data')\n error.incomplete = true\n throw error\n } else if (!sequentialMode) {\n throw new Error('Data read, but end of buffer not reached')\n }\n // else more to read, but we are reading sequentially, so don't clear source yet\n return result\n } catch (error) {\n clearSource()\n if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {\n error.incomplete = true\n }\n throw error\n }\n}\n\nexport function read() {\n let token = src[position++]\n const majorType = token >> 5\n token = token & 0x1f\n if (token > 0x17) {\n switch (token) {\n case 0x18:\n token = src[position++]\n break\n case 0x19:\n if (majorType === 7) {\n return getFloat16()\n }\n token = dataView.getUint16(position)\n position += 2\n break\n case 0x1a:\n if (majorType === 7) {\n const value = dataView.getFloat32(position)\n if (currentDecoder.useFloat32 > 2) {\n // this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved\n const multiplier = mult10[((src[position] & 0x7f) << 1) | (src[position + 1] >> 7)]\n position += 4\n return ((multiplier * value + (value > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n }\n position += 4\n return value\n }\n token = dataView.getUint32(position)\n position += 4\n break\n case 0x1b:\n if (majorType === 7) {\n const value = dataView.getFloat64(position)\n position += 8\n return value\n }\n if (majorType > 1) {\n if (dataView.getUint32(position) > 0)\n throw new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')\n token = dataView.getUint32(position + 4)\n } else if (currentDecoder.int64AsNumber) {\n token = dataView.getUint32(position) * 0x100000000\n token += dataView.getUint32(position + 4)\n } else token = dataView.getBigUint64(position)\n position += 8\n break\n case 0x1f:\n // indefinite length\n switch (majorType) {\n case 2: // byte string\n case 3: // text string\n throw new Error('Indefinite length not supported for byte or text strings')\n case 4: {\n // array\n const array = []\n let value\n let i = 0\n while ((value = read()) !== STOP_CODE) {\n if (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n array[i++] = value\n }\n return majorType === 4 ? array : majorType === 3 ? array.join('') : Buffer.concat(array)\n }\n case 5: {\n // map\n let key\n if (currentDecoder.mapsAsObjects) {\n const object = {}\n let i = 0\n if (currentDecoder.keyMap) {\n while ((key = read()) !== STOP_CODE) {\n if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n object[safeKey(currentDecoder.decodeKey(key))] = read()\n }\n } else {\n while ((key = read()) !== STOP_CODE) {\n if (i++ >= maxMapSize) throw new Error(`Property count exceeds ${maxMapSize}`)\n object[safeKey(key)] = read()\n }\n }\n return object\n }\n if (restoreMapsAsObject) {\n currentDecoder.mapsAsObjects = true\n restoreMapsAsObject = false\n }\n const map = new Map()\n if (currentDecoder.keyMap) {\n let i = 0\n while ((key = read()) !== STOP_CODE) {\n if (i++ >= maxMapSize) {\n throw new Error(`Map size exceeds ${maxMapSize}`)\n }\n map.set(currentDecoder.decodeKey(key), read())\n }\n } else {\n let i = 0\n while ((key = read()) !== STOP_CODE) {\n if (i++ >= maxMapSize) {\n throw new Error(`Map size exceeds ${maxMapSize}`)\n }\n map.set(key, read())\n }\n }\n return map\n }\n case 7:\n return STOP_CODE\n default:\n throw new Error(`Invalid major type for indefinite length ${majorType}`)\n }\n default:\n throw new Error(`Unknown token ${token}`)\n }\n }\n switch (majorType) {\n case 0: // positive int\n return token\n case 1: // negative int\n return ~token\n case 2: // buffer\n return readBin(token)\n case 3: // string\n if (srcStringEnd >= position) {\n return srcString.slice(position - srcStringStart, (position += token) - srcStringStart)\n }\n if (srcStringEnd === 0 && srcEnd < 140 && token < 32) {\n // for small blocks, avoiding the overhead of the extract call is helpful\n const string = token < 16 ? shortStringInJS(token) : longStringInJS(token)\n if (string != null) return string\n }\n return readFixedString(token)\n case 4: {\n // array\n if (token >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)\n const array = new Array(token)\n //if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())\n //else\n for (let i = 0; i < token; i++) array[i] = read()\n return array\n }\n case 5: {\n // map\n if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)\n if (currentDecoder.mapsAsObjects) {\n const object = {}\n if (currentDecoder.keyMap)\n for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read()\n else for (let i = 0; i < token; i++) object[safeKey(read())] = read()\n return object\n }\n if (restoreMapsAsObject) {\n currentDecoder.mapsAsObjects = true\n restoreMapsAsObject = false\n }\n const map = new Map()\n if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()), read())\n else for (let i = 0; i < token; i++) map.set(read(), read())\n return map\n }\n case 6: {\n // extension\n if (token >= BUNDLED_STRINGS_ID) {\n let structure = currentStructures[token & 0x1fff] // check record structures first\n // At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))\n if (structure) {\n if (!structure.read) structure.read = createStructureReader(structure)\n return structure.read()\n }\n if (token < 0x10000) {\n if (token === RECORD_INLINE_ID) {\n // we do a special check for this so that we can keep the\n // currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n const length = readJustLength()\n const id = read()\n const structure = read()\n recordDefinition(id, structure)\n const object = {}\n if (currentDecoder.keyMap)\n for (let i = 2; i < length; i++) {\n const key = currentDecoder.decodeKey(structure[i - 2])\n object[safeKey(key)] = read()\n }\n else\n for (let i = 2; i < length; i++) {\n const key = structure[i - 2]\n object[safeKey(key)] = read()\n }\n return object\n }\n if (token === RECORD_DEFINITIONS_ID) {\n const length = readJustLength()\n let id = read()\n for (let i = 2; i < length; i++) {\n recordDefinition(id++, read())\n }\n return read()\n }\n if (token === BUNDLED_STRINGS_ID) {\n return readBundleExt()\n }\n if (currentDecoder.getShared) {\n loadShared()\n structure = currentStructures[token & 0x1fff]\n if (structure) {\n if (!structure.read) structure.read = createStructureReader(structure)\n return structure.read()\n }\n }\n }\n }\n const extension = currentExtensions[token]\n if (extension) {\n if (extension.handlesRead) return extension(read)\n return extension(read())\n }\n const input = read()\n for (let i = 0; i < currentExtensionRanges.length; i++) {\n const value = currentExtensionRanges[i](token, input)\n if (value !== undefined) return value\n }\n return new Tag(input, token)\n }\n case 7: // fixed value\n switch (token) {\n case 0x14:\n return false\n case 0x15:\n return true\n case 0x16:\n return null\n case 0x17:\n return // undefined\n default: {\n const packedValue = (packedValues || getPackedValues())[token]\n if (packedValue !== undefined) return packedValue\n throw new Error(`Unknown token ${token}`)\n }\n }\n default: // negative int\n if (Number.isNaN(token)) {\n const error = new Error('Unexpected end of CBOR data')\n error.incomplete = true\n throw error\n }\n throw new Error(`Unknown CBOR token ${token}`)\n }\n}\nconst validName = /^[a-zA-Z_$][a-zA-Z\\d_$]*$/\nfunction createStructureReader(structure) {\n if (!structure) throw new Error('Structure is required in record definition')\n function readObject() {\n // get the array size from the header\n let length = src[position++]\n //let majorType = token >> 5\n length = length & 0x1f\n if (length > 0x17) {\n switch (length) {\n case 0x18:\n length = src[position++]\n break\n case 0x19:\n length = dataView.getUint16(position)\n position += 2\n break\n case 0x1a:\n length = dataView.getUint32(position)\n position += 4\n break\n default:\n throw new Error(`Expected array header, but got ${src[position - 1]}`)\n }\n }\n // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function\n let compiledReader = this.compiledReader // first look to see if we have the fast compiled function\n while (compiledReader) {\n // we have a fast compiled object literal reader\n if (compiledReader.propertyCount === length) return compiledReader(read) // with the right length, so we use it\n compiledReader = compiledReader.next // see if there is another reader with the right length\n }\n if (this.slowReads++ >= inlineObjectReadThreshold) {\n // create a fast compiled reader\n const array = this.length === length ? this : this.slice(0, length)\n compiledReader = currentDecoder.keyMap\n ? new Function(\n 'r',\n `return {${array\n .map((k) => currentDecoder.decodeKey(k))\n .map((k) => (validName.test(k) ? `${safeKey(k)}:r()` : `[${JSON.stringify(k)}]:r()`))\n .join(',')}}`\n )\n : new Function(\n 'r',\n `return {${array\n .map((key) => (validName.test(key) ? `${safeKey(key)}:r()` : `[${JSON.stringify(key)}]:r()`))\n .join(',')}}`\n )\n if (this.compiledReader) compiledReader.next = this.compiledReader // if there is an existing one, we store multiple readers as a linked list because it is usually pretty rare to have multiple readers (of different length) for the same structure\n compiledReader.propertyCount = length\n this.compiledReader = compiledReader\n return compiledReader(read)\n }\n const object = {}\n if (currentDecoder.keyMap)\n for (let i = 0; i < length; i++) object[safeKey(currentDecoder.decodeKey(this[i]))] = read()\n else\n for (let i = 0; i < length; i++) {\n object[safeKey(this[i])] = read()\n }\n return object\n }\n structure.slowReads = 0\n return readObject\n}\n\nfunction safeKey(key) {\n // protect against prototype pollution\n if (typeof key === 'string') return key === '__proto__' ? '__proto_' : key\n if (typeof key === 'number' || typeof key === 'boolean' || typeof key === 'bigint') return key.toString()\n if (key == null) return `${key}`\n // protect against expensive (DoS) string conversions\n throw new Error(`Invalid property name type ${typeof key}`)\n}\n\nlet readFixedString = readStringJS\nlet readString8 = readStringJS\nlet readString16 = readStringJS\nlet readString32 = readStringJS\n\nexport let isNativeAccelerationEnabled = false\nexport function setExtractor(extractStrings) {\n isNativeAccelerationEnabled = true\n readFixedString = readString(1)\n readString8 = readString(2)\n readString16 = readString(3)\n readString32 = readString(5)\n function readString(headerLength) {\n return function readString(length) {\n let string = strings[stringPosition++]\n if (string == null) {\n if (bundledStrings) return readStringJS(length)\n const extraction = extractStrings(position, srcEnd, length, src)\n if (typeof extraction === 'string') {\n string = extraction\n strings = EMPTY_ARRAY\n } else {\n strings = extraction\n stringPosition = 1\n srcStringEnd = 1 // even if a utf-8 string was decoded, must indicate we are in the midst of extracted strings and can't skip strings\n string = strings[0]\n if (string === undefined) throw new Error('Unexpected end of buffer')\n }\n }\n const srcStringLength = string.length\n if (srcStringLength <= length) {\n position += length\n return string\n }\n srcString = string\n srcStringStart = position\n srcStringEnd = position + srcStringLength\n position += length\n return string.slice(0, length) // we know we just want the beginning\n }\n }\n}\nfunction readStringJS(length) {\n let result\n if (length < 16) {\n if ((result = shortStringInJS(length))) return result\n }\n if (length > 64 && decoder) return decoder.decode(src.subarray(position, (position += length)))\n const end = position + length\n const units = []\n result = ''\n while (position < end) {\n const byte1 = src[position++]\n if ((byte1 & 0x80) === 0) {\n // 1 byte\n units.push(byte1)\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2 bytes\n const byte2 = src[position++] & 0x3f\n units.push(((byte1 & 0x1f) << 6) | byte2)\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3 bytes\n const byte2 = src[position++] & 0x3f\n const byte3 = src[position++] & 0x3f\n units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3)\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4 bytes\n const byte2 = src[position++] & 0x3f\n const byte3 = src[position++] & 0x3f\n const byte4 = src[position++] & 0x3f\n let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4\n if (unit > 0xffff) {\n unit -= 0x10000\n units.push(((unit >>> 10) & 0x3ff) | 0xd800)\n unit = 0xdc00 | (unit & 0x3ff)\n }\n units.push(unit)\n } else {\n units.push(byte1)\n }\n\n if (units.length >= 0x1000) {\n result += fromCharCode.apply(String, units)\n units.length = 0\n }\n }\n\n if (units.length > 0) {\n result += fromCharCode.apply(String, units)\n }\n\n return result\n}\nconst fromCharCode = String.fromCharCode\nfunction longStringInJS(length) {\n const start = position\n const bytes = new Array(length)\n for (let i = 0; i < length; i++) {\n const byte = src[position++]\n if ((byte & 0x80) > 0) {\n position = start\n return\n }\n bytes[i] = byte\n }\n return fromCharCode.apply(String, bytes)\n}\nfunction shortStringInJS(length) {\n if (length < 4) {\n if (length < 2) {\n if (length === 0) return ''\n\n const a = src[position++]\n if ((a & 0x80) > 1) {\n position -= 1\n return\n }\n return fromCharCode(a)\n }\n const a = src[position++]\n const b = src[position++]\n if ((a & 0x80) > 0 || (b & 0x80) > 0) {\n position -= 2\n return\n }\n if (length < 3) return fromCharCode(a, b)\n const c = src[position++]\n if ((c & 0x80) > 0) {\n position -= 3\n return\n }\n return fromCharCode(a, b, c)\n }\n const a = src[position++]\n const b = src[position++]\n const c = src[position++]\n const d = src[position++]\n if ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) {\n position -= 4\n return\n }\n if (length < 6) {\n if (length === 4) return fromCharCode(a, b, c, d)\n\n const e = src[position++]\n if ((e & 0x80) > 0) {\n position -= 5\n return\n }\n return fromCharCode(a, b, c, d, e)\n }\n if (length < 8) {\n const e = src[position++]\n const f = src[position++]\n if ((e & 0x80) > 0 || (f & 0x80) > 0) {\n position -= 6\n return\n }\n if (length < 7) return fromCharCode(a, b, c, d, e, f)\n const g = src[position++]\n if ((g & 0x80) > 0) {\n position -= 7\n return\n }\n return fromCharCode(a, b, c, d, e, f, g)\n }\n const e = src[position++]\n const f = src[position++]\n const g = src[position++]\n const h = src[position++]\n if ((e & 0x80) > 0 || (f & 0x80) > 0 || (g & 0x80) > 0 || (h & 0x80) > 0) {\n position -= 8\n return\n }\n if (length < 10) {\n if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h)\n\n const i = src[position++]\n if ((i & 0x80) > 0) {\n position -= 9\n return\n }\n return fromCharCode(a, b, c, d, e, f, g, h, i)\n }\n if (length < 12) {\n const i = src[position++]\n const j = src[position++]\n if ((i & 0x80) > 0 || (j & 0x80) > 0) {\n position -= 10\n return\n }\n if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j)\n const k = src[position++]\n if ((k & 0x80) > 0) {\n position -= 11\n return\n }\n return fromCharCode(a, b, c, d, e, f, g, h, i, j, k)\n }\n const i = src[position++]\n const j = src[position++]\n const k = src[position++]\n const l = src[position++]\n if ((i & 0x80) > 0 || (j & 0x80) > 0 || (k & 0x80) > 0 || (l & 0x80) > 0) {\n position -= 12\n return\n }\n if (length < 14) {\n if (length === 12) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l)\n\n const m = src[position++]\n if ((m & 0x80) > 0) {\n position -= 13\n return\n }\n return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m)\n }\n const m = src[position++]\n const n = src[position++]\n if ((m & 0x80) > 0 || (n & 0x80) > 0) {\n position -= 14\n return\n }\n if (length < 15) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n)\n const o = src[position++]\n if ((o & 0x80) > 0) {\n position -= 15\n return\n }\n return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)\n}\n\nfunction readBin(length) {\n return currentDecoder.copyBuffers\n ? // specifically use the copying slice (not the node one)\n Uint8Array.prototype.slice.call(src, position, (position += length))\n : src.subarray(position, (position += length))\n}\nfunction readExt(length) {\n const type = src[position++]\n if (currentExtensions[type]) {\n return currentExtensions[type](src.subarray(position, (position += length)))\n }\n throw new Error(`Unknown extension type ${type}`)\n}\nconst f32Array = new Float32Array(1)\nconst u8Array = new Uint8Array(f32Array.buffer, 0, 4)\nfunction getFloat16() {\n const byte0 = src[position++]\n const byte1 = src[position++]\n const exponent = (byte0 & 0x7f) >> 2\n if (exponent === 0x1f) {\n // specials\n if (byte1 || byte0 & 3) return Number.NaN\n return byte0 & 0x80 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY\n }\n if (exponent === 0) {\n // sub-normals\n // significand with 10 fractional bits and divided by 2^14\n const abs = (((byte0 & 3) << 8) | byte1) / (1 << 24)\n return byte0 & 0x80 ? -abs : abs\n }\n\n u8Array[3] =\n (byte0 & 0x80) | // sign bit\n ((exponent >> 1) + 56) // 4 of 5 of the exponent bits, re-offset-ed\n u8Array[2] =\n ((byte0 & 7) << 5) | // last exponent bit and first two mantissa bits\n (byte1 >> 3) // next 5 bits of mantissa\n u8Array[1] = byte1 << 5 // last three bits of mantissa\n u8Array[0] = 0\n return f32Array[0]\n}\n\nconst keyCache = new Array(4096)\nfunction readKey() {\n let length = src[position++]\n if (length >= 0x60 && length < 0x78) {\n // fixstr, potentially use key cache\n length = length - 0x60\n if (srcStringEnd >= position)\n // if it has been extracted, must use it (and faster anyway)\n return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)\n if (!(srcStringEnd === 0 && srcEnd < 180)) return readFixedString(length)\n } else {\n // not cacheable, go back and do a standard read\n position--\n return read()\n }\n const key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff\n let entry = keyCache[key]\n let checkPosition = position\n let end = position + length - 3\n let chunk\n let i = 0\n if (entry && entry.bytes === length) {\n while (checkPosition < end) {\n chunk = dataView.getUint32(checkPosition)\n if (chunk !== entry[i++]) {\n checkPosition = 0x70000000\n break\n }\n checkPosition += 4\n }\n end += 3\n while (checkPosition < end) {\n chunk = src[checkPosition++]\n if (chunk !== entry[i++]) {\n checkPosition = 0x70000000\n break\n }\n }\n if (checkPosition === end) {\n position = checkPosition\n return entry.string\n }\n end -= 3\n checkPosition = position\n }\n entry = []\n keyCache[key] = entry\n entry.bytes = length\n while (checkPosition < end) {\n chunk = dataView.getUint32(checkPosition)\n entry.push(chunk)\n checkPosition += 4\n }\n end += 3\n while (checkPosition < end) {\n chunk = src[checkPosition++]\n entry.push(chunk)\n }\n // for small blocks, avoiding the overhead of the extract call is helpful\n const string = length < 16 ? shortStringInJS(length) : longStringInJS(length)\n if (string != null) return (entry.string = string)\n return (entry.string = readFixedString(length))\n}\n\nexport class Tag {\n constructor(value, tag) {\n this.value = value\n this.tag = tag\n }\n}\n\ncurrentExtensions[1] = (epochSec) => {\n // numeric date extension\n return new Date(Math.round(epochSec * 1000))\n}\n\ncurrentExtensions[2] = (buffer) => {\n // bigint extension\n let value = BigInt(0)\n for (let i = 0, l = buffer.byteLength; i < l; i++) {\n value = BigInt(buffer[i]) + (value << BigInt(8))\n }\n return value\n}\n\ncurrentExtensions[3] = (buffer) => {\n // negative bigint extension\n return BigInt(-1) - currentExtensions[2](buffer)\n}\ncurrentExtensions[4] = (fraction) => {\n // best to reparse to maintain accuracy\n return +`${fraction[1]}e${fraction[0]}`\n}\n\ncurrentExtensions[5] = (fraction) => {\n // probably not sufficiently accurate\n return fraction[1] * Math.exp(fraction[0] * Math.log(2))\n}\n\n// the registration of the record definition extension\nconst recordDefinition = (id, structure) => {\n id = id - 0xe000\n const existingStructure = currentStructures[id]\n if (existingStructure?.isShared) {\n ;(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure\n }\n currentStructures[id] = structure\n\n structure.read = createStructureReader(structure)\n}\ncurrentExtensions[LEGACY_RECORD_INLINE_ID] = (data) => {\n const length = data.length\n const structure = data[1]\n recordDefinition(data[0], structure)\n const object = {}\n for (let i = 2; i < length; i++) {\n const key = structure[i - 2]\n object[safeKey(key)] = data[i]\n }\n return object\n}\ncurrentExtensions[14] = (value) => {\n if (bundledStrings) return bundledStrings[0].slice(bundledStrings.position0, (bundledStrings.position0 += value))\n return new Tag(value, 14)\n}\ncurrentExtensions[15] = (value) => {\n if (bundledStrings) return bundledStrings[1].slice(bundledStrings.position1, (bundledStrings.position1 += value))\n return new Tag(value, 15)\n}\nconst glbl = { Error, RegExp }\ncurrentExtensions[27] = (data) => {\n // http://cbor.schmorp.de/generic-object\n return (glbl[data[0]] || Error)(data[1], data[2])\n}\nconst packedTable = (read) => {\n if (src[position++] !== 0x84) {\n const error = new Error('Packed values structure must be followed by a 4 element array')\n if (src.length < position) error.incomplete = true\n throw error\n }\n const newPackedValues = read() // packed values\n if (!newPackedValues || !newPackedValues.length) {\n const error = new Error('Packed values structure must be followed by a 4 element array')\n error.incomplete = true\n throw error\n }\n packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues\n packedValues.prefixes = read()\n packedValues.suffixes = read()\n return read() // read the rump\n}\npackedTable.handlesRead = true\ncurrentExtensions[51] = packedTable\n\ncurrentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => {\n // packed reference\n if (!packedValues) {\n if (currentDecoder.getShared) loadShared()\n else return new Tag(data, PACKED_REFERENCE_TAG_ID)\n }\n if (typeof data === 'number') return packedValues[16 + (data >= 0 ? 2 * data : -2 * data - 1)]\n const error = new Error('No support for non-integer packed references yet')\n if (data === undefined) error.incomplete = true\n throw error\n}\n\n// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref\n// the real thing would need to implemennt more logic to populate the stringRefs table and\n// maintain a stack of stringRef \"namespaces\".\n//\n// currentExtensions[25] = (id) => {\n// \treturn stringRefs[id]\n// }\n// currentExtensions[256] = (read) => {\n// \tstringRefs = []\n// \ttry {\n// \t\treturn read()\n// \t} finally {\n// \t\tstringRefs = null\n// \t}\n// }\n// currentExtensions[256].handlesRead = true\n\ncurrentExtensions[28] = (read) => {\n // shareable http://cbor.schmorp.de/value-sharing (for structured clones)\n if (!referenceMap) {\n referenceMap = new Map()\n referenceMap.id = 0\n }\n const id = referenceMap.id++\n const startingPosition = position\n const token = src[position]\n let target\n // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read\n // ahead past references to record structure definitions\n if (token >> 5 === 4) target = []\n else target = {}\n\n const refEntry = { target } // a placeholder object\n referenceMap.set(id, refEntry)\n let targetProperties = read() // read the next value as the target object to id\n if (refEntry.used) {\n // there is a cycle, so we have to assign properties to original target\n if (Object.getPrototypeOf(target) !== Object.getPrototypeOf(targetProperties)) {\n // this means that the returned target does not match the targetProperties, so we need rerun the read to\n // have the correctly create instance be assigned as a reference, then we do the copy the properties back to the\n // target\n // reset the position so that the read can be repeated\n position = startingPosition\n // the returned instance is our new target for references\n target = targetProperties\n referenceMap.set(id, { target })\n targetProperties = read()\n }\n return Object.assign(target, targetProperties)\n }\n refEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one\n return targetProperties // no cycle, can just use the returned read object\n}\ncurrentExtensions[28].handlesRead = true\n\ncurrentExtensions[29] = (id) => {\n // sharedref http://cbor.schmorp.de/value-sharing (for structured clones)\n const refEntry = referenceMap.get(id)\n refEntry.used = true\n return refEntry.target\n}\n\ncurrentExtensions[258] = (array) => new Set(array) // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md\n;(currentExtensions[259] = (read) => {\n // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec\n // for decoding as a standard Map\n if (currentDecoder.mapsAsObjects) {\n currentDecoder.mapsAsObjects = false\n restoreMapsAsObject = true\n }\n return read()\n}).handlesRead = true\nfunction combine(a, b) {\n if (typeof a === 'string') return a + b\n if (Array.isArray(a)) return a.concat(b)\n return Object.assign({}, a, b)\n}\nfunction getPackedValues() {\n if (!packedValues) {\n if (currentDecoder.getShared) loadShared()\n else throw new Error('No packed values available')\n }\n return packedValues\n}\nconst SHARED_DATA_TAG_ID = 0x53687264 // ascii 'Shrd'\ncurrentExtensionRanges.push((tag, input) => {\n if (tag >= 225 && tag <= 255) return combine(getPackedValues().prefixes[tag - 224], input)\n if (tag >= 28704 && tag <= 32767) return combine(getPackedValues().prefixes[tag - 28672], input)\n if (tag >= 1879052288 && tag <= 2147483647) return combine(getPackedValues().prefixes[tag - 1879048192], input)\n if (tag >= 216 && tag <= 223) return combine(input, getPackedValues().suffixes[tag - 216])\n if (tag >= 27647 && tag <= 28671) return combine(input, getPackedValues().suffixes[tag - 27639])\n if (tag >= 1811940352 && tag <= 1879048191) return combine(input, getPackedValues().suffixes[tag - 1811939328])\n if (tag === SHARED_DATA_TAG_ID) {\n // we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)\n return {\n packedValues: packedValues,\n structures: currentStructures.slice(0),\n version: input,\n }\n }\n if (tag === 55799)\n // self-descriptive CBOR tag, just return input value\n return input\n})\n\nconst isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1\nexport const typedArrays = [\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n typeof BigUint64Array === 'undefined' ? { name: 'BigUint64Array' } : BigUint64Array,\n Int8Array,\n Int16Array,\n Int32Array,\n typeof BigInt64Array === 'undefined' ? { name: 'BigInt64Array' } : BigInt64Array,\n Float32Array,\n Float64Array,\n]\nconst typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86]\nfor (let i = 0; i < typedArrays.length; i++) {\n registerTypedArray(typedArrays[i], typedArrayTags[i])\n}\nfunction registerTypedArray(TypedArray, tag) {\n const dvMethod = `get${TypedArray.name.slice(0, -5)}`\n let bytesPerElement\n if (typeof TypedArray === 'function') bytesPerElement = TypedArray.BYTES_PER_ELEMENT\n else TypedArray = null\n for (let littleEndian = 0; littleEndian < 2; littleEndian++) {\n if (!littleEndian && bytesPerElement === 1) continue\n const sizeShift = bytesPerElement === 2 ? 1 : bytesPerElement === 4 ? 2 : bytesPerElement === 8 ? 3 : 0\n currentExtensions[littleEndian ? tag : tag - 4] =\n bytesPerElement === 1 || littleEndian === isLittleEndianMachine\n ? (buffer) => {\n if (!TypedArray) throw new Error(`Could not find typed array for code ${tag}`)\n if (!currentDecoder.copyBuffers) {\n // try provide a direct view, but will only work if we are byte-aligned\n if (\n bytesPerElement === 1 ||\n (bytesPerElement === 2 && !(buffer.byteOffset & 1)) ||\n (bytesPerElement === 4 && !(buffer.byteOffset & 3)) ||\n (bytesPerElement === 8 && !(buffer.byteOffset & 7))\n )\n return new TypedArray(buffer.buffer, buffer.byteOffset, buffer.byteLength >> sizeShift)\n }\n // we have to slice/copy here to get a new ArrayBuffer, if we are not word/byte aligned\n return new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)\n }\n : (buffer) => {\n if (!TypedArray) throw new Error(`Could not find typed array for code ${tag}`)\n const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n const elements = buffer.length >> sizeShift\n const ta = new TypedArray(elements)\n const method = dv[dvMethod]\n for (let i = 0; i < elements; i++) {\n ta[i] = method.call(dv, i << sizeShift, littleEndian)\n }\n return ta\n }\n }\n}\n\nfunction readBundleExt() {\n const length = readJustLength()\n const bundlePosition = position + read()\n for (let i = 2; i < length; i++) {\n // skip past bundles that were already read\n const bundleLength = readJustLength() // this will increment position, so must add to position afterwards\n position += bundleLength\n }\n const dataPosition = position\n position = bundlePosition\n bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())]\n bundledStrings.position0 = 0\n bundledStrings.position1 = 0\n bundledStrings.postBundlePosition = position\n position = dataPosition\n return read()\n}\n\nfunction readJustLength() {\n let token = src[position++] & 0x1f\n if (token > 0x17) {\n switch (token) {\n case 0x18:\n token = src[position++]\n break\n case 0x19:\n token = dataView.getUint16(position)\n position += 2\n break\n case 0x1a:\n token = dataView.getUint32(position)\n position += 4\n break\n }\n }\n return token\n}\n\nfunction loadShared() {\n if (currentDecoder.getShared) {\n const sharedData =\n saveState(() => {\n // save the state in case getShared modifies our buffer\n src = null\n return currentDecoder.getShared()\n }) || {}\n const updatedStructures = sharedData.structures || []\n currentDecoder.sharedVersion = sharedData.version\n packedValues = currentDecoder.sharedValues = sharedData.packedValues\n if (currentStructures === true) currentDecoder.structures = currentStructures = updatedStructures\n else currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))\n }\n}\n\nfunction saveState(callback) {\n const savedSrcEnd = srcEnd\n const savedPosition = position\n const savedStringPosition = stringPosition\n const savedSrcStringStart = srcStringStart\n const savedSrcStringEnd = srcStringEnd\n const savedSrcString = srcString\n const savedStrings = strings\n const savedReferenceMap = referenceMap\n const savedBundledStrings = bundledStrings\n\n // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)\n const savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed\n const savedStructures = currentStructures\n const savedDecoder = currentDecoder\n const savedSequentialMode = sequentialMode\n const value = callback()\n srcEnd = savedSrcEnd\n position = savedPosition\n stringPosition = savedStringPosition\n srcStringStart = savedSrcStringStart\n srcStringEnd = savedSrcStringEnd\n srcString = savedSrcString\n strings = savedStrings\n referenceMap = savedReferenceMap\n bundledStrings = savedBundledStrings\n src = savedSrc\n sequentialMode = savedSequentialMode\n currentStructures = savedStructures\n currentDecoder = savedDecoder\n dataView = new DataView(src.buffer, src.byteOffset, src.byteLength)\n return value\n}\nexport function clearSource() {\n src = null\n referenceMap = null\n currentStructures = null\n}\n\nexport function addExtension(extension) {\n currentExtensions[extension.tag] = extension.decode\n}\n\nexport function setSizeLimits(limits) {\n if (limits.maxMapSize) maxMapSize = limits.maxMapSize\n if (limits.maxArraySize) maxArraySize = limits.maxArraySize\n if (limits.maxObjectSize) maxObjectSize = limits.maxObjectSize\n}\n\nexport const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding\nfor (let i = 0; i < 256; i++) {\n mult10[i] = +`1e${Math.floor(45.15 - i * 0.30103)}`\n}\nconst defaultDecoder = new Decoder({ useRecords: false })\nexport const decode = defaultDecoder.decode\nexport const decodeMultiple = defaultDecoder.decodeMultiple\nexport const FLOAT32_OPTIONS = {\n NEVER: 0,\n ALWAYS: 1,\n DECIMAL_ROUND: 3,\n DECIMAL_FIT: 4,\n}\nexport function roundFloat32(float32Number) {\n f32Array[0] = float32Number\n const multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]\n return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier\n}\n","import { Decoder, FLOAT32_OPTIONS, Tag, addExtension as decodeAddExtension, mult10 } from './decode.js'\nlet textEncoder\ntry {\n textEncoder = new TextEncoder()\n} catch (error) {}\nlet extensions\nlet extensionClasses\nconst Buffer = typeof globalThis === 'object' && globalThis.Buffer\nconst hasNodeBuffer = typeof Buffer !== 'undefined'\nconst ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array\nconst ByteArray = hasNodeBuffer ? Buffer : Uint8Array\nconst MAX_STRUCTURES = 0x100\nconst MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000\nconst serializationId = 1\nlet throwOnIterable\nlet target\nlet targetView\nlet position = 0\nlet safeEnd\nlet bundledStrings = null\nconst MAX_BUNDLE_SIZE = 0xf000\nconst hasNonLatin = /[\\u0080-\\uFFFF]/\nconst RECORD_SYMBOL = Symbol('record-id')\nexport class Encoder extends Decoder {\n constructor(options) {\n super(options)\n this.offset = 0\n let typeBuffer\n let start\n let sharedStructures\n let hasSharedUpdate\n let structures\n let referenceMap\n options = options || {}\n const encodeUtf8 = ByteArray.prototype.utf8Write\n ? (string, position, maxBytes) => target.utf8Write(string, position, maxBytes)\n : textEncoder?.encodeInto\n ? (string, position) => textEncoder.encodeInto(string, target.subarray(position)).written\n : false\n\n const encoder = this\n const hasSharedStructures = options.structures || options.saveStructures\n let maxSharedStructures = options.maxSharedStructures\n if (maxSharedStructures == null) maxSharedStructures = hasSharedStructures ? 128 : 0\n if (maxSharedStructures > 8190) throw new Error('Maximum maxSharedStructure is 8190')\n const isSequential = options.sequential\n if (isSequential) {\n maxSharedStructures = 0\n }\n if (!this.structures) this.structures = []\n if (this.saveStructures) this.saveShared = this.saveStructures\n let samplingPackedValues\n let packedObjectMap\n let sharedValues = options.sharedValues\n let sharedPackedObjectMap\n if (sharedValues) {\n sharedPackedObjectMap = Object.create(null)\n for (let i = 0, l = sharedValues.length; i < l; i++) {\n sharedPackedObjectMap[sharedValues[i]] = i\n }\n }\n let recordIdsToRemove = []\n let transitionsCount = 0\n let serializationsSinceTransitionRebuild = 0\n\n this.mapEncode = function (value, encodeOptions) {\n // Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)\n if (this._keyMap && !this._mapped) {\n //console.log('encoding ', value)\n switch (value.constructor.name) {\n case 'Array':\n value = value.map((r) => this.encodeKeys(r))\n break\n //case 'Map':\n //\tvalue = this.encodeKeys(value)\n //\tbreak\n }\n //this._mapped = true\n }\n return this.encode(value, encodeOptions)\n }\n\n this.encode = (value, encodeOptions) => {\n if (!target) {\n target = new ByteArrayAllocate(8192)\n targetView = new DataView(target.buffer, 0, 8192)\n position = 0\n }\n safeEnd = target.length - 10\n if (safeEnd - position < 0x800) {\n // don't start too close to the end,\n target = new ByteArrayAllocate(target.length)\n targetView = new DataView(target.buffer, 0, target.length)\n safeEnd = target.length - 10\n position = 0\n } else if (encodeOptions === REUSE_BUFFER_MODE) position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster\n start = position\n