Banzhaf & Shapley-Shubik power index computation via DP, integrated
into trust engine 5-min cycle. Power tab in rNetwork 3D graph viewer
with animated bar chart, Gini/HHI gauges, and Banzhaf-scaled node
sizes. On-demand computation when DB empty. Left-drag now rotates.
New files:
- src/encryptid/power-indices.ts (pure math: Banzhaf DP, SS DP, Gini, HHI)
- modules/rnetwork/components/folk-power-indices.ts (standalone component)
API: GET /api/power-indices, GET /api/power-indices/:did,
POST /api/power-indices/simulate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove authenticatorAttachment:'platform' constraint so Firefox (and all
browsers) show security keys, phone-as-authenticator, and PIN options
alongside biometrics when registering a new passkey.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Send branded welcome email when user first adds profileEmail
- Reframe landing page around group coordination, not app listing
- Wordmark: orange r + teal Space matching favicon branding
- (you)rSpace wordplay in tagline, final CTA, meta tags, email
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add detectDeviceName() JS helper to all 6 registration pages (parses
UA → "Chrome on Windows", "Safari on iPhone", etc.)
- Accept deviceName in /api/register/complete, /api/account/device/complete,
and /api/device-link/:token/complete; store as credential label at creation
- Add optional label param to storeCredential() in db.ts
- Replace separate "Your Passkeys" section with unified device list in
"Linked Devices" showing name, status, created/last-used dates, and
inline rename (PATCH) and delete (DELETE) actions
- Make checklist "Second device" confirmation-aware: only marks done when
a second device has actually been used to sign in (has lastUsed set)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When scanning a device-link QR code, many phone apps open the URL in
an embedded WebView that lacks PublicKeyCredential support, causing
"user agent does not support public key credentials". Now the /link
page checks for WebAuthn early and shows a helpful fallback with a
Copy Link button so the user can open it in Safari/Chrome instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Generate or load RSA keypair for OIDC token signing (OIDC_RSA_PRIVATE_KEY env)
- Add /oidc/jwks endpoint exposing public key in JWK format
- Update discovery document with jwks_uri and RS256 algorithm
- Sign ID tokens and access tokens with RS256 private key
- Verify access tokens with RS256 public key in userinfo
- Fix OIDC_ISSUER default to auth.rspace.online (was auth.ridentity.online)
- Add POST handler for /oidc/userinfo (RFC compliance)
- Add error logging to userinfo endpoint for debugging
Fixes Cloudflare Access OIDC integration which requires asymmetric
token signing via JWKS for ID token verification.
Co-Authored-By: Claude Opus 4.6 <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>
New folk-holon-explorer shape unifying H3 geospatial holons and nested
rSpace spaces into a zoomable circular navigator with appreciation weight
normalization and MetatronGrid sacred geometry background. Endorsements
logged to trust engine via new POST /api/trust/endorse endpoint.
Co-Authored-By: Claude Opus 4.6 <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>
TASK-120 Phases 1-2: Add Linea mainnet (59144) and Linea Sepolia (59141)
to all chain maps (CHAIN_MAP, RPC, env names, native tokens, popular tokens,
CoinGecko, Zerion, chain colors/names, Safe prefixes). New WalletAdapter
class provides chain-parameterized abstraction over Safe/EOA/UP wallets
with immutable withUniversalProfile() and fromSafe/fromEOA/fromUP factories.
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>
Registration was hardcoded to authenticatorAttachment: 'platform',
which rejects devices without a platform authenticator (common on
Linux desktops). Now only forces platform when available, otherwise
lets browser offer cross-platform options (security keys, phone as
authenticator). Also relaxed isEncryptIDAvailable() to only require
WebAuthn support, not platform auth specifically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When EncryptID server returns plain text errors (e.g. "Internal Server
Error"), the client's .json() calls threw SyntaxError which surfaced
as an ugly parse error to users. Add .catch() to all unsafe .json()
calls in session.ts, login-button.ts, and recovery.ts so auth
gracefully falls back to unsigned tokens instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SMTP auth (port 587) credentials are stale, causing 535 auth failures
on startup. Detect internal mailcow/postfix hosts and connect on port
25 without auth, matching the pattern already used in server/spaces.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ranking: replace broken :hover drop-target with getBoundingClientRect hit testing
- Spider: add #isSliding guard to prevent slider destruction during drag
- Video gen: bump timeout to 10min, show real fal.ai queue position/status
- Fix NotificationCategory type to include 'payment' in db.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add internal endpoints for payment infrastructure integration:
- GET /api/internal/user-by-wallet — resolve wallet to email/username
- POST /api/internal/notify — trigger in-app notifications by wallet/DID
- Add 'payment' notification category and payment_sent/received event types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- App switcher: only show "Manage rApps" when there are actually
disabled modules or active restrictions. Move "Available to Add"
above "Remove" to prioritize adding. Eliminates duplicate module
listing when all modules are enabled.
- Shell: update app switcher on modules-changed event (was only
updating tab bar and folk-rapp, not the sidebar itself).
- SMTP: use space-agent@rspace.online as From for invite/approval
emails with proper envelope sender for DKIM alignment.
- Shell CSS: fix banner z-index, smooth header transition on banner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rTasks: port backlog-md ordinal algorithm (bisection + rebalance),
fix column detection via bounding-box hit test, add empty-column
drop zones, source column dimming, no-op detection, and optimistic
DOM updates (no flash). New bulk-sort-order rebalance endpoint.
EncryptID: sync claimed invite members to Automerge doc immediately,
redirect to space subdomain after identity claim.
Server: add /api/internal/sync-space-member endpoint, fallback
member check in WebSocket auth for not-yet-synced invites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each space gets {space}-agent@rspace.online as a real Mailcow mailbox
(auto-provisioned with generated password). Inbound emails are IMAP-polled
and processed by MI (Gemini Flash) for auto-reply. All outbound emails
(approvals, notifications) set reply-to to the agent address so replies
route back through MI.
- mailcow.ts: createMailbox/deleteMailbox/mailboxExists API
- schema.sql + db.ts: agent_mailboxes table for per-space IMAP creds
- space-alias-service.ts: provisionAgentMailbox/deprovisionAgentMailbox
- server.ts: internal routes for agent mailbox CRUD + member-emails
- rinbox/mod.ts: initAgentMailbox, per-space IMAP sync, processAgentMI
- rinbox/agent-notify.ts: sendSpaceNotification (BCC members)
- rcal/rtasks/rvote: notification hooks on create
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add label column to credentials, PATCH/DELETE endpoints for rename/remove,
device list UI in account modal with rename/remove actions, and clear stale
nudge dismiss timestamp after device registration so multiDevice API check
takes over permanently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix invite accept fetch URL in shell.ts (was missing /api/spaces prefix)
- After accepting invite, redirect to the invited space instead of reloading
- Notification actionUrls now point to the space subdomain (https://slug.rspace.online)
- Direct-add email includes inviter name, role, and space description
- Identity invite email includes space name/role context when inviting to a space
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
listSpaceInvites now queries both space_invites and identity_invites
tables, merging results so email-based invites (via /invite endpoint)
appear in the Pending Invites section. revokeSpaceInvite also falls
through to identity_invites if not found in space_invites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
- login-button.ts: no-known-accounts state shows passkey-first button
(unscoped WebAuthn) with email magic link fallback, auto-revealed on
NotAllowedError. Fix stale usernameInput ref.
- server.ts (auth.rspace.online): add localStorage known accounts system.
Returning users see their stored usernames as clickable buttons.
handleAuth() accepts optional username for scoped auth. Saves account
after successful login. renderSigninAccounts() called on page init.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Provision {space}@rspace.online forwarding aliases that route to
opted-in members' personal emails. Admins/mods opted in by default;
regular members can opt in via PUT /api/spaces/:slug/email-forwarding/me.
New: space-alias-service.ts, schema tables, 8 DB functions, 6 API routes.
Hooks: rinbox onSpaceCreate/Delete, spaces.ts member lifecycle, startup migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no known accounts exist in localStorage, show a username/email
input field instead of immediately triggering the unscoped passkey
picker. User types their username, then gets a scoped passkey prompt
for only that account's credentials.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logout no longer removes the account from the picker — users see
"Sign in as [username]" on next visit. fetchScopedCredentials now
returns full PublicKeyCredentialDescriptor with transports so the
browser can locate the right authenticator without showing a picker.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scoped passkey prompts via /api/auth/start so the browser only shows
matching credentials for the selected account. Known accounts stored
in localStorage and surfaced as a picker (1 account = named button,
multiple = list). "Use a different account" falls back to unscoped.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
When a user logs out in one browser, all other sessions are now revoked
on their next page load or token refresh. Adds logged_out_at column to
users table, server-side revocation checks on verify/refresh endpoints,
and a new /api/session/logout endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AES-256-GCM encryption for 18 PII fields across 6 tables (users,
guardians, identity_invites, space_invites, notifications, fund_claims).
HMAC-SHA256 hash indexes for email/UP address lookups. Keys derived from
JWT_SECRET via HKDF with dedicated salts. Dual-write to both plaintext
and _enc columns during transition; row mappers decrypt with plaintext
fallback. Includes idempotent backfill migration script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add /recover/social page for users to finalize account recovery after
guardian approvals, fix status filter so approved requests remain
findable, return requestId from initiation API with tracking link on
login page, and add actionUrl to recovery notifications.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The rspace container cannot resolve encryptid-db hostname, causing
/api/notifications/count to 524 timeout on every 30s poll. Rewrites
notification-routes.ts as an HTTP proxy to encryptid (which has DB
access), adds notification API endpoints to encryptid server, and
wraps BroadcastChannel.postMessage in try/catch to prevent uncaught
errors during navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
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>
New users get sent to /join for passkey registration + auto-space-join.
Existing users are directly added with in-app + email notification.
Add-by-username now also sends email notification if email is on file.
- Add id to /api/users/lookup response
- Enhance /api/internal/user-email/:userId with recovery + profile email
- Add GET /api/internal/user-by-email for email→DID resolution
- Rewrite POST /:slug/invite to use identity invite flow
- Add email notification to POST /:slug/members/add
- Add success/error feedback to space settings invite UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New spaces start with an empty canvas instead of 25+ template shapes.
Each space gets a {slug}@rspace.online team inbox (multi-sig ready)
via the rinbox onSpaceCreate hook. Fix EncryptID auto-provision passing
raw string instead of SpaceLifecycleContext to module hooks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix DID mismatch: server now stores and reads proper did🔑z6Mk... DIDs
from database instead of deriving truncated did🔑${slice(0,32)}
- Add PRF extension to WebAuthn create/get flows for client-side key derivation
- Derive DID, signing keys, encryption keys, and EOA wallet from passkey PRF
- Auto-upgrade truncated DIDs to proper format on sign-in
- Add POST /api/account/upgrade-did endpoint for DID migration
- Add 5-step educational registration wizard (identity, passkey, DID, wallet, security)
- Add email/username field to sign-in for scoped passkey selection
- Add magic link email login for external devices without passkeys
- Add POST /api/auth/magic-link and GET /magic-login verification page
- Add mintWelcomeBalance() for 5 fUSDC to new users
- Store EOA wallet address during registration when PRF available
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Space creation was broken because the canvas module has id "rspace" but
all navigation URLs used "/canvas". On production subdomain routing this
resulted in 404s after creating a space.
- Switch create-space form from deprecated /api/communities to /api/spaces
- Replace all /canvas navigation URLs with /rspace to match module ID
- Fix DID matching in space listing to check both sub and did:key formats
- Add proper client DID support in EncryptID registration flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mailcow rejects noreply@rspace.online because the authenticated user
is noreply@rmail.online. Updated all SMTP_FROM and SMTP_USER defaults
to use rmail.online consistently: spaces invites, rSplat notifications,
EncryptID auth emails, and rCart payment receipts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
activeLayerId was being written to the shared Automerge CRDT on every tab
switch, causing all open windows/devices to follow. Now active tab is
local-only. Adds REST API + server-side storage so authenticated users'
tab lists persist across sessions and devices.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- schema.sql: UP columns (up_address, up_key_manager_address, up_chain_id, up_deployed_at)
- db.ts: getUserUPAddress, setUserUPAddress, getUserByUPAddress
- server.ts: GET/POST /api/profile/:id/up endpoints, UP info in JWT claims
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add EncryptID internal endpoint for email lookup by userId
- rcart: send "Payment Sent" to payer and "Payment Received" to recipient
- rcart: resolve emails via EncryptID when not provided in request
- rsplat: add GLB/GLTF 3D viewer using Three.js GLTFLoader
- rsplat: enable publicWrite for photo uploads without space membership
- docker-compose: add SITE_URL and SPLAT_NOTIFY_EMAIL env vars
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>