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.
This commit is contained in:
SkateSpots 2026-09-28 13:53:46 +07:00
parent ec06a63b01
commit 356e4d5c95
2 changed files with 17 additions and 18 deletions

View file

@ -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/* →

View file

@ -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<string, string | undefined>).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`;