@dfinity/cbor
Version:
A small implementation of Concise Binary Object Representation (CBOR) in pure JavaScript.
309 lines (212 loc) • 9.24 kB
Markdown
# CBOR encoder/decoder
[](https://www.npmjs.com/package/@dfinity/cbor)

[](https://github.com/dfinity/cbor-js/actions/workflows/test.yml)
[](https://github.com/dfinity/cbor-js/actions/workflows/lint.yml)
A small implementation of Concise Binary Object Representation (CBOR) in pure JavaScript.
> Note: this package is not 100% compatible with the [CBOR specification](https://www.rfc-editor.org/rfc/rfc8949.html). See the [Not implemented](#not-implemented) section for more details.
## Installation
Using `npm`:
```bash
npm install @dfinity/cbor
```
Using `pnpm`:
```bash
pnpm add @dfinity/cbor
```
Using `yarn`:
```bash
yarn add @dfinity/cbor
```
## Usage
Simple:
```ts
import { encode, decode } from '@dfinity/cbor';
const value = true;
const encoded = encode(value); // returns `Uint8Array [245]` (which is "F5" in hex)
const decoded = decode(encoded); // returns `true`
```
With replacer/reviver:
```ts
import { encode, decode, type Replacer, type Reviver } from '@dfinity/cbor';
const value = { a: 1, b: 2 };
// Encoding with replacer
const replacer: Replacer = val => (typeof val === 'number' ? val * 2 : val);
const result = encode(value, replacer);
decode(result); // { a: 2, b: 4 }
// Decoding with reviver
const bytes = encode(value);
const reviver: Reviver = val => (typeof val === 'number' ? val * 2 : val);
decode(bytes, reviver); // { a: 2, b: 4 }
```
## API
<!-- TSDOC_START -->
## :toolbox: Functions
- [decode](#gear-decode)
- [encode](#gear-encode)
- [encodeWithSelfDescribedTag](#gear-encodewithselfdescribedtag)
### :gear: decode
Decodes a CBOR byte array into a value.
See {@link Reviver} for more information.
| Function | Type |
| -------- | ------------------------------------------------------------------------------------------------------- |
| `decode` | `<T extends unknown = any>(input: Uint8Array<ArrayBufferLike>, reviver?: Reviver<T> or undefined) => T` |
Parameters:
- `input`: - The CBOR byte array to decode.
- `reviver`: - A function that can be used to manipulate the decoded value.
Examples:
Simple
```ts
const value = true;
const encoded = encode(value); // returns `Uint8Array [245]` (which is "F5" in hex)
const decoded = decode(encoded); // returns `true`
```
Reviver
```ts
const bytes = ...; // Uint8Array corresponding to the CBOR encoding of `{ a: 1, b: 2 }`
const reviver: Reviver = val => (typeof val === 'number' ? val * 2 : val);
decode(bytes, reviver); // returns `{ a: 2, b: 4 }`
```
### :gear: encode
Encodes a value into a CBOR byte array.
| Function | Type |
| -------- | ---------------------------------------------------------------------------------------------------- |
| `encode` | `<T = any>(value: CborValue<T>, replacer?: Replacer<T> or undefined) => Uint8Array<ArrayBufferLike>` |
Parameters:
- `value`: - The value to encode.
- `replacer`: - A function that can be used to manipulate the input before it is encoded.
Examples:
Simple
```ts
const value = true;
const encoded = encode(value); // returns `Uint8Array [245]` (which is "F5" in hex)
```
Replacer
```ts
const replacer: Replacer = val => (typeof val === 'number' ? val * 2 : val);
encode({ a: 1, b: 2 }, replacer); // returns the Uint8Array corresponding to the CBOR encoding of `{ a: 2, b: 4 }`
```
### :gear: encodeWithSelfDescribedTag
Encodes a value into a CBOR byte array (same as {@link encode}), but prepends the self-described CBOR tag (55799).
| Function | Type |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- |
| `encodeWithSelfDescribedTag` | `<T = any>(value: CborValue<T>, replacer?: Replacer<T> or undefined) => Uint8Array<ArrayBufferLike>` |
Parameters:
- `value`: - The value to encode.
- `replacer`: - A function that can be used to manipulate the input before it is encoded.
Examples:
```ts
const value = true;
const encoded = encodeWithSelfDescribedTag(value); // returns the Uint8Array [217, 217, 247, 245] (which is "D9D9F7F5" in hex)
```
## :wrench: Constants
- [CBOR_SELF_DESCRIBED_TAG](#gear-cbor_self_described_tag)
- [CBOR_STOP_CODE](#gear-cbor_stop_code)
- [TOKEN_VALUE_MAX](#gear-token_value_max)
- [ONE_BYTE_MAX](#gear-one_byte_max)
- [TWO_BYTES_MAX](#gear-two_bytes_max)
- [FOUR_BYTES_MAX](#gear-four_bytes_max)
- [EIGHT_BYTES_MAX](#gear-eight_bytes_max)
### :gear: CBOR_SELF_DESCRIBED_TAG
The tag number `55799`, the self-described tag for CBOR.
The serialization of this tag's head is `0xd9d9f7`.
| Constant | Type |
| ------------------------- | ------- |
| `CBOR_SELF_DESCRIBED_TAG` | `55799` |
### :gear: CBOR_STOP_CODE
| Constant | Type |
| ---------------- | --------------- |
| `CBOR_STOP_CODE` | `unique symbol` |
### :gear: TOKEN_VALUE_MAX
| Constant | Type |
| ----------------- | ---- |
| `TOKEN_VALUE_MAX` | `23` |
### :gear: ONE_BYTE_MAX
| Constant | Type |
| -------------- | ----- |
| `ONE_BYTE_MAX` | `255` |
### :gear: TWO_BYTES_MAX
| Constant | Type |
| --------------- | ------- |
| `TWO_BYTES_MAX` | `65535` |
### :gear: FOUR_BYTES_MAX
| Constant | Type |
| ---------------- | ------------ |
| `FOUR_BYTES_MAX` | `4294967295` |
### :gear: EIGHT_BYTES_MAX
The maximum value that can be encoded in 8 bytes: `18446744073709551615n`.
| Constant | Type |
| ----------------- | -------- |
| `EIGHT_BYTES_MAX` | `bigint` |
## :factory: DecodingError
## :factory: EncodingError
## :nut_and_bolt: Enum
- [CborSimpleType](#gear-cborsimpletype)
- [CborMajorType](#gear-cbormajortype)
- [CborMinorType](#gear-cborminortype)
### :gear: CborSimpleType
| Property | Type | Description |
| ----------- | ------ | ----------- |
| `False` | `0x14` | |
| `True` | `0x15` | |
| `Null` | `0x16` | |
| `Undefined` | `0x17` | |
| `Break` | `0x1f` | |
### :gear: CborMajorType
| Property | Type | Description |
| ----------------- | ---- | ----------- |
| `UnsignedInteger` | `0` | |
| `NegativeInteger` | `1` | |
| `ByteString` | `2` | |
| `TextString` | `3` | |
| `Array` | `4` | |
| `Map` | `5` | |
| `Tag` | `6` | |
| `Simple` | `7` | |
### :gear: CborMinorType
| Property | Type | Description |
| ------------ | ---- | ----------- |
| `Value` | `23` | |
| `OneByte` | `24` | |
| `TwoBytes` | `25` | |
| `FourBytes` | `26` | |
| `EightBytes` | `27` | |
| `Indefinite` | `31` | |
<!-- TSDOC_END -->
## Not implemented
- Custom tag encoding/decoding.
- Custom tags allow for encoding and decoding of custom types.
- We currently don't use this custom tags (although we probably should).
- Since we don't directly encode developer provided data (that's encoded by Candid) then we can safely say we don't need the feature.
- Unit tests for text/byte strings with a length that does not fit in four bytes or less.
- The "length" of the text string can be encoded with up to 8 bytes, which means the largest possible string length is `18,446,744,073,709,551,615`. The tests cover a string length that's encoded up to four 4 bytes, longer than this and the tests became extremely slow.
- The largest number in 4 bytes is `2,147,483,647` which would represent the length of an ~2gb string, which is not possible to fit into a single IC message anyway.
- Indeterminite length encoding for text and byte strings
- To encode a string length longer than the previously mentioned 8 byte limit, a string can be encoded with an "indeterminate" length.
- Similar to the previous point, this would be impractical for the IC due to message limits.
## Contributing
Check out the [contribution guidelines](./.github/CONTRIBUTING.md).
### Setup
- Install [pnpm](https://pnpm.io/)
- Install [commitizen](https://commitizen-tools.github.io/commitizen/)
- Install [pre-commit](https://pre-commit.com/)
- Install dependencies:
```bash
pnpm install
```
### Running tests
```bash
pnpm test
```
### Formatting
```bash
pnpm format
```
### Generating documentation
We use [tsdoc-markdown](https://github.com/peterpeterparker/tsdoc-markdown) to generate the documentation.
To update the documentation in the `README.md` file, run:
```bash
pnpm tsdoc
```
## License
This project is licensed under the [Apache License 2.0](./LICENSE).