Skip to main content

Overview

Desktop cloud fallback is gated on a WORLDMONITOR_API_KEY. Without a valid key, the desktop app operates local-only (sidecar). A registration form collects emails via Convex DB for future key distribution.

Architecture

Desktop App                          Cloud (Vercel)
┌──────────────────┐                ┌──────────────────────┐
│ fetch('/api/...')│                │ api/[domain]/v1/[rpc]│
│        │         │                │        │              │
│ ┌──────▼───────┐ │                │ ┌──────▼───────┐      │
│ │ sidecar try  │ │                │ │ validateApiKey│      │
│ │ (local-first)│ │                │ │ (origin-aware)│      │
│ └──────┬───────┘ │                │ └──────┬───────┘      │
│   fail │         │                │   401 if invalid      │
│ ┌──────▼───────┐ │   fallback    │                       │
│ │ WM key check │─┼──────────────►│ ┌──────────────┐      │
│ │ (gate)       │ │  +header      │ │ route handler │      │
│ └──────────────┘ │               │ └──────────────┘      │
└──────────────────┘               └──────────────────────┘

Required Environment Variables

Vercel

VariableDescriptionExample
WORLDMONITOR_VALID_KEYSComma-separated list of valid API keyswm_abc123def456,wm_xyz789
CONVEX_URLConvex deployment URL (from npx convex deploy)https://xyz-123.convex.cloud

Generating API keys

Keys must be at least 16 characters (validated client-side). Recommended format:
# Generate a key
openssl rand -hex 24 | sed 's/^/wm_/'
# Example output: wm_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6
Add to WORLDMONITOR_VALID_KEYS in Vercel dashboard (comma-separated, no spaces).

Convex Setup

First-time deployment

# 1. Install (already in package.json)
npm install

# 2. Login to Convex
npx convex login

# 3. Initialize project (creates .env.local with CONVEX_URL)
npx convex init

# 4. Deploy schema and functions
npx convex deploy

# 5. Copy the deployment URL to Vercel env vars
# The URL is printed by `npx convex deploy` and saved in .env.local

Verify Convex deployment

# Typecheck Convex functions
npx convex dev --typecheck

# Open Convex dashboard to see registrations
npx convex dashboard

Schema

The registrations table stores:
FieldTypeDescription
emailstringOriginal email (for display)
normalizedEmailstringLowercased email (for dedup)
registeredAtnumberUnix timestamp
sourcestring?Where the registration came from
appVersionstring?Desktop app version
Indexed by normalizedEmail for duplicate detection.

Security Model

Client-side (desktop app)

  • installRuntimeFetchPatch() checks WORLDMONITOR_API_KEY before allowing cloud fallback
  • Key must be present AND valid (min 16 chars)
  • secretsReady promise ensures secrets are loaded before first fetch (2s timeout)
  • Fail-closed: any error in key check blocks cloud fallback

Server-side (Vercel edge)

  • api/_api-key.js validates X-WorldMonitor-Key header on sebuf routes
  • Origin-aware: desktop origins (tauri.localhost, tauri://, asset://) require a key
  • Web origins (worldmonitor.app) pass through without a key
  • Non-desktop origin with key header: key is still validated
  • Invalid key returns 401 { error: "Invalid API key" }

CORS

X-WorldMonitor-Key is allowed in both server/cors.ts and api/_cors.js.

Verification Checklist

After deployment:
  • Set WORLDMONITOR_VALID_KEYS in Vercel
  • Set CONVEX_URL in Vercel
  • Run npx convex deploy to push schema
  • Desktop without key: cloud fallback blocked (console shows cloud fallback blocked)
  • Desktop with invalid key: sebuf requests get 401
  • Desktop with valid key: cloud fallback works as before
  • Web access: no key required, works normally
  • Registration form: submit email, check Convex dashboard
  • Duplicate email: shows “already registered”
  • Existing settings tabs (LLMs, API Keys, Debug) unchanged

Files Reference

FileRole
src/services/runtime.tsClient-side key gate + header attachment
src/services/runtime-config.tsWORLDMONITOR_API_KEY type, validation, secretsReady
api/_api-key.jsServer-side key validation (origin-aware)
api/[domain]/v1/[rpc].tsSebuf gateway — calls validateApiKey
api/register-interest.jsRegistration endpoint → Convex
server/cors.ts / api/_cors.jsCORS headers with X-WorldMonitor-Key
src/components/WorldMonitorTab.tsSettings UI for key + registration
convex/schema.tsConvex DB schema
convex/registerInterest.tsConvex mutation