@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.
- package/dist/{agent-setup-B5AKHOgt.js → agent-setup-BYb2Tbdz.js} +2 -2
- package/dist/{agent-setup-B5AKHOgt.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
- package/dist/{api-keys-Tm7zvAPe.js → api-keys-CSMbsmAn.js} +3 -4
- package/dist/{api-keys-Tm7zvAPe.js.map → api-keys-CSMbsmAn.js.map} +1 -1
- package/dist/{apps-BsU_ILbP.js → apps-iBXNZhVN.js} +6 -7
- package/dist/{apps-BsU_ILbP.js.map → apps-iBXNZhVN.js.map} +1 -1
- package/dist/{atlas-dev-database-OWtqnG7W.js → atlas-dev-database-BusbHP6n.js} +4 -4
- package/dist/{atlas-dev-database-OWtqnG7W.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
- package/dist/{auth-Vl2hFKXP.js → auth-DRsTWPky.js} +6 -7
- package/dist/{auth-Vl2hFKXP.js.map → auth-DRsTWPky.js.map} +1 -1
- package/dist/{branch-pointer-9DnwkFJJ.js → branch-pointer-Bn_FjNld.js} +1 -1
- package/dist/{build-BBgT8EJZ.js → build-et7Rccxi.js} +6 -7
- package/dist/{build-BBgT8EJZ.js.map → build-et7Rccxi.js.map} +1 -1
- package/dist/{bundle-DtCCCr4w.js → bundle-DlqkDYSe.js} +3 -3
- package/dist/{bundle-DtCCCr4w.js.map → bundle-DlqkDYSe.js.map} +1 -1
- package/dist/{cloud-BpH0_bmV.js → cloud-B-ZIjHrA.js} +10 -11
- package/dist/{cloud-BpH0_bmV.js.map → cloud-B-ZIjHrA.js.map} +1 -1
- package/dist/commands/dev.d.ts +12 -0
- package/dist/commands/generate_sdk.d.ts +4 -2
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/upgrade.d.ts +12 -0
- package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
- package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
- package/dist/{console-CEGm0XNc.js → console-BlD9kjFW.js} +4 -4
- package/dist/{console-CEGm0XNc.js.map → console-BlD9kjFW.js.map} +1 -1
- package/dist/{context-CyflUrKg.js → context-DHiiiJ5C.js} +3 -4
- package/dist/context-DHiiiJ5C.js.map +1 -0
- package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
- package/dist/daemon-DDMRbz4T.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-9P6MnmdC.js} +90 -50
- package/dist/db-9P6MnmdC.js.map +1 -0
- package/dist/{derive-CsoFGAnK.js → derive-MTdClnkc.js} +2 -2
- package/dist/{derive-CsoFGAnK.js.map → derive-MTdClnkc.js.map} +1 -1
- package/dist/{dev-C0pbMmhS.js → dev-BDN_OKXA.js} +183 -23
- package/dist/dev-BDN_OKXA.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-FT9GbJVj.js} +73 -27
- package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
- package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
- package/dist/dev-server-CIZwAfZa.js.map +1 -0
- package/dist/{doctor-CATRdWm6.js → doctor-D8YXz7df.js} +6 -6
- package/dist/doctor-D8YXz7df.js.map +1 -0
- package/dist/{eject-DuasTr-F.js → eject-izG2KjMo.js} +3 -4
- package/dist/{eject-DuasTr-F.js.map → eject-izG2KjMo.js.map} +1 -1
- package/dist/{fold-static-hDHtDfTq.js → fold-static-CybSay_W.js} +3 -3
- package/dist/{fold-static-hDHtDfTq.js.map → fold-static-CybSay_W.js.map} +1 -1
- package/dist/{generate_sdk-Cvg5jjJF.js → generate_sdk-B4R65oUV.js} +21 -11
- package/dist/generate_sdk-B4R65oUV.js.map +1 -0
- package/dist/index.es.js +36 -37
- package/dist/index.es.js.map +1 -1
- package/dist/{init-BWAwHPtz.js → init-DYaeppEN.js} +50 -62
- package/dist/init-DYaeppEN.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-B_75fxZC.js +2 -0
- package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
- package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
- package/dist/{normalize-imports-BoBVh5tU.js → normalize-imports-BYw8ad87.js} +3 -3
- package/dist/{normalize-imports-BoBVh5tU.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
- package/dist/{prepare-DdnU70z8.js → prepare-1rVNd2PF.js} +5 -4
- package/dist/{prepare-DdnU70z8.js.map → prepare-1rVNd2PF.js.map} +1 -1
- package/dist/project-g4K6kV1t.js +701 -0
- package/dist/project-g4K6kV1t.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-BQUAC3Wi.js +2 -0
- package/dist/{resources-BdNRDEAy.js → resources-CovP8AZ-.js} +4 -5
- package/dist/{resources-BdNRDEAy.js.map → resources-CovP8AZ-.js.map} +1 -1
- package/dist/{schema-B0-p6T1O.js → schema-nuxvvc50.js} +5 -6
- package/dist/{schema-B0-p6T1O.js.map → schema-nuxvvc50.js.map} +1 -1
- package/dist/{skills-DfnTeyRz.js → skills-DeUIsZcT.js} +3 -4
- package/dist/{skills-DfnTeyRz.js.map → skills-DeUIsZcT.js.map} +1 -1
- package/dist/{start-BmEZkS0n.js → start-RzZqDroW.js} +20 -7
- package/dist/start-RzZqDroW.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/{status-BJ26yZOo.js → status-D9Zm88NZ.js} +8 -9
- package/dist/{status-BJ26yZOo.js.map → status-D9Zm88NZ.js.map} +1 -1
- package/dist/{storage-DKPUBTWG.js → storage-BB3umRfw.js} +3 -4
- package/dist/{storage-DKPUBTWG.js.map → storage-BB3umRfw.js.map} +1 -1
- package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
- package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
- package/dist/{telemetry-m9czTNGR.js → telemetry-TseNLk6X.js} +4 -4
- package/dist/{telemetry-m9czTNGR.js.map → telemetry-TseNLk6X.js.map} +1 -1
- package/dist/{upgrade-DjihWuZL.js → upgrade-apiPKKE_.js} +26 -4
- package/dist/{upgrade-DjihWuZL.js.map → upgrade-apiPKKE_.js.map} +1 -1
- package/dist/utils/args.d.ts +32 -3
- package/dist/utils/boot-retry.d.ts +41 -0
- package/dist/utils/dev-preflight.d.ts +34 -1
- package/dist/utils/dev-server.d.ts +11 -0
- package/dist/utils/project.d.ts +5 -1
- package/dist/utils/unknown-command.d.ts +4 -0
- package/package.json +7 -7
- 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/.env.example +5 -4
- package/templates/template/frontend/src/App.tsx +10 -9
- package/dist/args-BX0YD14a.js +0 -266
- package/dist/args-BX0YD14a.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/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/start-BmEZkS0n.js.map +0 -1
- package/dist/state-CCB-FAQ9.js.map +0 -1
|
@@ -101,13 +101,33 @@ export declare function probeTcp(host: string, port: number, timeoutMs?: number)
|
|
|
101
101
|
* forward. {@link waitForQueryable} is the check that a query will work.
|
|
102
102
|
*/
|
|
103
103
|
export declare function waitForPort(host: string, port: number, timeoutMs?: number, intervalMs?: number): Promise<boolean>;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Whether a database answered a query, and if not, the last reason it gave —
|
|
106
|
+
* and, for a database closed to new connections, its name.
|
|
107
|
+
*/
|
|
105
108
|
export type QueryReadiness = {
|
|
106
109
|
ready: true;
|
|
107
110
|
} | {
|
|
108
111
|
ready: false;
|
|
109
112
|
error: string;
|
|
113
|
+
closedDatabase?: string;
|
|
110
114
|
};
|
|
115
|
+
/** What opening a closed database again did, and what to say about it. */
|
|
116
|
+
export interface ClosedDatabaseHeal {
|
|
117
|
+
/** It accepts connections again. */
|
|
118
|
+
reopened: boolean;
|
|
119
|
+
/** The driver's own lines about it (`reopenedDatabasesNotice`). */
|
|
120
|
+
notice: string[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The database a connection was refused by because it is closed to new
|
|
124
|
+
* connections (`ALLOW_CONNECTIONS false`), or null.
|
|
125
|
+
*
|
|
126
|
+
* The driver's `closedDatabaseName`, for the error a bare `pg` connect gives:
|
|
127
|
+
* the sentence is matched, not SQLSTATE 55000, which also covers failures that
|
|
128
|
+
* have nothing to do with connecting.
|
|
129
|
+
*/
|
|
130
|
+
export declare function closedDatabaseName(error: unknown): string | null;
|
|
111
131
|
/**
|
|
112
132
|
* Poll until `SELECT 1` succeeds on this connection string, or the bound runs out.
|
|
113
133
|
*
|
|
@@ -118,10 +138,21 @@ export type QueryReadiness = {
|
|
|
118
138
|
* three. Every error is retried: a reset, "the database system is starting up"
|
|
119
139
|
* and a refused connection all mean "not yet", and the bound is what turns
|
|
120
140
|
* "not yet" into an answer.
|
|
141
|
+
*
|
|
142
|
+
* Except one, which is not "not yet": a database closed to new connections
|
|
143
|
+
* (`closedDatabaseName`), which is what a `rebase db branch create --force`
|
|
144
|
+
* killed mid-copy leaves its source as. Waiting cannot open it, and it was
|
|
145
|
+
* waited on for the whole minute. It is opened again with the driver's
|
|
146
|
+
* `reopenClosedDatabases`, once, and then either answers or the wait ends at
|
|
147
|
+
* once, naming it.
|
|
121
148
|
*/
|
|
122
149
|
export declare function waitForQueryable(databaseUrl: string, options?: {
|
|
123
150
|
timeoutMs?: number;
|
|
124
151
|
intervalMs?: number;
|
|
152
|
+
/** Opens a closed database again. The driver's `reopenClosedDatabases` by default; injected for tests. */
|
|
153
|
+
reopenClosed?: (databaseUrl: string) => Promise<ClosedDatabaseHeal>;
|
|
154
|
+
/** Where the driver's lines about a database it opened go. */
|
|
155
|
+
onNotice?: (line: string) => void;
|
|
125
156
|
}): Promise<QueryReadiness>;
|
|
126
157
|
/**
|
|
127
158
|
* What a failed schema push printed, as lines to show.
|
|
@@ -204,6 +235,8 @@ export interface EnsureDevDatabaseOptions {
|
|
|
204
235
|
startDatabase?: (projectRoot: string) => Promise<void>;
|
|
205
236
|
/** How long a started database has to answer `SELECT 1`. Defaults to 60s. */
|
|
206
237
|
readyTimeoutMs?: number;
|
|
238
|
+
/** Opens a database closed to new connections again; see `waitForQueryable`. Injected for tests. */
|
|
239
|
+
reopenClosed?: (databaseUrl: string) => Promise<ClosedDatabaseHeal>;
|
|
207
240
|
/**
|
|
208
241
|
* Who answers on the compose port. Asks Docker by default; injected for the
|
|
209
242
|
* same reason `startDatabase` is.
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The address `rebase dev` is starting its backend on, handed to the
|
|
3
|
+
* `generate-sdk` child it runs.
|
|
4
|
+
*
|
|
5
|
+
* Dev regenerates the SDK at boot, beside the database start and before the
|
|
6
|
+
* backend binds — so before the backend writes `.rebase/state.json`, which is
|
|
7
|
+
* where `generate-sdk` otherwise reads the address for the README's example.
|
|
8
|
+
* Dev knows the port it hands the backend, and the child's environment is the
|
|
9
|
+
* only channel between them.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEV_BACKEND_URL_ENV = "REBASE_DEV_BACKEND_URL";
|
|
1
12
|
/**
|
|
2
13
|
* The port `rebase dev` derives from the project root path.
|
|
3
14
|
* Range: 3001–3999 (avoids privileged ports and common services).
|
package/dist/utils/project.d.ts
CHANGED
|
@@ -158,7 +158,11 @@ export interface JsonFailureIssue {
|
|
|
158
158
|
* failure mode of not doing it is an unparseable stream.
|
|
159
159
|
*/
|
|
160
160
|
export declare function failAsJson(message: string, code: string, hint?: string, issues?: JsonFailureIssue[]): never;
|
|
161
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Did the command line ask for machine-readable output? Read as the parser
|
|
163
|
+
* reads a switch: `--json`, `--json=true` and `--json=1` ask for it,
|
|
164
|
+
* `--json=false` and `--json=0` do not.
|
|
165
|
+
*/
|
|
162
166
|
export declare function wantsJsonOutput(argv?: readonly string[]): boolean;
|
|
163
167
|
/**
|
|
164
168
|
* Require the project root or exit with a helpful error.
|
|
@@ -17,6 +17,10 @@ export declare function suggestCommand(typed: string, known: readonly string[]):
|
|
|
17
17
|
* `family` is empty for the top level: `rebase --help`, not `rebase --help`.
|
|
18
18
|
* `families` are the command families below this level, by name, whose
|
|
19
19
|
* commands a word may be one of.
|
|
20
|
+
*
|
|
21
|
+
* The typed word is repeated with any connection-string password masked: a URL
|
|
22
|
+
* pasted where the command goes (`rebase db "postgres://u:pw@h/db"`) is a
|
|
23
|
+
* word like any other here, and this line lands in terminals and CI logs.
|
|
20
24
|
*/
|
|
21
25
|
export declare function unknownCommandMessage(typed: string | undefined, known: readonly string[], family?: string, families?: Readonly<Record<string, readonly string[]>>): string;
|
|
22
26
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/cli",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Developer tools for Rebase projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"inquirer": "14.0.2",
|
|
44
44
|
"jiti": "^2.7.0",
|
|
45
45
|
"pg": "^8.22.0",
|
|
46
|
-
"@rebasepro/
|
|
47
|
-
"@rebasepro/
|
|
48
|
-
"@rebasepro/
|
|
49
|
-
"@rebasepro/
|
|
50
|
-
"@rebasepro/
|
|
51
|
-
"@rebasepro/server-postgres": "0.25.
|
|
46
|
+
"@rebasepro/client": "0.25.1",
|
|
47
|
+
"@rebasepro/codegen": "0.25.1",
|
|
48
|
+
"@rebasepro/server": "0.25.1",
|
|
49
|
+
"@rebasepro/types": "0.25.1",
|
|
50
|
+
"@rebasepro/agent-skills": "0.25.1",
|
|
51
|
+
"@rebasepro/server-postgres": "0.25.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^26.1.2",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$generated": "Generated from config by `rebase resources`. Edit the declarations, not this file.",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"resources": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "database",
|
|
7
|
+
"key": "(default)",
|
|
8
|
+
"engine": "postgres",
|
|
9
|
+
"transport": "server",
|
|
10
|
+
"usedBy": [
|
|
11
|
+
"collection:users"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"kind": "function",
|
|
16
|
+
"key": "hello",
|
|
17
|
+
"engine": "http",
|
|
18
|
+
"transport": "server",
|
|
19
|
+
"options": {
|
|
20
|
+
"portable": true,
|
|
21
|
+
"file": "backend/functions/hello.ts"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$generated": "Generated from config by `rebase resources`. Edit the declarations, not this file.",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"resources": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "database",
|
|
7
|
+
"key": "(default)",
|
|
8
|
+
"engine": "postgres",
|
|
9
|
+
"transport": "server",
|
|
10
|
+
"usedBy": [
|
|
11
|
+
"collection:authors",
|
|
12
|
+
"collection:posts",
|
|
13
|
+
"collection:tags",
|
|
14
|
+
"collection:users"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"kind": "function",
|
|
19
|
+
"key": "hello",
|
|
20
|
+
"engine": "http",
|
|
21
|
+
"transport": "server",
|
|
22
|
+
"options": {
|
|
23
|
+
"portable": true,
|
|
24
|
+
"file": "backend/functions/hello.ts"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$generated": "Generated from config by `rebase resources`. Edit the declarations, not this file.",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"resources": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "database",
|
|
7
|
+
"key": "(default)",
|
|
8
|
+
"engine": "postgres",
|
|
9
|
+
"transport": "server",
|
|
10
|
+
"usedBy": [
|
|
11
|
+
"collection:categories",
|
|
12
|
+
"collection:orders",
|
|
13
|
+
"collection:products",
|
|
14
|
+
"collection:users"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"kind": "function",
|
|
19
|
+
"key": "hello",
|
|
20
|
+
"engine": "http",
|
|
21
|
+
"transport": "server",
|
|
22
|
+
"options": {
|
|
23
|
+
"portable": true,
|
|
24
|
+
"file": "backend/functions/hello.ts"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$generated": "Generated from config by `rebase resources`. Edit the declarations, not this file.",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"resources": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "database",
|
|
7
|
+
"key": "(default)",
|
|
8
|
+
"engine": "postgres",
|
|
9
|
+
"transport": "server"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"kind": "function",
|
|
13
|
+
"key": "hello",
|
|
14
|
+
"engine": "http",
|
|
15
|
+
"transport": "server",
|
|
16
|
+
"options": {
|
|
17
|
+
"portable": true,
|
|
18
|
+
"file": "backend/functions/hello.ts"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -169,10 +169,11 @@ VITE_API_URL=
|
|
|
169
169
|
# STORAGE_TYPE=local
|
|
170
170
|
|
|
171
171
|
# --- Local filesystem (default — great for dev and single-server deployments) --
|
|
172
|
-
# Unset, files land in <project>/uploads, under `rebase dev`
|
|
173
|
-
# `rebase eject` writes alike. A relative path is read from
|
|
174
|
-
# server runs in: the project root under `rebase dev`,
|
|
175
|
-
# `rebase eject`. So ./uploads names two places, and an absolute
|
|
172
|
+
# Unset, files land in <project>/uploads, under `rebase dev`, `rebase start`
|
|
173
|
+
# and in the server `rebase eject` writes alike. A relative path is read from
|
|
174
|
+
# the directory the server runs in: the project root under `rebase dev`,
|
|
175
|
+
# backend/ after `rebase eject`. So ./uploads names two places, and an absolute
|
|
176
|
+
# path one.
|
|
176
177
|
# STORAGE_PATH=/absolute/path/to/uploads
|
|
177
178
|
# FORCE_LOCAL_STORAGE=true # Only with a durable volume holding STORAGE_PATH
|
|
178
179
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
import "@fontsource/jetbrains-mono";
|
|
4
2
|
import "@fontsource-variable/inter";
|
|
5
3
|
import "@fontsource-variable/instrument-sans";
|
|
@@ -19,14 +17,17 @@ import { collections } from "virtual:rebase-collections";
|
|
|
19
17
|
const API_URL = import.meta.env.VITE_API_URL;
|
|
20
18
|
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
// One client for the page, created when this module loads. Inside a component,
|
|
21
|
+
// even in a `useMemo`, `<React.StrictMode>` builds a second one in development,
|
|
22
|
+
// and both restore the session and open their own connections.
|
|
23
|
+
const rebaseClient = createRebaseClient({
|
|
24
|
+
baseUrl: API_URL,
|
|
25
|
+
// Store the refresh token in an httpOnly cookie (XSS-safe) rather than
|
|
26
|
+
// localStorage. The backend issues it via `auth.cookieAuth`.
|
|
27
|
+
auth: { authFlowMode: "cookie" }
|
|
28
|
+
});
|
|
29
29
|
|
|
30
|
+
export function App() {
|
|
30
31
|
const authController = useRebaseAuthController({
|
|
31
32
|
client: rebaseClient,
|
|
32
33
|
googleClientId: GOOGLE_CLIENT_ID
|
package/dist/args-BX0YD14a.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import arg from "arg";
|
|
3
|
-
//#region src/utils/redact.ts
|
|
4
|
-
/**
|
|
5
|
-
* Connection-string passwords, replaced before a line is printed.
|
|
6
|
-
*
|
|
7
|
-
* A refusal that repeats what was typed repeats a password with it, and these
|
|
8
|
-
* lines land in terminals, CI logs and issues. `user:***@` is the form every
|
|
9
|
-
* other message uses: the driver's `redactConnectionPasswords` in
|
|
10
|
-
* `@rebasepro/server-postgres`, which its entry does not export, and this
|
|
11
|
-
* mirrors. Covers the user-info password and a `password=` parameter.
|
|
12
|
-
*/
|
|
13
|
-
function redactConnectionPasswords(text) {
|
|
14
|
-
return text.replace(/(\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#@'"]*):[^\s/?#'"]*@/gi, "$1:***@").replace(/(\bpassword\s*=\s*)('[^']*'|[^\s&'"]+)/gi, "$1***");
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/utils/unknown-command.ts
|
|
18
|
-
/**
|
|
19
|
-
* What every command family says when it does not recognise a subcommand.
|
|
20
|
-
*
|
|
21
|
-
* Six families each did it differently, and the differences were not stylistic:
|
|
22
|
-
*
|
|
23
|
-
* rebase statsu "Unknown command: statsu" + the whole top-level help
|
|
24
|
-
* rebase auth foo "Unknown auth command: foo" + the whole auth help
|
|
25
|
-
* rebase apps foo "Unknown subcommand: foo" — which command's?
|
|
26
|
-
* rebase skills foo "Unknown skills subcommand: foo" + the whole help
|
|
27
|
-
* rebase telemetry x the help, silently, with exit code 1 and no error line
|
|
28
|
-
* rebase cloud debug x both a JSON error *and* the human one, in JSON mode
|
|
29
|
-
*
|
|
30
|
-
* Dumping a screen of help after an error is the wrong shape: the one line that
|
|
31
|
-
* says what happened scrolls off the top, and in a CI log it is buried in
|
|
32
|
-
* forty. None of them offered the correction, which for a typo is the entire
|
|
33
|
-
* answer — `statsu` is one transposition from `status`.
|
|
34
|
-
*
|
|
35
|
-
* So: one line, the near-miss when there is one, and where to read the rest.
|
|
36
|
-
*/
|
|
37
|
-
/**
|
|
38
|
-
* Damerau–Levenshtein distance, capped by the caller.
|
|
39
|
-
*
|
|
40
|
-
* The transposition is the reason this is not plain Levenshtein: `statsu` for
|
|
41
|
-
* `status` and `craete` for `create` are the two most common typing errors
|
|
42
|
-
* there are, and both are distance 2 without it — the same as two unrelated
|
|
43
|
-
* edits, which is too far to suggest anything at all.
|
|
44
|
-
*/
|
|
45
|
-
function editDistance(a, b) {
|
|
46
|
-
const rows = a.length + 1;
|
|
47
|
-
const cols = b.length + 1;
|
|
48
|
-
const d = Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
49
|
-
for (let i = 0; i < rows; i++) d[i][0] = i;
|
|
50
|
-
for (let j = 0; j < cols; j++) d[0][j] = j;
|
|
51
|
-
for (let i = 1; i < rows; i++) for (let j = 1; j < cols; j++) {
|
|
52
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
53
|
-
d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
|
|
54
|
-
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
|
|
55
|
-
}
|
|
56
|
-
return d[a.length][b.length];
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* The one command the user probably meant, or nothing.
|
|
60
|
-
*
|
|
61
|
-
* Tight on purpose. A suggestion that is wrong is worse than none: it sends
|
|
62
|
-
* someone to read the help for a command that was never the answer, and on a
|
|
63
|
-
* family like `db` — where `push` and `pull` are one edit apart — a loose
|
|
64
|
-
* threshold would confidently propose the destructive neighbour of what they
|
|
65
|
-
* typed. So: one edit for a short word, two for a long one, and a prefix match
|
|
66
|
-
* always counts (`rebase cloud dep` for `deploy`).
|
|
67
|
-
*/
|
|
68
|
-
function suggestCommand(typed, known) {
|
|
69
|
-
const word = typed.toLowerCase();
|
|
70
|
-
if (!word) return void 0;
|
|
71
|
-
if (word.length >= 3) {
|
|
72
|
-
const prefixed = known.filter((name) => name.toLowerCase().startsWith(word));
|
|
73
|
-
if (prefixed.length === 1) return prefixed[0];
|
|
74
|
-
}
|
|
75
|
-
const budget = word.length <= 4 ? 1 : 2;
|
|
76
|
-
let best;
|
|
77
|
-
for (const candidate of known) {
|
|
78
|
-
const distance = editDistance(word, candidate.toLowerCase());
|
|
79
|
-
if (distance > budget) continue;
|
|
80
|
-
if (!best || distance < best.distance) best = {
|
|
81
|
-
name: candidate,
|
|
82
|
-
distance
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
return best?.name;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* The family command a word names exactly, as `<family> <command>`, or nothing.
|
|
89
|
-
*
|
|
90
|
-
* `rebase deploy` is `rebase cloud deploy`: the word is a whole command one
|
|
91
|
-
* level down. Exact only — a near miss there is a guess about both the family
|
|
92
|
-
* and the command.
|
|
93
|
-
*/
|
|
94
|
-
function familyCommand(typed, families) {
|
|
95
|
-
const word = typed.toLowerCase();
|
|
96
|
-
for (const [family, commands] of Object.entries(families)) {
|
|
97
|
-
const match = commands.find((name) => name.toLowerCase() === word);
|
|
98
|
-
if (match) return `${family} ${match}`;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* The line itself, without printing it — so callers that must answer in JSON
|
|
103
|
-
* (the cloud family, whose `fail()` writes a machine-readable envelope) use the
|
|
104
|
-
* same words as the ones that print.
|
|
105
|
-
*
|
|
106
|
-
* `family` is empty for the top level: `rebase --help`, not `rebase --help`.
|
|
107
|
-
* `families` are the command families below this level, by name, whose
|
|
108
|
-
* commands a word may be one of.
|
|
109
|
-
*/
|
|
110
|
-
function unknownCommandMessage(typed, known, family = "", families = {}) {
|
|
111
|
-
const what = family ? `${family} command` : "command";
|
|
112
|
-
const suggestion = typed ? suggestCommand(typed, known) ?? familyCommand(typed, families) : void 0;
|
|
113
|
-
const help = family ? `rebase ${family} --help` : "rebase --help";
|
|
114
|
-
return suggestion ? `Unknown ${what} "${typed}" — did you mean \`${suggestion}\`? Run \`${help}\` for the rest.` : `Unknown ${what} "${typed ?? ""}". Run \`${help}\` for the ones there are.`;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Print the line to stderr and exit 1.
|
|
118
|
-
*
|
|
119
|
-
* stderr, not stdout: a mistyped command is a failure, and the families with a
|
|
120
|
-
* `--json` mode guarantee that stdout holds only their envelope.
|
|
121
|
-
*/
|
|
122
|
-
function unknownCommand(typed, known, family = "", families = {}) {
|
|
123
|
-
console.error(chalk.red(`✗ ${unknownCommandMessage(typed, known, family, families)}`));
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
//#endregion
|
|
127
|
-
//#region src/utils/args.ts
|
|
128
|
-
/**
|
|
129
|
-
* Argument parsing for the commands that take positional arguments.
|
|
130
|
-
*
|
|
131
|
-
* Every command in the small group used to parse its own line the same way:
|
|
132
|
-
* `arg(spec, { argv: rawArgs.slice(4), permissive: true })`, then read `_[0]`
|
|
133
|
-
* and `_[1]`. Both halves of that are wrong in a way that costs data.
|
|
134
|
-
*
|
|
135
|
-
* - **`permissive: true` turns an unknown flag into a positional.** `arg`
|
|
136
|
-
* pushes an undeclared flag into `_` as a bare token, so `_[1]` is whatever
|
|
137
|
-
* came second on the line, flag or not. `rebase auth reset-password
|
|
138
|
-
* bob@example.com --debug` set Bob's password to the literal `--debug` — and
|
|
139
|
-
* `--debug` is what `bin/rebase.js` prints after *every* failure as the thing
|
|
140
|
-
* to re-run with, so the single most likely next keystroke after a failed
|
|
141
|
-
* reset was the one that reset the account to a two-word string.
|
|
142
|
-
* - **`slice(4)` assumes the command words are at fixed indices.** They are
|
|
143
|
-
* not: a flag before the command shifts everything, so `rebase --debug auth
|
|
144
|
-
* reset-password bob@example.com NewPass1!` read the email as
|
|
145
|
-
* `reset-password` and the password as `bob@example.com`.
|
|
146
|
-
*
|
|
147
|
-
* So: parse the *whole* line — `rawArgs` is `process.argv` — against a spec
|
|
148
|
-
* strictly, with no permissive mode. `arg` then consumes every flag wherever it
|
|
149
|
-
* appears and rejects the ones nobody declared, which leaves `_` holding the
|
|
150
|
-
* command words followed by the real positionals, in order and at a known
|
|
151
|
-
* offset. An unrecognised flag becomes an error naming the command's help,
|
|
152
|
-
* which is the only safe answer: the alternative is guessing that it was meant
|
|
153
|
-
* as a value.
|
|
154
|
-
*
|
|
155
|
-
* `commands/cloud/index.ts` resolves its positionals against its own spec for
|
|
156
|
-
* the same reason; this is that idea for the commands whose positionals are
|
|
157
|
-
* credentials rather than resource names.
|
|
158
|
-
*/
|
|
159
|
-
/**
|
|
160
|
-
* Flags accepted on top of whatever a command declares.
|
|
161
|
-
*
|
|
162
|
-
* `--debug` is read by `bin/rebase.js` off `process.argv` and never by a
|
|
163
|
-
* command, but it has to be *declared* somewhere or strict parsing rejects the
|
|
164
|
-
* exact flag the CLI tells people to add. `--help`/`-h` are answered by each
|
|
165
|
-
* command's dispatcher before any work happens.
|
|
166
|
-
*/
|
|
167
|
-
var GLOBAL_COMMAND_FLAGS = {
|
|
168
|
-
"--debug": Boolean,
|
|
169
|
-
"--help": Boolean,
|
|
170
|
-
"-h": "--help"
|
|
171
|
-
};
|
|
172
|
-
/**
|
|
173
|
-
* The declared long flag an undeclared one was probably meant to be: one edit
|
|
174
|
-
* or one swap away (`--form` → `--from`), or an abbreviation of exactly one
|
|
175
|
-
* (`--anon` → `--anonymize`).
|
|
176
|
-
*/
|
|
177
|
-
function closestDeclaredFlag(typed, declared) {
|
|
178
|
-
if (!typed.startsWith("--")) return void 0;
|
|
179
|
-
const near = suggestCommand(typed.slice(2), declared.filter((flag) => flag.startsWith("--")).map((flag) => flag.slice(2)));
|
|
180
|
-
return near ? `--${near}` : void 0;
|
|
181
|
-
}
|
|
182
|
-
/** Past this many, a refusal names the help page rather than listing every flag. */
|
|
183
|
-
var LISTED_FLAGS_MAX = 8;
|
|
184
|
-
/**
|
|
185
|
-
* The sentence an undeclared flag is refused with — the one `db backup`,
|
|
186
|
-
* `db restore` and `db branch` say, so one CLI answers a typo one way:
|
|
187
|
-
*
|
|
188
|
-
* `rebase db pull` has no option --anonymise — did you mean --anonymize?
|
|
189
|
-
* Nothing was run. See `rebase db pull --help`.
|
|
190
|
-
*
|
|
191
|
-
* With nothing close it lists what the command takes, when that list is short
|
|
192
|
-
* enough to read.
|
|
193
|
-
*
|
|
194
|
-
* Exported for the commands that refuse a flag outside `parseCommandArgs`.
|
|
195
|
-
*/
|
|
196
|
-
function unknownOptionMessage(command, typed, spec) {
|
|
197
|
-
const near = closestDeclaredFlag(typed, Object.keys({
|
|
198
|
-
...GLOBAL_COMMAND_FLAGS,
|
|
199
|
-
...spec
|
|
200
|
-
}));
|
|
201
|
-
const own = Object.keys(spec).filter((flag) => flag.startsWith("--") && !(flag in GLOBAL_COMMAND_FLAGS));
|
|
202
|
-
return `\`rebase ${command}\` has no option ${typed}${near ? ` — did you mean ${near}?` : own.length === 0 ? " — it takes no options." : own.length <= LISTED_FLAGS_MAX ? ` — it takes ${own.join(", ")}.` : "."} Nothing was run. See \`rebase ${command} --help\`.`;
|
|
203
|
-
}
|
|
204
|
-
/** Did the line ask for help? Answered before dispatch, never by a handler. */
|
|
205
|
-
function wantsHelp(rawArgs) {
|
|
206
|
-
return rawArgs.includes("--help") || rawArgs.includes("-h");
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* The command line was wrong — nothing ran, and there is no stack to want.
|
|
210
|
-
*
|
|
211
|
-
* `bin/rebase.js` ends every failure with "Re-run with --debug for the stack
|
|
212
|
-
* trace.", which is right when something broke inside a command and absurd for
|
|
213
|
-
* a typo: the stack points at `arg` and this file, neither of which the person
|
|
214
|
-
* who mistyped `--ouput` has any interest in. Worse, `--debug` is a flag, so
|
|
215
|
-
* the suggested next command is *another* command line — and the one thing we
|
|
216
|
-
* have just established is that the command line is what went wrong.
|
|
217
|
-
*
|
|
218
|
-
* Marked with a property rather than left to `instanceof`, because the reader
|
|
219
|
-
* is `bin/rebase.js`: it imports the bundle, so the class object it would test
|
|
220
|
-
* against is not the one this file compiled to.
|
|
221
|
-
*/
|
|
222
|
-
var UsageError = class extends Error {
|
|
223
|
-
isUsageError = true;
|
|
224
|
-
constructor(message) {
|
|
225
|
-
super(message);
|
|
226
|
-
this.name = "UsageError";
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
/**
|
|
230
|
-
* Resolve a command's flags and positionals from the full `process.argv`.
|
|
231
|
-
*
|
|
232
|
-
* `commandWords` is how many words name the command itself — 2 for
|
|
233
|
-
* `auth reset-password`, 1 for `start` — and is applied to the *parsed*
|
|
234
|
-
* positionals rather than to `argv`, so a flag placed before the command no
|
|
235
|
-
* longer shifts them.
|
|
236
|
-
*
|
|
237
|
-
* `command` names the command in error messages, e.g. `auth reset-password`.
|
|
238
|
-
*
|
|
239
|
-
* Throws on an unknown flag, on a positional that looks like a flag, and on
|
|
240
|
-
* more positionals than the command takes. `bin/rebase.js` turns each into a
|
|
241
|
-
* one-line `✗ …` and exit 1.
|
|
242
|
-
*/
|
|
243
|
-
function parseCommandArgs({ spec, rawArgs, commandWords, command, maxPositionals }) {
|
|
244
|
-
let parsed;
|
|
245
|
-
try {
|
|
246
|
-
parsed = arg({
|
|
247
|
-
...GLOBAL_COMMAND_FLAGS,
|
|
248
|
-
...spec
|
|
249
|
-
}, { argv: rawArgs.slice(2) });
|
|
250
|
-
} catch (err) {
|
|
251
|
-
if (err instanceof Error && err.code === "ARG_UNKNOWN_OPTION") throw new UsageError(unknownOptionMessage(command, (/option: (\S+)$/.exec(err.message)?.[1] ?? err.message).split("=")[0], spec));
|
|
252
|
-
throw err;
|
|
253
|
-
}
|
|
254
|
-
const positionals = parsed._.slice(commandWords);
|
|
255
|
-
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\`).`);
|
|
256
|
-
if (maxPositionals !== void 0 && positionals.length > maxPositionals) throw new UsageError(`rebase ${command} takes ${maxPositionals} argument${maxPositionals === 1 ? "" : "s"}, got ${positionals.length}: ${redactConnectionPasswords(positionals.join(" "))}`);
|
|
257
|
-
return {
|
|
258
|
-
flags: parsed,
|
|
259
|
-
positionals,
|
|
260
|
-
help: Boolean(parsed["--help"])
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
//#endregion
|
|
264
|
-
export { unknownCommand as a, suggestCommand as i, parseCommandArgs as n, unknownCommandMessage as o, wantsHelp as r, redactConnectionPasswords as s, UsageError as t };
|
|
265
|
-
|
|
266
|
-
//# sourceMappingURL=args-BX0YD14a.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"args-BX0YD14a.js","names":[],"sources":["../src/utils/redact.ts","../src/utils/unknown-command.ts","../src/utils/args.ts"],"sourcesContent":["/**\n * Connection-string passwords, replaced before a line is printed.\n *\n * A refusal that repeats what was typed repeats a password with it, and these\n * lines land in terminals, CI logs and issues. `user:***@` is the form every\n * other message uses: the driver's `redactConnectionPasswords` in\n * `@rebasepro/server-postgres`, which its entry does not export, and this\n * mirrors. Covers the user-info password and a `password=` parameter.\n */\nexport function redactConnectionPasswords(text: string): string {\n return text\n .replace(/(\\b[a-z][a-z0-9+.-]*:\\/\\/[^\\s/?#@'\"]*):[^\\s/?#'\"]*@/gi, \"$1:***@\")\n .replace(/(\\bpassword\\s*=\\s*)('[^']*'|[^\\s&'\"]+)/gi, \"$1***\");\n}\n","/**\n * What every command family says when it does not recognise a subcommand.\n *\n * Six families each did it differently, and the differences were not stylistic:\n *\n * rebase statsu \"Unknown command: statsu\" + the whole top-level help\n * rebase auth foo \"Unknown auth command: foo\" + the whole auth help\n * rebase apps foo \"Unknown subcommand: foo\" — which command's?\n * rebase skills foo \"Unknown skills subcommand: foo\" + the whole help\n * rebase telemetry x the help, silently, with exit code 1 and no error line\n * rebase cloud debug x both a JSON error *and* the human one, in JSON mode\n *\n * Dumping a screen of help after an error is the wrong shape: the one line that\n * says what happened scrolls off the top, and in a CI log it is buried in\n * forty. None of them offered the correction, which for a typo is the entire\n * answer — `statsu` is one transposition from `status`.\n *\n * So: one line, the near-miss when there is one, and where to read the rest.\n */\nimport chalk from \"chalk\";\n\n/**\n * Damerau–Levenshtein distance, capped by the caller.\n *\n * The transposition is the reason this is not plain Levenshtein: `statsu` for\n * `status` and `craete` for `create` are the two most common typing errors\n * there are, and both are distance 2 without it — the same as two unrelated\n * edits, which is too far to suggest anything at all.\n */\nfunction editDistance(a: string, b: string): number {\n const rows = a.length + 1;\n const cols = b.length + 1;\n const d: number[][] = Array.from({ length: rows }, () => new Array<number>(cols).fill(0));\n\n for (let i = 0; i < rows; i++) d[i][0] = i;\n for (let j = 0; j < cols; j++) d[0][j] = j;\n\n for (let i = 1; i < rows; i++) {\n for (let j = 1; j < cols; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n d[i][j] = Math.min(\n d[i - 1][j] + 1,\n d[i][j - 1] + 1,\n d[i - 1][j - 1] + cost\n );\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);\n }\n }\n }\n return d[a.length][b.length];\n}\n\n/**\n * The one command the user probably meant, or nothing.\n *\n * Tight on purpose. A suggestion that is wrong is worse than none: it sends\n * someone to read the help for a command that was never the answer, and on a\n * family like `db` — where `push` and `pull` are one edit apart — a loose\n * threshold would confidently propose the destructive neighbour of what they\n * typed. So: one edit for a short word, two for a long one, and a prefix match\n * always counts (`rebase cloud dep` for `deploy`).\n */\nexport function suggestCommand(typed: string, known: readonly string[]): string | undefined {\n const word = typed.toLowerCase();\n if (!word) return undefined;\n\n // An abbreviation, but only when it names exactly one command. \"res\" is a\n // prefix of both `reset` and `restore`, and picking whichever comes first\n // in the list would be a coin toss dressed up as an answer.\n if (word.length >= 3) {\n const prefixed = known.filter(name => name.toLowerCase().startsWith(word));\n if (prefixed.length === 1) return prefixed[0];\n }\n\n const budget = word.length <= 4 ? 1 : 2;\n let best: { name: string; distance: number } | undefined;\n\n for (const candidate of known) {\n const distance = editDistance(word, candidate.toLowerCase());\n if (distance > budget) continue;\n if (!best || distance < best.distance) best = { name: candidate, distance };\n }\n\n return best?.name;\n}\n\n/**\n * The family command a word names exactly, as `<family> <command>`, or nothing.\n *\n * `rebase deploy` is `rebase cloud deploy`: the word is a whole command one\n * level down. Exact only — a near miss there is a guess about both the family\n * and the command.\n */\nfunction familyCommand(typed: string, families: Readonly<Record<string, readonly string[]>>): string | undefined {\n const word = typed.toLowerCase();\n for (const [family, commands] of Object.entries(families)) {\n const match = commands.find(name => name.toLowerCase() === word);\n if (match) return `${family} ${match}`;\n }\n return undefined;\n}\n\n/**\n * The line itself, without printing it — so callers that must answer in JSON\n * (the cloud family, whose `fail()` writes a machine-readable envelope) use the\n * same words as the ones that print.\n *\n * `family` is empty for the top level: `rebase --help`, not `rebase --help`.\n * `families` are the command families below this level, by name, whose\n * commands a word may be one of.\n */\nexport function unknownCommandMessage(\n typed: string | undefined,\n known: readonly string[],\n family = \"\",\n families: Readonly<Record<string, readonly string[]>> = {}\n): string {\n const what = family ? `${family} command` : \"command\";\n const suggestion = typed ? suggestCommand(typed, known) ?? familyCommand(typed, families) : undefined;\n const help = family ? `rebase ${family} --help` : \"rebase --help\";\n\n return suggestion\n ? `Unknown ${what} \"${typed}\" — did you mean \\`${suggestion}\\`? Run \\`${help}\\` for the rest.`\n : `Unknown ${what} \"${typed ?? \"\"}\". Run \\`${help}\\` for the ones there are.`;\n}\n\n/**\n * Print the line to stderr and exit 1.\n *\n * stderr, not stdout: a mistyped command is a failure, and the families with a\n * `--json` mode guarantee that stdout holds only their envelope.\n */\nexport function unknownCommand(\n typed: string | undefined,\n known: readonly string[],\n family = \"\",\n families: Readonly<Record<string, readonly string[]>> = {}\n): never {\n console.error(chalk.red(`✗ ${unknownCommandMessage(typed, known, family, families)}`));\n process.exit(1);\n}\n","/**\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\nimport { redactConnectionPasswords } from \"./redact\";\nimport { suggestCommand } from \"./unknown-command\";\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\n/**\n * The declared long flag an undeclared one was probably meant to be: one edit\n * or one swap away (`--form` → `--from`), or an abbreviation of exactly one\n * (`--anon` → `--anonymize`).\n */\nfunction closestDeclaredFlag(typed: string, declared: readonly string[]): string | undefined {\n if (!typed.startsWith(\"--\")) return undefined;\n const near = suggestCommand(typed.slice(2), declared.filter(flag => flag.startsWith(\"--\")).map(flag => flag.slice(2)));\n return near ? `--${near}` : undefined;\n}\n\n/** Past this many, a refusal names the help page rather than listing every flag. */\nconst LISTED_FLAGS_MAX = 8;\n\n/**\n * The sentence an undeclared flag is refused with — the one `db backup`,\n * `db restore` and `db branch` say, so one CLI answers a typo one way:\n *\n * `rebase db pull` has no option --anonymise — did you mean --anonymize?\n * Nothing was run. See `rebase db pull --help`.\n *\n * With nothing close it lists what the command takes, when that list is short\n * enough to read.\n *\n * Exported for the commands that refuse a flag outside `parseCommandArgs`.\n */\nexport function unknownOptionMessage(command: string, typed: string, spec: Readonly<Record<string, unknown>>): string {\n const declared = Object.keys({ ...GLOBAL_COMMAND_FLAGS, ...spec });\n const near = closestDeclaredFlag(typed, declared);\n const own = Object.keys(spec).filter(flag => flag.startsWith(\"--\") && !(flag in GLOBAL_COMMAND_FLAGS));\n const takes = near\n ? ` — did you mean ${near}?`\n : own.length === 0\n ? \" — it takes no options.\"\n : own.length <= LISTED_FLAGS_MAX ? ` — it takes ${own.join(\", \")}.` : \".\";\n\n return `\\`rebase ${command}\\` has no option ${typed}${takes} Nothing was run. See \\`rebase ${command} --help\\`.`;\n}\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 // arg's wording: `unknown or unexpected option: --form`.\n const typed = /option: (\\S+)$/.exec(err.message)?.[1] ?? err.message;\n throw new UsageError(unknownOptionMessage(command, typed.split(\"=\")[0], spec));\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 // Redacted: a connection string passed where a flag's value belongs\n // (`rebase db pull \"$PROD\"`) is still a password.\n throw new UsageError(\n `rebase ${command} takes ${maxPositionals} argument${maxPositionals === 1 ? \"\" : \"s\"}, ` +\n `got ${positionals.length}: ${redactConnectionPasswords(positionals.join(\" \"))}`\n );\n }\n\n return {\n flags: parsed,\n positionals,\n help: Boolean(parsed[\"--help\"])\n };\n}\n"],"mappings":"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"}
|