530f81416a
Replaces the Redis-over-Tailscale handoff with a far simpler HTTP surface on the existing public API — no Redis client, Tailscale, or firewall changes needed on the dev side. - GET /ai/stream — SSE feed of every ingested message, reads the internal Redis stream; resumes from Last-Event-ID on reconnect (no missed messages); heartbeats keep the connection warm through proxies - POST /ai/drafts — writeback: creates a ContentDraft (PENDING_REVIEW) that shows up in the admin /admin/drafts review UI - AiStreamGuard — static bearer token auth (AI_STREAM_TOKEN), accepts header or ?token= query for browser EventSource - Remove Tailscale sidecar + public Redis port; Redis stays internal-only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
31 lines
1.2 KiB
TypeScript
31 lines
1.2 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
const envSchema = z.object({
|
|
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
|
|
DATABASE_URL: z.string().url(),
|
|
REDIS_URL: z.string().url(),
|
|
API_PORT: z.coerce.number().default(3001),
|
|
JWT_SECRET: z.string().min(32),
|
|
MEILI_URL: z.string().url().default('http://localhost:7700'),
|
|
MEILI_MASTER_KEY: z.string().default('tower_meili_dev_key'),
|
|
LOG_LEVEL: z.enum(['trace', 'debug', 'info', 'warn', 'error']).default('info'),
|
|
WHATSAPP_SESSION_PATH: z.string().default('./sessions'),
|
|
TOWER_PORTAL_BASE_URL: z.string().url().default('http://localhost:3000'),
|
|
BCRYPT_ROUNDS: z.coerce.number().int().min(4).max(15).default(10),
|
|
JWT_EXPIRES_IN: z.string().default('7d'),
|
|
MEMBER_JWT_EXPIRES_IN: z.string().default('30d'),
|
|
OPENROUTER_API_KEY: z.string().optional(),
|
|
AI_STREAM_TOKEN: z.string().optional(),
|
|
});
|
|
|
|
export type Env = z.infer<typeof envSchema>;
|
|
|
|
export function validateEnv(env: NodeJS.ProcessEnv = process.env): Env {
|
|
const result = envSchema.safeParse(env);
|
|
if (!result.success) {
|
|
console.error('Invalid environment variables:', result.error.format());
|
|
throw new Error('Invalid environment variables');
|
|
}
|
|
return result.data;
|
|
}
|