@rebasepro/cli 0.25.0 → 0.26.0
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.
- package/README.md +2 -1
- package/bin/rebase.js +143 -4
- package/dist/{agent-setup-B5AKHOgt.js → agent-setup-D9mHRZ5R.js} +125 -3
- package/dist/agent-setup-D9mHRZ5R.js.map +1 -0
- package/dist/{api-keys-Tm7zvAPe.js → api-keys-CyJ26KEJ.js} +41 -10
- package/dist/api-keys-CyJ26KEJ.js.map +1 -0
- package/dist/{apps-BsU_ILbP.js → apps-CnLDV5b6.js} +6 -7
- package/dist/{apps-BsU_ILbP.js.map → apps-CnLDV5b6.js.map} +1 -1
- package/dist/{atlas-dev-database-OWtqnG7W.js → atlas-dev-database-BODqdCWt.js} +4 -4
- package/dist/{atlas-dev-database-OWtqnG7W.js.map → atlas-dev-database-BODqdCWt.js.map} +1 -1
- package/dist/{auth-Vl2hFKXP.js → auth-dII2jCO1.js} +10 -8
- package/dist/auth-dII2jCO1.js.map +1 -0
- package/dist/{branch-pointer-9DnwkFJJ.js → branch-pointer-BQUF6lYa.js} +1 -1
- package/dist/{build-BBgT8EJZ.js → build-Cza7ZQrp.js} +6 -7
- package/dist/{build-BBgT8EJZ.js.map → build-Cza7ZQrp.js.map} +1 -1
- package/dist/{bundle-DtCCCr4w.js → bundle-C6yEtMJ-.js} +53 -5
- package/dist/bundle-C6yEtMJ-.js.map +1 -0
- package/dist/bundle.d.ts +14 -0
- package/dist/{cloud-BpH0_bmV.js → cloud-BdnmqQaZ.js} +8528 -4342
- package/dist/cloud-BdnmqQaZ.js.map +1 -0
- package/dist/collections-dir-DlvDhime.js +69 -0
- package/dist/collections-dir-DlvDhime.js.map +1 -0
- package/dist/commands/agent-setup.d.ts +58 -0
- package/dist/commands/api-keys.d.ts +13 -0
- package/dist/commands/cloud/activity.d.ts +25 -0
- package/dist/commands/cloud/app-key.d.ts +18 -0
- package/dist/commands/cloud/auth.d.ts +1 -0
- package/dist/commands/cloud/billing-invoices.d.ts +39 -0
- package/dist/commands/cloud/claim.d.ts +7 -0
- package/dist/commands/cloud/context.d.ts +115 -6
- package/dist/commands/cloud/deploy-summary.d.ts +162 -0
- package/dist/commands/cloud/deploy.d.ts +64 -0
- package/dist/commands/cloud/env.d.ts +24 -0
- package/dist/commands/cloud/index.d.ts +13 -1
- package/dist/commands/cloud/init.d.ts +143 -0
- package/dist/commands/cloud/login-flow.d.ts +51 -0
- package/dist/commands/cloud/notifications.d.ts +28 -0
- package/dist/commands/cloud/orgs.d.ts +13 -0
- package/dist/commands/cloud/previews.d.ts +123 -0
- package/dist/commands/cloud/resources.d.ts +68 -14
- package/dist/commands/cloud/runtime-logs.d.ts +176 -0
- package/dist/commands/cloud/service-key.d.ts +15 -0
- package/dist/commands/cloud/token-capabilities.d.ts +61 -8
- package/dist/commands/cloud/tokens.d.ts +18 -3
- package/dist/commands/cloud/usage.d.ts +63 -0
- package/dist/commands/dev.d.ts +22 -0
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/generate-view.d.ts +94 -0
- package/dist/commands/generate_sdk.d.ts +19 -2
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/skills.d.ts +4 -3
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/storage.d.ts +4 -0
- package/dist/commands/upgrade.d.ts +12 -0
- package/dist/commands/verify.d.ts +96 -0
- package/dist/{consent-ClRHmcxf.js → consent-BD7F29T3.js} +2 -2
- package/dist/{consent-ClRHmcxf.js.map → consent-BD7F29T3.js.map} +1 -1
- package/dist/{console-CEGm0XNc.js → console-BXB6-8GT.js} +12 -6
- package/dist/console-BXB6-8GT.js.map +1 -0
- package/dist/{context-CyflUrKg.js → context-GUxkZm-S.js} +482 -26
- package/dist/context-GUxkZm-S.js.map +1 -0
- package/dist/{daemon-CknkDjd6.js → daemon-Cp7oNXth.js} +160 -5
- package/dist/daemon-Cp7oNXth.js.map +1 -0
- package/dist/{daemon-entry-CbLRrgzy.js → daemon-entry-zOC1revO.js} +6 -3
- package/dist/daemon-entry-zOC1revO.js.map +1 -0
- package/dist/{db-CRNpA5mH.js → db-KzlqddGD.js} +101 -54
- package/dist/db-KzlqddGD.js.map +1 -0
- package/dist/{derive-CsoFGAnK.js → derive-ae9UOoOB.js} +2 -2
- package/dist/{derive-CsoFGAnK.js.map → derive-ae9UOoOB.js.map} +1 -1
- package/dist/{dev-C0pbMmhS.js → dev-DTqVMgB3.js} +231 -44
- package/dist/dev-DTqVMgB3.js.map +1 -0
- package/dist/dev-db/daemon.d.ts +41 -0
- package/dist/dev-db/pull.d.ts +33 -5
- package/dist/dev-db/state.d.ts +9 -0
- package/dist/{dev-preflight-unHpiYO1.js → dev-preflight-Cxv3TiD1.js} +73 -27
- package/dist/dev-preflight-Cxv3TiD1.js.map +1 -0
- package/dist/{dev-server-B1UYifZJ.js → dev-server-OJsUGZEB.js} +14 -3
- package/dist/dev-server-OJsUGZEB.js.map +1 -0
- package/dist/{doctor-CATRdWm6.js → doctor-BRWOlqeG.js} +14 -12
- package/dist/doctor-BRWOlqeG.js.map +1 -0
- package/dist/{eject-DuasTr-F.js → eject-DABcDnPN.js} +3 -4
- package/dist/{eject-DuasTr-F.js.map → eject-DABcDnPN.js.map} +1 -1
- package/dist/{fold-static-hDHtDfTq.js → fold-static-BnAK-anQ.js} +3 -3
- package/dist/{fold-static-hDHtDfTq.js.map → fold-static-BnAK-anQ.js.map} +1 -1
- package/dist/generate-view-IFwCADvb.js +662 -0
- package/dist/generate-view-IFwCADvb.js.map +1 -0
- package/dist/{generate_sdk-Cvg5jjJF.js → generate_sdk-BvcWvoUh.js} +49 -13
- package/dist/generate_sdk-BvcWvoUh.js.map +1 -0
- package/dist/index.es.js +58 -40
- package/dist/index.es.js.map +1 -1
- package/dist/{init-BWAwHPtz.js → init-CaU6GhwI.js} +50 -62
- package/dist/init-CaU6GhwI.js.map +1 -0
- package/dist/invoked-command-CG_rIa_o.js +55 -0
- package/dist/invoked-command-CG_rIa_o.js.map +1 -0
- package/dist/last-dev-database-DpW5dfoX.js +2 -0
- package/dist/{manifest-DRp0UVTj.js → manifest-BtzDy7KQ.js} +36 -3
- package/dist/{manifest-DRp0UVTj.js.map → manifest-BtzDy7KQ.js.map} +1 -1
- package/dist/{normalize-imports-BoBVh5tU.js → normalize-imports-D0zXlM6g.js} +3 -3
- package/dist/{normalize-imports-BoBVh5tU.js.map → normalize-imports-D0zXlM6g.js.map} +1 -1
- package/dist/{path-flags-BFgG9V6y.js → path-flags-DNvtEi2-.js} +5 -4
- package/dist/path-flags-DNvtEi2-.js.map +1 -0
- package/dist/{prepare-DdnU70z8.js → prepare-CTw9NEkh.js} +5 -4
- package/dist/{prepare-DdnU70z8.js.map → prepare-CTw9NEkh.js.map} +1 -1
- package/dist/project-CasK56vN.js +701 -0
- package/dist/project-CasK56vN.js.map +1 -0
- package/dist/{pull-C3PXduzl.js → pull-DDMpsZ5r.js} +131 -24
- package/dist/pull-DDMpsZ5r.js.map +1 -0
- package/dist/refusal-ReeeGP8a.js +26 -0
- package/dist/refusal-ReeeGP8a.js.map +1 -0
- package/dist/resolve-D647F1LA.js +2 -0
- package/dist/{resources-BdNRDEAy.js → resources-CPSC5Kcu.js} +4 -5
- package/dist/{resources-BdNRDEAy.js.map → resources-CPSC5Kcu.js.map} +1 -1
- package/dist/{schema-B0-p6T1O.js → schema-BSXwZSiI.js} +9 -8
- package/dist/schema-BSXwZSiI.js.map +1 -0
- package/dist/{skills-DfnTeyRz.js → skills-BU2flMOy.js} +52 -8
- package/dist/skills-BU2flMOy.js.map +1 -0
- package/dist/{start-BmEZkS0n.js → start-mVb6upwY.js} +20 -7
- package/dist/start-mVb6upwY.js.map +1 -0
- package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
- package/dist/state-CYdBvnwA.js.map +1 -0
- package/dist/static-syntax-check.d.ts +64 -0
- package/dist/{status-BJ26yZOo.js → status-BREvtzJm.js} +8 -9
- package/dist/{status-BJ26yZOo.js.map → status-BREvtzJm.js.map} +1 -1
- package/dist/{storage-DKPUBTWG.js → storage-DtOXGflp.js} +159 -16
- package/dist/storage-DtOXGflp.js.map +1 -0
- package/dist/{telemetry-EMFRVRQi.js → telemetry-CgwJPVMO.js} +2 -2
- package/dist/{telemetry-EMFRVRQi.js.map → telemetry-CgwJPVMO.js.map} +1 -1
- package/dist/{telemetry-m9czTNGR.js → telemetry-DwK5RQJl.js} +4 -4
- package/dist/{telemetry-m9czTNGR.js.map → telemetry-DwK5RQJl.js.map} +1 -1
- package/dist/{upgrade-DjihWuZL.js → upgrade-B7sVwL8S.js} +26 -4
- package/dist/{upgrade-DjihWuZL.js.map → upgrade-B7sVwL8S.js.map} +1 -1
- package/dist/utils/args.d.ts +32 -3
- package/dist/utils/boot-retry.d.ts +41 -0
- package/dist/utils/collections-dir.d.ts +14 -0
- package/dist/utils/dev-preflight.d.ts +34 -1
- package/dist/utils/dev-server.d.ts +11 -0
- package/dist/utils/path-flags.d.ts +2 -1
- package/dist/utils/project.d.ts +5 -1
- package/dist/utils/tool-stdio.d.ts +1 -1
- package/dist/utils/unknown-command.d.ts +4 -0
- package/dist/verify-D7UsV_qe.js +730 -0
- package/dist/verify-D7UsV_qe.js.map +1 -0
- package/package.json +9 -7
- package/templates/eject/backend/src/index.ts +9 -1
- package/templates/generated-schemas/ecommerce.ts +3 -0
- package/templates/overlays/baas/ai-instructions.md +13 -0
- package/templates/resource-graphs/blank.json +25 -0
- package/templates/resource-graphs/blog.json +28 -0
- package/templates/resource-graphs/ecommerce.json +28 -0
- package/templates/resource-graphs/headless.json +22 -0
- package/templates/template/.claude/hooks/post-edit-collection.sh +99 -0
- package/templates/template/.claude/settings.json +17 -0
- package/templates/template/.env.example +15 -5
- package/templates/template/ai-instructions.md +21 -1
- package/templates/template/config/collections/presets/ecommerce/index.ts +23 -0
- package/templates/template/docker-compose.yml +4 -1
- package/templates/template/frontend/package.json +1 -0
- package/templates/template/frontend/src/App.tsx +10 -9
- package/templates/views/AppView.tsx.tmpl +138 -0
- package/templates/views/EntityView.tsx.tmpl +64 -0
- package/templates/views/index.ts.tmpl +8 -0
- package/dist/agent-setup-B5AKHOgt.js.map +0 -1
- package/dist/api-keys-Tm7zvAPe.js.map +0 -1
- package/dist/args-BX0YD14a.js +0 -266
- package/dist/args-BX0YD14a.js.map +0 -1
- package/dist/auth-Vl2hFKXP.js.map +0 -1
- package/dist/bundle-DtCCCr4w.js.map +0 -1
- package/dist/cloud-BpH0_bmV.js.map +0 -1
- package/dist/console-CEGm0XNc.js.map +0 -1
- package/dist/context-CyflUrKg.js.map +0 -1
- package/dist/daemon-CknkDjd6.js.map +0 -1
- package/dist/daemon-entry-CbLRrgzy.js.map +0 -1
- package/dist/db-CRNpA5mH.js.map +0 -1
- package/dist/dev-C0pbMmhS.js.map +0 -1
- package/dist/dev-preflight-unHpiYO1.js.map +0 -1
- package/dist/dev-server-B1UYifZJ.js.map +0 -1
- package/dist/doctor-CATRdWm6.js.map +0 -1
- package/dist/generate_sdk-Cvg5jjJF.js.map +0 -1
- package/dist/init-BWAwHPtz.js.map +0 -1
- package/dist/last-dev-database-c_dKz1S3.js +0 -2
- package/dist/path-flags-BFgG9V6y.js.map +0 -1
- package/dist/project-Wp2zoyeN.js +0 -349
- package/dist/project-Wp2zoyeN.js.map +0 -1
- package/dist/pull-C3PXduzl.js.map +0 -1
- package/dist/resolve-CNQjsatH.js +0 -2
- package/dist/schema-B0-p6T1O.js.map +0 -1
- package/dist/skills-DfnTeyRz.js.map +0 -1
- package/dist/start-BmEZkS0n.js.map +0 -1
- package/dist/state-CCB-FAQ9.js.map +0 -1
- package/dist/storage-DKPUBTWG.js.map +0 -1
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { i as recordEvent } from "./telemetry-
|
|
1
|
+
import { i as recordEvent } from "./telemetry-CgwJPVMO.js";
|
|
2
2
|
import { n as getPMCommands, t as detectPackageManager } from "./package-manager-DSEOwTqM.js";
|
|
3
|
-
import { a as findBackendDir, g as resolveTsx, h as resolvePluginCliScript, l as getActiveBackendPlugin, n as dependenciesNotInstalled, o as findEnvFile, p as requireProjectRoot, s as findFrontendDir, v as validateTsxInstallation } from "./project-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { C as switchOn, a as findBackendDir, b as UsageError, g as resolveTsx, h as resolvePluginCliScript, l as getActiveBackendPlugin, n as dependenciesNotInstalled, o as findEnvFile, p as requireProjectRoot, s as findFrontendDir, v as validateTsxInstallation, w as wantsHelp, x as parseCommandArgs } from "./project-CasK56vN.js";
|
|
4
|
+
import { d as findBackendApp, f as formatAppAddress, g as resolveBackendPaths, l as cmsMountOf, p as loadManifest, v as staticAppAddress } from "./manifest-BtzDy7KQ.js";
|
|
5
|
+
import { r as getProjectPort, t as DEV_BACKEND_URL_ENV } from "./dev-server-OJsUGZEB.js";
|
|
6
|
+
import { collectionsDirArgs, resolveCollectionsDir, resolveConfigDir } from "./collections-dir-DlvDhime.js";
|
|
7
|
+
import { t as Refusal } from "./refusal-ReeeGP8a.js";
|
|
8
|
+
import { i as ensureDevDatabase, o as probeTcp } from "./dev-preflight-Cxv3TiD1.js";
|
|
8
9
|
import { t as MANAGED_IDLE_TIMEOUT_MS } from "./constraints-CtiylsGf.js";
|
|
9
|
-
import { a as resolveCliEntry, o as resolveSpawn } from "./daemon-
|
|
10
|
-
import { DEV_DATABASE_KIND_ENV, i as lastDevDatabaseNotice, managedNotices, prepareDatabaseEnv, resolveProjectDatabase, s as recordLastDevDatabase } from "./prepare-
|
|
11
|
-
import { runDriverDbCommand, runDriverSchemaCommand } from "./db-
|
|
10
|
+
import { a as resolveCliEntry, o as resolveSpawn } from "./daemon-Cp7oNXth.js";
|
|
11
|
+
import { DEV_DATABASE_KIND_ENV, i as lastDevDatabaseNotice, managedNotices, prepareDatabaseEnv, resolveProjectDatabase, s as recordLastDevDatabase } from "./prepare-CTw9NEkh.js";
|
|
12
|
+
import { runDriverDbCommand, runDriverSchemaCommand } from "./db-KzlqddGD.js";
|
|
12
13
|
import { t as affectsSqlSchema } from "./collection-drift-BKj_BoMq.js";
|
|
13
14
|
import chalk from "chalk";
|
|
14
15
|
import fs from "fs";
|
|
@@ -20,6 +21,80 @@ import dotenv from "dotenv";
|
|
|
20
21
|
import { DEFAULT_RESOURCE_KEY, parseEnvBoolean } from "@rebasepro/types";
|
|
21
22
|
import { execa, execaCommandSync } from "execa";
|
|
22
23
|
import { StringDecoder } from "string_decoder";
|
|
24
|
+
//#region src/utils/boot-retry.ts
|
|
25
|
+
/**
|
|
26
|
+
* A backend boot that lost its database part-way, which booting again fixes.
|
|
27
|
+
*
|
|
28
|
+
* `rebase db branch create --force` closes the database it copies: it ends
|
|
29
|
+
* every connection to it and refuses new ones until the copy is done. A
|
|
30
|
+
* backend booting at that moment failed with `Failed to start the Rebase
|
|
31
|
+
* runtime … terminating connection due to administrator command (57P01)`, and
|
|
32
|
+
* `rebase dev` then said "Fix the error above; the watcher restarts it on the
|
|
33
|
+
* next change", about an error nobody could fix and that the next boot would
|
|
34
|
+
* not have. The same holds for a database that is restarting.
|
|
35
|
+
*
|
|
36
|
+
* This reads the backend's output and says when a failed boot is worth another
|
|
37
|
+
* try, and after how long: a few tries, each waiting twice as long as the one
|
|
38
|
+
* before, and none once the backend has failed for a reason of its own.
|
|
39
|
+
*/
|
|
40
|
+
/** The sentence that starts a boot failure, as `reportBootFailure` in `@rebasepro/server` writes it. */
|
|
41
|
+
var BOOT_FAILED = /Failed to start the Rebase runtime/;
|
|
42
|
+
/**
|
|
43
|
+
* Why a boot failed that a later boot does not, by what PostgreSQL said:
|
|
44
|
+
* the server ended the connection (57P01 `pg_terminate_backend`, 57P02, 57P03
|
|
45
|
+
* a server starting or stopping), or the database is closed to new
|
|
46
|
+
* connections (55000, what a forced branch create does while it copies).
|
|
47
|
+
* A connection the server ended while it sat idle is reported by `pg` on the
|
|
48
|
+
* next query, in its own words and with no code: "Client has encountered a
|
|
49
|
+
* connection error and is not queryable".
|
|
50
|
+
*/
|
|
51
|
+
var PASSING_CAUSES = [
|
|
52
|
+
/terminating connection due to administrator command/i,
|
|
53
|
+
/Client has encountered a connection error and is not queryable/i,
|
|
54
|
+
/\(57P0[123]\)/,
|
|
55
|
+
/is not currently accepting connections/i,
|
|
56
|
+
/the database system is (?:starting up|shutting down|in recovery mode)/i
|
|
57
|
+
];
|
|
58
|
+
var BootRetry = class {
|
|
59
|
+
maxAttempts;
|
|
60
|
+
firstDelayMs;
|
|
61
|
+
failing = false;
|
|
62
|
+
planned = false;
|
|
63
|
+
attempts = 0;
|
|
64
|
+
constructor(maxAttempts = 3, firstDelayMs = 1e3) {
|
|
65
|
+
this.maxAttempts = maxAttempts;
|
|
66
|
+
this.firstDelayMs = firstDelayMs;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read one line of the backend's output, colour removed. Returns a plan
|
|
70
|
+
* the first time a failing boot names a passing cause, and null otherwise,
|
|
71
|
+
* including once the tries are spent.
|
|
72
|
+
*/
|
|
73
|
+
line(text) {
|
|
74
|
+
if (BOOT_FAILED.test(text)) {
|
|
75
|
+
this.failing = true;
|
|
76
|
+
this.planned = false;
|
|
77
|
+
}
|
|
78
|
+
if (!this.failing || this.planned) return null;
|
|
79
|
+
if (!PASSING_CAUSES.some((cause) => cause.test(text))) return null;
|
|
80
|
+
this.planned = true;
|
|
81
|
+
if (this.attempts >= this.maxAttempts) return null;
|
|
82
|
+
this.attempts += 1;
|
|
83
|
+
return {
|
|
84
|
+
attempt: this.attempts,
|
|
85
|
+
of: this.maxAttempts,
|
|
86
|
+
delayMs: this.firstDelayMs * 2 ** (this.attempts - 1),
|
|
87
|
+
reason: text.trim()
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** The backend is serving: a later failure is a new one, with every try left. */
|
|
91
|
+
up() {
|
|
92
|
+
this.failing = false;
|
|
93
|
+
this.planned = false;
|
|
94
|
+
this.attempts = 0;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
23
98
|
//#region src/commands/dev.ts
|
|
24
99
|
/**
|
|
25
100
|
* CLI command: rebase dev
|
|
@@ -225,12 +300,53 @@ function devRuntimeEnv(projectRoot) {
|
|
|
225
300
|
*/
|
|
226
301
|
function devWatchIncludes(projectRoot, paths) {
|
|
227
302
|
const dirs = [paths.REBASE_DEV_FUNCTIONS, paths.REBASE_DEV_CRONS].filter((entry) => Boolean(entry)).map((entry) => path.resolve(projectRoot, entry));
|
|
228
|
-
dirs.push(path.join(projectRoot,
|
|
303
|
+
dirs.push(path.join(projectRoot, resolveConfigDir(projectRoot)));
|
|
229
304
|
return dirs;
|
|
230
305
|
}
|
|
231
306
|
/** Where dev watches the collections it regenerates the schema and SDK from. */
|
|
232
307
|
function devCollectionsDir(projectRoot) {
|
|
233
|
-
return
|
|
308
|
+
return resolveCollectionsDir(projectRoot);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Call `onAppear` once, when `target` exists, and return what stops waiting.
|
|
312
|
+
*
|
|
313
|
+
* Watches the nearest directory above `target` that exists (no higher than
|
|
314
|
+
* `root`), and follows the path down as each part of it appears — `fs.watch`
|
|
315
|
+
* cannot watch a directory that is not there yet. A headless project has no
|
|
316
|
+
* `config/collections` until `rebase schema introspect` writes one, and dev
|
|
317
|
+
* watched it only when it was there at start: the backend kept serving the
|
|
318
|
+
* API it derived from the database, and edits to the new files did nothing,
|
|
319
|
+
* until dev was restarted by hand.
|
|
320
|
+
*/
|
|
321
|
+
function whenDirectoryAppears(target, root, onAppear) {
|
|
322
|
+
let watcher = null;
|
|
323
|
+
let watching = null;
|
|
324
|
+
let done = false;
|
|
325
|
+
const stop = () => {
|
|
326
|
+
done = true;
|
|
327
|
+
watcher?.close();
|
|
328
|
+
watcher = null;
|
|
329
|
+
};
|
|
330
|
+
const arm = () => {
|
|
331
|
+
if (done) return;
|
|
332
|
+
if (fs.existsSync(target)) {
|
|
333
|
+
stop();
|
|
334
|
+
onAppear();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
let dir = path.dirname(target);
|
|
338
|
+
while (!fs.existsSync(dir) && dir !== root && path.dirname(dir) !== dir) dir = path.dirname(dir);
|
|
339
|
+
if (dir === watching || !fs.existsSync(dir)) return;
|
|
340
|
+
watcher?.close();
|
|
341
|
+
watching = dir;
|
|
342
|
+
try {
|
|
343
|
+
watcher = fs.watch(dir, () => arm());
|
|
344
|
+
} catch {
|
|
345
|
+
watcher = null;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
arm();
|
|
349
|
+
return stop;
|
|
234
350
|
}
|
|
235
351
|
/**
|
|
236
352
|
* The file dev writes to restart the backend, or `null` when tsx would not see it.
|
|
@@ -323,7 +439,7 @@ async function declaredAdditionalDatabases(projectRoot) {
|
|
|
323
439
|
try {
|
|
324
440
|
const backend = findBackendApp(loadManifest(projectRoot).manifest);
|
|
325
441
|
if (!backend) return [];
|
|
326
|
-
const { deriveResourceGraph, deriveOptionsFor } = await import("./derive-
|
|
442
|
+
const { deriveResourceGraph, deriveOptionsFor } = await import("./derive-ae9UOoOB.js").then((n) => n.i);
|
|
327
443
|
const { graph } = await deriveResourceGraph({
|
|
328
444
|
...deriveOptionsFor(projectRoot, backend.app),
|
|
329
445
|
cronsDir: void 0,
|
|
@@ -666,7 +782,7 @@ function readEnvVar(projectRoot, name) {
|
|
|
666
782
|
* mode serves whatever the database already has.
|
|
667
783
|
*/
|
|
668
784
|
function projectHasCollections(projectRoot) {
|
|
669
|
-
const collectionsDir =
|
|
785
|
+
const collectionsDir = devCollectionsDir(projectRoot);
|
|
670
786
|
return fs.existsSync(collectionsDir) && fs.readdirSync(collectionsDir).some((name) => /\.(ts|js|mts|mjs)$/.test(name) && !name.startsWith("index."));
|
|
671
787
|
}
|
|
672
788
|
/**
|
|
@@ -763,9 +879,13 @@ function needsStaleSchemaPreflight(generation) {
|
|
|
763
879
|
* hand, so it is captured, and on failure only the lines that say what went
|
|
764
880
|
* wrong are shown — not the stack under them. Like the schema, a failure never
|
|
765
881
|
* stops `dev`.
|
|
882
|
+
*
|
|
883
|
+
* `backendPort` is where the backend is, or is about to be: the README's
|
|
884
|
+
* example names it. The first run is before the backend binds, so it is told
|
|
885
|
+
* rather than left to read `.rebase/state.json`.
|
|
766
886
|
*/
|
|
767
|
-
async function regenerateSdk(projectRoot) {
|
|
768
|
-
if (!projectHasCollections(projectRoot)) return;
|
|
887
|
+
async function regenerateSdk(projectRoot, backendPort) {
|
|
888
|
+
if (!projectHasCollections(projectRoot)) return "skipped";
|
|
769
889
|
const entry = resolveCliEntry();
|
|
770
890
|
const { execPath, prefixArgs } = resolveSpawn(entry);
|
|
771
891
|
try {
|
|
@@ -775,16 +895,43 @@ async function regenerateSdk(projectRoot) {
|
|
|
775
895
|
"generate-sdk"
|
|
776
896
|
], {
|
|
777
897
|
cwd: projectRoot,
|
|
778
|
-
all: true
|
|
898
|
+
all: true,
|
|
899
|
+
...backendPort !== null ? { env: { [DEV_BACKEND_URL_ENV]: `http://localhost:${backendPort}` } } : {}
|
|
779
900
|
});
|
|
901
|
+
return "generated";
|
|
780
902
|
} catch (error) {
|
|
781
903
|
const cause = (typeof error === "object" && error !== null && "all" in error && typeof error.all === "string" ? error.all : "").split("\n").filter((line) => line.trim() && !/^\s+at /.test(line)).slice(-6);
|
|
782
904
|
console.log(` ${chalk.yellow("⚠")} ${chalk.gray("Could not regenerate the SDK types in generated/sdk.")}`);
|
|
783
905
|
if (cause.length > 0) console.log(chalk.gray(cause.map((line) => ` ${line.trim()}`).join("\n")));
|
|
784
906
|
console.log(` ${chalk.gray(`Run ${chalk.cyan("rebase generate-sdk")} to see why.`)}`);
|
|
907
|
+
return "failed";
|
|
785
908
|
}
|
|
786
909
|
}
|
|
787
910
|
/**
|
|
911
|
+
* What dev prints once a collection edit's regeneration is done.
|
|
912
|
+
*
|
|
913
|
+
* The green "regenerated" box only when neither half failed. It used to be
|
|
914
|
+
* printed unconditionally, right under "⚠ Could not regenerate the database
|
|
915
|
+
* schema … nothing was applied" — and then the backend refused to boot over
|
|
916
|
+
* the same collection error, so the success line was the one wrong thing on
|
|
917
|
+
* the screen.
|
|
918
|
+
*/
|
|
919
|
+
function collectionChangeSummary(schema, sdk) {
|
|
920
|
+
const failed = [schema === "failed" && "the database schema", sdk === "failed" && "the SDK types"].filter((part) => Boolean(part));
|
|
921
|
+
if (failed.length > 0) return [
|
|
922
|
+
chalk.yellow(` ⚠ Not regenerated: ${failed.join(" and ")} — fix the error above and save again.`),
|
|
923
|
+
chalk.gray(" The backend restarts and reports the same problem until it is fixed."),
|
|
924
|
+
""
|
|
925
|
+
];
|
|
926
|
+
return [
|
|
927
|
+
chalk.green(" ✓ Schema and SDK types regenerated. The backend restarts and boot"),
|
|
928
|
+
chalk.green(" creates what is missing — a new collection, a new property."),
|
|
929
|
+
chalk.gray(" For what boot leaves alone — a renamed column, a narrowed type,"),
|
|
930
|
+
chalk.gray(` a removed field — run ${chalk.cyan("rebase db push")}.`),
|
|
931
|
+
""
|
|
932
|
+
];
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
788
935
|
* One variable's value out of `.env` text, or undefined when it has none.
|
|
789
936
|
*
|
|
790
937
|
* The obvious `\s*(.+?)\s*$` does not do this, because `\s` matches a newline
|
|
@@ -982,7 +1129,7 @@ async function devCommand(rawArgs) {
|
|
|
982
1129
|
printDevHelp();
|
|
983
1130
|
return;
|
|
984
1131
|
}
|
|
985
|
-
if (rawArgs
|
|
1132
|
+
if (switchOn(rawArgs, "--generate") || rawArgs.includes("-g")) throw new UsageError("`rebase dev --generate` is gone: dev now regenerates the schema and the SDK types on every start and every collection save. Drop the flag.");
|
|
986
1133
|
const { flags: args } = parseCommandArgs({
|
|
987
1134
|
spec: DEV_FLAGS,
|
|
988
1135
|
rawArgs,
|
|
@@ -1009,7 +1156,7 @@ async function devCommand(rawArgs) {
|
|
|
1009
1156
|
const { port: startPort, source: startPortSource } = resolveStartPort(projectRoot, args["--port"]);
|
|
1010
1157
|
const portIsPinned = args["--port"] !== void 0;
|
|
1011
1158
|
const pinnedFrontendPort = process.env.REBASE_FRONTEND_PORT;
|
|
1012
|
-
if (pinnedFrontendPort && !/^\d+$/.test(pinnedFrontendPort)) throw new
|
|
1159
|
+
if (pinnedFrontendPort && !/^\d+$/.test(pinnedFrontendPort)) throw new Refusal(`REBASE_FRONTEND_PORT must be a number, got ${JSON.stringify(pinnedFrontendPort)}.`);
|
|
1013
1160
|
const frontendPort = pinnedFrontendPort ? Number(pinnedFrontendPort) : getProjectFrontendPort(projectRoot);
|
|
1014
1161
|
if (!frontendOnly) {
|
|
1015
1162
|
const refusal = await pinnedPortRefusal(startPort, portIsPinned);
|
|
@@ -1046,6 +1193,15 @@ async function devCommand(rawArgs) {
|
|
|
1046
1193
|
* which is the failure the flag exists to produce.
|
|
1047
1194
|
*/
|
|
1048
1195
|
let prepared = null;
|
|
1196
|
+
/**
|
|
1197
|
+
* The backend port the SDK README was last generated for: the one the
|
|
1198
|
+
* backend is told at boot, then each one it announces it bound.
|
|
1199
|
+
*/
|
|
1200
|
+
let sdkBackendPort = startsBackend ? startPort : null;
|
|
1201
|
+
const regenerateSdkFor = (port) => {
|
|
1202
|
+
sdkBackendPort = port;
|
|
1203
|
+
return regenerateSdk(projectRoot, port);
|
|
1204
|
+
};
|
|
1049
1205
|
if (!frontendOnly) {
|
|
1050
1206
|
const resolved = args["--docker"] ? resolveProjectDatabase(projectRoot, {
|
|
1051
1207
|
flagUrl,
|
|
@@ -1054,7 +1210,7 @@ async function devCommand(rawArgs) {
|
|
|
1054
1210
|
}) : null;
|
|
1055
1211
|
const dockerUrl = resolved?.kind === "docker" ? resolved.url ?? void 0 : void 0;
|
|
1056
1212
|
({schemaGeneration, database: prepared} = await overlapDevStartup({
|
|
1057
|
-
generate: async () => (await Promise.all([ensureGeneratedSchema(projectRoot),
|
|
1213
|
+
generate: async () => (await Promise.all([ensureGeneratedSchema(projectRoot), regenerateSdkFor(sdkBackendPort)]))[0],
|
|
1058
1214
|
preflight: () => runDatabasePreflight({
|
|
1059
1215
|
projectRoot,
|
|
1060
1216
|
disabled: noDb || flagUrl !== null,
|
|
@@ -1292,16 +1448,22 @@ async function devCommand(rawArgs) {
|
|
|
1292
1448
|
try {
|
|
1293
1449
|
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
1294
1450
|
const pluginCli = activePlugin ? resolvePluginCliScript(backendDir, activePlugin) : null;
|
|
1295
|
-
if (pluginCli && needsStaleSchemaPreflight(schemaGeneration))
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1451
|
+
if (pluginCli && needsStaleSchemaPreflight(schemaGeneration)) {
|
|
1452
|
+
const staleArgs = [
|
|
1453
|
+
"schema",
|
|
1454
|
+
"stale",
|
|
1455
|
+
"--fix"
|
|
1456
|
+
];
|
|
1457
|
+
await execa(tsxBin, [
|
|
1458
|
+
pluginCli,
|
|
1459
|
+
...staleArgs,
|
|
1460
|
+
...collectionsDirArgs(projectRoot, staleArgs)
|
|
1461
|
+
], {
|
|
1462
|
+
cwd: backendDir,
|
|
1463
|
+
stdio: "inherit",
|
|
1464
|
+
env
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1305
1467
|
} catch {}
|
|
1306
1468
|
const ejectedEntry = path.join(backendDir, "src", "index.ts");
|
|
1307
1469
|
const usesStockRuntime = !fs.existsSync(ejectedEntry);
|
|
@@ -1345,13 +1507,12 @@ async function devCommand(rawArgs) {
|
|
|
1345
1507
|
}
|
|
1346
1508
|
};
|
|
1347
1509
|
const collectionsDir = devCollectionsDir(projectRoot);
|
|
1348
|
-
|
|
1510
|
+
{
|
|
1349
1511
|
let debounce = null;
|
|
1350
1512
|
let sqlSchemaAffected = false;
|
|
1351
1513
|
let changed = "";
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
sqlSchemaAffected = sqlSchemaAffected || affectsSqlSchema(collectionsDir, filename);
|
|
1514
|
+
const collectionsChanged = (filename, affectsSchema) => {
|
|
1515
|
+
sqlSchemaAffected = sqlSchemaAffected || affectsSchema;
|
|
1355
1516
|
changed = filename;
|
|
1356
1517
|
if (debounce) clearTimeout(debounce);
|
|
1357
1518
|
debounce = setTimeout(() => {
|
|
@@ -1359,7 +1520,7 @@ async function devCommand(rawArgs) {
|
|
|
1359
1520
|
sqlSchemaAffected = false;
|
|
1360
1521
|
(async () => {
|
|
1361
1522
|
if (!regenerateSchema) {
|
|
1362
|
-
await
|
|
1523
|
+
await regenerateSdkFor(resolvedBackendPort ?? startPort);
|
|
1363
1524
|
restartBackend();
|
|
1364
1525
|
return;
|
|
1365
1526
|
}
|
|
@@ -1372,17 +1533,22 @@ async function devCommand(rawArgs) {
|
|
|
1372
1533
|
chalk.yellow(" └──────────────────────────────────────────────────────────────┘")
|
|
1373
1534
|
].join("\n"));
|
|
1374
1535
|
const schemaBefore = generatedSchemaStamp();
|
|
1375
|
-
await Promise.all([ensureGeneratedSchema(projectRoot),
|
|
1376
|
-
if (!(usesStockRuntime && generatedSchemaStamp() !== schemaBefore)) restartBackend();
|
|
1377
|
-
console.log(
|
|
1378
|
-
chalk.green(" ✓ Schema and SDK types regenerated. The backend restarts and boot"),
|
|
1379
|
-
chalk.green(" creates what is missing — a new collection, a new property."),
|
|
1380
|
-
chalk.gray(" For what boot leaves alone — a renamed column, a narrowed type,"),
|
|
1381
|
-
chalk.gray(` a removed field — run ${chalk.cyan("rebase db push")}.`),
|
|
1382
|
-
""
|
|
1383
|
-
].join("\n"));
|
|
1536
|
+
const [schemaResult, sdkResult] = await Promise.all([ensureGeneratedSchema(projectRoot), regenerateSdkFor(resolvedBackendPort ?? startPort)]);
|
|
1537
|
+
if (!(usesStockRuntime && schemaBefore !== null && generatedSchemaStamp() !== schemaBefore)) restartBackend();
|
|
1538
|
+
console.log(collectionChangeSummary(schemaResult, sdkResult).join("\n"));
|
|
1384
1539
|
})();
|
|
1385
1540
|
}, 500);
|
|
1541
|
+
};
|
|
1542
|
+
const watchCollections = () => {
|
|
1543
|
+
fs.watch(collectionsDir, { recursive: true }, (_eventType, filename) => {
|
|
1544
|
+
if (!filename || filename.startsWith(".") || filename.endsWith(".tmp")) return;
|
|
1545
|
+
collectionsChanged(filename, affectsSqlSchema(collectionsDir, filename));
|
|
1546
|
+
});
|
|
1547
|
+
};
|
|
1548
|
+
if (fs.existsSync(collectionsDir)) watchCollections();
|
|
1549
|
+
else whenDirectoryAppears(collectionsDir, projectRoot, () => {
|
|
1550
|
+
watchCollections();
|
|
1551
|
+
collectionsChanged(`${path.basename(collectionsDir)}/`, true);
|
|
1386
1552
|
});
|
|
1387
1553
|
}
|
|
1388
1554
|
if (!backendOnly && frontendDir && await frontendCanStartWithBackend({
|
|
@@ -1415,6 +1581,23 @@ async function devCommand(rawArgs) {
|
|
|
1415
1581
|
* after the entry crashes, so nothing exits to contradict it.
|
|
1416
1582
|
*/
|
|
1417
1583
|
let backendAnnounced = false;
|
|
1584
|
+
/**
|
|
1585
|
+
* A boot that lost its database part-way is booted again, a few
|
|
1586
|
+
* times, instead of waiting for a file change. See utils/boot-retry.ts:
|
|
1587
|
+
* a `rebase db branch create --force` that lands while the backend
|
|
1588
|
+
* boots ends its connections, and nothing in the project is wrong.
|
|
1589
|
+
*/
|
|
1590
|
+
const bootRetry = new BootRetry();
|
|
1591
|
+
const retryPassingBootFailure = (line) => {
|
|
1592
|
+
if (!usableTrigger || shuttingDown) return;
|
|
1593
|
+
const plan = bootRetry.line(stripAnsi(line));
|
|
1594
|
+
if (!plan) return;
|
|
1595
|
+
setTimeout(() => {
|
|
1596
|
+
if (shuttingDown || backendAnnounced) return;
|
|
1597
|
+
console.log(chalk.gray(` ↻ The backend lost its database while it was starting; starting it again (${plan.attempt} of ${plan.of}).`));
|
|
1598
|
+
restartBackend();
|
|
1599
|
+
}, plan.delayMs).unref?.();
|
|
1600
|
+
};
|
|
1418
1601
|
/** The verdict, printed once per failure rather than once per line. */
|
|
1419
1602
|
let backendDownReported = false;
|
|
1420
1603
|
const reportBackendDown = (headline) => {
|
|
@@ -1537,6 +1720,7 @@ async function devCommand(rawArgs) {
|
|
|
1537
1720
|
console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
|
|
1538
1721
|
noticeWatcherRestart(line);
|
|
1539
1722
|
noticePortMoved(line);
|
|
1723
|
+
retryPassingBootFailure(line);
|
|
1540
1724
|
const cleanLine = stripAnsi(line);
|
|
1541
1725
|
const swaggerMatch = cleanLine.match(/Swagger UI available.*"path":"([^"]+)"/);
|
|
1542
1726
|
if (swaggerMatch) swaggerPath = swaggerMatch[1];
|
|
@@ -1545,6 +1729,7 @@ async function devCommand(rawArgs) {
|
|
|
1545
1729
|
backendAnnounced = true;
|
|
1546
1730
|
backendDownReported = false;
|
|
1547
1731
|
missedProbes = 0;
|
|
1732
|
+
bootRetry.up();
|
|
1548
1733
|
if (backendOnly) process.exitCode = 0;
|
|
1549
1734
|
disarmReadyDeadline();
|
|
1550
1735
|
resolvedBackendPort = parseInt(serverMatch[1], 10);
|
|
@@ -1561,6 +1746,7 @@ async function devCommand(rawArgs) {
|
|
|
1561
1746
|
fs.writeFileSync(urlFile, `http://localhost:${resolvedBackendPort}`, "utf-8");
|
|
1562
1747
|
const portFile = path.join(projectRoot, DEV_PORT_FILENAME);
|
|
1563
1748
|
fs.writeFileSync(portFile, devPortFileContents(resolvedBackendPort, startPort), "utf-8");
|
|
1749
|
+
if (sdkBackendPort !== null && sdkBackendPort !== resolvedBackendPort) regenerateSdkFor(resolvedBackendPort);
|
|
1564
1750
|
}
|
|
1565
1751
|
});
|
|
1566
1752
|
/** Whether we've already shown a corrupted-modules recovery hint. */
|
|
@@ -1569,6 +1755,7 @@ async function devCommand(rawArgs) {
|
|
|
1569
1755
|
console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
|
|
1570
1756
|
noticeWatcherRestart(line);
|
|
1571
1757
|
noticePortMoved(line);
|
|
1758
|
+
retryPassingBootFailure(line);
|
|
1572
1759
|
if (!corruptedModulesWarned) {
|
|
1573
1760
|
const cleanLine = stripAnsi(line);
|
|
1574
1761
|
if (cleanLine.includes("Cannot find module") && cleanLine.includes("node_modules/.pnpm/")) {
|
|
@@ -1690,4 +1877,4 @@ ${chalk.green.bold("Description")}
|
|
|
1690
1877
|
//#endregion
|
|
1691
1878
|
export { devCommand };
|
|
1692
1879
|
|
|
1693
|
-
//# sourceMappingURL=dev-
|
|
1880
|
+
//# sourceMappingURL=dev-DTqVMgB3.js.map
|