@sammorrowdrums/mcpi-protocol 0.85.0-bootstrap.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mario Zechner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # @sammorrowdrums/mcpi-protocol
2
+
3
+ Runtime-neutral schemas, types, CBOR encoding, and byte-stream framing for the experimental mcpi protocol.
4
+
5
+ Protocol version `1` uses binary messages with this wire layout:
6
+
7
+ 1. A four-byte unsigned big-endian payload length.
8
+ 2. One definite-length CBOR item containing the message.
9
+
10
+ The first client message is always `hello`, containing `PROTOCOL_VERSION`. Subsequent messages use correlated request/response envelopes and server event envelopes. Session and server snapshots are authoritative. Progress events are transient UI hints and must not be reduced into authoritative state. Transports complete authentication before protocol bytes are exchanged.
11
+
12
+ Session lists contain `SessionMetadata`, the normalized durable metadata available without acquiring a session runtime. Only `id` and `createdAt` are required; `updatedAt`, `parentSessionId`, `sessionName`, and `cwd` are included when supported by the backing store. Runtime state such as phase, model, thinking level, attachment, and locking appears only in an acquired `SessionSnapshot`.
13
+
14
+ ## Validated message API
15
+
16
+ `encodeClientMessage()` and `encodeServerMessage()` validate a message and return a complete framed `Uint8Array`. The incremental decoders accept arbitrary fragmentation or coalescing, so they work with streams, sockets, and custom byte transports.
17
+
18
+ ```ts
19
+ import {
20
+ PROTOCOL_VERSION,
21
+ createServerMessageDecoder,
22
+ encodeClientMessage,
23
+ type ClientHello,
24
+ } from "@sammorrowdrums/mcpi-protocol";
25
+
26
+ const hello: ClientHello = {
27
+ type: "hello",
28
+ version: PROTOCOL_VERSION,
29
+ };
30
+
31
+ transport.send(encodeClientMessage(hello));
32
+
33
+ const decoder = createServerMessageDecoder({ maxFrameLength: 1024 * 1024 });
34
+ for (const message of decoder.push(incomingChunk)) {
35
+ handleServerMessage(message);
36
+ }
37
+ decoder.end(); // Call when the byte stream closes to detect truncation.
38
+ ```
39
+
40
+ `ClientMessageDecoder` and `ServerMessageDecoder` are also available directly. Schema violations, malformed CBOR, and invalid framing throw `ProtocolValidationError`. Validation errors do not retain rejected payloads.
41
+
42
+ `parseClientMessage()` and `parseServerMessage()` only validate already-decoded values. They do not parse JSON strings.
43
+
44
+ ## Transport support
45
+
46
+ Every transport carries the same complete bytes: `[uint32-be CBOR length][CBOR payload]`. Transports may split or coalesce those bytes arbitrarily.
47
+
48
+ This package does not bundle a transport. Consumers provide a byte-stream transport that preserves byte order and reports stream closure. Custom transports must handle arbitrary frame fragmentation and coalescing.
49
+
50
+ All transports are untrusted. Configure matching frame limits and enforce access controls appropriate for the transport before exposing a connection to the protocol. Unix sockets can use filesystem permissions, while network transports can authenticate during connection establishment.
51
+
52
+ ## Encoding and framing
53
+
54
+ `encodeCbor()` and `decodeCbor()` implement the protocol's strict RFC 8949 subset. `encodeFrame()` and `FrameDecoder` handle framing independently of schemas and CBOR.
55
+
56
+ The CBOR subset supports:
57
+
58
+ - `null` and booleans
59
+ - finite numbers, with integers restricted to JavaScript's safe range and non-integers encoded as float64
60
+ - UTF-8 strings
61
+ - `Uint8Array` byte strings
62
+ - definite-length arrays
63
+ - definite-length maps represented by objects with unique string keys
64
+
65
+ Undefined object properties are omitted. JSON-valued protocol fields reject CBOR byte strings and non-plain objects. Top-level undefined, undefined array entries, sparse arrays, non-finite or unsafe numbers, tags, indefinite-length items, malformed UTF-8, trailing data, excessive nesting, and oversized values are rejected.
66
+
67
+ Default limits are 16 MiB per CBOR payload/frame, 1,000,000 array elements or map entries, and 64 nested item levels. Options can configure these limits. A frame decoder validates the declared length before buffering payload bytes.
68
+
69
+ All schemas reject unknown object properties. The protocol is experimental and has no compatibility guarantees.
@@ -0,0 +1,4 @@
1
+ import { type CborOptions } from "./options.ts";
2
+ /** Decodes exactly one item from the protocol's strict RFC 8949 subset. */
3
+ export declare function decodeCbor(bytes: Uint8Array, options?: CborOptions): unknown;
4
+ //# sourceMappingURL=decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/cbor/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,WAAW,EAKhB,MAAM,cAAc,CAAC;AAwJtB,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAO5E","sourcesContent":["import {\n\tCborError,\n\ttype CborOptions,\n\ttype ResolvedCborOptions,\n\tresolveOptions,\n\ttextDecoder,\n\tUINT32_BASE,\n} from \"./options.ts\";\n\nclass CborReader {\n\tprivate readonly bytes: Uint8Array;\n\tprivate offset = 0;\n\tprivate readonly options: ResolvedCborOptions;\n\n\tconstructor(bytes: Uint8Array, options: ResolvedCborOptions) {\n\t\tthis.bytes = bytes;\n\t\tthis.options = options;\n\t}\n\n\tdecode(): unknown {\n\t\tconst value = this.readItem(0);\n\t\tif (this.offset !== this.bytes.byteLength) throw new CborError(\"CBOR payload contains trailing data\");\n\t\treturn value;\n\t}\n\n\tprivate readItem(depth: number): unknown {\n\t\tif (depth > this.options.maxDepth) {\n\t\t\tthrow new CborError(`CBOR nesting depth exceeds configured limit of ${this.options.maxDepth}`);\n\t\t}\n\t\tconst initial = this.readByte();\n\t\tconst majorType = initial >>> 5;\n\t\tconst additionalInformation = initial & 0x1f;\n\n\t\tswitch (majorType) {\n\t\t\tcase 0:\n\t\t\t\treturn this.readArgument(additionalInformation);\n\t\t\tcase 1: {\n\t\t\t\tconst value = -1 - this.readArgument(additionalInformation);\n\t\t\t\tif (!Number.isSafeInteger(value)) throw new CborError(\"Decoded CBOR integer is outside the safe range\");\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tcase 2: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"byte string\", this.options.maxByteLength);\n\t\t\t\treturn new Uint8Array(this.readBytes(length));\n\t\t\t}\n\t\t\tcase 3: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"text string\", this.options.maxByteLength);\n\t\t\t\tconst bytes = this.readBytes(length);\n\t\t\t\ttry {\n\t\t\t\t\treturn textDecoder.decode(bytes);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tthrow new CborError(\"CBOR text string contains invalid UTF-8\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase 4: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"array\", this.options.maxContainerLength);\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (let index = 0; index < length; index++) result.push(this.readItem(depth + 1));\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcase 5: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"map\", this.options.maxContainerLength);\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tconst keys = new Set<string>();\n\t\t\t\tfor (let index = 0; index < length; index++) {\n\t\t\t\t\tconst key = this.readItem(depth + 1);\n\t\t\t\t\tif (typeof key !== \"string\") throw new CborError(\"CBOR map keys must be strings\");\n\t\t\t\t\tif (keys.has(key)) throw new CborError(\"CBOR map contains a duplicate key\");\n\t\t\t\t\tkeys.add(key);\n\t\t\t\t\tObject.defineProperty(result, key, {\n\t\t\t\t\t\tconfigurable: true,\n\t\t\t\t\t\tenumerable: true,\n\t\t\t\t\t\tvalue: this.readItem(depth + 1),\n\t\t\t\t\t\twritable: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcase 6:\n\t\t\t\tthrow new CborError(\"CBOR tags are not supported\");\n\t\t\tcase 7:\n\t\t\t\treturn this.readSimple(additionalInformation);\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Malformed CBOR major type\");\n\t\t}\n\t}\n\n\tprivate readSimple(additionalInformation: number): unknown {\n\t\tswitch (additionalInformation) {\n\t\t\tcase 20:\n\t\t\t\treturn false;\n\t\t\tcase 21:\n\t\t\t\treturn true;\n\t\t\tcase 22:\n\t\t\t\treturn null;\n\t\t\tcase 27: {\n\t\t\t\tconst bytes = this.readBytes(8);\n\t\t\t\tconst value = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getFloat64(0, false);\n\t\t\t\tif (!Number.isFinite(value)) throw new CborError(\"Decoded CBOR number must be finite\");\n\t\t\t\tif (Number.isInteger(value) && !Number.isSafeInteger(value)) {\n\t\t\t\t\tthrow new CborError(\"Decoded CBOR integer is outside the safe range\");\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tcase 31:\n\t\t\t\tthrow new CborError(\"CBOR break marker is not supported\");\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Unsupported CBOR simple value or floating-point width\");\n\t\t}\n\t}\n\n\tprivate readLength(additionalInformation: number, kind: string, limit: number): number {\n\t\tif (additionalInformation === 31) throw new CborError(`Indefinite-length CBOR ${kind}s are not supported`);\n\t\tconst length = this.readArgument(additionalInformation);\n\t\tif (length > limit) throw new CborError(`CBOR ${kind} length exceeds configured limit of ${limit}`);\n\t\treturn length;\n\t}\n\n\tprivate readArgument(additionalInformation: number): number {\n\t\tif (additionalInformation < 24) return additionalInformation;\n\t\tswitch (additionalInformation) {\n\t\t\tcase 24:\n\t\t\t\treturn this.readByte();\n\t\t\tcase 25: {\n\t\t\t\tconst bytes = this.readBytes(2);\n\t\t\t\treturn bytes[0]! * 0x100 + bytes[1]!;\n\t\t\t}\n\t\t\tcase 26: {\n\t\t\t\tconst bytes = this.readBytes(4);\n\t\t\t\treturn bytes[0]! * 0x1_000_000 + bytes[1]! * 0x1_0000 + bytes[2]! * 0x100 + bytes[3]!;\n\t\t\t}\n\t\t\tcase 27: {\n\t\t\t\tconst high = this.readArgument(26);\n\t\t\t\tconst low = this.readArgument(26);\n\t\t\t\tif (high > 0x1f_ffff) throw new CborError(\"Decoded CBOR integer or length is outside the safe range\");\n\t\t\t\treturn high * UINT32_BASE + low;\n\t\t\t}\n\t\t\tcase 31:\n\t\t\t\tthrow new CborError(\"Indefinite-length CBOR items are not supported\");\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Malformed CBOR additional information\");\n\t\t}\n\t}\n\n\tprivate readByte(): number {\n\t\tif (this.offset >= this.bytes.byteLength) throw new CborError(\"Truncated CBOR payload\");\n\t\tconst value = this.bytes[this.offset]!;\n\t\tthis.offset++;\n\t\treturn value;\n\t}\n\n\tprivate readBytes(length: number): Uint8Array {\n\t\tif (length > this.bytes.byteLength - this.offset) throw new CborError(\"Truncated CBOR payload\");\n\t\tconst value = this.bytes.subarray(this.offset, this.offset + length);\n\t\tthis.offset += length;\n\t\treturn value;\n\t}\n}\n\n/** Decodes exactly one item from the protocol's strict RFC 8949 subset. */\nexport function decodeCbor(bytes: Uint8Array, options?: CborOptions): unknown {\n\tif (!(bytes instanceof Uint8Array)) throw new TypeError(\"CBOR input must be a Uint8Array\");\n\tconst resolved = resolveOptions(options);\n\tif (bytes.byteLength > resolved.maxByteLength) {\n\t\tthrow new CborError(`CBOR byte length exceeds configured limit of ${resolved.maxByteLength}`);\n\t}\n\treturn new CborReader(bytes, resolved).decode();\n}\n"]}
@@ -0,0 +1,165 @@
1
+ import { CborError, resolveOptions, textDecoder, UINT32_BASE, } from "./options.js";
2
+ class CborReader {
3
+ bytes;
4
+ offset = 0;
5
+ options;
6
+ constructor(bytes, options) {
7
+ this.bytes = bytes;
8
+ this.options = options;
9
+ }
10
+ decode() {
11
+ const value = this.readItem(0);
12
+ if (this.offset !== this.bytes.byteLength)
13
+ throw new CborError("CBOR payload contains trailing data");
14
+ return value;
15
+ }
16
+ readItem(depth) {
17
+ if (depth > this.options.maxDepth) {
18
+ throw new CborError(`CBOR nesting depth exceeds configured limit of ${this.options.maxDepth}`);
19
+ }
20
+ const initial = this.readByte();
21
+ const majorType = initial >>> 5;
22
+ const additionalInformation = initial & 0x1f;
23
+ switch (majorType) {
24
+ case 0:
25
+ return this.readArgument(additionalInformation);
26
+ case 1: {
27
+ const value = -1 - this.readArgument(additionalInformation);
28
+ if (!Number.isSafeInteger(value))
29
+ throw new CborError("Decoded CBOR integer is outside the safe range");
30
+ return value;
31
+ }
32
+ case 2: {
33
+ const length = this.readLength(additionalInformation, "byte string", this.options.maxByteLength);
34
+ return new Uint8Array(this.readBytes(length));
35
+ }
36
+ case 3: {
37
+ const length = this.readLength(additionalInformation, "text string", this.options.maxByteLength);
38
+ const bytes = this.readBytes(length);
39
+ try {
40
+ return textDecoder.decode(bytes);
41
+ }
42
+ catch (_error) {
43
+ throw new CborError("CBOR text string contains invalid UTF-8");
44
+ }
45
+ }
46
+ case 4: {
47
+ const length = this.readLength(additionalInformation, "array", this.options.maxContainerLength);
48
+ const result = [];
49
+ for (let index = 0; index < length; index++)
50
+ result.push(this.readItem(depth + 1));
51
+ return result;
52
+ }
53
+ case 5: {
54
+ const length = this.readLength(additionalInformation, "map", this.options.maxContainerLength);
55
+ const result = {};
56
+ const keys = new Set();
57
+ for (let index = 0; index < length; index++) {
58
+ const key = this.readItem(depth + 1);
59
+ if (typeof key !== "string")
60
+ throw new CborError("CBOR map keys must be strings");
61
+ if (keys.has(key))
62
+ throw new CborError("CBOR map contains a duplicate key");
63
+ keys.add(key);
64
+ Object.defineProperty(result, key, {
65
+ configurable: true,
66
+ enumerable: true,
67
+ value: this.readItem(depth + 1),
68
+ writable: true,
69
+ });
70
+ }
71
+ return result;
72
+ }
73
+ case 6:
74
+ throw new CborError("CBOR tags are not supported");
75
+ case 7:
76
+ return this.readSimple(additionalInformation);
77
+ default:
78
+ throw new CborError("Malformed CBOR major type");
79
+ }
80
+ }
81
+ readSimple(additionalInformation) {
82
+ switch (additionalInformation) {
83
+ case 20:
84
+ return false;
85
+ case 21:
86
+ return true;
87
+ case 22:
88
+ return null;
89
+ case 27: {
90
+ const bytes = this.readBytes(8);
91
+ const value = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getFloat64(0, false);
92
+ if (!Number.isFinite(value))
93
+ throw new CborError("Decoded CBOR number must be finite");
94
+ if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
95
+ throw new CborError("Decoded CBOR integer is outside the safe range");
96
+ }
97
+ return value;
98
+ }
99
+ case 31:
100
+ throw new CborError("CBOR break marker is not supported");
101
+ default:
102
+ throw new CborError("Unsupported CBOR simple value or floating-point width");
103
+ }
104
+ }
105
+ readLength(additionalInformation, kind, limit) {
106
+ if (additionalInformation === 31)
107
+ throw new CborError(`Indefinite-length CBOR ${kind}s are not supported`);
108
+ const length = this.readArgument(additionalInformation);
109
+ if (length > limit)
110
+ throw new CborError(`CBOR ${kind} length exceeds configured limit of ${limit}`);
111
+ return length;
112
+ }
113
+ readArgument(additionalInformation) {
114
+ if (additionalInformation < 24)
115
+ return additionalInformation;
116
+ switch (additionalInformation) {
117
+ case 24:
118
+ return this.readByte();
119
+ case 25: {
120
+ const bytes = this.readBytes(2);
121
+ return bytes[0] * 0x100 + bytes[1];
122
+ }
123
+ case 26: {
124
+ const bytes = this.readBytes(4);
125
+ return bytes[0] * 0x1_000_000 + bytes[1] * 0x1_0000 + bytes[2] * 0x100 + bytes[3];
126
+ }
127
+ case 27: {
128
+ const high = this.readArgument(26);
129
+ const low = this.readArgument(26);
130
+ if (high > 0x1f_ffff)
131
+ throw new CborError("Decoded CBOR integer or length is outside the safe range");
132
+ return high * UINT32_BASE + low;
133
+ }
134
+ case 31:
135
+ throw new CborError("Indefinite-length CBOR items are not supported");
136
+ default:
137
+ throw new CborError("Malformed CBOR additional information");
138
+ }
139
+ }
140
+ readByte() {
141
+ if (this.offset >= this.bytes.byteLength)
142
+ throw new CborError("Truncated CBOR payload");
143
+ const value = this.bytes[this.offset];
144
+ this.offset++;
145
+ return value;
146
+ }
147
+ readBytes(length) {
148
+ if (length > this.bytes.byteLength - this.offset)
149
+ throw new CborError("Truncated CBOR payload");
150
+ const value = this.bytes.subarray(this.offset, this.offset + length);
151
+ this.offset += length;
152
+ return value;
153
+ }
154
+ }
155
+ /** Decodes exactly one item from the protocol's strict RFC 8949 subset. */
156
+ export function decodeCbor(bytes, options) {
157
+ if (!(bytes instanceof Uint8Array))
158
+ throw new TypeError("CBOR input must be a Uint8Array");
159
+ const resolved = resolveOptions(options);
160
+ if (bytes.byteLength > resolved.maxByteLength) {
161
+ throw new CborError(`CBOR byte length exceeds configured limit of ${resolved.maxByteLength}`);
162
+ }
163
+ return new CborReader(bytes, resolved).decode();
164
+ }
165
+ //# sourceMappingURL=decoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/cbor/decoder.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tCborError,\n\ttype CborOptions,\n\ttype ResolvedCborOptions,\n\tresolveOptions,\n\ttextDecoder,\n\tUINT32_BASE,\n} from \"./options.ts\";\n\nclass CborReader {\n\tprivate readonly bytes: Uint8Array;\n\tprivate offset = 0;\n\tprivate readonly options: ResolvedCborOptions;\n\n\tconstructor(bytes: Uint8Array, options: ResolvedCborOptions) {\n\t\tthis.bytes = bytes;\n\t\tthis.options = options;\n\t}\n\n\tdecode(): unknown {\n\t\tconst value = this.readItem(0);\n\t\tif (this.offset !== this.bytes.byteLength) throw new CborError(\"CBOR payload contains trailing data\");\n\t\treturn value;\n\t}\n\n\tprivate readItem(depth: number): unknown {\n\t\tif (depth > this.options.maxDepth) {\n\t\t\tthrow new CborError(`CBOR nesting depth exceeds configured limit of ${this.options.maxDepth}`);\n\t\t}\n\t\tconst initial = this.readByte();\n\t\tconst majorType = initial >>> 5;\n\t\tconst additionalInformation = initial & 0x1f;\n\n\t\tswitch (majorType) {\n\t\t\tcase 0:\n\t\t\t\treturn this.readArgument(additionalInformation);\n\t\t\tcase 1: {\n\t\t\t\tconst value = -1 - this.readArgument(additionalInformation);\n\t\t\t\tif (!Number.isSafeInteger(value)) throw new CborError(\"Decoded CBOR integer is outside the safe range\");\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tcase 2: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"byte string\", this.options.maxByteLength);\n\t\t\t\treturn new Uint8Array(this.readBytes(length));\n\t\t\t}\n\t\t\tcase 3: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"text string\", this.options.maxByteLength);\n\t\t\t\tconst bytes = this.readBytes(length);\n\t\t\t\ttry {\n\t\t\t\t\treturn textDecoder.decode(bytes);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tthrow new CborError(\"CBOR text string contains invalid UTF-8\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase 4: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"array\", this.options.maxContainerLength);\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (let index = 0; index < length; index++) result.push(this.readItem(depth + 1));\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcase 5: {\n\t\t\t\tconst length = this.readLength(additionalInformation, \"map\", this.options.maxContainerLength);\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tconst keys = new Set<string>();\n\t\t\t\tfor (let index = 0; index < length; index++) {\n\t\t\t\t\tconst key = this.readItem(depth + 1);\n\t\t\t\t\tif (typeof key !== \"string\") throw new CborError(\"CBOR map keys must be strings\");\n\t\t\t\t\tif (keys.has(key)) throw new CborError(\"CBOR map contains a duplicate key\");\n\t\t\t\t\tkeys.add(key);\n\t\t\t\t\tObject.defineProperty(result, key, {\n\t\t\t\t\t\tconfigurable: true,\n\t\t\t\t\t\tenumerable: true,\n\t\t\t\t\t\tvalue: this.readItem(depth + 1),\n\t\t\t\t\t\twritable: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcase 6:\n\t\t\t\tthrow new CborError(\"CBOR tags are not supported\");\n\t\t\tcase 7:\n\t\t\t\treturn this.readSimple(additionalInformation);\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Malformed CBOR major type\");\n\t\t}\n\t}\n\n\tprivate readSimple(additionalInformation: number): unknown {\n\t\tswitch (additionalInformation) {\n\t\t\tcase 20:\n\t\t\t\treturn false;\n\t\t\tcase 21:\n\t\t\t\treturn true;\n\t\t\tcase 22:\n\t\t\t\treturn null;\n\t\t\tcase 27: {\n\t\t\t\tconst bytes = this.readBytes(8);\n\t\t\t\tconst value = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getFloat64(0, false);\n\t\t\t\tif (!Number.isFinite(value)) throw new CborError(\"Decoded CBOR number must be finite\");\n\t\t\t\tif (Number.isInteger(value) && !Number.isSafeInteger(value)) {\n\t\t\t\t\tthrow new CborError(\"Decoded CBOR integer is outside the safe range\");\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tcase 31:\n\t\t\t\tthrow new CborError(\"CBOR break marker is not supported\");\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Unsupported CBOR simple value or floating-point width\");\n\t\t}\n\t}\n\n\tprivate readLength(additionalInformation: number, kind: string, limit: number): number {\n\t\tif (additionalInformation === 31) throw new CborError(`Indefinite-length CBOR ${kind}s are not supported`);\n\t\tconst length = this.readArgument(additionalInformation);\n\t\tif (length > limit) throw new CborError(`CBOR ${kind} length exceeds configured limit of ${limit}`);\n\t\treturn length;\n\t}\n\n\tprivate readArgument(additionalInformation: number): number {\n\t\tif (additionalInformation < 24) return additionalInformation;\n\t\tswitch (additionalInformation) {\n\t\t\tcase 24:\n\t\t\t\treturn this.readByte();\n\t\t\tcase 25: {\n\t\t\t\tconst bytes = this.readBytes(2);\n\t\t\t\treturn bytes[0]! * 0x100 + bytes[1]!;\n\t\t\t}\n\t\t\tcase 26: {\n\t\t\t\tconst bytes = this.readBytes(4);\n\t\t\t\treturn bytes[0]! * 0x1_000_000 + bytes[1]! * 0x1_0000 + bytes[2]! * 0x100 + bytes[3]!;\n\t\t\t}\n\t\t\tcase 27: {\n\t\t\t\tconst high = this.readArgument(26);\n\t\t\t\tconst low = this.readArgument(26);\n\t\t\t\tif (high > 0x1f_ffff) throw new CborError(\"Decoded CBOR integer or length is outside the safe range\");\n\t\t\t\treturn high * UINT32_BASE + low;\n\t\t\t}\n\t\t\tcase 31:\n\t\t\t\tthrow new CborError(\"Indefinite-length CBOR items are not supported\");\n\t\t\tdefault:\n\t\t\t\tthrow new CborError(\"Malformed CBOR additional information\");\n\t\t}\n\t}\n\n\tprivate readByte(): number {\n\t\tif (this.offset >= this.bytes.byteLength) throw new CborError(\"Truncated CBOR payload\");\n\t\tconst value = this.bytes[this.offset]!;\n\t\tthis.offset++;\n\t\treturn value;\n\t}\n\n\tprivate readBytes(length: number): Uint8Array {\n\t\tif (length > this.bytes.byteLength - this.offset) throw new CborError(\"Truncated CBOR payload\");\n\t\tconst value = this.bytes.subarray(this.offset, this.offset + length);\n\t\tthis.offset += length;\n\t\treturn value;\n\t}\n}\n\n/** Decodes exactly one item from the protocol's strict RFC 8949 subset. */\nexport function decodeCbor(bytes: Uint8Array, options?: CborOptions): unknown {\n\tif (!(bytes instanceof Uint8Array)) throw new TypeError(\"CBOR input must be a Uint8Array\");\n\tconst resolved = resolveOptions(options);\n\tif (bytes.byteLength > resolved.maxByteLength) {\n\t\tthrow new CborError(`CBOR byte length exceeds configured limit of ${resolved.maxByteLength}`);\n\t}\n\treturn new CborReader(bytes, resolved).decode();\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { type CborOptions } from "./options.ts";
2
+ /** Encodes the protocol's strict, definite-length RFC 8949 subset. */
3
+ export declare function encodeCbor(value: unknown, options?: CborOptions): Uint8Array;
4
+ //# sourceMappingURL=encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../src/cbor/encoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,WAAW,EAOhB,MAAM,cAAc,CAAC;AAwMtB,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAK5E","sourcesContent":["import {\n\tCborError,\n\ttype CborOptions,\n\tMAX_UINT32,\n\ttype ResolvedCborOptions,\n\tresolveOptions,\n\ttextDecoder,\n\ttextEncoder,\n\tUINT32_BASE,\n} from \"./options.ts\";\n\nclass CborWriter {\n\tprivate buffer: Uint8Array;\n\tprivate offset = 0;\n\tprivate readonly maxByteLength: number;\n\n\tconstructor(maxByteLength: number) {\n\t\tthis.maxByteLength = maxByteLength;\n\t\tthis.buffer = new Uint8Array(Math.min(256, maxByteLength));\n\t}\n\n\twriteByte(value: number): void {\n\t\tthis.ensureCapacity(1);\n\t\tthis.buffer[this.offset] = value;\n\t\tthis.offset++;\n\t}\n\n\twriteBytes(bytes: Uint8Array): void {\n\t\tthis.ensureCapacity(bytes.byteLength);\n\t\tthis.buffer.set(bytes, this.offset);\n\t\tthis.offset += bytes.byteLength;\n\t}\n\n\twriteUint16(value: number): void {\n\t\tthis.ensureCapacity(2);\n\t\tthis.buffer[this.offset] = value >>> 8;\n\t\tthis.buffer[this.offset + 1] = value;\n\t\tthis.offset += 2;\n\t}\n\n\twriteUint32(value: number): void {\n\t\tthis.ensureCapacity(4);\n\t\tthis.buffer[this.offset] = value >>> 24;\n\t\tthis.buffer[this.offset + 1] = value >>> 16;\n\t\tthis.buffer[this.offset + 2] = value >>> 8;\n\t\tthis.buffer[this.offset + 3] = value;\n\t\tthis.offset += 4;\n\t}\n\n\twriteUint64(value: number): void {\n\t\tconst high = Math.floor(value / UINT32_BASE);\n\t\tconst low = value - high * UINT32_BASE;\n\t\tthis.writeUint32(high);\n\t\tthis.writeUint32(low);\n\t}\n\n\twriteFloat64(value: number): void {\n\t\tthis.ensureCapacity(9);\n\t\tthis.buffer[this.offset] = 0xfb;\n\t\tnew DataView(this.buffer.buffer).setFloat64(this.offset + 1, value, false);\n\t\tthis.offset += 9;\n\t}\n\n\tfinish(): Uint8Array {\n\t\treturn this.buffer.slice(0, this.offset);\n\t}\n\n\tprivate ensureCapacity(additionalBytes: number): void {\n\t\tconst required = this.offset + additionalBytes;\n\t\tif (required > this.maxByteLength) {\n\t\t\tthrow new CborError(`CBOR byte length exceeds configured limit of ${this.maxByteLength}`);\n\t\t}\n\t\tif (required <= this.buffer.byteLength) return;\n\n\t\tlet capacity = Math.max(1, this.buffer.byteLength);\n\t\twhile (capacity < required) capacity = Math.min(this.maxByteLength, Math.max(required, capacity * 2));\n\t\tconst expanded = new Uint8Array(capacity);\n\t\texpanded.set(this.buffer);\n\t\tthis.buffer = expanded;\n\t}\n}\n\nfunction writeArgument(writer: CborWriter, majorType: number, value: number): void {\n\tconst prefix = majorType << 5;\n\tif (value < 24) {\n\t\twriter.writeByte(prefix | value);\n\t} else if (value <= 0xff) {\n\t\twriter.writeByte(prefix | 24);\n\t\twriter.writeByte(value);\n\t} else if (value <= 0xffff) {\n\t\twriter.writeByte(prefix | 25);\n\t\twriter.writeUint16(value);\n\t} else if (value <= MAX_UINT32) {\n\t\twriter.writeByte(prefix | 26);\n\t\twriter.writeUint32(value);\n\t} else {\n\t\twriter.writeByte(prefix | 27);\n\t\twriter.writeUint64(value);\n\t}\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction encodeText(writer: CborWriter, value: string, options: ResolvedCborOptions): void {\n\tconst bytes = textEncoder.encode(value);\n\tif (bytes.byteLength > options.maxByteLength) {\n\t\tthrow new CborError(`CBOR text string length exceeds configured limit of ${options.maxByteLength}`);\n\t}\n\tif (textDecoder.decode(bytes) !== value)\n\t\tthrow new CborError(\"CBOR text strings must contain valid Unicode scalar values\");\n\twriteArgument(writer, 3, bytes.byteLength);\n\twriter.writeBytes(bytes);\n}\n\nfunction encodeValue(\n\twriter: CborWriter,\n\tvalue: unknown,\n\toptions: ResolvedCborOptions,\n\tdepth: number,\n\tancestors: Set<object>,\n): void {\n\tif (depth > options.maxDepth)\n\t\tthrow new CborError(`CBOR nesting depth exceeds configured limit of ${options.maxDepth}`);\n\n\tif (value === null) {\n\t\twriter.writeByte(0xf6);\n\t\treturn;\n\t}\n\tif (typeof value === \"boolean\") {\n\t\twriter.writeByte(value ? 0xf5 : 0xf4);\n\t\treturn;\n\t}\n\tif (typeof value === \"number\") {\n\t\tif (!Number.isFinite(value)) throw new CborError(\"CBOR numbers must be finite\");\n\t\tif (Number.isInteger(value) && !Object.is(value, -0)) {\n\t\t\tif (!Number.isSafeInteger(value)) throw new CborError(\"CBOR integers must be safe JavaScript integers\");\n\t\t\tif (value >= 0) writeArgument(writer, 0, value);\n\t\t\telse writeArgument(writer, 1, -1 - value);\n\t\t} else {\n\t\t\twriter.writeFloat64(value);\n\t\t}\n\t\treturn;\n\t}\n\tif (typeof value === \"string\") {\n\t\tencodeText(writer, value, options);\n\t\treturn;\n\t}\n\tif (value instanceof Uint8Array) {\n\t\tif (value.byteLength > options.maxByteLength) {\n\t\t\tthrow new CborError(`CBOR byte string length exceeds configured limit of ${options.maxByteLength}`);\n\t\t}\n\t\twriteArgument(writer, 2, value.byteLength);\n\t\twriter.writeBytes(value);\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tif (ancestors.has(value)) throw new CborError(\"CBOR values must not contain cycles\");\n\t\tif (value.length > options.maxContainerLength) {\n\t\t\tthrow new CborError(`CBOR array length exceeds configured limit of ${options.maxContainerLength}`);\n\t\t}\n\t\tancestors.add(value);\n\t\ttry {\n\t\t\twriteArgument(writer, 4, value.length);\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tif (!Object.hasOwn(value, index) || value[index] === undefined) {\n\t\t\t\t\tthrow new CborError(\"CBOR arrays must not contain holes or undefined values\");\n\t\t\t\t}\n\t\t\t\tencodeValue(writer, value[index], options, depth + 1, ancestors);\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(value);\n\t\t}\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tif (ancestors.has(value)) throw new CborError(\"CBOR values must not contain cycles\");\n\t\tfor (const symbol of Object.getOwnPropertySymbols(value)) {\n\t\t\tif (Object.prototype.propertyIsEnumerable.call(value, symbol)) {\n\t\t\t\tthrow new CborError(\"CBOR map keys must be strings\");\n\t\t\t}\n\t\t}\n\t\tconst entries: Array<readonly [string, unknown]> = [];\n\t\tfor (const key of Object.keys(value)) {\n\t\t\tconst entryValue = value[key];\n\t\t\tif (entryValue !== undefined) entries.push([key, entryValue]);\n\t\t}\n\t\tif (entries.length > options.maxContainerLength) {\n\t\t\tthrow new CborError(`CBOR map length exceeds configured limit of ${options.maxContainerLength}`);\n\t\t}\n\t\tancestors.add(value);\n\t\ttry {\n\t\t\twriteArgument(writer, 5, entries.length);\n\t\t\tfor (const [key, entryValue] of entries) {\n\t\t\t\tencodeText(writer, key, options);\n\t\t\t\tencodeValue(writer, entryValue, options, depth + 1, ancestors);\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(value);\n\t\t}\n\t\treturn;\n\t}\n\n\tthrow new CborError(`Unsupported CBOR value type: ${typeof value}`);\n}\n\n/** Encodes the protocol's strict, definite-length RFC 8949 subset. */\nexport function encodeCbor(value: unknown, options?: CborOptions): Uint8Array {\n\tconst resolved = resolveOptions(options);\n\tconst writer = new CborWriter(resolved.maxByteLength);\n\tencodeValue(writer, value, resolved, 0, new Set<object>());\n\treturn writer.finish();\n}\n"]}
@@ -0,0 +1,201 @@
1
+ import { CborError, MAX_UINT32, resolveOptions, textDecoder, textEncoder, UINT32_BASE, } from "./options.js";
2
+ class CborWriter {
3
+ buffer;
4
+ offset = 0;
5
+ maxByteLength;
6
+ constructor(maxByteLength) {
7
+ this.maxByteLength = maxByteLength;
8
+ this.buffer = new Uint8Array(Math.min(256, maxByteLength));
9
+ }
10
+ writeByte(value) {
11
+ this.ensureCapacity(1);
12
+ this.buffer[this.offset] = value;
13
+ this.offset++;
14
+ }
15
+ writeBytes(bytes) {
16
+ this.ensureCapacity(bytes.byteLength);
17
+ this.buffer.set(bytes, this.offset);
18
+ this.offset += bytes.byteLength;
19
+ }
20
+ writeUint16(value) {
21
+ this.ensureCapacity(2);
22
+ this.buffer[this.offset] = value >>> 8;
23
+ this.buffer[this.offset + 1] = value;
24
+ this.offset += 2;
25
+ }
26
+ writeUint32(value) {
27
+ this.ensureCapacity(4);
28
+ this.buffer[this.offset] = value >>> 24;
29
+ this.buffer[this.offset + 1] = value >>> 16;
30
+ this.buffer[this.offset + 2] = value >>> 8;
31
+ this.buffer[this.offset + 3] = value;
32
+ this.offset += 4;
33
+ }
34
+ writeUint64(value) {
35
+ const high = Math.floor(value / UINT32_BASE);
36
+ const low = value - high * UINT32_BASE;
37
+ this.writeUint32(high);
38
+ this.writeUint32(low);
39
+ }
40
+ writeFloat64(value) {
41
+ this.ensureCapacity(9);
42
+ this.buffer[this.offset] = 0xfb;
43
+ new DataView(this.buffer.buffer).setFloat64(this.offset + 1, value, false);
44
+ this.offset += 9;
45
+ }
46
+ finish() {
47
+ return this.buffer.slice(0, this.offset);
48
+ }
49
+ ensureCapacity(additionalBytes) {
50
+ const required = this.offset + additionalBytes;
51
+ if (required > this.maxByteLength) {
52
+ throw new CborError(`CBOR byte length exceeds configured limit of ${this.maxByteLength}`);
53
+ }
54
+ if (required <= this.buffer.byteLength)
55
+ return;
56
+ let capacity = Math.max(1, this.buffer.byteLength);
57
+ while (capacity < required)
58
+ capacity = Math.min(this.maxByteLength, Math.max(required, capacity * 2));
59
+ const expanded = new Uint8Array(capacity);
60
+ expanded.set(this.buffer);
61
+ this.buffer = expanded;
62
+ }
63
+ }
64
+ function writeArgument(writer, majorType, value) {
65
+ const prefix = majorType << 5;
66
+ if (value < 24) {
67
+ writer.writeByte(prefix | value);
68
+ }
69
+ else if (value <= 0xff) {
70
+ writer.writeByte(prefix | 24);
71
+ writer.writeByte(value);
72
+ }
73
+ else if (value <= 0xffff) {
74
+ writer.writeByte(prefix | 25);
75
+ writer.writeUint16(value);
76
+ }
77
+ else if (value <= MAX_UINT32) {
78
+ writer.writeByte(prefix | 26);
79
+ writer.writeUint32(value);
80
+ }
81
+ else {
82
+ writer.writeByte(prefix | 27);
83
+ writer.writeUint64(value);
84
+ }
85
+ }
86
+ function isPlainObject(value) {
87
+ if (typeof value !== "object" || value === null)
88
+ return false;
89
+ const prototype = Object.getPrototypeOf(value);
90
+ return prototype === Object.prototype || prototype === null;
91
+ }
92
+ function encodeText(writer, value, options) {
93
+ const bytes = textEncoder.encode(value);
94
+ if (bytes.byteLength > options.maxByteLength) {
95
+ throw new CborError(`CBOR text string length exceeds configured limit of ${options.maxByteLength}`);
96
+ }
97
+ if (textDecoder.decode(bytes) !== value)
98
+ throw new CborError("CBOR text strings must contain valid Unicode scalar values");
99
+ writeArgument(writer, 3, bytes.byteLength);
100
+ writer.writeBytes(bytes);
101
+ }
102
+ function encodeValue(writer, value, options, depth, ancestors) {
103
+ if (depth > options.maxDepth)
104
+ throw new CborError(`CBOR nesting depth exceeds configured limit of ${options.maxDepth}`);
105
+ if (value === null) {
106
+ writer.writeByte(0xf6);
107
+ return;
108
+ }
109
+ if (typeof value === "boolean") {
110
+ writer.writeByte(value ? 0xf5 : 0xf4);
111
+ return;
112
+ }
113
+ if (typeof value === "number") {
114
+ if (!Number.isFinite(value))
115
+ throw new CborError("CBOR numbers must be finite");
116
+ if (Number.isInteger(value) && !Object.is(value, -0)) {
117
+ if (!Number.isSafeInteger(value))
118
+ throw new CborError("CBOR integers must be safe JavaScript integers");
119
+ if (value >= 0)
120
+ writeArgument(writer, 0, value);
121
+ else
122
+ writeArgument(writer, 1, -1 - value);
123
+ }
124
+ else {
125
+ writer.writeFloat64(value);
126
+ }
127
+ return;
128
+ }
129
+ if (typeof value === "string") {
130
+ encodeText(writer, value, options);
131
+ return;
132
+ }
133
+ if (value instanceof Uint8Array) {
134
+ if (value.byteLength > options.maxByteLength) {
135
+ throw new CborError(`CBOR byte string length exceeds configured limit of ${options.maxByteLength}`);
136
+ }
137
+ writeArgument(writer, 2, value.byteLength);
138
+ writer.writeBytes(value);
139
+ return;
140
+ }
141
+ if (Array.isArray(value)) {
142
+ if (ancestors.has(value))
143
+ throw new CborError("CBOR values must not contain cycles");
144
+ if (value.length > options.maxContainerLength) {
145
+ throw new CborError(`CBOR array length exceeds configured limit of ${options.maxContainerLength}`);
146
+ }
147
+ ancestors.add(value);
148
+ try {
149
+ writeArgument(writer, 4, value.length);
150
+ for (let index = 0; index < value.length; index++) {
151
+ if (!Object.hasOwn(value, index) || value[index] === undefined) {
152
+ throw new CborError("CBOR arrays must not contain holes or undefined values");
153
+ }
154
+ encodeValue(writer, value[index], options, depth + 1, ancestors);
155
+ }
156
+ }
157
+ finally {
158
+ ancestors.delete(value);
159
+ }
160
+ return;
161
+ }
162
+ if (isPlainObject(value)) {
163
+ if (ancestors.has(value))
164
+ throw new CborError("CBOR values must not contain cycles");
165
+ for (const symbol of Object.getOwnPropertySymbols(value)) {
166
+ if (Object.prototype.propertyIsEnumerable.call(value, symbol)) {
167
+ throw new CborError("CBOR map keys must be strings");
168
+ }
169
+ }
170
+ const entries = [];
171
+ for (const key of Object.keys(value)) {
172
+ const entryValue = value[key];
173
+ if (entryValue !== undefined)
174
+ entries.push([key, entryValue]);
175
+ }
176
+ if (entries.length > options.maxContainerLength) {
177
+ throw new CborError(`CBOR map length exceeds configured limit of ${options.maxContainerLength}`);
178
+ }
179
+ ancestors.add(value);
180
+ try {
181
+ writeArgument(writer, 5, entries.length);
182
+ for (const [key, entryValue] of entries) {
183
+ encodeText(writer, key, options);
184
+ encodeValue(writer, entryValue, options, depth + 1, ancestors);
185
+ }
186
+ }
187
+ finally {
188
+ ancestors.delete(value);
189
+ }
190
+ return;
191
+ }
192
+ throw new CborError(`Unsupported CBOR value type: ${typeof value}`);
193
+ }
194
+ /** Encodes the protocol's strict, definite-length RFC 8949 subset. */
195
+ export function encodeCbor(value, options) {
196
+ const resolved = resolveOptions(options);
197
+ const writer = new CborWriter(resolved.maxByteLength);
198
+ encodeValue(writer, value, resolved, 0, new Set());
199
+ return writer.finish();
200
+ }
201
+ //# sourceMappingURL=encoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.js","sourceRoot":"","sources":["../../src/cbor/encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tCborError,\n\ttype CborOptions,\n\tMAX_UINT32,\n\ttype ResolvedCborOptions,\n\tresolveOptions,\n\ttextDecoder,\n\ttextEncoder,\n\tUINT32_BASE,\n} from \"./options.ts\";\n\nclass CborWriter {\n\tprivate buffer: Uint8Array;\n\tprivate offset = 0;\n\tprivate readonly maxByteLength: number;\n\n\tconstructor(maxByteLength: number) {\n\t\tthis.maxByteLength = maxByteLength;\n\t\tthis.buffer = new Uint8Array(Math.min(256, maxByteLength));\n\t}\n\n\twriteByte(value: number): void {\n\t\tthis.ensureCapacity(1);\n\t\tthis.buffer[this.offset] = value;\n\t\tthis.offset++;\n\t}\n\n\twriteBytes(bytes: Uint8Array): void {\n\t\tthis.ensureCapacity(bytes.byteLength);\n\t\tthis.buffer.set(bytes, this.offset);\n\t\tthis.offset += bytes.byteLength;\n\t}\n\n\twriteUint16(value: number): void {\n\t\tthis.ensureCapacity(2);\n\t\tthis.buffer[this.offset] = value >>> 8;\n\t\tthis.buffer[this.offset + 1] = value;\n\t\tthis.offset += 2;\n\t}\n\n\twriteUint32(value: number): void {\n\t\tthis.ensureCapacity(4);\n\t\tthis.buffer[this.offset] = value >>> 24;\n\t\tthis.buffer[this.offset + 1] = value >>> 16;\n\t\tthis.buffer[this.offset + 2] = value >>> 8;\n\t\tthis.buffer[this.offset + 3] = value;\n\t\tthis.offset += 4;\n\t}\n\n\twriteUint64(value: number): void {\n\t\tconst high = Math.floor(value / UINT32_BASE);\n\t\tconst low = value - high * UINT32_BASE;\n\t\tthis.writeUint32(high);\n\t\tthis.writeUint32(low);\n\t}\n\n\twriteFloat64(value: number): void {\n\t\tthis.ensureCapacity(9);\n\t\tthis.buffer[this.offset] = 0xfb;\n\t\tnew DataView(this.buffer.buffer).setFloat64(this.offset + 1, value, false);\n\t\tthis.offset += 9;\n\t}\n\n\tfinish(): Uint8Array {\n\t\treturn this.buffer.slice(0, this.offset);\n\t}\n\n\tprivate ensureCapacity(additionalBytes: number): void {\n\t\tconst required = this.offset + additionalBytes;\n\t\tif (required > this.maxByteLength) {\n\t\t\tthrow new CborError(`CBOR byte length exceeds configured limit of ${this.maxByteLength}`);\n\t\t}\n\t\tif (required <= this.buffer.byteLength) return;\n\n\t\tlet capacity = Math.max(1, this.buffer.byteLength);\n\t\twhile (capacity < required) capacity = Math.min(this.maxByteLength, Math.max(required, capacity * 2));\n\t\tconst expanded = new Uint8Array(capacity);\n\t\texpanded.set(this.buffer);\n\t\tthis.buffer = expanded;\n\t}\n}\n\nfunction writeArgument(writer: CborWriter, majorType: number, value: number): void {\n\tconst prefix = majorType << 5;\n\tif (value < 24) {\n\t\twriter.writeByte(prefix | value);\n\t} else if (value <= 0xff) {\n\t\twriter.writeByte(prefix | 24);\n\t\twriter.writeByte(value);\n\t} else if (value <= 0xffff) {\n\t\twriter.writeByte(prefix | 25);\n\t\twriter.writeUint16(value);\n\t} else if (value <= MAX_UINT32) {\n\t\twriter.writeByte(prefix | 26);\n\t\twriter.writeUint32(value);\n\t} else {\n\t\twriter.writeByte(prefix | 27);\n\t\twriter.writeUint64(value);\n\t}\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction encodeText(writer: CborWriter, value: string, options: ResolvedCborOptions): void {\n\tconst bytes = textEncoder.encode(value);\n\tif (bytes.byteLength > options.maxByteLength) {\n\t\tthrow new CborError(`CBOR text string length exceeds configured limit of ${options.maxByteLength}`);\n\t}\n\tif (textDecoder.decode(bytes) !== value)\n\t\tthrow new CborError(\"CBOR text strings must contain valid Unicode scalar values\");\n\twriteArgument(writer, 3, bytes.byteLength);\n\twriter.writeBytes(bytes);\n}\n\nfunction encodeValue(\n\twriter: CborWriter,\n\tvalue: unknown,\n\toptions: ResolvedCborOptions,\n\tdepth: number,\n\tancestors: Set<object>,\n): void {\n\tif (depth > options.maxDepth)\n\t\tthrow new CborError(`CBOR nesting depth exceeds configured limit of ${options.maxDepth}`);\n\n\tif (value === null) {\n\t\twriter.writeByte(0xf6);\n\t\treturn;\n\t}\n\tif (typeof value === \"boolean\") {\n\t\twriter.writeByte(value ? 0xf5 : 0xf4);\n\t\treturn;\n\t}\n\tif (typeof value === \"number\") {\n\t\tif (!Number.isFinite(value)) throw new CborError(\"CBOR numbers must be finite\");\n\t\tif (Number.isInteger(value) && !Object.is(value, -0)) {\n\t\t\tif (!Number.isSafeInteger(value)) throw new CborError(\"CBOR integers must be safe JavaScript integers\");\n\t\t\tif (value >= 0) writeArgument(writer, 0, value);\n\t\t\telse writeArgument(writer, 1, -1 - value);\n\t\t} else {\n\t\t\twriter.writeFloat64(value);\n\t\t}\n\t\treturn;\n\t}\n\tif (typeof value === \"string\") {\n\t\tencodeText(writer, value, options);\n\t\treturn;\n\t}\n\tif (value instanceof Uint8Array) {\n\t\tif (value.byteLength > options.maxByteLength) {\n\t\t\tthrow new CborError(`CBOR byte string length exceeds configured limit of ${options.maxByteLength}`);\n\t\t}\n\t\twriteArgument(writer, 2, value.byteLength);\n\t\twriter.writeBytes(value);\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tif (ancestors.has(value)) throw new CborError(\"CBOR values must not contain cycles\");\n\t\tif (value.length > options.maxContainerLength) {\n\t\t\tthrow new CborError(`CBOR array length exceeds configured limit of ${options.maxContainerLength}`);\n\t\t}\n\t\tancestors.add(value);\n\t\ttry {\n\t\t\twriteArgument(writer, 4, value.length);\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tif (!Object.hasOwn(value, index) || value[index] === undefined) {\n\t\t\t\t\tthrow new CborError(\"CBOR arrays must not contain holes or undefined values\");\n\t\t\t\t}\n\t\t\t\tencodeValue(writer, value[index], options, depth + 1, ancestors);\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(value);\n\t\t}\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tif (ancestors.has(value)) throw new CborError(\"CBOR values must not contain cycles\");\n\t\tfor (const symbol of Object.getOwnPropertySymbols(value)) {\n\t\t\tif (Object.prototype.propertyIsEnumerable.call(value, symbol)) {\n\t\t\t\tthrow new CborError(\"CBOR map keys must be strings\");\n\t\t\t}\n\t\t}\n\t\tconst entries: Array<readonly [string, unknown]> = [];\n\t\tfor (const key of Object.keys(value)) {\n\t\t\tconst entryValue = value[key];\n\t\t\tif (entryValue !== undefined) entries.push([key, entryValue]);\n\t\t}\n\t\tif (entries.length > options.maxContainerLength) {\n\t\t\tthrow new CborError(`CBOR map length exceeds configured limit of ${options.maxContainerLength}`);\n\t\t}\n\t\tancestors.add(value);\n\t\ttry {\n\t\t\twriteArgument(writer, 5, entries.length);\n\t\t\tfor (const [key, entryValue] of entries) {\n\t\t\t\tencodeText(writer, key, options);\n\t\t\t\tencodeValue(writer, entryValue, options, depth + 1, ancestors);\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(value);\n\t\t}\n\t\treturn;\n\t}\n\n\tthrow new CborError(`Unsupported CBOR value type: ${typeof value}`);\n}\n\n/** Encodes the protocol's strict, definite-length RFC 8949 subset. */\nexport function encodeCbor(value: unknown, options?: CborOptions): Uint8Array {\n\tconst resolved = resolveOptions(options);\n\tconst writer = new CborWriter(resolved.maxByteLength);\n\tencodeValue(writer, value, resolved, 0, new Set<object>());\n\treturn writer.finish();\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export { decodeCbor } from "./decoder.ts";
2
+ export { encodeCbor } from "./encoder.ts";
3
+ export { CborError, type CborOptions, DEFAULT_MAX_CBOR_BYTE_LENGTH, DEFAULT_MAX_CBOR_CONTAINER_LENGTH, DEFAULT_MAX_CBOR_DEPTH, } from "./options.ts";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cbor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACN,SAAS,EACT,KAAK,WAAW,EAChB,4BAA4B,EAC5B,iCAAiC,EACjC,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["export { decodeCbor } from \"./decoder.ts\";\nexport { encodeCbor } from \"./encoder.ts\";\nexport {\n\tCborError,\n\ttype CborOptions,\n\tDEFAULT_MAX_CBOR_BYTE_LENGTH,\n\tDEFAULT_MAX_CBOR_CONTAINER_LENGTH,\n\tDEFAULT_MAX_CBOR_DEPTH,\n} from \"./options.ts\";\n"]}
@@ -0,0 +1,4 @@
1
+ export { decodeCbor } from "./decoder.js";
2
+ export { encodeCbor } from "./encoder.js";
3
+ export { CborError, DEFAULT_MAX_CBOR_BYTE_LENGTH, DEFAULT_MAX_CBOR_CONTAINER_LENGTH, DEFAULT_MAX_CBOR_DEPTH, } from "./options.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cbor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACN,SAAS,EAET,4BAA4B,EAC5B,iCAAiC,EACjC,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["export { decodeCbor } from \"./decoder.ts\";\nexport { encodeCbor } from \"./encoder.ts\";\nexport {\n\tCborError,\n\ttype CborOptions,\n\tDEFAULT_MAX_CBOR_BYTE_LENGTH,\n\tDEFAULT_MAX_CBOR_CONTAINER_LENGTH,\n\tDEFAULT_MAX_CBOR_DEPTH,\n} from \"./options.ts\";\n"]}
@@ -0,0 +1,26 @@
1
+ export declare const UINT32_BASE = 4294967296;
2
+ export declare const MAX_UINT32 = 4294967295;
3
+ /** Safe defaults for untrusted protocol payloads. */
4
+ export declare const DEFAULT_MAX_CBOR_BYTE_LENGTH: number;
5
+ export declare const DEFAULT_MAX_CBOR_CONTAINER_LENGTH = 1000000;
6
+ export declare const DEFAULT_MAX_CBOR_DEPTH = 64;
7
+ export interface CborOptions {
8
+ /** Maximum encoded input/output bytes and maximum byte/text string length. */
9
+ maxByteLength?: number;
10
+ /** Maximum number of elements in an array or entries in a map. */
11
+ maxContainerLength?: number;
12
+ /** Maximum recursive item depth. */
13
+ maxDepth?: number;
14
+ }
15
+ export interface ResolvedCborOptions {
16
+ maxByteLength: number;
17
+ maxContainerLength: number;
18
+ maxDepth: number;
19
+ }
20
+ export declare class CborError extends Error {
21
+ constructor(message: string);
22
+ }
23
+ export declare const textEncoder: import("util").TextEncoder;
24
+ export declare const textDecoder: import("util").TextDecoder;
25
+ export declare function resolveOptions(options: CborOptions | undefined): ResolvedCborOptions;
26
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/cbor/options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,aAAgB,CAAC;AACzC,eAAO,MAAM,UAAU,aAAc,CAAC;AAGtC,qDAAqD;AACrD,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAC7D,eAAO,MAAM,iCAAiC,UAAY,CAAC;AAC3D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,MAAM,WAAW,WAAW;IAC3B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACnC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AAED,eAAO,MAAM,WAAW,4BAAoB,CAAC;AAC7C,eAAO,MAAM,WAAW,4BAA6D,CAAC;AAStF,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,mBAAmB,CAUpF","sourcesContent":["export const UINT32_BASE = 0x1_0000_0000;\nexport const MAX_UINT32 = 0xffff_ffff;\nconst MAX_CONFIGURED_DEPTH = 512;\n\n/** Safe defaults for untrusted protocol payloads. */\nexport const DEFAULT_MAX_CBOR_BYTE_LENGTH = 16 * 1024 * 1024;\nexport const DEFAULT_MAX_CBOR_CONTAINER_LENGTH = 1_000_000;\nexport const DEFAULT_MAX_CBOR_DEPTH = 64;\n\nexport interface CborOptions {\n\t/** Maximum encoded input/output bytes and maximum byte/text string length. */\n\tmaxByteLength?: number;\n\t/** Maximum number of elements in an array or entries in a map. */\n\tmaxContainerLength?: number;\n\t/** Maximum recursive item depth. */\n\tmaxDepth?: number;\n}\n\nexport interface ResolvedCborOptions {\n\tmaxByteLength: number;\n\tmaxContainerLength: number;\n\tmaxDepth: number;\n}\n\nexport class CborError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CborError\";\n\t}\n}\n\nexport const textEncoder = new TextEncoder();\nexport const textDecoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\n\nfunction resolveLimit(name: string, value: number, maximum: number): number {\n\tif (!Number.isSafeInteger(value) || value < 0 || value > maximum) {\n\t\tthrow new RangeError(`${name} must be an integer between 0 and ${maximum}`);\n\t}\n\treturn value;\n}\n\nexport function resolveOptions(options: CborOptions | undefined): ResolvedCborOptions {\n\treturn {\n\t\tmaxByteLength: resolveLimit(\"maxByteLength\", options?.maxByteLength ?? DEFAULT_MAX_CBOR_BYTE_LENGTH, MAX_UINT32),\n\t\tmaxContainerLength: resolveLimit(\n\t\t\t\"maxContainerLength\",\n\t\t\toptions?.maxContainerLength ?? DEFAULT_MAX_CBOR_CONTAINER_LENGTH,\n\t\t\tMAX_UINT32,\n\t\t),\n\t\tmaxDepth: resolveLimit(\"maxDepth\", options?.maxDepth ?? DEFAULT_MAX_CBOR_DEPTH, MAX_CONFIGURED_DEPTH),\n\t};\n}\n"]}