Commit Graph

299 Commits

Author SHA1 Message Date
Jeff Emmett 4212a651e1 fix(auth): exchange WebAuthn credential for server-signed JWT + rNetwork CRM cleanup
- Session manager now calls EncryptID /api/auth/start + /api/auth/complete
  to get a properly signed JWT instead of creating unsigned local tokens.
  This fixes 401 errors on /api/payments, /api/notifications, and other
  authenticated endpoints that verify tokens via EncryptID server.
- Token refresh calls /api/session/refresh instead of extending unsigned tokens
- Server generateSessionToken now includes authTime, jti, recoveryConfigured
- rNetwork: /crm route renders folk-crm-view instead of iframe
- rNetwork: ?view=app redirects 301 to /crm (backward compat)
- rNetwork: graph viewer always uses API (removed hardcoded demo data)
- docker-compose: pass through TWENTY_API_TOKEN from Infisical
- rcart: add catalog product images

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:13:19 -07:00
Jeff Emmett c2c3d1fb06 feat(rflows): funnel config threshold bar + extend slider to $5000
Replace three threshold dot rows with a single red→yellow→green color bar.
Extend outflow slider range from $3000 to $5000.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:10:17 -07:00
Jeff Emmett 4199a8c6e0 feat(rcart): add "Payer Decides" option for payment type and amount
- Add 'payer_choice' as third paymentType option on request form
- When set, the payment page shows a One-time / Recurring toggle for the payer
- Payer's choice sent to server via chosenPaymentType in status update
- Server uses chosenPaymentType to determine subscription reset behavior
- Combined with existing amountEditable, creators can now leave both
  amount and payment type fully up to the payer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:57:09 -07:00
Jeff Emmett 636fc133fe feat(rcart): add subscription/inventory/method-toggles to payment requests + fix 403
- Fix: add publicWrite to cartModule so payment routes aren't blocked
  by space-level write auth (routes have their own auth checks)
- Add paymentType field: 'single' (one-time) or 'subscription' (reusable QR)
- Add maxPayments inventory limit: QR codes auto-fill when limit reached
- Add paymentCount to track how many payments received
- Add enabledMethods: toggle card/wallet/encryptid per payment request
- Payment page only shows enabled tabs, shows inventory progress bar
- Subscriptions reset to 'pending' after each payment until filled
- New 'filled' status for inventory-limited payments that are full

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:35:11 -07:00
Jeff Emmett ba3d45372d feat: integrate heartbeat with rSchedule shapes
folk-calendar subscribes to clock:tick/daily to refresh today marker.
folk-reminders-widget auto-refreshes every 5 minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:24:21 -07:00
Jeff Emmett 05a7fbfc5a fix(rflows): align Coinbase env vars with Infisical names (CDP prefix)
COINBASE_API_KEY_ID → COINBASE_CDP_KEY_ID
COINBASE_API_KEY_SECRET → COINBASE_CDP_KEY_SECRET
COINBASE_PROJECT_ID → COINBASE_CDP_PROJECT_ID

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:19:17 -07:00
Jeff Emmett c049d7e8df feat(rcart): QR code payment requests with self-service generator
Add shareable QR payment system to rCart:
- PaymentRequestDoc schema with amountEditable support
- Payment API routes (create, list, get, update, QR SVG, Transak session)
- folk-payment-page: 3-tab payer view (Card/Wallet/EncryptID passkey)
- folk-payment-request: self-service QR generator with passkey auth
- Payments tab in folk-cart-shop for managing requests
- Extract Transak utils to shared/transak.ts (used by rFlows + rCart)

Routes: /:space/rcart/request (generator), /:space/rcart/pay/:id (payer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:11:20 -07:00
Jeff Emmett b3c449f54e feat(rflows+rwallet): diverse relay providers — on-ramp abstraction, configurable RPC, Pimlico bundler
- On-ramp provider interface + registry (transak > coinbase > ramp priority)
- TransakOnrampAdapter, CoinbaseOnrampAdapter, RampOnrampAdapter
- Provider-agnostic user-onramp endpoint with dynamic /api/onramp/config
- Coinbase + Ramp Network webhook handlers
- Frontend provider dropdown in Fund modal with multi-provider postMessage
- Configurable RPC: env var overrides (RPC_BASE etc), Alchemy auto-construct, public fallback
- Pimlico ERC-4337 bundler client + auth-gated routes (submit/send/receipt)
- Remove hardcoded Transak staging creds from entrypoint.sh (use Infisical)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:10:44 -07:00
Jeff Emmett c4717e3c68 feat: auth-fetch, shape registry, and data pipes (TASK-13, TASK-41, TASK-42)
TASK-13: rApp frontends now inject EncryptID bearer tokens via authFetch()
and gate mutations behind requireAuth() — rvote, rfiles, rmaps all protected.
Demo mode unaffected.

TASK-41: Dynamic shape registry replaces 300-line switch in canvas.html and
165-line if-chain in community-sync.ts. All 41 shape classes now co-locate
fromData()/applyData() with their existing toJSON(), making shape creation
and sync fully data-driven.

TASK-42: Data pipes between shapes via typed ports. Shapes declare
input/output PortDescriptors, arrows connect ports with type checking,
100ms debounce, and color tinting. AI shapes (prompt, image-gen, video-gen,
transcription) have initial port descriptors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:59:51 -07:00
Jeff Emmett 9bb00a8bab feat(rflows+rtasks): BCRG demo flow with live rTasks integration
Replace TBFF preset with 19-node BCRG Community Flow (2 sources →
central funnel → 5 person funnels → 11 outcomes). Seed matching
BCRG Outcomes board in rTasks (4 DONE, 5 IN_PROGRESS, 2 TODO).

Add SyncServer.registerWatcher() for cross-module doc change hooks.
When an rFlows outcome is marked "completed", auto-create a DONE task
in rTasks with ref:rflows:outcome:{id} deduplication.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:47:13 -07:00
Jeff Emmett d79d560771 feat(rsplat): interactive demo scenes + AI image-to-3D generation
Replace fake demo data with real HuggingFace CDN Gaussian splats (train,
truck, garden) that open in an inline 3D viewer without server round-trips.
Add "Generate from Image" tab that sends images to fal.ai Trellis for
AI-powered 3D model generation. Add gallery header and progress UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:29:15 -07:00
Jeff Emmett c36b0abc32 feat(rnetwork): inline force-directed graph in CRM view
Replace the Graph tab's external link with an interactive SVG graph
rendered directly from CRM data (people, companies, opportunities).
Companies appear as colored clusters with people orbiting around them,
and cross-org opportunity links shown as dashed purple edges.

Includes pan/zoom/drag interactions and auto fit-to-view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:22:18 -07:00
Jeff Emmett 31b088543e feat: add ViewHistory for in-app back navigation, rename rWork to rTasks
Add shared ViewHistory<V> utility class that provides a proper navigation
stack for rApps with hierarchical views. Replaces hardcoded data-back
targets with stack-based back navigation across 10 rApps: rtrips, rmaps,
rtasks, rforum, rphotos, rvote, rnotes, rinbox, rschedule, rcart.

Rename rWork module to rTasks — directory, component (folk-tasks-board),
CSS, exports, domains, and all cross-module references updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:04:13 -07:00
Jeff Emmett 9de37d7405 feat(rnotes): real-time transcript rendering + open notebook integration
Add segment-based live transcription to voice recorder and in-editor
dictation, wire AUDIO note recording, and add send-to-notebook endpoint
for RAG indexing via open-notebook service.

- Add openNotebookSourceId field to NoteItem schema
- Add POST /api/notes/send-to-notebook proxy route to open-notebook
- Add dictation preview bar with interim speech below editor toolbar
- Rewrite voice recorder with TranscriptSegment-based live rendering
- Convert transcript segments to Tiptap JSON with timestamps on save
- Wire Record button in AUDIO note view with full MediaRecorder flow
- Add Send to Notebook button + Indexed badge in note meta panel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:20:31 -07:00
Jeff Emmett fa3441269b feat(rinbox): theme-aware inbox with read/unread/attention states
Replace hardcoded dark-mode colors with --rs-* CSS custom properties
for automatic light/dark theming. Add inbox header bar with unread
count, sender avatar circles, and rich thread status indicators
(replied, forwarded, needs-attention badges with visual hierarchy).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:20:16 -07:00
Jeff Emmett f0cecc1529 feat(rpubs): add collaborative document editing via Automerge CRDT
Wire rPubs editor to the shared local-first runtime so multiple users
can co-author publications in real time. Drafts persist to IndexedDB
and sync via WebSocket automatically.

- New schemas.ts with PubsDoc schema and pubsDocId helper
- Editor connects to runtime, discovers/creates drafts
- Debounced content sync (800ms) with cursor preservation
- Title/author/format metadata sync between collaborators
- Draft list sidebar with create/switch functionality
- Sync status badge in toolbar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:01:08 -07:00
Jeff Emmett d96130f919 feat: fix tab duplication, add info popover, add rFlows guided tour
Fix tab duplication by syncing tabBar state after layer-add, deduplicating
Automerge layers, and syncing app-switcher tabs to CommunitySync. Add info
icon popover that lazy-loads module landing page content with auto-show on
first visit. Add 5-step guided tour for rFlows with spotlight overlay,
auto-advance on click, and toolbar restart button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:04:33 -07:00
Jeff Emmett e8a54f1eb6 feat(rflows): migrate to Transak API-based widget URL
Transak deprecated direct query-parameter URLs. The new flow uses
their Create Widget URL API with a Partner Access Token to generate
one-time sessionId-based URLs server-side. Also stops exposing the
API key in config endpoints and adds referrerpolicy to the iframe.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:00:46 -07:00
Jeff Emmett 3f71b219bb fix(rflows): remove iframe sandbox restricting Transak widget
The sandbox attribute was blocking Transak's internal redirects,
causing T-INF-101 access denied errors. Transak needs full iframe
capabilities for its payment flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:41:34 -07:00
Jeff Emmett 23f0cce9a1 fix(rflows): hardcode Base mainnet chainId (8453)
Infisical has BASE_CHAIN_ID=84532 (Base Sepolia testnet) which
conflicts with the live Openfort API key. Hardcode 8453 to prevent
testnet/mainnet mismatch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:38:38 -07:00
Jeff Emmett 30a409b2f8 fix(rflows): fix Openfort wallet label — colon not allowed in name
Openfort rejects ':' in player name query param. Changed label from
'user:email@example.com' to just 'email@example.com'. Also improved
error serialization for Openfort's non-standard APIError objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:30:27 -07:00
Jeff Emmett 01a794b0f2 fix(rflows): remove Coinbase onramp, use Transak only
Coinbase CDP integration was causing 500 errors ([object Object]).
Simplify to Transak-only: remove CoinbaseOnrampProvider import/init,
provider selection UI, and popup window branch. Also fix error handler
to properly stringify non-Error objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:24:18 -07:00
Jeff Emmett 8072b250ea feat: canvas background selector — grid, dot, or blank preference
Add user-selectable canvas background style via data-canvas-bg attribute
and CSS custom properties (--rs-canvas-bg-image, --rs-canvas-bg-size).
Three options: grid (default), dot, blank — persisted in localStorage.

- theme.css: new tokens + [data-canvas-bg] selectors
- rstack-identity.ts: Grid/Dot/Blank selector in user dropdown
- canvas.html: CSS vars, zoom-aware scaling, canvas-bg-change listener
- flows.css: use shared bg-image/bg-size vars (fixes rFlows theme bug)
- FOUC prevention in all entry points (shell.ts, create-space.html)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 18:37:50 -07:00
Jeff Emmett 72100c0922 feat: migrate hardcoded colors to --rs-* CSS variables across 18 modules
Replace structural UI colors with theme-aware CSS custom properties so
all rApp modules respond correctly to light/dark theme switching.

Covers: folk-social-post, folk-forum-dashboard, folk-video-player,
folk-video-chat, folk-thread-gallery, folk-campaign-manager,
folk-wallet-viewer, folk-vote-dashboard, folk-swag-designer,
folk-cart-shop, folk-workflow-block, folk-choices-dashboard,
folk-pubs-editor, folk-book-shelf, folk-flows-app, folk-analytics-view,
folk-campaign-planner, and flows.css canvas background.

Intentionally preserved: platform brand colors, chain colors,
data-viz/chart colors, video player black, call action buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 18:34:13 -07:00
Jeff Emmett 1cd8225680 feat(rcal): zoom bar relocation, likelihood feature, rich demo data, remove floating map
- Move zoom bars between calendar and map panes when docked (3-column grid layout)
- Add likelihood/pencil-in feature: tentative events render with dashed borders, lower opacity, percentage badges across all 7 view paths + modal + map markers
- Expand demo data from ~47 to 105 events spanning months -1 to +8 with periodic (yoga, standups), episodic (workshop series, book club), and tentative (25-80% likelihood) events
- Add Community and Health source categories
- Remove floating map option — map is now docked or minimized only
- Decouple zoom bars by default (spatialGranularity=Country, zoomCoupled=false)
- Preserve effective spatial index when decoupling via 'c' key or button
- Extend lunar computation range to month+9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 17:07:16 -07:00
Jeff Emmett b2347ec418 feat: per-rApp inline config + module-aware settings panel
Add <rstack-module-setup> component for inline module configuration
(replaces static "Not Configured" instructions). Enhance settings
gear panel to show the current module's settingsSchema at the top.
Pass module-id through shell rendering and tab-cache switching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:45:48 -07:00
Jeff Emmett 1f6b019dbf feat(rmaps): theme support, mobile fix, theme-aware map tiles
Replace all hardcoded dark colors with --rs-* CSS variables in both
demo and room modes. Add LIGHT_STYLE (CARTO voyager) tiles and
MutationObserver to swap MapLibre styles on theme toggle. Make SVG
demo map theme-aware (ocean, continents, graticule, pins). Fix mobile
layout with calc(100vh) sizing instead of fixed heights. Remove
hardcoded theme: "dark" from mod.ts renderShell calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:22:11 -07:00
Jeff Emmett 53af7fc057 feat(rcal): docked map layout + theme-aware tiles; emoji tab badges
- rCal: default map to docked (side-by-side) layout instead of floating overlay
- rCal: switch map tiles between Voyager (light) and dark_all (dark) based on theme
- rCal: boost dark mode map brightness/contrast for readability
- rCal: watch for theme changes via MutationObserver for live tile swapping
- Tab bar: replace text badges with emoji icons, fix badge colors for light themes
- App switcher: fix badge text color to dark for gradient backgrounds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:13:28 -07:00
Jeff Emmett e37044f599 feat(rflows): redesign canvas toolbar + zoom controls, remove sufficiency badge
Move toolbar from horizontal top-right strip to vertical left-side panel
with larger, more prominent buttons and emoji icons. Replace basic +/-
zoom buttons with a pill-shaped widget showing live zoom percentage and a
fit-to-view button. Remove the "0% Enough" sufficiency badge overlay.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:39:04 -07:00
Jeff Emmett 49f55dffc8 fix: resolve 500s on notifications, cache errors in SW, and [object Object] on-ramp alert
- Notification routes: wrap GET / and GET /count in try-catch, return
  graceful fallbacks instead of 500s when DB table is missing/unavailable
- getUnreadCount: add null safety (row?.count ?? 0) and catch DB errors
- Service worker: add .catch(() => {}) to all cache.put() calls to
  suppress NetworkError on quota-exceeded or corrupted cache entries
- On-ramp error display: coerce err.error to string so alerts show the
  actual message instead of [object Object]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:31:14 -07:00
Jeff Emmett c92ca0fe05 feat(rsocials): newsletter manager + listmonk proxy + backlog tasks
Add Listmonk newsletter management proxy API with role-based auth,
newsletter manager component, password setting type support, and
new backlog task files. Update newsletter subscribe URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:24:02 -07:00
Jeff Emmett e1bdc98b98 feat(rsocials): multi-view campaign planner (timeline, platform, table)
Add three alternative views to the campaign planner canvas:
- Timeline: horizontal chronological layout with day columns and phase bars
- Platform: kanban columns grouped by platform with post cards
- Table: compact sortable table with status, platform, content, dates

View switcher in toolbar preserves canvas state when switching. Clicking
any post in alt views navigates back to canvas with that node selected
and centered. Keyboard shortcuts guarded to canvas-only view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:21:59 -07:00
Jeff Emmett c8e95ed506 feat(rcart): add cart tab to browser extension + install banner in web UI
Extension gets Clipper/Cart mode tabs, space/cart picker with persistence,
JSON-LD product detection, "Add to rCart" context menu, and badge count.
Web UI shows a dismissible indigo banner prompting extension install when
not detected. Content script sets detection marker on rspace.online pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:07:13 -07:00
Jeff Emmett 932151aa88 fix(rsocials): campaign planner loads with fit-to-view on initial visit
Previously the planner restored a stale zoomed-out viewport from
localStorage, and fitView() could fail silently if the SVG had zero
dimensions during shadow DOM layout. Now: skip viewport restore on
initial load, retry fitView up to 3 rAFs, and clamp min zoom to 50%.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:58:27 -07:00
Jeff Emmett 9a7548e5ca feat(rflows): faucet-shaped source nodes with purchase modal + MetaMask
Replace flat source cards with pipe/valve/spigot faucet SVG. Click opens a
centered purchase modal (label, amount, payment method) instead of the cramped
side panel. Adds MetaMask as a new payment option alongside Card and rIdentity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:56:13 -07:00
Jeff Emmett 5ded81046c feat(rschedule): add automation canvas link and workflow gallery to landing page
Adds "Automation Canvas" CTA button in hero and "Your Automations" section
that fetches workflows from API and displays as grid cards or compact list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:54:33 -07:00
Jeff Emmett f22bc4781c feat(rtrips): wire up demo dashboard with 6-card live grid
Add /demo route, Vite build entry for trips-demo.ts, and demo page
CSS (hero, toolbar, 2×3 card grid, calendar, polls, funds, cart).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:42:35 -07:00
Jeff Emmett 8bc7787d37 feat(rschedule): n8n-style automation canvas at /:space/rschedule/reminders
Visual workflow builder with drag-and-drop node palette (15 node types across
triggers, conditions, and actions), SVG canvas with Bezier wiring, config panel,
REST-persisted CRUD, topological execution engine, cron tick loop integration,
webhook trigger endpoint, and two demo workflows (proximity notification +
document sign-off pipeline).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:42:34 -07:00
Jeff Emmett 61b25e299f feat(rinbox): reply/forward, SMTP send, personal/agent inboxes, canvas shape
Add reply, reply-all, and forward endpoints with proper RFC 5322 threading
headers (In-Reply-To, References). SMTP send executes automatically when
approval threshold is met via nodemailer. Personal inbox CRUD lets users
connect their own IMAP accounts. Agent inbox system with regex-based rules
for auto-classify/auto-reply (drafts go through approval workflow).
Multi-sig email canvas shape (folk-multisig-email) with draft/pending/sent
states and 5s polling. Per-space auto-provisioning via onSpaceCreate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:51:47 +00:00
Jeff Emmett de2a1baf84 fix(rsocials): serve campaign planner (n8n flow builder) at /campaigns
The /campaigns route was serving folk-campaign-manager (simple list view)
instead of folk-campaign-planner (the drag-and-drop flow canvas). The
planner was fully built but had no route.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:37:18 -07:00
Jeff Emmett 5ddc345341 feat(rwallet): port D3 visualizations from rwallet-online
Add 3 interactive D3 visualizations (Balance River Timeline, Multi-Chain
Flow Map, Single-Chain Sankey) as tabbed views alongside the existing
balance table. D3 loaded lazily from CDN on first viz tab click. Demo
mode shows all visualizations with mock TEC Commons Fund data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 01:47:18 -07:00
Jeff Emmett aad08c2eec fix(rsocials): use space-scoped data instead of global scope
rsocials had defaultScope: "global" but client components passed the raw
space slug, creating threads in space-specific docs (e.g. commonshub).
Server routes then looked in the non-existent "global" doc → 404.
Changed to defaultScope: "space" to match how client actually works.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 01:27:00 -07:00
Jeff Emmett 12d3e86e13 feat(rcart): merge group shopping into rCart module
Add shared shopping carts with URL product extraction, pooled funding,
and extension support alongside existing cosmolocal catalog/orders.

- Shopping cart schemas (ShoppingCartDoc, ShoppingCartIndexDoc)
- Server-side product extraction (JSON-LD, meta tags, Amazon/Shopify)
- 13 new API routes (cart CRUD, items, contributions, extension endpoints)
- 3-tab UI (Carts/Catalog/Orders) with cart detail, funding progress
- Local-first client subscriptions for real-time cart sync
- Updated landing page to reflect group shopping workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 01:21:38 -07:00
Jeff Emmett 62a96c164a feat(rvote): Reddit-style vote column + priority trend chart
- Reddit-style vote column: prominent up/down chevrons flanking the score
  on each ranking proposal card, with x² cost indicator
- Quadratic weight picker: compact inline buttons for +2/+3/+5 and -2
  below the proposal description (supplements chevron ±1)
- Priority Trends chart: SVG line chart showing how proposal scores
  evolve over time, with color-coded lines per proposal, end dots,
  grid lines, time labels, and a toggleable legend
- Score history tracking: records snapshots on each vote, seeds 7 days
  of simulated history for demo mode
- Orange for upvotes, blue for downvotes (matching rvote.online palette)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:52:47 -07:00
Jeff Emmett 35dd1c3d77 feat(rmaps): MapLibre GL map, WebSocket room sync, room history + ping friends
Replace the map room placeholder with a real MapLibre GL dark map (CartoDB
dark_all tiles). Port RoomSync from rmaps-online for WebSocket-based
participant/waypoint sync. Add localStorage room history with thumbnail
capture, participant sidebar with ping buttons, continuous GPS sharing
via watchPosition, and waypoint drop. Demo mode unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:44:28 -07:00
Jeff Emmett 192659b49c feat(rvote): enhanced landing, demo page, and dashboard to match rvote.online quality
- Add /demo route with interactive poll page (connection status, reset, live sync)
- Full rd-* CSS system for demo poll cards, badges, loading states
- Fix landing page links: demo.rspace.online/rvote → /rvote/demo
- Enhanced folk-vote-dashboard: inline voting on proposal cards, grouped by
  status (voting/ranking/decided), create-proposal form, tally bars,
  downvote support, richer visual design with progress indicators
- Add vote-demo.ts build step in vite.config.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:42:57 -07:00
Jeff Emmett a5c7bb784e fix(rsocials): subdomain-aware link generation
Links on subdomain routing (e.g. jeff.rspace.online) were including
the space in the path (/demo/rsocials/campaigns) instead of just
/rsocials/campaigns. Added basePath getter to all components and
detect subdomain in the server-rendered hub page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:31:45 -07:00
Jeff Emmett c19142791e feat(rnotes): type-specific notes, voice recording, web clipper, module settings
Phase 1: All 7 note types (NOTE, CODE, BOOKMARK, CLIP, IMAGE, AUDIO, FILE)
with type-specific editors, filter bar, new-note dropdown, and demo notes.
Phase 1.5: Code Snippet and Voice Note slash commands.
Phase 2: Voice recording with 3-tier transcription cascade (server Whisper,
Web Speech API, offline Parakeet TDT), mic button in toolbar, standalone
voice recorder component, upload/transcribe/diarize server routes.
Phase 3: Manifest V3 browser extension (web clipper) retargeted to
rspace.online with slug-based routing, article unlock via Wayback/Google
Cache/archive.ph strategies.
Phase 4: Per-module settings framework — settingsSchema on modules,
moduleSettings in CommunityMeta, gear icon in space settings Modules tab,
rNotes declares defaultNotebookId setting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:39:10 -07:00
Jeff Emmett c2b821ba0d feat(rcal): dual zoom lenses — temporal + spatial sliders
Add a visible spatial zoom slider (teal) below the existing temporal slider
(indigo) with a coupling toggle between them. When coupled, dragging either
track moves both; when decoupled, spatial slider controls map zoom independently.
Fix T_TO_S mapping gaps (Season→Region, Decade→Planet).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:11:37 -07:00
Jeff Emmett 5053d69ade fix(rcal): map shows only events from visible calendar period
Previously the map rendered ALL events regardless of which time period
the calendar was displaying. Now markers, transit lines, and map bounds
are filtered to the visible date range (day/week/month/season/year).
The map auto-fits to the bounds of visible located events when zoom
coupling is active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:54:05 -07:00
Jeff Emmett e9eb56aa2e feat(rmeets): add landing page emphasizing data sovereignty
Rich landing page for rspace.online/rmeets with sections on self-hosted
infrastructure, data sovereignty, ecosystem integrations, and roadmap
(local transcription, BYOS, data integrations).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:04:15 -07:00
Jeff Emmett 0cf1db56f4 feat(rmeets): register rMeets as rApp with Jitsi embed
Adds rMeets module with hub page (Quick Meet, Join Room, Jitsi Lobby)
and room pages that embed jeffsi.localvibe.live via renderExternalAppShell.
Jitsi URL configurable via JITSI_URL env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:54:10 -07:00
Jeff Emmett d45aaabea7 fix(rflows): theme toggle in shadow DOM + icon-only canvas toolbar
- Fix rFlows light/dark theme: change CSS selectors from :root /
  [data-theme] to :host / :host([data-theme]) so they work inside
  shadow DOM. Mirror data-theme attribute from <html> onto the
  folk-flows-app host element via MutationObserver.
- Canvas toolbar: icons only (no text labels), hover opens group
  name header + submenu flyout. Minimize button moved to top with
  chevron icon, collapses to wrench icon. Mobile gets emoji + text
  via ::after pseudo-element for touch accessibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:39:29 -07:00
Jeff Emmett f24fee942b feat(rflows): fix text-click drag, smart source labels, Pay by buttons
- Prevent foreignObject HTML clicks from starting node drag (select + inline edit instead)
- New source nodes get personalized "{username}'s stream to {flowName}" label
- Replace source type <select> dropdowns with clickable "Pay by" button grid
  in ICP panel, editor panel, and source modal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:19:46 -07:00
Jeff Emmett 0e9d00d2ac feat(rsocials): add Listmonk newsletter page + legacy domain redirect
- Add /newsletter-list route embedding Listmonk via iframe
- Add LISTMONK_URL env var to docker-compose
- Add Traefik redirect: social.jeffemmett.com → demo.rspace.online/rsocials
- Add backlog task for linked wallets security hardening (TASK-HIGH.5)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:15:05 -07:00
Jeff Emmett bc810d34e4 fix(security): low-severity hardening and security headers
- L-1: Remove internal error details from SIWE verify response
- L-2: Stop forwarding raw Safe API error bodies to clients (log server-side)
- L-3: Evict stale keys from nonce rate limiter to prevent memory leak
- L-4: Add input length/type guards on wallet-link verify body fields
- L-5: Sanitize and cap limit query param on Safe transfers route (max 200)
- L-6: Server recomputes addressHash from SIWE address instead of trusting
  client-supplied value for dedup
- L-7: Reset LinkedWalletStore singleton on logout to clear cached keys
- I-1: Add X-Content-Type-Options, X-Frame-Options, Referrer-Policy headers
- I-9: Build EIP712Domain type array dynamically from domain fields in
  ExternalSigner.signTypedData (was hardcoded to empty, dropping fields)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:06:07 -07:00
Jeff Emmett 92fde65d60 fix(security): rate limit, sender verification, icon sanitization, SSRF prevention
- H-3: Rate limit wallet-link nonce to 5 per user per 5 minutes (429)
- H-4: Verify sender address matches JWT walletAddress in add-owner-proposal;
  also include walletAddress in JWT eid claims
- M-1: Sanitize EIP-6963 provider icons — only allow https: and safe
  data:image/(png|jpeg|gif|webp), block SVG and javascript: URIs
- M-2: Validate threshold is a positive integer ≤ newOwnerCount, fetch
  actual Safe owner list for bounds checking
- M-3: Add VALID_ETH_ADDR regex validation to all 9 routes that accept
  address params (Safe proxy, EOA proxy, propose, confirm, execute,
  add-owner-proposal) to prevent SSRF via path traversal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:51:18 -07:00
Jeff Emmett 45f5cea095 fix(security): AES-256-GCM encryption at rest, XSS escape, salted hashes
- C-1: Replace Base64 fake encryption with real AES-256-GCM server-side
  encryption for linked wallet data (HKDF-derived key from JWT_SECRET)
- H-1: Escape token name/symbol in balance table to prevent XSS
- H-2: Salt address hash with user ID to prevent cross-user correlation
- M-4: Remove cleartext sessionStorage cache for linked wallets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:42:09 -07:00
Jeff Emmett d861c0ad99 fix(encryptid): harden wallet link flow + add device_registration type
- Atomic nonce consumption prevents TOCTOU races
- SIWE domain validation against allowlist
- Unique constraint on linked_wallets(user_id, address_hash)
- Add device_registration to challenge type enum

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:17:50 -07:00
Jeff Emmett c789481d91 feat(rwallet): link external wallets via EIP-6963 + SIWE
Users can now connect browser wallets (MetaMask, Rainbow, etc.) to their
EncryptID identity via SIWE ownership proof, and view linked wallet
balances in the unified rWallet viewer.

New files:
- eip6963.ts: EIP-6963 multi-provider discovery
- external-signer.ts: EIP-1193 provider wrapper for tx signing
- linked-wallets.ts: encrypted client-side store (same AES-256-GCM pattern)

Server: wallet-link nonce/verify/list/delete routes, linked_wallets table,
Safe add-owner-proposal endpoint, new session permissions.

UI: "My Wallets" section with provider picker, SIWE linking flow,
wallet type badges, and click-to-view for linked wallets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:10:12 -07:00
Jeff Emmett 93b6b2eb2c fix(rwallet): use CSS variable theming + soften global light mode
Replace ~30 hardcoded dark hex colors in folk-wallet-viewer with --rs-*
CSS variables so rWallet adapts to both light and dark themes. Warm up
the global light palette from pure white to off-white tones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:27:07 -07:00
Jeff Emmett f2ce77321f fix(rnotes): remove premature seed from onInit (runs before loadAllDocs)
seedDemoIfEmpty in onInit ran before docs were loaded from disk, causing
duplicate notebooks. Seeding is already handled post-loadAllDocs via
the seedTemplate hook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:16:19 -07:00
Jeff Emmett a689445af5 feat(rcal): add swipe/pan navigation and pinch-to-zoom gestures
Add pointer-based gesture handling to the calendar for lateral navigation
(drag/swipe left/right) and pinch-to-zoom between temporal layers. Also
fix dark mode across 30+ canvas shape components by replacing hardcoded
white backgrounds and input styles with --rs-* CSS custom property
references (with light-mode fallbacks).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:12:47 -07:00
Jeff Emmett fe031094a4 fix(rnotes): resolve global scope for notebook docIds and seeding
The rnotes module has defaultScope: 'global' but several code paths
used the raw space slug instead of the resolved scope:

- subscribeNotebook() built docIds with space slug (e.g. jeff🎶...)
  instead of resolved scope (global🎶...), breaking Automerge sync
- seedDemoIfEmpty() seeded notebooks under space-scoped paths, orphaning
  them when the API queries global-scoped prefix
- onSpaceCreate() created default notebook under space scope

Also migrated 3 orphaned jeff-scoped notebook files to global/ on server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:36:38 -07:00
Jeff Emmett f5388ecc2c fix(rwallet): migrate to new Safe Global API (api.safe.global)
Safe Global deprecated per-chain subdomains (safe-transaction-*.safe.global)
in favour of api.safe.global/tx-service/{shortcode}. The old URLs now 308
redirect, and the /balances/usd/ endpoint no longer exists.

- Update CHAIN_MAP prefixes to new shortcodes (eth, oeth, gno, etc.)
- Switch all Safe API calls to new base URL
- Use /balances/ instead of /balances/usd/ (fiat data no longer available)
- Normalize balance response with native token info and placeholder fiat fields
- Update client to show tokens with non-zero balance even without fiat data
- Update encryptid/server.ts Safe verify endpoint to new API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:57:09 -07:00
Jeff Emmett f9ccd18f15 fix(rnotes): add auth headers to all REST API calls
folk-notes-app was missing Authorization headers on all fetch calls,
causing 403 errors on non-demo spaces. Now uses getAccessToken() from
rstack-identity consistently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:51:04 -07:00
Jeff Emmett 494568599f fix(rnotes): cache-bust JS/CSS for notebook creation fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:39:55 -07:00
Jeff Emmett c73635dcd3 fix(rsocials): remove redundant /demo space prefix from internal URLs
Subdomain routing (demo.rspace.online) already prepends the space,
so links should use /rsocials/... not /demo/rsocials/...

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:38:57 -07:00
Jeff Emmett 0b5e8198d6 fix(rwallet): always show testnet chains when toggle is on
Testnet chains (Sepolia, Base Sepolia) are now always included in
detection results when testnets are toggled on, even if no native
balance is found. This allows viewing ERC-20 tokens on testnets
where native ETH balance may be zero.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:38:39 -07:00
Jeff Emmett b553acd756 merge: resolve rsocials conflict, keep dev campaigns page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:32:45 -07:00
Jeff Emmett 79f0ebb538 fix(rnotes): create notebook instantly without browser prompt
Skip the browser prompt() dialog — clicking "+ New Notebook" now
immediately creates an "Untitled Notebook" and opens it for editing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:32:03 -07:00
Jeff Emmett 6173e17bb9 feat(rsocials): hub navigation page, route renames, and campaigns listing
Restructure rSocials landing to a hub with navigation cards for Campaigns,
Threads, and Thread Editor. Rename /thread routes to /thread-editor for
clarity. Render campaigns listing inline instead of redirecting. Also
improve rNotes notebook creation to auto-open first note for editing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:31:23 -07:00
Jeff Emmett 01a4c95fa2 chore(rwallet): cache-bust wallet viewer JS (v=2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:56:36 -07:00
Jeff Emmett b8f32a863e chore(rwallet): cache-bust wallet viewer JS (v=2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:56:18 -07:00
Jeff Emmett 20c26cd3d7 feat: scope system, cross-space navigation, and spaces-as-layers
Phase 1 — Fix scope system: new scope-resolver.ts resolves global vs
space-scoped docId prefixes. Server middleware sets effectiveSpace on
Hono context. All 18 modules updated to use dataSpace for Automerge
doc access while keeping space for display. Client runtime gets
setModuleScopes() and resolveDocSpace() for local-first scope
resolution.

Phase 2 — Seamless cross-space navigation: TabCache now tracks panes
per space:module key. OfflineRuntime maintains lazy WebSocket
connections per space. Space-switcher dispatches space-switch event
handled client-side with history.pushState instead of full reload.

Phase 3 — Spaces as layers: Layer type extended with spaceSlug and
spaceRole. Tab bar gains "Add Space Layer" picker. Canvas renders
cross-space shapes with visual indicators. Space layers persisted as
SpaceRefs via nesting API. Runtime provides getAllActiveSpaces() and
subscribeModuleAcrossSpaces() for module-level data aggregation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 06:33:32 +00:00
Jeff Emmett bfb3a588ed feat(rwallet): rich landing UI, testnet toggle, and wallet type badges
Replaces the bare address-only empty state with a full dashboard landing:
hero branding, supported chain chips, feature cards, clickable example
wallets (TEC, Gitcoin, Vitalik), and animated loading spinner.

Adds testnet toggle (off by default) that filters Sepolia/Base Sepolia
from detection endpoints via ?testnets=true query param. Shows Safe
Multisig / EOA Wallet badge when a wallet is loaded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:42:23 -08:00
Jeff Emmett be8982f160 chore: switch payment defaults from staging to production
- Transak: default env PRODUCTION, fail if API key missing instead of
  falling back to STAGING_KEY
- Coinbase: default environment production instead of sandbox
- Openfort: default chain ID 8453 (Base mainnet) instead of 84532 (Sepolia)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 11:28:22 -08:00
Jeff Emmett 6c807afeb0 fix: one wallet per EncryptID user, deduplicate fund claims
- OpenfortProvider.findOrCreateWallet() searches by player name before
  creating, ensuring the same email always maps to the same wallet
- Fund claims endpoint expires old pending claims before creating new ones
- Added expireFundClaim() to db layer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:33:45 -08:00
Jeff Emmett 5f3ffcc8d2 feat: add EOA wallet support to rWallet for any address
Previously rWallet only supported Safe multisig wallets. Now it falls
back to EOA detection via public RPC endpoints when no Safe is found,
allowing any Ethereum address to view native balances across chains.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:17:46 -08:00
Jeff Emmett 9cdf246cc1 fix(rflows): prevent Delete/Backspace from deleting nodes while editing
- Use composedPath()[0] instead of e.target in document keydown handler
  to pierce Shadow DOM event retargeting (inputs inside shadow DOM were
  seen as the host element, bypassing the INPUT tag guard)
- Block Delete/Backspace at document level when editor or inline config
  panel is open
- Add stopPropagation on editor panel inputs for defense-in-depth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:41:00 -08:00
Jeff Emmett cdcb287188 fix(rflows): fallback to demo nodes when IDB document is corrupted
If no nodes were loaded after local-first init (corrupted Automerge
doc from previous IDB transaction errors), fall back to demo nodes
instead of showing empty "No nodes to display" screen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:29:52 -08:00
Jeff Emmett c21aab5797 fix(rflows): open Coinbase in popup (CSP blocks iframe), fix delete in modals
Coinbase pay.coinbase.com sets frame-ancestors CSP that blocks iframing
from third-party domains. Now opens Coinbase in a popup window with a
waiting modal, while Transak still uses iframe. Also prevents Delete/
Backspace from deleting canvas nodes when a modal overlay is open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:51:30 -08:00
Jeff Emmett 10a801e045 feat(encryptid): add fund claim flow for on-ramp transactions
After payment via Coinbase/Transak, users receive a claim email to link
their funded wallet to their EncryptID account — no keys or seed phrases
needed. Adds fund_claims table, CRUD layer, internal service-to-service
API, public claim page, and post-payment UX showing claim instructions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:53:57 -08:00
Jeff Emmett 3e4cdcee0e feat(rflows): dual provider support — Coinbase + Transak selectable
- user-onramp endpoint accepts optional `provider` param
- /api/onramp/config returns `available` array of configured providers
- Fund modal shows provider dropdown when both are available
- Transak widget URL now built server-side (consistent with Coinbase flow)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:29:04 -08:00
Jeff Emmett 4701e74784 feat(rflows): move on-ramp directly into rspace-online
Replace flow-service proxy for user-onramp with direct Coinbase + Openfort
provider calls. Eliminates double-hop dependency and simplifies deployment.

- Add CoinbaseOnrampProvider (Ed25519 JWT → CDP session → widget URL)
- Add OpenfortProvider (smart wallet creation on Base)
- Initialize providers from env vars in onInit()
- Update folk-flows-app to support Coinbase widget alongside Transak
- Add jose and @openfort/openfort-node dependencies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:20:35 -08:00
Jeff Emmett 266bc1cdef fix(rflows): node vanish on edit, API URL prefix, add Quick Fund UX
- Fix redrawNodeOnly() to use innerHTML for atomic DOM replacement
  instead of child-by-child moves that cause blur-event reentrancy
- Fix openTransakWidget/openUserOnRamp to use getApiBase() instead
  of hardcoded /s/ prefix
- Add content-type checking before res.json() to surface clear errors
- Add try/catch in server proxy for flow-service unreachable (502)
- Add "Fund" toolbar button with quickFund() one-step modal
- Replace promptEmail() with promptFundDetails() (amount+email+label)
- Pass actual flowRate instead of hardcoded fiatAmount: 50

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:58:36 -08:00
Jeff Emmett a0ad58df57 feat(rflows): integrate payment-infra user on-ramp for wallet-less funding
- Add POST /api/flows/user-onramp proxy route in mod.ts
- Add promptEmail(), openWidgetModal(), openUserOnRamp() methods
- Fund with Card now branches: wallet exists → direct Transak, no wallet → email → wallet → Transak
- Show truncated wallet address in source modal when provisioned

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:05:10 -08:00
Jeff Emmett eeae7d2aa1 feat(rflows): close source→funnel flow gap, interactive sizing + drag handles
Source nodes now drive funnel inflow rates via computeInflowRates() which
sums source allocations before each simulation tick. Source width scales
with flowRate, funnel height scales linearly with capacity, and valve/
capacity drag handles are always visible on hover (no inline-edit needed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:52:09 -08:00
Jeff Emmett 5b2862afd7 fix: prevent Automerge sync from overwriting local image state
onChange handler was resetting _tweetImages on every sync event,
undoing local deletions before they could round-trip. Now only
updates state in readonly mode; edit mode preserves local changes.

Also add cache-busting timestamps to uploaded/generated image URLs
to prevent browser from showing stale cached images.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:43:16 -08:00
Jeff Emmett b7111f01ee fix: deep-clone Automerge proxies to prevent stale image data
Automerge proxy objects silently ignore property writes outside
change() calls. When this._thread was a proxy, removeTweetImage's
assignment to this._thread.tweetImages was silently discarded,
causing deleted photos to reappear.

Fix by deep-cloning all Automerge reads (subscribeOffline, onChange,
loadDraft) so this._thread is always a plain mutable object.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:14:46 -08:00
Jeff Emmett b591267b81 feat: remove title/header image, add Twitter-style link previews
Remove the title input and header image upload/generate section from
the thread builder editor. Title is now auto-derived from first tweet.

Add link preview cards that render inline in tweet content, similar to
Twitter's URL card unfurling. Server-side /api/link-preview endpoint
fetches OG metadata (title, description, image) with caching.

URLs in tweet text are rendered as clickable links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:04:58 -08:00
Jeff Emmett ffbc1ce127 fix: use abstract art style for thread images, no text
Replace infographic/typography prompts with atmospheric abstract art
prompts. Images now use flowing gradients, organic shapes, and moody
lighting to evoke the tweet's theme without any text or typography.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:48:43 -08:00
Jeff Emmett f8557b1940 feat: upgrade thread image prompts to memetic infographic style
Replace generic "dark themed, minimal" prompts with detailed
infographic-style prompts that generate bold, shareable visuals
with typography overlays, iconic symbols, and data-viz elements.

Add try/catch error handling around fal.ai calls to prevent
unhandled network errors from crashing the request handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:44:08 -08:00
Jeff Emmett ec83f5c9c1 feat: replace rSocials canvas with n8n-style campaign planner
Add flow-based campaign planner with draggable Post/Thread/Platform/
Audience/Phase nodes, port wiring, 3 edge types (publish/sequence/
target), inline config panels, context menu, keyboard shortcuts,
touch gestures, and Automerge local-first persistence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:18:30 -08:00
Jeff Emmett d8f9f46515 feat: rFlows visual redesign — HTML card nodes, Sankey widths, smooth drag
- Switch source/outcome nodes from SVG shapes to foreignObject HTML cards
  with white backgrounds, gradient headers, status badges, and progress bars
- Add foreignObject text overlay to funnel nodes (keep SVG tank shape)
- Fix Sankey edge widths: flow-value-relative formula instead of percentage
- Smooth drag: rAF throttle + lightweight edge path patching during drag
- Add dot grid canvas background, arrowhead markers, larger port dots
- Fixed node sizes: source 220x120, outcome 220x180

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:18:06 -08:00
Jeff Emmett 92dff99793 fix: thread image 404 on subdomains + move photo section to top
Pass /data/ paths through subdomain routing without rewriting so
generated image files are accessible on *.rspace.online subdomains.

Move image upload/generate section above the compose textarea in the
thread builder editor layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:00:58 -08:00
Jeff Emmett 32cab9c67e fix: deep-clone thread before Automerge write to avoid proxy re-insertion
Automerge throws "Cannot create a reference to an existing document
object" when assigning an Automerge proxy object back into the doc.
Now JSON round-trips the thread data before writing, and strips null
fields that should be absent rather than null in the document.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:46:02 -08:00
Jeff Emmett a1b50eb0da fix: Automerge undefined rejection + thread not synced to server
- tweetImages and imageUrl set to null instead of undefined when empty
  (Automerge rejects undefined as invalid JSON)
- Updated ThreadData schema to allow null for optional fields
- This was the root cause of the 404 on image generation: saveDraft
  threw on undefined, so the thread never synced to the server, and
  the server-side route returned "Thread not found"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:14:06 -08:00
Jeff Emmett f9bafc8ef0 fix: Transak modal not opening — namespace querySelector + wallet check
- Use DOM API (createElementNS + createElement) to build foreignObject
  panel instead of innerHTML, ensuring proper HTML namespace for
  querySelector to traverse SVG→HTML boundary
- Query buttons/inputs from HTML panel root instead of SVG overlay
- Remove wallet address requirement for demo mode (use zero address)
- Add console logging and .catch() for Transak widget debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:07:28 -08:00
Jeff Emmett 1335c38d48 fix: thread builder offline runtime race + getDoc method name
Two bugs:
- subscribeOffline() bailed if runtime wasn't initialized yet (race with
  shell.ts init). Now waits for runtime to appear, then awaits init().
- getDoc() called runtime.getDoc() which doesn't exist — method is
  runtime.get(). Caused "e.getDoc is not a function" crash in listThreads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:06:47 -08:00