{"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 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 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  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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"}