Commit Graph

1046 Commits

Author SHA1 Message Date
Jeff Emmett df77c9c903 feat(shell): cross-tab sync via BroadcastChannel + keyboard shortcuts & swipe gestures
Add BroadcastChannel for instant same-browser tab sync — opening/closing
tabs in one window propagates immediately to sibling tabs. Extract
reconcileRemoteLayers() helper shared by BroadcastChannel and Automerge,
which cleans up cached DOM panes on remote removal and handles
active-tab-closed scenarios.

Also adds configurable rApp shortcuts (Ctrl/Alt+1-9), header swipe
gestures for rApp cycling, and body data-module-id attr for swipe context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 13:04:31 -07:00
Jeff Emmett 8741f5dbd5 feat(rnotes): add presence indicators on notebook cards and note items
Show colored dots on notebook cards and note list items indicating which
peers are currently viewing/editing. Uses existing presence message relay
with zero server changes — heartbeat every 10s, stale peer GC at 20s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:43:04 -07:00
Jeff Emmett ad9e54dbe9 refactor(rinbox): replace forwarding banner with popup modal
Convert inline forwarding banner to a click-triggered modal overlay.
Fix API field name bug (data.target → data.forwardsTo). Add email
input for no-email state with sovereignty messaging. Remove dismiss
logic in favor of modal open/close.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:15:53 -07:00
Jeff Emmett 42a84cb72e refactor(rsocials): consolidate threads + thread editor into single nav item
The thread gallery already has a "New Thread" button linking to the editor,
so a separate hub button and subnav pill for the editor is redundant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:11:24 -07:00
Jeff Emmett d9b298a56e chore(backlog): add CrowdSurf integration task definitions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:00:14 -07:00
Jeff Emmett 88c6c70f9e fix(rmaps): add cache-busting version to JS/CSS script tags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:56:35 -07:00
Jeff Emmett 8bd8348529 feat(encryptid): fix DID consistency, add PRF key derivation, stepper signup, and magic link login
- Fix DID mismatch: server now stores and reads proper did🔑z6Mk... DIDs
  from database instead of deriving truncated did🔑${slice(0,32)}
- Add PRF extension to WebAuthn create/get flows for client-side key derivation
- Derive DID, signing keys, encryption keys, and EOA wallet from passkey PRF
- Auto-upgrade truncated DIDs to proper format on sign-in
- Add POST /api/account/upgrade-did endpoint for DID migration
- Add 5-step educational registration wizard (identity, passkey, DID, wallet, security)
- Add email/username field to sign-in for scoped passkey selection
- Add magic link email login for external devices without passkeys
- Add POST /api/auth/magic-link and GET /magic-login verification page
- Add mintWelcomeBalance() for 5 fUSDC to new users
- Store EOA wallet address during registration when PRF available

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:29:20 -07:00
Jeff Emmett db61e54d7b feat(rmaps): mobile UX overhaul — floating FAB menu, self-marker, bottom sheet, privacy consolidation
- Fix QR code (replace broken Node.js import with api.qrserver.com API)
- Rename "Share Room" → "Share rMap" across UI
- Add "hidden" precision level replacing ghost mode toggle
- Unified 5-level privacy panel (Exact → Hidden/Ghost) as button list
- Pulsing blue dot self-marker (replaces emoji circle for own position)
- Locate-me FAB (bottom-left, both mobile and desktop)
- Mobile: edge-to-edge map, floating FAB menu with staggered animations
- Mobile: bottom sheet for participants (peek/expand with touch drag)
- Mobile: hide sidebar/controls/privacy panel, overlay compact nav bar
- Extract shared participant list helpers for desktop sidebar + mobile sheet

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:23:41 -07:00
Jeff Emmett 1c93e3bb67 feat(rinbox): add email forwarding prompt banner and fix auth token reading
Replace broken encryptid-token localStorage reads with getAccessToken/getUsername
from rspace-header. Add forwarding status check against EncryptID API with
enable/disable/dismiss banner on mailboxes view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:23:01 -07:00
Jeff Emmett 92df7d332d fix(canvas): only show reminder calendar on icon click, not on shape select/drag
Remove the auto-opening calendar on shape selection and the drag-to-calendar
compact mode. The 📅 icon on selected shapes remains as the entry point.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:15:18 -07:00
Jeff Emmett 15c118923b fix(spaces): match owner DID format in space list + resolve all TS errors
Space dropdown showed "Request Access" for the owner's own space because
the /api/spaces endpoint only checked claims.sub against ownerDID, missing
the did🔑 format used by auto-provisioned spaces. Now uses dual-check
matching the resolveRole helper pattern.

Also fixes 15 pre-existing TypeScript errors:
- server/index.ts: add Hono AppEnv type for context variables
- modules/rnetwork/mod.ts: cast tuple index to number for arithmetic
- modules/rsplat/folk-splat-viewer.ts: type CDN-loaded three.js as any
- modules/rtube/mod.ts: cast Uint8Array to BlobPart for FormData

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:11:32 -07:00
Jeff Emmett 73ad020812 fix(spaces): fix space creation routing and use /rspace URLs
Space creation was broken because the canvas module has id "rspace" but
all navigation URLs used "/canvas". On production subdomain routing this
resulted in 404s after creating a space.

- Switch create-space form from deprecated /api/communities to /api/spaces
- Replace all /canvas navigation URLs with /rspace to match module ID
- Fix DID matching in space listing to check both sub and did:key formats
- Add proper client DID support in EncryptID registration flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:07:01 -07:00
Jeff Emmett 8bd6e61ffc feat(rsocials): add campaigns dashboard with workflow thumbnail grid
New gallery landing page at /campaigns showing all campaign workflows as
cards with miniature SVG previews. Click a card to open the editor at
?workflow=<id>. Editor gains back-link to dashboard and workflow attribute
for deep-linking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:47:03 -07:00
Jeff Emmett 39ec09bb3b fix(compat): improve cross-browser support for Firefox, Safari, and older browsers
Add global polyfills for AbortSignal.timeout() (Safari <17, Firefox <122)
and crypto.randomUUID() (Safari <15.4, Firefox <95) in shell HTML templates.
Add -webkit-backdrop-filter prefix across 13 files for older Safari support.
Add Firefox scrollbar (scrollbar-width/scrollbar-color), range input
(::-moz-range-thumb/track), and color-mix() rgba fallbacks. Create shared
compat.ts utility module. Lowers browser floor from Safari 17/Firefox 122
to Safari 15.4/Firefox 95.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:43:38 -07:00
Jeff Emmett a736321189 feat(rnotes): add real-time Yjs collaboration, comments, and suggestions
Replace whole-content Automerge sync with character-level Yjs CRDT for
NOTE-type notes. Adds cursor presence, inline comments with threaded
replies, and track-changes suggesting mode.

- Custom Yjs WebSocket provider bridging over existing rSpace WS
- Server-side yjs-sync/yjs-awareness message relay (pure broadcast)
- y-indexeddb for offline persistence, periodic plaintext sync to Automerge
- Comment mark + panel with resolve/reply/delete
- Suggestion insert/delete marks with accept/reject support
- Schema v3→v4 (collabEnabled, comments fields)
- Collab toolbar: comment button, suggesting toggle, peer indicators

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:36:09 -07:00
Jeff Emmett b51dac1b22 test(spaces): add API test script for space creation & member management
Covers 19 test cases: space CRUD, member add by username, role changes
(viewer/member/moderator/admin), email invites, removal, auth guards.
Run with: ./e2e/tests/space-members-api.sh <AUTH_TOKEN>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:15:52 -07:00
Jeff Emmett 1f97a2ceba fix(smtp): use noreply@rmail.online as sender across all modules
Mailcow rejects noreply@rspace.online because the authenticated user
is noreply@rmail.online. Updated all SMTP_FROM and SMTP_USER defaults
to use rmail.online consistently: spaces invites, rSplat notifications,
EncryptID auth emails, and rCart payment receipts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:00:41 -07:00
Jeff Emmett 315a29a6d7 fix(shell): hide notification/share/settings icons on mobile, add to identity dropdown
On mobile (<=640px), the header right section was too crowded with icons.
Now hides notification bell, share panel, and settings gear buttons, and
adds equivalent mobile-only items in the identity dropdown menu. Share
uses native navigator.share() when available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:58:52 -07:00
Jeff Emmett 9b81ba70b6 feat(shell): add share button to global header with QR, copy link, email invite
Extract canvas inline share panel into reusable <rstack-share-panel> web component
and add it to the shell header between notification bell and settings gear. Canvas
now uses the component too, removing ~230 lines of inline HTML/CSS/JS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:51:21 -07:00
Jeff Emmett e5814b12c6 fix(rsplat): use fal.ai response_url for result fetch, add poll logging
The result fetch was constructing its own URL instead of using the
response_url returned by fal.ai's status poll. This caused 422 errors.
Now captures response_url from poll and uses it for result retrieval.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:51:05 -07:00
Jeff Emmett 97636235bf fix(spaces): use correct EncryptID internal URL for member operations
The spaces module was defaulting to http://localhost:3000 for EncryptID
API calls, which resolves to the rspace container itself (both run on
port 3000). Changed to http://encryptid:3000 matching server/index.ts.
Also improved error surfacing in /members/add endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:50:13 -07:00
Jeff Emmett d999c98b98 fix(rsplat): resize images with sharp before fal.ai submission
Phone photos (3-4MB, 4000px+) were failing with "Invalid image" on
fal.ai Hunyuan3D. Now resizes to max 1024px JPEG with sharp before
submitting, and uses PUBLIC_ORIGIN HTTPS URL instead of data URI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:36:59 -07:00
Jeff Emmett 05b8e2676a fix(canvas): mobile toolbar uses collapse instead of FAB overlay
Replace the floating action button toggle with the same collapse/expand
behavior as desktop. Toolbar sits as a compact icon column on the left,
panels open to the right, and corner tools move to bottom-right.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:30:20 -07:00
Jeff Emmett be81618b70 fix(tabs): prevent closed tabs from reopening via server sync race
Two race conditions caused closed tabs to resurrect:
1. syncTabsFromServer() fetch completing after a local close, merging
   the stale server response back in
2. Debounced PUT killed by page navigation when closing the active tab,
   so the server never learned about the close

Fix: track closed moduleIds per session to skip during merge, and flush
server PUT with keepalive:true before navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:30:11 -07:00
Jeff Emmett ad22ed7482 fix(rsplat): send image as data URI to fal.ai, fix http:// URL issue
The publicUrl helper was generating http:// URLs (x-forwarded-proto from
Traefik), causing fal.ai to fail with "Invalid image" 422 errors. Now
reads the staged image from disk and sends as base64 data URI for
reliable delivery. Also bumps poll timeout from 5 to 8 minutes and
surfaces actual fal.ai error messages to the client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:26:36 -07:00
Jeff Emmett d5d3f09b28 feat(rvnb): add (you)rVnB — community RV & camper rental module
Peer-to-peer RV/camper rentals within community trust networks.
Forked from rBnb with vehicle-specific concepts: specs, mileage
policies, pickup/dropoff locations, and dry humor throughout.

4 seed vehicles, full CRUD API, Leaflet map with pickup/dropoff
markers, rental request flow, endorsement tags including
"suspiciously_clean" and "smells_like_adventure".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 19:26:59 -07:00
Jeff Emmett ab2f69cd8a fix(canvas): use subdomain for space slug on *.rspace.online hosts
The communitySlug derivation was parsing path segments (e.g. /rcal) as
part of the space name instead of using the subdomain. On
jeff.rspace.online/rcal, this caused communitySlug to be "rcal" instead
of "jeff", making tab navigation redirect to rcal.rspace.online.

Now: on subdomain hosts, space always comes from the subdomain. Path
segments are only parsed for the space on localhost.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 18:20:29 -07:00
Jeff Emmett e42fa5c5d2 feat(canvas): reminder scheduling UX — icon, context menu, drag-to-calendar, email notify
Add four reminder scheduling affordances to the canvas:
- Floating 📅 icon on selected shapes toggles the reminder widget
- Right-click "Schedule a reminder" context menu option
- Drag-to-calendar compact mode (shows after 200ms of shape movement)
- Email notification via EncryptID on reminder creation

Closes TASK-122

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 18:02:13 -07:00
Jeff Emmett 362bdd5857 fix(rchoices): move CrowdSurf under rChoices sub-nav, fix header overlap
- Hide CrowdSurf from app switcher (hidden: true) since it's now a
  sub-tab of rChoices
- Replace dead outputPaths (Polls/Results with no routes) with actual
  tabs: Spider Chart, Ranking, Voting, CrowdSurf
- Add /:tab route handler so sub-nav pills link to working URLs
- Component reads tab attribute for initial tab selection
- Remove internal .demo-tabs (shell sub-nav replaces them)
- Bump JS cache version to v=6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:43:18 -07:00
Jeff Emmett e0d976ac92 fix(tabs): track active tab correctly on close + long-press reorder
currentModuleId was a const that never updated on client-side tab
switches, causing close to either do nothing or switch to the wrong
tab. Now uses tabBar.active as source of truth and picks the nearest
remaining tab on close. Also adds touch long-press (400ms) drag
reorder for mobile tabs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:37:24 -07:00
Jeff Emmett 383441edf7 feat(rchoices): inline CrowdSurf swipe cards with sortition
Replace CrowdSurf tab placeholder with working swipe-card interface
populated from rChoices session data (or demo fallback). Uses seeded
PRNG (mulberry32 + djb2 hash) for deterministic daily sortition per
user, preventing position bias. Right-swipe = approve (casts vote via
local-first client), left-swipe = skip. Swipe state persists in
localStorage across page reloads. Includes summary view with
session-grouped approvals and reset functionality.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:29:50 -07:00
Jeff Emmett 1811f5e7b4 fix(rchoices): bump JS cache version to v=5 for tab CSS fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:14:04 -07:00
Jeff Emmett 352ad33fff fix(rchoices): responsive tabs — icon-only on mobile to prevent overflow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:11:49 -07:00
Jeff Emmett 14c183b992 fix(rsplat): use request Host header for staged image URLs
fal.ai needs to download the staged image. Using hardcoded PUBLIC_ORIGIN
(rspace.online) fails because Cloudflare redirects /data/ paths and the
subdomain (jeff.rspace.online) isn't matched. Now derives the public URL
from the request's Host header. Added logging for staged image URLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:02:10 -07:00
Jeff Emmett 3c1802ab07 fix(rsplat): serve staged images via /api/ path to avoid Cloudflare redirect
Cloudflare/Traefik 301-redirects /data/ paths to data.rspace.online, which
fal.ai can't follow. Staged images now served at /api/files/generated/ which
passes through correctly. Added route alias for backwards compat.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:59:25 -07:00
Jeff Emmett d4c0fdf7eb fix(rsplat): stop polling on 404 when job lost after server restart
In-memory gen3dJobs are lost on container restart. The poll was silently
swallowing 404s and looping forever. Now stops after 3 consecutive 404s
with a clear "server restarted" message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:51:34 -07:00
Jeff Emmett 60ee7930ba fix(rchoices): hide tab labels on mobile, show icons only
Also adds backlog task for rTasks email checklist HMAC flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:50:02 -07:00
Jeff Emmett b80275abcb fix(rchoices): fix tab overlap + show icons-only on mobile
Adds margin-top to demo-tabs to prevent overlap with shell nav.
Hides tab labels on narrow screens (<=480px), showing only icons
so all 4 tabs fit. Bumps JS cache to v=4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:47:10 -07:00
Jeff Emmett e7f0181f70 fix: stop cross-tab active tab fighting + add per-user tab persistence
activeLayerId was being written to the shared Automerge CRDT on every tab
switch, causing all open windows/devices to follow. Now active tab is
local-only. Adds REST API + server-side storage so authenticated users'
tab lists persist across sessions and devices.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:40:50 -07:00
Jeff Emmett 2eb9ca2d8f fix(rsplat): use queue API for Hunyuan3D + fix controls z-index
Also fix canvas.html null reference crash when share-badge is stripped
by extractCanvasContent() header removal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:37:36 -07:00
Jeff Emmett 077bcf260a feat(rchoices): add CrowdSurf tab to choices dashboard
Adds a fourth sub-tab linking to the CrowdSurf module with teaser content.
Bumps JS cache version to v=3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:37:31 -07:00
Jeff Emmett dae8f72acb fix(rsplat): importmap must precede model-viewer module script
Browser ignores importmap when a <script type="module"> appears before it,
breaking Three.js imports and causing the 3D gen UI to hang at staging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:33:48 -07:00
Jeff Emmett 6b3fbd36b0 feat(rsplat): gallery thumbnails via model-viewer + fix 3D gen error handling
GLB models now render inline 3D previews using Google's <model-viewer> web
component with auto-rotate. AI-generated models show source image thumbnails.
Fixed fal.ai result fetch with retry logic and detailed logging for diagnosis.
Save flow now uses save-generated API with thumbnail_url passthrough.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:22:31 -07:00
Jeff Emmett 7da90088c4 fix(rsplat): fix GLB viewer not rendering on mobile
Defer initThreeViewer to next animation frame so the DOM has laid out
before reading container dimensions. Fall back to viewport size instead
of hardcoded 800x600 when container reports zero dimensions. Add proper
MIME types for GLB/GLTF file serving.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:15:24 +00:00
Jeff Emmett 2ea6fee951 feat: add CrowdSurf module — swipe-based community activity coordination
Implements the Crowdsurfing protocol (gospelofchange/Crowdsurfing) as an
rSpace module with full local-first Automerge CRDT sync. Users propose
activities with commitment thresholds, others swipe to join and declare
contributions, and activities trigger when enough people commit.

Module includes schemas, local-first client, swipe UI dashboard with
pointer gesture detection, landing page, seed template data, and
Vite build integration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:12:19 +00:00
Jeff Emmett 51da13ac46 feat(rbnb): add community hospitality module — trust-based space sharing
New rSpace module for couch surfing and space sharing within community networks.
Gift economy as first-class option, rNetwork trust graph for auto-accept,
messages embedded in CRDTs, endorsements feed back into trust graph.

- schemas.ts: Listing, StayRequest, Endorsement, AvailabilityWindow, SpaceConfig types
- mod.ts: 18 API endpoints (listings, availability, stays, endorsements, search, stats, config)
- landing.ts: Marketing page with warm amber/red/pink palette
- local-first-client.ts: Automerge sync wrapper (BnbLocalFirstClient)
- components: folk-bnb-view (grid+map), folk-listing (card shape), folk-stay-request (detail)
- bnb.css: Economy badges, status indicators, message thread styles
- Registered in server/index.ts, added r🏠 badge to app switcher under "Sharing"
- 6 demo listings (gift couch, exchange farm, suggested tent, sliding loft, gift hub, fixed cabin)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:01:50 -07:00
Jeff Emmett 646c3fcaf3 fix(canvas): null-guard share-badge to prevent crash on shell-wrapped pages
The canvas header is stripped when served via renderShell (extractCanvasContent),
removing the #share-badge button. The JS then crashes on shareBadge.addEventListener
which prevents all canvas interaction. Add null guards for all share panel elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:58:26 -07:00
Jeff Emmett de828c4247 fix(rsplat): bump JS cache version to v=9
Force browsers to fetch updated folk-splat-viewer.js with
error handling fixes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:57:13 -07:00
Jeff Emmett f1de3b654e fix(rsplat): handle formData parse errors in image-stage endpoint
Wrap formData() in try/catch with logging to diagnose Content-Type
issues through Cloudflare tunnel. Also fix client-side error handling
to clear progress timer and show actual error message on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:53:59 -07:00
Jeff Emmett fd63c2bc6f feat(rsplat): default to image upload + switch job queue to Hunyuan3D
- Default upload tab is now "Generate from Image"
- Entire dotted drop area is clickable to open file browser
- Update process3DGenJob to use Hunyuan3D v2.1 via fal.ai queue API
  (was still using old Trellis endpoint)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:48:43 -07:00