跳转到主要内容
这些端点不属于任何领域 RPC 服务 —— 它们位于 API 表面的根层,负责处理平台层面的关注点。

引导

GET /api/bootstrap

为仪表盘提供单次往返的初始数据加载。在单次响应中返回所有已注册引导的 Redis 缓存键,从其 seed 封装中解包出来。
  • 认证:浏览器 wm-session cookie、X-WorldMonitor-KeyX-Api-Key 别名。用户签发的密钥会针对当前 API 访问权限进行验证。
  • 匿名天气:?keys=weatherAlerts 仅在未发送任何 API 密钥头时公开。如果你附加 X-WorldMonitor-Key / X-Api-Key,即使是天气请求也会被完全验证 —— 格式错误的密钥返回 401,没有当前 API 访问权限的密钥返回 403。始终发送密钥的调用方必须发送有效的、有权限的密钥(或省略该头以使用匿名天气路径)。
  • 服务器到服务器:直接用 X-WorldMonitor-Key: wm_... 调用 https://api.worldmonitor.app/api/bootstrap。此端点没有单独的网关主机、令牌交换、激活步骤或 IP 白名单要求。
  • 缓存:浏览器/会话响应保留默认分层缓存策略:全键响应使用 Cache-Control: public, s-maxage=600, stale-while-revalidate=120, stale-if-error=900 加上快速层的 CDN-Cache-Control;显式 ?tier=fast / ?tier=slow 请求使用浏览器 max-age=60 / max-age=300 和 CDN s-maxage=600 / s-maxage=7200。密钥认证的响应使用 Cache-Control: no-store 且不发出 CDN 缓存头。
  • 速率限制:此端点上的用户 API 密钥验证具有 fail-closed 的固定每 IP 60 秒 600 次预验证上限,与默认的 API 滑动窗口限流器分开。
  • 结构:{ "data": { "earthquakes": ..., "outages": ..., "marketQuotes": ... }, "missing": [] } —— 约 40+ 个已解包的已 seed 领域负载嵌套在 data 之下,外加一个 missing 列表用于 Redis 中不存在的缓存键。
在页面初始加载时使用此端点,可避免 40 个并行的 RPC 调用。

版本

GET /api/version

返回 koala73/worldmonitor 的最新 GitHub Release。桌面应用使用此端点检测是否有更新的发布版本,并提示用户升级。它不是当前部署的 Vercel commit。
{
  "version": "2.6.7",
  "tag": "v2.6.7",
  "url": "https://github.com/koala73/worldmonitor/releases/tag/v2.6.7",
  "prerelease": false
}
缓存策略为 public, s-maxage=300, stale-while-revalidate=60, stale-if-error=3600。当 GitHub API 不可达时,返回 502 { "error": "upstream" }502 { "error": "fetch_failed" }

缓存清理

POST /api/cache-purge

内部端点。通过显式列表或 glob 模式使 Redis 缓存键失效。
  • 认证:Authorization: Bearer $RELAY_SHARED_SECRET(使用 timing-safe 比较)。其他任何凭据返回 401
  • 请求体(keys / patterns 至少需要其一):
    {
      "keys":     ["market:stocks-bootstrap:v1", "infra:outages:v1"],
      "patterns": ["market:sectors:*"],
      "dryRun":   false
    }
    
  • 限制:最多 20 个显式键,最多 3 个模式(每个必须以 * 结尾,裸 * 会被拒绝),总共最多 200 次删除,每个模式最多 5 次 SCAN 迭代。
  • 安全:前缀为 rl: / __ 的键始终被跳过;会匹配 military:bases:*conflict:iran-events:*conflict:ucdp-events:*(持久 seed)的模式会被跳过。
  • 非生产环境:在 preview / development 部署上,键会自动加上 {env}:{git-sha}: 前缀,因此清理操作不会影响生产数据。
  • 响应:
    { "matched": 4, "deleted": 4, "keys": ["..."], "dryRun": false, "truncated": false }
    

健康检查

GET /api/health

针对所有已注册 seed 键的聚合新鲜度报告。在 JSON status 字段中返回 HEALTHYWARNINGDEGRADEDUNHEALTHYREDIS_DOWN REDIS_DOWN 外的所有状态均返回 HTTP 200。REDIS_DOWN 返回 HTTP 503,因为 Redis 不可达且端点无法评估 seed 状态。响应不被缓存(private, no-store, max-age=0 加上 CDN-Cache-Control: no-store)。 通过 UptimeRobot / Better Stack 并使用 ?compact=1 进行监控 —— 任何非 HEALTHY 状态都应触发告警。完整的详细视图需要 operator/enterprise API 密钥,因为它包含规范的缓存键名和新鲜度阈值。
{
  "status": "HEALTHY",
  "checkedAt": "2026-04-19T12:00:00Z",
  "summary": {
    "total": 194,
    "ok": 180,
    "warn": 5,
    "onDemandWarn": 9,
    "staleContent": 0,
    "crit": 0
  },
  "checks": {
    "marketQuotes": { "status": "OK", "records": 78, "seedAgeMin": 12 },
    "earthquakes": { "status": "OK", "records": 142, "seedAgeMin": 8 }
  }
}

GET /api/seed-health

针对由 Railway cron 驱动的 seeder 的并行注册表,具有各自的节奏阈值。与 /api/health 不同 —— 当节奏变化时两者都必须更新。参见健康检查端点

POST /api/seed-contract-probe

内部探针,用于验证每个 seed 生产者的封装结构是否与其消费者匹配。如果任何消费者读取了生产者不再输出的字段,则返回违规。

用户偏好设置

GET /api/user-prefs

POST /api/user-prefs

每用户仪表盘偏好设置(布局、开关、过滤器)。需要 Clerk bearer 凭据。由 Convex 提供支持。
{
  "layout": "classic",
  "enabledLayers": ["conflict", "aviation", "maritime"],
  "defaultCountry": "US"
}
  • 幂等性:POST /api/user-prefs 上支持可选的 Idempotency-Key。使用相同键重试并附带相同请求体会重放原始偏好设置响应,而非再次应用更新。

API key 缓存失效

POST /api/invalidate-user-api-key-cache

在订阅变更后(Dodo webhook → Convex → 此端点)使用户的权益(entitlement)缓存失效。内部端点 —— 需要 RELAY_SHARED_SECRET

地理工具

GET /api/geo?iso2=US

返回国家元数据:质心、bbox、首都、ISO 代码。

GET /api/reverse-geocode?lat=40.7&lon=-74.0

使用内置坐标数据集将 lat/lon 反向地理编码为最近的国家 + 城市。

GET /api/data/city-coords?q=Tokyo

城市名 → 坐标查询。

实用工具

GET /api/download?platform=<id>&variant=<id>

重定向到 koala73/worldmonitor 最新 GitHub release 中匹配的资产。成功时返回 302 指向资产 URL,任何失败时(未知平台、无匹配、GitHub 错误)返回 302 指向 releases/latest platform(必填,精确字符串):
匹配
windows-exe*_x64-setup.exe
windows-msi*_x64_en-US.msi
macos-arm64*_aarch64.dmg
macos-x64*_x64.dmg(排除 *setup*)
linux-appimage*_amd64.AppImage
linux-appimage-arm64*_aarch64.AppImage
variant(可选):
将资产名称过滤为
full / worldworldmonitor
techtechmonitor
financefinancemonitor
将 302 缓存 5 分钟(s-maxage=300stale-while-revalidate=60stale-if-error=600)。

POST /api/leads/v1/submit-contact

公开的企业联系表单。通过 Turnstile 验证,按 IP 限流。属于 LeadsService 的一部分。

POST /api/leads/v1/register-interest

捕获邮箱用于 Pro 候补名单注册。写入 Convex 并发送确认邮件。属于 LeadsService 的一部分。 浏览器调用方必须通过 Turnstile。使用 source: "desktop-settings" 的桌面调用方仅当请求使用共享的桌面密钥进行身份验证时,才能绕过 Turnstile:
  • X-WorldMonitor-Desktop-Timestamp:Unix epoch 毫秒,与服务器时间相差不超过 5 分钟。
  • X-WorldMonitor-Desktop-Signature:sha256=<hex HMAC-SHA256>
HMAC 输入为 <timestamp>\n<canonical JSON>,其中 canonical JSON 按顺序包含 emailsourceappVersionreferredBywebsiteturnstileToken。在桌面 sidecar 和云 API 上都要配置 WM_DESKTOP_SHARED_SECRET。在滚动推出期间,WM_DESKTOP_AUTH_ALLOW_LEGACY=true 仅在云 API 未配置 WM_DESKTOP_SHARED_SECRET 时接受未签名的旧版桌面请求。一旦设置了云密钥,桌面请求在缺少有效签名时将拒绝访问(fail closed),且仍受更严格的桌面限流约束。