executeRetry now fires the same onZapSuccess hook as the main send path with
the retried shares' proof, so a zap completed via the retry flow gets its
optimistic bump and preimage-verified tally publish too (was previously only
on the first-attempt path). Closes the retry-path item in the plan checklist.
Co-Authored-By: Claude Fable 5 <[email protected]>
Third slice of docs/zap-tally-plan.md §5.3-5.5 — the publish side:
- zapSplit.js: surface receipt.preimage (NWC pay_invoice result.preimage).
- zapController.js: onZapSuccess now forwards per-share proof
{recipientType, amountSats, bolt11, preimage, zapRequest} for every settled
share with a preimage.
- zapTallyPublisher.js (new): buildTallyFromShare (pure — builds the addressable
tally from a share's bolt11/preimage/zap-request, d=payment_hash, pointers
from the zap request) + publishZapTallies (best-effort, flag-gated, never
throws).
- ModalManager.js: onZapSuccess keeps the instant optimistic bump AND publishes
the tallies via nostrClient.signAndPublishEvent to write relays (an
all-timeout publish is a soft success per #49). A publish failure is
non-fatal — the durable local ledger still shows the sender their zap.
With the counting slice (025ab348), a sent zap now: shows instantly (ledger),
publishes a verified tally, and every bitvid client counts it — surviving the
recipient never publishing a 9735. Tests: tests/zap-tally-publisher.test.mjs
(5). Lint + build green.
Co-Authored-By: Claude Fable 5 <[email protected]>
Mirrors ingestLocalViewEvent for view counts: sending a zap through the
video modal now bumps that video's zap total immediately on the card + modal
badge, instead of waiting for the relay receipt (delayed by the 2-min cache
TTL, and dependent on the recipient's wallet actually publishing a 9735).
- zapTotals store tracks optimisticSats separately from real receipt sats;
getSnapshot/request return the sum. When the real receipt for the pointer
later arrives, runBatch clears the optimistic portion so it's never
double-counted. If the receipt never lands (custodial wallets often don't
publish), the bump persists in-memory until reload — keeping the zapper's
own view honest.
- ZapController fires a new onZapSuccess({video, sats}) at the fully-success
terminal point (sats = context.shares.total; both creator + platform shares
tag the video, so the eventual relay total matches).
- ModalManager derives the pointer via app.deriveVideoPointerInfo (the SAME
key the cards/modal subscribe with) and calls ingestLocalVideoZap.
Live-verified: a rendered card's badge went 0 sats -> 5K sats instantly on
ingest, no relay round-trip. Test covers the bump + replace-on-real-receipt.
Co-Authored-By: Claude Fable 5 <[email protected]>
Two fixes from live testing:
- "NWC doesn't sync unless I click Restore": devices with sync ENABLED only
ever pushed-on-save — edits from another device sat unseen until the
manual Restore click. encryptedSyncItem.autoPullIfNewer pulls the remote
note at login when its created_at is newer than this device's last-synced
marker (set on push AND now after a successful pull, so the same note is
never re-pulled and the next conflict check stays honest). Wired into the
login restore flow ahead of the one-time offer; disabled items are never
touched.
- "Could not get user information" on a known-good creator address: that
reason string comes from the LNURL SERVER, and the failing fetch was the
PLATFORM-FEE address, not the creator's. prepareLightningContext now
wraps both metadata fetches so the toast names which address failed
(e.g. "Platform fee Lightning address (…): Could not get user
information") instead of blaming the creator.
Co-Authored-By: Claude Fable 5 <[email protected]>
- NWC connection was fully broken: parseNwcUri passed a hex secret to
nostr-tools getPublicKey (needs Uint8Array) and threw. Convert hex->bytes.
- A successful zap was shown as a red error when the kind-9735 receipt
couldn't be validated. The NWC preimage already proves payment, so a
paid-but-unconfirmed share is now a success-with-note, not a failure.
- Receipt discovery: query by the reliably-indexed #e/#a/#p tags instead of
#bolt11 (which most relays don't index), and poll a few times since the
receipt is published shortly after payment.
- In-flight "Sending..." status no longer mis-toned as a warning; success
path fully resets the form; an in-flight-open click no longer cancels the
open (which made the popover need many clicks); fee fallback verified
no-bypass.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
I modified `js/channelProfile.js` to implement the logic that toggles the "Send" button to "Done" and closes the dialog when clicked. Additionally, I updated `js/ui/zapController.js` to prevent the form from resetting entirely on success, which preserves receipts; instead, it now manually clears the comment and sets the completed state.
These changes ensure consistent "Done" button behavior across both the Channel Profile and Video Modal zap interfaces. I also included minor `package.json` updates for linting dependencies.