Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers, document generators, FCC compliance tools, Canada CRTC formation, Ansible infrastructure, and deployment scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
f8cd37ac8c
1823 changed files with 145167 additions and 0 deletions
111
api/src/config.ts
Normal file
111
api/src/config.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// Environment configuration — singleton, loaded once at startup.
|
||||
|
||||
function required(name: string): string {
|
||||
const v = process.env[name];
|
||||
if (!v) throw new Error(`Missing required env var: ${name}`);
|
||||
return v;
|
||||
}
|
||||
|
||||
function optional(name: string, fallback: string): string {
|
||||
return process.env[name] ?? fallback;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
port: number;
|
||||
nodeEnv: string;
|
||||
postgres: {
|
||||
connectionString: string;
|
||||
};
|
||||
erpnext: {
|
||||
url: string;
|
||||
apiKey: string;
|
||||
apiSecret: string;
|
||||
siteName: string;
|
||||
};
|
||||
listmonk: {
|
||||
url: string;
|
||||
user: string;
|
||||
password: string;
|
||||
};
|
||||
minio: {
|
||||
endpoint: string;
|
||||
port: number;
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
};
|
||||
stripe: {
|
||||
secretKey: string;
|
||||
webhookSecret: string;
|
||||
};
|
||||
smtp: {
|
||||
host: string;
|
||||
port: number;
|
||||
user: string;
|
||||
pass: string;
|
||||
from: string;
|
||||
};
|
||||
}
|
||||
|
||||
// Env-var guard for production: refuse to boot with placeholder secrets.
|
||||
// Catches the common footgun of deploying with `change-this-in-production`
|
||||
// still in effect on ADMIN_JWT_SECRET, WEBHOOK_SECRET, etc.
|
||||
function refuseInsecureProduction(): void {
|
||||
if (process.env.NODE_ENV !== "production") return;
|
||||
const bad: string[] = [];
|
||||
const check = (name: string, sentinels: string[] = []) => {
|
||||
const v = process.env[name] ?? "";
|
||||
if (!v) bad.push(`${name} is unset`);
|
||||
else if (sentinels.includes(v)) bad.push(`${name} is still set to a placeholder`);
|
||||
};
|
||||
check("ADMIN_JWT_SECRET", ["change-this-in-production"]);
|
||||
check("WEBHOOK_SECRET", ["change-this-in-production"]);
|
||||
check("SHKEEPER_API_KEY");
|
||||
check("STRIPE_WEBHOOK_SECRET");
|
||||
if (bad.length) {
|
||||
throw new Error(
|
||||
`[config] Refusing to start in production with insecure settings:\n` +
|
||||
bad.map(b => ` - ${b}`).join("\n"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function loadConfig(): Config {
|
||||
refuseInsecureProduction();
|
||||
return {
|
||||
port: parseInt(optional("PORT", "3001"), 10),
|
||||
nodeEnv: optional("NODE_ENV", "development"),
|
||||
postgres: {
|
||||
connectionString: required("DATABASE_URL"),
|
||||
},
|
||||
erpnext: {
|
||||
url: optional("ERPNEXT_URL", "http://erpnext:8000"),
|
||||
apiKey: optional("ERPNEXT_API_KEY", ""),
|
||||
apiSecret: optional("ERPNEXT_API_SECRET", ""),
|
||||
siteName: optional("ERPNEXT_SITE_NAME", optional("ERPNEXT_HOST_HEADER", "performancewest.net")),
|
||||
},
|
||||
listmonk: {
|
||||
url: optional("LISTMONK_URL", "http://listmonk:9000"),
|
||||
user: optional("LISTMONK_USER", "api"),
|
||||
password: optional("LISTMONK_PASSWORD", ""),
|
||||
},
|
||||
minio: {
|
||||
endpoint: optional("MINIO_ENDPOINT", "localhost"),
|
||||
port: parseInt(optional("MINIO_PORT", "9000"), 10),
|
||||
accessKey: optional("MINIO_ACCESS_KEY", ""),
|
||||
secretKey: optional("MINIO_SECRET_KEY", ""),
|
||||
},
|
||||
stripe: {
|
||||
secretKey: optional("STRIPE_SECRET_KEY", ""),
|
||||
webhookSecret: optional("STRIPE_WEBHOOK_SECRET", ""),
|
||||
},
|
||||
smtp: {
|
||||
host: optional("SMTP_HOST", "mail.smtp2go.com"),
|
||||
port: parseInt(optional("SMTP_PORT", "587"), 10),
|
||||
user: optional("SMTP_USER", ""),
|
||||
pass: optional("SMTP_PASS", ""),
|
||||
from: optional("SMTP_FROM", "Performance West <noreply@performancewest.net>"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const config = loadConfig();
|
||||
Loading…
Add table
Add a link
Reference in a new issue