initial commit
Some checks failed
CI / Go — node-agent tests (push) Has been cancelled
CI / Go — edge-gateway build (push) Has been cancelled
CI / Node — lint, typecheck, test, build (push) Has been cancelled

This commit is contained in:
smueller
2026-06-26 10:45:08 +02:00
commit e37ea87b35
118 changed files with 7726 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
{
"name": "@hexahost/config",
"version": "0.0.0",
"private": true,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"zod": "^3.24.1"
},
"devDependencies": {
"@hexahost/typescript-config": "workspace:*",
"typescript": "^5.7.3"
}
}

View File

@@ -0,0 +1,95 @@
import { z } from 'zod';
const logLevelSchema = z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent']);
const appEnvSchema = z.enum(['development', 'test', 'staging', 'production']);
export const configSchema = z.object({
APP_NAME: z.string().default('HexaHost GameCloud'),
APP_ENV: appEnvSchema.default('development'),
APP_URL: z.string().url(),
API_URL: z.string().url(),
DATABASE_URL: z.string().min(1),
REDIS_URL: z.string().min(1),
SESSION_SECRET: z.string().min(32),
LOG_LEVEL: logLevelSchema.default('info'),
API_PORT: z.coerce.number().int().min(1).max(65535).default(3001),
WORKER_PORT: z.coerce.number().int().min(1).max(65535).default(3002),
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
});
export type AppConfig = z.infer<typeof configSchema>;
function readEnv(): Record<string, string | undefined> {
return { ...process.env };
}
export function loadConfig(env: Record<string, string | undefined> = readEnv()): AppConfig {
return configSchema.parse({
APP_NAME: env['APP_NAME'],
APP_ENV: env['APP_ENV'],
APP_URL: env['APP_URL'],
API_URL: env['API_URL'],
DATABASE_URL: env['DATABASE_URL'],
REDIS_URL: env['REDIS_URL'],
SESSION_SECRET: env['SESSION_SECRET'],
LOG_LEVEL: env['LOG_LEVEL'],
API_PORT: env['API_PORT'],
WORKER_PORT: env['WORKER_PORT'],
NODE_ENV: env['NODE_ENV'],
});
}
export function validateConfig(env: Record<string, string | undefined> = readEnv()): AppConfig {
const requiredKeys = [
'APP_URL',
'API_URL',
'DATABASE_URL',
'REDIS_URL',
'SESSION_SECRET',
] as const;
const missing = requiredKeys.filter((key) => !env[key] || env[key]!.trim() === '');
if (missing.length > 0) {
throw new Error(
`Missing required environment variables: ${missing.join(', ')}`,
);
}
const result = configSchema.safeParse({
APP_NAME: env['APP_NAME'],
APP_ENV: env['APP_ENV'],
APP_URL: env['APP_URL'],
API_URL: env['API_URL'],
DATABASE_URL: env['DATABASE_URL'],
REDIS_URL: env['REDIS_URL'],
SESSION_SECRET: env['SESSION_SECRET'],
LOG_LEVEL: env['LOG_LEVEL'],
API_PORT: env['API_PORT'],
WORKER_PORT: env['WORKER_PORT'],
NODE_ENV: env['NODE_ENV'],
});
if (!result.success) {
const issues = result.error.issues
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
.join('; ');
throw new Error(`Invalid configuration: ${issues}`);
}
return result.data;
}
let cachedConfig: AppConfig | undefined;
export function getConfig(): AppConfig {
if (!cachedConfig) {
cachedConfig = validateConfig();
}
return cachedConfig;
}
export function resetConfigCache(): void {
cachedConfig = undefined;
}

View File

@@ -0,0 +1,9 @@
{
"extends": "@hexahost/typescript-config/library.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}