Initial implementation of Bluetooth toy control app
Next.js app with a browser-side buttplug/buttplug-wasm control layer (server never touches real-time device commands), SQLite storage via Drizzle, single-secret auth, recordings/replay with device remapping, a usage stats dashboard, Docker deployment, and Gitea CI. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8WkFF5ppURBAB918593Eb
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod";
|
||||
|
||||
// ACCESS_PASSWORD gates the login form; AUTH_SECRET signs the session JWT.
|
||||
// These are deliberately separate - reusing the login password as the
|
||||
// signing key would let a JWT-signing weakness leak the login secret itself.
|
||||
const envSchema = z.object({
|
||||
ACCESS_PASSWORD: z.string().min(1, "ACCESS_PASSWORD must be set"),
|
||||
AUTH_SECRET: z.string().min(16, "AUTH_SECRET must be at least 16 characters"),
|
||||
DATABASE_PATH: z.string().min(1).default("./data/app.db"),
|
||||
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).optional(),
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof envSchema>;
|
||||
|
||||
let cached: Env | undefined;
|
||||
|
||||
export function getEnv(): Env {
|
||||
if (cached) return cached;
|
||||
const parsed = envSchema.safeParse(process.env);
|
||||
if (!parsed.success) {
|
||||
throw new Error(`Invalid environment configuration: ${parsed.error.message}`);
|
||||
}
|
||||
cached = parsed.data;
|
||||
return cached;
|
||||
}
|
||||
Reference in New Issue
Block a user