Voeg web-push + @types/web-push toe aan package.json. Registreer NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT en INTERNAL_PUSH_SECRET als .optional() in lib/env.ts. Documenteer alle vier in .env.example en README. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
33 lines
1.3 KiB
TypeScript
33 lines
1.3 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(),
|
|
})
|
|
|
|
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
|