# `@suaveplan/license` — codec/base32 _(no submodules)_ ## Purpose Crockford-style Base32 codec used to serialise the packed payload and signature into a printable license-key string. The alphabet (`0-9 A-Z` minus `I`, `L`, `O`, `U`) is shared with upstream so any key generated by upstream parses under suaveplan and vice versa. The encoder inserts `-` separators every 5 characters for legibility; the decoder ignores them. ## Features - 32-character Crockford alphabet, omitting `I`/`L`/`O`/`U`. - Dash-grouped output, `XXXXX-XXXXX-...`. - Case-insensitive decode (uppercase canonical). - Round-trips arbitrary `Uint8Array` data. - Raises `LicenseError(LICENSE.INVALID_ENCODING)` on any non-alphabet character, with the offending character in `error.context.character`. ## Usage: Basic ```ts import { base32Decode, base32Encode } from "@suaveplan/license/codec/base32/base32"; const encoded = base32Encode(new Uint8Array([1, 2, 3, 4, 5])); // e.g. "0426-1850-A" const decoded = base32Decode(encoded); ``` ## Usage: Advanced Catching invalid input: ```ts import { LicenseError } from "@suaveplan/license"; import { base32Decode } from "@suaveplan/license/codec/base32/base32"; try { base32Decode("INVALID-CHAR-!"); } catch (e) { if (e instanceof LicenseError && e.code === "LICENSE.INVALID_ENCODING") { console.warn("Bad character:", e.context?.character); } } ``` ## API Reference ### `base32Encode(buf: Uint8Array): string` Returns the Base32 encoding of `buf`, grouped into 5-character chunks separated by `-`. Empty input returns the empty string. ### `base32Decode(str: string): Uint8Array` Strips `-`, uppercases, and decodes the resulting characters. Throws `LicenseError(LICENSE.INVALID_ENCODING)` for any unknown character. Input is trimmed to a byte boundary — trailing partial-byte bits are discarded (matching upstream behaviour). ## Implementation Notes The implementation uses string concatenation of binary digits rather than bit shifts because the 5-bit-to-8-bit boundary makes manual shifting verbose; the perf cost is negligible for license-key-sized inputs (≤73 bytes). For larger inputs, prefer `@suaveplan/crypto-utils`' base32 implementation. The trailing-bit truncation in `base32Decode` matches upstream's `Math.floor(bits / 8)` so identical inputs decode to identical bytes across both codebases.