Scrum4Me/lib/env.ts
Janpeter Visser eaabec8471
feat(PBI-66): wekelijkse sync van model_prices via Anthropic /v1/models (#167)
Nieuw script `npm run db:sync-model-prices` haalt de actuele Claude 4.x
modellijst op bij de Anthropic API en upsert prijzen in `model_prices`.
Anthropic biedt geen prijs-API, dus prijzen blijven onderhouden in een
PRICE_TABLE constante in het script. Cache-tier-prijzen worden afgeleid
via vaste multipliers (read 0.1x, write 1.25x). Nieuwe Claude 4.x modellen
worden gedetecteerd en gelogd als warning zodat duidelijk is wanneer de
tabel handmatig moet worden bijgewerkt.

- scripts/sync-model-prices.ts: idempotent upsert, --dry-run, retry op 5xx
- ANTHROPIC_API_KEY als optional env-var (.env.example, lib/env.ts)
- scripts/README.md: gebruiksinstructies + edge cases
- docs/plans/sync-model-prices.md: ontwerpdocument

Verificatie: `npm run lint`, `vitest` (563/563), TypeScript clean.
Echt gedraaid tegen DB: 3 created (eerste run) -> 3 unchanged (tweede run).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:38:33 +02:00

36 lines
1.5 KiB
TypeScript

import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().min(1, 'DATABASE_URL is required'),
DIRECT_URL: z.string().optional(),
SESSION_SECRET: z.string().min(32, 'SESSION_SECRET must be at least 32 characters'),
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
// M11 (ST-1107) — gedeeld geheim tussen Vercel cron-trigger en
// /api/cron/expire-questions. In productie verplicht; lokaal dev mag missen
// (de cron-route geeft 401 als de header niet matcht).
CRON_SECRET: z.string().optional(),
// PBI-55 Web Push — alle vier .optional() zodat de app ook start zonder VAPID
NEXT_PUBLIC_VAPID_PUBLIC_KEY: z.string().optional(),
VAPID_PRIVATE_KEY: z.string().optional(),
VAPID_SUBJECT: z
.string()
.refine(
(v) => v.startsWith('mailto:') || z.string().email().safeParse(v).success,
{ message: 'VAPID_SUBJECT must start with mailto: or be a valid email' }
)
.optional(),
INTERNAL_PUSH_SECRET: z.string().min(32).optional(),
// PBI-66 — Anthropic API key voor scripts/sync-model-prices.ts.
// Niet nodig in app-runtime, alleen bij het wekelijkse sync-script.
ANTHROPIC_API_KEY: z.string().optional(),
})
const parsed = envSchema.safeParse(process.env)
if (!parsed.success) {
console.error('❌ Invalid environment variables:')
console.error(parsed.error.flatten().fieldErrors)
throw new Error('Invalid environment variables. Check .env.local.')
}
export const env = parsed.data