Initial commit (unpacked platform)
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { config as loadDotenv } from "dotenv";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
// Ladda .env från paketet ELLER monorepo-roten (pnpm --filter sätter cwd till paketet).
|
||||
for (const candidate of [".env", "../.env", "../../.env"]) {
|
||||
const p = path.resolve(process.cwd(), candidate);
|
||||
if (existsSync(p)) {
|
||||
loadDotenv({ path: p });
|
||||
break;
|
||||
}
|
||||
}
|
||||
import { z } from "zod";
|
||||
import { BRAND } from "@app/shared-types";
|
||||
|
||||
/** All konfiguration valideras vid start – tydliga fel i stället för mystiska krascher. */
|
||||
const configSchema = z.object({
|
||||
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
|
||||
API_PORT: z.coerce.number().int().default(4000),
|
||||
API_BASE_URL: z.string().default("http://localhost:4000"),
|
||||
CORS_ORIGINS: z.string().default("http://localhost:5173"),
|
||||
LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"),
|
||||
|
||||
DATABASE_URL: z.string().default("postgres://app_user:app_dev_password@localhost:5432/app"),
|
||||
REDIS_URL: z.string().default("redis://localhost:6379"),
|
||||
|
||||
JWT_ACCESS_SECRET: z.string().min(10).default("dev-only-change-me"),
|
||||
JWT_REFRESH_SECRET: z.string().min(10).default("dev-only-change-me-too"),
|
||||
JWT_ACCESS_TTL_SECONDS: z.coerce.number().int().default(900),
|
||||
JWT_REFRESH_TTL_SECONDS: z.coerce.number().int().default(2_592_000),
|
||||
|
||||
ENTITLEMENT_SIGNING_SECRET: z.string().min(10).default("dev-only-change-me-three"),
|
||||
ENTITLEMENT_TTL_HOURS: z.coerce.number().int().default(24),
|
||||
ENTITLEMENT_GRACE_DAYS: z.coerce.number().int().default(7),
|
||||
|
||||
S3_MODE: z.enum(["mock", "aws"]).default("mock"),
|
||||
S3_BUCKET: z.string().default(""),
|
||||
S3_REGION: z.string().default("eu-north-1"),
|
||||
/** Tom = AWS S3; sätt för S3-kompatibel lagring (MinIO/R2/Hetzner). */
|
||||
S3_ENDPOINT: z.string().default(""),
|
||||
/** Tomma = IAM-roll/instansprofil används (rekommenderat i AWS). */
|
||||
S3_ACCESS_KEY_ID: z.string().default(""),
|
||||
S3_SECRET_ACCESS_KEY: z.string().default(""),
|
||||
|
||||
AAMOS_MODE: z.enum(["http", "mock"]).default("http"),
|
||||
AAMOS_API_URL: z.string().optional(),
|
||||
AAMOS_API_KEY: z.string().optional(),
|
||||
AAMOS_TIMEOUT_MS: z.coerce.number().int().default(60_000),
|
||||
|
||||
APP_STORE_MODE: z.enum(["production", "sandbox"]).default("sandbox"),
|
||||
EMAIL_MODE: z.enum(["log", "smtp"]).default("log"),
|
||||
SMTP_HOST: z.string().default(""),
|
||||
SMTP_PORT: z.coerce.number().int().default(587),
|
||||
SMTP_SECURE: z
|
||||
.enum(["true", "false"])
|
||||
.default("false")
|
||||
.transform((v) => v === "true"),
|
||||
SMTP_USER: z.string().default(""),
|
||||
SMTP_PASS: z.string().default(""),
|
||||
MAIL_FROM: z.string().default(""),
|
||||
APPLE_BUNDLE_ID: z.string().default(""),
|
||||
GOOGLE_PACKAGE_NAME: z.string().default(""),
|
||||
});
|
||||
|
||||
export type AppConfig = z.infer<typeof configSchema>;
|
||||
|
||||
export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
|
||||
const parsed = configSchema.safeParse(env);
|
||||
if (!parsed.success) {
|
||||
console.error("Ogiltig konfiguration:", parsed.error.flatten().fieldErrors);
|
||||
process.exit(1);
|
||||
}
|
||||
const cfg = parsed.data;
|
||||
// Varumärkesberoende defaults ur brand.config.json (i18n-spec §28)
|
||||
if (!cfg.S3_BUCKET) cfg.S3_BUCKET = `${BRAND.slug}-production`;
|
||||
if (!cfg.APPLE_BUNDLE_ID) cfg.APPLE_BUNDLE_ID = BRAND.iosBundleId;
|
||||
if (!cfg.GOOGLE_PACKAGE_NAME) cfg.GOOGLE_PACKAGE_NAME = BRAND.androidPackage;
|
||||
if (cfg.NODE_ENV === "production") {
|
||||
const insecure = [
|
||||
cfg.JWT_ACCESS_SECRET,
|
||||
cfg.JWT_REFRESH_SECRET,
|
||||
cfg.ENTITLEMENT_SIGNING_SECRET,
|
||||
].some((s) => s.startsWith("dev-only"));
|
||||
if (insecure) {
|
||||
console.error("SÄKERHETSSTOPP: dev-hemligheter i produktion (spec §56).");
|
||||
process.exit(1);
|
||||
}
|
||||
if (cfg.AAMOS_MODE === "mock") {
|
||||
console.error("SÄKERHETSSTOPP: AAMOS_MODE=mock är inte tillåtet i produktion.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
Reference in New Issue
Block a user