Adds a non-HttpOnly `rspace_hint` cookie scoped to .rspace.online carrying
only the public username (+ optional displayName). No JWT, session, or
credential crosses origins — WebAuthn RP ID rspace.online still drives
the actual ceremony, so moving between space subdomains requires a single
passkey tap instead of re-registering an account.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop beforeunload leave broadcast — was flashing users offline during
intra-space page nav between rApps
- Heartbeat 10s → 5s; GC stale threshold 15s → 12s
- Presence payload now carries userId; overlay keys peer map by userId
so reconnects with a new WS peerId map back to the same row
- uniquePeers() prefers entries with module/context metadata so the panel
shows which rApp a peer is in, even alongside cursor-only awareness
- rApp dropdown no longer shows a "Manage rApps" panel for disabled modules.
Enable/disable lives in Edit Space → Modules only.
- /api/internal/user-email/:userId now resolves by id OR did (real did🔑z6Mk…
or legacy synthetic did🔑<32-char id prefix>), so Edit Space members list
shows display names instead of raw DIDs.
- /api/spaces/:slug/invites admin check now accepts ownerDID stored as either
raw userId or did🔑. Routes the list through a new internal endpoint on
encryptid so Automerge-owned spaces without a space_members row still work.
- /join page registration payload was missing userId, causing every invite
claim to fail with "Missing required fields: userId, credential, username".
Same fix applied to the OIDC accept page flow.
Schema for the new Calendly-style rSchedule port plus two new shared
canvas components (folk-app-canvas, folk-widget) that replace per-rApp
tab-based nav with a unified widget-on-canvas surface.
Complete the rename started in dda7760 (which removed rschedule/ but
left callers unmigrated and the rminders/ dir uncommitted). Updates
vite.config.ts build entries, API base fetches in folk-comment-pin,
folk-rapp widget map, module-display meta, calendar reminder-drop
route, docs comment-panel, e2e fixtures, shell/landing/mcp-server
references, and backlog/ONTOLOGY docs.
Fixes vite build failure: "Could not resolve entry module
modules/rschedule/components/folk-schedule-app.ts".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous limits (avg 120/min, burst 30) had no sourceCriterion. Traefik
default groups by request Host, so ALL users of rspace.online shared a
single 120/min bucket — tripped almost immediately under normal load
(repeated 429s in rpast, api/mi/models, etc).
Scope per Cloudflare client IP (CF-Connecting-IP header) and raise to
600/min average with 150 burst — interactive use can spike above 120/min
from one client easily (module loads + polling + autosave).
- Rename 'Add' to 'Invite' in the By-Username add-member row to match
the By-Email path and reflect that it goes through an invite flow.
- Add 10px top margin to .add-member-row so the role dropdown and
button don't visually collide with the search input/selected-user
area above.
Email-invite path previously only showed 'Invite sent' without
refreshing the list. Username-invite path reloaded members but not
invitations. Both now call #loadInvitations after a successful POST.
- New rpast module renders a cross-rApp personal timeline
- shared/markwhen/ projection layer hydrates from syncServer docs
- rCal gets a Timeline applet wiring into the same markwhen view
- rstack-markwhen-view component for embedding elsewhere
- Smoke-test fixtures under output/ and scripts/smoke-rpast.ts
- Adds @markwhen/{parser,timeline,calendar,mw} deps
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Default voice en-US-AvaMultilingualNeural -> en-US-AndrewMultilingualNeural
(smoother, less feminine timbre).
- Volume 0.55 -> 0.3, rate -8% -> -10%, pitch -2Hz -> -6Hz.
- Browser fallback matches: pitch 0.85, volume 0.3.
- Client passes voiceMode flag to /api/mi/ask; server appends a VOICE
MODE section to the system prompt demanding ≤1-2 short sentences,
no lists/markdown/emoji/preamble — because listening to long replies
is tedious.
- Deduplicate cursor rendering using #uniquePeers() (was showing
multiple cursors per user from different tabs/sessions)
- Strict same-page filtering: cursors only visible when peers share
the same effectiveViewId (viewId ?? moduleId)
- Users on different rApps no longer see each other's cursors
- Applied same fixes to focus rings and panel "different view" badge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add saveDocImmediate() for synchronous awaitable saves (no debounce)
- Add SyncServer.flushAll() to iterate all in-memory docs
- Fix eviction race: onDocEvict now uses saveDocImmediate instead of
debounced saveDoc (which could fire after doc deleted from memory)
- Add SIGTERM/SIGINT handlers with 10s timeout safety net
- Add visibilitychange flush on client (reliable on mobile/bfcache)
- Flush pending IDB saves in DocSyncManager.disconnect()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only redirect to personal dashboard when on demo landing page.
Logging in from any module page now reloads in place.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pool-out port to folk-commitment-pool, two new applets (weaving-coverage
for rTime, resource-coverage for rTasks), fetchLiveData polling in FolkApplet,
and canvas AI tool declarations for both new applets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dashboard was empty because folk-cred-dashboard.ts had no Vite build
entry — the JS never got compiled. Add build step to vite.config.ts,
fix script src to /dist/modules/rcred/folk-cred-dashboard.js, and
darken badge background from #fbbf24 to #d97706 so it doesn't blend
with the ⭐ emoji.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add r⭐ badge for rcred in favicon, app-switcher, and tab-bar badge
maps. Render 'r' with #dc8300 orange in badge pills across all three
components (favicon SVG tspan, app-switcher HTML spans, tab-bar HTML
spans). App names (e.g. "rDocs") intentionally left uncolored.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Persistent chat panel accessible from any page via header icon.
Sliding right panel (360px) with channel selector, message feed,
composer, and unread badge. REST polling with localStorage state
persistence. Includes unread-count API endpoint for badge updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tours were demoing stale features and auto-triggering annoyingly.
TourEngine.start() now returns immediately (no-ops). Shell welcome
tour JS/CSS/HTML removed. "Start Guided Tour" links stripped from
all 27 landing pages. Tour CSS selectors removed from info panel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remote cursor arrows and focus rings from peers viewing a different
note in rDocs are now suppressed. A generic viewId concept on the
collab overlay lets any rApp with sub-views opt in via a
rspace-view-change CustomEvent. Peers on a different view appear
dimmed in the people panel with a document icon hint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Store shape listener refs in Map, remove in unregisterShape() (critical leak)
- Compact Automerge history every 500 changes via clone() to cap WASM heap
- Clean shapeLastPos entries on shape removal
- Store outside-click handler ref, clean up in disconnectedCallback()
- Cap MI messages at 50 and prompt messages at 30 to prevent unbounded growth
- Store keep-alive interval handle
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show red alert dot on "My Account" dropdown item when email, multi-device,
or social recovery tasks are incomplete. Remove postal address section
from the account modal (render, state, loader, listeners).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace three separate mic controls (bar dictation, bar miC, panel miC)
with a single 🎤 toggle in the bar that activates the full voice loop:
speech-to-text → auto-submit after 1.5s silence → TTS response.
- Remove standalone dictation mode (#dictation, #interimText)
- Remove panel header miC button
- Single mic button uses voice mode state animations (pulse red = listening,
spin amber = thinking, pulse cyan = speaking)
- Tighten TTS output to ~2 sentences for succinct responses
- Voice strip still shows in panel with waveform, status, and stop button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add r<emoji> badges for rDocs, rDesign, rSheets, rTime, rGov, rAgents,
rExchange to both MODULE_BADGES and FAVICON_BADGE_MAP
- Add MODULE_CATEGORIES entries for all new modules
- Add "Govern" category for rGov
- Sort modules alphabetically within each function category
- Add sort toggle (By Function / A-Z) at bottom of sidebar, persisted
in localStorage
- Add star/pin button on each rApp — pinned items appear in a "Pinned"
section above "Recent", persisted in localStorage
- Fix rAuctions module ID: 'auctions' → 'rauctions' for consistency,
with alias in MODULE_ALIASES for backward compat
- Change rAuctions emoji from 🏛 to 🎭
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add per-object visibility levels (viewer/member/moderator/admin) across
all rSpace modules. Objects default to 'viewer' (open), so existing data
remains visible. Server-side GET handlers resolve caller role and filter;
MCP tools filter lists and check single-item access; frontend components
do defense-in-depth filtering with visibility picker (mod+) and lock badges.
- shared/membrane.ts: types + isVisibleTo, filterByVisibility, filterArrayByVisibility
- 9 schema files: visibility field on TaskItem, NoteItem, CalendarEvent, etc.
- 8 module routes: GET handlers filter by caller role
- 6 MCP tool files: list filtering + single-item visibility checks
- 4 frontend components: client filtering, picker, lock badges
- 18 unit tests (all passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MI bar z-index lowered to 1 so dropdowns render above it; panel
gets z-index 10001 only when open
- SW registration URL bumped to v=8 to match cache version
- rtime: pool and weaving are now two separate scrollable sections
on mobile (50vh/60vh min-heights) with a "Commitment Weaving"
section header visible on constrained screens
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add /api/auth/*, /api/register/*, /api/account/* proxy routes to
rspace-online server, forwarding to encryptid container internally.
This eliminates cross-origin requests that Safari blocks via ITP or
Cloudflare security challenges.
- Change client auth URLs from https://auth.rspace.online to same-origin
in rstack-identity, rspace-header, login-button, and session modules.
- Add PRF extension try/catch fallback in webauthn.ts — Safari throws
TypeError on the unsupported PRF extension, now retries without it.
- Bump SW cache version v7→v8 to bust stale cached bundles.
Fixes passkey login for Safari/macOS users (e.g. christina) who were
getting "Network error when attempting to reach resource".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Red pulsing alert dot on avatar when social recovery not configured
- SVG puzzle piece visualization for guardian slots (empty/pending/accepted)
- Key assembly animation when 2+ guardians accepted
- Recovery drill system: test the full guardian approval flow without actual recovery
- POST /api/recovery/drill/initiate, GET .../status, POST .../complete
- Drill-specific emails with "TEST ONLY" branding
- Live polling UI with puzzle pieces filling in as guardians approve
- Drill timestamp tracking (last_drill_at on users table)
- Solo walkthrough modal: 5-step animated preview of how recovery works
- Approval page detects drill flag, shows DRILL badge
- Account status now returns acceptedGuardianCount and lastDrillAt
- Recovery section shows emergency override messaging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sign-in modal: detect email input and send as { email } to auth/start
- Add "Send Magic Link" button alongside passkey sign-in
- Registration: optional email field sent with register/complete
- Enter on username field tabs to email; Enter on email submits
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getAllKnownUsernames() now pulls from 4 sources: current session,
rspace-username cache, known-personas list, and encryptid-known-accounts
- On specific space: stay on that page (reload only, no redirect away)
- On landing: go straight to dashboard (hardcode "rspace" module)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display known accounts as clickable buttons in the sign-in modal so users
pick their username rather than typing it — prevents accidental new passkey
creation from typos. Falls back to manual input via "Use a different account".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds always-visible home button in tab bar, toggleable dashboard overlay,
widget card system with 8 widgets (tasks, calendar, activity, members,
tools, quick actions, wallet, flows), customize mode with toggle/reorder,
and dashboard summary API endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser-side:
- Fix switchSpace() to LRU-evict idle space WebSocket connections (cap: 3)
- Add runtime.unsubscribe() to disconnectedCallback in 24 components
- Fix DocSyncManager.unsubscribe() to clean up syncStates, timers, listeners
- Fix 14 components leaking RAF loops, ResizeObservers, MutationObservers,
document/window listeners, setIntervals, MapLibre WebGL contexts, and
AbortControllers on disconnect
- Deduplicate Automerge WASM: module builds now use global shim from
shell-offline instead of bundling ~2.5MB each (8 modules affected)
Server-side:
- Add LRU eviction to SyncServer.#docs (cap: 500, evicts idle docs with
no subscribers, persists to disk before eviction)
- registerWatcher() now returns unsubscribe function
Data:
- Cap unbounded CRDT arrays: rexchange chatMessages (200), rcart events (200)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 2-3 of the rNotes/rDocs split. Rewrites rNotes from a full TipTap
editor (~1800 lines) into a lightweight Obsidian/Logseq vault sync and
browse module (~560 lines). Rich editing features remain in rDocs.
rNotes vault browser:
- VaultDoc schema: metadata-only in Automerge (title, tags, hash, wikilinks)
- ZIP vault uploads stored on disk at /data/files/uploads/vaults/
- File tree browser, search, read-only markdown preview
- Wikilink graph data endpoint for visualization
- 5 MCP tools: list_vaults, browse_vault, search_vault, get_vault_note, sync_status
- Browser extension compat shim redirects old API calls to rDocs
Cleanup:
- Removed dead editor files from rnotes (converters, components, local-first-client)
- Updated MI integration to use getRecentVaultNotesForMI
- Updated ONTOLOGY.md with new module descriptions
- Bumped JS cache versions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds Figma-style threaded comment markers anchored to data-collab-id
elements across all module pages. Comments stored in per-space Automerge
doc, synced via existing local-first stack. Bell is now context-aware
(canvas pins on canvas, module pins on module pages). Notifications
route through existing WS/push/email system with new module_comment
and module_mention event types.
New files: module-comment-types, module-comment-schemas,
rstack-module-comments component. Updated: shell, comment bell,
notification routes. Added data-collab-id to crowdsurf, rtime, rmeets.
Fixed pre-existing SKILL_LABELS import error in rtime/mod.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a ✕ button next to the + tab button that closes all open rApp tabs
and returns to the user dashboard. Shows a confirm() prompt with tab count
before proceeding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The collab overlay was running a 5s setInterval GC timer on every page
load even with zero peers. Now the timer starts only when the first
peer arrives and stops when all peers are garbage collected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HMAC-signed stateless tokens let external respondents vote on rChoices
polls or RSVP to rCal events via a single tap — no account required.
Routes mounted at /respond/:token bypass space auth. Typed EventAttendee
schema replaces unknown[] on CalendarEvent.attendees. Invite endpoints
on both modules generate tokens and optionally send email invitations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three client-side registration flows still had authenticatorAttachment: 'platform'
hardcoded, blocking Samsung Passkey and Linux users:
- lib/rspace-header.ts (main site header registration)
- shared/components/rstack-identity.ts (2 occurrences)
Also added server-side validation for missing userId in register/complete
to return 400 instead of crashing with TypeError.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts 4420d9c — the FAB change was applied to the wrong component.
The intended target is the rSpace canvas toolbar, not the app switcher.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Repositions the rApp switcher as a floating action button in the bottom-right
corner that expands upward into a rounded panel. Removes all sidebar push-offset
CSS since the panel now overlays content without layout shift.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pointerdown on document was hiding the dropdown before click could fire
on My Account / My Spaces / My Wallets buttons. Switching to click lets
stopPropagation in item handlers prevent premature close.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audit and fix ~60 violations across 47 files where URLs were constructed
as /{space}/moduleId instead of /moduleId (subdomain provides the space).
- Add getModuleApiBase() helper to shared/url-helpers.ts
- Fix client components: use getModuleApiBase() for fetch URLs,
rspaceNavUrl() for navigation
- Fix server routes: use c.get("isSubdomain") for redirects and
JSON response URLs
- Fix OAuth callbacks (notion, google, clickup): subdomain-aware redirects
- Fix email notification URLs (rvote): use {space}.rspace.online format
- Fix webhook registration (rtasks/clickup): subdomain-aware endpoint URL
- Replace broken #getSpaceSlug() methods in folk-feed, folk-splat
- Replace NODE_ENV checks with proper isSubdomain checks (rdata, rnetwork)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MoonPay as the primary card payment provider for rCart. MoonPay
uses HMAC-SHA256 signed URLs (no session API needed, no IP whitelisting).
Falls back to Transak if MoonPay keys aren't configured.
- shared/moonpay.ts: URL builder with HMAC signing, currency mapping
- New /api/payments/:id/card-session endpoint picks provider automatically
- Frontend uses unified startCardPayment() with multi-provider message handling
- Set MOONPAY_API_KEY + MOONPAY_SECRET_KEY to activate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>