Commit Graph

186 Commits

Author SHA1 Message Date
Jeff Emmett 0753b31990 fix(spaces): correct API paths for member/invite operations in settings panel
All fetch calls in rstack-space-settings were missing the /api/spaces prefix,
causing 404s for add-by-username, invite-by-email, change-role, remove-member,
and load-invites. Also add color-scheme: light dark to fix native select
dropdowns rendering in light mode on dark theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 15:15:33 -07:00
Jeff Emmett 8071b620e1 fix(auth): throttle session validation, typed auth-change events, misc fixes
- rstack-identity.ts: throttle server session validation to every 5min,
  add reason detail to all auth-change events (signin/signout/revoked/
  refresh/persona-switch), remove redundant location.reload on signout
- shell.ts: skip UI side-effects on token refresh, only redirect home
  on genuine signout/revocation
- server.ts: add PUT to CORS allowMethods
- folk-inbox-client.ts: pass auth token on mailbox API fetch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 12:21:26 -07:00
Jeff Emmett c2d7e8b238 fix(shell): prevent infinite loop when rapidly switching tabs
Abort previous in-flight fetch when switchTo() is called again, and
guard the shell's fallback navigation against stale callbacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:44:38 -07:00
Jeff Emmett 06a58f1bba fix(ui): theme-adaptive rSocials buttons + device link textbox
- campaign-wizard.css: fix undefined --rs-surface-hover → --rs-bg-hover
- campaign-workflow.css: replace hardcoded blue colors with theme vars
  (--rs-primary-hover, --rs-bg-active, --rs-border, --rs-primary)
- rstack-identity.ts: device link URL input --rs-bg-inset → --rs-input-bg
  (--rs-bg-inset was never defined in theme.css, dark fallback always won)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:39:14 -07:00
Jeff Emmett 423d2612af fix(auth): preserve active tab through login on bare domain
The identity component's inline _getCurrentModule() assumed path-based
routing (/{space}/{moduleId}) for non-subdomain URLs, returning "rspace"
instead of the actual module. On bare domain (rspace.online/rnotes),
this caused login to redirect to the canvas instead of rnotes.

Add _isBareDomain() check so _getCurrentSpace() returns "demo" and
_getCurrentModule() reads parts[0] (the module) on the bare domain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:27:30 -07:00
Jeff Emmett 22b5c00a13 fix(routing): prevent domain stacking and remove Try Demo button
- Fix server-side redirect to always use canonical rspace.online as base
  domain instead of deriving from hostClean (prevents demo.rspace.rspace.online)
- Fix bare-domain check to exact match instead of .includes() (prevents
  stacked subdomains from triggering bare-domain routing)
- Fix client-side rspaceNavUrl to guard against reserved subdomain names
  being used as space subdomains (e.g. rspace.rspace.online)
- Fix identity component _navUrl with same canonical domain guards
- Remove "Try Demo" header button from all shell rendering functions
- Remove demo-btn CSS styles
- Fix pre-existing SchemaType error in Gemini tool declarations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 11:16:46 -07:00
Jeff Emmett dd46905e12 feat(mi): agentic upgrade — multi-turn loop, LiteLLM, media gen, live data
Transform MI from single-shot chat into an agentic system:

- LiteLLM provider with Claude Sonnet/Haiku models via proxy
- Agentic loop (max 5 turns): stream → parse actions → execute server-side → feed results back
- Server-side media generation (fal.ai + Gemini) as first-class MI actions
- Module data queries (rnotes, rtasks, rcal) read directly from Automerge
- System prompt enriched with recent notes, open tasks, and calendar events
- Client handles new NDJSON types (turn, action-start, action-result)
- Extracted shared media helpers, refactored image/video endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:26:56 -07:00
Jeff Emmett 3596bb9d7c fix(ui): raise MI search z-index and unclip header overflow
Search dropdown was rendering behind overlays and getting clipped by
the header's overflow:hidden. Bump z-index to 10001 and set overflow
to visible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:02:04 -07:00
Jeff Emmett efa5a5c315 fix(collab): read username from session.claims.username instead of session.username
The encryptid session stores username at claims.username, not at the
top level. Also falls back to the rspace-username localStorage key
that rstack-identity sets on login.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 18:03:01 -07:00
Jeff Emmett cefc1aa5b7 fix(collab): rename Solo/Share to Online/Offline, use EncryptID usernames
Swap toggle labels to Online/Offline (more intuitive). Resolve canvas
peer usernames from encryptid_session instead of rspace-username fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:45:55 -07:00
Jeff Emmett e70b40df9a fix(collab): theme-aware N-online badge and people panel
The collab overlay badge used --rs-bg-secondary (which doesn't exist in
the theme system), causing it to always fall back to dark hardcoded values.
Updated all Shadow DOM CSS to use proper theme variables (--rs-glass-bg,
--rs-glass-border, --rs-text-primary, etc.) with light-mode-safe fallbacks
so the badge and panel are readable in both dark and light themes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:39:40 -07:00
Jeff Emmett 41051715b9 feat(rtasks): ClickUp two-way sync integration
Add bidirectional sync between rTasks and ClickUp:
- API client with 100 req/min rate limiter
- OAuth2 + personal API token connection flows
- Import wizard (workspace → space → list picker)
- Outbound push queue (5s intervals, 10-item batches)
- Inbound webhook with HMAC-SHA256 validation
- Field-level conflict detection (rTasks wins)
- Source badges (purple CU) with sync status dots on task cards
- Sync status indicator in board header for connected boards

Also fix 6 pre-existing TS errors across crowdsurf, rcal, rnotes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:37:01 -07:00
Jeff Emmett e8379541cc fix(tabs): strip duplicate shell elements from canvas tab injection
The canvas.html body contained <rstack-tab-bar>, <rstack-space-settings>,
and <rstack-history-panel> elements that weren't being stripped by
extractCanvasContent (the tab-row regex failed due to extra children).
When injected via TabCache, these duplicate elements interfered with the
shell's tab management, causing tabs to appear wiped.

Fixes:
- Server: robust div-counting strip for rstack-tab-row + explicit strips
  for space-settings and history-panel
- Client: DOM-based safety strip in TabCache.extractContent()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:21:52 -07:00
Jeff Emmett 13a7e44e24 feat(identity): replace device nudge toast with QR code for mobile linking
Instead of a "Set up now" button, the device nudge now generates a device
link token and displays a scannable QR code + copyable link URL directly
in the toast, making it easy to link a phone or tablet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:06:29 -07:00
Jeff Emmett df8631360e feat(collab): unified presence system across all 27 rApps
Harmonize the two disconnected presence systems into one:
- New shared/collab-presence.ts utility (broadcastPresence, startPresenceHeartbeat)
- Collab overlay now listens to custom presence messages, shows module context in people panel
- Fixed Shadow DOM focus tracking using composedPath() for focus rings through shadow boundaries
- Replaced rNotes custom presence with shared utility (kept sidebar dots)
- Added presence heartbeat to all 27 rApp components with dynamic context strings
- Bumped cache versions in all modified mod.ts files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:56:06 -07:00
Jeff Emmett 677a69645e debug(shell): add console logging to trace tab-switch failure for rspace
Adds diagnostic console.log to layer-switch handler, TabCache.switchTo,
fetchAndInject, and reconcileRemoteLayers to identify why clicking the
rspace tab closes all tabs and shows the dashboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:32:57 -07:00
Jeff Emmett 433833da0c fix(shell): prevent remote sync from wiping all tabs and showing dashboard
reconcileRemoteLayers() could wipe all local tabs when Automerge sync
or BroadcastChannel delivered empty layer data (CRDT initial state,
sync race). This caused clicking tabs to show an infinite-loading
dashboard. Now: empty remote layers are rejected when an active module
exists, and the current module always stays in the tab list.

Also adds 10s fetch timeout to TabCache.fetchAndInject() to prevent
infinite loading spinners on slow/failed module fetches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:23:45 -07:00
Jeff Emmett 50edf06900 feat(encryptid): periodic nudge toast for users without a second device
Shows a dismissible toast notification 3s after page load when the user
has only one passkey. Links directly to the device section in My Account.
Dismissal remembered for 7 days via localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:14:59 -07:00
Jeff Emmett a7eda3c53f feat(encryptid): post-signup prompt recommending second device linking
After registration, users now see a welcome modal that prominently
recommends linking a second device via QR code before entering their
space. Provides backup access and cross-device sign-in awareness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:05:50 -07:00
Jeff Emmett 772e5e4352 fix(shell): header button reliability — history, settings, comments
History panel: lazy doc acquisition from CommunitySync/offline runtime
on open + listen for community-sync-ready event for late connections.

Space settings: reposition panel after every re-render (async data loads
were destroying inline positioning styles), clamp max-height to viewport,
fix wrong global name (__rspaceCommunitySync → __communitySync).

Comment bell: render DOM once, update badge without innerHTML churn,
listen for community-sync-ready event, cache sync reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 16:04:11 -07:00
Jeff Emmett a83c714f5a fix(auth): username-first flow in rstack-identity sign-in modal
The actual login UI lives in rstack-identity.ts, not login-button.ts.
Added username input to the sign-in modal, pass allowCredentials from
server to WebAuthn so the browser auto-selects the matching passkey.
Shows "No account found" if username not recognized. Enter key support
and auto-focus on the username field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 14:44:39 -07:00
Jeff Emmett 4536b5cab1 fix: remove rvote proposals from space dashboard + fix protocol in redirects
1. Remove all rvote/proposals fetching from rstack-user-dashboard.
   rApp-specific data (proposals) should stay within the rVote module,
   not leak into the space-level dashboard.

2. Fix url.protocol in bare-domain redirects — TLS is terminated by
   Cloudflare/Traefik so url.protocol is always http: internally.
   Use https: for production domains.

3. Rewrite /{space}/api/... paths internally on bare domain instead
   of redirecting to subdomain (avoids CORS + mixed content issues).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 12:29:15 -07:00
Jeff Emmett 8f1ad52557 feat(collab): unify header & tab-row — shared people-panel across all rApps
Canvas now uses the same rstack-collab-overlay component as all other
rApps instead of its own custom #people-online-badge. Header restructured
to match renderShell() layout (history/settings in dropdown-wraps on left).
Bridge API (updatePeer/removePeer/setConnState/clearPeers) lets canvas
feed CommunitySync peers into the shared component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 11:46:26 -07:00
Jeff Emmett f9767191e8 fix(auth): reload page on logout and redirect logged-in users from space grid
After logout, reload the page so the server re-renders the current rApp
in logged-out/demo mode instead of showing a blank screen. Cross-tab
logout also triggers a reload. Space dashboard now redirects logged-in
users to the rSpace canvas instead of showing the rApp grid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:54:35 -07:00
Jeff Emmett 4722aca065 fix(auth): wire cross-session logout in rstack-identity + encryptid profile
rstack-identity is the actual sign-out component used in production.
clearSession() now calls /api/session/logout, and connectedCallback
validates the session with the server to detect revocation. Also
updated the auth.rspace.online profile page handleLogout().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:46:44 -07:00
Jeff Emmett aa4a200f32 feat(history): add "Revert to this point" button in Time Machine panel
Forward Automerge change that overwrites content fields with snapshot data,
preserving meta and full history. Also fixes pre-existing TS errors in
folk-flow-river (undefined exitX) and test-full-loop (StepResult type).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 19:08:15 -07:00
Jeff Emmett 0c46e33148 fix(collab): embed online badge in tab row instead of fixed overlay
The "N online" collab badge was position:fixed at top:8px, overlapping
the header login area. Move it into the tab bar slot (main shell) or
header-right section (standalone shells) so it flows inline with other
chrome elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 18:19:29 -07:00
Jeff Emmett 1282ba5325 feat(history): humanize activity entries with icons and timestamps
Replace raw Automerge change messages (e.g. "Update shape abc-123-uuid")
with human-readable text and contextual icons. Add per-entry timestamps
for clearer chronology within author groups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 17:56:13 -07:00
Jeff Emmett 30f037c2a0 feat(dashboard): redesign space dashboard with members, activity, votes
Replace the global "Your Spaces" grid with a space-centric dashboard showing
members, previously open tools, recent activity, active votes, and quick
actions. Fix layout cut-off by positioning dashboard fixed below header+tab
row (top: 92px) with sidebar-push support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:57:54 -07:00
Jeff Emmett 389dc70e77 fix(settings): position dropdown below and to the right of gear icon
The panel was right-aligned relative to the button which pushed it
off-screen since the gear is on the left side of the header. Now
left-aligns with the button and clamps to stay within viewport.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:37:25 -07:00
Jeff Emmett afd2a5a40b fix(canvas): persistent drawing tools + online/offline label + drag fixes
Drawing/shape tools (pencil, line, rect, circle) now stay active for
multiple strokes instead of resetting to selector after each use.
Renamed collab overlay badge from "Solo/Share" to "Offline/Online".
Prevent canvas drag when interacting with image-gen and prompt content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:03:15 -07:00
Jeff Emmett 8649598c26 fix(tab-cache): add Accept header so tab fetch works on private spaces
The TabCache fetchAndInject() was sending fetch() without Accept: text/html,
causing the server to treat it as an API request and return 401 on private
spaces. Also adds .catch() fallbacks to shell tab handlers for resilience.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:00:51 -07:00
Jeff Emmett f5de97c60c feat(ux): move comment button to header bar with unresolved badge
Move the "Leave Comment" button from the bottom canvas toolbar to the
top header bar as <rstack-comment-bell>, positioned left of the
notification bell. Shows a red badge with unresolved comment pin count.
Wires canvas via comment-pin-activate/comment-pins-changed custom events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 14:02:27 -07:00
Jeff Emmett b91233092b fix(ux): move people-online badge into sub-tab header bar
- Move people badge + panel from fixed position to inline in .rstack-tab-row
- Badge sits right of the layer toggle icon with a subtle separator
- Panel drops down from badge position instead of floating fixed
- Online/Offline toggle replaces Solo/Multi labels for clarity
- Badge shows "Offline" with gray dot when in offline mode
- Mobile: hide text label, show dots only
- Tab bar gets flex:1 + min-width:0 to share row space

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 13:29:45 -07:00
Jeff Emmett d458a00550 fix(ux): instant bulk-delete dialog + post-login space routing
Bulk delete dialog: switch from click to pointerdown for instant
touch response, raise z-index above all overlays, add hover/active
feedback and keyboard support.

Post-login routing: reload page when logging in on a non-demo space
so access gates clear and CRDT sync reconnects with auth. Silently
provisions personal space in background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 13:21:03 -07:00
Jeff Emmett 1930d7dab0 feat(identity): local persona switcher for client-side multi-account
Store known personas in localStorage, auto-register on login. Dropdown
shows other personas with one-click switch (triggers passkey re-auth),
add/remove persona buttons, and cross-tab sync.

Also fix pre-existing TS errors: non-null assert on filtered functionCall,
add optional VerifyOptions param to authenticateWSUpgrade type declaration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 12:10:55 -07:00
Jeff Emmett 73cc1d1cc4 feat(spaces): add Create Space modal with member invites and invite links
Adds an intermediate modal when creating a space: name/slug editing with
availability check, description, visibility radio cards, discoverable
toggle, member search with @username lookup and email invites, and a
shareable invite link generated post-creation.

Server: adds discoverable field to CommunityMeta, extends PATCH /:slug,
adds POST /:slug/invites for generic invite token creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 12:04:27 -07:00
Jeff Emmett 48d11f5ec9 feat(canvas): simplify comment pins — optional notes + link rNotes
Pins no longer require a message. Added "Link existing rNote" picker
to attach space notes to pins. Linked notes show as clickable links
in the popover with unlink option.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 19:13:58 -07:00
Jeff Emmett 07e3c7348c feat(canvas): add Figma-style comment pin system
Overlay markers at canvas or shape-relative coords with threaded
comments, @mention notifications, and rSchedule reminder integration.
Toolbar "Leave Comment" button (/) next to Note tool.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:47:03 -07:00
Jeff Emmett 7618433498 refactor(auth): replace @encryptid/sdk imports with local auth module
Consolidates token verification into server/auth.ts, removing the
external SDK dependency. All modules now import from the local module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 16:41:59 -07:00
Jeff Emmett 29c4f48634 feat(identity): store verified email on profile + show in account modal
Email verification wrote to the `email` column but account status read
from `profile_email` — now setUserEmail writes both. Account modal email
section displays the verified address when collapsed. Tour finale step
triggers identity setup on completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 15:49:09 -07:00
Jeff Emmett 2de61cd7ad feat(rcal): move zoom/legend below calendar, add multi-day event spans
- Reorder layout: nav → calendar → legend → zoom bars → bottom bar
- Add "Calendar Legend" heading above source badges
- Fix getEventsForDate() to support multi-day range checking
- Render colored span bars across day cells for multi-day events
- Make showAccountModal/isSignedIn public on rstack-identity
- Tour final step triggers identity setup flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 15:10:39 -07:00
Jeff Emmett 466a0305fd fix(spaces): dedup space switcher + restructure into sections
Personal space rename only applies when isPersonal flag is set (not all
private spaces). Demo forced to public visibility. Public spaces no
longer filtered out. Sections: Private → Permissioned → Public →
✦ Discover → Create.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 14:35:07 -07:00
Jeff Emmett fe7157ffe1 fix(shell): position settings/history panels below their buttons
Both panels now use position:fixed with JS-computed coordinates from
getBoundingClientRect(), ensuring they open directly below their
respective header buttons and right-aligned to the button edge.
History panel clamps left edge to prevent off-screen overflow.

Also adds missing click handlers for settings-btn and history-btn
in canvas.html (previously only wired in shell.ts module pages).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:59:44 -07:00
Jeff Emmett 63c1b7c1e7 refactor(shell): convert settings & history panels to dropdown menus
Replace full-height slide-in panels with compact dropdowns that appear
beneath header icons. Both icons now grouped in header-right with
mutual exclusion and click-outside-to-close behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 23:17:17 -07:00
Jeff Emmett 6491681e3e fix(auth): force platform authenticator + redirect disabled modules
Force authenticatorAttachment: 'platform' across all WebAuthn registration
flows to prevent USB security key prompts. Redirect browser navigations to
space root when accessing disabled modules instead of returning JSON error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:31:13 -07:00
Jeff Emmett cc504d4a86 fix(spaces): make DID resolve endpoint public (no auth needed for profile data)
The resolve-dids endpoint was returning 401 because unsigned fallback tokens
fail HS256 verification. Since username/displayName is public profile data,
remove auth requirement from the endpoint and client call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 18:06:36 -07:00
Jeff Emmett 524356d233 feat(tours+solo): add tours to remaining modules and solo mode toggle
Add guided tours to 6 modules that were missing them:
- Shadow DOM: rsocials dashboard, crowdsurf, rdata (TourEngine)
- Light DOM: rsplat, rbnb, rvnb (new LightTourEngine class)

Add solo mode toggle to collab overlay — click the presence badge
to hide your cursor/presence from others. Persists via localStorage,
dispatches event to canvas PresenceManager.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 17:26:57 -07:00
Jeff Emmett 64f9603e39 fix(spaces): stop module settings selects from polluting scope overrides
Module settings selects (notebook-id, select types) shared the .scope-select
CSS class with actual data-scope selects, causing their values to be sent as
scopeOverrides — triggering "Invalid scope '' for rnotes" on save.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:49:17 -07:00
Jeff Emmett acafe15c4b feat(spaces): resolve member DIDs to usernames in space settings
Add POST /api/users/resolve-dids batch endpoint in EncryptID, proxy
/api/users/* through rspace server, and batch-resolve missing displayNames
in the space settings panel so owners and members show usernames not DIDs.

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