widget: headless signer — restore + sign without the custom element

The element was the only way to sign, so a host that renders its own UI, a
background job, or a headless test couldn't sign without mounting
<bitlogin-auth>. Add @bitlogin/widget/headless: createHeadlessSigner() → a
DOM-free wrapper over the crypto worker exposing restore, getPublicKey,
signEvent, nip44Encrypt/Decrypt, isUnlocked, logout, destroy.

It restores the cached session and signs with no element and no window.nostr.
It deliberately cannot interactively log in (that needs the password UI):
restore() returns null when nothing is cached, at which point the host mounts
<bitlogin-auth> once; after that the headless signer works across reloads.

New bitlogin-headless.js build entry + @bitlogin/widget/headless export
(also re-exported from @bitlogin/widget). Covered by headless.test.ts with a
scripted worker; README gains "Signing without the widget (headless)".

Addresses the "headless session-restore API" item of the Tessera integration
feedback (docs/TODO.md).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BXQCvJPA6sVSQ5j8uBd9bB
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-08-11 22:54:14 -04:00
1 parent 5ae41ed9db
commit b8b19599e0
7 files changed
+245 -5

No files matched your search

+10 -4
View File
@@ -379,10 +379,16 @@ how much they cost.
Remaining polish: have the widget also record the profile display `name` once
fetched (currently `name` is only set when the caller supplies it), and add an
`@bitlogin/widget/session` `.d.ts` (tracked under the Small item below).
- **A headless session-restore API.** Related: expose session restore +
`getPublicKey`/`signEvent` without the custom element, so a host app can wire
its own UI and only load the visual widget for login/management. Right now the
element is the only entry point.
- **[DONE 2026-08-11] A headless session-restore API.** Shipped
`@bitlogin/widget/headless` (`bitlogin-headless.js`): `createHeadlessSigner()`
→ `restore()` / `getPublicKey()` / `signEvent()` / `nip44Encrypt|Decrypt` /
`isUnlocked()` / `logout()` / `destroy()`, a DOM-free wrapper over the crypto
worker. It restores the cached session and signs with no custom element and no
`window.nostr`; it deliberately can't interactively log in (`restore()`
returns null when nothing is cached → mount `<bitlogin-auth>` once). Covered by
`headless.test.ts` (scripted-worker); also re-exported from `@bitlogin/widget`;
README "Signing without the widget (headless)". Deploy alongside
`cryptoWorker.js` + shared chunks.
### Medium