{"_id":"@bilkobibitkov/preflight-license","_rev":"7-ef42dcc33b92c1b3f144be982a13dc4b","name":"@bilkobibitkov/preflight-license","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.4":{"name":"@bilkobibitkov/preflight-license","version":"1.0.4","keywords":["preflight","license","cli","ai-agents"],"author":{"name":"Bilko"},"license":"MIT","_id":"@bilkobibitkov/preflight-license@1.0.4","maintainers":[{"name":"bilkobibitkov","email":"BilkoBibitkov2000@gmail.com"}],"homepage":"https://github.com/StanislavBG/preflight-license#readme","bugs":{"url":"https://github.com/StanislavBG/preflight-license/issues"},"bin":{"preflight-keygen":"dist/keygen.js"},"dist":{"shasum":"76fd8a79293869aa177f9888492f3984105a7262","tarball":"https://registry.npmjs.org/@bilkobibitkov/preflight-license/-/preflight-license-1.0.4.tgz","fileCount":18,"integrity":"sha512-rpGrstqt8sTEDx7PnT5/DxaZOAE195TmjVYNrU9IkG7GiDYSBGNNsvHO26S2xb0gyq313JwMUaCjqLNNhsrOJg==","signatures":[{"sig":"MEUCIQDjFRDud62xtc3JcwkX9/KDZnNZvGLi/smfWsuUKlbO4QIgDerY3e9v98NRA36sjHc6kHX7dtzRy/Nb1VTQfBCMwLY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38386},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"d0d550f828cf629d0ce950b1c6286f72e374962e","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"bilkobibitkov","email":"BilkoBibitkov2000@gmail.com"},"repository":{"url":"git+https://github.com/StanislavBG/preflight-license.git","type":"git"},"_npmVersion":"10.9.4","description":"Offline license key validation for Preflight CLIs","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","vitest":"^3.2.4","typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/preflight-license_1.0.4_1778238471361_0.2685945375026675","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Renamed. Use 'preflight-license' (bare, no scope): npm i preflight-license"}},"time":{"created":"2026-05-08T11:07:51.292Z","modified":"2026-05-11T01:04:42.861Z","1.0.0":"2026-03-21T05:22:29.479Z","1.0.3":"2026-03-22T13:05:25.140Z","1.0.4":"2026-05-08T11:07:51.500Z"},"bugs":{"url":"https://github.com/StanislavBG/preflight-license/issues"},"author":{"name":"Bilko"},"license":"MIT","homepage":"https://github.com/StanislavBG/preflight-license#readme","keywords":["preflight","license","cli","ai-agents"],"repository":{"url":"git+https://github.com/StanislavBG/preflight-license.git","type":"git"},"description":"Offline license key validation for Preflight CLIs","maintainers":[{"name":"bilkobibitkov","email":"BilkoBibitkov2000@gmail.com"}],"readme":"# @preflight/license\n\nOffline license key validation for the Preflight CLI suite. No license server, no network calls — keys are self-contained HMAC-signed tokens validated locally.\n\n## Install\n\n```bash\nnpm install @preflight/license\n```\n\n## How it works\n\nKeys are structured as:\n\n```\npreflight_<base64url-payload>.<hmac-signature>\n```\n\nThe payload is a JSON object containing `{ org, tier, expiry, issued }`. The HMAC signature binds the payload to a shared signing secret. Validation happens entirely offline — the CLI checks the signature and expiry, that's it.\n\n**Tiers:** `free` | `team` | `enterprise`\n\n## Usage in a CLI\n\n```typescript\nimport { guard, getLicense } from '@preflight/license';\n\n// Gate a paid feature — prints upgrade message and exits if unlicensed\nguard('team', { feature: '--format sarif' });\n\n// Or check the license yourself\nconst license = getLicense();\nif (!license.valid) {\n  console.error('No valid license.');\n}\n```\n\n`getLicense()` reads `PREFLIGHT_LICENSE_KEY` from the environment. Set it to a valid key to unlock paid features.\n\n### guard() behaviour\n\n| Scenario | Result |\n|----------|--------|\n| No key set | Prints upgrade message, exits with code 1 |\n| Valid team key, team feature | Passes — no output |\n| Expired key | Prints expiry date, exits with code 1 |\n| Tampered key | Prints \"invalid signature\", exits with code 1 |\n| Free feature (no guard call) | Always passes |\n\n## validate()\n\nFor lower-level use:\n\n```typescript\nimport { validate } from '@preflight/license';\n\nconst result = validate(process.env.PREFLIGHT_LICENSE_KEY);\n// {\n//   valid: boolean\n//   tier: 'free' | 'team' | 'enterprise'\n//   org: string\n//   expiry: string | null   // ISO date or null for perpetual\n//   reason?: string         // human-readable when valid=false\n// }\n```\n\n## mintKey()\n\nGenerate a key programmatically (useful in tests):\n\n```typescript\nimport { mintKey } from '@preflight/license';\n\nconst key = mintKey({ org: 'acme', tier: 'team', days: 365, perpetual: false });\n// preflight_eyJvcmciOiJhY21l....<signature>\n```\n\n## Key generation (CLI)\n\nUse the `preflight-keygen` CLI to mint keys for customers:\n\n```bash\n# Install globally or run via npx\nnpx @preflight/license keygen --org acme --tier team --days 365\n\n# Perpetual key (no expiry)\nnpx @preflight/license keygen --org acme --tier enterprise --perpetual\n\n# Production: always set PREFLIGHT_SIGN_SECRET\nPREFLIGHT_SIGN_SECRET=my-prod-secret npx @preflight/license keygen --org acme --tier team --days 365\n```\n\nOutput:\n\n```\n  Org:    acme\n  Tier:   team\n  Expiry: 365 days\n\n  PREFLIGHT_LICENSE_KEY=preflight_eyJvcmciOiJhY21l....\n```\n\nGive the customer the `PREFLIGHT_LICENSE_KEY=...` line to set in their CI environment.\n\n## Integrating into a new CLI\n\n1. Install: `npm install @preflight/license`\n2. Import `guard` from `@preflight/license`\n3. Call `guard('team', { feature: '--format sarif' })` before executing any paid feature\n\n```typescript\n// In your command handler:\nimport { guard } from '@preflight/license';\n\nasync function runCommand(opts: { format?: string }) {\n  if (opts.format === 'sarif' || opts.format === 'junit') {\n    guard('team', { feature: `--format ${opts.format}` });\n  }\n  // ... rest of command\n}\n```\n\n4. Done. Free features are unaffected — only calls guarded by `guard('team', ...)` require a key.\n\n## Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `PREFLIGHT_LICENSE_KEY` | License key provided by the customer |\n| `PREFLIGHT_SIGN_SECRET` | Override signing secret (operator use — key generation) |\n\n## Security model\n\nThis is **intentional soft security** — the signing secret ships with the package. Any determined user can reverse-engineer it. This is the same model used by tools like Laravel Spark and Gumroad license keys. The goal is honest enforcement, not cryptographic DRM.\n\nFor v2: add an optional online validation endpoint (1 API call per day) to catch key reuse across organizations.\n\n## Rotate the signing secret\n\n1. Set `PREFLIGHT_SIGN_SECRET=new-secret` when minting new keys\n2. Old keys signed with the default secret continue to work (they check against the baked-in default)\n3. At v2.0.0, remove the default fallback — all keys must use the explicit secret\n\n## License\n\nMIT\n","readmeFilename":"README.md"}