@rebasepro/cli 0.25.0 → 0.25.1

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.
Files changed (125) hide show
  1. package/dist/{agent-setup-B5AKHOgt.js → agent-setup-BYb2Tbdz.js} +2 -2
  2. package/dist/{agent-setup-B5AKHOgt.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
  3. package/dist/{api-keys-Tm7zvAPe.js → api-keys-CSMbsmAn.js} +3 -4
  4. package/dist/{api-keys-Tm7zvAPe.js.map → api-keys-CSMbsmAn.js.map} +1 -1
  5. package/dist/{apps-BsU_ILbP.js → apps-iBXNZhVN.js} +6 -7
  6. package/dist/{apps-BsU_ILbP.js.map → apps-iBXNZhVN.js.map} +1 -1
  7. package/dist/{atlas-dev-database-OWtqnG7W.js → atlas-dev-database-BusbHP6n.js} +4 -4
  8. package/dist/{atlas-dev-database-OWtqnG7W.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
  9. package/dist/{auth-Vl2hFKXP.js → auth-DRsTWPky.js} +6 -7
  10. package/dist/{auth-Vl2hFKXP.js.map → auth-DRsTWPky.js.map} +1 -1
  11. package/dist/{branch-pointer-9DnwkFJJ.js → branch-pointer-Bn_FjNld.js} +1 -1
  12. package/dist/{build-BBgT8EJZ.js → build-et7Rccxi.js} +6 -7
  13. package/dist/{build-BBgT8EJZ.js.map → build-et7Rccxi.js.map} +1 -1
  14. package/dist/{bundle-DtCCCr4w.js → bundle-DlqkDYSe.js} +3 -3
  15. package/dist/{bundle-DtCCCr4w.js.map → bundle-DlqkDYSe.js.map} +1 -1
  16. package/dist/{cloud-BpH0_bmV.js → cloud-B-ZIjHrA.js} +10 -11
  17. package/dist/{cloud-BpH0_bmV.js.map → cloud-B-ZIjHrA.js.map} +1 -1
  18. package/dist/commands/dev.d.ts +12 -0
  19. package/dist/commands/generate_sdk.d.ts +4 -2
  20. package/dist/commands/init.d.ts +20 -0
  21. package/dist/commands/start.d.ts +10 -0
  22. package/dist/commands/upgrade.d.ts +12 -0
  23. package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
  24. package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
  25. package/dist/{console-CEGm0XNc.js → console-BlD9kjFW.js} +4 -4
  26. package/dist/{console-CEGm0XNc.js.map → console-BlD9kjFW.js.map} +1 -1
  27. package/dist/{context-CyflUrKg.js → context-DHiiiJ5C.js} +3 -4
  28. package/dist/context-DHiiiJ5C.js.map +1 -0
  29. package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
  30. package/dist/daemon-DDMRbz4T.js.map +1 -0
  31. package/dist/{daemon-entry-CbLRrgzy.js → daemon-entry-zOC1revO.js} +6 -3
  32. package/dist/daemon-entry-zOC1revO.js.map +1 -0
  33. package/dist/{db-CRNpA5mH.js → db-9P6MnmdC.js} +90 -50
  34. package/dist/db-9P6MnmdC.js.map +1 -0
  35. package/dist/{derive-CsoFGAnK.js → derive-MTdClnkc.js} +2 -2
  36. package/dist/{derive-CsoFGAnK.js.map → derive-MTdClnkc.js.map} +1 -1
  37. package/dist/{dev-C0pbMmhS.js → dev-BDN_OKXA.js} +183 -23
  38. package/dist/dev-BDN_OKXA.js.map +1 -0
  39. package/dist/dev-db/daemon.d.ts +41 -0
  40. package/dist/dev-db/pull.d.ts +33 -5
  41. package/dist/dev-db/state.d.ts +9 -0
  42. package/dist/{dev-preflight-unHpiYO1.js → dev-preflight-FT9GbJVj.js} +73 -27
  43. package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
  44. package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
  45. package/dist/dev-server-CIZwAfZa.js.map +1 -0
  46. package/dist/{doctor-CATRdWm6.js → doctor-D8YXz7df.js} +6 -6
  47. package/dist/doctor-D8YXz7df.js.map +1 -0
  48. package/dist/{eject-DuasTr-F.js → eject-izG2KjMo.js} +3 -4
  49. package/dist/{eject-DuasTr-F.js.map → eject-izG2KjMo.js.map} +1 -1
  50. package/dist/{fold-static-hDHtDfTq.js → fold-static-CybSay_W.js} +3 -3
  51. package/dist/{fold-static-hDHtDfTq.js.map → fold-static-CybSay_W.js.map} +1 -1
  52. package/dist/{generate_sdk-Cvg5jjJF.js → generate_sdk-B4R65oUV.js} +21 -11
  53. package/dist/generate_sdk-B4R65oUV.js.map +1 -0
  54. package/dist/index.es.js +36 -37
  55. package/dist/index.es.js.map +1 -1
  56. package/dist/{init-BWAwHPtz.js → init-DYaeppEN.js} +50 -62
  57. package/dist/init-DYaeppEN.js.map +1 -0
  58. package/dist/invoked-command-CG_rIa_o.js +55 -0
  59. package/dist/invoked-command-CG_rIa_o.js.map +1 -0
  60. package/dist/last-dev-database-B_75fxZC.js +2 -0
  61. package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
  62. package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
  63. package/dist/{normalize-imports-BoBVh5tU.js → normalize-imports-BYw8ad87.js} +3 -3
  64. package/dist/{normalize-imports-BoBVh5tU.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
  65. package/dist/{prepare-DdnU70z8.js → prepare-1rVNd2PF.js} +5 -4
  66. package/dist/{prepare-DdnU70z8.js.map → prepare-1rVNd2PF.js.map} +1 -1
  67. package/dist/project-g4K6kV1t.js +701 -0
  68. package/dist/project-g4K6kV1t.js.map +1 -0
  69. package/dist/{pull-C3PXduzl.js → pull-DDMpsZ5r.js} +131 -24
  70. package/dist/pull-DDMpsZ5r.js.map +1 -0
  71. package/dist/refusal-ReeeGP8a.js +26 -0
  72. package/dist/refusal-ReeeGP8a.js.map +1 -0
  73. package/dist/resolve-BQUAC3Wi.js +2 -0
  74. package/dist/{resources-BdNRDEAy.js → resources-CovP8AZ-.js} +4 -5
  75. package/dist/{resources-BdNRDEAy.js.map → resources-CovP8AZ-.js.map} +1 -1
  76. package/dist/{schema-B0-p6T1O.js → schema-nuxvvc50.js} +5 -6
  77. package/dist/{schema-B0-p6T1O.js.map → schema-nuxvvc50.js.map} +1 -1
  78. package/dist/{skills-DfnTeyRz.js → skills-DeUIsZcT.js} +3 -4
  79. package/dist/{skills-DfnTeyRz.js.map → skills-DeUIsZcT.js.map} +1 -1
  80. package/dist/{start-BmEZkS0n.js → start-RzZqDroW.js} +20 -7
  81. package/dist/start-RzZqDroW.js.map +1 -0
  82. package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
  83. package/dist/state-CYdBvnwA.js.map +1 -0
  84. package/dist/{status-BJ26yZOo.js → status-D9Zm88NZ.js} +8 -9
  85. package/dist/{status-BJ26yZOo.js.map → status-D9Zm88NZ.js.map} +1 -1
  86. package/dist/{storage-DKPUBTWG.js → storage-BB3umRfw.js} +3 -4
  87. package/dist/{storage-DKPUBTWG.js.map → storage-BB3umRfw.js.map} +1 -1
  88. package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
  89. package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
  90. package/dist/{telemetry-m9czTNGR.js → telemetry-TseNLk6X.js} +4 -4
  91. package/dist/{telemetry-m9czTNGR.js.map → telemetry-TseNLk6X.js.map} +1 -1
  92. package/dist/{upgrade-DjihWuZL.js → upgrade-apiPKKE_.js} +26 -4
  93. package/dist/{upgrade-DjihWuZL.js.map → upgrade-apiPKKE_.js.map} +1 -1
  94. package/dist/utils/args.d.ts +32 -3
  95. package/dist/utils/boot-retry.d.ts +41 -0
  96. package/dist/utils/dev-preflight.d.ts +34 -1
  97. package/dist/utils/dev-server.d.ts +11 -0
  98. package/dist/utils/project.d.ts +5 -1
  99. package/dist/utils/unknown-command.d.ts +4 -0
  100. package/package.json +7 -7
  101. package/templates/resource-graphs/blank.json +25 -0
  102. package/templates/resource-graphs/blog.json +28 -0
  103. package/templates/resource-graphs/ecommerce.json +28 -0
  104. package/templates/resource-graphs/headless.json +22 -0
  105. package/templates/template/.env.example +5 -4
  106. package/templates/template/frontend/src/App.tsx +10 -9
  107. package/dist/args-BX0YD14a.js +0 -266
  108. package/dist/args-BX0YD14a.js.map +0 -1
  109. package/dist/context-CyflUrKg.js.map +0 -1
  110. package/dist/daemon-CknkDjd6.js.map +0 -1
  111. package/dist/daemon-entry-CbLRrgzy.js.map +0 -1
  112. package/dist/db-CRNpA5mH.js.map +0 -1
  113. package/dist/dev-C0pbMmhS.js.map +0 -1
  114. package/dist/dev-preflight-unHpiYO1.js.map +0 -1
  115. package/dist/dev-server-B1UYifZJ.js.map +0 -1
  116. package/dist/doctor-CATRdWm6.js.map +0 -1
  117. package/dist/generate_sdk-Cvg5jjJF.js.map +0 -1
  118. package/dist/init-BWAwHPtz.js.map +0 -1
  119. package/dist/last-dev-database-c_dKz1S3.js +0 -2
  120. package/dist/project-Wp2zoyeN.js +0 -349
  121. package/dist/project-Wp2zoyeN.js.map +0 -1
  122. package/dist/pull-C3PXduzl.js.map +0 -1
  123. package/dist/resolve-CNQjsatH.js +0 -2
  124. package/dist/start-BmEZkS0n.js.map +0 -1
  125. package/dist/state-CCB-FAQ9.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"state-CCB-FAQ9.js","names":[],"sources":["../src/dev-db/state.ts"],"sourcesContent":["/**\n * The managed database's state file, and the rules for trusting it.\n *\n * The daemon outlives the command that started it — `rebase db push` in one\n * terminal and `rebase dev` in another have to reach the *same* PGlite, because\n * two processes opening one data directory would corrupt it. So the daemon\n * records where it is, and every command reads that record.\n *\n * A record on disk is a claim, not a fact. The process it names may have been\n * killed, the machine may have rebooted and handed the pid to something else,\n * and the port may now belong to a stranger. {@link readState} therefore only\n * parses; deciding whether a record is live is {@link isDaemonAlive}'s job, and\n * it asks the daemon rather than the operating system.\n */\n\nimport { createHash } from \"crypto\";\nimport fs from \"fs\";\nimport { DEFAULT_RESOURCE_KEY, resourceEnvSuffix } from \"@rebasepro/types\";\nimport net from \"net\";\nimport path from \"path\";\n\n/** Everything under here is generated and gitignored. */\nexport const DEV_DB_DIR = \".rebase\";\n/** PGlite's own data directory. Deleting it is what `--reset` means. */\nexport const DATA_DIR_NAME = \"pgdata\";\n/** The record the daemon writes once it is accepting connections. */\nexport const STATE_FILE_NAME = \"pglite.json\";\n/**\n * Held by whoever is currently starting a daemon.\n *\n * Without it, `rebase dev` and `rebase db push` started in the same second both\n * see no state file, both spawn, and two processes open one PGlite data\n * directory — the exact corruption the single-daemon design exists to prevent.\n * Observed as `ENOTEMPTY` during cleanup, which is the harmless way for it to\n * show up; the harmful way is a damaged database.\n */\nexport const START_LOCK_NAME = \"starting.lock\";\n/**\n * The port each managed database last listened on, by key.\n *\n * Kept apart from the state file because it has to outlive the daemon: the\n * state file is cleared on every stop, and it is what a stopped daemon's\n * successor reads to come back where the last one was. See\n * {@link chooseManagedPort}.\n */\nexport const PORTS_FILE_NAME = \"pglite-ports.json\";\n\nexport interface DaemonState {\n /** TCP port the socket server is listening on, chosen when it started. */\n port: number;\n /** The daemon process. Used only as a fast negative check. */\n pid: number;\n /** Absolute path of the PGlite data directory this daemon has open. */\n dataDir: string;\n /** ISO timestamp, for diagnostics. */\n startedAt: string;\n /**\n * A random token the daemon also answers with over the wire, on\n * {@link identityPort}.\n *\n * Without it, \"is the daemon alive?\" degrades to \"is something listening on\n * that port?\", which is a different question and answers yes for whatever\n * process happened to take the port after a reboot. Rebase would then send\n * migrations to a stranger.\n */\n token: string;\n /** Loopback port that answers the identity check. */\n identityPort: number;\n /**\n * The additional databases this daemon serves, by declared key.\n *\n * One PGlite instance each — PGlite is one database per instance, so\n * `database(\"analytics\")` is a second data directory and a second port,\n * not a `CREATE DATABASE`. Started on demand when a command asks for the\n * key over the identity socket, and recorded here so `rebase status` and\n * a reset can see them. The default database is the fields above.\n */\n databases?: Record<string, { port: number; dataDir: string }>;\n}\n\nexport function devDbDir(projectRoot: string): string {\n return path.join(projectRoot, DEV_DB_DIR);\n}\n\nexport function dataDir(projectRoot: string): string {\n return path.join(devDbDir(projectRoot), DATA_DIR_NAME);\n}\n\n/**\n * The data directory for an additional declared database.\n *\n * `pgdata__analytics`: the key spelled the way its variable is, so the\n * directory beside `pgdata` and `DATABASE_URL__ANALYTICS` are visibly the\n * same thing.\n */\nexport function additionalDataDir(projectRoot: string, key: string): string {\n return path.join(devDbDir(projectRoot), `${DATA_DIR_NAME}${resourceEnvSuffix(key).toLowerCase()}`);\n}\n\nexport function stateFile(projectRoot: string): string {\n return path.join(devDbDir(projectRoot), STATE_FILE_NAME);\n}\n\nexport function startLockFile(projectRoot: string): string {\n return path.join(devDbDir(projectRoot), START_LOCK_NAME);\n}\n\n/**\n * Take the start lock, or report that somebody else holds it.\n *\n * `wx` is the whole mechanism: create-if-absent is a single atomic syscall, so\n * exactly one of two racing processes can succeed no matter how close together\n * they arrive.\n *\n * A lock older than `staleAfterMs` is broken rather than waited on — the holder\n * may have been killed between creating it and starting anything, and a\n * developer should never have to know this file exists in order to unstick\n * their project.\n */\nexport function acquireStartLock(projectRoot: string, staleAfterMs: number): boolean {\n const target = startLockFile(projectRoot);\n fs.mkdirSync(devDbDir(projectRoot), { recursive: true });\n\n const attempt = (): boolean => {\n try {\n const handle = fs.openSync(target, \"wx\");\n fs.writeSync(handle, `${process.pid} ${new Date().toISOString()}\\n`);\n fs.closeSync(handle);\n\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\n return false;\n }\n };\n\n if (attempt()) return true;\n\n try {\n // Clamped at zero: a filesystem whose timestamp granularity rounds the\n // mtime *up* reports a negative age for a lock created moments ago,\n // and a negative age is below every threshold — so `staleAfterMs: 0`,\n // which means \"break any lock\", would refuse to break one.\n const age = Math.max(0, Date.now() - fs.statSync(target).mtimeMs);\n if (age < staleAfterMs) return false;\n fs.unlinkSync(target);\n } catch {\n // Vanished under us, which means the holder finished. Either way the\n // next attempt is the answer.\n }\n\n return attempt();\n}\n\nexport function releaseStartLock(projectRoot: string): void {\n try {\n fs.unlinkSync(startLockFile(projectRoot));\n } catch {\n // Already released is the desired end state.\n }\n}\n\n/**\n * Parse the record, or `null` for anything that is not one.\n *\n * Every failure is the same answer — absent — because every failure has the\n * same remedy: start a daemon. A corrupt state file is not worth an error\n * message to a user who never wrote it.\n */\nexport function readState(projectRoot: string): DaemonState | null {\n let raw: string;\n try {\n raw = fs.readFileSync(stateFile(projectRoot), \"utf8\");\n } catch {\n return null;\n }\n\n try {\n const parsed = JSON.parse(raw) as Partial<DaemonState>;\n if (\n typeof parsed.port !== \"number\" ||\n !Number.isInteger(parsed.port) ||\n parsed.port <= 0 ||\n parsed.port > 65535 ||\n typeof parsed.pid !== \"number\" ||\n typeof parsed.dataDir !== \"string\" ||\n typeof parsed.token !== \"string\" ||\n parsed.token.length === 0 ||\n typeof parsed.identityPort !== \"number\" ||\n !Number.isInteger(parsed.identityPort) ||\n parsed.identityPort <= 0 ||\n parsed.identityPort > 65535\n ) {\n return null;\n }\n\n // Only well-formed entries survive: a malformed one is treated as\n // absent, and the next ensure asks the daemon for it again.\n const databases: Record<string, { port: number; dataDir: string }> = {};\n if (parsed.databases && typeof parsed.databases === \"object\") {\n for (const [key, entry] of Object.entries(parsed.databases)) {\n if (\n entry && typeof entry.port === \"number\" && Number.isInteger(entry.port)\n && entry.port > 0 && entry.port <= 65535 && typeof entry.dataDir === \"string\"\n ) {\n databases[key] = { port: entry.port, dataDir: entry.dataDir };\n }\n }\n }\n\n return {\n port: parsed.port,\n pid: parsed.pid,\n dataDir: parsed.dataDir,\n startedAt: typeof parsed.startedAt === \"string\" ? parsed.startedAt : \"\",\n token: parsed.token,\n identityPort: parsed.identityPort,\n ...(Object.keys(databases).length > 0 ? { databases } : {})\n };\n } catch {\n return null;\n }\n}\n\nexport function writeState(projectRoot: string, state: DaemonState): void {\n fs.mkdirSync(devDbDir(projectRoot), { recursive: true });\n // Written whole then moved, so a reader never sees half a record — commands\n // poll this file while the daemon is starting.\n const target = stateFile(projectRoot);\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n fs.renameSync(temporary, target);\n}\n\nexport function clearState(projectRoot: string): void {\n try {\n fs.unlinkSync(stateFile(projectRoot));\n } catch {\n // Already gone is the desired end state.\n }\n}\n\n/** Is *some* process with this pid running? A fast, cheap negative check. */\nexport function pidRunning(pid: number): boolean {\n try {\n // Signal 0 performs the permission and existence checks without\n // delivering anything.\n process.kill(pid, 0);\n\n return true;\n } catch (error) {\n // EPERM means it exists and belongs to someone else, which for our\n // purposes is still \"running\".\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/** Can a TCP connection be opened to this port on loopback? */\nexport function portAccepting(port: number, timeoutMs = 1000): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = new net.Socket();\n const settle = (answer: boolean) => {\n socket.removeAllListeners();\n socket.destroy();\n resolve(answer);\n };\n socket.setTimeout(timeoutMs);\n socket.once(\"connect\", () => settle(true));\n socket.once(\"timeout\", () => settle(false));\n socket.once(\"error\", () => settle(false));\n socket.connect(port, \"127.0.0.1\");\n });\n}\n\n/**\n * Ask a port for a free one, then hand back the number.\n *\n * Deliberately not the probe `rebase init` uses: that one has a documented\n * failure where a port is free to probe and unusable to publish. This binds on\n * loopback only, which is also where the daemon listens, so a port that binds\n * here binds there.\n */\nexport function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n server.close(() => reject(new Error(\"Could not determine a free port.\")));\n\n return;\n }\n const { port } = address;\n server.close(() => resolve(port));\n });\n });\n}\n\n/** Where a project's derived database port falls: 25432–26431. */\nconst MANAGED_PORT_FIRST = 25432;\nconst MANAGED_PORT_SPAN = 1000;\n\n/**\n * The port a project's managed database tries first when nothing is recorded:\n * derived from the project path, and for an additional database from its key\n * too, so two projects — and a project's two databases — rarely ask for the\n * same one.\n *\n * Below every ephemeral range (Linux hands out 32768 and up, macOS 49152 and\n * up), so an outgoing connection's source port never sits on it, and clear of\n * the ports `rebase dev` derives for the backend (3001–3999), the admin panel\n * (5173–5372) and the compose database (5433–5632).\n */\nexport function derivedManagedPort(projectRoot: string, key: string = DEFAULT_RESOURCE_KEY): number {\n const seed = key === DEFAULT_RESOURCE_KEY ? path.resolve(projectRoot) : `${path.resolve(projectRoot)}\\0${key}`;\n const digest = createHash(\"sha256\").update(seed).digest();\n return MANAGED_PORT_FIRST + (digest.readUInt32BE(0) % MANAGED_PORT_SPAN);\n}\n\nfunction portsFile(projectRoot: string): string {\n return path.join(devDbDir(projectRoot), PORTS_FILE_NAME);\n}\n\n/** The port each database last listened on, by key; empty when nothing is recorded or the record is unreadable. */\nfunction readRecordedPorts(projectRoot: string): Record<string, number> {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(portsFile(projectRoot), \"utf8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n const ports: Record<string, number> = {};\n for (const [key, port] of Object.entries(parsed)) {\n if (typeof port === \"number\" && Number.isInteger(port) && port > 0 && port <= 65535) ports[key] = port;\n }\n return ports;\n } catch {\n return {};\n }\n}\n\n/**\n * Remember where these databases listen, merged into what is recorded.\n *\n * Best effort: a `.rebase/` that cannot be written costs the next start its\n * preference, not the start itself.\n */\nexport function recordManagedPorts(projectRoot: string, ports: Record<string, number>): void {\n try {\n fs.mkdirSync(devDbDir(projectRoot), { recursive: true });\n const merged = { ...readRecordedPorts(projectRoot), ...ports };\n const target = portsFile(projectRoot);\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(merged, null, 2)}\\n`, \"utf8\");\n fs.renameSync(temporary, target);\n } catch {\n // See above.\n }\n}\n\n/** Can a server listen on this loopback port right now? */\nexport function portBindable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once(\"error\", () => resolve(false));\n server.listen(port, \"127.0.0.1\", () => server.close(() => resolve(true)));\n });\n}\n\n/**\n * The port a managed database should listen on: where it listened last time,\n * else the one derived from the project path, else any free one.\n *\n * Stable on purpose. A backend holds the URL it was started with, and a pool\n * reconnects to the same address on its own — so a database that comes back on\n * the port it had is one a running `rebase dev` recovers from without a\n * restart. It used to be whatever the operating system handed out, and a `rebase\n * db stop` followed by any command that starts it again left the backend\n * dialling a port nothing listened on, answering 503 until dev was restarted.\n *\n * @param canBind stands in for {@link portBindable} in the tests.\n */\nexport async function chooseManagedPort(\n projectRoot: string,\n key: string = DEFAULT_RESOURCE_KEY,\n canBind: (port: number) => Promise<boolean> = portBindable\n): Promise<number> {\n const candidates = [readRecordedPorts(projectRoot)[key], derivedManagedPort(projectRoot, key)];\n for (const port of new Set(candidates.filter((candidate): candidate is number => candidate !== undefined))) {\n if (await canBind(port)) return port;\n }\n return findFreePort();\n}\n"],"mappings":"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"}