first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
# `@suaveplan/license` — codec/base32
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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.