widget: make an unmounted-widget teardown loud, not a silent hang

Removing <bitlogin-auth> from the DOM terminates its crypto worker. A host
that re-renders surrounding markup (framework diff, htmx swap, innerHTML
reset) can do this incidentally, after which signing calls fail -- and the
failure was hard to diagnose.

Two guardrails:

- disconnectedCallback logs a console.error when the element is removed
  while a session (BitLogin account or NIP-07/46) is active, naming the
  unmount as the cause and pointing at the README "Integration gotcha".
- WorkerClient.terminate(reason) records the reason; both in-flight calls
  (via failAll) and any later call (via the dead-flag path) reject with it,
  so an unmounted widget produces one legible error message instead of a
  bare or mismatched one. The dead flag already prevented the infinite
  hang; this makes the cause visible and unifies the wording.

Adds worker/workerClient.test.ts (fake Worker) covering both rejection
paths. Updates the README gotcha paragraphs from "hangs forever with no
error" to the new loud-rejection behavior.

Addresses the "unmount guardrail" 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 19:25:59 -04:00
1 parent c9791b9840
commit 86d7ee0114
5 files changed
+111 -15

No files matched your search

+11 -6
View File
@@ -386,12 +386,17 @@ how much they cost.
### Medium
- **The unmount-kills-the-worker footfooter deserves a guardrail.** The docs
warn that removing `<bitlogin-auth>` tears down the crypto worker and hangs
every later signing call with no error. I hit exactly this. Consider: (a) a
console.error when the element is disconnected while a session is active, and
(b) `signEvent` rejecting with a clear "widget was unmounted" error instead of
hanging forever. Silent infinite-hang is the worst failure mode.
- **[DONE 2026-08-11] The unmount-kills-the-worker footgun now has a guardrail.**
The docs warned that removing `<bitlogin-auth>` tears down the crypto worker
and hangs every later signing call with no error. **Shipped both asks:**
(a) `disconnectedCallback` now logs a `console.error` when the element is
removed while a session is active, naming the unmount and pointing at the
README "Integration gotcha"; and (b) `WorkerClient.terminate(reason)` records
the reason and `signEvent`/`getPublicKey`/etc. — whether in-flight at teardown
or issued afterward — reject with that message instead of hanging (the
`dead`-flag path already prevented the infinite hang; this makes the *cause*
legible and unifies the message). Covered by `worker/workerClient.test.ts`;
README gotcha paragraphs updated to say "rejects loudly," not "hangs forever."
- **Styling hooks / CSS parts.** The widget renders in a shadow root, so a host
can only frame it, not theme it. A few `::part()` hooks (button, panel, text)
would let it match a host design system instead of looking pasted in. Tessera