Replace NRelay1 async iterator (unreliable) with nostr-tools SimplePool.subscribeMany()
using onevent callback — same pattern as Ditto/Coracle/Nostrudel.
- Switch to relay.nsec.app, relay.damus.io, relay.primal.net (support ephemeral events)
- Use nip04.decrypt() from nostr-tools for Amber's connect response decryption
- Proper cleanup of pool and subscription on abort/close
- Fall back to signerPubkey as userPubkey if NConnectSigner.getPublicKey() fails
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Completely replaces the broken NIP-55 intent approach with NIP-46:
- Amber tab: generates nostrconnect:// URI, opens Amber, waits for
Amber to connect back via relay using NLogin.fromNostrConnect()
(same pattern as Ditto/soapbox-pub)
- Bunker tab: paste bunker:// URI from Amber or nsec.app
- Extension tab: NIP-07 browser extension (desktop)
- useLoginActions: updated to match Ditto's implementation with
nostrconnect(), generateNostrConnectParams, generateNostrConnectURI
- Clean mobile-first UI — no clipboard hacks, no intent tricks
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
NIP-55 (nostrsigner: intents) is fundamentally broken from Capacitor
WebView — no combination of window.open, window.location.href, or
anchor clicks works reliably across all Android WebView versions.
Switch to NIP-46 (bunker://) which works everywhere via WebSockets:
- User opens Amber → Connect apps → Add app → copies bunker:// URI
- Pastes it into the login dialog
- NLogin.fromBunker() completes the handshake over a relay
- Login works in browser, PWA, and Capacitor APK identically
This is exactly how Ditto (soapbox-pub) implements Amber login.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Capacitor native apps fail with "malformed nostrsigner request" when
using callbackUrl because Amber treats custom URI schemes as invalid.
Fix: detect window.Capacitor.isNativePlatform() and use the no-callback
clipboard flow (openAmberForLoginNoCallback) instead of the callbackUrl
flow. Amber copies the pubkey to clipboard, app reads it on
visibilitychange when user returns.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Amber login (critical):
- Replace window.location.href with window.open(_system) in Capacitor WebViews
- Capacitor's WebView throws "malformed nostrsigner request" on href navigation
- New openAmberUrl() helper detects Capacitor via window.Capacitor.isNativePlatform()
- Add openAmberForLoginNoCallback() for PWA/Capacitor clipboard flow
- Fix all 6 Amber URL opens in amber.ts + LoginDialog.tsx
Mobile nav:
- Newsletter and Sasquatch AI (/pyramid) added to hamburger menu
- Sasquatch floating guide now shows on mobile (removed hidden md:block)
Lab page mobile:
- Action buttons (Offer Coaching/Filming/Editing/Get Card) now 2-col grid on mobile
- Service type filter (Coaches/Filmers/Editors) now 3-col grid, full width
- Reduced top padding on mobile (py-6 → py-12 on md+)
- Text truncates cleanly, icons don't overflow
Wallet page mobile:
- Reduced padding (py-6 md:py-8)
- Tab triggers use h-auto + py-2.5 to avoid overflow
- Smaller header text on mobile
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
PWA standalone mode is single-tab. Opening nostrsigner: with a callbackUrl
sends the callback to the browser (a different app), not back to the PWA.
The PWA tab is suspended and never sees the result.
Fix:
- Detect PWA standalone mode via matchMedia('(display-mode: standalone)')
- In PWA mode: open Amber WITHOUT a callbackUrl — Amber copies pubkey to
clipboard automatically when no callback is given
- Use visibilitychange to detect when user returns to PWA after approving
- Auto-read clipboard on return and complete login silently
- Manual "I approved" button now tries localStorage first (browser), then
falls back to clipboard read (PWA) — covers both contexts with one button
- Browser mode unchanged: localStorage cross-tab polling still works
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Root cause: on GrapheneOS, Amber opens /amber-callback in a BRAND NEW TAB.
login.amber() was being called in that new tab's React instance, which has
no effect on the original tab where the user is waiting.
Fix:
- AmberCallbackPage now writes pubkey to localStorage('amber_pending_pubkey')
instead of calling login.amber() — a cross-tab signal
- LoginDialog polls for 'amber_pending_pubkey' every 400ms and calls
login.amber() itself in the correct React context
- Manual "I approved" button also reads the same key
- Removed reliance on getAmberLogin() which checked the wrong localStorage key
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Root cause: window.location.href navigates the tab away entirely on Android,
destroying sessionStorage. When Amber calls back to /amber-callback the login
completes there, but returning to the dialog the state is lost.
Fixes:
- Switch from sessionStorage to localStorage for amber_return_path and
amber_login_attempt_ts — survives tab navigation on Android
- Add 500ms polling loop in handleAmberLogin that checks getAmberLogin()
every 500ms — detects when AmberCallbackPage stored the pubkey and
auto-completes login without needing visibilitychange to fire
- Add "I approved — complete login" manual button in waiting state as
explicit fallback for stuck users (reads localStorage right away)
- AmberCallbackPage now uses localStorage for all persistence
- Clean up poll interval on dialog close and unmount
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Add dedicated /amber-callback route so Amber always has a stable return URL
- Handles get_public_key (login), sign_event, nip44/nip04 encrypt/decrypt
- Shows animated processing screen while completing, then redirects back
- Add subscribeToAmberReturn() helper in amber.ts using visibilitychange
- Auto-detects when user returns to the tab after cancelling in Amber
- Resets login UI to initial state gracefully
- Update buildCallbackUrl() to use /amber-callback instead of current page URL
- Rewrite Amber tab in LoginDialog:
- Remove 2-step clipboard paste flow entirely
- Single tap opens Amber, login completes automatically on return
- Waiting state shows animated dots + cancel button
- No manual pubkey entry needed
- Save return path in sessionStorage so AmberCallbackPage redirects user back
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The entire skate-spots codebase was accidentally copied into src/src/ and
public/public/ instead of src/ and public/ directly. This left the real
src/ directory as blank MKStack template stubs, explaining why the landing
page showed the default template instead of SkateSpots.
Changes made:
- Copied all files from src/src/ up to src/ (App.tsx, AppRouter.tsx, main.tsx,
all pages, components, hooks, contexts, lib, i18n, test)
- Copied all files from public/public/ up to public/ (images, manifest, etc.)
- Deleted src/src/ and public/public/ nested directories
- Removed HelloWorld.tsx template stub from pages/
- Retained the previously fixed index.css (Tailwind v3 directives)
Full skate-spots feature set is now active:
- All 30+ routes (map, events, spots, coaches, marketplace, wallet, etc.)
- NWCProvider, LanguageProvider, PWAInstallPrompt, AmberCallbackHandler
- Skate community relays (goskatespots.nostr1.com, wotr.relatr.xyz, etc.)
- Outfit Variable font, Amber pre-check in main.tsx
- All hooks (useSkateSpots, useCoaches, useZaps, etc.)
- i18n support (en/es)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-15 22:18:28 +07:00
Renamed from src/src/components/auth/LoginDialog.tsx (Browse further)