A zero-dependency library to encode and decode CBOR (RFC8949) for TypeScript. It preserves the semantics of original data as much as possible.
Supported CBOR features notable:
- Generic encoding and decoding — This is why it's lossless.
- Indefinite-length byte strings, text strings, arrays, and maps
- Preferred serialization and deterministic encoding
- Some tags defined in RFC8949
- Diagnostic notation
- Streamed decoding
- CBOR Sequences
lossless-cbor is meant to be a reference implementation of CBOR in TypeScript (i.e. a type-safe alternative of cbor-object).
There have been several libraries to work with CBOR in the world of TypeScript, but from what I've seen, all those are lossy, meaning they decode CBOR binaries immediately into bare TypeScript values. That is a lossy transformation by nature; numbers are all coerced to double-precision floats, the original order of map entries whose string keys can be interpreted as decimal natural numbers is broken, no support for maps with non-string keys, etc., and even no escape hatch against them is provided at worst.
This library, on the other hand, doesn't decode into bare values directly, and instead decode into “data items” which are objects that preserve the semantics of the original CBOR representation. For example:
import fromBytes from "https://deno.land/x/lossless_cbor/fromBytes.ts"
// integer `42` in CBOR
const majorType = 0
const additionalInformation = 24
const argument = 42
const bytes = Uint8Array.of((majorType << 5) + additionalInformation, argument)
const dataItem = await fromBytes(bytes, { allowEmpty: false })
console.log(dataItem)
/*
{
type: "int",
value: 42n,
head: {
majorType: 0,
argument: 42n,
additional: { information: 24, bytes: Blob { size: 1, type: "" } }
}
}
*/This design allows you to precisely work with CBOR data.
The modules under the ./src/ directory are also accessible under https://deno.land/x/lossless_cbor/.
DataItem is the interface between CBOR binaries and bare TypeScript values.
---
config:
theme: neutral
themeCSS: |-
span.nodeLabel, span.edgeLabel {
font-family: monospace !important;
background: transparent;
}
div.labelBkg { background: transparent; }
span.edgeLabel p {
display: inline-flex;
align-items: center;
height: 1.5lh;
padding: 0 0.75em;
border: 1px solid gray;
border-radius: 5px;
}
---
graph LR
B0((ByteSource))
B1((Uint8Array))
D((DataItem))
V0((unknown))
V1((string))
D -->|diagnose| V1
B0 -->|decode| V0
B0 -->|fromBytes| D -->|toValue| V0
V0 -->|fromValue| D -->|toBytes| B1
V0 -->|encode| B1
Only the items accessible from the default exports of published modules are meant to be public APIs and remain stable throughout minor version bumps. Named exports should be considered private and unstable. Any single release may randomly contain breaking changes to named exports, so users should avoid relying on them.