@cbortech/cbor
v0.25.9
Published
Convert between CBOR, CDN (CBOR-EDN), and JavaScript values
Downloads
1,446
Maintainers
Readme
@cbortech/cbor
TypeScript library for converting between CBOR, CDN (CBOR-EDN), and JavaScript values.
A live playground is available at https://cbor.tech/cbor/.
This package exposes the CBOR facade plus a separate AST entrypoint for the
CBOR node classes needed by extensions. Lower-level parser and encoder internals
are not part of the documented public API.
Install
npm install @cbortech/cborImport
import { CBOR } from '@cbortech/cbor';Default import is also supported:
import CBOR from '@cbortech/cbor';Quick Examples
JavaScript to CBOR bytes
import { CBOR } from '@cbortech/cbor';
const bytes = CBOR.encode({ hello: 'world', n: 42 });
console.log(bytes);
// Uint8Array(...)CBOR bytes to JavaScript
import { CBOR } from '@cbortech/cbor';
const value = CBOR.decode(
new Uint8Array([
0xa2, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x65, 0x77, 0x6f, 0x72, 0x6c,
0x64, 0x61, 0x6e, 0x18, 0x2a,
])
);
console.log(value);
// { hello: 'world', n: 42 }CBOR Sequence to JavaScript values
decodeSeq reads concatenated CBOR items as a CBOR Sequence and yields each item as a JavaScript value.
import { CBOR } from '@cbortech/cbor';
const a = CBOR.encode({ id: 1 });
const b = CBOR.encode({ id: 2 });
const seq = new Uint8Array([...a, ...b]);
const values = [...CBOR.decodeSeq(seq)];
// [{ id: 1 }, { id: 2 }]CBOR bytes to CDN
decompile converts CBOR binary data to a CDN text string. It handles CBOR Sequences automatically: multiple concatenated items produce newline-separated CDN output.
import { CBOR } from '@cbortech/cbor';
// Single item
const text = CBOR.decompile(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
console.log(text);
// [1,2,3]
// CBOR Sequence — each item on its own line
const seq = new Uint8Array([...CBOR.encode(1), ...CBOR.encode('two')]);
console.log(CBOR.decompile(seq));
// 1
// "two"CDN to CBOR bytes
compile converts a CDN text string to CBOR binary data. Multi-item CDN Sequences automatically produce a CBOR Sequence (RFC 8742): concatenated items.
import { CBOR } from '@cbortech/cbor';
// Single item
const bytes = CBOR.compile('[1, 2, 3]');
console.log(bytes);
// Uint8Array([0x83, 0x01, 0x02, 0x03])
// CDN Sequence — output is a CBOR Sequence
const seq = CBOR.compile('{"id":1}\n{"id":2}');
console.log([...CBOR.decodeSeq(seq)]);
// [{ id: 1 }, { id: 2 }]CBOR bytes to hex dump
toHex converts CBOR binary data to an annotated hex dump string. CBOR Sequences are handled automatically: each item produces its own dump, separated by newlines.
import { CBOR } from '@cbortech/cbor';
const bytes = CBOR.encode([1, 2, 3]);
console.log(CBOR.toHex(bytes));
// 83 -- Array of length 3
// 01 -- 1
// 02 -- 2
// 03 -- 3Hex dump to CBOR bytes
fromHex parses an annotated hex dump back to CBOR binary data. Multi-item dumps produce a CBOR Sequence (RFC 8742): concatenated items.
import { CBOR } from '@cbortech/cbor';
const bytes = CBOR.fromHex(`
83 -- Array of length 3
01 -- 1
02 -- 2
03 -- 3
`);
console.log([...CBOR.decodeSeq(bytes)]);
// [[1, 2, 3]]JavaScript to CDN
import { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify({ a: 1, b: true, c: null });
console.log(text);
// {"a":1,"b":true,"c":null}Pretty CDN
import { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify({ items: [1, 2, 3], ok: true }, { indent: 2 });
console.log(text);
// {
// "items": [
// 1,
// 2,
// 3
// ],
// "ok": true
// }CDN to JavaScript
import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse("[1, h'deadbeef', true, null]");
console.log(value);
// [1, Uint8Array(...), true, null]CDN Sequence to JavaScript values
parseSeq parses multiple CDN items separated by whitespace, commas, or comments, and also accepts JSONL / NDJSON input.
import { CBOR } from '@cbortech/cbor';
const values = [...CBOR.parseSeq('1 "two" [3]')];
// [1, 'two', [3]]
const jsonl = '{"id":1}\n{"id":2}\n{"id":3}';
const rows = [...CBOR.parseSeq(jsonl)];
// [{ id: 1 }, { id: 2 }, { id: 3 }]Normalize CDN
import { CBOR } from '@cbortech/cbor';
const text = CBOR.format('{ "b" : [ 1,2 ], "a" : true }', { indent: 2 });
console.log(text);
// {
// "b": [
// 1,
// 2
// ],
// "a": true
// }Split text strings while formatting
textStringFormat can split long text strings with CDN string concatenation.
It is applied when indent is specified.
import { CBOR } from '@cbortech/cbor';
const text = CBOR.format('{"text": "line1\\nline2\\nline3"}', {
indent: 2,
textStringFormat: ['newline'],
});
console.log(text);
// {
// "text": "line1\n" +
// "line2\n" +
// "line3"
// }For strings that contain CDN or JSON-like content, use cdn.
import { CBOR } from '@cbortech/cbor';
const text = CBOR.format('{"cdn": "[1,2,3]"}', {
indent: 2,
textStringFormat: ['cdn'],
});
console.log(text);
// {
// "cdn": "[" +
// "1," +
// "2," +
// "3" +
// "]"
// }Working With The AST
CBOR.fromCBOR(), CBOR.fromCDN(), and CBOR.fromJS() return a CBOR item.
Concrete node classes such as CborTextString, CborByteString, CborArray,
and CborTag are exported from @cbortech/cbor/ast for extensions. Every item
supports these methods:
import { CBOR } from '@cbortech/cbor';
import { CborItem } from '@cbortech/cbor/ast';
const item = CBOR.fromCDN('{ "x": 1 }');
item satisfies CborItem;
const bytes = item.toCBOR();
const text = item.toCDN();
const value = item.toJS();Parse to AST, then serialize
import { CBOR } from '@cbortech/cbor';
const item = CBOR.fromCDN('[_ 1, 2, 3]');
console.log(item.toCDN());
// [_ 1,2,3]
console.log(item.toCBOR());
// Uint8Array(...)Decode to AST, then inspect as CDN
import { CBOR } from '@cbortech/cbor';
const item = CBOR.fromCBOR(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
console.log(item.toCDN());
// [1,2,3]
console.log(item.toJS());
// [1, 2, 3]JSON-like API
CBOR.parse() and CBOR.stringify() intentionally feel similar to
JSON.parse() and JSON.stringify().
Unlike JSON, CBOR can represent undefined as a value. Use CBOR.OMIT from a
reviver or replacer when you want to remove an object entry or map entry
explicitly, instead of producing an undefined value.
Reviver function
import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse(
'{"createdAt": "2026-05-06T00:00:00Z"}',
(key, value) => {
if (key === 'createdAt') return new Date(value);
return value;
}
);
console.log(value);
// { createdAt: 2026-05-06T00:00:00.000Z }Replacer function
import { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify({ id: 1, password: 'secret' }, (key, value) =>
key === 'password' ? CBOR.OMIT : value
);
console.log(text);
// {"id":1}Replacer key list
import { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify(
{ id: 1, name: 'Alice', password: 'secret' },
['id', 'name'],
2
);
console.log(text);
// {
// "id": 1,
// "name": "Alice"
// }Default Options
Create a CBOR instance when you want to reuse the same options.
import { CBOR } from '@cbortech/cbor';
const cbor = new CBOR({
extensions: [CBOR.dt_as_Date],
indent: 2,
});
const value = cbor.parse("DT'2026-05-06T00:00:00Z'");
console.log(value);
// Date(...)
console.log(cbor.stringify({ value }));
// {
// "value": DT'2026-05-06T00:00:00Z'
// }Dates
CDN dt'...' and DT'...' literals are parsed by default. Add CBOR.dt_as_Date
when you want JavaScript Date objects.
import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse("DT'2026-05-06T00:00:00Z'", {
extensions: [CBOR.dt_as_Date],
});
console.log(value instanceof Date);
// trueimport { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify(new Date('2026-05-06T00:00:00Z'), {
extensions: [CBOR.dt_as_Date],
});
console.log(text);
// DT'2026-05-06T00:00:00Z'Optional Extensions
This package includes several bundled extensions that are not enabled by
default. Import what you need and pass it through the extensions option.
b32 / h32
Byte-string literals using RFC 4648 Base32 encoding. These prefixes are described in §8 of RFC 8949 and also mentioned in draft-ietf-cbor-edn-literals.
b32— §6 Base32 (A–Z 2–7alphabet)h32— §7 Base32Hex (0–9 A–Valphabet)
import { CBOR, b32, h32 } from '@cbortech/cbor';
const v1 = CBOR.fromCDN("b32'AEBAGBA'", { extensions: [b32] });
console.log(v1.toCDN({ appStrings: false }));
// h'01020304'
const v2 = CBOR.fromCDN("h32'00P00'", { extensions: [h32] });
console.log(v2.toCDN({ appStrings: false }));
// h'003200'float
Interprets a hex bit-pattern as an IEEE 754 floating-point value. This extension is described in draft-bormann-cbor-edn-app-ext and also used in cbor-test-vectors.
import { CBOR, float } from '@cbortech/cbor';
const v = CBOR.fromCDN("float'7e00'", { extensions: [float] });
console.log(v.toCDN({ appStrings: false }));
// NaN
// Interpret bytes as float bits
const v2 = CBOR.fromCDN("float<<h'3f800000'>>", { extensions: [float] });
console.log(v2.toCDN({ appStrings: false }));
// 1.0_2same
same<<expr, expr, ...>> verifies that every item in the sequence encodes to
identical CBOR bytes and returns the first item. This extension is described in
draft-bormann-cbor-edn-app-ext.
import { CBOR, same } from '@cbortech/cbor';
const v = CBOR.fromCDN("same<<h'0102', h'0102'>>", { extensions: [same] });
console.log(v.toCDN({ appStrings: false }));
// h'0102'
// A single-item sequence always passes
const v2 = CBOR.fromCDN('same<<42>>', { extensions: [same] });
console.log(v2.toCDN({ appStrings: false }));
// 42Additional application extensions are published as separate packages. Install
the ones you need and pass them through the extensions option.
hash
hash is an application extension defined in §3.3 of
draft-ietf-cbor-edn-literals.
It represents cryptographic hash values in the form hash'algorithm:value'.
Because it requires an external cryptographic library, it is provided separately
as @cbortech/hash-extension.
npm install @cbortech/hash-extensionimport { CBOR } from '@cbortech/cbor';
import { hash } from '@cbortech/hash-extension';
const cbor = new CBOR({ extensions: [hash] });
const digest = cbor.parse(
"hash'sha-256:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='"
);
// Uint8Array(32) [227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200,
// 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76,
// 164, 149, 153, 27, 120, 82, 184, 85]uuid
uuid is a library-specific application extension, provided separately as
@cbortech/uuid-extension.
npm install @cbortech/uuid-extensionimport { CBOR } from '@cbortech/cbor';
import { uuid } from '@cbortech/uuid-extension';
const cbor = new CBOR({ extensions: [uuid] });
const id = cbor.parse("uuid'550e8400-e29b-41d4-a716-446655440000'");
// Uint8Array(16) [85, 14, 132, 0, 226, 155, 65, 212, 167, 22, 68, 102, 85, 68, 0, 0]Tags
Use CBOR.Tag for CBOR tagged values in JavaScript.
import { CBOR } from '@cbortech/cbor';
const tagged = CBOR.Tag.set('hello', 42n);
const text = CBOR.stringify(tagged);
console.log(text);
// 42("hello")import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse('42("hello")');
console.log(CBOR.Tag.get(value));
// 42n
console.log(CBOR.Tag.getValue(value));
// "hello"Use stripTags: true when you only need the tagged content as a plain
JavaScript value.
import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse('42("hello")', { stripTags: true });
console.log(value);
// "hello"Simple Values
Use CBOR.Simple for CBOR simple values other than false, true, null, and
undefined.
import { CBOR } from '@cbortech/cbor';
const text = CBOR.stringify(new CBOR.Simple(16));
console.log(text);
// simple(16)import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse('simple(16)');
console.log(value instanceof CBOR.Simple);
// true
console.log(value.value);
// 16Maps
By default, CBOR maps with text keys become plain JavaScript objects.
import { CBOR } from '@cbortech/cbor';
const value = CBOR.parse('{"a": 1, "b": 2}');
console.log(value);
// { a: 1, b: 2 }Use mapAs: 'entries' when you need to preserve non-string keys or duplicate
keys.
import { CBOR } from '@cbortech/cbor';
const entries = CBOR.parse('{1: "one", 1: "uno"}', {
mapAs: 'entries',
});
console.log(entries instanceof CBOR.MapEntries);
// true
console.log(entries);
// [[1, "one"], [1, "uno"]]CBOR.MapEntries can be passed back to CBOR.stringify() or CBOR.encode().
import { CBOR } from '@cbortech/cbor';
const entries = new CBOR.MapEntries([1, 'one'], [1, 'uno']);
console.log(CBOR.stringify(entries));
// {1:"one",1:"uno"}Hex Dumps
CBOR.toHex() and CBOR.fromHex() are the shortcut entry points (see Quick Examples).
For full AST access — byte ranges, re-encoding, selective inspection — use item.toHexDump() and CBOR.fromHexDump() directly:
import { CBOR } from '@cbortech/cbor';
const item = CBOR.fromCDN('[_ 1, [2, 3]]');
const dump = item.toHexDump();
console.log(dump);
// 9F -- Start indefinite-length array
// ...import { CBOR } from '@cbortech/cbor';
const item = CBOR.fromHexDump(`
83 -- Array of length 3
01 -- 1
02 -- 2
03 -- 3
`);
console.log(item.toCDN());
// [1,2,3]Tokenization
The @cbortech/cbor/cdn subpath exposes the same lexer the parser uses, for
tooling such as syntax highlighters that must stay in exact agreement with
parsing behavior:
import { tokenize, tokenizeLenient } from '@cbortech/cbor/cdn';
const { tokens, comments } = tokenize('[1, "ab"] # note');
// tokens: [{ type: 'LBRACKET', offset: 0, endOffset: 1, ... }, ...]
const lenient = tokenizeLenient('[1, "ab');
// Never throws: clean tokens, then one ERROR token covering the
// unscannable tail, plus the failure in lenient.error.Syntax errors thrown by fromCDN/parse/tokenize are CdnSyntaxError
instances (a SyntaxError subclass, also exported from the main entry) and
carry offset, line, column, and — where known — endOffset.
Public API
The documented public exports are:
CBORCdnSyntaxError
The CBOR facade also exposes:
CBOR.TagCBOR.SimpleCBOR.MapEntriesCBOR.dt_as_DateCBOR.OMIT
Lower-level CDN tokenization lives in @cbortech/cbor/cdn
(tokenize, tokenizeLenient, Token, TokenType, EdnComment),
and AST node classes in @cbortech/cbor/ast.
Specifications
This library targets:
CDN is a human-readable text notation for CBOR data. It is useful for examples, test vectors, debugging, fixtures, and configuration-like files where raw CBOR bytes would be hard to read.
It looks similar to JSON for ordinary arrays, maps, strings, numbers, booleans,
and null values, but it can also represent CBOR-specific features such as byte
strings, tags, simple values, indefinite-length items, non-string map keys, and
application literals like dt'2026-05-06T00:00:00Z'.
CDN is a superset of JSON and JSONC, so ordinary JSON data and commented JSON-style data can be parsed and formatted as CDN without special handling.
CDN is still an Internet-Draft rather than a widely deployed RFC.
License
Apache-2.0
