Package Exports
- @sovereignbase/bytecodec
- @sovereignbase/bytecodec/package.json
Readme
bytecodec
Typed JavaScript and TypeScript byte utilities for base64, base64url, hex, Z85, UTF-8 strings, unsigned BigInt conversion, JSON, gzip, concatenation, comparison, and byte-source normalization. The package ships tree-shakeable ESM plus CommonJS entry points and keeps the same API across Node, Bun, Deno, browsers, and edge runtimes.
Compatibility
- Runtimes: Node, Bun, Deno, browsers, Cloudflare Workers, and edge runtimes.
- Module formats: ESM by default, with CommonJS exports for
require()consumers in Node and Bun. - Node and Bun runtime behavior: uses
Bufferfor base64 helpers andnode:zlibfor gzip. - Browser and edge gzip support requires
CompressionStreamandDecompressionStream. - TypeScript: bundled types.
Goals
- Developer-friendly API for base64, base64url, hex, Z85, UTF-8, unsigned BigInt conversion, JSON, gzip, concat, equality, and byte normalization.
- No runtime dependencies or bundler shims.
- Tree-shakeable ESM by default with CommonJS compatibility and no side effects.
- Returns copies for safety when normalizing inputs.
- Consistent behavior across Node, browsers, and edge runtimes.
Installation
npm install @sovereignbase/bytecodec
# or
pnpm add @sovereignbase/bytecodec
# or
yarn add @sovereignbase/bytecodec
# or
bun add @sovereignbase/bytecodec
# or
deno add jsr:@sovereignbase/bytecodec
# or
vlt install jsr:@sovereignbase/bytecodecUsage
Bytes wrapper
import { Bytes } from '@sovereignbase/bytecodec'
// The `Bytes` convenience class wraps the same functions as static methods.
const encoded = Bytes.toBase64String(new Uint8Array([1, 2, 3])) // base64 stringBase64
import { toBase64String, fromBase64String } from '@sovereignbase/bytecodec'
const bytes = new Uint8Array([104, 101, 108, 108, 111])
const encoded = toBase64String(bytes) // string of base64 chars
const decoded = fromBase64String(encoded) // Uint8ArrayCommonJS
const { toBase64String, fromBase64String } = require('@sovereignbase/bytecodec')
const encoded = toBase64String([104, 101, 108, 108, 111]) // string of base64 chars
const decoded = fromBase64String(encoded) // Uint8ArrayBase64URL
import {
toBase64UrlString,
fromBase64UrlString,
} from '@sovereignbase/bytecodec'
const bytes = new Uint8Array([104, 101, 108, 108, 111])
const encoded = toBase64UrlString(bytes) // string of base64url chars
const decoded = fromBase64UrlString(encoded) // Uint8ArrayHex
import { toHex, fromHex } from '@sovereignbase/bytecodec'
const bytes = new Uint8Array([222, 173, 190, 239])
const encoded = toHex(bytes) // "deadbeef"
const decoded = fromHex(encoded) // Uint8ArrayZ85
import { toZ85String, fromZ85String } from '@sovereignbase/bytecodec'
const bytes = new Uint8Array([0x86, 0x4f, 0xd2, 0x6f, 0xb5, 0x59, 0xf7, 0x5b])
const encoded = toZ85String(bytes) // "HelloWorld"
const decoded = fromZ85String(encoded) // Uint8ArrayZ85 encodes 4 input bytes into 5 output characters, so toZ85String() requires a byte length divisible by 4 and fromZ85String() requires a string length divisible by 5.
UTF-8 strings
import { fromString, toString } from '@sovereignbase/bytecodec'
const textBytes = fromString('caffe and rockets') // Uint8Array
const text = toString(textBytes) // "caffe and rockets"BigInt
import { fromBigInt, toBigInt } from '@sovereignbase/bytecodec'
const bytes = fromBigInt(0x1234n) // Uint8Array([0x12, 0x34])
const value = toBigInt(bytes) // 0x1234nBigInt helpers use unsigned big-endian encoding. fromBigInt(0n) returns an empty Uint8Array, because no byte width is implied.
Leading zero bytes are not preserved, so the helpers model integers rather than fixed-width binary fields.
JSON
import { fromJSON, toJSON } from '@sovereignbase/bytecodec'
const jsonBytes = fromJSON({ ok: true, count: 3 }) // Uint8Array
const obj = toJSON(jsonBytes) // { ok: true, count: 3 }Compression
import { toCompressed, fromCompressed } from '@sovereignbase/bytecodec'
const compressed = await toCompressed(new Uint8Array([1, 2, 3])) // Uint8Array
const restored = await fromCompressed(compressed) // Uint8ArrayNormalization
import {
toUint8Array,
toArrayBuffer,
toBufferSource,
} from '@sovereignbase/bytecodec'
const normalized = toUint8Array([1, 2, 3]) // Uint8Array
const copied = toArrayBuffer(normalized) // ArrayBuffer
const bufferSource = toBufferSource(normalized) // Uint8Array as BufferSourceAccepted byte inputs (ByteSource) are:
ArrayBufferSharedArrayBufferArrayBufferViewnumber[]
Equality
import { equals } from '@sovereignbase/bytecodec'
const isSame = equals(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3])) // true | falseConcatenating
import { concat } from '@sovereignbase/bytecodec'
const joined = concat([new Uint8Array([1, 2]), new Uint8Array([3, 4]), [5, 6]]) // Uint8ArrayRuntime behavior
Node
Uses Buffer.from for base64 helpers, TextEncoder and TextDecoder when available with Buffer fallback for UTF-8, and node:zlib for gzip.
Bun
Uses the same API shape as Node. ESM and CommonJS entry points are both exported.
Browsers / Edge runtimes
Uses TextEncoder, TextDecoder, btoa, and atob. Gzip uses CompressionStream and DecompressionStream when available.
Validation & errors
Validation failures throw BytecodecError instances with a code string, for example BASE64URL_INVALID_LENGTH, BIGINT_UNSIGNED_EXPECTED, HEX_INVALID_CHARACTER, Z85_INVALID_BLOCK, BASE64_DECODER_UNAVAILABLE, UTF8_DECODER_UNAVAILABLE, and GZIP_COMPRESSION_UNAVAILABLE. Messages are prefixed with {@sovereignbase/bytecodec}.
Safety / copying semantics
toUint8Array, toArrayBuffer, and toBufferSource always return copies. concat normalizes each input to a fresh Uint8Array before joining.
Tests
npm test covers:
- 75 unit tests
- 7 integration tests
- Node E2E: 23/23 passed in ESM and 23/23 passed in CommonJS
- Bun E2E: 23/23 passed in ESM and 23/23 passed in CommonJS
- Deno E2E: 23/23 passed in ESM
- Cloudflare Workers E2E: 23/23 passed in ESM
- Edge Runtime E2E: 23/23 passed in ESM
- Browser E2E: 5/5 passed in Chromium, Firefox, WebKit, mobile-chrome, and mobile-safari
- Coverage gate: 100% statements, branches, functions, and lines
Benchmarks
Latest local npm run bench run on 2026-03-27 with Node v22.14.0 (win32 x64):
| Benchmark | Result |
|---|---|
| base64 encode | 979,522 ops/s (51.0 ms) |
| base64 decode | 1,825,737 ops/s (27.4 ms) |
| base64url encode | 407,973 ops/s (122.6 ms) |
| base64url decode | 560,991 ops/s (89.1 ms) |
| hex encode | 781,944 ops/s (63.9 ms) |
| hex decode | 806,002 ops/s (62.0 ms) |
| z85 encode | 170,125 ops/s (293.9 ms) |
| z85 decode | 1,141,472 ops/s (43.8 ms) |
| utf8 encode | 1,241,977 ops/s (40.3 ms) |
| utf8 decode | 2,610,407 ops/s (19.2 ms) |
| bigint encode | 490,692 ops/s (101.9 ms) |
| bigint decode | 428,938 ops/s (116.6 ms) |
| json encode | 588,066 ops/s (34.0 ms) |
| json decode | 603,058 ops/s (33.2 ms) |
| concat 3 buffers | 560,639 ops/s (89.2 ms) |
| toUint8Array | 6,292,910 ops/s (31.8 ms) |
| toArrayBuffer | 677,822 ops/s (295.1 ms) |
| toBufferSource | 7,465,472 ops/s (26.8 ms) |
| equals same | 2,217,064 ops/s (90.2 ms) |
| equals diff | 2,302,002 ops/s (86.9 ms) |
| gzip compress | 3,473 ops/s (115.2 ms) |
| gzip decompress | 4,753 ops/s (84.2 ms) |
Command: npm run bench
Results vary by machine and Node version.
License
Apache-2.0