{"version":3,"file":"binding.mjs","names":["defaults.pgliteDefaultUrl","parseDotenv"],"sources":["../../src/db/binding.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { parse as parseDotenv } from \"dotenv\";\nimport defaults from \"./defaults.json\";\nimport type { WorkspaceIdentity } from \"./identity\";\n\n/**\n * Materialize the environment a spawned tool needs to reach the binding's\n * database: the canonical secret name mapped to the resolved URL. The process\n * that resolves bindings (the CLI composition root) pushes this into spawned\n * children so they never re-derive secrets from ambient state.\n */\nexport function bindingEnv(binding: { secretName: string; url: string }): Record<string, string> {\n  return { [binding.secretName]: binding.url };\n}\n\n/**\n * The zero-config local database: a persistent, file-backed PGlite data dir\n * resolved per workspace process (`.bos/db` relative to the workspace cwd).\n * No ports, no docker — concurrent projects never collide. This default is a\n * runtime-driver concern only: drizzle-kit commands (db:push/db:studio/\n * db:migrate) need a real postgres DSN in the environment.\n *\n * Single-sourced in `defaults.json` (read by plain-node tooling like the\n * regression env too) — never hardcode the literal elsewhere. Scaffolded\n * templates and plugin secret defaults deliberately keep their own frozen\n * copy: a database location is pinned at init, it must not silently follow\n * a framework upgrade.\n */\nexport const PGLITE_DEFAULT_URL = defaults.pgliteDefaultUrl;\n\nfunction findEnvFile(startDir: string | undefined): string | undefined {\n  if (!startDir) return undefined;\n  let current = startDir;\n  for (let i = 0; i < 15; i++) {\n    const candidate = join(current, \".env\");\n    if (existsSync(candidate)) return candidate;\n    const parent = dirname(current);\n    if (parent === current) return undefined;\n    current = parent;\n  }\n  return undefined;\n}\n\n/**\n * Resolve the connection URL for a workspace identity.\n *\n * Resolution order:\n *   1. the canonical secret in the provided environment\n *   2. the canonical secret in the nearest `.env` walked up from the\n *      workspace directory (existing environment wins — values are not\n *      overridden, matching dotenv semantics)\n *   3. the persistent local default (`PGLITE_DEFAULT_URL`) — consumed by the\n *      runtime driver (`createDatabaseDriver`), so boot migrations apply\n *      zero-config against the workspace's `.bos/db` data dir\n *\n * drizzle-kit commands need a postgres DSN; feeding them the pglite default\n * fails loudly at connect time.\n */\nexport function resolveDatabaseUrl(\n  identity: WorkspaceIdentity,\n  options: {\n    env?: Record<string, string | undefined>;\n  } = {},\n): string {\n  const env = options.env ?? process.env;\n\n  const direct = env[identity.secretName];\n  if (direct) return direct;\n\n  const envFile = findEnvFile(identity.workspaceDir);\n  if (envFile) {\n    try {\n      const parsed = parseDotenv(readFileSync(envFile, \"utf-8\"));\n      const fromFile = parsed[identity.secretName];\n      if (fromFile) return fromFile;\n    } catch {\n      // unreadable .env — fall through to the default\n    }\n  }\n\n  return PGLITE_DEFAULT_URL;\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,WAAW,SAAsE;CAC/F,OAAO,GAAG,QAAQ,aAAa,QAAQ,IAAI;AAC7C;;;;;;;;;;;;;;AAeA,MAAa,qBAAqBA;AAElC,SAAS,YAAY,UAAkD;CACrE,IAAI,CAAC,UAAU,OAAO;CACtB,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,YAAY,KAAK,SAAS,MAAM;EACtC,IAAI,WAAW,SAAS,GAAG,OAAO;EAClC,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,SAAS,OAAO;EAC/B,UAAU;CACZ;AAEF;;;;;;;;;;;;;;;;AAiBA,SAAgB,mBACd,UACA,UAEI,CAAC,GACG;CAGR,MAAM,UAFM,QAAQ,OAAO,QAAQ,IAEjB,CAAC,SAAS;CAC5B,IAAI,QAAQ,OAAO;CAEnB,MAAM,UAAU,YAAY,SAAS,YAAY;CACjD,IAAI,SACF,IAAI;EAEF,MAAM,WADSC,MAAY,aAAa,SAAS,OAAO,CAClC,CAAC,CAAC,SAAS;EACjC,IAAI,UAAU,OAAO;CACvB,QAAQ,CAER;CAGF,OAAO;AACT"}