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

4.9 KiB

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<LicenseErrorCode> 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).