Files
2026-05-27 23:47:53 +01:00

2.7 KiB

@suaveplan/license — codec/bitpack

(no submodules)

Purpose

Bit-precise pack/unpack primitives used to serialise the 72-bit license payload into 9 bytes. Plain DataView / typed-array slicing can only write whole bytes, so we walk the buffer bit-by-bit. Two thin classes hold the cursor: SimpleBitPacker writes MSB-first, SimpleBitUnpacker reads MSB-first. Both round-trip identically to upstream's @suaveplan/license bitpacker.

Features

  • packUint(value, bits) — writes an unsigned integer in [0, 2^bits) using bits bits; raises LicenseError(LICENSE.PAYLOAD_OUT_OF_RANGE) when the value exceeds the declared width or is negative.
  • unpackUint(bits) — reads the next bits-wide unsigned integer; raises LicenseError(LICENSE.MALFORMED) when the read would underflow the buffer.
  • getBytes() / getBitCount() / getBitPosition() introspection helpers used by the spec-conformance tests.

Usage: Basic

import {
    SimpleBitPacker,
    SimpleBitUnpacker,
} from "@suaveplan/license/codec/bitpack/bitpack";

const p = new SimpleBitPacker();
p.packUint(2, 3); // 3-bit version
p.packUint(17, 5); // 5-bit signingKeyId
const bytes = p.getBytes();

const u = new SimpleBitUnpacker(bytes);
const version = u.unpackUint(3); // 2
const keyId = u.unpackUint(5); // 17

Usage: Advanced

Round-tripping a full 72-bit payload:

import { FIELD_BITS } from "@suaveplan/license/constants/constants";
import {
    SimpleBitPacker,
    SimpleBitUnpacker,
} from "@suaveplan/license/codec/bitpack/bitpack";

const p = new SimpleBitPacker();
for (const [_field, bits] of Object.entries(FIELD_BITS)) {
    p.packUint(0, bits);
}
const bytes = p.getBytes(); // 9 bytes

const u = new SimpleBitUnpacker(bytes);
for (const [_field, bits] of Object.entries(FIELD_BITS)) {
    u.unpackUint(bits); // === 0
}

API Reference

class SimpleBitPacker

  • packUint(value: number, bits: number): void — write an unsigned integer; throws on overflow / negative.
  • getBytes(): Uint8Array — snapshot the packed bytes.
  • getBitCount(): number — total bits written.

class SimpleBitUnpacker

  • constructor(buffer: Uint8Array) — wrap a byte buffer.
  • unpackUint(bits: number): number — read the next integer; throws MALFORMED on underflow.
  • getBitPosition(): number — current read cursor.

Implementation Notes

The packer grows its internal number[] buffer one byte at a time because the upstream layout is small (9 bytes) and pre-sizing would require knowing the total bit count in advance. The 1 << bits overflow check is safe for the bit widths used by the license schema (≤19 bits); for wider integers, callers should use a dedicated bigint bitpacker.