@bcts/dcbor 1.0.0-alpha.10
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 +48 -0
- package/README.md +13 -0
- package/dist/index.cjs +9151 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3107 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +3107 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +9155 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +9027 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +80 -0
- package/src/.claude-flow/metrics/agent-metrics.json +1 -0
- package/src/.claude-flow/metrics/performance.json +87 -0
- package/src/.claude-flow/metrics/task-metrics.json +10 -0
- package/src/byte-string.ts +300 -0
- package/src/cbor-codable.ts +170 -0
- package/src/cbor-tagged-codable.ts +72 -0
- package/src/cbor-tagged-decodable.ts +184 -0
- package/src/cbor-tagged-encodable.ts +138 -0
- package/src/cbor-tagged.ts +104 -0
- package/src/cbor.ts +869 -0
- package/src/conveniences.ts +840 -0
- package/src/date.ts +553 -0
- package/src/decode.ts +276 -0
- package/src/diag.ts +462 -0
- package/src/dump.ts +277 -0
- package/src/error.ts +259 -0
- package/src/exact.ts +714 -0
- package/src/float.ts +279 -0
- package/src/global.d.ts +34 -0
- package/src/globals.d.ts +0 -0
- package/src/index.ts +180 -0
- package/src/map.ts +308 -0
- package/src/prelude.ts +70 -0
- package/src/set.ts +515 -0
- package/src/simple.ts +153 -0
- package/src/stdlib.ts +55 -0
- package/src/string-util.ts +55 -0
- package/src/tag.ts +53 -0
- package/src/tags-store.ts +294 -0
- package/src/tags.ts +231 -0
- package/src/varint.ts +124 -0
- package/src/walk.ts +516 -0
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bcts/dcbor",
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Blockchain Commons Deterministic CBOR (dCBOR) for TypeScript",
|
|
6
|
+
"license": "BSD-2-Clause-Patent",
|
|
7
|
+
"author": "Leonardo Custodio <leonardo@custodio.me>",
|
|
8
|
+
"homepage": "https://bcts.dev",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/leonardocustodio/bcts",
|
|
12
|
+
"directory": "packages/dcbor"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/leonardocustodio/bcts/issues"
|
|
16
|
+
},
|
|
17
|
+
"main": "dist/index.cjs",
|
|
18
|
+
"module": "dist/index.mjs",
|
|
19
|
+
"types": "dist/index.d.mts",
|
|
20
|
+
"browser": "dist/index.iife.js",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.mts",
|
|
24
|
+
"import": "./dist/index.mjs",
|
|
25
|
+
"require": "./dist/index.cjs",
|
|
26
|
+
"default": "./dist/index.mjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"src",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsdown",
|
|
36
|
+
"dev": "tsdown --watch",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"test:cli": "vitest run tests/cli.test.ts",
|
|
40
|
+
"test:examples": "npm run build && node scripts/test-examples.js",
|
|
41
|
+
"lint": "eslint 'src/**/*.ts' 'tests/**/*.ts'",
|
|
42
|
+
"lint:fix": "eslint 'src/**/*.ts' 'tests/**/*.ts' --fix",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"clean": "rm -rf dist",
|
|
45
|
+
"docs": "typedoc",
|
|
46
|
+
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"cbor",
|
|
50
|
+
"dcbor",
|
|
51
|
+
"deterministic",
|
|
52
|
+
"blockchain-commons",
|
|
53
|
+
"encoding",
|
|
54
|
+
"serialization",
|
|
55
|
+
"codec",
|
|
56
|
+
"binary"
|
|
57
|
+
],
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@bcts/eslint": "^0.1.0",
|
|
63
|
+
"@bcts/tsconfig": "^0.1.0",
|
|
64
|
+
"@eslint/js": "^9.39.2",
|
|
65
|
+
"@types/collections": "^5.1.5",
|
|
66
|
+
"@types/node": "^25.0.3",
|
|
67
|
+
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
68
|
+
"@typescript-eslint/parser": "^8.50.1",
|
|
69
|
+
"eslint": "^9.39.2",
|
|
70
|
+
"ts-node": "^10.9.2",
|
|
71
|
+
"tsdown": "^0.18.3",
|
|
72
|
+
"typedoc": "^0.28.15",
|
|
73
|
+
"typescript": "^5.9.3",
|
|
74
|
+
"vitest": "^4.0.16"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"byte-data": "^19.0.1",
|
|
78
|
+
"collections": "^5.1.13"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"startTime": 1764550116519,
|
|
3
|
+
"sessionId": "session-1764550116519",
|
|
4
|
+
"lastActivity": 1764550116519,
|
|
5
|
+
"sessionDuration": 0,
|
|
6
|
+
"totalTasks": 1,
|
|
7
|
+
"successfulTasks": 1,
|
|
8
|
+
"failedTasks": 0,
|
|
9
|
+
"totalAgents": 0,
|
|
10
|
+
"activeAgents": 0,
|
|
11
|
+
"neuralEvents": 0,
|
|
12
|
+
"memoryMode": {
|
|
13
|
+
"reasoningbankOperations": 0,
|
|
14
|
+
"basicOperations": 0,
|
|
15
|
+
"autoModeSelections": 0,
|
|
16
|
+
"modeOverrides": 0,
|
|
17
|
+
"currentMode": "auto"
|
|
18
|
+
},
|
|
19
|
+
"operations": {
|
|
20
|
+
"store": {
|
|
21
|
+
"count": 0,
|
|
22
|
+
"totalDuration": 0,
|
|
23
|
+
"errors": 0
|
|
24
|
+
},
|
|
25
|
+
"retrieve": {
|
|
26
|
+
"count": 0,
|
|
27
|
+
"totalDuration": 0,
|
|
28
|
+
"errors": 0
|
|
29
|
+
},
|
|
30
|
+
"query": {
|
|
31
|
+
"count": 0,
|
|
32
|
+
"totalDuration": 0,
|
|
33
|
+
"errors": 0
|
|
34
|
+
},
|
|
35
|
+
"list": {
|
|
36
|
+
"count": 0,
|
|
37
|
+
"totalDuration": 0,
|
|
38
|
+
"errors": 0
|
|
39
|
+
},
|
|
40
|
+
"delete": {
|
|
41
|
+
"count": 0,
|
|
42
|
+
"totalDuration": 0,
|
|
43
|
+
"errors": 0
|
|
44
|
+
},
|
|
45
|
+
"search": {
|
|
46
|
+
"count": 0,
|
|
47
|
+
"totalDuration": 0,
|
|
48
|
+
"errors": 0
|
|
49
|
+
},
|
|
50
|
+
"init": {
|
|
51
|
+
"count": 0,
|
|
52
|
+
"totalDuration": 0,
|
|
53
|
+
"errors": 0
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"performance": {
|
|
57
|
+
"avgOperationDuration": 0,
|
|
58
|
+
"minOperationDuration": null,
|
|
59
|
+
"maxOperationDuration": null,
|
|
60
|
+
"slowOperations": 0,
|
|
61
|
+
"fastOperations": 0,
|
|
62
|
+
"totalOperationTime": 0
|
|
63
|
+
},
|
|
64
|
+
"storage": {
|
|
65
|
+
"totalEntries": 0,
|
|
66
|
+
"reasoningbankEntries": 0,
|
|
67
|
+
"basicEntries": 0,
|
|
68
|
+
"databaseSize": 0,
|
|
69
|
+
"lastBackup": null,
|
|
70
|
+
"growthRate": 0
|
|
71
|
+
},
|
|
72
|
+
"errors": {
|
|
73
|
+
"total": 0,
|
|
74
|
+
"byType": {},
|
|
75
|
+
"byOperation": {},
|
|
76
|
+
"recent": []
|
|
77
|
+
},
|
|
78
|
+
"reasoningbank": {
|
|
79
|
+
"semanticSearches": 0,
|
|
80
|
+
"sqlFallbacks": 0,
|
|
81
|
+
"embeddingGenerated": 0,
|
|
82
|
+
"consolidations": 0,
|
|
83
|
+
"avgQueryTime": 0,
|
|
84
|
+
"cacheHits": 0,
|
|
85
|
+
"cacheMisses": 0
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte string utilities for dCBOR.
|
|
3
|
+
*
|
|
4
|
+
* Represents a CBOR byte string (major type 2).
|
|
5
|
+
*
|
|
6
|
+
* `ByteString` is a wrapper around a byte array, optimized for use in CBOR
|
|
7
|
+
* encoding and decoding operations. It provides a richer API for working with
|
|
8
|
+
* byte data in the context of CBOR compared to using raw `Uint8Array` values.
|
|
9
|
+
*
|
|
10
|
+
* In dCBOR, byte strings follow the general deterministic encoding rules:
|
|
11
|
+
* - They must use definite-length encoding
|
|
12
|
+
* - Their length must be encoded in the shortest possible form
|
|
13
|
+
*
|
|
14
|
+
* @module byte-string
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type Cbor, MajorType, cbor as toCbor } from "./cbor";
|
|
18
|
+
import { CborError } from "./error";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents a CBOR byte string (major type 2).
|
|
22
|
+
*
|
|
23
|
+
* Use Cases:
|
|
24
|
+
* - Binary data such as images, audio, or other non-text content
|
|
25
|
+
* - Cryptographic values like hashes, signatures, and public keys
|
|
26
|
+
* - Embedded CBOR (wrapped with tag 24)
|
|
27
|
+
* - Other serialized data formats embedded in CBOR
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* // Creating a byte string from various sources
|
|
32
|
+
* const bytes1 = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
33
|
+
* const bytes2 = ByteString.from([5, 6, 7, 8]);
|
|
34
|
+
* const bytes3 = ByteString.from(new Uint8Array([9, 10, 11, 12]));
|
|
35
|
+
*
|
|
36
|
+
* // Converting to and from CBOR
|
|
37
|
+
* const cborValue = bytes1.toCbor();
|
|
38
|
+
*
|
|
39
|
+
* // ByteString provides Uint8Array-like operations
|
|
40
|
+
* const bytes = new ByteString(new Uint8Array([1, 2]));
|
|
41
|
+
* bytes.extend(new Uint8Array([3, 4]));
|
|
42
|
+
* assert(bytes.len() === 4);
|
|
43
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4]));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class ByteString {
|
|
47
|
+
#data: Uint8Array;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a new `ByteString` from a Uint8Array or array of bytes.
|
|
51
|
+
*
|
|
52
|
+
* @param data - The byte data
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* // From a Uint8Array
|
|
57
|
+
* const bytes1 = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
58
|
+
*
|
|
59
|
+
* // From a number array
|
|
60
|
+
* const bytes2 = new ByteString(new Uint8Array([5, 6, 7, 8]));
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
constructor(data: Uint8Array | number[]) {
|
|
64
|
+
if (Array.isArray(data)) {
|
|
65
|
+
this.#data = new Uint8Array(data);
|
|
66
|
+
} else {
|
|
67
|
+
this.#data = new Uint8Array(data);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a new `ByteString` from various input types.
|
|
73
|
+
*
|
|
74
|
+
* @param data - Uint8Array, number array, or string
|
|
75
|
+
* @returns New ByteString instance
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const bytes1 = ByteString.from([1, 2, 3, 4]);
|
|
80
|
+
* const bytes2 = ByteString.from(new Uint8Array([5, 6, 7, 8]));
|
|
81
|
+
* const bytes3 = ByteString.from("hello");
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
static from(data: Uint8Array | number[] | string): ByteString {
|
|
85
|
+
if (typeof data === "string") {
|
|
86
|
+
return new ByteString(new TextEncoder().encode(data));
|
|
87
|
+
}
|
|
88
|
+
return new ByteString(data);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns a reference to the underlying byte data.
|
|
93
|
+
*
|
|
94
|
+
* @returns The raw bytes
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
99
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4]));
|
|
100
|
+
*
|
|
101
|
+
* // You can use standard slice operations on the result
|
|
102
|
+
* assert.deepEqual(bytes.data().slice(1, 3), new Uint8Array([2, 3]));
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
data(): Uint8Array {
|
|
106
|
+
return this.#data;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the length of the byte string in bytes.
|
|
111
|
+
*
|
|
112
|
+
* @returns Number of bytes
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const empty = new ByteString(new Uint8Array([]));
|
|
117
|
+
* assert(empty.len() === 0);
|
|
118
|
+
*
|
|
119
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
120
|
+
* assert(bytes.len() === 4);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
len(): number {
|
|
124
|
+
return this.#data.length;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Returns `true` if the byte string contains no bytes.
|
|
129
|
+
*
|
|
130
|
+
* @returns true if empty
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const empty = new ByteString(new Uint8Array([]));
|
|
135
|
+
* assert(empty.isEmpty());
|
|
136
|
+
*
|
|
137
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
138
|
+
* assert(!bytes.isEmpty());
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
isEmpty(): boolean {
|
|
142
|
+
return this.#data.length === 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Extends the byte string with additional bytes.
|
|
147
|
+
*
|
|
148
|
+
* @param other - Bytes to append
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const bytes = new ByteString(new Uint8Array([1, 2]));
|
|
153
|
+
* bytes.extend(new Uint8Array([3, 4]));
|
|
154
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4]));
|
|
155
|
+
*
|
|
156
|
+
* // You can extend with different types
|
|
157
|
+
* bytes.extend([5, 6]);
|
|
158
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4, 5, 6]));
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
extend(other: Uint8Array | number[]): void {
|
|
162
|
+
const otherArray = Array.isArray(other) ? new Uint8Array(other) : other;
|
|
163
|
+
const newData = new Uint8Array(this.#data.length + otherArray.length);
|
|
164
|
+
newData.set(this.#data, 0);
|
|
165
|
+
newData.set(otherArray, this.#data.length);
|
|
166
|
+
this.#data = newData;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Creates a new Uint8Array containing a copy of the byte string's data.
|
|
171
|
+
*
|
|
172
|
+
* @returns Copy of the data
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
177
|
+
* const arr = bytes.toUint8Array();
|
|
178
|
+
* assert.deepEqual(arr, new Uint8Array([1, 2, 3, 4]));
|
|
179
|
+
*
|
|
180
|
+
* // The returned array is a clone, so you can modify it independently
|
|
181
|
+
* const arr2 = bytes.toUint8Array();
|
|
182
|
+
* arr2[0] = 99;
|
|
183
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4])); // original unchanged
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
toUint8Array(): Uint8Array {
|
|
187
|
+
return new Uint8Array(this.#data);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Returns an iterator over the bytes in the byte string.
|
|
192
|
+
*
|
|
193
|
+
* @returns Iterator yielding each byte
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3]));
|
|
198
|
+
* const iter = bytes.iter();
|
|
199
|
+
*
|
|
200
|
+
* assert(iter.next().value === 1);
|
|
201
|
+
* assert(iter.next().value === 2);
|
|
202
|
+
* assert(iter.next().value === 3);
|
|
203
|
+
* assert(iter.next().done);
|
|
204
|
+
*
|
|
205
|
+
* // You can also use for loops
|
|
206
|
+
* let sum = 0;
|
|
207
|
+
* for (const byte of bytes) {
|
|
208
|
+
* sum += byte;
|
|
209
|
+
* }
|
|
210
|
+
* assert(sum === 6);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
iter(): Iterator<number> {
|
|
214
|
+
return this.#data.values();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Makes ByteString iterable.
|
|
219
|
+
*/
|
|
220
|
+
[Symbol.iterator](): Iterator<number> {
|
|
221
|
+
return this.iter();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Converts the ByteString to a CBOR value.
|
|
226
|
+
*
|
|
227
|
+
* @returns CBOR byte string
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const bytes = new ByteString(new Uint8Array([1, 2, 3, 4]));
|
|
232
|
+
* const cborValue = bytes.toCbor();
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
toCbor(): Cbor {
|
|
236
|
+
return toCbor(this.#data);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Attempts to convert a CBOR value into a ByteString.
|
|
241
|
+
*
|
|
242
|
+
* @param cbor - CBOR value
|
|
243
|
+
* @returns ByteString if successful
|
|
244
|
+
* @throws Error if the CBOR value is not a byte string
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* const cborValue = toCbor(new Uint8Array([1, 2, 3, 4]));
|
|
249
|
+
* const bytes = ByteString.fromCbor(cborValue);
|
|
250
|
+
* assert.deepEqual(bytes.data(), new Uint8Array([1, 2, 3, 4]));
|
|
251
|
+
*
|
|
252
|
+
* // Converting from a different CBOR type throws
|
|
253
|
+
* const cborInt = toCbor(42);
|
|
254
|
+
* try {
|
|
255
|
+
* ByteString.fromCbor(cborInt); // throws
|
|
256
|
+
* } catch(e) {
|
|
257
|
+
* // Error: Wrong type
|
|
258
|
+
* }
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
static fromCbor(cbor: Cbor): ByteString {
|
|
262
|
+
if (cbor.type !== MajorType.ByteString) {
|
|
263
|
+
throw new CborError({ type: "WrongType" });
|
|
264
|
+
}
|
|
265
|
+
return new ByteString(cbor.value);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Get element at index.
|
|
270
|
+
*
|
|
271
|
+
* @param index - Index to access
|
|
272
|
+
* @returns Byte at index or undefined
|
|
273
|
+
*/
|
|
274
|
+
at(index: number): number | undefined {
|
|
275
|
+
return this.#data[index];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Equality comparison.
|
|
280
|
+
*
|
|
281
|
+
* @param other - ByteString to compare with
|
|
282
|
+
* @returns true if equal
|
|
283
|
+
*/
|
|
284
|
+
equals(other: ByteString): boolean {
|
|
285
|
+
if (this.#data.length !== other.#data.length) return false;
|
|
286
|
+
for (let i = 0; i < this.#data.length; i++) {
|
|
287
|
+
if (this.#data[i] !== other.#data[i]) return false;
|
|
288
|
+
}
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Clone this ByteString.
|
|
294
|
+
*
|
|
295
|
+
* @returns New ByteString with copied data
|
|
296
|
+
*/
|
|
297
|
+
clone(): ByteString {
|
|
298
|
+
return new ByteString(this.toUint8Array());
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBOR Encoding and Decoding Interfaces.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces provide functionality for converting between TypeScript types and
|
|
5
|
+
* CBOR data. They form the foundation of the dCBOR serialization
|
|
6
|
+
* infrastructure.
|
|
7
|
+
*
|
|
8
|
+
* The main interfaces are:
|
|
9
|
+
*
|
|
10
|
+
* - `CborEncodable`: For types that can be encoded to CBOR
|
|
11
|
+
* - `CborDecodable`: For types that can be decoded from CBOR
|
|
12
|
+
* - `CborCodable`: For types that can do both (a combination of the above)
|
|
13
|
+
*
|
|
14
|
+
* These interfaces allow for ergonomic conversions using TypeScript's type system and
|
|
15
|
+
* enable seamless integration with dCBOR's deterministic encoding rules.
|
|
16
|
+
*
|
|
17
|
+
* @module cbor-codable
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { Cbor } from "./cbor";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Interface for types that can be encoded to CBOR.
|
|
24
|
+
*
|
|
25
|
+
* This interface provides convenient methods for converting
|
|
26
|
+
* instances into CBOR objects and binary data.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // Custom type that can convert to CBOR
|
|
31
|
+
* class Person implements CborEncodable {
|
|
32
|
+
* constructor (public name: string, public age: number) {}
|
|
33
|
+
*
|
|
34
|
+
* toCbor(): Cbor {
|
|
35
|
+
* const map = new CborMap();
|
|
36
|
+
* map.set(cbor('name'), cbor(this.name));
|
|
37
|
+
* map.set(cbor('age'), cbor(this.age));
|
|
38
|
+
* return cbor(map);
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* toCborData(): Uint8Array {
|
|
42
|
+
* return cborData(this.toCbor());
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* // Use the interface
|
|
47
|
+
* const person = new Person('Alice', 30);
|
|
48
|
+
*
|
|
49
|
+
* // Convert to CBOR
|
|
50
|
+
* const cborValue = person.toCbor();
|
|
51
|
+
*
|
|
52
|
+
* // Convert directly to binary CBOR data
|
|
53
|
+
* const data = person.toCborData();
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export interface CborEncodable {
|
|
57
|
+
/**
|
|
58
|
+
* Converts this value to a CBOR object.
|
|
59
|
+
*
|
|
60
|
+
* @returns CBOR representation
|
|
61
|
+
*/
|
|
62
|
+
toCbor(): Cbor;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Converts this value directly to binary CBOR data.
|
|
66
|
+
*
|
|
67
|
+
* This is a shorthand for `cborData(this.toCbor())`.
|
|
68
|
+
*
|
|
69
|
+
* @returns Binary CBOR data
|
|
70
|
+
*/
|
|
71
|
+
toCborData(): Uint8Array;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Interface for types that can be decoded from CBOR.
|
|
76
|
+
*
|
|
77
|
+
* This interface serves as a marker to indicate that a type
|
|
78
|
+
* supports being created from CBOR data.
|
|
79
|
+
*
|
|
80
|
+
* @typeParam T - The type being decoded
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // Custom type that can be decoded from CBOR
|
|
85
|
+
* class Person implements CborDecodable<Person> {
|
|
86
|
+
* constructor(public name: string = '', public age: number = 0) {}
|
|
87
|
+
*
|
|
88
|
+
* static fromCbor(cbor: Cbor): Person {
|
|
89
|
+
* if (cbor.type !== MajorType.Map) {
|
|
90
|
+
* throw new Error('Expected a CBOR map');
|
|
91
|
+
* }
|
|
92
|
+
* const map = cbor.value as CborMap;
|
|
93
|
+
* const name = extractCbor(map.get(cbor('name'))!) as string;
|
|
94
|
+
* const age = extractCbor(map.get(cbor('age'))!) as number;
|
|
95
|
+
* return new Person(name, age);
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* tryFromCbor(cbor: Cbor): Person {
|
|
99
|
+
* return Person.fromCbor(cbor);
|
|
100
|
+
* }
|
|
101
|
+
* }
|
|
102
|
+
*
|
|
103
|
+
* // Parse from CBOR
|
|
104
|
+
* const cborMap = ...; // some CBOR map
|
|
105
|
+
* const person = Person.fromCbor(cborMap);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export interface CborDecodable<T> {
|
|
109
|
+
/**
|
|
110
|
+
* Try to create an instance from a CBOR value.
|
|
111
|
+
*
|
|
112
|
+
* @param cbor - CBOR value to decode
|
|
113
|
+
* @returns Decoded instance
|
|
114
|
+
* @throws Error if decoding fails
|
|
115
|
+
*/
|
|
116
|
+
tryFromCbor(cbor: Cbor): T;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Interface for types that can be both encoded to and decoded from CBOR.
|
|
121
|
+
*
|
|
122
|
+
* This interface is a convenience marker for types that implement both
|
|
123
|
+
* `CborEncodable` and `CborDecodable`. It serves to indicate full CBOR
|
|
124
|
+
* serialization support.
|
|
125
|
+
*
|
|
126
|
+
* @typeParam T - The type being encoded/decoded
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* // Custom type that implements both conversion directions
|
|
131
|
+
* class Person implements CborCodable<Person> {
|
|
132
|
+
* constructor(public name: string = '', public age: number = 0) {}
|
|
133
|
+
*
|
|
134
|
+
* // Implement encoding to CBOR
|
|
135
|
+
* toCbor(): Cbor {
|
|
136
|
+
* const map = new CborMap();
|
|
137
|
+
* map.set(cbor('name'), cbor(this.name));
|
|
138
|
+
* map.set(cbor('age'), cbor(this.age));
|
|
139
|
+
* return cbor(map);
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* toCborData(): Uint8Array {
|
|
143
|
+
* return cborData(this.toCbor());
|
|
144
|
+
* }
|
|
145
|
+
*
|
|
146
|
+
* // Implement decoding from CBOR
|
|
147
|
+
* static fromCbor(cbor: Cbor): Person {
|
|
148
|
+
* if (cbor.type !== MajorType.Map) {
|
|
149
|
+
* throw new Error('Expected a CBOR map');
|
|
150
|
+
* }
|
|
151
|
+
* const map = cbor.value as CborMap;
|
|
152
|
+
* const name = extractCbor(map.get(cbor('name'))!) as string;
|
|
153
|
+
* const age = extractCbor(map.get(cbor('age'))!) as number;
|
|
154
|
+
* return new Person(name, age);
|
|
155
|
+
* }
|
|
156
|
+
*
|
|
157
|
+
* tryFromCbor(cbor: Cbor): Person {
|
|
158
|
+
* return Person.fromCbor(cbor);
|
|
159
|
+
* }
|
|
160
|
+
* }
|
|
161
|
+
*
|
|
162
|
+
* // Person now implements CborCodable
|
|
163
|
+
* const person = new Person('Alice', 30);
|
|
164
|
+
* const cborValue = person.toCbor(); // Using CborEncodable
|
|
165
|
+
*
|
|
166
|
+
* // Create a round-trip copy
|
|
167
|
+
* const personCopy = Person.fromCbor(cborValue); // Using CborDecodable
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export interface CborCodable<T> extends CborEncodable, CborDecodable<T> {}
|