/** * License-key parsing. Matches the service's wire format exactly. * * ## Wire format * * A key string looks like `LIC1--`. Both halves * are Crockford base32 (no padding) of the raw bytes. * * ### v1 payload (74 bytes, fixed) * * ```text * offset size field * 0 1 version = 1 * 1 1 flags * 2 16 product_id (UUID bytes) * 18 16 license_id (UUID bytes) * 34 8 issued_at (i64 unix seconds, big-endian) * 42 32 fingerprint_hash (SHA-256, or all-zero) * ``` * * ### v2 payload (83 bytes + variable entitlements) * * ```text * offset size field * 0 1 version = 2 * 1 1 flags * 2 16 product_id * 18 16 license_id * 34 8 issued_at * 42 8 expires_at (i64, 0 = perpetual) * 50 32 fingerprint_hash * 82 1 num_entitlements (u8) * 83 * entitlements — each: [u8 len][len utf-8 bytes] * ``` * * Clients verifying a v1 key treat `expiresAt` as 0 and `entitlements` as * empty, so application code can branch on flags / fields uniformly. */ declare const KEY_PREFIX = "LIC1"; /** v1 format identifier. */ declare const KEY_VERSION_V1 = 1; /** v2 format identifier. */ declare const KEY_VERSION_V2 = 2; /** Highest format version this client understands. */ declare const KEY_VERSION = 2; /** Set when the key is bound to a specific machine fingerprint hash. */ declare const FLAG_FINGERPRINT_BOUND = 1; /** Set on trial keys. */ declare const FLAG_TRIAL = 2; /** Decoded fields of the signed payload. */ interface LicensePayload { /** Format version (1 or 2). */ version: number; /** Feature flags. */ flags: number; /** Raw 16-byte product id (UUID). */ productId: Uint8Array; /** Raw 16-byte license id (UUID). */ licenseId: Uint8Array; /** Unix seconds issued. */ issuedAt: number; /** Unix seconds expiry; `0` for perpetual. Always `0` on v1 keys. */ expiresAt: number; /** SHA-256 hash of the bound machine fingerprint, or all-zero. */ fingerprintHash: Uint8Array; /** Entitlement slugs granted by this license. Empty on v1 keys. */ entitlements: string[]; /** Product UUID in canonical string form. */ productUuid: string; /** License UUID in canonical string form. */ licenseUuid: string; /** True if the key is fingerprint-bound. */ isFingerprintBound: boolean; /** True if the key is flagged as a trial. */ isTrial: boolean; } /** A parsed (not yet verified) license key. */ interface LicenseKey { payload: LicensePayload; /** * Raw payload bytes (what the server signed over). Length is 74 on v1, * `>= 83` on v2. */ signedBytes: Uint8Array; /** Raw 64-byte signature. */ signature: Uint8Array; } /** True if `nowUnixSeconds` is at or after the key's `expiresAt`. */ declare function isExpiredAt(payload: LicensePayload, nowUnixSeconds: number): boolean; /** True if the license grants the given entitlement slug. */ declare function hasEntitlement(payload: LicensePayload, slug: string): boolean; /** Parse a `LIC1-...-...` string. Does NOT verify. */ declare function parseLicenseKey(raw: string): LicenseKey; /** * Issuer public key. Accepts either raw 32-byte Ed25519 key material or a * PEM-encoded SubjectPublicKeyInfo blob (which is what the service returns * from `/v1/pubkey`). */ /** Parsed Ed25519 public key, ready for signature verification. */ declare class PublicKey { /** Raw 32-byte Ed25519 public key material. */ readonly raw: Uint8Array; constructor(raw: Uint8Array); /** Parse a PEM blob as emitted by the service. */ static fromPem(pem: string): PublicKey; /** Construct from raw bytes (no PEM envelope). */ static fromBytes(bytes: Uint8Array): PublicKey; } /** Offline Ed25519 signature verification. */ interface VerifyOk { /** Parsed payload fields. */ payload: LicensePayload; /** License UUID as a canonical string. */ licenseId: string; /** Product UUID as a canonical string. */ productId: string; } /** Verifies license keys against a single issuing server's public key. */ declare class Verifier { private pubkey; constructor(pubkey: PublicKey); /** Verify a license key string. Throws on any failure. */ verify(keyStr: string): VerifyOk; /** * Verify AND enforce that, if the key is fingerprint-bound, the given * fingerprint matches. If the key is not bound, the fingerprint is * ignored. Throws on any failure. */ verifyWithFingerprint(keyStr: string, fingerprint: string): VerifyOk; /** * Verify a key and additionally reject it with an `expired` error if * `nowUnixSeconds` is at or past its `expiresAt`. Perpetual keys * (`expiresAt === 0`) are accepted regardless of `nowUnixSeconds`. This is * offline-only — no grace window logic; use `Client.validate` for that. */ verifyWithTime(keyStr: string, nowUnixSeconds: number): VerifyOk; } /** * Online operations against a running `licensing-service` instance. * * All methods use the global `fetch` available in Node 18+ and every modern * browser. No additional runtime required. */ interface ValidateResponse { ok: boolean; /** * Machine-readable reason on failure. One of: * `bad_format`, `bad_signature`, `not_found`, `revoked`, `suspended`, * `expired`, `product_mismatch`, `fingerprint_mismatch`, * `too_many_machines`, `rate_limited`, `invalid_state`. */ reason?: string; licenseId?: string; productId?: string; productSlug?: string; issuedAt?: string; /** Expiry timestamp (RFC 3339) if the license has one. */ expiresAt?: string; /** End of the grace window (RFC 3339) when in a grace period. */ graceUntil?: string; /** True when the key is past `expiresAt` but still inside the grace window. */ inGracePeriod?: boolean; /** True if this license is flagged as a trial. */ isTrial?: boolean; /** Entitlement slugs granted by the license. */ entitlements?: string[]; /** License status string: `active`, `suspended`, `revoked`. */ status?: string; /** Machine id created or matched by this call (when fingerprint was sent). */ machineId?: string; /** Seat cap: `0` unlimited, `1` single-seat, `n` n-seat. */ maxMachines?: number; } interface ValidateOptions { /** Product slug the caller expects the key to cover. */ productSlug?: string; /** Raw machine fingerprint; enables seat binding / cap enforcement. */ fingerprint?: string; /** Client-supplied hostname, stored against the machine row on activation. */ hostname?: string; /** Client-supplied platform descriptor, e.g. `'linux-x86_64'`. */ platform?: string; } interface MachineResponse { ok: boolean; reason?: string; machineId?: string; activeCount?: number; maxMachines?: number; } interface PurchaseSession { /** Our internal invoice id — use with `pollPurchase`. */ invoiceId: string; /** BTCPay's invoice id (opaque). */ btcpayInvoiceId: string; /** URL to open in the buyer's browser to pay. */ checkoutUrl: string; /** Price in satoshis. */ amountSats: number; /** Where the service recommends polling. */ pollUrl: string; } interface PollResponse { invoiceId: string; /** `pending | settled | expired | invalid`. */ status: string; productId: string; amountSats: number; /** Populated once the license has been issued. */ licenseKey?: string; licenseId?: string; } interface StartPurchaseOptions { /** Optional email for the receipt. */ buyerEmail?: string; /** Optional URL the buyer should be returned to after payment. */ redirectUrl?: string; /** Optional discount / referral code. */ code?: string; /** Optional buyer note recorded on the invoice (admin-visible). */ buyerNote?: string; } interface RedeemFreeOptions { /** Optional email recorded on the synthetic invoice + license. */ buyerEmail?: string; /** Optional buyer note. */ buyerNote?: string; } interface RedeemFreeResponse { licenseId: string; /** The fully-signed license key, ready for offline verification. */ licenseKey: string; invoiceId: string; redemptionId: string; } /** An HTTP client pinned to one licensing-service base URL. */ declare class Client { private base; constructor(baseUrl: string); /** The normalized base URL this client is pinned to. */ baseUrl(): string; /** Fetch the server's PEM-encoded public key. */ fetchPubkeyPem(): Promise; /** * Server-authoritative validation. Returns the full response including * expiry / entitlements / seat fields introduced in v2. * * Two-argument form kept for call-site compatibility with earlier SDK * versions; pass an options object for the full set of fields. */ validate(key: string, productSlugOrOptions?: string | ValidateOptions, fingerprint?: string): Promise; /** Lightweight heartbeat. Server updates `last_heartbeat_at`. */ heartbeat(key: string, fingerprint: string): Promise; /** Explicitly activate a seat for the given fingerprint. */ activate(key: string, fingerprint: string, opts?: { hostname?: string; platform?: string; }): Promise; /** Free a seat held by the given fingerprint. */ deactivate(key: string, fingerprint: string, reason?: string): Promise; /** Start a purchase. Returns the checkout URL and invoice id. */ startPurchase(productSlug: string, opts?: StartPurchaseOptions): Promise; /** * Redeem a `free_license` code: bypass BTCPay entirely and receive the * signed license key directly. Throws if the code is unknown / disabled * / expired / wrong product / not a free_license code, or if the cap * has been reached. */ redeemFreeLicense(productSlug: string, code: string, opts?: RedeemFreeOptions): Promise; /** Poll a purchase by its invoice id. */ pollPurchase(invoiceId: string): Promise; /** * Convenience: open the checkout, poll until a license key is issued, * then return it. Suitable for CLI usage or for an app UI that shows a * spinner while the buyer pays. */ waitForLicense(invoiceId: string, options?: { intervalMs?: number; timeoutMs?: number; }): Promise; private toValidateResponse; private toMachineResponse; private get; private post; private request; } /** Hash a raw fingerprint string to the 32-byte form embedded in keys. */ declare function hashFingerprint(raw: string): Uint8Array; /** All errors thrown by this library inherit from `LicensingError`. */ declare class LicensingError extends Error { /** * Machine-readable reason code. Common values: * `"bad_format"`, `"bad_encoding"`, `"bad_version"`, `"bad_signature"`, * `"expired"`, `"server_error"`, `"http_error"`, `"other"`. */ readonly code: string; constructor(code: string, message: string); } export { Client, FLAG_FINGERPRINT_BOUND, FLAG_TRIAL, KEY_PREFIX, KEY_VERSION, KEY_VERSION_V1, KEY_VERSION_V2, type LicenseKey, type LicensePayload, LicensingError, type MachineResponse, type PollResponse, PublicKey, type PurchaseSession, type RedeemFreeOptions, type RedeemFreeResponse, type StartPurchaseOptions, type ValidateOptions, type ValidateResponse, Verifier, type VerifyOk, hasEntitlement, hashFingerprint, isExpiredAt, parseLicenseKey };