UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines 9 kB
{"version":3,"file":"infra.cjs","names":[],"sources":["../../src/cli/infra.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { config as loadDotenv } from \"dotenv\";\nimport type { RuntimeConfig } from \"../types\";\n\nconst POSTGRES_USER = \"everythingdev\";\nconst POSTGRES_PASSWORD = \"everythingdev\";\nconst API_DATABASE_SECRET = \"API_DATABASE_URL\";\nconst AUTH_DATABASE_SECRET = \"AUTH_DATABASE_URL\";\nconst BASE_DATABASE_PORT = 5434;\n\ninterface DatabaseSecretConfig {\n secret: string;\n slug: string;\n port: number;\n serviceName: string;\n databaseName: string;\n volumeName: string;\n url: string;\n}\n\nfunction uniqueSecrets(values: Array<string | undefined>): string[] {\n const secrets: string[] = [];\n const seen = new Set<string>();\n\n for (const value of values) {\n if (!value || seen.has(value)) continue;\n seen.add(value);\n secrets.push(value);\n }\n\n return secrets;\n}\n\nfunction getRuntimeSecrets(runtimeConfig: RuntimeConfig): string[] {\n const pluginSecrets = Object.values(runtimeConfig.plugins ?? {}).flatMap(\n (plugin) => plugin.secrets ?? [],\n );\n\n return uniqueSecrets([\n API_DATABASE_SECRET,\n AUTH_DATABASE_SECRET,\n ...(runtimeConfig.api.secrets ?? []),\n ...(runtimeConfig.auth?.secrets ?? []),\n ...pluginSecrets,\n ]);\n}\n\nfunction normalizeDatabaseSlug(secret: string): string {\n return secret.replace(/_DATABASE_URL$/, \"\").toLowerCase();\n}\n\nfunction buildDatabaseConfigs(secrets: string[]): DatabaseSecretConfig[] {\n const databaseSecrets = uniqueSecrets(\n secrets.filter((secret) => secret.endsWith(\"_DATABASE_URL\")),\n );\n\n const additionalSecrets = databaseSecrets\n .filter((secret) => secret !== API_DATABASE_SECRET && secret !== AUTH_DATABASE_SECRET)\n .sort((a, b) => a.localeCompare(b));\n\n const orderedSecrets = [API_DATABASE_SECRET, AUTH_DATABASE_SECRET, ...additionalSecrets];\n\n return orderedSecrets.map((secret, index) => {\n const slug = normalizeDatabaseSlug(secret);\n const port =\n secret === API_DATABASE_SECRET\n ? 5432\n : secret === AUTH_DATABASE_SECRET\n ? 5433\n : BASE_DATABASE_PORT + index - 2;\n\n return {\n secret,\n slug,\n port,\n serviceName: `postgres-${slug.replace(/_/g, \"-\")}`,\n databaseName: `${slug}_db`,\n volumeName: `postgres_${slug}_data`,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,\n };\n });\n}\n\nfunction defaultSecretValue(\n secret: string,\n databases: Map<string, DatabaseSecretConfig>,\n options: { forExample: boolean },\n): string {\n if (secret === \"BETTER_AUTH_SECRET\") {\n return options.forExample ? \"\" : randomBytes(32).toString(\"base64url\");\n }\n\n if (secret === \"CORS_ORIGIN\") {\n return \"http://localhost:3000\";\n }\n\n return databases.get(secret)?.url ?? \"\";\n}\n\nfunction renderEnvFile(\n secrets: string[],\n databases: DatabaseSecretConfig[],\n options: { forExample: boolean },\n): string {\n const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));\n const lines = [\n \"# Generated from configured bos secrets\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n\n for (const secret of secrets) {\n lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, options)}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderDockerCompose(databases: DatabaseSecretConfig[]): string {\n const lines = [\n \"x-pg-common: &pg-common\",\n \" image: postgres:17-alpine\",\n \" environment: &pg-env\",\n ` POSTGRES_USER: ${POSTGRES_USER}`,\n ` POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}`,\n \" healthcheck:\",\n ' test: [\"CMD-SHELL\", \"pg_isready -U everythingdev\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n \"services:\",\n ];\n\n for (const database of databases) {\n lines.push(` ${database.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(\" environment:\");\n lines.push(\" <<: *pg-env\");\n lines.push(` POSTGRES_DB: ${database.databaseName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${database.port}:5432\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${database.volumeName}:/var/lib/postgresql/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const database of databases) {\n lines.push(` ${database.volumeName}:`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {\n const secrets = getRuntimeSecrets(runtimeConfig);\n const databases = buildDatabaseConfigs(secrets);\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n writeFileSync(envExamplePath, renderEnvFile(secrets, databases, { forExample: true }));\n writeFileSync(dockerComposePath, renderDockerCompose(databases));\n\n return secrets;\n}\n\nexport function ensureEnvFile(configDir: string): void {\n const envPath = join(configDir, \".env\");\n const examplePath = join(configDir, \".env.example\");\n\n if (existsSync(envPath) || !existsSync(examplePath)) return;\n\n const content = readFileSync(examplePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const secret = randomBytes(32).toString(\"base64url\");\n const updated = lines\n .map((line) => {\n if (/^BETTER_AUTH_SECRET=/.test(line)) {\n return `BETTER_AUTH_SECRET=${secret}`;\n }\n return line;\n })\n .join(\"\\n\");\n\n writeFileSync(envPath, updated);\n p.log.info(\"Created .env from generated .env.example with generated BETTER_AUTH_SECRET\");\n}\n\nexport function loadProjectEnv(configDir: string): void {\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return;\n\n loadDotenv({ path: envPath, processEnv: process.env, quiet: true });\n}\n"],"mappings":"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"}