mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 15:07:10 +02:00
cffb981ad14779f87c19ad361e87a866cb4fc3d2
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cffb981ad1 |
feat: add emoji set address as 4th param in NIP-30 emoji tags
NIP-30 allows an optional 4th tag parameter specifying the source emoji set address (e.g. "30030:pubkey:identifier"). This threads that address through the full emoji pipeline so it appears in posts, replies, reactions, and zap requests. - Add local blueprints.ts with patched NoteBlueprint, NoteReplyBlueprint, GroupMessageBlueprint, and ReactionBlueprint that emit the 4th param; marked TODO to revert once applesauce-common supports it upstream - Add address? to EmojiWithAddress, EmojiTag, EmojiSearchResult, and EmojiTag in create-zap-request - Store address in EmojiSearchService.addEmojiSet (30030:pubkey:identifier) - Thread address through both editor serializers (MentionEditor, RichEditor) and the emoji node TipTap attributes - Fix EmojiPickerDialog to pass address when calling onEmojiSelect and when re-indexing context emojis - Update SendMessageOptions.emojiTags and sendReaction customEmoji param to use EmojiTag throughout the adapter chain Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
97dd30f587 |
Add anonymous zap option with throwaway signer (#154)
* feat: add anonymous zap option Add "Zap anonymously" checkbox that allows users to send zaps without revealing their identity. When enabled, creates a throwaway keypair to sign the zap request instead of using the active account's signer. This also enables users without a signer account to send zaps by checking the anonymous option. * feat: prioritize recipient's inbox relays for zap receipts Add selectZapRelays utility that properly selects relays for zap receipt publication with the following priority: 1. Recipient's inbox relays (so they see the zap) 2. Sender's inbox relays (so sender can verify) 3. Fallback aggregator relays This ensures zap receipts are published where recipients will actually see them, rather than just the sender's relays. Includes comprehensive tests for relay selection logic. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
3f811ed072 |
feat: zap action for chat (#151)
* feat: add configurable zap tagging for chat messages Implements a protocol adapter interface for configuring how zap requests should be tagged for chat messages. This enables proper NIP-53 live activity zapping with appropriate a-tag and goal e-tag support. Changes: - Add ZapConfig interface to base-adapter for protocol-specific zap configuration - Add getZapConfig() method to ChatProtocolAdapter (default: unsupported) - Implement getZapConfig() in NIP-53 adapter with proper tagging: - Always a-tag the live activity (kind 30311) - If zapping host with goal, also e-tag the goal event - Add goal tag parsing to live-activity.ts and types - Update createZapRequest to accept custom tags parameter - Add Zap action to ChatMessageContextMenu (shown when supported) - Update ZapWindow to pass custom tags through to zap request - NIP-29 groups inherit default (unsupported) behavior * feat: add custom tags and relays to zap command Extends the zap command to support custom tags and relay specification, enabling full translation from chat zap config to zap command. Changes: - Add -T/--tag flag to specify custom tags (type, value, optional relay hint) - Add -r/--relay flag to specify where zap receipt should be published - Update ZapWindow to accept and pass through relays prop - Update ChatMessageContextMenu to pass relays from zapConfig - Update man page with new options and examples - Add comprehensive tests for zap parser flag handling Example usage: zap npub... -T a 30311:pk:id wss://relay.example.com zap npub... -r wss://relay1.com -r wss://relay2.com * fix: include event pointer when zapping chat messages Pass the message event as eventPointer when opening ZapWindow from chat context menu. This enables: - Event preview in the zap window - Proper window title showing "Zap [username]" * feat: add zap command reconstruction for Edit feature Add zap case to command-reconstructor.ts so that clicking "Edit" on a zap window title shows a complete command with: - Recipient as npub - Event pointer as nevent/naddr - Custom tags with -T flags - Relays with -r flags This enables users to see and modify the full zap configuration. * fix: separate eventPointer and addressPointer for proper zap tagging - Refactor createZapRequest to use separate eventPointer (for e-tag) and addressPointer (for a-tag) instead of a union type - Remove duplicate p-tag issue (only tag recipient, not event author) - Remove duplicate e-tag issue (only one e-tag with relay hint if available) - Update ZapConfig interface to include addressPointer field - Update NIP-53 adapter to return addressPointer for live activity context - Update ChatMessageContextMenu to pass addressPointer from zapConfig - Update command-reconstructor to properly serialize addressPointer as -T a - Update ZapWindow to pass addressPointer to createZapRequest This ensures proper NIP-53 zap tagging: message author gets p-tag, live activity gets a-tag, and message event gets e-tag (all separate). * refactor: move eventPointer to ZapConfig for NIP-53 adapter - Add eventPointer field to ZapConfig interface for message e-tag - NIP-53 adapter now returns eventPointer from getZapConfig - ChatMessageContextMenu uses eventPointer from zapConfig directly - Remove goal logic from NIP-53 zap config (simplify for now) This gives the adapter full control over zap configuration, including which event to reference in the e-tag. * fix: update zap-parser to return separate eventPointer and addressPointer The ParsedZapCommand interface now properly separates: - eventPointer: for regular events (nevent, note, hex ID) → e-tag - addressPointer: for addressable events (naddr) → a-tag This aligns with ZapWindowProps which expects separate fields, fixing the issue where addressPointer from naddr was being passed as eventPointer and ignored. * feat: improve relay selection for zap requests with e+a tags When both eventPointer and addressPointer are provided: - Collect outbox relays from both semantic authors - Include relay hints from both pointers - Deduplicate and use combined relay set Priority order: 1. Explicit params.relays (respects CLI -r flags) 2. Semantic author outbox relays + pointer relay hints 3. Sender read relays (fallback) 4. Aggregator relays (final fallback) * fix: pass all zap props from WindowRenderer to ZapWindow WindowRenderer was only passing recipientPubkey and eventPointer, dropping addressPointer, customTags, and relays. This caused CLI flags like -T (custom tags) and -r (relays) to be ignored. Now all parsed zap command props flow through to ZapWindow and subsequently to createZapRequest. * refactor: let createZapRequest collect relays from both authors Remove top-level relays from NIP-53 zapConfig so createZapRequest can automatically collect outbox relays from both: - eventPointer.author (message author / zap recipient) - addressPointer.pubkey (stream host) The relay hints in the pointers are still included via the existing logic in createZapRequest. * fix: deduplicate explicit relays in createZapRequest Ensure params.relays is deduplicated before use, not just the automatically collected relays. This handles cases where CLI -r flags might specify duplicate relay URLs. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
f56228f88a |
fix: remove double URL encoding in zap requests (#145)
The zap request JSON was being encoded twice:
1. Manually via encodeURIComponent in serializeZapRequest()
2. Automatically by URLSearchParams.set() when building callback URL
This caused overly-encoded URLs (e.g., '{' → '%7B' → '%257B').
Fix: Remove manual encoding and let URLSearchParams handle it.
Verified: Tests pass, build succeeds
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
72fb47224c |
feat: add NIP-57 zap command foundation (#141)
* feat: add NIP-57 zap command foundation Implements the foundational structure for sending Lightning zaps (NIP-57) to Nostr users and events. This commit adds the command interface, UI components, and routing logic. The actual LNURL resolution and zap request creation will be implemented in follow-up commits. Components Added: - ZapWindow: Full-featured UI for zapping with amount presets, custom amounts, wallet integration, and QR code fallback - parseZapCommand: Parser supporting multiple formats (npub, nprofile, nevent, naddr, NIP-05, $me alias) - Command registration in man pages with examples - Window routing and title generation Features: - Preset amount buttons (21, 100, 500, 1000, 5000, 10000 sats) - Custom amount input - Amount usage tracking (remembers most-used amounts) - Comment field for zap messages - Event context rendering (shows zapped event in UI) - Dual payment methods: NWC wallet or QR code/invoice copy - Dynamic recipient resolution (from event author if zapping event) Usage: zap fiatjaf.com # Zap a user by NIP-05 zap npub1... # Zap a user by npub zap nevent1... # Zap an event (recipient = author) zap npub1... nevent1... # Zap specific user for specific event Next Steps: - Implement LNURL-pay resolution (fetch callback URL and nostrPubkey) - Create kind 9734 zap request event with applesauce factory - Implement invoice generation via LNURL callback - Integrate NWC wallet payment - Add zap action to event context menus - Implement zap receipt listening (kind 9735) * feat: implement full NIP-57 zap flow with LNURL and NWC Completes the production-ready implementation of Lightning zaps (NIP-57) with full LNURL-pay resolution, zap request creation, NWC wallet payment, and QR code fallback. Core Implementation: 1. **LNURL Resolution** (src/lib/lnurl.ts) - Resolve Lightning addresses (lud16) to LNURL-pay endpoints - Validate zap support (allowsNostr, nostrPubkey) - Fetch invoices from LNURL callbacks with zap requests - Amount validation (min/max sendable) - Comment length validation 2. **Zap Request Creation** (src/lib/create-zap-request.ts) - Build kind 9734 zap request events using applesauce EventFactory - Sign with user's active account - Include recipient (p tag), amount, relays, optional event context (e/a tags) - Serialize to URL-encoded JSON for LNURL callbacks - Smart relay selection (user's inbox relays for zap receipts) 3. **ZapWindow Complete Flow** (src/components/ZapWindow.tsx) - Resolve recipient's Lightning address from profile (lud16) - Create and sign zap request with user credentials - Fetch invoice from LNURL callback - Pay with NWC wallet OR show QR code - QR code generation with qrcode library - Success feedback with LNURL success actions - Comprehensive error handling and user notifications - Toast notifications for each step 4. **Event Menu Integration** (src/components/nostr/kinds/BaseEventRenderer.tsx) - Add "Zap" action to event dropdown menu - Automatically includes event context (e or a tag) - Yellow zap icon (⚡) for visual consistency - Opens ZapWindow with pre-filled recipient and event Flow Diagram: 1. User clicks "Zap" on event or runs `zap` command 2. Resolve recipient's lud16 → LNURL-pay endpoint 3. Validate zap support (allowsNostr, nostrPubkey) 4. Create kind 9734 zap request (signed by sender) 5. Send to LNURL callback → get BOLT11 invoice 6. Pay via NWC wallet OR show QR code 7. Zap receipt (kind 9735) published by LNURL service Features: - ✅ Full NIP-57 compliance - ✅ LNURL-pay support with validation - ✅ Applesauce EventFactory for signing - ✅ NWC wallet integration - ✅ QR code fallback for manual payment - ✅ Event context (zapping specific notes/articles) - ✅ Amount presets with usage tracking - ✅ Custom amounts and comments - ✅ Comprehensive error handling - ✅ Step-by-step user feedback - ✅ Event menu integration Security: - Uses user's active account signer - Validates LNURL responses - Validates amount ranges - No private key exposure - HTTPS-only LNURL endpoints Dependencies: - qrcode: QR code generation - applesauce-core: EventFactory for signing - Existing NWC wallet implementation Related: #135 (NWC wallet viewer) Implements: NIP-57 (Lightning Zaps) * fix: resolve TypeScript errors in ZapWindow - Remove unused imports (useEffect, isAddressableKind, NostrEvent) - Fix walletInfo access: fetch from getInfo() hook instead of direct property - Store wallet info in component state with useEffect - All TypeScript syntax errors resolved * fix: resolve all TypeScript build errors in zap implementation - ZapWindow.tsx: Import useProfile from @/hooks/useProfile instead of applesauce-react/hooks - ZapWindow.tsx: Remove Tabs import (unused) - ZapWindow.tsx: Remove htmlFor prop from Label components (not supported) - create-zap-request.ts: Remove non-existent EventTemplate import - create-zap-request.ts: Use inferred type for template object - lnurl.ts: Prefix unused lnurl parameter with underscore All TypeScript compilation errors resolved. Code ready for production build. * fix: correct useProfile usage and ProfileContent handling in ZapWindow - Remove eventStore argument from useProfile (takes pubkey and optional relay hints) - Fix recipientProfile usage: already ProfileContent, don't call getProfileContent again - Fix authorProfile: call getProfileContent on NostrEvent, not on ProfileContent - Fix lud16/lud06 access: use recipientProfile directly - Fix success toast: use recipientProfile?.name instead of content?.name All type errors resolved. ProfileContent is returned by useProfile, not NostrEvent. * feat: refine ZapWindow UI and add dynamic window title UI Refinements per user request: - Remove QrCode unused import - Simplify payment flow to single adaptive button - Button shows "Log in to Zap" if user can't sign - Button shows "Pay with Wallet" if NWC available, else "Pay" - Fix activeAccount usage to use accountManager.active - Remove unused getProfileContent import - Remove unused eventAuthorName variable Dynamic Title: - Add "Zap [username]" dynamic title in DynamicWindowTitle - Fetches recipient profile and displays name or fallback - Shows recipient's display name, name, or truncated pubkey Build fixes: - Fix TypeScript errors with unused imports - Fix activeAccount.signer property access - All tests passing (939 passed) * feat: add emoji autocompletion to zap comments and refine UI Zap Comment Enhancements: - Replace plain Input with MentionEditor for emoji autocompletion - Add NIP-30 emoji tag support to zap requests (kind 9734) - Emoji tags are properly serialized and included in zap events - Support :emoji: syntax with custom emoji from emoji search Event Preview Refinements: - Remove Card wrapper from zapped event preview - Remove padding and borders for cleaner display - Event renders directly without container styling Implementation Details: - Add EmojiTag interface to create-zap-request.ts - Update ZapRequestParams to include emojiTags array - Extract emoji tags from MentionEditor in handleZap - Pass emoji tags through zap request creation pipeline - Add useProfileSearch and useEmojiSearch hooks to ZapWindow - Use MentionEditor ref to get serialized content with emojis All tests passing (939 passed) Build successful * feat: compact ZapWindow UI and improve debugging UI Improvements: - Reduce padding from p-6 to p-4 and space-y-6 to space-y-3 - Convert amount grid to single-row flex layout with gap-1.5 - Add formatAmount() helper for shortened numbers (21, 1k, 5k, 10k) - Move custom amount input inline with preset amounts - Reduce button size to "sm" for more compact display - Remove separate label for custom amount - Make comment field more compact (removed min-height) Debugging Enhancements: - Add console.log for recipient profile and lud16/lud06 - Add logging for LNURL resolution steps - Add logging for zap request creation - Add logging for invoice fetch from callback - Add debug logging for emoji search service initialization - Test emoji search on mount to verify it's working Number Format: - 21 → "21" - 1000 → "1k" - 5000 → "5k" - 10000 → "10k" - Handles decimals: 1500 → "1.5k" The compact layout makes better use of vertical space and provides comprehensive debug logging to help troubleshoot LNURL and emoji issues. All tests passing (939 passed) Build successful * fix: open LoginDialog instead of connection window for zap login Changes: - Import LoginDialog component into ZapWindow - Add showLogin state to control LoginDialog visibility - Update handleLogin to open LoginDialog instead of connection window - Remove unused useGrimoire import and addWindow destructuring - Add LoginDialog component to render alongside QR dialog User Experience: - "Log in to Zap" button now opens proper login dialog - Users can log in with extension, readonly, nsec, or NIP-46 - After login, user can proceed with zap flow - More intuitive than opening relay connection window All tests passing (939 passed) Build successful * feat: auto-close ZapWindow after successful wallet payment Changes: - Add onClose callback prop to ZapWindowProps interface - Pass onClose from WindowRenderer to ZapWindow component - Call onClose() with 1.5s delay after successful wallet payment - Allow user to see success toast before window closes User Experience: - After zapping with wallet, window automatically closes - 1.5 second delay allows user to see success message - Prevents accidental double-zapping - Cleaner flow - no manual window closing needed Implementation: - WindowRenderer passes onClose callback to ZapWindow - ZapWindow calls onClose after payment success and toasts - setTimeout(onClose, 1500) provides brief delay for UX - QR code path unchanged (window stays open for payment) All tests passing (939 passed) Build successful * feat: full-width custom amount and wallet timeout with QR fallback Custom Amount Input: - Change custom amount input from w-24 to flex-1 - Now takes full remaining width in flex row - Better UX on smaller screens and more obvious input field Wallet Payment Timeout Handling: - Add 30 second timeout to wallet payments using Promise.race - On timeout, automatically show QR code as fallback - Add paymentTimedOut state to track timeout condition - Toast warning when payment times out Retry with Wallet Feature: - Add handleRetryWallet function to retry timed out payment - Show "Retry with Wallet" button in QR dialog when timed out - Button only appears if wallet is connected and payment capable - Retry uses same 30s timeout, shows error if fails again - Provides loading state with spinner during retry User Flow: 1. User attempts wallet payment 2. If timeout after 30s, shows QR code automatically 3. User can scan QR to pay manually OR 4. User can click "Retry with Wallet" to try again 5. If retry times out, stays on QR for manual payment Implementation Details: - Promise.race between payInvoice and 30s timeout - Timeout throws Error("TIMEOUT") for easy detection - QR dialog conditionally shows retry button - Retry resets state and attempts payment again - Console logging for debugging timeout issues All tests passing (939 passed) Build successful * feat: production-ready zaps with manual close and profile integration Payment Flow Improvements: - Remove auto-close after successful payment - Change "Zap Sent!" button to "Done" button that requires user click - User must manually close window by clicking Done after payment - Retry payment also requires manual close after success Profile Viewer Integration: - Add Zap icon next to lightning address in ProfileViewer - Click zap icon to open ZapWindow for that profile - Yellow icon with hover effect for visual feedback - Integrates seamlessly with existing profile UI Production Cleanup: - Remove all debug console.log statements - Keep console.error for production error logging - Remove unused emojiService variable from useEmojiSearch - Fix Loader2 className typo (animate-spin) - Clean code ready for production deployment User Experience: 1. View profile with lightning address 2. Click yellow zap icon to open zap window 3. Enter amount and optional comment 4. Pay with wallet (or QR code if timeout) 5. See success message 6. Click "Done" to close window (manual control) Testing: - All lint checks pass (no errors, only warnings) - TypeScript build successful - All 939 tests passing - Production-ready code Code Quality: - No debug logging in production - Proper error handling maintained - Clean, maintainable code - Follows project conventions * fix: remove duplicate zapTitle condition in DynamicWindowTitle Removed duplicate zapTitle if-else branch at line 870 that was causing lint error. The first zapTitle condition at line 803 handles all cases, making the second occurrence unreachable. * feat: improve zap UX with inline QR and faster imports - Move imports to top level instead of dynamic imports for faster resolution - Show QR code inline in ZapWindow instead of separate dialog - Show recipient name and address when not zapping an event - Make Lightning address clickable in ProfileViewer with icon on left - Use recipientName consistently throughout zap flow This significantly reduces the "Resolving Lightning address..." delay and provides a cleaner, more integrated UX for viewing and paying invoices. * feat: optimize zap UX with better error handling and UI improvements LNURL improvements: - Add 10s timeouts to Lightning address resolution and invoice fetching - Better error messages with more context (response status, error text) - Handle AbortError for timeout scenarios UI improvements: - Bigger amount buttons (default size instead of sm) - Custom amount on separate line for better layout - Disable all zap UI when recipient has no Lightning address - Show clear warning when Lightning address is missing - Only show comment editor when Lightning address is available Toast cleanup: - Remove chatty info toasts ("Resolving...", "Creating...", "Fetching...") - Only show errors and success messages - Cleaner, less noisy UX This addresses common issues with LNURL requests timing out and makes the UI more responsive and informative when zaps cannot be sent. * feat: full-width custom amount and wallet timeout with QR fallback QR code improvements: - Add profile picture overlay in center of QR code (25% size, circular) - Remove redundant "Copy Invoice" button (keep icon button only) - Show "Open in Wallet" as full-width button UI improvements: - Use UserName component everywhere (clickable, styled, shows Grimoire members) - Custom amount now full-width on separate line - Better visual hierarchy Default amounts updated: - Changed from [21, 100, 500, 1000, 5000, 10000] - To [21, 420, 2100, 42000] - More aligned with common zap amounts The profile picture overlay helps users identify who they're zapping while maintaining QR code scannability. UserName component provides consistent styling and clickable profile links. --------- Co-authored-by: Claude <noreply@anthropic.com> |