npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cbortech/cbor-cli

v0.27.0

Published

Command-line tool to convert between CBOR binary data, CDN (Concise Diagnostic Notation) text, and annotated hex dumps

Readme

@cbortech/cbor-cli

Command-line tool to convert between CBOR binary data, CDN (CBOR EDN) text, and annotated hex dumps.

Built on @cbortech/cbor. A live playground is available at https://cbor.tech/cbor/.

Install

npm install -g @cbortech/cbor-cli

Or run it without installing:

npx @cbortech/cbor-cli --help

The installed command is named cbor.

Quick Examples

# CDN text → CBOR binary
echo '{"hello": "world", "n": 42}' | cbor compile -o hello.cbor

# CBOR binary → CDN text (decompile is the default command)
cbor hello.cbor
# {"hello": "world", "n": 42}

# CBOR binary → annotated hex dump
cbor toHex hello.cbor
# A2                    -- Map of length 2
#    65 68 65 6C 6C 6F  -- "hello"
#    65 77 6F 72 6C 64  -- "world"
#    61 6E              -- "n"
#    18 2A              -- 42

# Annotated hex dump (or plain hex) → CBOR binary
cbor toHex hello.cbor | cbor fromHex | cbor decompile --indent 0
# {"hello":"world","n":42}

# Format (pretty-print) CDN text, preserving comments
echo '# config
{"retries": 3, }' | cbor format

# Check CBOR data for well-formedness and validity
cbor validate hello.cbor
# hello.cbor: ok (1 item)

Commands

Every command reads from a file given as a positional argument, or from stdin when the argument is omitted or -. Output goes to stdout unless -o <file> is given. All commands exit with status 0 on success and 1 on failure.

Every command also accepts --extensions <list> to select which application extensions are enabled — see Selecting extensions.

cbor compile [input]

Compile CDN text into CBOR binary data. A multi-item CDN sequence produces a CBOR Sequence (RFC 8742).

| Option | Description | | --------------------- | --------------------------------------------------------------------- | | -o, --output <file> | Output CBOR file (default: stdout) | | --unresolved <mode> | Unknown / disabled app-extension prefixes: cpa999 (wrap) | error | | --no-strict | Report CDN validity violations as warnings and continue |

As a safety measure, compile (and fromHex) refuse to write binary data directly to a terminal — write to a file with -o or pipe the output.

cbor decompile [input]

Decompile CBOR binary data into CDN text. A CBOR Sequence produces one CDN item per line.

decompile is also the default command: cbor input.cbor and cat input.cbor | cbor are equivalent to cbor decompile input.cbor and cat input.cbor | cbor decompile. If a file happens to share its name with a command, separate it with -- (e.g. cbor -- compile).

| Option | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | -o, --output <file> | Output CDN file (default: stdout) | | -i, --indent <n> | Indentation spaces per level (default: 2, 0 = single-line) | | --commas <style> | comma | none | trailing (default: comma) | | --bstr-encoding <enc> | Byte string encoding: hex | base64 | base64url (default: hex) | | --sqstr <mode> | Single-quoted byte strings: printable-string | string | none (default: printable-string) | | --int-format <fmt> | decimal | hex | octal | binary (default: decimal) | | --float-format <fmt> | decimal | hex | app-extension (float'...', losslessly preserves NaN/Infinity) (default: decimal) | | --encoding-indicators <mode> | Emit _N indicators: auto | always | never (default: auto) | | --no-split-cdn | Don't split text strings that parse as CDN (default: split when --indent is set) | | --no-split-newline | Don't split text strings at newlines (default: split when --indent is set) | | --no-preserve-concatenation | Join "a" + "b" source concatenation into one literal (default: keep it split when --indent is set) | | --no-preserve-raw-string | Convert `…` raw string literals to double-quoted strings (default: keep them as written) | | --no-inline-leaf-containers | Expand every container across multiple lines when indenting (default: containers with no nested array/map stay on one line) | | --no-preserve-blank-lines | Don't re-emit blank lines between entries (default: preserve them when --indent is set) | | --no-preserve-number-format | Normalize integer/float literals via --int-format/--float-format (default: keep their original spelling) | | --no-preserve-app-prefix | Regenerate app-extension notation instead of preserving its original spelling (default: preserve it) | | --modern-concat | Render preserved "a" + "b" concatenation (and elisions) as draft-27 t1<<...>>/b1<<...>> notation (default: off) | | --modern-stream-syntax | Render indefinite-length strings as draft-27 ilts<<...>>/ilbs<<...>> notation instead of (_ "a", "b") (default: off) | | --no-strict | Report CBOR validity violations as warnings and continue |

--preserve-app-sequence / --no-preserve-app-sequence are deprecated aliases for --preserve-app-prefix / --no-preserve-app-prefix, kept for backward compatibility; --preserve-app-prefix takes precedence when both are given.

cbor format [input]

Format CDN text: parse it and re-serialize it. Comments are preserved by default; single-line output (--indent 0) always strips them, since line comments can only be terminated by a newline. For a multi-item CDN sequence, --preserve-blank-lines also re-emits a blank line between two top-level items that had one in the source, in addition to the entries it preserves within a single item's containers.

Accepts all of the rendering options of decompile, plus:

| Option | Description | | ------------------------ | --------------------------------------------------------------------- | | --no-preserve-comments | Strip comments from the output | | --unresolved <mode> | Unknown / disabled app-extension prefixes: cpa999 (wrap) | error | | --no-strict | Report CDN validity violations as warnings and continue |

cbor toHex [input]

Convert CBOR binary data to an annotated hex dump (or plain hex with --no-annotate).

| Option | Description | | ------------------------- | -------------------------------------------------------- | | -o, --output <file> | Output text file (default: stdout) | | -i, --indent <n> | Indentation spaces per nesting level (default: 3) | | --comment-style <style> | Comment marker: -- | # (default: --) | | --no-annotate | Emit plain hex without annotations | | --no-strict | Report CBOR validity violations as warnings and continue |

cbor fromHex [input]

Convert a hex dump back to CBOR binary data. By default the input is an annotated dump as produced by cbor toHex (comments are ignored); with --format plain the input is bare hex (whitespace allowed).

| Option | Description | | --------------------- | ----------------------------------------------------------- | | -o, --output <file> | Output CBOR file (default: stdout) | | --format <fmt> | Input format: annotated | plain (default: annotated) | | --no-strict | Report CBOR validity violations as warnings and continue |

cbor validate [input]

Check input for well-formedness and validity. Recoverable validity violations (e.g. duplicate map keys) are reported as warnings; truly malformed data (including a CDN syntax error that stops parsing) is reported as invalid. Informational hints — e.g. a CDN prefix that matches a known optional extension which isn't enabled — are printed as <name>: hint: … but don't affect the result. Exits 0 only when the input is clean.

Passing --cddl additionally checks each decoded/parsed item against a CDDL schema; a mismatch is reported as a cddl violation line and makes the result invalid, same as any other validity violation.

| Option | Description | | --------------------- | --------------------------------------------------------------------------------- | | -t, --type <type> | Input type: cbor | cdn | hex (default: cbor) | | --unresolved <mode> | Unknown / disabled app-extension prefixes (CDN input): cpa999 (wrap) | error | | --cddl <file> | CDDL schema file to validate each decoded/parsed item against | | --cddl-rule <name> | CDDL rule to validate against (default: the schema root rule) |

$ printf '\xa2\x61\x61\x01\x61\x61\x02' | cbor validate
stdin: warning: duplicate map key at offset 4
stdin: 1 item, 1 warning
$ echo $?
1

$ echo 'person = { name: tstr, ? age: uint }' > person.cddl
$ echo '{"name": 42}' | cbor validate --type cdn --cddl person.cddl
stdin: cddl violation: value for 'name' does not match at /name (offset 9)
stdin: invalid (1 item, 1 CDDL violation)
$ echo $?
1

CDN Extensions

The following application extensions are available:

| Extension | Description | | --------------- | ------------------------------------------------------------------- | | dt / DT | RFC 3339 date-time as a bare epoch number / as tag 1 | | ip / IP | IP address as a bare byte string / as tag 52 | | cri / CRI | URI reference as a bare CRI array / as tag 99 | | t1 / b1 | concatenate string/byte-string arguments into one text/byte string | | ilts / ilbs | build an indefinite-length text/byte string, one chunk per argument | | float | IEEE 754 bit patterns (float16/32/64) | | hash | cryptographic hash of the content (SHA-256 by default) | | b32 / h32 | base32 / base32hex byte strings (RFC 4648); string form only | | same | assert that all items encode to identical CBOR bytes | | uuid / UUID | UUID as a bare byte string / as tag 37 | | SET | mathematical finite set (tag 258) | | MAP | explicit Map datatype (tag 259; non-text keys allowed) |

# dt'…' / ip'…' as bare values, DT'…' / IP'…' as tagged values
echo "dt'2024-01-01T00:00:00Z'" | cbor compile | cbor toHex
# 1A 65 92 00 80  -- 1704067200
echo "IP'192.0.2.1'" | cbor compile | cbor toHex
# D8 34              -- Tag 52
#    44 C0 00 02 01  -- h'c0000201'

# cri'…' as a bare CRI array (RFC 3986 URI reference)
echo "cri'https://example.com/path'" | cbor compile | cbor toHex
# 83                             -- Array of length 3
#    23                          -- -4
#    82                          -- Array of length 2
#       67 65 78 61 6D 70 6C 65  -- "example"
#       63 63 6F 6D              -- "com"
#    81                          -- Array of length 1
#       64 70 61 74 68           -- "path"

# t1/b1 concatenate arguments into a single string
echo "t1<<'foo', 'bar'>>" | cbor compile | cbor toHex
# 66 66 6F 6F 62 61 72  -- "foobar"

# ilts/ilbs build an indefinite-length string, one chunk per argument
echo "ilts<<'foo', 'bar'>>" | cbor compile | cbor toHex
# 7F              -- Start indefinite-length text string
#    63 66 6F 6F  -- "foo"
#    63 62 61 72  -- "bar"
# FF              -- "break"

# SHA-256 of the text "foo" as a byte string
echo "hash'foo'" | cbor compile | cbor decompile --sqstr none
# h'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'

# UUID as a byte string (uuid'…') or tag 37 (UUID'…')
echo "uuid'019e226f-78d8-7892-8c91-79013e6905e2'" | cbor compile | cbor toHex
# 50 01 9E 22 6F 78 D8 78 92 8C 91 79 01 3E 69 05 E2  -- h'019e226f78d878928c9179013e6905e2'

# base32 byte string and a float16 bit pattern
echo "[b32'MZXW6', float'7ef0']" | cbor compile | cbor toHex
# 82              -- Array of length 2
#    43 66 6F 6F  -- 'foo'
#    F9 7E F0     -- NaN

# same<<…>> asserts equal encodings (fails otherwise)
echo "same<<b64'AA', h'00'>>" | cbor compile | cbor toHex
# 41 00  -- h'00'

# SET<<[…]>> (tag 258) and MAP<<{…}>> (tag 259)
echo 'SET<<["a","b","c"]>>' | cbor compile | cbor toHex
# D9 01 02     -- Tag 258
#    83        -- Array of length 3
#       61 61  -- "a"
#       61 62  -- "b"
#       61 63  -- "c"

Note that, like hash'…', the untagged forms (dt'…', ip'…', cri'…') have an app-string spelling that is only visible right after parsing CDN (e.g. cbor format) — once compiled to CBOR bytes and decompiled again, they round-trip as the plain values they encode to, since nothing marks them as coming from an app-string. The tagged forms (DT'…', IP'…', CRI'…') do carry a real CBOR tag and so keep their notation through a full compile → decompile round-trip.

Selecting extensions

Every command accepts --extensions <list> to control which application extensions are enabled:

  • --extensions all (default) — everything in the table above.
  • --extensions none — no application extensions.
  • --extensions dt,t1,hash — exactly the named extensions (comma-separated names from the table).

When CDN input uses a prefix whose extension is disabled, the literal is wrapped in a CPA999 tag (999(["dt", "…"])) and a warning is printed. Pass --unresolved error (on compile, format, and validate) to reject such input instead — useful for allowlisting untrusted CDN. On the binary side, a disabled extension's tag simply decodes as a generic tag.

# allowlist: only dt/DT and t1/b1 are interpreted
echo "dt'2024-01-01T00:00:00Z'" | cbor compile --extensions dt,t1 | cbor toHex
# 1A 65 92 00 80  -- 1704067200

# reject anything not on the allowlist
echo "hash'foo'" | cbor compile --extensions dt,t1 --unresolved error
# cbor: EDN parse error at line 1, column 1: unknown app-string extension: "hash"

# a disabled extension's tag decodes generically
echo "UUID'019e226f-78d8-7892-8c91-79013e6905e2'" | cbor compile \
  | cbor decompile --extensions none --indent 0
# 37(h'019e226f78d878928c9179013e6905e2')

Exit Codes and Diagnostics

  • 0 — success.
  • 1 — any failure (parse/decode error, invalid option value, I/O error, or validate finding at least one warning).

Errors and warnings are written to stderr, prefixed with cbor:. Warnings include the byte offset (CBOR input) or line/column (CDN input) where the violation was detected.

validate is the exception: its report (<name>: ok (…), <name>: warning: …, <name>: invalid) is written to stdout, like a linter's output, so it can be piped or grepped. In the invalid case, the error message (parse/decode error, but also e.g. an I/O error or an invalid --type value) is additionally printed to stderr, cbor:-prefixed.

Specifications

Implementation notes:

  • CDN follows draft-27 while retaining draft-25's (_ ...) streamstring syntax and + string-concatenation syntax.
  • CDDL implements every RFC 8610 control operator, plus RFC 9165's .plus, .cat, and .feature.
  • The RFC 9682 updates are implemented: its string-literal grammar (including \u{...}), empty data models at the syntax layer (a model with no rules is still a semantic error when compiled), and non-literal #6.<type> / #7.<type> head numbers. Comment PCHAR validation, bare CR line endings, and comments ending at EOF are intentionally accepted more leniently than the collected ABNF.

License

Apache-2.0