MVP slice of #445. Ship the smallest useful NIP-05 endpoint first; defer aggregation, relays, per-pod overrides to follow-ups.
Scope
Single-user mode only. Single name, single pubkey. No knobs.
GET /.well-known/nostr.json returns:
{ "names": { "<single-user-name>": "<hex pubkey from the profile VM>" } }
Where:
- <single-user-name> = the NIP-05 reserved _ name. NIP-05 §3 specifies _ as the "naked domain" identifier — the user IS the domain, no name@ prefix needed. For a single-user pod where the pod IS the server, that's the natural identifier. --single-user-name controls the WebID path (separate concern); NIP-05 in single-user mode is intrinsically single-name and uses _. A future phase can add --nip05-name <name> if alice@example.com style is wanted on a single-user pod.
- <hex pubkey> = read from /profile/card.jsonld's verificationMethod via the existing extractNostrPubkeysFromProfile helper in src/auth/nostr-keys.js. No new key-reading code, no touching /private/.
If no key is provisioned (no VM in the profile, or the VM has no Nostr-shaped pubkey), return { "names": {} }. NIP-05 verifiers handle the empty case fine.
If the server isn't in single-user mode, return 404 — multi-user aggregation is the next slice.
Public read (no WAC, no auth). Access-Control-Allow-Origin: * so browser-based Nostr clients can verify.
What this MVP doesn't ship (deferred to follow-ups)
- Multi-user aggregation (path mode) — one shared /.well-known/nostr.json listing every pod's mapping.
- Subdomain mode per-host filtering — each subdomain serves its own.
- ?name= query filtering (per NIP-05 §3) — return everything for now.
- relays field auto-populated from --nostr.
- nip46 remote signer.
- Per-pod opt-out / opt-in.
- Custom names via --nip05-name.
Acceptance
- GET /.well-known/nostr.json on a --single-user --provision-keys server returns { names: { "_": "<hex>" } }.
- Same request when no key was provisioned returns { names: {} }.
- Same request in multi-user mode returns 404.
- Access-Control-Allow-Origin: * header on the response.
- Reads the pubkey from the WebID profile's VM via the existing extractor — no new key-reading code, no touching /private/.
- Tests cover: provisioned single-user, single-user with no key, multi-user (404).
Refs #445.
Reactions are currently unavailable
MVP slice of #445. Ship the smallest useful NIP-05 endpoint first; defer aggregation, relays, per-pod overrides to follow-ups.
Scope
Single-user mode only. Single name, single pubkey. No knobs.
GET /.well-known/nostr.json returns:
{ "names": { "<single-user-name>": "<hex pubkey from the profile VM>" } }Where:
If no key is provisioned (no VM in the profile, or the VM has no Nostr-shaped pubkey), return { "names": {} }. NIP-05 verifiers handle the empty case fine.
If the server isn't in single-user mode, return 404 — multi-user aggregation is the next slice.
Public read (no WAC, no auth). Access-Control-Allow-Origin: * so browser-based Nostr clients can verify.
What this MVP doesn't ship (deferred to follow-ups)
Acceptance
Refs #445.