# Add @suaveplan/license — port-main verbatim + enterprise stack **Package**: `@suaveplan/license` **Status**: PROPOSED **Type**: migration (port-main wire-format verbatim) + enterprise enhancements (additive) - **Spec delta**: ./specs/license/spec.md ## Why Software license-key issuance and validation. Ports `../suaveplan/packages/security/license/` verbatim at the wire-format level (72-bit bitpacked payload, secp256k1 signature truncated to 20 bytes by default, Crockford Base32 with signature-derived obfuscation) so genesis-generated keys interoperate byte-for-byte with upstream-generated keys. Layers the genesis enterprise stack on top: `SuaveplanError`-typed errors with a 12-code registry, Zod boundary validation, OpenTelemetry counters/histogram, `AbortSignal`, injectable `Clock`/`Rng`, sibling `.md` docs ≥200 words each, mitata benchmarks, fast-check property tests, dep-graph test, spec-conformance test, 100/100/100/100 coverage. Adds a pluggable `RevocationStore` with an in-memory implementation as an opt-in offline blocklist — does not change the wire format. Unblocks `@suaveplan/server-keys` (in flight; `enterprise-server-server-keys`). ## What changes Net-new package at version `0.1.0`. Public surface (every symbol from upstream `index.ts`/`index.types.ts`/`bitpack.ts`/`obfuscation.ts`, plus enterprise additions): - Codec: `base32Encode` / `base32Decode`, `SimpleBitPacker` / `SimpleBitUnpacker`, `packPayload` / `unpackPayload`, `obfuscateLicenseKey` / `deobfuscateLicenseKey` / `extractSignatureFromKey` - Time: `getDayNumber`, `dayNumberToDate`, `checkExpiration` — `Clock` injectable - Flags: `hasFlag`, `combineFlags`, `hasFeature`, `combineFeatures`, `getEnabledFeatures` - Generation: `generateLicense`, `createPayload` (Rng injectable), `parseLicense` - Validation: `validateLicense`, `isValidLicense` — full + truncated signature paths - Manager: `LicenseManager` class with `addPublicKey` / `setSigningKey` / `setRevocationStore` / `generate` / `generateTrial` / `validate` / `isValid` / `parse` / `revoke` / `isRevoked` - Revocation: `RevocationStore` interface, `createMemoryRevocationStore` (LRU), `fingerprintLicense`, `LicenseValidationError.REVOKED` (additive enum variant; the other 6 variants are preserved verbatim) - Errors: `LicenseError extends SuaveplanError` with 12 codes (`LICENSE.{INVALID_INPUT, INVALID_ENCODING, MALFORMED, PAYLOAD_OUT_OF_RANGE, UNSUPPORTED_VERSION, UNKNOWN_SIGNING_KEY, INVALID_SIGNATURE, EXPIRED, REVOKED, NO_SIGNING_KEY, FEATURE_INDEX_OUT_OF_RANGE, ABORTED}`) - Schemas: `LicensePayloadSchema`, `LicenseGenerationOptionsSchema`, `LicenseValidationOptionsSchema`, `QuickLicenseOptionsSchema` (Zod) - OTel: counter `license.generate_total`, counter `license.validate_total{license.valid}`, histogram `license.validate_duration_ms` - Enums + types preserved verbatim from upstream: `TimeEncodingType`, `LicenseFlags`, `PackageTier`, `LicenseValidationError`, `LicensePayload`, `LicenseDetails`, `LicenseGenerationOptions`, `LicenseGenerationResult`, `LicenseValidationOptions`, `LicenseValidationSuccess`, `LicenseValidationFailure`, `LicenseValidationResult`, `LicenseParsedResult`, `LicenseManagerConfig`, `QuickLicenseOptions`, `KeyRegistry` - Constants verbatim from upstream: `LICENSE_VERSION` (=2), `FULL_SIGNATURE_BYTES` (=64), `SIGNATURE_BYTES` (=20), `MIN_SIGNATURE_BYTES` (=16), `BASE32_ALPHABET`, `LICENSE_SCHEMA`, plus genesis-added `PAYLOAD_BYTES` (=9) - Subpath exports per feature module ## Out of scope - **Network-based revocation (HTTP CRL/OCSP).** Follow-up package; the shipped `RevocationStore` interface accepts async implementations so the follow-up is non-breaking. - **Hardware-fingerprint enforcement.** `MACHINE_LOCKED` enum value is preserved (wire format); enforcement is application policy. - **License rotation workflows.** Business logic, owned by callers. - **Schema-registry integration.** Wire format is self-describing via the 3-bit `version` field. ## Source mapping | Capability | Upstream source | Notes | |---|---|---| | Wire format (72-bit payload, sig modes, Base32, obfuscation) | `../suaveplan/packages/security/license/src/{index,index.types,bitpack,obfuscation}.ts` | verbatim | | Enterprise audit requirements (no React/Node deps, Zod, fast-check, deterministic Clock/Rng, OTel, structured errors, AbortSignal, i18n-ready, 100% coverage, 200-word `.md`) | `../suaveplan/enterprise/license.md` L37-L63 | all addressed | | `LicenseError` + `LICENSE_*` code registry, OTel instruments, `RevocationStore`, `Clock`/`Rng` injection, `AbortSignal` plumbing, dep-graph + spec-conformance tests, mitata benchmarks | genesis-original | genesis-wide enterprise policy (`CLAUDE.md`, `openspec/AGENTS.md`) — upstream throws plain Errors and has no OTel/Zod/revocation | ## Impact ### Affected dependents None today — net-new on genesis. First consumer will be `@suaveplan/server-keys` (separate change `enterprise-server-server-keys`).