Epic: rework pending signer requests (perf, multi-account, widget scope)
Labels: enhancement
Context
Interactive signers (NIP-46 bunker, NIP-55 signer app, NIP-07 extension) expose the
requests waiting for user approval through EventSigner.pendingRequestsStream.
NPendingRequests in ndk_flutter renders them as a floating panel.
Three problems, one root cause each.
1. The stream is quadratic
Every signer registers a request in its internal map before the concurrency
throttle, and _notifyPendingRequestsChange() rebuilds the whole list on every
add and every remove. For n requests that is 2n emissions, each O(n).
2. It is single-account by construction
NPendingRequests subscribes to getLoggedAccount().signer.pendingRequestsStream
only. Accounts.accounts holds every logged-in account, each with its own live
signer, so requests belonging to any other account are invisible. Switching
accounts silently drops in-flight requests from the UI, and cancelRequest routes
to the logged account's signer, where the request id does not exist, so the cancel
button is a silent no-op.
3. The widget does too much and too little
It ships an expand/collapse panel with a request list, per-request metadata and a
cancel button, which is a worse version of a dedicated screen (see
packages/sample-app/lib/pending_requests_page.dart, 694 lines, doing the same
thing properly). At the same time it cannot represent more than one account.
A floating AnimatedPositioned panel also collides with FABs, bottom navigation,
snackbars and the keyboard on mobile.
Direction
The value of the package is the plumbing, not the pixels.
Ship a headless aggregation API in ndk that any consumer can use, plus a minimal
placeable counter in ndk_flutter that calls back into the host app. The host app
builds its own dedicated screen.
This also dissolves the multi-account problem instead of solving it: a count
aggregates across accounts trivially, a flat list does not (it would need grouping,
per-account identity, and per-signer cancel routing).
Plan
Sequential, each one depends on the previous:
- #TBD Coalesce pending-request stream emissions (perf, no API change)
- #TBD Make
PendingSignerRequest.signerPubkey reliable
- #TBD Expose an aggregated pending-requests stream across all accounts
- #TBD Replace
NPendingRequests with a placeable counter
- #TBD Sample app: adopt the counter, make the pending requests page multi-account
1 and 2 touch the same three signer files, so they must not be worked on in
parallel. 5 is the acceptance test for 3: if it is painful to write, 3 is wrong.
Epic: rework pending signer requests (perf, multi-account, widget scope)
Labels:
enhancementContext
Interactive signers (NIP-46 bunker, NIP-55 signer app, NIP-07 extension) expose the
requests waiting for user approval through
EventSigner.pendingRequestsStream.NPendingRequestsinndk_flutterrenders them as a floating panel.Three problems, one root cause each.
1. The stream is quadratic
Every signer registers a request in its internal map before the concurrency
throttle, and
_notifyPendingRequestsChange()rebuilds the whole list on everyadd and every remove. For n requests that is 2n emissions, each O(n).
2. It is single-account by construction
NPendingRequestssubscribes togetLoggedAccount().signer.pendingRequestsStreamonly.
Accounts.accountsholds every logged-in account, each with its own livesigner, so requests belonging to any other account are invisible. Switching
accounts silently drops in-flight requests from the UI, and
cancelRequestroutesto the logged account's signer, where the request id does not exist, so the cancel
button is a silent no-op.
3. The widget does too much and too little
It ships an expand/collapse panel with a request list, per-request metadata and a
cancel button, which is a worse version of a dedicated screen (see
packages/sample-app/lib/pending_requests_page.dart, 694 lines, doing the samething properly). At the same time it cannot represent more than one account.
A floating
AnimatedPositionedpanel also collides with FABs, bottom navigation,snackbars and the keyboard on mobile.
Direction
The value of the package is the plumbing, not the pixels.
Ship a headless aggregation API in
ndkthat any consumer can use, plus a minimalplaceable counter in
ndk_flutterthat calls back into the host app. The host appbuilds its own dedicated screen.
This also dissolves the multi-account problem instead of solving it: a count
aggregates across accounts trivially, a flat list does not (it would need grouping,
per-account identity, and per-signer cancel routing).
Plan
Sequential, each one depends on the previous:
PendingSignerRequest.signerPubkeyreliableNPendingRequestswith a placeable counter1 and 2 touch the same three signer files, so they must not be worked on in
parallel. 5 is the acceptance test for 3: if it is painful to write, 3 is wrong.