feat(proxy): tools/grant.js admin CLI for entitlements (PR 3/5 — premium tier)#50
Draft
DocNR wants to merge 1 commit into
Draft
feat(proxy): tools/grant.js admin CLI for entitlements (PR 3/5 — premium tier)#50DocNR wants to merge 1 commit into
DocNR wants to merge 1 commit into
Conversation
PR 3 of the premium-tier series. Phase 1 manual-grant tool — lets the
developer flip premium on for themselves + testers via SSH+CLI before
Lightning acquisition lands in Phase 2. Same data file (entitlements.json)
that the /entitlement endpoint reads.
Subcommands:
grant <npub|hex> [--note "..."] [--by "..."] [--expires-at <unix>]
revoke <npub|hex>
list [--tier free|premium]
audit [--threshold N] [--days D] (default 5 / 30d)
bootstrap-existing [--clients-file <path>] [--threshold N] (default 3)
help
Globals:
--file <path> Override entitlements.json (default ./entitlements.json)
Highlights:
- Inline NIP-19 bech32 decoder (npub → hex). No new deps.
- Pass-through for hex pubkeys; case-insensitive.
- Bech32 checksum + HRP verification — rejects nsec1, malformed inputs,
corrupted checksums.
- bootstrap-existing reads clients.json + auto-grants premium to any
signer with ≥N paired clients. Idempotent (skips already-premium).
Useful one-shot at deploy to give heavy testers headroom on the
tighter premium tier without manual per-pubkey grants.
Run on Dell:
sudo -u clave-proxy node ~/clave-proxy-test/relay-proxy/tools/grant.js \\
--file=/opt/clave-proxy-test/entitlements.json grant npub1...
Tests: 15 new (bech32 round-trip + parseArgs covering all flag forms +
checksum/HRP rejection paths). Full proxy suite green at 126/126.
Local smoke test (grant→list→revoke cycle on /tmp file):
$ node tools/grant.js --file=/tmp/test.json grant npub125f...
granted premium to 55127fc9...9b21
granted_at: 2026-05-10T01:13:15.000Z
granted_by: admin:cli
note: smoke test
expires_at: never
$ node tools/grant.js --file=/tmp/test.json list
1 entitlement entry:
55127fc9... premium effective=premium granted=... expires=lifetime devices=0
$ node tools/grant.js --file=/tmp/test.json revoke 55127fc9...
revoked premium from 55127fc9...9b21
Stacks on PR #49 (which stacks on PR #48). Will rebase if review changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
Owner
Author
|
Paused — queued for Phase 2. This is part of a server-side entitlement series (#48 → #49 → #50, plus an uncommitted iOS service layer on Preserved as draft because:
Architecture decision (Apple IAP vs Lightning device-bound vs Lightning npub-bound) deferred until there's a real monetization timeline. No action needed here. Will revisit when payment work begins. Plan: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR 3 of the premium-tier series. Phase 1 manual-grant CLI — lets you flip premium on for yourself + testers via SSH before Phase 2 Lightning acquisition lands. Same
entitlements.jsondata file that the/entitlementendpoint reads in #49.Stacks on #49 (which stacks on #48). Base branch is
feat/entitlement-endpoint. Merge order: #48 → #49 → this.Subcommands
Global flag:
--file <path>overrides the entitlements.json path (default./entitlements.json).Highlights
bootstrap-existingreadsclients.json+ auto-grants premium to any signer with ≥N paired clients. Idempotent (skips already-premium). Useful one-shot at deploy to give heavy testers (yourself + Brian etc.) headroom on the tighter premium tier without manual per-pubkey grants.How to use on Dell
The CLI runs from the source clone — no need to deploy it alongside the proxy:
Then verify:
sudo -u clave-proxy node ~/clave-proxy-test/relay-proxy/tools/grant.js \ --file=/opt/clave-proxy-test/entitlements.json listTests
--flag value,--flag=value, boolean flags, mixedLocal end-to-end smoke (grant→list→revoke cycle on /tmp file)
Files changed
relay-proxy/tools/grant.js(new, 359 lines)relay-proxy/test/grant.test.js(new, 15 tests, 118 lines)Risk
Low. Tool only — no proxy or production behavior change. Changes the on-disk state of
entitlements.jsonwhen the operator runs it; that file isn't read by anything except this CLI + the/entitlementendpoint (#49) +/pair-clientcap check (#49), both already shipped.After merge
bootstrap-existingagainst/opt/clave-proxy-test/clients.jsonto grant premium to existing heavy testers.🤖 Generated with Claude Code