mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-09-20 08:02:19 +02:00
CARTO now requires an API key for its basemap tiles; without one every tile in the DEFAULT dark/light map carries an "API KEY REQUIRED" watermark. The tile URLs were hardcoded in mapStyles.ts with no way to supply a key, and because the frontend ships as a prebuilt image a NEXT_PUBLIC_ variable would be baked in empty for every Docker user. - New frontend-local route GET /api/basemap-config reads CARTO_API_KEY from the frontend container's environment at request time (same pattern as BACKEND_URL), so no image rebuild is needed. - useBasemapConfig() fetches it once per page load; MaplibreViewer builds the MapLibre style from it via buildBasemapStyle(theme, key) and defers the map's first style load until the config has settled, avoiding a burst of unkeyed tile requests followed by a style swap. - Tile URLs move to CARTO's documented rastertiles/ path with ?key= appended when configured. Unkeyed URLs serve byte-identical tiles to the old path, so deployments without a key behave exactly as before. - CARTO_API_KEY wired through docker-compose.yml and documented in .env.example, README (data source table + frontend env table) and docs/OUTBOUND_DATA.md. - Tests cover the route (unset / set / trimmed) and the style builder. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
/**
|
|
* Runtime basemap configuration for the browser map.
|
|
*
|
|
* CARTO_API_KEY is a plain server-side env var on the frontend container
|
|
* (see docker-compose.yml). Like BACKEND_URL it is read at request time, so
|
|
* operators running the prebuilt GHCR image can set it in .env without a
|
|
* rebuild. A NEXT_PUBLIC_ var would be baked in at image build time and
|
|
* therefore always empty for them.
|
|
*
|
|
* The key is not a secret in the usual sense — the browser sends it to
|
|
* CARTO on every tile request — but it is only returned to same-origin
|
|
* callers of this Next.js server, never proxied to the backend.
|
|
*/
|
|
|
|
import { NextResponse } from 'next/server';
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
const NO_STORE_HEADERS = {
|
|
'Cache-Control': 'no-store, max-age=0',
|
|
Pragma: 'no-cache',
|
|
};
|
|
|
|
export type BasemapConfigResponse = {
|
|
carto: {
|
|
configured: boolean;
|
|
key: string;
|
|
};
|
|
};
|
|
|
|
export function readCartoApiKey(): string {
|
|
return String(process.env.CARTO_API_KEY || '').trim();
|
|
}
|
|
|
|
export async function GET() {
|
|
const key = readCartoApiKey();
|
|
const body: BasemapConfigResponse = {
|
|
carto: { configured: key.length > 0, key },
|
|
};
|
|
return NextResponse.json(body, { headers: NO_STORE_HEADERS });
|
|
}
|