@cbortech/cbor 0.23.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/README.md ADDED
@@ -0,0 +1,488 @@
1
+ # @cbortech/cbor
2
+
3
+ TypeScript library for converting between [CBOR](#specifications),
4
+ [CBOR-EDN](#specifications), and JavaScript values.
5
+
6
+ This package currently exposes a small public API centered on the `CBOR` facade.
7
+ Lower-level parser, encoder, and AST classes are intentionally not part of the
8
+ documented public API yet.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @cbortech/cbor
14
+ ```
15
+
16
+ ## Import
17
+
18
+ ```ts
19
+ import { CBOR } from '@cbortech/cbor';
20
+ ```
21
+
22
+ Default import is also supported:
23
+
24
+ ```ts
25
+ import CBOR from '@cbortech/cbor';
26
+ ```
27
+
28
+ ## Quick Examples
29
+
30
+ ### JavaScript to CBOR bytes
31
+
32
+ ```ts
33
+ import { CBOR } from '@cbortech/cbor';
34
+
35
+ const bytes = CBOR.encode({ hello: 'world', n: 42 });
36
+
37
+ console.log(bytes);
38
+ // Uint8Array(...)
39
+ ```
40
+
41
+ ### CBOR bytes to JavaScript
42
+
43
+ ```ts
44
+ import { CBOR } from '@cbortech/cbor';
45
+
46
+ const value = CBOR.decode(
47
+ new Uint8Array([
48
+ 0xa2, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x65, 0x77, 0x6f, 0x72, 0x6c,
49
+ 0x64, 0x61, 0x6e, 0x18, 0x2a,
50
+ ])
51
+ );
52
+
53
+ console.log(value);
54
+ // { hello: 'world', n: 42 }
55
+ ```
56
+
57
+ ### CBOR bytes to CBOR-EDN
58
+
59
+ ```ts
60
+ import { CBOR } from '@cbortech/cbor';
61
+
62
+ const text = CBOR.cborToCborEdn(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
63
+
64
+ console.log(text);
65
+ // [1,2,3]
66
+ ```
67
+
68
+ ### CBOR-EDN to CBOR bytes
69
+
70
+ ```ts
71
+ import { CBOR } from '@cbortech/cbor';
72
+
73
+ const bytes = CBOR.cborEdnToCbor('[1, 2, 3]');
74
+
75
+ console.log(bytes);
76
+ // Uint8Array([0x83, 0x01, 0x02, 0x03])
77
+ ```
78
+
79
+ ### JavaScript to CBOR-EDN
80
+
81
+ ```ts
82
+ import { CBOR } from '@cbortech/cbor';
83
+
84
+ const text = CBOR.stringify({ a: 1, b: true, c: null });
85
+
86
+ console.log(text);
87
+ // {"a":1,"b":true,"c":null}
88
+ ```
89
+
90
+ ### Pretty CBOR-EDN
91
+
92
+ ```ts
93
+ import { CBOR } from '@cbortech/cbor';
94
+
95
+ const text = CBOR.stringify({ items: [1, 2, 3], ok: true }, { indent: 2 });
96
+
97
+ console.log(text);
98
+ // {
99
+ // "items": [
100
+ // 1,
101
+ // 2,
102
+ // 3
103
+ // ],
104
+ // "ok": true
105
+ // }
106
+ ```
107
+
108
+ ### CBOR-EDN to JavaScript
109
+
110
+ ```ts
111
+ import { CBOR } from '@cbortech/cbor';
112
+
113
+ const value = CBOR.parse("[1, h'deadbeef', true, null]");
114
+
115
+ console.log(value);
116
+ // [1, Uint8Array(...), true, null]
117
+ ```
118
+
119
+ ### Normalize CBOR-EDN
120
+
121
+ ```ts
122
+ import { CBOR } from '@cbortech/cbor';
123
+
124
+ const text = CBOR.format('{ "b" : [ 1,2 ], "a" : true }', { indent: 2 });
125
+
126
+ console.log(text);
127
+ // {
128
+ // "b": [
129
+ // 1,
130
+ // 2
131
+ // ],
132
+ // "a": true
133
+ // }
134
+ ```
135
+
136
+ ### Split text strings while formatting
137
+
138
+ `textStringFormat` can split long text strings with EDN string concatenation.
139
+ It is applied when `indent` is specified.
140
+
141
+ ```ts
142
+ import { CBOR } from '@cbortech/cbor';
143
+
144
+ const text = CBOR.format('{"text": "line1\\nline2\\nline3"}', {
145
+ indent: 2,
146
+ textStringFormat: ['newline'],
147
+ });
148
+
149
+ console.log(text);
150
+ // {
151
+ // "text": "line1\n" +
152
+ // "line2\n" +
153
+ // "line3"
154
+ // }
155
+ ```
156
+
157
+ For strings that contain CBOR-EDN or JSON-like content, use `cboredn`.
158
+
159
+ ```ts
160
+ import { CBOR } from '@cbortech/cbor';
161
+
162
+ const text = CBOR.format('{"edn": "[1,2,3]"}', {
163
+ indent: 2,
164
+ textStringFormat: ['cboredn'],
165
+ });
166
+
167
+ console.log(text);
168
+ // {
169
+ // "edn": "[" +
170
+ // "1," +
171
+ // "2," +
172
+ // "3" +
173
+ // "]"
174
+ // }
175
+ ```
176
+
177
+ ## Working With The AST
178
+
179
+ `CBOR.fromCBOR()`, `CBOR.fromEDN()`, and `CBOR.fromJS()` return a CBOR item.
180
+ The concrete node classes are not documented as public API yet, but every item
181
+ supports these methods:
182
+
183
+ ```ts
184
+ import { CBOR } from '@cbortech/cbor';
185
+
186
+ const item = CBOR.fromEDN('{ "x": 1 }');
187
+
188
+ const bytes = item.toCBOR();
189
+ const text = item.toEDN();
190
+ const value = item.toJS();
191
+ ```
192
+
193
+ ### Parse to AST, then serialize
194
+
195
+ ```ts
196
+ import { CBOR } from '@cbortech/cbor';
197
+
198
+ const item = CBOR.fromEDN('[_ 1, 2, 3]');
199
+
200
+ console.log(item.toEDN());
201
+ // [_ 1,2,3]
202
+
203
+ console.log(item.toCBOR());
204
+ // Uint8Array(...)
205
+ ```
206
+
207
+ ### Decode to AST, then inspect as EDN
208
+
209
+ ```ts
210
+ import { CBOR } from '@cbortech/cbor';
211
+
212
+ const item = CBOR.fromCBOR(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
213
+
214
+ console.log(item.toEDN());
215
+ // [1,2,3]
216
+
217
+ console.log(item.toJS());
218
+ // [1, 2, 3]
219
+ ```
220
+
221
+ ## JSON-like API
222
+
223
+ `CBOR.parse()` and `CBOR.stringify()` intentionally feel similar to
224
+ `JSON.parse()` and `JSON.stringify()`.
225
+
226
+ Unlike JSON, CBOR can represent `undefined` as a value. Use `CBOR.OMIT` from a
227
+ reviver or replacer when you want to remove an object entry or map entry
228
+ explicitly, instead of producing an `undefined` value.
229
+
230
+ ### Reviver function
231
+
232
+ ```ts
233
+ import { CBOR } from '@cbortech/cbor';
234
+
235
+ const value = CBOR.parse(
236
+ '{"createdAt": "2026-05-06T00:00:00Z"}',
237
+ (key, value) => {
238
+ if (key === 'createdAt') return new Date(value);
239
+ return value;
240
+ }
241
+ );
242
+
243
+ console.log(value);
244
+ // { createdAt: 2026-05-06T00:00:00.000Z }
245
+ ```
246
+
247
+ ### Replacer function
248
+
249
+ ```ts
250
+ import { CBOR } from '@cbortech/cbor';
251
+
252
+ const text = CBOR.stringify({ id: 1, password: 'secret' }, (key, value) =>
253
+ key === 'password' ? CBOR.OMIT : value
254
+ );
255
+
256
+ console.log(text);
257
+ // {"id":1}
258
+ ```
259
+
260
+ ### Replacer key list
261
+
262
+ ```ts
263
+ import { CBOR } from '@cbortech/cbor';
264
+
265
+ const text = CBOR.stringify(
266
+ { id: 1, name: 'Alice', password: 'secret' },
267
+ ['id', 'name'],
268
+ 2
269
+ );
270
+
271
+ console.log(text);
272
+ // {
273
+ // "id": 1,
274
+ // "name": "Alice"
275
+ // }
276
+ ```
277
+
278
+ ## Default Options
279
+
280
+ Create a `CBOR` instance when you want to reuse the same options.
281
+
282
+ ```ts
283
+ import { CBOR } from '@cbortech/cbor';
284
+
285
+ const cbor = new CBOR({
286
+ extensions: [CBOR.dt_as_Date],
287
+ indent: 2,
288
+ });
289
+
290
+ const value = cbor.parse("DT'2026-05-06T00:00:00Z'");
291
+
292
+ console.log(value);
293
+ // Date(...)
294
+
295
+ console.log(cbor.stringify({ value }));
296
+ // {
297
+ // "value": DT'2026-05-06T00:00:00Z'
298
+ // }
299
+ ```
300
+
301
+ ## Dates
302
+
303
+ CBOR-EDN `dt'...'` and `DT'...'` literals are parsed by default. Add `CBOR.dt_as_Date`
304
+ when you want JavaScript `Date` objects.
305
+
306
+ ```ts
307
+ import { CBOR } from '@cbortech/cbor';
308
+
309
+ const value = CBOR.parse("DT'2026-05-06T00:00:00Z'", {
310
+ extensions: [CBOR.dt_as_Date],
311
+ });
312
+
313
+ console.log(value instanceof Date);
314
+ // true
315
+ ```
316
+
317
+ ```ts
318
+ import { CBOR } from '@cbortech/cbor';
319
+
320
+ const text = CBOR.stringify(new Date('2026-05-06T00:00:00Z'), {
321
+ extensions: [CBOR.dt_as_Date],
322
+ });
323
+
324
+ console.log(text);
325
+ // DT'2026-05-06T00:00:00Z'
326
+ ```
327
+
328
+ ## Tags
329
+
330
+ Use `CBOR.Tag` for CBOR tagged values in JavaScript.
331
+
332
+ ```ts
333
+ import { CBOR } from '@cbortech/cbor';
334
+
335
+ const tagged = CBOR.Tag.set('hello', 42n);
336
+ const text = CBOR.stringify(tagged);
337
+
338
+ console.log(text);
339
+ // 42("hello")
340
+ ```
341
+
342
+ ```ts
343
+ import { CBOR } from '@cbortech/cbor';
344
+
345
+ const value = CBOR.parse('42("hello")');
346
+
347
+ console.log(CBOR.Tag.get(value));
348
+ // 42n
349
+
350
+ console.log(CBOR.Tag.getValue(value));
351
+ // "hello"
352
+ ```
353
+
354
+ ## Simple Values
355
+
356
+ Use `CBOR.Simple` for CBOR simple values other than `false`, `true`, `null`, and
357
+ `undefined`.
358
+
359
+ ```ts
360
+ import { CBOR } from '@cbortech/cbor';
361
+
362
+ const text = CBOR.stringify(new CBOR.Simple(16));
363
+
364
+ console.log(text);
365
+ // simple(16)
366
+ ```
367
+
368
+ ```ts
369
+ import { CBOR } from '@cbortech/cbor';
370
+
371
+ const value = CBOR.parse('simple(16)');
372
+
373
+ console.log(value instanceof CBOR.Simple);
374
+ // true
375
+
376
+ console.log(value.value);
377
+ // 16
378
+ ```
379
+
380
+ ## Maps
381
+
382
+ By default, CBOR maps with text keys become plain JavaScript objects.
383
+
384
+ ```ts
385
+ import { CBOR } from '@cbortech/cbor';
386
+
387
+ const value = CBOR.parse('{"a": 1, "b": 2}');
388
+
389
+ console.log(value);
390
+ // { a: 1, b: 2 }
391
+ ```
392
+
393
+ Use `mapAs: 'entries'` when you need to preserve non-string keys or duplicate
394
+ keys.
395
+
396
+ ```ts
397
+ import { CBOR } from '@cbortech/cbor';
398
+
399
+ const entries = CBOR.parse('{1: "one", 1: "uno"}', {
400
+ mapAs: 'entries',
401
+ });
402
+
403
+ console.log(entries instanceof CBOR.MapEntries);
404
+ // true
405
+
406
+ console.log(entries);
407
+ // [[1, "one"], [1, "uno"]]
408
+ ```
409
+
410
+ `CBOR.MapEntries` can be passed back to `CBOR.stringify()` or `CBOR.encode()`.
411
+
412
+ ```ts
413
+ import { CBOR } from '@cbortech/cbor';
414
+
415
+ const entries = new CBOR.MapEntries([1, 'one'], [1, 'uno']);
416
+
417
+ console.log(CBOR.stringify(entries));
418
+ // {1:"one",1:"uno"}
419
+ ```
420
+
421
+ ## Hex Dumps
422
+
423
+ CBOR items can produce and parse annotated hex dumps.
424
+
425
+ ```ts
426
+ import { CBOR } from '@cbortech/cbor';
427
+
428
+ const item = CBOR.fromEDN('[_ 1, [2, 3]]');
429
+ const dump = item.toHexDump();
430
+
431
+ console.log(dump);
432
+ // 9F -- Start indefinite-length array
433
+ // ...
434
+ ```
435
+
436
+ ```ts
437
+ import { CBOR } from '@cbortech/cbor';
438
+
439
+ const item = CBOR.fromHexDump(`
440
+ 83 -- Array of length 3
441
+ 01 -- 1
442
+ 02 -- 2
443
+ 03 -- 3
444
+ `);
445
+
446
+ console.log(item.toEDN());
447
+ // [1,2,3]
448
+ ```
449
+
450
+ ## Public API
451
+
452
+ The documented public export is:
453
+
454
+ - `CBOR`
455
+
456
+ The `CBOR` facade also exposes:
457
+
458
+ - `CBOR.Tag`
459
+ - `CBOR.Simple`
460
+ - `CBOR.MapEntries`
461
+ - `CBOR.dt_as_Date`
462
+ - `CBOR.OMIT`
463
+
464
+ ## Specifications
465
+
466
+ This library targets:
467
+
468
+ - [CBOR, RFC 8949](https://www.rfc-editor.org/rfc/rfc8949)
469
+ - [CBOR Extended Diagnostic Notation (CBOR-EDN), draft-ietf-cbor-edn-literals-23](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/23/)
470
+
471
+ CBOR-EDN is a human-readable text notation for CBOR data. It is useful for
472
+ examples, test vectors, debugging, fixtures, and configuration-like files where
473
+ raw CBOR bytes would be hard to read.
474
+
475
+ It looks similar to JSON for ordinary arrays, maps, strings, numbers, booleans,
476
+ and null values, but it can also represent CBOR-specific features such as byte
477
+ strings, tags, simple values, indefinite-length items, non-string map keys, and
478
+ application literals like `dt'2026-05-06T00:00:00Z'`.
479
+
480
+ CBOR-EDN is a superset of JSON and JSONC, so ordinary JSON data and
481
+ commented JSON-style data can be parsed and formatted as CBOR-EDN without
482
+ special handling.
483
+
484
+ CBOR-EDN is still an Internet-Draft rather than a widely deployed RFC.
485
+
486
+ ## License
487
+
488
+ Apache-2.0