{"version":3,"file":"delegation-json.d.ts","sourceRoot":"","sources":["../../../src/slash/delegation-json.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,WAAW,CAAA;CAAE,CAAC;AAElD,sEAAsE;AACtE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAwG3F","sourcesContent":["const MAX_JSON_DEPTH = 64;\nconst MAX_JSON_ENTRIES = 100_000;\n\nexport type BoundedJsonClone =\n\t| { ok: true; value: unknown; encodedBytes: number }\n\t| { ok: false; reason: \"invalid\" | \"too_large\" };\n\n/** Clone plain JSON data without invoking getters or toJSON hooks. */\nexport function cloneJsonWithinByteLimit(input: unknown, maxBytes: number): BoundedJsonClone {\n\tlet minimumBytes = 0;\n\tlet entries = 0;\n\tconst active = new WeakSet<object>();\n\n\tconst addMinimumBytes = (bytes: number): void => {\n\t\tminimumBytes += bytes;\n\t\tif (minimumBytes > maxBytes) throw new RangeError(\"too_large\");\n\t};\n\n\tconst visit = (value: unknown, depth: number): unknown => {\n\t\tif (depth > MAX_JSON_DEPTH) throw new TypeError(\"invalid\");\n\t\tif (value === null) {\n\t\t\taddMinimumBytes(4);\n\t\t\treturn null;\n\t\t}\n\t\tif (typeof value === \"boolean\") {\n\t\t\taddMinimumBytes(value ? 4 : 5);\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === \"number\") {\n\t\t\tif (!Number.isFinite(value)) throw new TypeError(\"invalid\");\n\t\t\tconst encoded = JSON.stringify(Object.is(value, -0) ? 0 : value);\n\t\t\taddMinimumBytes(Buffer.byteLength(encoded, \"utf8\"));\n\t\t\treturn Object.is(value, -0) ? 0 : value;\n\t\t}\n\t\tif (typeof value === \"string\") {\n\t\t\t// Quoting and escaping can only increase the encoded size.\n\t\t\taddMinimumBytes(Buffer.byteLength(value, \"utf8\") + 2);\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value !== \"object\") throw new TypeError(\"invalid\");\n\n\t\tconst object = value as object;\n\t\tif (active.has(object)) throw new TypeError(\"invalid\");\n\t\tactive.add(object);\n\t\ttry {\n\t\t\tconst prototype = Object.getPrototypeOf(object);\n\t\t\tconst keys = Reflect.ownKeys(object);\n\t\t\tif (Array.isArray(object)) {\n\t\t\t\tif (prototype !== Array.prototype) throw new TypeError(\"invalid\");\n\t\t\t\tconst lengthDescriptor = Object.getOwnPropertyDescriptor(object, \"length\");\n\t\t\t\tif (\n\t\t\t\t\t!lengthDescriptor ||\n\t\t\t\t\t!(\"value\" in lengthDescriptor) ||\n\t\t\t\t\t!Number.isSafeInteger(lengthDescriptor.value) ||\n\t\t\t\t\tlengthDescriptor.value < 0\n\t\t\t\t) {\n\t\t\t\t\tthrow new TypeError(\"invalid\");\n\t\t\t\t}\n\t\t\t\tconst length = lengthDescriptor.value as number;\n\t\t\t\taddMinimumBytes(2 + Math.max(0, length - 1));\n\t\t\t\tconst output: unknown[] = [];\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tif (typeof key === \"symbol\") throw new TypeError(\"invalid\");\n\t\t\t\t\tif (key === \"length\") continue;\n\t\t\t\t\tif (!/^(?:0|[1-9][0-9]*)$/.test(key) || Number(key) >= length) throw new TypeError(\"invalid\");\n\t\t\t\t}\n\t\t\t\tfor (let index = 0; index < length; index++) {\n\t\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, String(index));\n\t\t\t\t\tif (!descriptor || !(\"value\" in descriptor) || !descriptor.enumerable) throw new TypeError(\"invalid\");\n\t\t\t\t\tentries++;\n\t\t\t\t\tif (entries > MAX_JSON_ENTRIES) throw new TypeError(\"invalid\");\n\t\t\t\t\toutput.push(visit(descriptor.value, depth + 1));\n\t\t\t\t}\n\t\t\t\treturn output;\n\t\t\t}\n\n\t\t\tif (prototype !== Object.prototype && prototype !== null) throw new TypeError(\"invalid\");\n\t\t\taddMinimumBytes(2 + Math.max(0, keys.length - 1));\n\t\t\tconst output: Record<string, unknown> = {};\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (typeof key === \"symbol\") throw new TypeError(\"invalid\");\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key);\n\t\t\t\tif (!descriptor || !(\"value\" in descriptor) || !descriptor.enumerable) throw new TypeError(\"invalid\");\n\t\t\t\tentries++;\n\t\t\t\tif (entries > MAX_JSON_ENTRIES) throw new TypeError(\"invalid\");\n\t\t\t\taddMinimumBytes(Buffer.byteLength(JSON.stringify(key), \"utf8\") + 1);\n\t\t\t\tObject.defineProperty(output, key, {\n\t\t\t\t\tvalue: visit(descriptor.value, depth + 1),\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn output;\n\t\t} finally {\n\t\t\tactive.delete(object);\n\t\t}\n\t};\n\n\ttry {\n\t\tconst value = visit(input, 0);\n\t\tconst encoded = JSON.stringify(value);\n\t\tif (encoded === undefined) return { ok: false, reason: \"invalid\" };\n\t\tconst encodedBytes = Buffer.byteLength(encoded, \"utf8\");\n\t\tif (encodedBytes > maxBytes) return { ok: false, reason: \"too_large\" };\n\t\treturn { ok: true, value, encodedBytes };\n\t} catch (error) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: error instanceof RangeError && error.message === \"too_large\" ? \"too_large\" : \"invalid\",\n\t\t};\n\t}\n}\n"]}