Bundles leaflet CSS + MarkerCluster CSS (main.tsx) and the default marker PNGs (SpotMap) instead of loading them from unpkg.com, so boot makes no third-party request; unpkg.com removed from the CSP (index.html meta + _headers + netlify.toml). Adds dns-prefetch/preconnect for relay.skate-spots.org and blossom.skate-spots.org.
- netlify/functions/ai.mjs: POST /api/ai runs against Netlify's AI Gateway —
Netlify injects OPENROUTER_API_KEY + OPENROUTER_BASE_URL into Functions, so no
key is managed or shipped. Curated model allowlist, best-effort per-IP
throttle, CORS for web + Capacitor, and SSE streamed straight through.
- sasquatchBrain: call the proxy instead of OpenRouter directly; drop
VITE_OPENROUTER_API_KEY entirely; PROXY_MODELS set to the slugs that actually
work via the gateway (its ZDR policy blocks gemini/anthropic/gpt-4o-mini).
- netlify.toml: [functions] directory.
- Verified in production: POST https://skate-spots.org/api/ai -> 200.
- Add root SECURITY.md documenting the threat model (plaintext nsec / NWC in
localStorage inherent to client-side Nostr), reporting channels (Nostr DM /
NIP-05), in/out of scope, the CSP and its trade-offs, untrusted-data
rendering rules, URL/CSS sanitization, author-scoped queries, NWC budget
guidance, accepted residual risks, and an auditor file map.
- netlify.toml now serves the same Content-Security-Policy as public/_headers
and uses X-Frame-Options: DENY + Permissions-Policy, so the hardening holds
regardless of which static host serves the web build.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>