everything-dev 1.51.5 → 1.51.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.mjs +1 -1
- package/dist/api-contract.cjs +0 -1
- package/dist/api-contract.cjs.map +1 -1
- package/dist/api-contract.mjs.map +1 -1
- package/dist/app.cjs +1 -1
- package/dist/app.cjs.map +1 -1
- package/dist/app.mjs +1 -1
- package/dist/app.mjs.map +1 -1
- package/dist/build.cjs +16 -22
- package/dist/build.cjs.map +1 -1
- package/dist/build.mjs +16 -22
- package/dist/build.mjs.map +1 -1
- package/dist/cli/catalog.cjs.map +1 -1
- package/dist/cli/catalog.mjs.map +1 -1
- package/dist/cli/db-doctor.cjs +0 -1
- package/dist/cli/db-doctor.cjs.map +1 -1
- package/dist/cli/db-doctor.mjs.map +1 -1
- package/dist/cli/db-repair.cjs +0 -1
- package/dist/cli/db-repair.cjs.map +1 -1
- package/dist/cli/db-repair.mjs.map +1 -1
- package/dist/cli/db-studio.cjs.map +1 -1
- package/dist/cli/db-studio.mjs.map +1 -1
- package/dist/cli/framework-version.cjs +2 -1
- package/dist/cli/framework-version.cjs.map +1 -1
- package/dist/cli/framework-version.mjs +1 -1
- package/dist/cli/framework-version.mjs.map +1 -1
- package/dist/cli/help.cjs.map +1 -1
- package/dist/cli/help.mjs.map +1 -1
- package/dist/cli/infra.cjs +4 -0
- package/dist/cli/infra.cjs.map +1 -1
- package/dist/cli/infra.mjs +1 -1
- package/dist/cli/infra.mjs.map +1 -1
- package/dist/cli/init.cjs +3 -4
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +0 -1
- package/dist/cli/init.d.cts.map +1 -1
- package/dist/cli/init.d.mts +0 -1
- package/dist/cli/init.d.mts.map +1 -1
- package/dist/cli/init.mjs +3 -3
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/parse.cjs.map +1 -1
- package/dist/cli/parse.mjs.map +1 -1
- package/dist/cli/prompts.cjs.map +1 -1
- package/dist/cli/prompts.mjs.map +1 -1
- package/dist/cli/snapshot.cjs +0 -1
- package/dist/cli/snapshot.cjs.map +1 -1
- package/dist/cli/snapshot.mjs.map +1 -1
- package/dist/cli/status.cjs +0 -1
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.mjs.map +1 -1
- package/dist/cli/sync.cjs +2 -2
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +2 -2
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli/timing.cjs.map +1 -1
- package/dist/cli/timing.mjs.map +1 -1
- package/dist/cli/upgrade.cjs +3 -0
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs +1 -1
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/code-artifacts.cjs +0 -1
- package/dist/code-artifacts.cjs.map +1 -1
- package/dist/code-artifacts.mjs.map +1 -1
- package/dist/components/dev-view.cjs +0 -1
- package/dist/components/dev-view.cjs.map +1 -1
- package/dist/components/dev-view.mjs.map +1 -1
- package/dist/components/streaming-view.cjs.map +1 -1
- package/dist/components/streaming-view.mjs.map +1 -1
- package/dist/config.cjs +0 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +0 -1
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +0 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +58 -60
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +58 -60
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts.map +1 -1
- package/dist/contract.meta.d.mts.map +1 -1
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs.map +1 -1
- package/dist/db.cjs +0 -1
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts.map +1 -1
- package/dist/db.d.mts.map +1 -1
- package/dist/db.mjs.map +1 -1
- package/dist/dev-logs.cjs +2 -1
- package/dist/dev-logs.cjs.map +1 -1
- package/dist/dev-logs.mjs +1 -1
- package/dist/dev-logs.mjs.map +1 -1
- package/dist/dev-session.cjs +3 -1
- package/dist/dev-session.cjs.map +1 -1
- package/dist/dev-session.mjs +3 -2
- package/dist/dev-session.mjs.map +1 -1
- package/dist/fastkv.cjs +2 -7
- package/dist/fastkv.cjs.map +1 -1
- package/dist/fastkv.d.cts.map +1 -1
- package/dist/fastkv.d.mts.map +1 -1
- package/dist/fastkv.mjs +2 -7
- package/dist/fastkv.mjs.map +1 -1
- package/dist/http-client.cjs +4 -1
- package/dist/http-client.cjs.map +1 -1
- package/dist/http-client.mjs +1 -1
- package/dist/http-client.mjs.map +1 -1
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/infra/planner.cjs +5 -1
- package/dist/infra/planner.cjs.map +1 -1
- package/dist/infra/planner.mjs +1 -1
- package/dist/infra/planner.mjs.map +1 -1
- package/dist/infra/preflight.cjs +0 -1
- package/dist/infra/preflight.cjs.map +1 -1
- package/dist/infra/preflight.mjs.map +1 -1
- package/dist/infra/types.cjs +0 -1
- package/dist/infra/types.cjs.map +1 -1
- package/dist/infra/types.mjs.map +1 -1
- package/dist/integrity.cjs +0 -1
- package/dist/integrity.cjs.map +1 -1
- package/dist/integrity.d.cts.map +1 -1
- package/dist/integrity.d.mts.map +1 -1
- package/dist/integrity.mjs.map +1 -1
- package/dist/internal/manifest-normalizer.cjs +2 -2
- package/dist/internal/manifest-normalizer.cjs.map +1 -1
- package/dist/internal/manifest-normalizer.mjs +2 -2
- package/dist/internal/manifest-normalizer.mjs.map +1 -1
- package/dist/merge.cjs +1 -2
- package/dist/merge.cjs.map +1 -1
- package/dist/merge.d.cts.map +1 -1
- package/dist/merge.d.mts.map +1 -1
- package/dist/merge.mjs +1 -1
- package/dist/merge.mjs.map +1 -1
- package/dist/mf.cjs +0 -1
- package/dist/mf.cjs.map +1 -1
- package/dist/mf.d.cts +0 -1
- package/dist/mf.d.cts.map +1 -1
- package/dist/mf.d.mts +0 -1
- package/dist/mf.d.mts.map +1 -1
- package/dist/mf.mjs.map +1 -1
- package/dist/near-cli.cjs +3 -1
- package/dist/near-cli.cjs.map +1 -1
- package/dist/near-cli.mjs +1 -1
- package/dist/near-cli.mjs.map +1 -1
- package/dist/network.cjs.map +1 -1
- package/dist/network.mjs.map +1 -1
- package/dist/orchestrator.cjs +5 -4
- package/dist/orchestrator.cjs.map +1 -1
- package/dist/orchestrator.mjs +5 -3
- package/dist/orchestrator.mjs.map +1 -1
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +50 -53
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +50 -53
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs.map +1 -1
- package/dist/process-registry.cjs +4 -1
- package/dist/process-registry.cjs.map +1 -1
- package/dist/process-registry.mjs +1 -1
- package/dist/process-registry.mjs.map +1 -1
- package/dist/publish.cjs +1 -0
- package/dist/publish.cjs.map +1 -1
- package/dist/publish.mjs +1 -1
- package/dist/publish.mjs.map +1 -1
- package/dist/sdk.cjs +0 -1
- package/dist/service-descriptor.cjs +0 -1
- package/dist/service-descriptor.cjs.map +1 -1
- package/dist/service-descriptor.d.cts +1 -0
- package/dist/service-descriptor.d.cts.map +1 -1
- package/dist/service-descriptor.d.mts +0 -1
- package/dist/service-descriptor.d.mts.map +1 -1
- package/dist/service-descriptor.mjs.map +1 -1
- package/dist/shared-deps.cjs +0 -1
- package/dist/shared-deps.cjs.map +1 -1
- package/dist/shared-deps.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +2 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +2 -3
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/ui/head.cjs.map +1 -1
- package/dist/ui/head.d.cts +0 -1
- package/dist/ui/head.d.cts.map +1 -1
- package/dist/ui/head.d.mts +0 -1
- package/dist/ui/head.d.mts.map +1 -1
- package/dist/ui/head.mjs.map +1 -1
- package/dist/ui/index.d.cts +1 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/metadata.cjs +1 -1
- package/dist/ui/metadata.cjs.map +1 -1
- package/dist/ui/metadata.d.cts.map +1 -1
- package/dist/ui/metadata.d.mts.map +1 -1
- package/dist/ui/metadata.mjs +1 -1
- package/dist/ui/metadata.mjs.map +1 -1
- package/dist/ui/router.cjs.map +1 -1
- package/dist/ui/router.d.cts +0 -1
- package/dist/ui/router.d.cts.map +1 -1
- package/dist/ui/router.d.mts +0 -1
- package/dist/ui/router.d.mts.map +1 -1
- package/dist/ui/router.mjs.map +1 -1
- package/dist/ui/runtime.cjs.map +1 -1
- package/dist/ui/runtime.d.cts +0 -1
- package/dist/ui/runtime.d.cts.map +1 -1
- package/dist/ui/runtime.d.mts +0 -1
- package/dist/ui/runtime.d.mts.map +1 -1
- package/dist/ui/runtime.mjs.map +1 -1
- package/dist/ui/types.d.cts +0 -1
- package/dist/ui/types.d.cts.map +1 -1
- package/dist/ui/types.d.mts +0 -1
- package/dist/ui/types.d.mts.map +1 -1
- package/dist/utils/banner.cjs +0 -1
- package/dist/utils/banner.cjs.map +1 -1
- package/dist/utils/banner.mjs.map +1 -1
- package/dist/utils/linkify.cjs.map +1 -1
- package/dist/utils/linkify.mjs.map +1 -1
- package/dist/utils/run.cjs +0 -1
- package/dist/utils/run.cjs.map +1 -1
- package/dist/utils/run.mjs.map +1 -1
- package/dist/utils/save-config.cjs +0 -1
- package/dist/utils/save-config.cjs.map +1 -1
- package/dist/utils/save-config.mjs.map +1 -1
- package/dist/utils/string.cjs.map +1 -1
- package/dist/utils/string.mjs.map +1 -1
- package/dist/utils/theme.cjs.map +1 -1
- package/dist/utils/theme.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-studio.mjs","names":[],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { getMigrationStorage, pluginMigrationSlug } from \"../db\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\nexport async function runStudioRemote(info: PluginDbInfo): Promise<void> {\n const dbDir = resolve(info.projectDir, \".bos\", \"db\", info.key);\n\n mkdirSync(dbDir, { recursive: true });\n\n const storage = getMigrationStorage(pluginMigrationSlug(info.key));\n const journalSchema = storage.schema;\n const journalTable = storage.table;\n\n const configPath = join(dbDir, \"drizzle.config.ts\");\n const configContent = `import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./drizzle/schema.ts\",\n out: \"./drizzle\",\n dialect: \"postgresql\",\n dbCredentials: {\n url: \"${info.databaseUrl}\",\n },\n migrations: {\n schema: \"${journalSchema}\",\n table: \"${journalTable}\",\n },\n verbose: true,\n strict: true,\n});\n`;\n\n writeFileSync(configPath, configContent);\n\n p.log.info(`Introspecting database schema for ${info.key}...`);\n try {\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"pull\", \"--config\", configPath], {\n cwd: dbDir,\n });\n } catch {\n throw new Error(\n `Failed to introspect database for \"${info.key}\". ` +\n `Check that ${info.databaseSecret} is correct and the database is reachable.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key}...`);\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: dbDir,\n });\n}\n\nfunction spawnAsync(cmd: string, args: string[], options: { cwd: string }): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(cmd, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: true,\n });\n\n child.on(\"error\", (err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(\n new Error(\n `\"${cmd}\" not found. Ensure it is installed (e.g. 'npm install -g drizzle-kit').`,\n ),\n );\n } else {\n reject(new Error(`Failed to start ${cmd}: ${err.message}`));\n }\n });\n\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) {\n resolvePromise();\n } else {\n reject(new Error(`\"${cmd}\" exited with code ${code}`));\n }\n });\n });\n}\n"],"mappings":";;;;;;;AAiBA,SAAgB,oBACd,WACA,eACA,YACc;CACd,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;
|
|
1
|
+
{"version":3,"file":"db-studio.mjs","names":[],"sources":["../../src/cli/db-studio.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { getMigrationStorage, pluginMigrationSlug } from \"../db\";\nimport type { RuntimeConfig } from \"../types\";\n\nexport interface PluginDbInfo {\n key: string;\n source: \"local\" | \"remote\";\n section: \"app.api\" | \"app.auth\" | \"plugins\";\n databaseSecret: string;\n databaseUrl: string;\n workspaceDir?: string;\n projectDir: string;\n}\n\nexport function resolvePluginDbInfo(\n pluginKey: string,\n runtimeConfig: RuntimeConfig,\n projectDir: string,\n): PluginDbInfo {\n let source: \"local\" | \"remote\" | undefined;\n let section: PluginDbInfo[\"section\"];\n let secrets: string[] | undefined;\n let localPath: string | undefined;\n let key: string;\n\n if (pluginKey === \"api\" && runtimeConfig.api) {\n source = runtimeConfig.api.source;\n section = \"app.api\";\n secrets = runtimeConfig.api.secrets;\n localPath = runtimeConfig.api.localPath;\n key = \"api\";\n } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n source = runtimeConfig.auth.source;\n section = \"app.auth\";\n secrets = runtimeConfig.auth.secrets;\n localPath = runtimeConfig.auth.localPath;\n key = \"auth\";\n } else if (runtimeConfig.plugins?.[pluginKey]) {\n const plugin = runtimeConfig.plugins[pluginKey];\n source = plugin.source;\n section = \"plugins\";\n secrets = plugin.secrets;\n localPath = plugin.localPath;\n key = pluginKey;\n } else {\n throw new Error(\n `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. ` +\n `Available: ${[\n \"api\",\n ...(runtimeConfig.auth ? [\"auth\"] : []),\n ...Object.keys(runtimeConfig.plugins ?? {}),\n ].join(\", \")}`,\n );\n }\n\n const dbSecret = secrets?.find((s) => s.endsWith(\"_DATABASE_URL\"));\n if (!dbSecret) {\n throw new Error(\n `Plugin \"${pluginKey}\" has no database secret (no secret ending in _DATABASE_URL). ` +\n `Secrets: ${(secrets ?? []).join(\", \") || \"none\"}`,\n );\n }\n\n const dbUrl = process.env[dbSecret];\n if (!dbUrl) {\n throw new Error(\n `.env missing ${dbSecret} for plugin \"${pluginKey}\". ` +\n `Add it to your .env file (see .env.example).`,\n );\n }\n\n return {\n key,\n source: source ?? \"remote\",\n section,\n databaseSecret: dbSecret,\n databaseUrl: dbUrl,\n workspaceDir: localPath,\n projectDir,\n };\n}\n\nexport async function runStudioLocal(info: PluginDbInfo): Promise<void> {\n const workspaceRoot = info.workspaceDir\n ? resolve(info.projectDir, info.workspaceDir)\n : resolve(info.projectDir, info.key);\n const configPath = join(workspaceRoot, \"drizzle.config.ts\");\n\n if (!existsSync(configPath)) {\n throw new Error(\n `No drizzle.config.ts found in ${workspaceRoot}. ` +\n `Run 'drizzle-kit init' first in the plugin workspace.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key} (local)...`);\n\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: workspaceRoot,\n });\n}\n\nexport async function runStudioRemote(info: PluginDbInfo): Promise<void> {\n const dbDir = resolve(info.projectDir, \".bos\", \"db\", info.key);\n\n mkdirSync(dbDir, { recursive: true });\n\n const storage = getMigrationStorage(pluginMigrationSlug(info.key));\n const journalSchema = storage.schema;\n const journalTable = storage.table;\n\n const configPath = join(dbDir, \"drizzle.config.ts\");\n const configContent = `import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./drizzle/schema.ts\",\n out: \"./drizzle\",\n dialect: \"postgresql\",\n dbCredentials: {\n url: \"${info.databaseUrl}\",\n },\n migrations: {\n schema: \"${journalSchema}\",\n table: \"${journalTable}\",\n },\n verbose: true,\n strict: true,\n});\n`;\n\n writeFileSync(configPath, configContent);\n\n p.log.info(`Introspecting database schema for ${info.key}...`);\n try {\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"pull\", \"--config\", configPath], {\n cwd: dbDir,\n });\n } catch {\n throw new Error(\n `Failed to introspect database for \"${info.key}\". ` +\n `Check that ${info.databaseSecret} is correct and the database is reachable.`,\n );\n }\n\n p.log.info(`Starting Drizzle Studio for ${info.key}...`);\n await spawnAsync(\"npx\", [\"drizzle-kit\", \"studio\", \"--config\", configPath], {\n cwd: dbDir,\n });\n}\n\nfunction spawnAsync(cmd: string, args: string[], options: { cwd: string }): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(cmd, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: true,\n });\n\n child.on(\"error\", (err) => {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(\n new Error(\n `\"${cmd}\" not found. Ensure it is installed (e.g. 'npm install -g drizzle-kit').`,\n ),\n );\n } else {\n reject(new Error(`Failed to start ${cmd}: ${err.message}`));\n }\n });\n\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) {\n resolvePromise();\n } else {\n reject(new Error(`\"${cmd}\" exited with code ${code}`));\n }\n });\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
2
1
|
let node_fs = require("node:fs");
|
|
3
2
|
let node_path = require("node:path");
|
|
4
3
|
|
|
@@ -67,5 +66,7 @@ function readInstalledFrameworkVersion(projectDir, packageName) {
|
|
|
67
66
|
|
|
68
67
|
//#endregion
|
|
69
68
|
exports.readInstalledFrameworkVersion = readInstalledFrameworkVersion;
|
|
69
|
+
exports.readNodeModulesVersion = readNodeModulesVersion;
|
|
70
|
+
exports.readRootCatalogVersion = readRootCatalogVersion;
|
|
70
71
|
exports.resolveFrameworkPackage = resolveFrameworkPackage;
|
|
71
72
|
//# sourceMappingURL=framework-version.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-version.cjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface FrameworkPackageResolution {\n specifier?: string;\n installedVersion?: string;\n isLinked: boolean;\n isWorkspaceLike: boolean;\n}\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nfunction readSpecifier(pkg: Record<string, unknown>, packageName: string): string | undefined {\n const deps = (pkg.dependencies ?? {}) as Record<string, string>;\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;\n const peerDeps = (pkg.peerDependencies ?? {}) as Record<string, string>;\n return deps[packageName] || devDeps[packageName] || peerDeps[packageName];\n}\n\nexport function resolveFrameworkPackage(\n projectDir: string,\n packageName: string,\n): FrameworkPackageResolution {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) {\n return { isLinked: false, isWorkspaceLike: false };\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const specifier = readSpecifier(pkg, packageName);\n\n if (!specifier) {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"link:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: true,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"workspace:\") || specifier.startsWith(\"file:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: false,\n isWorkspaceLike: true,\n };\n }\n\n if (specifier === \"catalog:\") {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n return {\n specifier,\n installedVersion: stripVersionPrefix(specifier),\n isLinked: false,\n isWorkspaceLike: false,\n };\n}\n\nexport function readInstalledFrameworkVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n return resolveFrameworkPackage(projectDir, packageName).installedVersion;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"framework-version.cjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface FrameworkPackageResolution {\n specifier?: string;\n installedVersion?: string;\n isLinked: boolean;\n isWorkspaceLike: boolean;\n}\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nfunction readSpecifier(pkg: Record<string, unknown>, packageName: string): string | undefined {\n const deps = (pkg.dependencies ?? {}) as Record<string, string>;\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;\n const peerDeps = (pkg.peerDependencies ?? {}) as Record<string, string>;\n return deps[packageName] || devDeps[packageName] || peerDeps[packageName];\n}\n\nexport function resolveFrameworkPackage(\n projectDir: string,\n packageName: string,\n): FrameworkPackageResolution {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) {\n return { isLinked: false, isWorkspaceLike: false };\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const specifier = readSpecifier(pkg, packageName);\n\n if (!specifier) {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"link:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: true,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"workspace:\") || specifier.startsWith(\"file:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: false,\n isWorkspaceLike: true,\n };\n }\n\n if (specifier === \"catalog:\") {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n return {\n specifier,\n installedVersion: stripVersionPrefix(specifier),\n isLinked: false,\n isWorkspaceLike: false,\n };\n}\n\nexport function readInstalledFrameworkVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n return resolveFrameworkPackage(projectDir, packageName).installedVersion;\n}\n"],"mappings":";;;;AAUA,SAAS,mBAAmB,SAAyB;CACnD,OAAO,QAAQ,QAAQ,aAAa,EAAE;AACxC;AAEA,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,8BAAe,YAAY,cAAc;CAC/C,IAAI,yBAAY,OAAO,GAAG,OAAO;CAIjC,MAAM,UAHM,KAAK,gCAAmB,SAAS,OAAO,CAGlC,CAAC,CAAC,YAAY,UAAU;CAC1C,OAAO,UAAU,mBAAmB,OAAO,IAAI;AACjD;AAEA,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,8BAAe,YAAY,gBAAgB,aAAa,cAAc;CAC5E,IAAI,yBAAY,OAAO,GAAG,OAAO;CAEjC,OADY,KAAK,gCAAmB,SAAS,OAAO,CAC3C,CAAC,CAAC;AACb;AAEA,SAAS,cAAc,KAA8B,aAAyC;CAC5F,MAAM,OAAQ,IAAI,gBAAgB,CAAC;CACnC,MAAM,UAAW,IAAI,mBAAmB,CAAC;CACzC,MAAM,WAAY,IAAI,oBAAoB,CAAC;CAC3C,OAAO,KAAK,gBAAgB,QAAQ,gBAAgB,SAAS;AAC/D;AAEA,SAAgB,wBACd,YACA,aAC4B;CAC5B,MAAM,8BAAe,YAAY,cAAc;CAC/C,IAAI,yBAAY,OAAO,GACrB,OAAO;EAAE,UAAU;EAAO,iBAAiB;CAAM;CAInD,MAAM,YAAY,cADN,KAAK,gCAAmB,SAAS,OAAO,CAClB,GAAG,WAAW;CAEhD,IAAI,CAAC,WAGH,OAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,WAC3B,KAAK,uBAAuB,YAAY,WAAW;EAIzE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,UAAU,WAAW,OAAO,GAC9B,OAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,WAAW;EAChE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,UAAU,WAAW,YAAY,KAAK,UAAU,WAAW,OAAO,GACpE,OAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,WAAW;EAChE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,cAAc,YAGhB,OAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,WAC3B,KAAK,uBAAuB,YAAY,WAAW;EAIzE,UAAU;EACV,iBAAiB;CACnB;CAGF,OAAO;EACL;EACA,kBAAkB,mBAAmB,SAAS;EAC9C,UAAU;EACV,iBAAiB;CACnB;AACF;AAEA,SAAgB,8BACd,YACA,aACoB;CACpB,OAAO,wBAAwB,YAAY,WAAW,CAAC,CAAC;AAC1D"}
|
|
@@ -65,5 +65,5 @@ function readInstalledFrameworkVersion(projectDir, packageName) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
//#endregion
|
|
68
|
-
export { readInstalledFrameworkVersion, resolveFrameworkPackage };
|
|
68
|
+
export { readInstalledFrameworkVersion, readNodeModulesVersion, readRootCatalogVersion, resolveFrameworkPackage };
|
|
69
69
|
//# sourceMappingURL=framework-version.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-version.mjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface FrameworkPackageResolution {\n specifier?: string;\n installedVersion?: string;\n isLinked: boolean;\n isWorkspaceLike: boolean;\n}\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nfunction readSpecifier(pkg: Record<string, unknown>, packageName: string): string | undefined {\n const deps = (pkg.dependencies ?? {}) as Record<string, string>;\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;\n const peerDeps = (pkg.peerDependencies ?? {}) as Record<string, string>;\n return deps[packageName] || devDeps[packageName] || peerDeps[packageName];\n}\n\nexport function resolveFrameworkPackage(\n projectDir: string,\n packageName: string,\n): FrameworkPackageResolution {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) {\n return { isLinked: false, isWorkspaceLike: false };\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const specifier = readSpecifier(pkg, packageName);\n\n if (!specifier) {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"link:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: true,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"workspace:\") || specifier.startsWith(\"file:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: false,\n isWorkspaceLike: true,\n };\n }\n\n if (specifier === \"catalog:\") {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n return {\n specifier,\n installedVersion: stripVersionPrefix(specifier),\n isLinked: false,\n isWorkspaceLike: false,\n };\n}\n\nexport function readInstalledFrameworkVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n return resolveFrameworkPackage(projectDir, packageName).installedVersion;\n}\n"],"mappings":";;;;AAUA,SAAS,mBAAmB,SAAyB;
|
|
1
|
+
{"version":3,"file":"framework-version.mjs","names":[],"sources":["../../src/cli/framework-version.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface FrameworkPackageResolution {\n specifier?: string;\n installedVersion?: string;\n isLinked: boolean;\n isWorkspaceLike: boolean;\n}\n\nfunction stripVersionPrefix(version: string): string {\n return version.replace(/^[\\^~>=]+/, \"\");\n}\n\nexport function readRootCatalogVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n workspaces?: { catalog?: Record<string, string> };\n };\n const version = pkg.workspaces?.catalog?.[packageName];\n return version ? stripVersionPrefix(version) : undefined;\n}\n\nexport function readNodeModulesVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n const pkgPath = join(projectDir, \"node_modules\", packageName, \"package.json\");\n if (!existsSync(pkgPath)) return undefined;\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { version?: string };\n return pkg.version;\n}\n\nfunction readSpecifier(pkg: Record<string, unknown>, packageName: string): string | undefined {\n const deps = (pkg.dependencies ?? {}) as Record<string, string>;\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;\n const peerDeps = (pkg.peerDependencies ?? {}) as Record<string, string>;\n return deps[packageName] || devDeps[packageName] || peerDeps[packageName];\n}\n\nexport function resolveFrameworkPackage(\n projectDir: string,\n packageName: string,\n): FrameworkPackageResolution {\n const pkgPath = join(projectDir, \"package.json\");\n if (!existsSync(pkgPath)) {\n return { isLinked: false, isWorkspaceLike: false };\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const specifier = readSpecifier(pkg, packageName);\n\n if (!specifier) {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"link:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: true,\n isWorkspaceLike: false,\n };\n }\n\n if (specifier.startsWith(\"workspace:\") || specifier.startsWith(\"file:\")) {\n return {\n specifier,\n installedVersion: readNodeModulesVersion(projectDir, packageName),\n isLinked: false,\n isWorkspaceLike: true,\n };\n }\n\n if (specifier === \"catalog:\") {\n const catalog = readRootCatalogVersion(projectDir, packageName);\n const installed = catalog ?? readNodeModulesVersion(projectDir, packageName);\n return {\n specifier,\n installedVersion: installed,\n isLinked: false,\n isWorkspaceLike: false,\n };\n }\n\n return {\n specifier,\n installedVersion: stripVersionPrefix(specifier),\n isLinked: false,\n isWorkspaceLike: false,\n };\n}\n\nexport function readInstalledFrameworkVersion(\n projectDir: string,\n packageName: string,\n): string | undefined {\n return resolveFrameworkPackage(projectDir, packageName).installedVersion;\n}\n"],"mappings":";;;;AAUA,SAAS,mBAAmB,SAAyB;CACnD,OAAO,QAAQ,QAAQ,aAAa,EAAE;AACxC;AAEA,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,UAAU,KAAK,YAAY,cAAc;CAC/C,IAAI,CAAC,WAAW,OAAO,GAAG,OAAO;CAIjC,MAAM,UAHM,KAAK,MAAM,aAAa,SAAS,OAAO,CAGlC,CAAC,CAAC,YAAY,UAAU;CAC1C,OAAO,UAAU,mBAAmB,OAAO,IAAI;AACjD;AAEA,SAAgB,uBACd,YACA,aACoB;CACpB,MAAM,UAAU,KAAK,YAAY,gBAAgB,aAAa,cAAc;CAC5E,IAAI,CAAC,WAAW,OAAO,GAAG,OAAO;CAEjC,OADY,KAAK,MAAM,aAAa,SAAS,OAAO,CAC3C,CAAC,CAAC;AACb;AAEA,SAAS,cAAc,KAA8B,aAAyC;CAC5F,MAAM,OAAQ,IAAI,gBAAgB,CAAC;CACnC,MAAM,UAAW,IAAI,mBAAmB,CAAC;CACzC,MAAM,WAAY,IAAI,oBAAoB,CAAC;CAC3C,OAAO,KAAK,gBAAgB,QAAQ,gBAAgB,SAAS;AAC/D;AAEA,SAAgB,wBACd,YACA,aAC4B;CAC5B,MAAM,UAAU,KAAK,YAAY,cAAc;CAC/C,IAAI,CAAC,WAAW,OAAO,GACrB,OAAO;EAAE,UAAU;EAAO,iBAAiB;CAAM;CAInD,MAAM,YAAY,cADN,KAAK,MAAM,aAAa,SAAS,OAAO,CAClB,GAAG,WAAW;CAEhD,IAAI,CAAC,WAGH,OAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,WAC3B,KAAK,uBAAuB,YAAY,WAAW;EAIzE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,UAAU,WAAW,OAAO,GAC9B,OAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,WAAW;EAChE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,UAAU,WAAW,YAAY,KAAK,UAAU,WAAW,OAAO,GACpE,OAAO;EACL;EACA,kBAAkB,uBAAuB,YAAY,WAAW;EAChE,UAAU;EACV,iBAAiB;CACnB;CAGF,IAAI,cAAc,YAGhB,OAAO;EACL;EACA,kBAJc,uBAAuB,YAAY,WAC3B,KAAK,uBAAuB,YAAY,WAAW;EAIzE,UAAU;EACV,iBAAiB;CACnB;CAGF,OAAO;EACL;EACA,kBAAkB,mBAAmB,SAAS;EAC9C,UAAU;EACV,iBAAiB;CACnB;AACF;AAEA,SAAgB,8BACd,YACA,aACoB;CACpB,OAAO,wBAAwB,YAAY,WAAW,CAAC,CAAC;AAC1D"}
|
package/dist/cli/help.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.cjs","names":["commandCatalog"],"sources":["../../src/cli/help.ts"],"sourcesContent":["import { commandCatalog } from \"./catalog\";\n\nexport function printHelp() {\n process.stdout.write(`everything-dev commands\\n\\n`);\n\n for (const command of commandCatalog) {\n process.stdout.write(` everything-dev ${command.commandPath.join(\" \")}`);\n process.stdout.write(command.meta.longRunning ? \" (long running)\" : \"\");\n process.stdout.write(`\\n ${command.summary}\\n`);\n }\n\n process.stdout.write(`\\n'bos' is an alias for 'everything-dev'.\\n`);\n}\n"],"mappings":";;;AAEA,SAAgB,YAAY;
|
|
1
|
+
{"version":3,"file":"help.cjs","names":["commandCatalog"],"sources":["../../src/cli/help.ts"],"sourcesContent":["import { commandCatalog } from \"./catalog\";\n\nexport function printHelp() {\n process.stdout.write(`everything-dev commands\\n\\n`);\n\n for (const command of commandCatalog) {\n process.stdout.write(` everything-dev ${command.commandPath.join(\" \")}`);\n process.stdout.write(command.meta.longRunning ? \" (long running)\" : \"\");\n process.stdout.write(`\\n ${command.summary}\\n`);\n }\n\n process.stdout.write(`\\n'bos' is an alias for 'everything-dev'.\\n`);\n}\n"],"mappings":";;;AAEA,SAAgB,YAAY;CAC1B,QAAQ,OAAO,MAAM,6BAA6B;CAElD,KAAK,MAAM,WAAWA,gCAAgB;EACpC,QAAQ,OAAO,MAAM,oBAAoB,QAAQ,YAAY,KAAK,GAAG,GAAG;EACxE,QAAQ,OAAO,MAAM,QAAQ,KAAK,cAAc,oBAAoB,EAAE;EACtE,QAAQ,OAAO,MAAM,SAAS,QAAQ,QAAQ,GAAG;CACnD;CAEA,QAAQ,OAAO,MAAM,6CAA6C;AACpE"}
|
package/dist/cli/help.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.mjs","names":[],"sources":["../../src/cli/help.ts"],"sourcesContent":["import { commandCatalog } from \"./catalog\";\n\nexport function printHelp() {\n process.stdout.write(`everything-dev commands\\n\\n`);\n\n for (const command of commandCatalog) {\n process.stdout.write(` everything-dev ${command.commandPath.join(\" \")}`);\n process.stdout.write(command.meta.longRunning ? \" (long running)\" : \"\");\n process.stdout.write(`\\n ${command.summary}\\n`);\n }\n\n process.stdout.write(`\\n'bos' is an alias for 'everything-dev'.\\n`);\n}\n"],"mappings":";;;AAEA,SAAgB,YAAY;
|
|
1
|
+
{"version":3,"file":"help.mjs","names":[],"sources":["../../src/cli/help.ts"],"sourcesContent":["import { commandCatalog } from \"./catalog\";\n\nexport function printHelp() {\n process.stdout.write(`everything-dev commands\\n\\n`);\n\n for (const command of commandCatalog) {\n process.stdout.write(` everything-dev ${command.commandPath.join(\" \")}`);\n process.stdout.write(command.meta.longRunning ? \" (long running)\" : \"\");\n process.stdout.write(`\\n ${command.summary}\\n`);\n }\n\n process.stdout.write(`\\n'bos' is an alias for 'everything-dev'.\\n`);\n}\n"],"mappings":";;;AAEA,SAAgB,YAAY;CAC1B,QAAQ,OAAO,MAAM,6BAA6B;CAElD,KAAK,MAAM,WAAW,gBAAgB;EACpC,QAAQ,OAAO,MAAM,oBAAoB,QAAQ,YAAY,KAAK,GAAG,GAAG;EACxE,QAAQ,OAAO,MAAM,QAAQ,KAAK,cAAc,oBAAoB,EAAE;EACtE,QAAQ,OAAO,MAAM,SAAS,QAAQ,QAAQ,GAAG;CACnD;CAEA,QAAQ,OAAO,MAAM,6CAA6C;AACpE"}
|
package/dist/cli/infra.cjs
CHANGED
|
@@ -411,6 +411,10 @@ exports.getSecretGroups = getSecretGroups;
|
|
|
411
411
|
exports.loadPortState = loadPortState;
|
|
412
412
|
exports.loadProjectEnv = loadProjectEnv;
|
|
413
413
|
exports.materializeInfraPlan = materializeInfraPlan;
|
|
414
|
+
exports.normalizeDatabaseSlug = normalizeDatabaseSlug;
|
|
415
|
+
exports.normalizeRedisSlug = normalizeRedisSlug;
|
|
416
|
+
exports.renderDockerComposeFromPlan = renderDockerComposeFromPlan;
|
|
417
|
+
exports.renderEnvFileFromPlan = renderEnvFileFromPlan;
|
|
414
418
|
exports.savePortState = savePortState;
|
|
415
419
|
exports.syncGeneratedInfra = syncGeneratedInfra;
|
|
416
420
|
exports.writeGeneratedInfra = writeGeneratedInfra;
|
package/dist/cli/infra.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infra.cjs","names":[],"sources":["../../src/cli/infra.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, 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 HOST_SECRET = \"CORS_ORIGIN\";\nconst BASE_POSTGRES_PORT = 5434;\nconst BASE_REDIS_PORT = 6379;\n\nexport interface DatabaseSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n databaseName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface RedisSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface SecretGroup {\n section: string;\n secrets: string[];\n}\n\ninterface DevPortState {\n host?: number;\n api?: number;\n ui?: number;\n auth?: number;\n pluginPortStart?: number;\n}\n\nexport interface PortState {\n postgresPorts: Record<string, number>;\n redisPorts: Record<string, number>;\n devPorts?: DevPortState;\n}\n\nexport interface GeneratedInfraSpec {\n groups: SecretGroup[];\n databases: DatabaseSecretConfig[];\n redis: RedisSecretConfig[];\n}\n\ninterface SyncGeneratedInfraResult {\n secrets: string[];\n envExampleChanged: boolean;\n dockerComposeChanged: boolean;\n staleEnvWarnings: 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\nexport function loadPortState(configDir?: string): PortState {\n if (!configDir) return { postgresPorts: {}, redisPorts: {} };\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n if (!existsSync(statePath)) return { postgresPorts: {}, redisPorts: {} };\n try {\n const raw = JSON.parse(readFileSync(statePath, \"utf-8\")) as Partial<PortState>;\n return {\n postgresPorts: raw.postgresPorts ?? {},\n redisPorts: raw.redisPorts ?? {},\n devPorts: raw.devPorts,\n };\n } catch {\n return { postgresPorts: {}, redisPorts: {} };\n }\n}\n\nexport function savePortState(configDir: string, state: PortState): void {\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\\n`);\n}\n\nexport type { DevPortState };\n\nfunction resolvePort(slug: string, portMap: Record<string, number>, basePort: number): number {\n if (portMap[slug] !== undefined) return portMap[slug];\n const assigned = Object.values(portMap);\n const maxAssigned = assigned.length > 0 ? Math.max(...assigned) : basePort - 1;\n const next = Math.max(maxAssigned + 1, basePort);\n portMap[slug] = next;\n return next;\n}\n\nexport function normalizeRedisSlug(secret: string): string {\n return secret.replace(/_REDIS_URL$/, \"\").toLowerCase();\n}\n\nexport function getSecretGroups(runtimeConfig: RuntimeConfig): SecretGroup[] {\n const groups: SecretGroup[] = [];\n const seen = new Set<string>();\n\n const addGroup = (section: string, secrets: string[]) => {\n const filtered = secrets.filter((s) => {\n if (seen.has(s)) return false;\n seen.add(s);\n return true;\n });\n if (filtered.length > 0) {\n groups.push({ section, secrets: filtered });\n }\n };\n\n addGroup(\"app.host\", uniqueSecrets([...(runtimeConfig.host.secrets ?? []), HOST_SECRET]));\n\n addGroup(\"app.api\", uniqueSecrets(runtimeConfig.api.secrets ?? []));\n\n if (runtimeConfig.auth) {\n addGroup(\"app.auth\", uniqueSecrets(runtimeConfig.auth.secrets ?? []));\n }\n\n if (runtimeConfig.plugins) {\n for (const [pluginKey, plugin] of Object.entries(runtimeConfig.plugins)) {\n if (plugin.secrets && plugin.secrets.length > 0) {\n addGroup(`plugins.${pluginKey}`, plugin.secrets);\n }\n }\n }\n\n return groups;\n}\n\nfunction buildGeneratedInfraSpec(\n runtimeConfig: RuntimeConfig,\n configDir?: string,\n): { spec: GeneratedInfraSpec; portState: PortState } {\n const groups = getSecretGroups(runtimeConfig);\n const allSecrets = groups.flatMap((group) => group.secrets);\n const originMap = configDir ? buildOriginMap(configDir, runtimeConfig) : new Map();\n const portState = loadPortState(configDir);\n\n const databases = buildDatabaseConfigs(allSecrets, originMap, portState.postgresPorts);\n const redis = buildRedisConfigs(allSecrets, originMap, portState.redisPorts);\n\n return { spec: { groups, databases, redis }, portState };\n}\n\nexport function normalizeDatabaseSlug(secret: string): string {\n return secret.replace(/_DATABASE_URL$/, \"\").toLowerCase();\n}\n\nexport function buildOriginMap(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): Map<string, string> {\n const configPath = join(configDir, \"bos.config.json\");\n\n const originMap = new Map<string, string>();\n const account = runtimeConfig.account;\n\n const resolveOrigin = (extendsRef: unknown): string | null => {\n if (typeof extendsRef === \"string\") {\n const match = extendsRef.match(/^bos:\\/\\/([^/]+)\\//);\n return match?.[1] ?? null;\n }\n return null;\n };\n\n const rawConfig = existsSync(configPath)\n ? (JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>)\n : null;\n const rawPlugins = rawConfig?.plugins as Record<string, unknown> | undefined;\n\n for (const secret of runtimeConfig.api.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n const rawApp = rawConfig?.app as Record<string, unknown> | undefined;\n const authExtends = (rawApp?.auth as Record<string, unknown> | undefined)?.extends;\n const authOrigin = resolveOrigin(authExtends) ?? account;\n for (const secret of runtimeConfig.auth?.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, authOrigin);\n }\n\n for (const [pluginKey, pluginEntry] of Object.entries(runtimeConfig.plugins ?? {})) {\n const rawPlugin = rawPlugins?.[pluginKey];\n let pluginOrigin: string;\n if (typeof rawPlugin === \"string\") {\n pluginOrigin = resolveOrigin(rawPlugin) ?? account;\n } else if (rawPlugin && typeof rawPlugin === \"object\") {\n pluginOrigin = resolveOrigin((rawPlugin as Record<string, unknown>).extends) ?? account;\n } else {\n pluginOrigin = account;\n }\n for (const secret of pluginEntry.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, pluginOrigin);\n }\n }\n\n for (const secret of runtimeConfig.host.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n return originMap;\n}\n\nexport function buildDatabaseConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): DatabaseSecretConfig[] {\n const databaseSecrets = uniqueSecrets(\n secrets.filter((secret) => secret.endsWith(\"_DATABASE_URL\")),\n );\n\n const orderedSecrets = [...databaseSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeDatabaseSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeDatabaseSlug(secret);\n if (secret === API_DATABASE_SECRET) {\n portMap[slug] = 5432;\n } else if (secret === AUTH_DATABASE_SECRET) {\n portMap[slug] = 5433;\n } else {\n resolvePort(slug, portMap, BASE_POSTGRES_PORT);\n }\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeDatabaseSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_postgres_${slug}_data`\n : `postgres_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-postgres-${slug}` : `postgres-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `postgres-${slug.replace(/_/g, \"-\")}`,\n containerName,\n databaseName: `${slug}_db`,\n volumeName,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,\n };\n });\n}\n\nexport function buildRedisConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): RedisSecretConfig[] {\n const redisSecrets = uniqueSecrets(secrets.filter((secret) => secret.endsWith(\"_REDIS_URL\")));\n const orderedSecrets = [...redisSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeRedisSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeRedisSlug(a).localeCompare(normalizeRedisSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeRedisSlug(secret);\n resolvePort(slug, portMap, BASE_REDIS_PORT);\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeRedisSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_redis_${slug}_data`\n : `redis_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-redis-${slug}` : `redis-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `redis-${slug.replace(/_/g, \"-\")}`,\n containerName,\n volumeName,\n url: `redis://localhost:${port}`,\n };\n });\n}\n\nfunction extractPortFromUrl(url: string): string | null {\n const match = url.match(/:(\\d{4,5})(?:\\/|$)/);\n return match?.[1] ?? null;\n}\n\nfunction resolveDevHostPort(runtimeConfig: RuntimeConfig): number {\n if (typeof runtimeConfig.host?.port === \"number\") return runtimeConfig.host.port;\n const fromUrl = runtimeConfig.host?.url ? extractPortFromUrl(runtimeConfig.host.url) : null;\n if (fromUrl) {\n const parsed = Number.parseInt(fromUrl, 10);\n if (!Number.isNaN(parsed)) return parsed;\n }\n return 3000;\n}\n\nfunction defaultSecretValue(\n secret: string,\n databases: Map<string, DatabaseSecretConfig>,\n redisConfigs: Map<string, RedisSecretConfig>,\n options: { forExample: boolean; devHostPort?: number },\n): string {\n if (secret === \"BETTER_AUTH_SECRET\") {\n return options.forExample ? \"\" : randomBytes(32).toString(\"base64url\");\n }\n\n if (secret === \"CORS_ORIGIN\") {\n if (typeof options.devHostPort === \"number\") {\n return `http://localhost:${options.devHostPort}`;\n }\n return \"http://localhost:3000\";\n }\n\n return databases.get(secret)?.url ?? redisConfigs.get(secret)?.url ?? \"\";\n}\n\nfunction renderEnvFile(\n groups: SecretGroup[],\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n options: { forExample: boolean; devHostPort?: number },\n): string {\n const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));\n const redisMap = new Map(redisConfigs.map((entry) => [entry.secret, entry]));\n const lines: string[] = [\n \"# Generated from configured bos secrets\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n\n for (const group of groups) {\n lines.push(`# ${group.section}`);\n for (const secret of group.secrets) {\n lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, redisMap, options)}`);\n }\n lines.push(\"\");\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderDockerCompose(\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redisConfigs.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const database of databases) {\n lines.push(` ${database.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${database.containerName}`);\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 for (const redis of redisConfigs) {\n lines.push(` ${redis.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${redis.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${redis.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${redis.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const database of databases) {\n lines.push(` ${database.volumeName}:`);\n lines.push(` name: ${database.volumeName}`);\n }\n for (const redis of redisConfigs) {\n lines.push(` ${redis.volumeName}:`);\n lines.push(` name: ${redis.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderEnvFileFromPlan(env: Record<string, string>, devHostPort?: number): string {\n const lines: string[] = [\n \"# Generated from bos dev infra plan\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n const sortedKeys = Object.keys(env).sort();\n for (const key of sortedKeys) {\n let value = env[key];\n if (key === \"CORS_ORIGIN\" && devHostPort && !value) {\n value = `http://localhost:${devHostPort}`;\n }\n lines.push(`${key}=${value}`);\n }\n lines.push(\"\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderDockerComposeFromPlan(\n databases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n redis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redis.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const db of databases) {\n lines.push(` ${db.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${db.containerName}`);\n lines.push(\" environment:\");\n lines.push(\" <<: *pg-env\");\n lines.push(` POSTGRES_DB: ${db.databaseName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${db.port}:5432\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${db.volumeName}:/var/lib/postgresql/data`);\n lines.push(\"\");\n }\n\n for (const r of redis) {\n lines.push(` ${r.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${r.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${r.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${r.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const db of databases) {\n lines.push(` ${db.volumeName}:`);\n lines.push(` name: ${db.volumeName}`);\n }\n for (const r of redis) {\n lines.push(` ${r.volumeName}:`);\n lines.push(` name: ${r.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function materializeInfraPlan(\n configDir: string,\n planEnv: Record<string, string>,\n planDatabases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n planRedis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n devHostPort?: number,\n): { envExampleChanged: boolean; dockerComposeChanged: boolean } {\n const envContent = renderEnvFileFromPlan(planEnv, devHostPort);\n const dockerContent = renderDockerComposeFromPlan(planDatabases, planRedis, projectName);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n return {\n envExampleChanged: syncTextFile(envExamplePath, envContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, dockerContent),\n };\n}\n\nfunction syncTextFile(filePath: string, nextContent: string): boolean {\n if (existsSync(filePath) && readFileSync(filePath, \"utf-8\") === nextContent) {\n return false;\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nexport function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {\n const result = syncGeneratedInfra(configDir, runtimeConfig);\n\n if (result.staleEnvWarnings.length > 0) {\n p.log.warn(\n `.env has ${result.staleEnvWarnings.length} stale value(s) compared to .env.example:`,\n );\n for (const warning of result.staleEnvWarnings) {\n p.log.message(` ${warning}`);\n }\n }\n\n return result.secrets;\n}\n\nexport function syncGeneratedInfra(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): SyncGeneratedInfraResult {\n const { spec, portState } = buildGeneratedInfraSpec(runtimeConfig, configDir);\n const secrets = spec.groups.flatMap((group) => group.secrets);\n const envOptions: { forExample: true; devHostPort?: number } = { forExample: true };\n if (runtimeConfig.env === \"development\") {\n envOptions.devHostPort = resolveDevHostPort(runtimeConfig);\n }\n const newEnvContent = renderEnvFile(spec.groups, spec.databases, spec.redis, envOptions);\n const newDockerContent = renderDockerCompose(spec.databases, spec.redis, runtimeConfig.account);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n const staleWarnings = checkEnvStaleness(configDir, spec.databases, spec.redis);\n\n if (configDir) {\n savePortState(configDir, portState);\n }\n\n return {\n secrets,\n envExampleChanged: syncTextFile(envExamplePath, newEnvContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, newDockerContent),\n staleEnvWarnings: staleWarnings,\n };\n}\n\nfunction checkEnvStaleness(\n configDir: string,\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n): string[] {\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return [];\n\n const existingEnv = readFileSync(envPath, \"utf-8\");\n const envMap = new Map<string, string>();\n for (const line of existingEnv.split(\"\\n\")) {\n const match = line.match(/^([A-Z_]+)=(.*)$/);\n if (match) envMap.set(match[1], match[2]);\n }\n\n const stale: string[] = [];\n\n for (const db of databases) {\n const existing = envMap.get(db.secret);\n if (existing && existing !== db.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${db.secret}: port ${oldPort} → ${db.port}`);\n }\n }\n\n for (const redis of redisConfigs) {\n const existing = envMap.get(redis.secret);\n if (existing && existing !== redis.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${redis.secret}: port ${oldPort} → ${redis.port}`);\n }\n }\n\n return stale;\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\nlet envLoadedDir: string | null = null;\n\nexport function loadProjectEnv(configDir: string): void {\n if (envLoadedDir === configDir) return;\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return;\n\n loadDotenv({ path: envPath, processEnv: process.env, quiet: true });\n envLoadedDir = configDir;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"infra.cjs","names":[],"sources":["../../src/cli/infra.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, 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 HOST_SECRET = \"CORS_ORIGIN\";\nconst BASE_POSTGRES_PORT = 5434;\nconst BASE_REDIS_PORT = 6379;\n\nexport interface DatabaseSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n databaseName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface RedisSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface SecretGroup {\n section: string;\n secrets: string[];\n}\n\ninterface DevPortState {\n host?: number;\n api?: number;\n ui?: number;\n auth?: number;\n pluginPortStart?: number;\n}\n\nexport interface PortState {\n postgresPorts: Record<string, number>;\n redisPorts: Record<string, number>;\n devPorts?: DevPortState;\n}\n\nexport interface GeneratedInfraSpec {\n groups: SecretGroup[];\n databases: DatabaseSecretConfig[];\n redis: RedisSecretConfig[];\n}\n\ninterface SyncGeneratedInfraResult {\n secrets: string[];\n envExampleChanged: boolean;\n dockerComposeChanged: boolean;\n staleEnvWarnings: 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\nexport function loadPortState(configDir?: string): PortState {\n if (!configDir) return { postgresPorts: {}, redisPorts: {} };\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n if (!existsSync(statePath)) return { postgresPorts: {}, redisPorts: {} };\n try {\n const raw = JSON.parse(readFileSync(statePath, \"utf-8\")) as Partial<PortState>;\n return {\n postgresPorts: raw.postgresPorts ?? {},\n redisPorts: raw.redisPorts ?? {},\n devPorts: raw.devPorts,\n };\n } catch {\n return { postgresPorts: {}, redisPorts: {} };\n }\n}\n\nexport function savePortState(configDir: string, state: PortState): void {\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\\n`);\n}\n\nexport type { DevPortState };\n\nfunction resolvePort(slug: string, portMap: Record<string, number>, basePort: number): number {\n if (portMap[slug] !== undefined) return portMap[slug];\n const assigned = Object.values(portMap);\n const maxAssigned = assigned.length > 0 ? Math.max(...assigned) : basePort - 1;\n const next = Math.max(maxAssigned + 1, basePort);\n portMap[slug] = next;\n return next;\n}\n\nexport function normalizeRedisSlug(secret: string): string {\n return secret.replace(/_REDIS_URL$/, \"\").toLowerCase();\n}\n\nexport function getSecretGroups(runtimeConfig: RuntimeConfig): SecretGroup[] {\n const groups: SecretGroup[] = [];\n const seen = new Set<string>();\n\n const addGroup = (section: string, secrets: string[]) => {\n const filtered = secrets.filter((s) => {\n if (seen.has(s)) return false;\n seen.add(s);\n return true;\n });\n if (filtered.length > 0) {\n groups.push({ section, secrets: filtered });\n }\n };\n\n addGroup(\"app.host\", uniqueSecrets([...(runtimeConfig.host.secrets ?? []), HOST_SECRET]));\n\n addGroup(\"app.api\", uniqueSecrets(runtimeConfig.api.secrets ?? []));\n\n if (runtimeConfig.auth) {\n addGroup(\"app.auth\", uniqueSecrets(runtimeConfig.auth.secrets ?? []));\n }\n\n if (runtimeConfig.plugins) {\n for (const [pluginKey, plugin] of Object.entries(runtimeConfig.plugins)) {\n if (plugin.secrets && plugin.secrets.length > 0) {\n addGroup(`plugins.${pluginKey}`, plugin.secrets);\n }\n }\n }\n\n return groups;\n}\n\nfunction buildGeneratedInfraSpec(\n runtimeConfig: RuntimeConfig,\n configDir?: string,\n): { spec: GeneratedInfraSpec; portState: PortState } {\n const groups = getSecretGroups(runtimeConfig);\n const allSecrets = groups.flatMap((group) => group.secrets);\n const originMap = configDir ? buildOriginMap(configDir, runtimeConfig) : new Map();\n const portState = loadPortState(configDir);\n\n const databases = buildDatabaseConfigs(allSecrets, originMap, portState.postgresPorts);\n const redis = buildRedisConfigs(allSecrets, originMap, portState.redisPorts);\n\n return { spec: { groups, databases, redis }, portState };\n}\n\nexport function normalizeDatabaseSlug(secret: string): string {\n return secret.replace(/_DATABASE_URL$/, \"\").toLowerCase();\n}\n\nexport function buildOriginMap(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): Map<string, string> {\n const configPath = join(configDir, \"bos.config.json\");\n\n const originMap = new Map<string, string>();\n const account = runtimeConfig.account;\n\n const resolveOrigin = (extendsRef: unknown): string | null => {\n if (typeof extendsRef === \"string\") {\n const match = extendsRef.match(/^bos:\\/\\/([^/]+)\\//);\n return match?.[1] ?? null;\n }\n return null;\n };\n\n const rawConfig = existsSync(configPath)\n ? (JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>)\n : null;\n const rawPlugins = rawConfig?.plugins as Record<string, unknown> | undefined;\n\n for (const secret of runtimeConfig.api.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n const rawApp = rawConfig?.app as Record<string, unknown> | undefined;\n const authExtends = (rawApp?.auth as Record<string, unknown> | undefined)?.extends;\n const authOrigin = resolveOrigin(authExtends) ?? account;\n for (const secret of runtimeConfig.auth?.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, authOrigin);\n }\n\n for (const [pluginKey, pluginEntry] of Object.entries(runtimeConfig.plugins ?? {})) {\n const rawPlugin = rawPlugins?.[pluginKey];\n let pluginOrigin: string;\n if (typeof rawPlugin === \"string\") {\n pluginOrigin = resolveOrigin(rawPlugin) ?? account;\n } else if (rawPlugin && typeof rawPlugin === \"object\") {\n pluginOrigin = resolveOrigin((rawPlugin as Record<string, unknown>).extends) ?? account;\n } else {\n pluginOrigin = account;\n }\n for (const secret of pluginEntry.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, pluginOrigin);\n }\n }\n\n for (const secret of runtimeConfig.host.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n return originMap;\n}\n\nexport function buildDatabaseConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): DatabaseSecretConfig[] {\n const databaseSecrets = uniqueSecrets(\n secrets.filter((secret) => secret.endsWith(\"_DATABASE_URL\")),\n );\n\n const orderedSecrets = [...databaseSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeDatabaseSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeDatabaseSlug(secret);\n if (secret === API_DATABASE_SECRET) {\n portMap[slug] = 5432;\n } else if (secret === AUTH_DATABASE_SECRET) {\n portMap[slug] = 5433;\n } else {\n resolvePort(slug, portMap, BASE_POSTGRES_PORT);\n }\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeDatabaseSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_postgres_${slug}_data`\n : `postgres_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-postgres-${slug}` : `postgres-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `postgres-${slug.replace(/_/g, \"-\")}`,\n containerName,\n databaseName: `${slug}_db`,\n volumeName,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,\n };\n });\n}\n\nexport function buildRedisConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): RedisSecretConfig[] {\n const redisSecrets = uniqueSecrets(secrets.filter((secret) => secret.endsWith(\"_REDIS_URL\")));\n const orderedSecrets = [...redisSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeRedisSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeRedisSlug(a).localeCompare(normalizeRedisSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeRedisSlug(secret);\n resolvePort(slug, portMap, BASE_REDIS_PORT);\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeRedisSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_redis_${slug}_data`\n : `redis_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-redis-${slug}` : `redis-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `redis-${slug.replace(/_/g, \"-\")}`,\n containerName,\n volumeName,\n url: `redis://localhost:${port}`,\n };\n });\n}\n\nfunction extractPortFromUrl(url: string): string | null {\n const match = url.match(/:(\\d{4,5})(?:\\/|$)/);\n return match?.[1] ?? null;\n}\n\nfunction resolveDevHostPort(runtimeConfig: RuntimeConfig): number {\n if (typeof runtimeConfig.host?.port === \"number\") return runtimeConfig.host.port;\n const fromUrl = runtimeConfig.host?.url ? extractPortFromUrl(runtimeConfig.host.url) : null;\n if (fromUrl) {\n const parsed = Number.parseInt(fromUrl, 10);\n if (!Number.isNaN(parsed)) return parsed;\n }\n return 3000;\n}\n\nfunction defaultSecretValue(\n secret: string,\n databases: Map<string, DatabaseSecretConfig>,\n redisConfigs: Map<string, RedisSecretConfig>,\n options: { forExample: boolean; devHostPort?: number },\n): string {\n if (secret === \"BETTER_AUTH_SECRET\") {\n return options.forExample ? \"\" : randomBytes(32).toString(\"base64url\");\n }\n\n if (secret === \"CORS_ORIGIN\") {\n if (typeof options.devHostPort === \"number\") {\n return `http://localhost:${options.devHostPort}`;\n }\n return \"http://localhost:3000\";\n }\n\n return databases.get(secret)?.url ?? redisConfigs.get(secret)?.url ?? \"\";\n}\n\nfunction renderEnvFile(\n groups: SecretGroup[],\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n options: { forExample: boolean; devHostPort?: number },\n): string {\n const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));\n const redisMap = new Map(redisConfigs.map((entry) => [entry.secret, entry]));\n const lines: string[] = [\n \"# Generated from configured bos secrets\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n\n for (const group of groups) {\n lines.push(`# ${group.section}`);\n for (const secret of group.secrets) {\n lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, redisMap, options)}`);\n }\n lines.push(\"\");\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderDockerCompose(\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redisConfigs.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const database of databases) {\n lines.push(` ${database.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${database.containerName}`);\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 for (const redis of redisConfigs) {\n lines.push(` ${redis.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${redis.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${redis.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${redis.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const database of databases) {\n lines.push(` ${database.volumeName}:`);\n lines.push(` name: ${database.volumeName}`);\n }\n for (const redis of redisConfigs) {\n lines.push(` ${redis.volumeName}:`);\n lines.push(` name: ${redis.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderEnvFileFromPlan(env: Record<string, string>, devHostPort?: number): string {\n const lines: string[] = [\n \"# Generated from bos dev infra plan\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n const sortedKeys = Object.keys(env).sort();\n for (const key of sortedKeys) {\n let value = env[key];\n if (key === \"CORS_ORIGIN\" && devHostPort && !value) {\n value = `http://localhost:${devHostPort}`;\n }\n lines.push(`${key}=${value}`);\n }\n lines.push(\"\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderDockerComposeFromPlan(\n databases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n redis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redis.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const db of databases) {\n lines.push(` ${db.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${db.containerName}`);\n lines.push(\" environment:\");\n lines.push(\" <<: *pg-env\");\n lines.push(` POSTGRES_DB: ${db.databaseName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${db.port}:5432\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${db.volumeName}:/var/lib/postgresql/data`);\n lines.push(\"\");\n }\n\n for (const r of redis) {\n lines.push(` ${r.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${r.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${r.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${r.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const db of databases) {\n lines.push(` ${db.volumeName}:`);\n lines.push(` name: ${db.volumeName}`);\n }\n for (const r of redis) {\n lines.push(` ${r.volumeName}:`);\n lines.push(` name: ${r.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function materializeInfraPlan(\n configDir: string,\n planEnv: Record<string, string>,\n planDatabases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n planRedis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n devHostPort?: number,\n): { envExampleChanged: boolean; dockerComposeChanged: boolean } {\n const envContent = renderEnvFileFromPlan(planEnv, devHostPort);\n const dockerContent = renderDockerComposeFromPlan(planDatabases, planRedis, projectName);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n return {\n envExampleChanged: syncTextFile(envExamplePath, envContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, dockerContent),\n };\n}\n\nfunction syncTextFile(filePath: string, nextContent: string): boolean {\n if (existsSync(filePath) && readFileSync(filePath, \"utf-8\") === nextContent) {\n return false;\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nexport function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {\n const result = syncGeneratedInfra(configDir, runtimeConfig);\n\n if (result.staleEnvWarnings.length > 0) {\n p.log.warn(\n `.env has ${result.staleEnvWarnings.length} stale value(s) compared to .env.example:`,\n );\n for (const warning of result.staleEnvWarnings) {\n p.log.message(` ${warning}`);\n }\n }\n\n return result.secrets;\n}\n\nexport function syncGeneratedInfra(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): SyncGeneratedInfraResult {\n const { spec, portState } = buildGeneratedInfraSpec(runtimeConfig, configDir);\n const secrets = spec.groups.flatMap((group) => group.secrets);\n const envOptions: { forExample: true; devHostPort?: number } = { forExample: true };\n if (runtimeConfig.env === \"development\") {\n envOptions.devHostPort = resolveDevHostPort(runtimeConfig);\n }\n const newEnvContent = renderEnvFile(spec.groups, spec.databases, spec.redis, envOptions);\n const newDockerContent = renderDockerCompose(spec.databases, spec.redis, runtimeConfig.account);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n const staleWarnings = checkEnvStaleness(configDir, spec.databases, spec.redis);\n\n if (configDir) {\n savePortState(configDir, portState);\n }\n\n return {\n secrets,\n envExampleChanged: syncTextFile(envExamplePath, newEnvContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, newDockerContent),\n staleEnvWarnings: staleWarnings,\n };\n}\n\nfunction checkEnvStaleness(\n configDir: string,\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n): string[] {\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return [];\n\n const existingEnv = readFileSync(envPath, \"utf-8\");\n const envMap = new Map<string, string>();\n for (const line of existingEnv.split(\"\\n\")) {\n const match = line.match(/^([A-Z_]+)=(.*)$/);\n if (match) envMap.set(match[1], match[2]);\n }\n\n const stale: string[] = [];\n\n for (const db of databases) {\n const existing = envMap.get(db.secret);\n if (existing && existing !== db.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${db.secret}: port ${oldPort} → ${db.port}`);\n }\n }\n\n for (const redis of redisConfigs) {\n const existing = envMap.get(redis.secret);\n if (existing && existing !== redis.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${redis.secret}: port ${oldPort} → ${redis.port}`);\n }\n }\n\n return stale;\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\nlet envLoadedDir: string | null = null;\n\nexport function loadProjectEnv(configDir: string): void {\n if (envLoadedDir === configDir) return;\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return;\n\n loadDotenv({ path: envPath, processEnv: process.env, quiet: true });\n envLoadedDir = configDir;\n}\n"],"mappings":"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"}
|
package/dist/cli/infra.mjs
CHANGED
|
@@ -401,5 +401,5 @@ function loadProjectEnv(configDir) {
|
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
//#endregion
|
|
404
|
-
export { buildDatabaseConfigs, buildOriginMap, buildRedisConfigs, ensureEnvFile, getSecretGroups, loadPortState, loadProjectEnv, materializeInfraPlan, savePortState, syncGeneratedInfra, writeGeneratedInfra };
|
|
404
|
+
export { buildDatabaseConfigs, buildOriginMap, buildRedisConfigs, ensureEnvFile, getSecretGroups, loadPortState, loadProjectEnv, materializeInfraPlan, normalizeDatabaseSlug, normalizeRedisSlug, renderDockerComposeFromPlan, renderEnvFileFromPlan, savePortState, syncGeneratedInfra, writeGeneratedInfra };
|
|
405
405
|
//# sourceMappingURL=infra.mjs.map
|
package/dist/cli/infra.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infra.mjs","names":[],"sources":["../../src/cli/infra.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, 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 HOST_SECRET = \"CORS_ORIGIN\";\nconst BASE_POSTGRES_PORT = 5434;\nconst BASE_REDIS_PORT = 6379;\n\nexport interface DatabaseSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n databaseName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface RedisSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface SecretGroup {\n section: string;\n secrets: string[];\n}\n\ninterface DevPortState {\n host?: number;\n api?: number;\n ui?: number;\n auth?: number;\n pluginPortStart?: number;\n}\n\nexport interface PortState {\n postgresPorts: Record<string, number>;\n redisPorts: Record<string, number>;\n devPorts?: DevPortState;\n}\n\nexport interface GeneratedInfraSpec {\n groups: SecretGroup[];\n databases: DatabaseSecretConfig[];\n redis: RedisSecretConfig[];\n}\n\ninterface SyncGeneratedInfraResult {\n secrets: string[];\n envExampleChanged: boolean;\n dockerComposeChanged: boolean;\n staleEnvWarnings: 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\nexport function loadPortState(configDir?: string): PortState {\n if (!configDir) return { postgresPorts: {}, redisPorts: {} };\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n if (!existsSync(statePath)) return { postgresPorts: {}, redisPorts: {} };\n try {\n const raw = JSON.parse(readFileSync(statePath, \"utf-8\")) as Partial<PortState>;\n return {\n postgresPorts: raw.postgresPorts ?? {},\n redisPorts: raw.redisPorts ?? {},\n devPorts: raw.devPorts,\n };\n } catch {\n return { postgresPorts: {}, redisPorts: {} };\n }\n}\n\nexport function savePortState(configDir: string, state: PortState): void {\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\\n`);\n}\n\nexport type { DevPortState };\n\nfunction resolvePort(slug: string, portMap: Record<string, number>, basePort: number): number {\n if (portMap[slug] !== undefined) return portMap[slug];\n const assigned = Object.values(portMap);\n const maxAssigned = assigned.length > 0 ? Math.max(...assigned) : basePort - 1;\n const next = Math.max(maxAssigned + 1, basePort);\n portMap[slug] = next;\n return next;\n}\n\nexport function normalizeRedisSlug(secret: string): string {\n return secret.replace(/_REDIS_URL$/, \"\").toLowerCase();\n}\n\nexport function getSecretGroups(runtimeConfig: RuntimeConfig): SecretGroup[] {\n const groups: SecretGroup[] = [];\n const seen = new Set<string>();\n\n const addGroup = (section: string, secrets: string[]) => {\n const filtered = secrets.filter((s) => {\n if (seen.has(s)) return false;\n seen.add(s);\n return true;\n });\n if (filtered.length > 0) {\n groups.push({ section, secrets: filtered });\n }\n };\n\n addGroup(\"app.host\", uniqueSecrets([...(runtimeConfig.host.secrets ?? []), HOST_SECRET]));\n\n addGroup(\"app.api\", uniqueSecrets(runtimeConfig.api.secrets ?? []));\n\n if (runtimeConfig.auth) {\n addGroup(\"app.auth\", uniqueSecrets(runtimeConfig.auth.secrets ?? []));\n }\n\n if (runtimeConfig.plugins) {\n for (const [pluginKey, plugin] of Object.entries(runtimeConfig.plugins)) {\n if (plugin.secrets && plugin.secrets.length > 0) {\n addGroup(`plugins.${pluginKey}`, plugin.secrets);\n }\n }\n }\n\n return groups;\n}\n\nfunction buildGeneratedInfraSpec(\n runtimeConfig: RuntimeConfig,\n configDir?: string,\n): { spec: GeneratedInfraSpec; portState: PortState } {\n const groups = getSecretGroups(runtimeConfig);\n const allSecrets = groups.flatMap((group) => group.secrets);\n const originMap = configDir ? buildOriginMap(configDir, runtimeConfig) : new Map();\n const portState = loadPortState(configDir);\n\n const databases = buildDatabaseConfigs(allSecrets, originMap, portState.postgresPorts);\n const redis = buildRedisConfigs(allSecrets, originMap, portState.redisPorts);\n\n return { spec: { groups, databases, redis }, portState };\n}\n\nexport function normalizeDatabaseSlug(secret: string): string {\n return secret.replace(/_DATABASE_URL$/, \"\").toLowerCase();\n}\n\nexport function buildOriginMap(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): Map<string, string> {\n const configPath = join(configDir, \"bos.config.json\");\n\n const originMap = new Map<string, string>();\n const account = runtimeConfig.account;\n\n const resolveOrigin = (extendsRef: unknown): string | null => {\n if (typeof extendsRef === \"string\") {\n const match = extendsRef.match(/^bos:\\/\\/([^/]+)\\//);\n return match?.[1] ?? null;\n }\n return null;\n };\n\n const rawConfig = existsSync(configPath)\n ? (JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>)\n : null;\n const rawPlugins = rawConfig?.plugins as Record<string, unknown> | undefined;\n\n for (const secret of runtimeConfig.api.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n const rawApp = rawConfig?.app as Record<string, unknown> | undefined;\n const authExtends = (rawApp?.auth as Record<string, unknown> | undefined)?.extends;\n const authOrigin = resolveOrigin(authExtends) ?? account;\n for (const secret of runtimeConfig.auth?.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, authOrigin);\n }\n\n for (const [pluginKey, pluginEntry] of Object.entries(runtimeConfig.plugins ?? {})) {\n const rawPlugin = rawPlugins?.[pluginKey];\n let pluginOrigin: string;\n if (typeof rawPlugin === \"string\") {\n pluginOrigin = resolveOrigin(rawPlugin) ?? account;\n } else if (rawPlugin && typeof rawPlugin === \"object\") {\n pluginOrigin = resolveOrigin((rawPlugin as Record<string, unknown>).extends) ?? account;\n } else {\n pluginOrigin = account;\n }\n for (const secret of pluginEntry.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, pluginOrigin);\n }\n }\n\n for (const secret of runtimeConfig.host.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n return originMap;\n}\n\nexport function buildDatabaseConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): DatabaseSecretConfig[] {\n const databaseSecrets = uniqueSecrets(\n secrets.filter((secret) => secret.endsWith(\"_DATABASE_URL\")),\n );\n\n const orderedSecrets = [...databaseSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeDatabaseSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeDatabaseSlug(secret);\n if (secret === API_DATABASE_SECRET) {\n portMap[slug] = 5432;\n } else if (secret === AUTH_DATABASE_SECRET) {\n portMap[slug] = 5433;\n } else {\n resolvePort(slug, portMap, BASE_POSTGRES_PORT);\n }\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeDatabaseSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_postgres_${slug}_data`\n : `postgres_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-postgres-${slug}` : `postgres-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `postgres-${slug.replace(/_/g, \"-\")}`,\n containerName,\n databaseName: `${slug}_db`,\n volumeName,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,\n };\n });\n}\n\nexport function buildRedisConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): RedisSecretConfig[] {\n const redisSecrets = uniqueSecrets(secrets.filter((secret) => secret.endsWith(\"_REDIS_URL\")));\n const orderedSecrets = [...redisSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeRedisSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeRedisSlug(a).localeCompare(normalizeRedisSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeRedisSlug(secret);\n resolvePort(slug, portMap, BASE_REDIS_PORT);\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeRedisSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_redis_${slug}_data`\n : `redis_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-redis-${slug}` : `redis-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `redis-${slug.replace(/_/g, \"-\")}`,\n containerName,\n volumeName,\n url: `redis://localhost:${port}`,\n };\n });\n}\n\nfunction extractPortFromUrl(url: string): string | null {\n const match = url.match(/:(\\d{4,5})(?:\\/|$)/);\n return match?.[1] ?? null;\n}\n\nfunction resolveDevHostPort(runtimeConfig: RuntimeConfig): number {\n if (typeof runtimeConfig.host?.port === \"number\") return runtimeConfig.host.port;\n const fromUrl = runtimeConfig.host?.url ? extractPortFromUrl(runtimeConfig.host.url) : null;\n if (fromUrl) {\n const parsed = Number.parseInt(fromUrl, 10);\n if (!Number.isNaN(parsed)) return parsed;\n }\n return 3000;\n}\n\nfunction defaultSecretValue(\n secret: string,\n databases: Map<string, DatabaseSecretConfig>,\n redisConfigs: Map<string, RedisSecretConfig>,\n options: { forExample: boolean; devHostPort?: number },\n): string {\n if (secret === \"BETTER_AUTH_SECRET\") {\n return options.forExample ? \"\" : randomBytes(32).toString(\"base64url\");\n }\n\n if (secret === \"CORS_ORIGIN\") {\n if (typeof options.devHostPort === \"number\") {\n return `http://localhost:${options.devHostPort}`;\n }\n return \"http://localhost:3000\";\n }\n\n return databases.get(secret)?.url ?? redisConfigs.get(secret)?.url ?? \"\";\n}\n\nfunction renderEnvFile(\n groups: SecretGroup[],\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n options: { forExample: boolean; devHostPort?: number },\n): string {\n const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));\n const redisMap = new Map(redisConfigs.map((entry) => [entry.secret, entry]));\n const lines: string[] = [\n \"# Generated from configured bos secrets\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n\n for (const group of groups) {\n lines.push(`# ${group.section}`);\n for (const secret of group.secrets) {\n lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, redisMap, options)}`);\n }\n lines.push(\"\");\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderDockerCompose(\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redisConfigs.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const database of databases) {\n lines.push(` ${database.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${database.containerName}`);\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 for (const redis of redisConfigs) {\n lines.push(` ${redis.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${redis.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${redis.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${redis.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const database of databases) {\n lines.push(` ${database.volumeName}:`);\n lines.push(` name: ${database.volumeName}`);\n }\n for (const redis of redisConfigs) {\n lines.push(` ${redis.volumeName}:`);\n lines.push(` name: ${redis.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderEnvFileFromPlan(env: Record<string, string>, devHostPort?: number): string {\n const lines: string[] = [\n \"# Generated from bos dev infra plan\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n const sortedKeys = Object.keys(env).sort();\n for (const key of sortedKeys) {\n let value = env[key];\n if (key === \"CORS_ORIGIN\" && devHostPort && !value) {\n value = `http://localhost:${devHostPort}`;\n }\n lines.push(`${key}=${value}`);\n }\n lines.push(\"\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderDockerComposeFromPlan(\n databases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n redis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redis.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const db of databases) {\n lines.push(` ${db.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${db.containerName}`);\n lines.push(\" environment:\");\n lines.push(\" <<: *pg-env\");\n lines.push(` POSTGRES_DB: ${db.databaseName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${db.port}:5432\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${db.volumeName}:/var/lib/postgresql/data`);\n lines.push(\"\");\n }\n\n for (const r of redis) {\n lines.push(` ${r.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${r.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${r.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${r.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const db of databases) {\n lines.push(` ${db.volumeName}:`);\n lines.push(` name: ${db.volumeName}`);\n }\n for (const r of redis) {\n lines.push(` ${r.volumeName}:`);\n lines.push(` name: ${r.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function materializeInfraPlan(\n configDir: string,\n planEnv: Record<string, string>,\n planDatabases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n planRedis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n devHostPort?: number,\n): { envExampleChanged: boolean; dockerComposeChanged: boolean } {\n const envContent = renderEnvFileFromPlan(planEnv, devHostPort);\n const dockerContent = renderDockerComposeFromPlan(planDatabases, planRedis, projectName);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n return {\n envExampleChanged: syncTextFile(envExamplePath, envContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, dockerContent),\n };\n}\n\nfunction syncTextFile(filePath: string, nextContent: string): boolean {\n if (existsSync(filePath) && readFileSync(filePath, \"utf-8\") === nextContent) {\n return false;\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nexport function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {\n const result = syncGeneratedInfra(configDir, runtimeConfig);\n\n if (result.staleEnvWarnings.length > 0) {\n p.log.warn(\n `.env has ${result.staleEnvWarnings.length} stale value(s) compared to .env.example:`,\n );\n for (const warning of result.staleEnvWarnings) {\n p.log.message(` ${warning}`);\n }\n }\n\n return result.secrets;\n}\n\nexport function syncGeneratedInfra(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): SyncGeneratedInfraResult {\n const { spec, portState } = buildGeneratedInfraSpec(runtimeConfig, configDir);\n const secrets = spec.groups.flatMap((group) => group.secrets);\n const envOptions: { forExample: true; devHostPort?: number } = { forExample: true };\n if (runtimeConfig.env === \"development\") {\n envOptions.devHostPort = resolveDevHostPort(runtimeConfig);\n }\n const newEnvContent = renderEnvFile(spec.groups, spec.databases, spec.redis, envOptions);\n const newDockerContent = renderDockerCompose(spec.databases, spec.redis, runtimeConfig.account);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n const staleWarnings = checkEnvStaleness(configDir, spec.databases, spec.redis);\n\n if (configDir) {\n savePortState(configDir, portState);\n }\n\n return {\n secrets,\n envExampleChanged: syncTextFile(envExamplePath, newEnvContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, newDockerContent),\n staleEnvWarnings: staleWarnings,\n };\n}\n\nfunction checkEnvStaleness(\n configDir: string,\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n): string[] {\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return [];\n\n const existingEnv = readFileSync(envPath, \"utf-8\");\n const envMap = new Map<string, string>();\n for (const line of existingEnv.split(\"\\n\")) {\n const match = line.match(/^([A-Z_]+)=(.*)$/);\n if (match) envMap.set(match[1], match[2]);\n }\n\n const stale: string[] = [];\n\n for (const db of databases) {\n const existing = envMap.get(db.secret);\n if (existing && existing !== db.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${db.secret}: port ${oldPort} → ${db.port}`);\n }\n }\n\n for (const redis of redisConfigs) {\n const existing = envMap.get(redis.secret);\n if (existing && existing !== redis.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${redis.secret}: port ${oldPort} → ${redis.port}`);\n }\n }\n\n return stale;\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\nlet envLoadedDir: string | null = null;\n\nexport function loadProjectEnv(configDir: string): void {\n if (envLoadedDir === configDir) return;\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return;\n\n loadDotenv({ path: envPath, processEnv: process.env, quiet: true });\n envLoadedDir = configDir;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"infra.mjs","names":[],"sources":["../../src/cli/infra.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, 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 HOST_SECRET = \"CORS_ORIGIN\";\nconst BASE_POSTGRES_PORT = 5434;\nconst BASE_REDIS_PORT = 6379;\n\nexport interface DatabaseSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n databaseName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface RedisSecretConfig {\n secret: string;\n slug: string;\n fromKey: string;\n port: number;\n serviceName: string;\n containerName: string;\n volumeName: string;\n url: string;\n}\n\nexport interface SecretGroup {\n section: string;\n secrets: string[];\n}\n\ninterface DevPortState {\n host?: number;\n api?: number;\n ui?: number;\n auth?: number;\n pluginPortStart?: number;\n}\n\nexport interface PortState {\n postgresPorts: Record<string, number>;\n redisPorts: Record<string, number>;\n devPorts?: DevPortState;\n}\n\nexport interface GeneratedInfraSpec {\n groups: SecretGroup[];\n databases: DatabaseSecretConfig[];\n redis: RedisSecretConfig[];\n}\n\ninterface SyncGeneratedInfraResult {\n secrets: string[];\n envExampleChanged: boolean;\n dockerComposeChanged: boolean;\n staleEnvWarnings: 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\nexport function loadPortState(configDir?: string): PortState {\n if (!configDir) return { postgresPorts: {}, redisPorts: {} };\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n if (!existsSync(statePath)) return { postgresPorts: {}, redisPorts: {} };\n try {\n const raw = JSON.parse(readFileSync(statePath, \"utf-8\")) as Partial<PortState>;\n return {\n postgresPorts: raw.postgresPorts ?? {},\n redisPorts: raw.redisPorts ?? {},\n devPorts: raw.devPorts,\n };\n } catch {\n return { postgresPorts: {}, redisPorts: {} };\n }\n}\n\nexport function savePortState(configDir: string, state: PortState): void {\n const statePath = join(configDir, \".bos\", \"infra-state.json\");\n mkdirSync(dirname(statePath), { recursive: true });\n writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\\n`);\n}\n\nexport type { DevPortState };\n\nfunction resolvePort(slug: string, portMap: Record<string, number>, basePort: number): number {\n if (portMap[slug] !== undefined) return portMap[slug];\n const assigned = Object.values(portMap);\n const maxAssigned = assigned.length > 0 ? Math.max(...assigned) : basePort - 1;\n const next = Math.max(maxAssigned + 1, basePort);\n portMap[slug] = next;\n return next;\n}\n\nexport function normalizeRedisSlug(secret: string): string {\n return secret.replace(/_REDIS_URL$/, \"\").toLowerCase();\n}\n\nexport function getSecretGroups(runtimeConfig: RuntimeConfig): SecretGroup[] {\n const groups: SecretGroup[] = [];\n const seen = new Set<string>();\n\n const addGroup = (section: string, secrets: string[]) => {\n const filtered = secrets.filter((s) => {\n if (seen.has(s)) return false;\n seen.add(s);\n return true;\n });\n if (filtered.length > 0) {\n groups.push({ section, secrets: filtered });\n }\n };\n\n addGroup(\"app.host\", uniqueSecrets([...(runtimeConfig.host.secrets ?? []), HOST_SECRET]));\n\n addGroup(\"app.api\", uniqueSecrets(runtimeConfig.api.secrets ?? []));\n\n if (runtimeConfig.auth) {\n addGroup(\"app.auth\", uniqueSecrets(runtimeConfig.auth.secrets ?? []));\n }\n\n if (runtimeConfig.plugins) {\n for (const [pluginKey, plugin] of Object.entries(runtimeConfig.plugins)) {\n if (plugin.secrets && plugin.secrets.length > 0) {\n addGroup(`plugins.${pluginKey}`, plugin.secrets);\n }\n }\n }\n\n return groups;\n}\n\nfunction buildGeneratedInfraSpec(\n runtimeConfig: RuntimeConfig,\n configDir?: string,\n): { spec: GeneratedInfraSpec; portState: PortState } {\n const groups = getSecretGroups(runtimeConfig);\n const allSecrets = groups.flatMap((group) => group.secrets);\n const originMap = configDir ? buildOriginMap(configDir, runtimeConfig) : new Map();\n const portState = loadPortState(configDir);\n\n const databases = buildDatabaseConfigs(allSecrets, originMap, portState.postgresPorts);\n const redis = buildRedisConfigs(allSecrets, originMap, portState.redisPorts);\n\n return { spec: { groups, databases, redis }, portState };\n}\n\nexport function normalizeDatabaseSlug(secret: string): string {\n return secret.replace(/_DATABASE_URL$/, \"\").toLowerCase();\n}\n\nexport function buildOriginMap(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): Map<string, string> {\n const configPath = join(configDir, \"bos.config.json\");\n\n const originMap = new Map<string, string>();\n const account = runtimeConfig.account;\n\n const resolveOrigin = (extendsRef: unknown): string | null => {\n if (typeof extendsRef === \"string\") {\n const match = extendsRef.match(/^bos:\\/\\/([^/]+)\\//);\n return match?.[1] ?? null;\n }\n return null;\n };\n\n const rawConfig = existsSync(configPath)\n ? (JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>)\n : null;\n const rawPlugins = rawConfig?.plugins as Record<string, unknown> | undefined;\n\n for (const secret of runtimeConfig.api.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n const rawApp = rawConfig?.app as Record<string, unknown> | undefined;\n const authExtends = (rawApp?.auth as Record<string, unknown> | undefined)?.extends;\n const authOrigin = resolveOrigin(authExtends) ?? account;\n for (const secret of runtimeConfig.auth?.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, authOrigin);\n }\n\n for (const [pluginKey, pluginEntry] of Object.entries(runtimeConfig.plugins ?? {})) {\n const rawPlugin = rawPlugins?.[pluginKey];\n let pluginOrigin: string;\n if (typeof rawPlugin === \"string\") {\n pluginOrigin = resolveOrigin(rawPlugin) ?? account;\n } else if (rawPlugin && typeof rawPlugin === \"object\") {\n pluginOrigin = resolveOrigin((rawPlugin as Record<string, unknown>).extends) ?? account;\n } else {\n pluginOrigin = account;\n }\n for (const secret of pluginEntry.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, pluginOrigin);\n }\n }\n\n for (const secret of runtimeConfig.host.secrets ?? []) {\n if (!originMap.has(secret)) originMap.set(secret, account);\n }\n\n return originMap;\n}\n\nexport function buildDatabaseConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): DatabaseSecretConfig[] {\n const databaseSecrets = uniqueSecrets(\n secrets.filter((secret) => secret.endsWith(\"_DATABASE_URL\")),\n );\n\n const orderedSecrets = [...databaseSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeDatabaseSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeDatabaseSlug(secret);\n if (secret === API_DATABASE_SECRET) {\n portMap[slug] = 5432;\n } else if (secret === AUTH_DATABASE_SECRET) {\n portMap[slug] = 5433;\n } else {\n resolvePort(slug, portMap, BASE_POSTGRES_PORT);\n }\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeDatabaseSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_postgres_${slug}_data`\n : `postgres_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-postgres-${slug}` : `postgres-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `postgres-${slug.replace(/_/g, \"-\")}`,\n containerName,\n databaseName: `${slug}_db`,\n volumeName,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,\n };\n });\n}\n\nexport function buildRedisConfigs(\n secrets: string[],\n originMap: Map<string, string>,\n portMap: Record<string, number>,\n): RedisSecretConfig[] {\n const redisSecrets = uniqueSecrets(secrets.filter((secret) => secret.endsWith(\"_REDIS_URL\")));\n const orderedSecrets = [...redisSecrets];\n\n // Prune stale entries from removed plugins\n const currentSlugs = new Set(orderedSecrets.map(normalizeRedisSlug));\n for (const slug of Object.keys(portMap)) {\n if (!currentSlugs.has(slug)) delete portMap[slug];\n }\n\n // Sort by slug for deterministic assignment order\n orderedSecrets.sort((a, b) => normalizeRedisSlug(a).localeCompare(normalizeRedisSlug(b)));\n\n for (const secret of orderedSecrets) {\n const slug = normalizeRedisSlug(secret);\n resolvePort(slug, portMap, BASE_REDIS_PORT);\n }\n\n return orderedSecrets.map((secret) => {\n const slug = normalizeRedisSlug(secret);\n const fromKey = originMap.get(secret) ?? \"\";\n const port = portMap[slug];\n\n const volumeName = fromKey\n ? `${fromKey.replace(/\\./g, \"_\")}_redis_${slug}_data`\n : `redis_${slug}_data`;\n\n const containerName = fromKey ? `${fromKey}-redis-${slug}` : `redis-${slug}`;\n\n return {\n secret,\n slug,\n fromKey,\n port,\n serviceName: `redis-${slug.replace(/_/g, \"-\")}`,\n containerName,\n volumeName,\n url: `redis://localhost:${port}`,\n };\n });\n}\n\nfunction extractPortFromUrl(url: string): string | null {\n const match = url.match(/:(\\d{4,5})(?:\\/|$)/);\n return match?.[1] ?? null;\n}\n\nfunction resolveDevHostPort(runtimeConfig: RuntimeConfig): number {\n if (typeof runtimeConfig.host?.port === \"number\") return runtimeConfig.host.port;\n const fromUrl = runtimeConfig.host?.url ? extractPortFromUrl(runtimeConfig.host.url) : null;\n if (fromUrl) {\n const parsed = Number.parseInt(fromUrl, 10);\n if (!Number.isNaN(parsed)) return parsed;\n }\n return 3000;\n}\n\nfunction defaultSecretValue(\n secret: string,\n databases: Map<string, DatabaseSecretConfig>,\n redisConfigs: Map<string, RedisSecretConfig>,\n options: { forExample: boolean; devHostPort?: number },\n): string {\n if (secret === \"BETTER_AUTH_SECRET\") {\n return options.forExample ? \"\" : randomBytes(32).toString(\"base64url\");\n }\n\n if (secret === \"CORS_ORIGIN\") {\n if (typeof options.devHostPort === \"number\") {\n return `http://localhost:${options.devHostPort}`;\n }\n return \"http://localhost:3000\";\n }\n\n return databases.get(secret)?.url ?? redisConfigs.get(secret)?.url ?? \"\";\n}\n\nfunction renderEnvFile(\n groups: SecretGroup[],\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n options: { forExample: boolean; devHostPort?: number },\n): string {\n const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));\n const redisMap = new Map(redisConfigs.map((entry) => [entry.secret, entry]));\n const lines: string[] = [\n \"# Generated from configured bos secrets\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n\n for (const group of groups) {\n lines.push(`# ${group.section}`);\n for (const secret of group.secrets) {\n lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, redisMap, options)}`);\n }\n lines.push(\"\");\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderDockerCompose(\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redisConfigs.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const database of databases) {\n lines.push(` ${database.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${database.containerName}`);\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 for (const redis of redisConfigs) {\n lines.push(` ${redis.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${redis.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${redis.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${redis.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const database of databases) {\n lines.push(` ${database.volumeName}:`);\n lines.push(` name: ${database.volumeName}`);\n }\n for (const redis of redisConfigs) {\n lines.push(` ${redis.volumeName}:`);\n lines.push(` name: ${redis.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderEnvFileFromPlan(env: Record<string, string>, devHostPort?: number): string {\n const lines: string[] = [\n \"# Generated from bos dev infra plan\",\n \"# Update values as needed for your local environment\",\n \"\",\n ];\n const sortedKeys = Object.keys(env).sort();\n for (const key of sortedKeys) {\n let value = env[key];\n if (key === \"CORS_ORIGIN\" && devHostPort && !value) {\n value = `http://localhost:${devHostPort}`;\n }\n lines.push(`${key}=${value}`);\n }\n lines.push(\"\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function renderDockerComposeFromPlan(\n databases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n redis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n): string {\n const lines = [`name: ${projectName}`, \"\"];\n\n if (databases.length > 0) {\n lines.push(\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 );\n }\n\n if (redis.length > 0) {\n lines.push(\n \"x-redis-common: &redis-common\",\n \" image: redis:7-alpine\",\n \" command: redis-server --appendonly yes\",\n \" healthcheck:\",\n ' test: [\"CMD\", \"redis-cli\", \"ping\"]',\n \" interval: 3s\",\n \" timeout: 3s\",\n \" retries: 5\",\n \"\",\n );\n }\n\n lines.push(\"services:\");\n\n for (const db of databases) {\n lines.push(` ${db.serviceName}:`);\n lines.push(\" <<: *pg-common\");\n lines.push(` container_name: ${db.containerName}`);\n lines.push(\" environment:\");\n lines.push(\" <<: *pg-env\");\n lines.push(` POSTGRES_DB: ${db.databaseName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${db.port}:5432\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${db.volumeName}:/var/lib/postgresql/data`);\n lines.push(\"\");\n }\n\n for (const r of redis) {\n lines.push(` ${r.serviceName}:`);\n lines.push(\" <<: *redis-common\");\n lines.push(` container_name: ${r.containerName}`);\n lines.push(\" ports:\");\n lines.push(` - \"${r.port}:6379\"`);\n lines.push(\" volumes:\");\n lines.push(` - ${r.volumeName}:/data`);\n lines.push(\"\");\n }\n\n lines.push(\"volumes:\");\n for (const db of databases) {\n lines.push(` ${db.volumeName}:`);\n lines.push(` name: ${db.volumeName}`);\n }\n for (const r of redis) {\n lines.push(` ${r.volumeName}:`);\n lines.push(` name: ${r.volumeName}`);\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function materializeInfraPlan(\n configDir: string,\n planEnv: Record<string, string>,\n planDatabases: {\n serviceName: string;\n containerName: string;\n port: number;\n volumeName: string;\n databaseName: string;\n }[],\n planRedis: { serviceName: string; containerName: string; port: number; volumeName: string }[],\n projectName: string,\n devHostPort?: number,\n): { envExampleChanged: boolean; dockerComposeChanged: boolean } {\n const envContent = renderEnvFileFromPlan(planEnv, devHostPort);\n const dockerContent = renderDockerComposeFromPlan(planDatabases, planRedis, projectName);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n return {\n envExampleChanged: syncTextFile(envExamplePath, envContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, dockerContent),\n };\n}\n\nfunction syncTextFile(filePath: string, nextContent: string): boolean {\n if (existsSync(filePath) && readFileSync(filePath, \"utf-8\") === nextContent) {\n return false;\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nexport function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {\n const result = syncGeneratedInfra(configDir, runtimeConfig);\n\n if (result.staleEnvWarnings.length > 0) {\n p.log.warn(\n `.env has ${result.staleEnvWarnings.length} stale value(s) compared to .env.example:`,\n );\n for (const warning of result.staleEnvWarnings) {\n p.log.message(` ${warning}`);\n }\n }\n\n return result.secrets;\n}\n\nexport function syncGeneratedInfra(\n configDir: string,\n runtimeConfig: RuntimeConfig,\n): SyncGeneratedInfraResult {\n const { spec, portState } = buildGeneratedInfraSpec(runtimeConfig, configDir);\n const secrets = spec.groups.flatMap((group) => group.secrets);\n const envOptions: { forExample: true; devHostPort?: number } = { forExample: true };\n if (runtimeConfig.env === \"development\") {\n envOptions.devHostPort = resolveDevHostPort(runtimeConfig);\n }\n const newEnvContent = renderEnvFile(spec.groups, spec.databases, spec.redis, envOptions);\n const newDockerContent = renderDockerCompose(spec.databases, spec.redis, runtimeConfig.account);\n\n const envExamplePath = join(configDir, \".env.example\");\n const dockerComposePath = join(configDir, \"docker-compose.yml\");\n\n const staleWarnings = checkEnvStaleness(configDir, spec.databases, spec.redis);\n\n if (configDir) {\n savePortState(configDir, portState);\n }\n\n return {\n secrets,\n envExampleChanged: syncTextFile(envExamplePath, newEnvContent),\n dockerComposeChanged: syncTextFile(dockerComposePath, newDockerContent),\n staleEnvWarnings: staleWarnings,\n };\n}\n\nfunction checkEnvStaleness(\n configDir: string,\n databases: DatabaseSecretConfig[],\n redisConfigs: RedisSecretConfig[],\n): string[] {\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return [];\n\n const existingEnv = readFileSync(envPath, \"utf-8\");\n const envMap = new Map<string, string>();\n for (const line of existingEnv.split(\"\\n\")) {\n const match = line.match(/^([A-Z_]+)=(.*)$/);\n if (match) envMap.set(match[1], match[2]);\n }\n\n const stale: string[] = [];\n\n for (const db of databases) {\n const existing = envMap.get(db.secret);\n if (existing && existing !== db.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${db.secret}: port ${oldPort} → ${db.port}`);\n }\n }\n\n for (const redis of redisConfigs) {\n const existing = envMap.get(redis.secret);\n if (existing && existing !== redis.url) {\n const oldPort = extractPortFromUrl(existing) ?? \"?\";\n stale.push(`${redis.secret}: port ${oldPort} → ${redis.port}`);\n }\n }\n\n return stale;\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\nlet envLoadedDir: string | null = null;\n\nexport function loadProjectEnv(configDir: string): void {\n if (envLoadedDir === configDir) return;\n const envPath = join(configDir, \".env\");\n if (!existsSync(envPath)) return;\n\n loadDotenv({ path: envPath, processEnv: process.env, quiet: true });\n envLoadedDir = configDir;\n}\n"],"mappings":"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"}
|
package/dist/cli/init.cjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
2
|
const require_http_client = require('../http-client.cjs');
|
|
4
3
|
const require_fastkv = require('../fastkv.cjs');
|
|
5
4
|
const require_merge = require('../merge.cjs');
|
|
@@ -455,14 +454,14 @@ async function personalizeConfig(destination, opts) {
|
|
|
455
454
|
}
|
|
456
455
|
} else config.plugins = {};
|
|
457
456
|
if (opts.mode === "sync" && opts.existingConfig) {
|
|
458
|
-
const managedRootKeys = new Set([
|
|
457
|
+
const managedRootKeys = /* @__PURE__ */ new Set([
|
|
459
458
|
"extends",
|
|
460
459
|
"account",
|
|
461
460
|
"domain",
|
|
462
461
|
"app",
|
|
463
462
|
"plugins"
|
|
464
463
|
]);
|
|
465
|
-
const preservedRootKeys = new Set([
|
|
464
|
+
const preservedRootKeys = /* @__PURE__ */ new Set([
|
|
466
465
|
...managedRootKeys,
|
|
467
466
|
...Object.keys(opts.existingConfig),
|
|
468
467
|
...explicitRootKeys
|
|
@@ -717,7 +716,7 @@ function stripOrphanedWorkspacesFromLockfile(lockfilePath, allowedWorkspaces) {
|
|
|
717
716
|
const workspaces = lockfile.workspaces;
|
|
718
717
|
if (!workspaces || typeof workspaces !== "object") return;
|
|
719
718
|
const workspaceMap = workspaces;
|
|
720
|
-
const allowed = new Set(["", ...allowedWorkspaces]);
|
|
719
|
+
const allowed = /* @__PURE__ */ new Set(["", ...allowedWorkspaces]);
|
|
721
720
|
const keys = Object.keys(workspaceMap);
|
|
722
721
|
let changed = false;
|
|
723
722
|
for (const key of keys) {
|