@rebasepro/cli 0.24.0 → 0.24.1-canary.g56af4a4

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 (118) hide show
  1. package/bin/rebase.js +3 -0
  2. package/dist/agent-setup-B31F00DC.js +324 -0
  3. package/dist/agent-setup-B31F00DC.js.map +1 -0
  4. package/dist/api-keys-BPBi5nOF.js +524 -0
  5. package/dist/api-keys-BPBi5nOF.js.map +1 -0
  6. package/dist/apps-CPXNElX4.js +256 -0
  7. package/dist/apps-CPXNElX4.js.map +1 -0
  8. package/dist/args-BnmsEXvu.js +109 -0
  9. package/dist/args-BnmsEXvu.js.map +1 -0
  10. package/dist/atlas-dev-database-DTMuEScS.js +62 -0
  11. package/dist/atlas-dev-database-DTMuEScS.js.map +1 -0
  12. package/dist/auth-DvY94ZuL.js +395 -0
  13. package/dist/auth-DvY94ZuL.js.map +1 -0
  14. package/dist/branch-pointer-DIhKbQLp.js +2 -0
  15. package/dist/build-CFwUx-Ff.js +336 -0
  16. package/dist/build-CFwUx-Ff.js.map +1 -0
  17. package/dist/bundle-BQhP_xiA.js +1617 -0
  18. package/dist/bundle-BQhP_xiA.js.map +1 -0
  19. package/dist/cli.d.ts +2 -2
  20. package/dist/cloud-CkTr-yt0.js +9640 -0
  21. package/dist/cloud-CkTr-yt0.js.map +1 -0
  22. package/dist/collection-drift-BKj_BoMq.js +106 -0
  23. package/dist/collection-drift-BKj_BoMq.js.map +1 -0
  24. package/dist/commands/api-keys.d.ts +2 -0
  25. package/dist/commands/db.d.ts +37 -24
  26. package/dist/commands/dev.d.ts +103 -0
  27. package/dist/commands/generate_sdk.d.ts +26 -0
  28. package/dist/commands/skills.d.ts +22 -7
  29. package/dist/commands/storage.d.ts +46 -0
  30. package/dist/consent-BWHaYx5p.js +76 -0
  31. package/dist/consent-BWHaYx5p.js.map +1 -0
  32. package/dist/context-BqhRydBg.js +1234 -0
  33. package/dist/context-BqhRydBg.js.map +1 -0
  34. package/dist/daemon-DBn-shxX.js +2 -0
  35. package/dist/{daemon-entry-LTFKtpHy.js → daemon-entry-Da-D3rmH.js} +3 -4
  36. package/dist/daemon-entry-Da-D3rmH.js.map +1 -0
  37. package/dist/db-CMpBK3sv.js +1252 -0
  38. package/dist/db-CMpBK3sv.js.map +1 -0
  39. package/dist/derive-RPIsAVO4.js +474 -0
  40. package/dist/derive-RPIsAVO4.js.map +1 -0
  41. package/dist/dev-C9P5Yp9k.js +1593 -0
  42. package/dist/dev-C9P5Yp9k.js.map +1 -0
  43. package/dist/dev-db/atlas-dev-database.d.ts +32 -0
  44. package/dist/dev-db/daemon-entry.d.ts +13 -0
  45. package/dist/dev-preflight-N1evJL3S.js +2 -0
  46. package/dist/doctor-DYs-NqFI.js +771 -0
  47. package/dist/doctor-DYs-NqFI.js.map +1 -0
  48. package/dist/eject-BT6t37D0.js +335 -0
  49. package/dist/eject-BT6t37D0.js.map +1 -0
  50. package/dist/fold-static-C1EtHlfV.js +201 -0
  51. package/dist/fold-static-C1EtHlfV.js.map +1 -0
  52. package/dist/function-portability-BIvlvR9q.js +265 -0
  53. package/dist/function-portability-BIvlvR9q.js.map +1 -0
  54. package/dist/generate_sdk-UV635zSe.js +477 -0
  55. package/dist/generate_sdk-UV635zSe.js.map +1 -0
  56. package/dist/index.es.js +141 -24674
  57. package/dist/index.es.js.map +1 -1
  58. package/dist/init-fXeBcxuN.js +1042 -0
  59. package/dist/init-fXeBcxuN.js.map +1 -0
  60. package/dist/manifest-DzlC60WX.js +871 -0
  61. package/dist/manifest-DzlC60WX.js.map +1 -0
  62. package/dist/normalize-imports-CmVdE9iZ.js +100 -0
  63. package/dist/normalize-imports-CmVdE9iZ.js.map +1 -0
  64. package/dist/{package-manager-CXQevsE1.js → package-manager-DSEOwTqM.js} +2 -2
  65. package/dist/{package-manager-CXQevsE1.js.map → package-manager-DSEOwTqM.js.map} +1 -1
  66. package/dist/path-flags-DUBuI2i1.js +77 -0
  67. package/dist/path-flags-DUBuI2i1.js.map +1 -0
  68. package/dist/precompress.d.ts +17 -0
  69. package/dist/prepare-Btn9Ewbn.js +1052 -0
  70. package/dist/prepare-Btn9Ewbn.js.map +1 -0
  71. package/dist/{project-DmaGLmH2.js → project-Wp2zoyeN.js} +33 -4
  72. package/dist/project-Wp2zoyeN.js.map +1 -0
  73. package/dist/resolve-CJLkfFV0.js +2 -0
  74. package/dist/resources-DT1COn_6.js +161 -0
  75. package/dist/resources-DT1COn_6.js.map +1 -0
  76. package/dist/schema-BDBWvCHu.js +125 -0
  77. package/dist/schema-BDBWvCHu.js.map +1 -0
  78. package/dist/skills-DTFibT1m.js +642 -0
  79. package/dist/skills-DTFibT1m.js.map +1 -0
  80. package/dist/start-rU2e3Kp5.js +228 -0
  81. package/dist/start-rU2e3Kp5.js.map +1 -0
  82. package/dist/{state-C59Elrnt.js → state-Do7ZJYkF.js} +49 -4
  83. package/dist/state-Do7ZJYkF.js.map +1 -0
  84. package/dist/status-BR9oyi-y.js +351 -0
  85. package/dist/status-BR9oyi-y.js.map +1 -0
  86. package/dist/storage-DyvrSTH3.js +303 -0
  87. package/dist/storage-DyvrSTH3.js.map +1 -0
  88. package/dist/telemetry-CAWNCugs.js +338 -0
  89. package/dist/telemetry-CAWNCugs.js.map +1 -0
  90. package/dist/telemetry-DbLqGIBW.js +129 -0
  91. package/dist/telemetry-DbLqGIBW.js.map +1 -0
  92. package/dist/unknown-command-DNwDcX3w.js +98 -0
  93. package/dist/unknown-command-DNwDcX3w.js.map +1 -0
  94. package/dist/upgrade-D-5-Od96.js +1265 -0
  95. package/dist/upgrade-D-5-Od96.js.map +1 -0
  96. package/dist/utils/project.d.ts +16 -0
  97. package/dist/{version-DsgBmP22.js → version-Buyyo1ut.js} +2 -2
  98. package/dist/{version-DsgBmP22.js.map → version-Buyyo1ut.js.map} +1 -1
  99. package/package.json +7 -7
  100. package/templates/eject/backend/src/env.ts +1 -1
  101. package/templates/eject/backend/src/index.ts +10 -2
  102. package/templates/template/README.md +1 -1
  103. package/templates/template/ai-instructions.md +2 -1
  104. package/templates/template/frontend/vite.config.ts +11 -3
  105. package/templates/template/scripts/example.ts +2 -1
  106. package/dist/branch-pointer-kk9F5FBO.js +0 -111
  107. package/dist/branch-pointer-kk9F5FBO.js.map +0 -1
  108. package/dist/constraints-DKGbNfUW.js +0 -48
  109. package/dist/constraints-DKGbNfUW.js.map +0 -1
  110. package/dist/daemon-C8p32i-n.js +0 -357
  111. package/dist/daemon-C8p32i-n.js.map +0 -1
  112. package/dist/daemon-entry-LTFKtpHy.js.map +0 -1
  113. package/dist/dev-preflight-CNLl4rdo.js +0 -367
  114. package/dist/dev-preflight-CNLl4rdo.js.map +0 -1
  115. package/dist/project-DmaGLmH2.js.map +0 -1
  116. package/dist/resolve-BAeRUBhg.js +0 -74
  117. package/dist/resolve-BAeRUBhg.js.map +0 -1
  118. package/dist/state-C59Elrnt.js.map +0 -1
@@ -0,0 +1,256 @@
1
+ import { i as failAsJson, p as requireProjectRoot } from "./project-Wp2zoyeN.js";
2
+ import { n as parseCommandArgs, r as wantsHelp } from "./args-BnmsEXvu.js";
3
+ import { t as unknownCommand } from "./unknown-command-DNwDcX3w.js";
4
+ import { d as findBackendApp, f as formatAppAddress, m as manifestExists, o as ManifestError, p as loadManifest, s as assessManagedCompatibility, v as staticAppAddress, x as writeManifest, y as synthesizeManifest } from "./manifest-DzlC60WX.js";
5
+ import { M as readLink } from "./context-BqhRydBg.js";
6
+ import { r as foldableApps } from "./fold-static-C1EtHlfV.js";
7
+ import chalk from "chalk";
8
+ import fs from "fs";
9
+ import path from "path";
10
+ //#region src/commands/apps.ts
11
+ /**
12
+ * CLI command: rebase apps
13
+ *
14
+ * Inspect the apps this repository contributes to a project, adopt a
15
+ * `rebase.json` for a project that predates it, and print the client bootstrap
16
+ * an app needs to reach its backend.
17
+ *
18
+ * The distinction that runs through all of this: a *repository* declares apps,
19
+ * a *project* owns them. Two repositories can contribute to the same project and
20
+ * never know about each other, which is what makes a separate frontend repo — or
21
+ * a mobile app with no repo relationship at all — an ordinary thing rather than
22
+ * a special case.
23
+ */
24
+ function printHelp() {
25
+ console.log(`
26
+ ${chalk.bold("rebase apps")} — the apps this repository contributes
27
+
28
+ ${chalk.bold("Usage")}
29
+ rebase apps list List declared apps and their build outputs
30
+ rebase apps init Write a rebase.json inferred from this project
31
+ rebase apps config <app> Print the client configuration for an app
32
+
33
+ ${chalk.bold("Options")}
34
+ --json Machine-readable output
35
+ --force Overwrite an existing rebase.json (apps init)
36
+ -h, --help Show this help
37
+ `.trim());
38
+ }
39
+ /** Everything the switch below dispatches, for the did-you-mean. */
40
+ var APPS_SUBCOMMANDS = [
41
+ "list",
42
+ "init",
43
+ "config"
44
+ ];
45
+ async function appsCommand(subcommand, rawArgs = []) {
46
+ if (!subcommand || subcommand === "--help" || wantsHelp(rawArgs)) {
47
+ printHelp();
48
+ return;
49
+ }
50
+ const { flags: args, positionals } = parseCommandArgs({
51
+ spec: {
52
+ "--json": Boolean,
53
+ "--force": Boolean
54
+ },
55
+ rawArgs,
56
+ commandWords: 1,
57
+ command: "apps",
58
+ maxPositionals: 2
59
+ });
60
+ switch (subcommand) {
61
+ case "list":
62
+ await listApps(Boolean(args["--json"]));
63
+ break;
64
+ case "init":
65
+ await initManifest(Boolean(args["--force"]));
66
+ break;
67
+ case "config":
68
+ await printAppConfig(positionals[1], Boolean(args["--json"]));
69
+ break;
70
+ default: unknownCommand(subcommand, APPS_SUBCOMMANDS, "apps");
71
+ }
72
+ }
73
+ /**
74
+ * One app's line in `rebase apps list`.
75
+ *
76
+ * A static app shows its full address — the https URL when its `path` gives it
77
+ * a hostname — and the CMS as the address a browser would open. `CMS at /` on
78
+ * an app that lives on `admin.example.com` reads as the project's own root,
79
+ * which is the one place that CMS is not.
80
+ */
81
+ function describeApp(name, app) {
82
+ switch (app.type) {
83
+ case "backend": return app.runtime === "custom" ? `custom runtime — ${app.dockerfile ?? "Dockerfile"}` + (app.context && app.context !== "." ? ` (context: ${app.context})` : "") : `managed runtime, config: ${app.config ?? "config"}`;
84
+ case "static": {
85
+ const address = staticAppAddress(name, app);
86
+ return `${app.root} → ${app.output} @ ${formatAppAddress(address)}` + (app.cms ? ` ${chalk.magenta(`CMS at ${formatAppAddress({
87
+ ...address,
88
+ path: app.cms
89
+ })}`)}` : "");
90
+ }
91
+ default: return "";
92
+ }
93
+ }
94
+ async function listApps(asJson) {
95
+ const loaded = loadManifestOrExit(requireProjectRoot(), asJson);
96
+ const compatibility = assessManagedCompatibility(loaded.manifest);
97
+ if (asJson) {
98
+ console.log(JSON.stringify({
99
+ source: loaded.source,
100
+ rebase: loaded.manifest.rebase,
101
+ apps: loaded.manifest.apps,
102
+ managed: compatibility
103
+ }, null, 2));
104
+ return;
105
+ }
106
+ if (loaded.source === "synthesized") {
107
+ console.log(chalk.dim("No rebase.json — showing the layout inferred from this project."));
108
+ console.log(chalk.dim(`Run ${chalk.cyan("rebase apps init")} to write it down.\n`));
109
+ }
110
+ console.log(chalk.bold(`Rebase ${loaded.manifest.rebase}`));
111
+ console.log("");
112
+ const entries = Object.entries(loaded.manifest.apps);
113
+ if (entries.length === 0) {
114
+ console.log(chalk.yellow("No apps declared."));
115
+ return;
116
+ }
117
+ const width = Math.max(...entries.map(([name]) => name.length));
118
+ for (const [name, app] of entries) console.log(` ${chalk.cyan(name.padEnd(width))} ${chalk.dim(app.type.padEnd(8))} ${describeApp(name, app)}`);
119
+ console.log("");
120
+ if (compatibility.eligible) console.log(chalk.green("✓ Eligible for the managed runtime."));
121
+ else {
122
+ console.log(chalk.yellow("• Uses the custom runtime:"));
123
+ for (const reason of compatibility.reasons) console.log(chalk.dim(` ${reason}`));
124
+ }
125
+ }
126
+ async function initManifest(force) {
127
+ const projectRoot = requireProjectRoot();
128
+ if (manifestExists(projectRoot) && !force) {
129
+ console.error(chalk.red("✗ rebase.json already exists."));
130
+ console.error(chalk.dim(" Pass --force to overwrite it."));
131
+ process.exit(1);
132
+ }
133
+ const manifest = synthesizeManifest(projectRoot);
134
+ const filePath = writeManifest(projectRoot, manifest);
135
+ console.log(chalk.green(`✓ Wrote ${path.relative(projectRoot, filePath)}`));
136
+ console.log("");
137
+ for (const [name, app] of Object.entries(manifest.apps)) console.log(` ${chalk.cyan(name)} ${chalk.dim(`(${app.type})`)}`);
138
+ const compatibility = assessManagedCompatibility(manifest);
139
+ if (!compatibility.eligible) {
140
+ console.log("");
141
+ console.log(chalk.yellow("This project will use the custom runtime:"));
142
+ for (const reason of compatibility.reasons) console.log(chalk.dim(` ${reason}`));
143
+ }
144
+ }
145
+ /**
146
+ * Print what a client needs to reach this project.
147
+ *
148
+ * Never prints a secret. The API URL and an app's publishable identity are meant
149
+ * to ship inside a client bundle; anything that is not safe there does not belong
150
+ * in output that will inevitably be pasted into a `.env` that gets committed.
151
+ */
152
+ async function printAppConfig(appName, asJson) {
153
+ const projectRoot = requireProjectRoot();
154
+ const loaded = loadManifestOrExit(projectRoot, asJson);
155
+ if (!appName) {
156
+ if (asJson) failAsJson("Which app? Usage: rebase apps config <app>", "app_not_named", `Declared: ${Object.keys(loaded.manifest.apps).join(", ") || "(none)"}`);
157
+ console.error(chalk.red("✗ Which app? Usage: rebase apps config <app>"));
158
+ process.exit(1);
159
+ }
160
+ const app = loaded.manifest.apps[appName];
161
+ if (!app) {
162
+ if (asJson) failAsJson(`No app named "${appName}" in rebase.json.`, "app_not_found", `Declared: ${Object.keys(loaded.manifest.apps).join(", ") || "(none)"}`);
163
+ console.error(chalk.red(`✗ No app named "${appName}" in rebase.json.`));
164
+ console.error(chalk.dim(` Declared: ${Object.keys(loaded.manifest.apps).join(", ") || "(none)"}`));
165
+ process.exit(1);
166
+ }
167
+ const link = readLink(projectRoot);
168
+ const sameOrigin = servedByBackend(loaded.manifest, appName);
169
+ const apiUrl = sameOrigin ? "" : resolveApiUrl(projectRoot, link);
170
+ const config = {
171
+ app: appName,
172
+ type: app.type,
173
+ apiUrl: apiUrl ?? null,
174
+ sameOrigin,
175
+ project: link?.projectId ?? link?.slug ?? null
176
+ };
177
+ if (asJson) {
178
+ console.log(JSON.stringify(config, null, 2));
179
+ return;
180
+ }
181
+ if (sameOrigin) {
182
+ console.log(chalk.bold(`# ${appName}`));
183
+ console.log("");
184
+ console.log("VITE_API_URL=");
185
+ console.log("");
186
+ console.log(chalk.dim(`Empty on purpose: \`rebase build\` folds ${appName} into the backend bundle, so it`));
187
+ console.log(chalk.dim("calls the API on the same origin it is served from, locally and deployed alike."));
188
+ console.log(chalk.dim("(`rebase dev` points it at the dev backend by itself.)"));
189
+ return;
190
+ }
191
+ if (!apiUrl) {
192
+ console.log(chalk.yellow("This checkout is not linked to a project yet."));
193
+ console.log(chalk.dim(` Run ${chalk.cyan("rebase cloud link")} (cloud) or ${chalk.cyan("rebase cloud link <url>")} (self-hosted).`));
194
+ console.log("");
195
+ }
196
+ console.log(chalk.bold(`# ${appName}`));
197
+ console.log("");
198
+ console.log(`VITE_API_URL=${apiUrl ?? "http://localhost:3001"}`);
199
+ console.log("");
200
+ console.log(chalk.dim("Then, in the app:"));
201
+ console.log(chalk.dim(" const rebase = createRebaseClient({ baseUrl: import.meta.env.VITE_API_URL });"));
202
+ }
203
+ /**
204
+ * Work out the API base URL for this checkout.
205
+ *
206
+ * Prefers an explicit link, then the dev server's own record of where it bound.
207
+ * The dev port is chosen dynamically, so a hardcoded default would be wrong on
208
+ * any machine running more than one project.
209
+ */
210
+ function resolveApiUrl(projectRoot, link) {
211
+ if (link?.apiUrl) return link.apiUrl;
212
+ const statePath = path.join(projectRoot, ".rebase", "state.json");
213
+ if (fs.existsSync(statePath)) try {
214
+ const state = JSON.parse(fs.readFileSync(statePath, "utf8"));
215
+ if (state.baseUrl && typeof state.pid === "number" && isRunning(state.pid)) return state.baseUrl;
216
+ } catch {}
217
+ }
218
+ /** Signal 0 checks a process exists without touching it; EPERM means it does, as someone else. */
219
+ function isRunning(pid) {
220
+ try {
221
+ process.kill(pid, 0);
222
+ return true;
223
+ } catch (err) {
224
+ return err.code === "EPERM";
225
+ }
226
+ }
227
+ /**
228
+ * Whether `rebase build` folds this static app into the backend bundle, which
229
+ * then serves it on the API's own origin: a managed backend, and an app with
230
+ * built output to fold. The same predicate the build folds by.
231
+ */
232
+ function servedByBackend(manifest, appName) {
233
+ const backend = findBackendApp(manifest);
234
+ if (!backend || backend.app.type !== "backend" || backend.app.runtime === "custom") return false;
235
+ return foldableApps(manifest).apps.some((app) => app.name === appName);
236
+ }
237
+ function loadManifestOrExit(projectRoot, asJson = false) {
238
+ try {
239
+ return loadManifest(projectRoot);
240
+ } catch (err) {
241
+ if (err instanceof ManifestError) {
242
+ if (asJson) failAsJson(err.message, "manifest_invalid", "Fix rebase.json, then run this again.", err.issues.map((issue) => ({
243
+ path: issue.path,
244
+ message: issue.message
245
+ })));
246
+ console.error(chalk.red(`✗ ${err.message}`));
247
+ for (const issue of err.issues) console.error(chalk.red(` ${issue.path ? `${issue.path}: ` : ""}${issue.message}`));
248
+ process.exit(1);
249
+ }
250
+ throw err;
251
+ }
252
+ }
253
+ //#endregion
254
+ export { APPS_SUBCOMMANDS, appsCommand };
255
+
256
+ //# sourceMappingURL=apps-CPXNElX4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-CPXNElX4.js","names":[],"sources":["../src/commands/apps.ts"],"sourcesContent":["/**\n * CLI command: rebase apps\n *\n * Inspect the apps this repository contributes to a project, adopt a\n * `rebase.json` for a project that predates it, and print the client bootstrap\n * an app needs to reach its backend.\n *\n * The distinction that runs through all of this: a *repository* declares apps,\n * a *project* owns them. Two repositories can contribute to the same project and\n * never know about each other, which is what makes a separate frontend repo — or\n * a mobile app with no repo relationship at all — an ordinary thing rather than\n * a special case.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport type { RebaseAppConfig } from \"@rebasepro/types\";\nimport { failAsJson, requireProjectRoot } from \"../utils/project\";\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport {\n assessManagedCompatibility,\n findBackendApp,\n formatAppAddress,\n loadManifest,\n ManifestError,\n manifestExists,\n staticAppAddress,\n synthesizeManifest,\n writeManifest\n} from \"../manifest\";\nimport { readLink } from \"./cloud/context\";\nimport { unknownCommand } from \"../utils/unknown-command\";\nimport { foldableApps } from \"../fold-static\";\n\nfunction printHelp(): void {\n console.log(`\n${chalk.bold(\"rebase apps\")} — the apps this repository contributes\n\n${chalk.bold(\"Usage\")}\n rebase apps list List declared apps and their build outputs\n rebase apps init Write a rebase.json inferred from this project\n rebase apps config <app> Print the client configuration for an app\n\n${chalk.bold(\"Options\")}\n --json Machine-readable output\n --force Overwrite an existing rebase.json (apps init)\n -h, --help Show this help\n`.trim());\n}\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const APPS_SUBCOMMANDS = [\"list\", \"init\", \"config\"] as const;\n\nexport async function appsCommand(subcommand: string | undefined, rawArgs: string[] = []): Promise<void> {\n // Help is answered before parsing, so `rebase apps config --help` prints the\n // page rather than being rejected for naming no app.\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printHelp();\n return;\n }\n\n // Only `apps` is a command word here: this one parser serves every\n // subcommand, so the subcommand stays in the positionals and the app name\n // `apps config` takes follows it.\n const { flags: args, positionals } = parseCommandArgs({\n spec: {\n \"--json\": Boolean,\n \"--force\": Boolean\n },\n rawArgs,\n commandWords: 1,\n command: \"apps\",\n maxPositionals: 2\n });\n\n switch (subcommand) {\n case \"list\":\n await listApps(Boolean(args[\"--json\"]));\n break;\n case \"init\":\n await initManifest(Boolean(args[\"--force\"]));\n break;\n case \"config\":\n await printAppConfig(positionals[1], Boolean(args[\"--json\"]));\n break;\n default:\n unknownCommand(subcommand, APPS_SUBCOMMANDS, \"apps\");\n }\n}\n\n/**\n * One app's line in `rebase apps list`.\n *\n * A static app shows its full address — the https URL when its `path` gives it\n * a hostname — and the CMS as the address a browser would open. `CMS at /` on\n * an app that lives on `admin.example.com` reads as the project's own root,\n * which is the one place that CMS is not.\n */\nexport function describeApp(name: string, app: RebaseAppConfig): string {\n switch (app.type) {\n case \"backend\":\n return app.runtime === \"custom\"\n // The context is named only when it is not the project, which is\n // the case where it changes what you would type. A workspace app\n // builds from the workspace root, and a listing that showed only\n // the Dockerfile implied a `docker build .` beside it that fails.\n ? `custom runtime — ${app.dockerfile ?? \"Dockerfile\"}`\n + (app.context && app.context !== \".\" ? ` (context: ${app.context})` : \"\")\n : `managed runtime, config: ${app.config ?? \"config\"}`;\n case \"static\": {\n const address = staticAppAddress(name, app);\n return `${app.root} → ${app.output} @ ${formatAppAddress(address)}`\n + (app.cms ? ` ${chalk.magenta(`CMS at ${formatAppAddress({ ...address, path: app.cms })}`)}` : \"\");\n }\n default:\n return \"\";\n }\n}\n\nasync function listApps(asJson: boolean): Promise<void> {\n const projectRoot = requireProjectRoot();\n const loaded = loadManifestOrExit(projectRoot, asJson);\n const compatibility = assessManagedCompatibility(loaded.manifest);\n\n if (asJson) {\n console.log(JSON.stringify(\n {\n source: loaded.source,\n rebase: loaded.manifest.rebase,\n apps: loaded.manifest.apps,\n managed: compatibility\n },\n null,\n 2\n ));\n return;\n }\n\n if (loaded.source === \"synthesized\") {\n console.log(chalk.dim(\"No rebase.json — showing the layout inferred from this project.\"));\n console.log(chalk.dim(`Run ${chalk.cyan(\"rebase apps init\")} to write it down.\\n`));\n }\n\n console.log(chalk.bold(`Rebase ${loaded.manifest.rebase}`));\n console.log(\"\");\n\n const entries = Object.entries(loaded.manifest.apps);\n if (entries.length === 0) {\n console.log(chalk.yellow(\"No apps declared.\"));\n return;\n }\n\n const width = Math.max(...entries.map(([name]) => name.length));\n for (const [name, app] of entries) {\n console.log(\n ` ${chalk.cyan(name.padEnd(width))} ${chalk.dim(app.type.padEnd(8))} ${describeApp(name, app)}`\n );\n }\n\n console.log(\"\");\n if (compatibility.eligible) {\n console.log(chalk.green(\"✓ Eligible for the managed runtime.\"));\n } else {\n console.log(chalk.yellow(\"• Uses the custom runtime:\"));\n for (const reason of compatibility.reasons) {\n console.log(chalk.dim(` ${reason}`));\n }\n }\n}\n\nasync function initManifest(force: boolean): Promise<void> {\n const projectRoot = requireProjectRoot();\n\n if (manifestExists(projectRoot) && !force) {\n console.error(chalk.red(\"✗ rebase.json already exists.\"));\n console.error(chalk.dim(\" Pass --force to overwrite it.\"));\n process.exit(1);\n }\n\n const manifest = synthesizeManifest(projectRoot);\n const filePath = writeManifest(projectRoot, manifest);\n\n console.log(chalk.green(`✓ Wrote ${path.relative(projectRoot, filePath)}`));\n console.log(\"\");\n for (const [name, app] of Object.entries(manifest.apps)) {\n console.log(` ${chalk.cyan(name)} ${chalk.dim(`(${app.type})`)}`);\n }\n\n const compatibility = assessManagedCompatibility(manifest);\n if (!compatibility.eligible) {\n console.log(\"\");\n console.log(chalk.yellow(\"This project will use the custom runtime:\"));\n for (const reason of compatibility.reasons) {\n console.log(chalk.dim(` ${reason}`));\n }\n }\n}\n\n/**\n * Print what a client needs to reach this project.\n *\n * Never prints a secret. The API URL and an app's publishable identity are meant\n * to ship inside a client bundle; anything that is not safe there does not belong\n * in output that will inevitably be pasted into a `.env` that gets committed.\n */\nasync function printAppConfig(appName: string | undefined, asJson: boolean): Promise<void> {\n const projectRoot = requireProjectRoot();\n const loaded = loadManifestOrExit(projectRoot, asJson);\n\n if (!appName) {\n if (asJson) {\n failAsJson(\"Which app? Usage: rebase apps config <app>\", \"app_not_named\",\n `Declared: ${Object.keys(loaded.manifest.apps).join(\", \") || \"(none)\"}`);\n }\n console.error(chalk.red(\"✗ Which app? Usage: rebase apps config <app>\"));\n process.exit(1);\n }\n\n const app = loaded.manifest.apps[appName];\n if (!app) {\n if (asJson) {\n failAsJson(`No app named \"${appName}\" in rebase.json.`, \"app_not_found\",\n `Declared: ${Object.keys(loaded.manifest.apps).join(\", \") || \"(none)\"}`);\n }\n console.error(chalk.red(`✗ No app named \"${appName}\" in rebase.json.`));\n console.error(chalk.dim(` Declared: ${Object.keys(loaded.manifest.apps).join(\", \") || \"(none)\"}`));\n process.exit(1);\n }\n\n const link = readLink(projectRoot);\n // An app the backend bundle serves calls the API on its own origin, so the\n // right value is empty — wherever the project is linked, and whatever a\n // dev server once wrote down. A URL here is baked into the build and\n // follows the bundle into production.\n const sameOrigin = servedByBackend(loaded.manifest, appName);\n const apiUrl = sameOrigin ? \"\" : resolveApiUrl(projectRoot, link);\n\n const config = {\n app: appName,\n type: app.type,\n apiUrl: apiUrl ?? null,\n sameOrigin,\n project: link?.projectId ?? link?.slug ?? null\n };\n\n if (asJson) {\n console.log(JSON.stringify(config, null, 2));\n return;\n }\n\n if (sameOrigin) {\n console.log(chalk.bold(`# ${appName}`));\n console.log(\"\");\n console.log(\"VITE_API_URL=\");\n console.log(\"\");\n console.log(chalk.dim(`Empty on purpose: \\`rebase build\\` folds ${appName} into the backend bundle, so it`));\n console.log(chalk.dim(\"calls the API on the same origin it is served from, locally and deployed alike.\"));\n console.log(chalk.dim(\"(`rebase dev` points it at the dev backend by itself.)\"));\n return;\n }\n\n if (!apiUrl) {\n console.log(chalk.yellow(\"This checkout is not linked to a project yet.\"));\n // `rebase cloud link`, not `rebase link`. There has never been a\n // top-level `link` command — `cli.ts` dispatches `cloud`, and the link\n // lives inside that family — so this hint named something that exits 1\n // on the very screen that exists to tell you what to run next.\n console.log(chalk.dim(` Run ${chalk.cyan(\"rebase cloud link\")} (cloud) or ${chalk.cyan(\"rebase cloud link <url>\")} (self-hosted).`));\n console.log(\"\");\n }\n\n console.log(chalk.bold(`# ${appName}`));\n console.log(\"\");\n console.log(`VITE_API_URL=${apiUrl ?? \"http://localhost:3001\"}`);\n console.log(\"\");\n console.log(chalk.dim(\"Then, in the app:\"));\n console.log(chalk.dim(\" const rebase = createRebaseClient({ baseUrl: import.meta.env.VITE_API_URL });\"));\n}\n\n/**\n * Work out the API base URL for this checkout.\n *\n * Prefers an explicit link, then the dev server's own record of where it bound.\n * The dev port is chosen dynamically, so a hardcoded default would be wrong on\n * any machine running more than one project.\n */\nfunction resolveApiUrl(projectRoot: string, link: ReturnType<typeof readLink>): string | undefined {\n if (link?.apiUrl) return link.apiUrl;\n\n const statePath = path.join(projectRoot, \".rebase\", \"state.json\");\n if (fs.existsSync(statePath)) {\n try {\n const state = JSON.parse(fs.readFileSync(statePath, \"utf8\")) as { baseUrl?: string; pid?: number };\n // Only a dev server that is still running: the file outlives the\n // process, and a port nothing listens on is not an address.\n if (state.baseUrl && typeof state.pid === \"number\" && isRunning(state.pid)) return state.baseUrl;\n } catch {\n // Stale or partially written state file: fall through.\n }\n }\n\n return undefined;\n}\n\n/** Signal 0 checks a process exists without touching it; EPERM means it does, as someone else. */\nfunction isRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * Whether `rebase build` folds this static app into the backend bundle, which\n * then serves it on the API's own origin: a managed backend, and an app with\n * built output to fold. The same predicate the build folds by.\n */\nexport function servedByBackend(manifest: ReturnType<typeof loadManifest>[\"manifest\"], appName: string): boolean {\n const backend = findBackendApp(manifest);\n if (!backend || backend.app.type !== \"backend\" || backend.app.runtime === \"custom\") return false;\n return foldableApps(manifest).apps.some(app => app.name === appName);\n}\n\nfunction loadManifestOrExit(projectRoot: string, asJson = false): ReturnType<typeof loadManifest> {\n try {\n return loadManifest(projectRoot);\n } catch (err) {\n if (err instanceof ManifestError) {\n // A caller that asked for JSON gets one on this exit too. It used\n // to get the human bullet list on stderr and an empty stdout —\n // `apps list --json` against the one manifest a caller most needs\n // to be told about.\n if (asJson) {\n failAsJson(err.message, \"manifest_invalid\", \"Fix rebase.json, then run this again.\",\n err.issues.map(issue => ({ path: issue.path, message: issue.message })));\n }\n console.error(chalk.red(`✗ ${err.message}`));\n for (const issue of err.issues) {\n console.error(chalk.red(` ${issue.path ? `${issue.path}: ` : \"\"}${issue.message}`));\n }\n process.exit(1);\n }\n throw err;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ import arg from "arg";
2
+ //#region src/utils/args.ts
3
+ /**
4
+ * Argument parsing for the commands that take positional arguments.
5
+ *
6
+ * Every command in the small group used to parse its own line the same way:
7
+ * `arg(spec, { argv: rawArgs.slice(4), permissive: true })`, then read `_[0]`
8
+ * and `_[1]`. Both halves of that are wrong in a way that costs data.
9
+ *
10
+ * - **`permissive: true` turns an unknown flag into a positional.** `arg`
11
+ * pushes an undeclared flag into `_` as a bare token, so `_[1]` is whatever
12
+ * came second on the line, flag or not. `rebase auth reset-password
13
+ * bob@example.com --debug` set Bob's password to the literal `--debug` — and
14
+ * `--debug` is what `bin/rebase.js` prints after *every* failure as the thing
15
+ * to re-run with, so the single most likely next keystroke after a failed
16
+ * reset was the one that reset the account to a two-word string.
17
+ * - **`slice(4)` assumes the command words are at fixed indices.** They are
18
+ * not: a flag before the command shifts everything, so `rebase --debug auth
19
+ * reset-password bob@example.com NewPass1!` read the email as
20
+ * `reset-password` and the password as `bob@example.com`.
21
+ *
22
+ * So: parse the *whole* line — `rawArgs` is `process.argv` — against a spec
23
+ * strictly, with no permissive mode. `arg` then consumes every flag wherever it
24
+ * appears and rejects the ones nobody declared, which leaves `_` holding the
25
+ * command words followed by the real positionals, in order and at a known
26
+ * offset. An unrecognised flag becomes an error naming the command's help,
27
+ * which is the only safe answer: the alternative is guessing that it was meant
28
+ * as a value.
29
+ *
30
+ * `commands/cloud/index.ts` resolves its positionals against its own spec for
31
+ * the same reason; this is that idea for the commands whose positionals are
32
+ * credentials rather than resource names.
33
+ */
34
+ /**
35
+ * Flags accepted on top of whatever a command declares.
36
+ *
37
+ * `--debug` is read by `bin/rebase.js` off `process.argv` and never by a
38
+ * command, but it has to be *declared* somewhere or strict parsing rejects the
39
+ * exact flag the CLI tells people to add. `--help`/`-h` are answered by each
40
+ * command's dispatcher before any work happens.
41
+ */
42
+ var GLOBAL_COMMAND_FLAGS = {
43
+ "--debug": Boolean,
44
+ "--help": Boolean,
45
+ "-h": "--help"
46
+ };
47
+ /** Did the line ask for help? Answered before dispatch, never by a handler. */
48
+ function wantsHelp(rawArgs) {
49
+ return rawArgs.includes("--help") || rawArgs.includes("-h");
50
+ }
51
+ /**
52
+ * The command line was wrong — nothing ran, and there is no stack to want.
53
+ *
54
+ * `bin/rebase.js` ends every failure with "Re-run with --debug for the stack
55
+ * trace.", which is right when something broke inside a command and absurd for
56
+ * a typo: the stack points at `arg` and this file, neither of which the person
57
+ * who mistyped `--ouput` has any interest in. Worse, `--debug` is a flag, so
58
+ * the suggested next command is *another* command line — and the one thing we
59
+ * have just established is that the command line is what went wrong.
60
+ *
61
+ * Marked with a property rather than left to `instanceof`, because the reader
62
+ * is `bin/rebase.js`: it imports the bundle, so the class object it would test
63
+ * against is not the one this file compiled to.
64
+ */
65
+ var UsageError = class extends Error {
66
+ isUsageError = true;
67
+ constructor(message) {
68
+ super(message);
69
+ this.name = "UsageError";
70
+ }
71
+ };
72
+ /**
73
+ * Resolve a command's flags and positionals from the full `process.argv`.
74
+ *
75
+ * `commandWords` is how many words name the command itself — 2 for
76
+ * `auth reset-password`, 1 for `start` — and is applied to the *parsed*
77
+ * positionals rather than to `argv`, so a flag placed before the command no
78
+ * longer shifts them.
79
+ *
80
+ * `command` names the command in error messages, e.g. `auth reset-password`.
81
+ *
82
+ * Throws on an unknown flag, on a positional that looks like a flag, and on
83
+ * more positionals than the command takes. `bin/rebase.js` turns each into a
84
+ * one-line `✗ …` and exit 1.
85
+ */
86
+ function parseCommandArgs({ spec, rawArgs, commandWords, command, maxPositionals }) {
87
+ let parsed;
88
+ try {
89
+ parsed = arg({
90
+ ...GLOBAL_COMMAND_FLAGS,
91
+ ...spec
92
+ }, { argv: rawArgs.slice(2) });
93
+ } catch (err) {
94
+ if (err instanceof Error && err.code === "ARG_UNKNOWN_OPTION") throw new UsageError(`${err.message} — run \`rebase ${command} --help\` for the options it takes.`);
95
+ throw err;
96
+ }
97
+ const positionals = parsed._.slice(commandWords);
98
+ for (const value of positionals) if (value.startsWith("-")) throw new UsageError(`\`${value}\` looks like an option, not a value — pass it with an explicit flag (\`rebase ${command} --help\`).`);
99
+ if (maxPositionals !== void 0 && positionals.length > maxPositionals) throw new UsageError(`rebase ${command} takes ${maxPositionals} argument${maxPositionals === 1 ? "" : "s"}, got ${positionals.length}: ${positionals.join(" ")}`);
100
+ return {
101
+ flags: parsed,
102
+ positionals,
103
+ help: Boolean(parsed["--help"])
104
+ };
105
+ }
106
+ //#endregion
107
+ export { parseCommandArgs as n, wantsHelp as r, UsageError as t };
108
+
109
+ //# sourceMappingURL=args-BnmsEXvu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args-BnmsEXvu.js","names":[],"sources":["../src/utils/args.ts"],"sourcesContent":["/**\n * Argument parsing for the commands that take positional arguments.\n *\n * Every command in the small group used to parse its own line the same way:\n * `arg(spec, { argv: rawArgs.slice(4), permissive: true })`, then read `_[0]`\n * and `_[1]`. Both halves of that are wrong in a way that costs data.\n *\n * - **`permissive: true` turns an unknown flag into a positional.** `arg`\n * pushes an undeclared flag into `_` as a bare token, so `_[1]` is whatever\n * came second on the line, flag or not. `rebase auth reset-password\n * bob@example.com --debug` set Bob's password to the literal `--debug` — and\n * `--debug` is what `bin/rebase.js` prints after *every* failure as the thing\n * to re-run with, so the single most likely next keystroke after a failed\n * reset was the one that reset the account to a two-word string.\n * - **`slice(4)` assumes the command words are at fixed indices.** They are\n * not: a flag before the command shifts everything, so `rebase --debug auth\n * reset-password bob@example.com NewPass1!` read the email as\n * `reset-password` and the password as `bob@example.com`.\n *\n * So: parse the *whole* line — `rawArgs` is `process.argv` — against a spec\n * strictly, with no permissive mode. `arg` then consumes every flag wherever it\n * appears and rejects the ones nobody declared, which leaves `_` holding the\n * command words followed by the real positionals, in order and at a known\n * offset. An unrecognised flag becomes an error naming the command's help,\n * which is the only safe answer: the alternative is guessing that it was meant\n * as a value.\n *\n * `commands/cloud/index.ts` resolves its positionals against its own spec for\n * the same reason; this is that idea for the commands whose positionals are\n * credentials rather than resource names.\n */\nimport arg from \"arg\";\n\n/**\n * Flags accepted on top of whatever a command declares.\n *\n * `--debug` is read by `bin/rebase.js` off `process.argv` and never by a\n * command, but it has to be *declared* somewhere or strict parsing rejects the\n * exact flag the CLI tells people to add. `--help`/`-h` are answered by each\n * command's dispatcher before any work happens.\n */\nexport const GLOBAL_COMMAND_FLAGS = {\n \"--debug\": Boolean,\n \"--help\": Boolean,\n \"-h\": \"--help\"\n} as const;\n\nexport interface ParsedCommand<S extends arg.Spec> {\n /** The declared flags, as `arg` resolved them. */\n flags: arg.Result<S>;\n /** What is left after the command words — never a flag. */\n positionals: string[];\n /** `--help` or `-h` appeared anywhere on the line. */\n help: boolean;\n}\n\n/** Did the line ask for help? Answered before dispatch, never by a handler. */\nexport function wantsHelp(rawArgs: string[]): boolean {\n return rawArgs.includes(\"--help\") || rawArgs.includes(\"-h\");\n}\n\n/**\n * The command line was wrong — nothing ran, and there is no stack to want.\n *\n * `bin/rebase.js` ends every failure with \"Re-run with --debug for the stack\n * trace.\", which is right when something broke inside a command and absurd for\n * a typo: the stack points at `arg` and this file, neither of which the person\n * who mistyped `--ouput` has any interest in. Worse, `--debug` is a flag, so\n * the suggested next command is *another* command line — and the one thing we\n * have just established is that the command line is what went wrong.\n *\n * Marked with a property rather than left to `instanceof`, because the reader\n * is `bin/rebase.js`: it imports the bundle, so the class object it would test\n * against is not the one this file compiled to.\n */\nexport class UsageError extends Error {\n readonly isUsageError = true;\n\n constructor(message: string) {\n super(message);\n this.name = \"UsageError\";\n }\n}\n\n/**\n * Resolve a command's flags and positionals from the full `process.argv`.\n *\n * `commandWords` is how many words name the command itself — 2 for\n * `auth reset-password`, 1 for `start` — and is applied to the *parsed*\n * positionals rather than to `argv`, so a flag placed before the command no\n * longer shifts them.\n *\n * `command` names the command in error messages, e.g. `auth reset-password`.\n *\n * Throws on an unknown flag, on a positional that looks like a flag, and on\n * more positionals than the command takes. `bin/rebase.js` turns each into a\n * one-line `✗ …` and exit 1.\n */\nexport function parseCommandArgs<S extends arg.Spec>({\n spec,\n rawArgs,\n commandWords,\n command,\n maxPositionals\n}: {\n spec: S;\n rawArgs: string[];\n commandWords: number;\n command: string;\n maxPositionals?: number;\n}): ParsedCommand<S> {\n let parsed: arg.Result<S> & { \"--help\"?: boolean };\n try {\n const merged = {\n ...GLOBAL_COMMAND_FLAGS,\n ...spec\n };\n parsed = arg(merged, { argv: rawArgs.slice(2) }) as arg.Result<S> & { \"--help\"?: boolean };\n } catch (err) {\n if (err instanceof Error && (err as arg.ArgError).code === \"ARG_UNKNOWN_OPTION\") {\n throw new UsageError(\n `${err.message} — run \\`rebase ${command} --help\\` for the options it takes.`\n );\n }\n throw err;\n }\n\n const positionals = parsed._.slice(commandWords);\n\n for (const value of positionals) {\n // Only reachable past a `--` separator or for a bare `-`, since anything\n // else beginning with `-` was either declared or already rejected above.\n // Still refused rather than accepted: a value that looks like a flag is\n // as likely to be a typo as an argument, and one of these positions is a\n // password.\n if (value.startsWith(\"-\")) {\n throw new UsageError(\n `\\`${value}\\` looks like an option, not a value — pass it with an explicit flag ` +\n `(\\`rebase ${command} --help\\`).`\n );\n }\n }\n\n if (maxPositionals !== undefined && positionals.length > maxPositionals) {\n throw new UsageError(\n `rebase ${command} takes ${maxPositionals} argument${maxPositionals === 1 ? \"\" : \"s\"}, ` +\n `got ${positionals.length}: ${positionals.join(\" \")}`\n );\n }\n\n return {\n flags: parsed,\n positionals,\n help: Boolean(parsed[\"--help\"])\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,uBAAuB;CAChC,WAAW;CACX,UAAU;CACV,MAAM;AACV;;AAYA,SAAgB,UAAU,SAA4B;CAClD,OAAO,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,IAAI;AAC9D;;;;;;;;;;;;;;;AAgBA,IAAa,aAAb,cAAgC,MAAM;CAClC,eAAwB;CAExB,YAAY,SAAiB;EACzB,MAAM,OAAO;EACb,KAAK,OAAO;CAChB;AACJ;;;;;;;;;;;;;;;AAgBA,SAAgB,iBAAqC,EACjD,MACA,SACA,cACA,SACA,kBAOiB;CACjB,IAAI;CACJ,IAAI;EAKA,SAAS,IAAI;GAHT,GAAG;GACH,GAAG;EAEM,GAAQ,EAAE,MAAM,QAAQ,MAAM,CAAC,EAAE,CAAC;CACnD,SAAS,KAAK;EACV,IAAI,eAAe,SAAU,IAAqB,SAAS,sBACvD,MAAM,IAAI,WACN,GAAG,IAAI,QAAQ,kBAAkB,QAAQ,oCAC7C;EAEJ,MAAM;CACV;CAEA,MAAM,cAAc,OAAO,EAAE,MAAM,YAAY;CAE/C,KAAK,MAAM,SAAS,aAMhB,IAAI,MAAM,WAAW,GAAG,GACpB,MAAM,IAAI,WACN,KAAK,MAAM,iFACE,QAAQ,YACzB;CAIR,IAAI,mBAAmB,KAAA,KAAa,YAAY,SAAS,gBACrD,MAAM,IAAI,WACN,UAAU,QAAQ,SAAS,eAAe,WAAW,mBAAmB,IAAI,KAAK,IAAI,QAC9E,YAAY,OAAO,IAAI,YAAY,KAAK,GAAG,GACtD;CAGJ,OAAO;EACH,OAAO;EACP;EACA,MAAM,QAAQ,OAAO,SAAS;CAClC;AACJ"}
@@ -0,0 +1,62 @@
1
+ import { o as findFreePort } from "./state-Do7ZJYkF.js";
2
+ import { o as managedUrl } from "./prepare-Btn9Ewbn.js";
3
+ import { loadExtensions } from "./daemon-entry-Da-D3rmH.js";
4
+ //#region src/dev-db/atlas-dev-database.ts
5
+ /**
6
+ * A second, throwaway PGlite for Atlas to plan against.
7
+ *
8
+ * Atlas computes a schema change by replaying the desired schema into an
9
+ * **empty** database and diffing. On a real server the driver makes one as
10
+ * `<db>_dev_diff`; PGlite serves exactly one database, so that `CREATE
11
+ * DATABASE` succeeds and creates nothing, and `rebase db push`, `generate` and
12
+ * `migrate` were refused on the managed database outright — which left it with
13
+ * no way to drop, rename or narrow a column: boot only ever adds.
14
+ *
15
+ * So the command that needs one starts one: in memory, in this process, for
16
+ * as long as the command runs. It shares nothing with the managed database's
17
+ * daemon (a separate instance, no data directory, a port of its own), so the
18
+ * project's data is never the thing Atlas fills and clears, and nothing is
19
+ * left behind — not a directory, not a process.
20
+ *
21
+ * Measured with Atlas 1.2.3 against PGlite 0.5.6: `schema apply` with this as
22
+ * `--dev-url` plans and applies a DROP COLUMN and a `varchar(200)` →
23
+ * `varchar(50)` narrowing on a PGlite target, and the dev database is empty
24
+ * again afterwards, so one instance serves every Atlas call of a command.
25
+ *
26
+ * It runs on this process's event loop. The driver runs as a child process,
27
+ * which is what keeps the loop free to serve it; a synchronous wait on that
28
+ * child would hang Atlas.
29
+ */
30
+ async function startAtlasDevDatabase() {
31
+ const { PGlite } = await import("@electric-sql/pglite");
32
+ const { PGLiteSocketServer } = await import("@electric-sql/pglite-socket");
33
+ const extensions = await loadExtensions();
34
+ const db = await PGlite.create({ extensions });
35
+ const port = await findFreePort();
36
+ const server = new PGLiteSocketServer({
37
+ db,
38
+ port,
39
+ host: "127.0.0.1",
40
+ maxConnections: 4
41
+ });
42
+ try {
43
+ await server.start();
44
+ } catch (err) {
45
+ await db.close().catch(() => void 0);
46
+ throw err;
47
+ }
48
+ let stopped = false;
49
+ return {
50
+ url: managedUrl(port),
51
+ async stop() {
52
+ if (stopped) return;
53
+ stopped = true;
54
+ await server.stop().catch(() => void 0);
55
+ await db.close().catch(() => void 0);
56
+ }
57
+ };
58
+ }
59
+ //#endregion
60
+ export { startAtlasDevDatabase };
61
+
62
+ //# sourceMappingURL=atlas-dev-database-DTMuEScS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atlas-dev-database-DTMuEScS.js","names":[],"sources":["../src/dev-db/atlas-dev-database.ts"],"sourcesContent":["/**\n * A second, throwaway PGlite for Atlas to plan against.\n *\n * Atlas computes a schema change by replaying the desired schema into an\n * **empty** database and diffing. On a real server the driver makes one as\n * `<db>_dev_diff`; PGlite serves exactly one database, so that `CREATE\n * DATABASE` succeeds and creates nothing, and `rebase db push`, `generate` and\n * `migrate` were refused on the managed database outright — which left it with\n * no way to drop, rename or narrow a column: boot only ever adds.\n *\n * So the command that needs one starts one: in memory, in this process, for\n * as long as the command runs. It shares nothing with the managed database's\n * daemon (a separate instance, no data directory, a port of its own), so the\n * project's data is never the thing Atlas fills and clears, and nothing is\n * left behind — not a directory, not a process.\n *\n * Measured with Atlas 1.2.3 against PGlite 0.5.6: `schema apply` with this as\n * `--dev-url` plans and applies a DROP COLUMN and a `varchar(200)` →\n * `varchar(50)` narrowing on a PGlite target, and the dev database is empty\n * again afterwards, so one instance serves every Atlas call of a command.\n *\n * It runs on this process's event loop. The driver runs as a child process,\n * which is what keeps the loop free to serve it; a synchronous wait on that\n * child would hang Atlas.\n */\n\nimport { loadExtensions } from \"./daemon-entry\";\nimport { MANAGED_SERVER_MAX_CONNECTIONS } from \"./constraints\";\nimport { managedUrl } from \"./daemon\";\nimport { findFreePort } from \"./state\";\n\nexport interface AtlasDevDatabase {\n /** Connection string for Atlas's `--dev-url`. */\n url: string;\n /** Stop serving and drop the instance. Safe to call twice. */\n stop(): Promise<void>;\n}\n\nexport async function startAtlasDevDatabase(): Promise<AtlasDevDatabase> {\n const { PGlite } = (await import(\"@electric-sql/pglite\")) as {\n PGlite: { create(options: unknown): Promise<unknown> };\n };\n const { PGLiteSocketServer } = (await import(\"@electric-sql/pglite-socket\")) as {\n PGLiteSocketServer: new (options: unknown) => { start(): Promise<void>; stop(): Promise<void> };\n };\n\n // The same extension bundles as the managed database: a schema that\n // creates `pg_trgm` or `vector` must replay here exactly as it applies\n // there, or Atlas fails on the replay rather than the apply.\n const extensions = await loadExtensions();\n // No `dataDir`: in memory, gone with the process.\n const db = (await PGlite.create({ extensions })) as { close(): Promise<void> };\n const port = await findFreePort();\n const server = new PGLiteSocketServer({\n db,\n port,\n host: \"127.0.0.1\",\n maxConnections: MANAGED_SERVER_MAX_CONNECTIONS\n });\n try {\n await server.start();\n } catch (err) {\n await db.close().catch(() => undefined);\n throw err;\n }\n\n let stopped = false;\n return {\n url: managedUrl(port),\n async stop() {\n if (stopped) return;\n stopped = true;\n await server.stop().catch(() => undefined);\n await db.close().catch(() => undefined);\n }\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,eAAsB,wBAAmD;CACrE,MAAM,EAAE,WAAY,MAAM,OAAO;CAGjC,MAAM,EAAE,uBAAwB,MAAM,OAAO;CAO7C,MAAM,aAAa,MAAM,eAAe;CAExC,MAAM,KAAM,MAAM,OAAO,OAAO,EAAE,WAAW,CAAC;CAC9C,MAAM,OAAO,MAAM,aAAa;CAChC,MAAM,SAAS,IAAI,mBAAmB;EAClC;EACA;EACA,MAAM;EACN,gBAAA;CACJ,CAAC;CACD,IAAI;EACA,MAAM,OAAO,MAAM;CACvB,SAAS,KAAK;EACV,MAAM,GAAG,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;EACtC,MAAM;CACV;CAEA,IAAI,UAAU;CACd,OAAO;EACH,KAAK,WAAW,IAAI;EACpB,MAAM,OAAO;GACT,IAAI,SAAS;GACb,UAAU;GACV,MAAM,OAAO,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;GACzC,MAAM,GAAG,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1C;CACJ;AACJ"}