{"version":3,"file":"switchboard-reset-Ctegiqdm.mjs","sources":["../src/services/switchboard-reset.ts"],"sourcesContent":["import { yellow, red, green, cyan } from \"colorette\";\nimport { promises as fs } from \"node:fs\";\n\nexport interface ResetSwitchboardOptions {\n  dbPath?: string;\n  yes?: boolean;\n}\n\nexport interface ResolvedResetPaths {\n  reactorDir: string | null;\n  readModelDir: string | null;\n  postgresUrl: string | null;\n}\n\nconst CONFIRMATION_TOKEN = \"reset\";\n\nexport function isPostgresUrl(url: string): boolean {\n  return url.startsWith(\"postgresql://\") || url.startsWith(\"postgres://\");\n}\n\nfunction isInteractive(): boolean {\n  return Boolean(process.stdin.isTTY) && !process.env.CI;\n}\n\n/**\n * Resolves the on-disk PGlite directories that `--reset` would delete.\n * Mirrors the resolution in apps/switchboard/src/server.mts so we touch the\n * same paths the running switchboard uses. When a Postgres URL is configured\n * the corresponding directory is null and `postgresUrl` is populated so the\n * caller can refuse.\n */\nexport function resolveResetPaths(\n  options: ResetSwitchboardOptions,\n  env: NodeJS.ProcessEnv = process.env,\n): ResolvedResetPaths {\n  const readModelDbPath =\n    options.dbPath ?? env.DATABASE_URL ?? env.PH_SWITCHBOARD_DATABASE_URL;\n  const readModelPath = readModelDbPath || \".ph/read-storage\";\n  const reactorDbUrl =\n    options.dbPath ??\n    env.PH_REACTOR_DATABASE_URL ??\n    env.PH_SWITCHBOARD_DATABASE_URL;\n  const reactorPath = reactorDbUrl || \"./.ph/reactor-storage\";\n\n  const reactorIsPostgres = !!reactorDbUrl && isPostgresUrl(reactorDbUrl);\n  const readModelIsPostgres =\n    !!readModelDbPath && isPostgresUrl(readModelDbPath);\n\n  let postgresUrl: string | null = null;\n  if (reactorIsPostgres) postgresUrl = reactorDbUrl as string;\n  else if (readModelIsPostgres) postgresUrl = readModelDbPath as string;\n\n  return {\n    reactorDir: reactorIsPostgres ? null : reactorPath,\n    readModelDir: readModelIsPostgres ? null : readModelPath,\n    postgresUrl,\n  };\n}\n\nasync function promptForConfirmation(): Promise<boolean> {\n  const enquirer = await import(\"enquirer\");\n  try {\n    const answer = await enquirer.default.prompt<{ confirmation: string }>({\n      type: \"input\",\n      name: \"confirmation\",\n      message: `Type \"${CONFIRMATION_TOKEN}\" to confirm wiping the local switchboard databases:`,\n    });\n    return answer.confirmation.trim() === CONFIRMATION_TOKEN;\n  } catch {\n    return false;\n  }\n}\n\nexport async function resetSwitchboardDatabase(\n  options: ResetSwitchboardOptions,\n): Promise<void> {\n  const paths = resolveResetPaths(options);\n\n  if (paths.postgresUrl) {\n    console.error(\n      red(\n        `Refusing to reset: a PostgreSQL URL is configured (${paths.postgresUrl}).`,\n      ),\n    );\n    console.error(\n      yellow(\n        \"`ph switchboard --reset` only wipes the local PGlite stores. \" +\n          \"To reset a Postgres-backed switchboard, drop/recreate the database manually.\",\n      ),\n    );\n    process.exit(1);\n  }\n\n  const targets = [paths.reactorDir, paths.readModelDir].filter(\n    (d): d is string => d !== null,\n  );\n\n  if (targets.length === 0) {\n    console.error(red(\"No local PGlite directories resolved; nothing to do.\"));\n    process.exit(1);\n  }\n\n  console.log(yellow(\"The following directories will be permanently deleted:\"));\n  for (const dir of targets) {\n    console.log(`  - ${dir}`);\n  }\n  console.log(\n    yellow(\n      \"This will wipe all local switchboard state. Migrations will re-run on next `ph switchboard`.\",\n    ),\n  );\n\n  let confirmed = false;\n  if (options.yes) {\n    confirmed = true;\n  } else if (isInteractive()) {\n    confirmed = await promptForConfirmation();\n  } else {\n    console.error(\n      red(\n        \"Refusing to reset in a non-interactive context without --yes. Re-run with --yes to confirm.\",\n      ),\n    );\n    process.exit(1);\n  }\n\n  if (!confirmed) {\n    console.error(red(\"Aborted: confirmation not provided.\"));\n    process.exit(1);\n  }\n\n  for (const dir of targets) {\n    await fs.rm(dir, { recursive: true, force: true });\n    console.log(cyan(`Removed ${dir}`));\n  }\n\n  console.log(\n    green(\n      \"Switchboard local storage reset. Run `ph switchboard` to re-initialize.\",\n    ),\n  );\n}\n"],"names":["fs"],"mappings":";;;;;AAcA,MAAM,qBAAqB;AAE3B,SAAgB,cAAc,KAAsB;CAClD,OAAO,IAAI,WAAW,eAAe,KAAK,IAAI,WAAW,aAAa;AACxE;AAEA,SAAS,gBAAyB;CAChC,OAAO,QAAQ,QAAQ,MAAM,KAAK,KAAK,CAAC,QAAQ,IAAI;AACtD;;;;;;;;AASA,SAAgB,kBACd,SACA,MAAyB,QAAQ,KACb;CACpB,MAAM,kBACJ,QAAQ,UAAU,IAAI,gBAAgB,IAAI;CAC5C,MAAM,gBAAgB,mBAAmB;CACzC,MAAM,eACJ,QAAQ,UACR,IAAI,2BACJ,IAAI;CACN,MAAM,cAAc,gBAAgB;CAEpC,MAAM,oBAAoB,CAAC,CAAC,gBAAgB,cAAc,YAAY;CACtE,MAAM,sBACJ,CAAC,CAAC,mBAAmB,cAAc,eAAe;CAEpD,IAAI,cAA6B;CACjC,IAAI,mBAAmB,cAAc;MAChC,IAAI,qBAAqB,cAAc;CAE5C,OAAO;EACL,YAAY,oBAAoB,OAAO;EACvC,cAAc,sBAAsB,OAAO;EAC3C;CACF;AACF;AAEA,eAAe,wBAA0C;CACvD,MAAM,WAAW,MAAM,OAAO;CAC9B,IAAI;EAMF,QAAO,MALc,SAAS,QAAQ,OAAiC;GACrE,MAAM;GACN,MAAM;GACN,SAAS,SAAS,mBAAmB;EACvC,CAAC,EAAA,CACa,aAAa,KAAK,MAAM;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAsB,yBACpB,SACe;CACf,MAAM,QAAQ,kBAAkB,OAAO;CAEvC,IAAI,MAAM,aAAa;EACrB,QAAQ,MACN,IACE,sDAAsD,MAAM,YAAY,GAC1E,CACF;EACA,QAAQ,MACN,OACE,2IAEF,CACF;EACA,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,UAAU,CAAC,MAAM,YAAY,MAAM,YAAY,CAAC,CAAC,QACpD,MAAmB,MAAM,IAC5B;CAEA,IAAI,QAAQ,WAAW,GAAG;EACxB,QAAQ,MAAM,IAAI,sDAAsD,CAAC;EACzE,QAAQ,KAAK,CAAC;CAChB;CAEA,QAAQ,IAAI,OAAO,wDAAwD,CAAC;CAC5E,KAAK,MAAM,OAAO,SAChB,QAAQ,IAAI,OAAO,KAAK;CAE1B,QAAQ,IACN,OACE,8FACF,CACF;CAEA,IAAI,YAAY;CAChB,IAAI,QAAQ,KACV,YAAY;MACP,IAAI,cAAc,GACvB,YAAY,MAAM,sBAAsB;MACnC;EACL,QAAQ,MACN,IACE,6FACF,CACF;EACA,QAAQ,KAAK,CAAC;CAChB;CAEA,IAAI,CAAC,WAAW;EACd,QAAQ,MAAM,IAAI,qCAAqC,CAAC;EACxD,QAAQ,KAAK,CAAC;CAChB;CAEA,KAAK,MAAM,OAAO,SAAS;EACzB,MAAMA,SAAG,GAAG,KAAK;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACjD,QAAQ,IAAI,KAAK,WAAW,KAAK,CAAC;CACpC;CAEA,QAAQ,IACN,MACE,yEACF,CACF;AACF","debug_id":"17d56bac-3fa6-5ce5-b8c7-495f6c94c9d7"}