From 356e4d5c9504e2ddfd842308df71b8f4c55123a9 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Mon, 28 Sep 2026 13:53:46 +0700 Subject: [PATCH] feat(ai): route production AI to our own proxy on ai.skate-spots.org - DNS: A record ai.skate-spots.org -> 185.18.221.2 (Netlify DNS). - TLS: Caddy on the CVM host, automatic Let's Encrypt (verified live). - Client: production builds (web + APK) now default to https://ai.skate-spots.org/api/ai; dev uses local /api/ai. Override with VITE_SASQUATCH_AI_BASE to revert to the Netlify Function, which stays deployed as a fallback. --- AGENTS.md | 13 +++++++------ src/lib/sasquatchAi.ts | 22 ++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 1b9fb9f..df246f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -568,12 +568,13 @@ session with **no other memory of this project**. So: (`SASQUATCH_*`) copied from Netlify env to `~/skatespots-ai/.env` (600); **verified live** (`POST /api/ai/status` → the real Routstr balance). The client picks the base in **one place — `src/lib/sasquatchAi.ts`** (`sasquatchAiBase()`, - also used for the NIP-98 `u` tag): set - `VITE_SASQUATCH_AI_BASE=https://ai.skate-spots.org/api/ai` to switch the app - over; unset keeps the Netlify Function (fully reversible). ⚠️ **Not switched - over yet** — still needs a DNS name → the CVM host + **Caddy** for TLS - (`ai-proxy/Caddyfile`, `ai-proxy/DEPLOY.md`); until then the app calls `/api/ai` - on Netlify. + also used for the NIP-98 `u` tag). **Live (2026-09-28):** `ai.skate-spots.org` + → the CVM host (an `A` record in **Netlify DNS**; ⚠️ the API silently *dropped + the first create* — verify the NS actually serves a new record), TLS via + **Caddy** (auto Let's Encrypt, installed on the host). Production builds now + default to it (`import.meta.env.PROD` → `https://ai.skate-spots.org/api/ai`); + dev uses local `/api/ai`. ⚠️ `netlify/functions/ai.mjs` is now a **fallback + only** — revert with `VITE_SASQUATCH_AI_BASE=https://skate-spots.org/api/ai`. - **Mints directory**: `/mints` page lists Cashu mints from the community **MintRadar** project. MintRadar has **no CORS**, so it's fetched same-origin at `/api/mints/*` — prod proxies via `public/_redirects` (`/api/mints/* → diff --git a/src/lib/sasquatchAi.ts b/src/lib/sasquatchAi.ts index 88f0ece..590c28e 100644 --- a/src/lib/sasquatchAi.ts +++ b/src/lib/sasquatchAi.ts @@ -1,24 +1,22 @@ import { isNativePlatform } from '@/lib/platform'; /** - * Base URL of the Sasquatch AI proxy — the single place the app decides where AI - * requests go. + * Where Sasquatch's AI requests go. * - * Default: the original Netlify Function at `/api/ai` (same-origin on web; the - * absolute production origin on native, which has no same-origin server). + * Production builds (the web bundle AND the Capacitor APK — both are `vite + * build`) call our own proxy on the CVM host: `ai-proxy/`, see + * `ai-proxy/DEPLOY.md`. Dev keeps using the local `/api/ai`. * - * To move AI off Netlify onto our own host (ai-proxy/ on the CVM host), set the - * build-time override: - * VITE_SASQUATCH_AI_BASE=https://ai.skate-spots.org/api/ai - * This is a pure routing switch and trivially reversible: the proxy accepts any - * host — it only checks that a NIP-98 `u` value ends in `/api/ai`. - * - * Returns an absolute URL, so it's safe to use both for `fetch()` and as the - * NIP-98 `u` tag. + * `VITE_SASQUATCH_AI_BASE` overrides both — e.g. point back at the Netlify + * Function with `https://skate-spots.org/api/ai` to revert. That function stays + * deployed as a fallback path. */ +const PRODUCTION_AI_BASE = 'https://ai.skate-spots.org/api/ai'; + export function sasquatchAiBase(): string { const override = (import.meta.env as Record).VITE_SASQUATCH_AI_BASE; if (override) return override.replace(/\/+$/, ''); + if (import.meta.env.PROD) return PRODUCTION_AI_BASE; if (isNativePlatform()) return 'https://skate-spots.org/api/ai'; const origin = typeof location !== 'undefined' ? location.origin : 'https://skate-spots.org'; return `${origin}/api/ai`;