Initial import
This commit is contained in:
8
packages/config/README.md
Normal file
8
packages/config/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# packages/config
|
||||
|
||||
Shared runtime configuration package for environment parsing and normalization.
|
||||
|
||||
## Implemented in this iteration
|
||||
- Typed environment loader
|
||||
- Normalized app, database, provider, storage, Telegram, email, and key-pool settings
|
||||
- Small helpers for required values, integers, booleans, and URL parsing
|
||||
21
packages/config/package.json
Normal file
21
packages/config/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@nproxy/config",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"check": "tsc -p tsconfig.json --noEmit"
|
||||
}
|
||||
}
|
||||
0
packages/config/src/.gitkeep
Normal file
0
packages/config/src/.gitkeep
Normal file
160
packages/config/src/index.ts
Normal file
160
packages/config/src/index.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
export interface RuntimeUrls {
|
||||
appBaseUrl: URL;
|
||||
adminBaseUrl: URL;
|
||||
nanoBananaApiBaseUrl: URL;
|
||||
s3Endpoint: URL;
|
||||
}
|
||||
|
||||
export interface DatabaseConfig {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface AuthConfig {
|
||||
sessionSecret: string;
|
||||
passwordPepper: string;
|
||||
}
|
||||
|
||||
export interface ProviderConfig {
|
||||
nanoBananaDefaultModel: string;
|
||||
}
|
||||
|
||||
export interface PaymentConfig {
|
||||
provider: string;
|
||||
apiKey: string;
|
||||
webhookSecret: string;
|
||||
}
|
||||
|
||||
export interface StorageConfig {
|
||||
region: string;
|
||||
bucket: string;
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
forcePathStyle: boolean;
|
||||
}
|
||||
|
||||
export interface TelegramConfig {
|
||||
botToken: string;
|
||||
botMode: "polling";
|
||||
}
|
||||
|
||||
export interface EmailConfig {
|
||||
provider: string;
|
||||
from: string;
|
||||
apiKey: string;
|
||||
}
|
||||
|
||||
export interface KeyPoolConfig {
|
||||
cooldownMinutes: number;
|
||||
failuresBeforeManualReview: number;
|
||||
balancePollSeconds: number;
|
||||
}
|
||||
|
||||
export interface AppRuntimeConfig {
|
||||
nodeEnv: string;
|
||||
urls: RuntimeUrls;
|
||||
database: DatabaseConfig;
|
||||
auth: AuthConfig;
|
||||
provider: ProviderConfig;
|
||||
payment: PaymentConfig;
|
||||
storage: StorageConfig;
|
||||
telegram: TelegramConfig;
|
||||
email: EmailConfig;
|
||||
keyPool: KeyPoolConfig;
|
||||
}
|
||||
|
||||
export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppRuntimeConfig {
|
||||
return {
|
||||
nodeEnv: readString(env, "NODE_ENV"),
|
||||
urls: {
|
||||
appBaseUrl: readUrl(env, "APP_BASE_URL"),
|
||||
adminBaseUrl: readUrl(env, "ADMIN_BASE_URL"),
|
||||
nanoBananaApiBaseUrl: readUrl(env, "NANO_BANANA_API_BASE_URL"),
|
||||
s3Endpoint: readUrl(env, "S3_ENDPOINT"),
|
||||
},
|
||||
database: {
|
||||
url: readString(env, "DATABASE_URL"),
|
||||
},
|
||||
auth: {
|
||||
sessionSecret: readString(env, "SESSION_SECRET"),
|
||||
passwordPepper: readString(env, "PASSWORD_PEPPER"),
|
||||
},
|
||||
provider: {
|
||||
nanoBananaDefaultModel: readString(env, "NANO_BANANA_DEFAULT_MODEL"),
|
||||
},
|
||||
payment: {
|
||||
provider: readString(env, "PAYMENT_PROVIDER"),
|
||||
apiKey: readString(env, "PAYMENT_PROVIDER_API_KEY"),
|
||||
webhookSecret: readString(env, "PAYMENT_PROVIDER_WEBHOOK_SECRET"),
|
||||
},
|
||||
storage: {
|
||||
region: readString(env, "S3_REGION"),
|
||||
bucket: readString(env, "S3_BUCKET"),
|
||||
accessKey: readString(env, "S3_ACCESS_KEY"),
|
||||
secretKey: readString(env, "S3_SECRET_KEY"),
|
||||
forcePathStyle: readBoolean(env, "S3_FORCE_PATH_STYLE"),
|
||||
},
|
||||
telegram: {
|
||||
botToken: readString(env, "TELEGRAM_BOT_TOKEN"),
|
||||
botMode: readTelegramMode(env, "TELEGRAM_BOT_MODE"),
|
||||
},
|
||||
email: {
|
||||
provider: readString(env, "EMAIL_PROVIDER"),
|
||||
from: readString(env, "EMAIL_FROM"),
|
||||
apiKey: readString(env, "EMAIL_API_KEY"),
|
||||
},
|
||||
keyPool: {
|
||||
cooldownMinutes: readInteger(env, "KEY_COOLDOWN_MINUTES"),
|
||||
failuresBeforeManualReview: readInteger(env, "KEY_FAILURES_BEFORE_MANUAL_REVIEW"),
|
||||
balancePollSeconds: readInteger(env, "KEY_BALANCE_POLL_SECONDS"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function readString(env: NodeJS.ProcessEnv, key: string): string {
|
||||
const value = env[key];
|
||||
|
||||
if (!value) {
|
||||
throw new Error(`Missing required environment variable: ${key}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function readInteger(env: NodeJS.ProcessEnv, key: string): number {
|
||||
const value = readString(env, key);
|
||||
const parsed = Number.parseInt(value, 10);
|
||||
|
||||
if (!Number.isInteger(parsed)) {
|
||||
throw new Error(`Environment variable ${key} must be an integer`);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function readBoolean(env: NodeJS.ProcessEnv, key: string): boolean {
|
||||
const value = readString(env, key).toLowerCase();
|
||||
|
||||
if (value === "true") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value === "false") {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new Error(`Environment variable ${key} must be "true" or "false"`);
|
||||
}
|
||||
|
||||
function readUrl(env: NodeJS.ProcessEnv, key: string): URL {
|
||||
return new URL(readString(env, key));
|
||||
}
|
||||
|
||||
function readTelegramMode(env: NodeJS.ProcessEnv, key: string): "polling" {
|
||||
const value = readString(env, key);
|
||||
|
||||
if (value !== "polling") {
|
||||
throw new Error(`Environment variable ${key} must be "polling" for MVP`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
12
packages/config/tsconfig.json
Normal file
12
packages/config/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user