initttt
This commit is contained in:
181
packages/settings/index.ts
Normal file
181
packages/settings/index.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
import * as v from "valibot";
|
||||
|
||||
import "dotenv/config";
|
||||
|
||||
/**
|
||||
* Settings schema using Valibot for validation
|
||||
*/
|
||||
export const settingsSchema = v.object({
|
||||
appName: v.string(),
|
||||
nodeEnv: v.string(),
|
||||
logLevel: v.string(),
|
||||
|
||||
isDevelopment: v.optional(v.boolean()),
|
||||
|
||||
redisUrl: v.string(),
|
||||
databaseUrl: v.string(),
|
||||
|
||||
internalApiKey: v.string(),
|
||||
debugKey: v.string(),
|
||||
|
||||
processorApiUrl: v.string(),
|
||||
appBuilderApiUrl: v.string(),
|
||||
appBuilderAssetsPublicUrl: v.string(),
|
||||
clientDownloadedApkName: v.string(),
|
||||
mobileAppApiUrl: v.string(),
|
||||
|
||||
betterAuthUrl: v.string(),
|
||||
betterAuthSecret: v.string(),
|
||||
|
||||
twoFaSecret: v.string(),
|
||||
twofaSessionExpiryMinutes: v.optional(v.number()),
|
||||
twofaRequiredHours: v.optional(v.number()),
|
||||
|
||||
defaultAdminEmail: v.string(),
|
||||
defaultAdminPassword: v.string(),
|
||||
|
||||
otelServiceName: v.string(),
|
||||
otelExporterOtlpHttpEndpoint: v.string(),
|
||||
|
||||
// R2/Object Storage settings
|
||||
r2BucketName: v.string(),
|
||||
r2Region: v.string(),
|
||||
r2Endpoint: v.string(),
|
||||
r2AccessKey: v.string(),
|
||||
r2SecretKey: v.string(),
|
||||
r2PublicUrl: v.optional(v.string()),
|
||||
|
||||
// File upload settings
|
||||
maxFileSize: v.number(),
|
||||
allowedMimeTypes: v.array(v.string()),
|
||||
allowedExtensions: v.array(v.string()),
|
||||
});
|
||||
|
||||
export type Settings = v.InferOutput<typeof settingsSchema>;
|
||||
|
||||
/**
|
||||
* Helper to get environment variable with default value
|
||||
*/
|
||||
function getEnv(key: string, defaultValue: string = ""): string {
|
||||
return process.env[key] ?? defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get environment variable as number with default value
|
||||
*/
|
||||
function getEnvNumber(key: string, defaultValue: number): number {
|
||||
const value = process.env[key];
|
||||
if (!value) return defaultValue;
|
||||
const parsed = Number(value);
|
||||
return Number.isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse comma-separated string into array
|
||||
*/
|
||||
function parseCommaSeparated(value: string): string[] {
|
||||
return value
|
||||
.split(",")
|
||||
.map((item) => item.trim())
|
||||
.filter((item) => item.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and validate settings from environment variables
|
||||
*/
|
||||
function loadSettings(): Settings {
|
||||
const nodeEnv = getEnv("NODE_ENV", "development");
|
||||
|
||||
const rawSettings = {
|
||||
appName: getEnv("APP_NAME", "App"),
|
||||
nodeEnv,
|
||||
logLevel: getEnv("LOG_LEVEL", "info"),
|
||||
|
||||
isDevelopment: nodeEnv === "development",
|
||||
|
||||
redisUrl: getEnv("REDIS_URL", "redis://localhost:6379"),
|
||||
databaseUrl: getEnv("DATABASE_URL"),
|
||||
|
||||
internalApiKey: getEnv("INTERNAL_API_KEY"),
|
||||
debugKey: getEnv("DEBUG_KEY"),
|
||||
|
||||
processorApiUrl: getEnv("PROCESSOR_API_URL", "http://localhost:3000"),
|
||||
appBuilderApiUrl: getEnv(
|
||||
"APP_BUILDER_API_URL",
|
||||
"http://localhost:3001",
|
||||
),
|
||||
appBuilderAssetsPublicUrl: getEnv(
|
||||
"APP_BUILDER_ASSETS_PUBLIC_URL",
|
||||
"http://localhost:3001",
|
||||
),
|
||||
clientDownloadedApkName: getEnv(
|
||||
"CLIENT_DOWNLOADED_APK_NAME",
|
||||
"illusory-client.apk",
|
||||
),
|
||||
mobileAppApiUrl: getEnv("MOBILE_APP_API_URL"),
|
||||
|
||||
betterAuthUrl: getEnv("BETTER_AUTH_URL"),
|
||||
betterAuthSecret: getEnv("BETTER_AUTH_SECRET"),
|
||||
|
||||
twoFaSecret: getEnv("TWOFA_SECRET"),
|
||||
twofaSessionExpiryMinutes: getEnvNumber(
|
||||
"TWOFA_SESSION_EXPIRY_MINUTES",
|
||||
10,
|
||||
),
|
||||
twofaRequiredHours: getEnvNumber("TWOFA_REQUIRED_HOURS", 24),
|
||||
|
||||
defaultAdminEmail: getEnv("DEFAULT_ADMIN_EMAIL"),
|
||||
defaultAdminPassword: getEnv("DEFAULT_ADMIN_PASSWORD"),
|
||||
|
||||
otelServiceName: getEnv("OTEL_SERVICE_NAME"),
|
||||
otelExporterOtlpHttpEndpoint: getEnv(
|
||||
"OTEL_EXPORTER_OTLP_HTTP_ENDPOINT",
|
||||
),
|
||||
|
||||
// R2/Object Storage settings
|
||||
r2BucketName: getEnv("R2_BUCKET_NAME"),
|
||||
r2Region: getEnv("R2_REGION", "auto"),
|
||||
r2Endpoint: getEnv("R2_ENDPOINT"),
|
||||
r2AccessKey: getEnv("R2_ACCESS_KEY"),
|
||||
r2SecretKey: getEnv("R2_SECRET_KEY"),
|
||||
r2PublicUrl: getEnv("R2_PUBLIC_URL") || undefined,
|
||||
|
||||
// File upload settings
|
||||
maxFileSize: getEnvNumber("MAX_FILE_SIZE", 10485760), // 10MB default
|
||||
allowedMimeTypes: parseCommaSeparated(
|
||||
getEnv(
|
||||
"ALLOWED_MIME_TYPES",
|
||||
"image/jpeg,image/png,image/webp,image/gif,application/pdf,text/plain",
|
||||
),
|
||||
),
|
||||
allowedExtensions: parseCommaSeparated(
|
||||
getEnv("ALLOWED_EXTENSIONS", "jpg,jpeg,png,webp,gif,pdf,txt"),
|
||||
),
|
||||
};
|
||||
|
||||
try {
|
||||
return v.parse(settingsSchema, rawSettings);
|
||||
} catch (error) {
|
||||
console.error("❌ Settings validation failed:");
|
||||
if (error instanceof v.ValiError) {
|
||||
for (const issue of error.issues) {
|
||||
console.error(
|
||||
` - ${issue.path?.map((p: any) => p.key).join(".")}: ${issue.message}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error(error);
|
||||
}
|
||||
throw new Error(
|
||||
"Failed to load settings. Check environment variables.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const settings = loadSettings();
|
||||
|
||||
export const getSetting = <K extends keyof Settings>(key: K): Settings[K] => {
|
||||
return settings[key];
|
||||
};
|
||||
|
||||
console.log(`✅ Settings loaded | ${settings.appName} (${settings.nodeEnv})`);
|
||||
15
packages/settings/package.json
Normal file
15
packages/settings/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "@pkg/settings",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^17.2.3",
|
||||
"valibot": "^1.2.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user