@rebasepro/cli 0.25.0-canary.ge06257e → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/bin/rebase.js +9 -5
  2. package/dist/{agent-setup-C83DXnlx.js → agent-setup-BYb2Tbdz.js} +2 -2
  3. package/dist/{agent-setup-C83DXnlx.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
  4. package/dist/{api-keys-Bc4FJKYp.js → api-keys-CSMbsmAn.js} +28 -22
  5. package/dist/api-keys-CSMbsmAn.js.map +1 -0
  6. package/dist/{apps-wG-ZTryA.js → apps-iBXNZhVN.js} +6 -7
  7. package/dist/{apps-wG-ZTryA.js.map → apps-iBXNZhVN.js.map} +1 -1
  8. package/dist/{atlas-dev-database-DeK3Sa4h.js → atlas-dev-database-BusbHP6n.js} +4 -4
  9. package/dist/{atlas-dev-database-DeK3Sa4h.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
  10. package/dist/{auth-BL7bNQVu.js → auth-DRsTWPky.js} +77 -11
  11. package/dist/auth-DRsTWPky.js.map +1 -0
  12. package/dist/{branch-pointer-DTQNLFtb.js → branch-pointer-Bn_FjNld.js} +1 -1
  13. package/dist/{build-h_7Re-67.js → build-et7Rccxi.js} +6 -7
  14. package/dist/{build-h_7Re-67.js.map → build-et7Rccxi.js.map} +1 -1
  15. package/dist/{bundle-CqURVN-K.js → bundle-DlqkDYSe.js} +6 -21
  16. package/dist/bundle-DlqkDYSe.js.map +1 -0
  17. package/dist/{cloud-DVV_5GPG.js → cloud-B-ZIjHrA.js} +10 -11
  18. package/dist/{cloud-DVV_5GPG.js.map → cloud-B-ZIjHrA.js.map} +1 -1
  19. package/dist/commands/api-keys.d.ts +4 -1
  20. package/dist/commands/auth.d.ts +3 -2
  21. package/dist/commands/dev.d.ts +12 -0
  22. package/dist/commands/generate_sdk.d.ts +4 -2
  23. package/dist/commands/init.d.ts +20 -0
  24. package/dist/commands/start.d.ts +10 -0
  25. package/dist/commands/upgrade.d.ts +12 -0
  26. package/dist/connection-banner-DbLJzWf4.js +128 -0
  27. package/dist/connection-banner-DbLJzWf4.js.map +1 -0
  28. package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
  29. package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
  30. package/dist/{console-Dw3HLdUs.js → console-BlD9kjFW.js} +4 -4
  31. package/dist/{console-Dw3HLdUs.js.map → console-BlD9kjFW.js.map} +1 -1
  32. package/dist/{context-BM-oOMNX.js → context-DHiiiJ5C.js} +3 -4
  33. package/dist/context-DHiiiJ5C.js.map +1 -0
  34. package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
  35. package/dist/daemon-DDMRbz4T.js.map +1 -0
  36. package/dist/{daemon-entry-C6pxdily.js → daemon-entry-zOC1revO.js} +204 -5
  37. package/dist/daemon-entry-zOC1revO.js.map +1 -0
  38. package/dist/{db-Dkn9XhT-.js → db-9P6MnmdC.js} +237 -86
  39. package/dist/db-9P6MnmdC.js.map +1 -0
  40. package/dist/{derive-Dl0z2OWi.js → derive-MTdClnkc.js} +29 -14
  41. package/dist/{derive-Dl0z2OWi.js.map → derive-MTdClnkc.js.map} +1 -1
  42. package/dist/{dev-DAcZR4Pp.js → dev-BDN_OKXA.js} +183 -23
  43. package/dist/dev-BDN_OKXA.js.map +1 -0
  44. package/dist/dev-db/connection-banner.d.ts +47 -0
  45. package/dist/dev-db/daemon.d.ts +41 -0
  46. package/dist/dev-db/notification-proxy.d.ts +82 -1
  47. package/dist/dev-db/pull.d.ts +33 -5
  48. package/dist/dev-db/state.d.ts +9 -0
  49. package/dist/{dev-preflight-CorMg7Ub.js → dev-preflight-FT9GbJVj.js} +73 -4
  50. package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
  51. package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
  52. package/dist/dev-server-CIZwAfZa.js.map +1 -0
  53. package/dist/{doctor-Ds_lzc9p.js → doctor-D8YXz7df.js} +6 -6
  54. package/dist/doctor-D8YXz7df.js.map +1 -0
  55. package/dist/{eject-CJHkfnat.js → eject-izG2KjMo.js} +3 -4
  56. package/dist/{eject-CJHkfnat.js.map → eject-izG2KjMo.js.map} +1 -1
  57. package/dist/{fold-static-BC9CYicw.js → fold-static-CybSay_W.js} +3 -3
  58. package/dist/{fold-static-BC9CYicw.js.map → fold-static-CybSay_W.js.map} +1 -1
  59. package/dist/{generate_sdk-kfkZmG-d.js → generate_sdk-B4R65oUV.js} +22 -12
  60. package/dist/generate_sdk-B4R65oUV.js.map +1 -0
  61. package/dist/index.es.js +36 -37
  62. package/dist/index.es.js.map +1 -1
  63. package/dist/{init-CjoJoThg.js → init-DYaeppEN.js} +52 -63
  64. package/dist/init-DYaeppEN.js.map +1 -0
  65. package/dist/invoked-command-CG_rIa_o.js +55 -0
  66. package/dist/invoked-command-CG_rIa_o.js.map +1 -0
  67. package/dist/last-dev-database-B_75fxZC.js +2 -0
  68. package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
  69. package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
  70. package/dist/{normalize-imports-BHxL2d05.js → normalize-imports-BYw8ad87.js} +3 -3
  71. package/dist/{normalize-imports-BHxL2d05.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
  72. package/dist/precompress.d.ts +0 -7
  73. package/dist/{prepare-C1iaiTC4.js → prepare-1rVNd2PF.js} +7 -6
  74. package/dist/prepare-1rVNd2PF.js.map +1 -0
  75. package/dist/project-g4K6kV1t.js +701 -0
  76. package/dist/project-g4K6kV1t.js.map +1 -0
  77. package/dist/{pull-COpNJFzY.js → pull-DDMpsZ5r.js} +143 -63
  78. package/dist/pull-DDMpsZ5r.js.map +1 -0
  79. package/dist/refusal-ReeeGP8a.js +26 -0
  80. package/dist/refusal-ReeeGP8a.js.map +1 -0
  81. package/dist/resolve-BQUAC3Wi.js +2 -0
  82. package/dist/resources/derive.d.ts +9 -0
  83. package/dist/{resources-CLm6g0br.js → resources-CovP8AZ-.js} +4 -5
  84. package/dist/{resources-CLm6g0br.js.map → resources-CovP8AZ-.js.map} +1 -1
  85. package/dist/{schema-BKdh6UoE.js → schema-nuxvvc50.js} +5 -6
  86. package/dist/{schema-BKdh6UoE.js.map → schema-nuxvvc50.js.map} +1 -1
  87. package/dist/{skills-DEhYiPeO.js → skills-DeUIsZcT.js} +3 -4
  88. package/dist/{skills-DEhYiPeO.js.map → skills-DeUIsZcT.js.map} +1 -1
  89. package/dist/{start-BsPJedPQ.js → start-RzZqDroW.js} +20 -7
  90. package/dist/start-RzZqDroW.js.map +1 -0
  91. package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
  92. package/dist/state-CYdBvnwA.js.map +1 -0
  93. package/dist/{status-D_B3tlDy.js → status-D9Zm88NZ.js} +11 -12
  94. package/dist/{status-D_B3tlDy.js.map → status-D9Zm88NZ.js.map} +1 -1
  95. package/dist/{storage-CtB8polS.js → storage-BB3umRfw.js} +3 -4
  96. package/dist/{storage-CtB8polS.js.map → storage-BB3umRfw.js.map} +1 -1
  97. package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
  98. package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
  99. package/dist/{telemetry-BYmPU-Ji.js → telemetry-TseNLk6X.js} +4 -4
  100. package/dist/{telemetry-BYmPU-Ji.js.map → telemetry-TseNLk6X.js.map} +1 -1
  101. package/dist/{upgrade-DbuKX9lv.js → upgrade-apiPKKE_.js} +29 -6
  102. package/dist/{upgrade-DbuKX9lv.js.map → upgrade-apiPKKE_.js.map} +1 -1
  103. package/dist/utils/args.d.ts +45 -3
  104. package/dist/utils/boot-retry.d.ts +41 -0
  105. package/dist/utils/dev-preflight.d.ts +34 -1
  106. package/dist/utils/dev-server.d.ts +11 -0
  107. package/dist/utils/project.d.ts +5 -1
  108. package/dist/utils/redact.d.ts +10 -0
  109. package/dist/utils/refusal.d.ts +18 -0
  110. package/dist/utils/unknown-command.d.ts +4 -0
  111. package/package.json +7 -7
  112. package/templates/overlays/baas/README.md +2 -1
  113. package/templates/resource-graphs/blank.json +25 -0
  114. package/templates/resource-graphs/blog.json +28 -0
  115. package/templates/resource-graphs/ecommerce.json +28 -0
  116. package/templates/resource-graphs/headless.json +22 -0
  117. package/templates/template/.env.example +11 -4
  118. package/templates/template/frontend/src/App.tsx +10 -9
  119. package/templates/template/frontend/vite.config.ts +7 -73
  120. package/dist/api-keys-Bc4FJKYp.js.map +0 -1
  121. package/dist/args-CcBphFdj.js +0 -237
  122. package/dist/args-CcBphFdj.js.map +0 -1
  123. package/dist/auth-BL7bNQVu.js.map +0 -1
  124. package/dist/bundle-CqURVN-K.js.map +0 -1
  125. package/dist/context-BM-oOMNX.js.map +0 -1
  126. package/dist/daemon-CknkDjd6.js.map +0 -1
  127. package/dist/daemon-entry-C6pxdily.js.map +0 -1
  128. package/dist/db-Dkn9XhT-.js.map +0 -1
  129. package/dist/dev-DAcZR4Pp.js.map +0 -1
  130. package/dist/dev-preflight-CorMg7Ub.js.map +0 -1
  131. package/dist/dev-server-B1UYifZJ.js.map +0 -1
  132. package/dist/doctor-Ds_lzc9p.js.map +0 -1
  133. package/dist/generate_sdk-kfkZmG-d.js.map +0 -1
  134. package/dist/init-CjoJoThg.js.map +0 -1
  135. package/dist/last-dev-database-BEBPfAMY.js +0 -2
  136. package/dist/prepare-C1iaiTC4.js.map +0 -1
  137. package/dist/project-Wp2zoyeN.js +0 -349
  138. package/dist/project-Wp2zoyeN.js.map +0 -1
  139. package/dist/pull-COpNJFzY.js.map +0 -1
  140. package/dist/resolve-b_p9bmdH.js +0 -2
  141. package/dist/start-BsPJedPQ.js.map +0 -1
  142. package/dist/state-CCB-FAQ9.js.map +0 -1
@@ -1,237 +0,0 @@
1
- import chalk from "chalk";
2
- import arg from "arg";
3
- //#region src/utils/unknown-command.ts
4
- /**
5
- * What every command family says when it does not recognise a subcommand.
6
- *
7
- * Six families each did it differently, and the differences were not stylistic:
8
- *
9
- * rebase statsu "Unknown command: statsu" + the whole top-level help
10
- * rebase auth foo "Unknown auth command: foo" + the whole auth help
11
- * rebase apps foo "Unknown subcommand: foo" — which command's?
12
- * rebase skills foo "Unknown skills subcommand: foo" + the whole help
13
- * rebase telemetry x the help, silently, with exit code 1 and no error line
14
- * rebase cloud debug x both a JSON error *and* the human one, in JSON mode
15
- *
16
- * Dumping a screen of help after an error is the wrong shape: the one line that
17
- * says what happened scrolls off the top, and in a CI log it is buried in
18
- * forty. None of them offered the correction, which for a typo is the entire
19
- * answer — `statsu` is one transposition from `status`.
20
- *
21
- * So: one line, the near-miss when there is one, and where to read the rest.
22
- */
23
- /**
24
- * Damerau–Levenshtein distance, capped by the caller.
25
- *
26
- * The transposition is the reason this is not plain Levenshtein: `statsu` for
27
- * `status` and `craete` for `create` are the two most common typing errors
28
- * there are, and both are distance 2 without it — the same as two unrelated
29
- * edits, which is too far to suggest anything at all.
30
- */
31
- function editDistance(a, b) {
32
- const rows = a.length + 1;
33
- const cols = b.length + 1;
34
- const d = Array.from({ length: rows }, () => new Array(cols).fill(0));
35
- for (let i = 0; i < rows; i++) d[i][0] = i;
36
- for (let j = 0; j < cols; j++) d[0][j] = j;
37
- for (let i = 1; i < rows; i++) for (let j = 1; j < cols; j++) {
38
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
39
- d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
40
- 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);
41
- }
42
- return d[a.length][b.length];
43
- }
44
- /**
45
- * The one command the user probably meant, or nothing.
46
- *
47
- * Tight on purpose. A suggestion that is wrong is worse than none: it sends
48
- * someone to read the help for a command that was never the answer, and on a
49
- * family like `db` — where `push` and `pull` are one edit apart — a loose
50
- * threshold would confidently propose the destructive neighbour of what they
51
- * typed. So: one edit for a short word, two for a long one, and a prefix match
52
- * always counts (`rebase cloud dep` for `deploy`).
53
- */
54
- function suggestCommand(typed, known) {
55
- const word = typed.toLowerCase();
56
- if (!word) return void 0;
57
- if (word.length >= 3) {
58
- const prefixed = known.filter((name) => name.toLowerCase().startsWith(word));
59
- if (prefixed.length === 1) return prefixed[0];
60
- }
61
- const budget = word.length <= 4 ? 1 : 2;
62
- let best;
63
- for (const candidate of known) {
64
- const distance = editDistance(word, candidate.toLowerCase());
65
- if (distance > budget) continue;
66
- if (!best || distance < best.distance) best = {
67
- name: candidate,
68
- distance
69
- };
70
- }
71
- return best?.name;
72
- }
73
- /**
74
- * The family command a word names exactly, as `<family> <command>`, or nothing.
75
- *
76
- * `rebase deploy` is `rebase cloud deploy`: the word is a whole command one
77
- * level down. Exact only — a near miss there is a guess about both the family
78
- * and the command.
79
- */
80
- function familyCommand(typed, families) {
81
- const word = typed.toLowerCase();
82
- for (const [family, commands] of Object.entries(families)) {
83
- const match = commands.find((name) => name.toLowerCase() === word);
84
- if (match) return `${family} ${match}`;
85
- }
86
- }
87
- /**
88
- * The line itself, without printing it — so callers that must answer in JSON
89
- * (the cloud family, whose `fail()` writes a machine-readable envelope) use the
90
- * same words as the ones that print.
91
- *
92
- * `family` is empty for the top level: `rebase --help`, not `rebase --help`.
93
- * `families` are the command families below this level, by name, whose
94
- * commands a word may be one of.
95
- */
96
- function unknownCommandMessage(typed, known, family = "", families = {}) {
97
- const what = family ? `${family} command` : "command";
98
- const suggestion = typed ? suggestCommand(typed, known) ?? familyCommand(typed, families) : void 0;
99
- const help = family ? `rebase ${family} --help` : "rebase --help";
100
- return suggestion ? `Unknown ${what} "${typed}" — did you mean \`${suggestion}\`? Run \`${help}\` for the rest.` : `Unknown ${what} "${typed ?? ""}". Run \`${help}\` for the ones there are.`;
101
- }
102
- /**
103
- * Print the line to stderr and exit 1.
104
- *
105
- * stderr, not stdout: a mistyped command is a failure, and the families with a
106
- * `--json` mode guarantee that stdout holds only their envelope.
107
- */
108
- function unknownCommand(typed, known, family = "", families = {}) {
109
- console.error(chalk.red(`✗ ${unknownCommandMessage(typed, known, family, families)}`));
110
- process.exit(1);
111
- }
112
- //#endregion
113
- //#region src/utils/args.ts
114
- /**
115
- * Argument parsing for the commands that take positional arguments.
116
- *
117
- * Every command in the small group used to parse its own line the same way:
118
- * `arg(spec, { argv: rawArgs.slice(4), permissive: true })`, then read `_[0]`
119
- * and `_[1]`. Both halves of that are wrong in a way that costs data.
120
- *
121
- * - **`permissive: true` turns an unknown flag into a positional.** `arg`
122
- * pushes an undeclared flag into `_` as a bare token, so `_[1]` is whatever
123
- * came second on the line, flag or not. `rebase auth reset-password
124
- * bob@example.com --debug` set Bob's password to the literal `--debug` — and
125
- * `--debug` is what `bin/rebase.js` prints after *every* failure as the thing
126
- * to re-run with, so the single most likely next keystroke after a failed
127
- * reset was the one that reset the account to a two-word string.
128
- * - **`slice(4)` assumes the command words are at fixed indices.** They are
129
- * not: a flag before the command shifts everything, so `rebase --debug auth
130
- * reset-password bob@example.com NewPass1!` read the email as
131
- * `reset-password` and the password as `bob@example.com`.
132
- *
133
- * So: parse the *whole* line — `rawArgs` is `process.argv` — against a spec
134
- * strictly, with no permissive mode. `arg` then consumes every flag wherever it
135
- * appears and rejects the ones nobody declared, which leaves `_` holding the
136
- * command words followed by the real positionals, in order and at a known
137
- * offset. An unrecognised flag becomes an error naming the command's help,
138
- * which is the only safe answer: the alternative is guessing that it was meant
139
- * as a value.
140
- *
141
- * `commands/cloud/index.ts` resolves its positionals against its own spec for
142
- * the same reason; this is that idea for the commands whose positionals are
143
- * credentials rather than resource names.
144
- */
145
- /**
146
- * Flags accepted on top of whatever a command declares.
147
- *
148
- * `--debug` is read by `bin/rebase.js` off `process.argv` and never by a
149
- * command, but it has to be *declared* somewhere or strict parsing rejects the
150
- * exact flag the CLI tells people to add. `--help`/`-h` are answered by each
151
- * command's dispatcher before any work happens.
152
- */
153
- var GLOBAL_COMMAND_FLAGS = {
154
- "--debug": Boolean,
155
- "--help": Boolean,
156
- "-h": "--help"
157
- };
158
- /**
159
- * The declared long flag an undeclared one was probably meant to be, from
160
- * `arg`'s `unknown or unexpected option: --form`: one edit or one swap away
161
- * (`--from`), the way the driver's flag check and `db backup` answer a typo.
162
- */
163
- function closestDeclaredFlag(argMessage, declared) {
164
- const typed = /option: (--[^\s=]+)/.exec(argMessage)?.[1];
165
- if (!typed) return void 0;
166
- const near = suggestCommand(typed.slice(2), declared.filter((flag) => flag.startsWith("--")).map((flag) => flag.slice(2)));
167
- return near ? `--${near}` : void 0;
168
- }
169
- /** Did the line ask for help? Answered before dispatch, never by a handler. */
170
- function wantsHelp(rawArgs) {
171
- return rawArgs.includes("--help") || rawArgs.includes("-h");
172
- }
173
- /**
174
- * The command line was wrong — nothing ran, and there is no stack to want.
175
- *
176
- * `bin/rebase.js` ends every failure with "Re-run with --debug for the stack
177
- * trace.", which is right when something broke inside a command and absurd for
178
- * a typo: the stack points at `arg` and this file, neither of which the person
179
- * who mistyped `--ouput` has any interest in. Worse, `--debug` is a flag, so
180
- * the suggested next command is *another* command line — and the one thing we
181
- * have just established is that the command line is what went wrong.
182
- *
183
- * Marked with a property rather than left to `instanceof`, because the reader
184
- * is `bin/rebase.js`: it imports the bundle, so the class object it would test
185
- * against is not the one this file compiled to.
186
- */
187
- var UsageError = class extends Error {
188
- isUsageError = true;
189
- constructor(message) {
190
- super(message);
191
- this.name = "UsageError";
192
- }
193
- };
194
- /**
195
- * Resolve a command's flags and positionals from the full `process.argv`.
196
- *
197
- * `commandWords` is how many words name the command itself — 2 for
198
- * `auth reset-password`, 1 for `start` — and is applied to the *parsed*
199
- * positionals rather than to `argv`, so a flag placed before the command no
200
- * longer shifts them.
201
- *
202
- * `command` names the command in error messages, e.g. `auth reset-password`.
203
- *
204
- * Throws on an unknown flag, on a positional that looks like a flag, and on
205
- * more positionals than the command takes. `bin/rebase.js` turns each into a
206
- * one-line `✗ …` and exit 1.
207
- */
208
- function parseCommandArgs({ spec, rawArgs, commandWords, command, maxPositionals }) {
209
- let parsed;
210
- try {
211
- parsed = arg({
212
- ...GLOBAL_COMMAND_FLAGS,
213
- ...spec
214
- }, { argv: rawArgs.slice(2) });
215
- } catch (err) {
216
- if (err instanceof Error && err.code === "ARG_UNKNOWN_OPTION") {
217
- const near = closestDeclaredFlag(err.message, Object.keys({
218
- ...GLOBAL_COMMAND_FLAGS,
219
- ...spec
220
- }));
221
- throw new UsageError(`${err.message}${near ? ` (did you mean ${near}?)` : ""} — run \`rebase ${command} --help\` for the options it takes.`);
222
- }
223
- throw err;
224
- }
225
- const positionals = parsed._.slice(commandWords);
226
- 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\`).`);
227
- if (maxPositionals !== void 0 && positionals.length > maxPositionals) throw new UsageError(`rebase ${command} takes ${maxPositionals} argument${maxPositionals === 1 ? "" : "s"}, got ${positionals.length}: ${positionals.join(" ")}`);
228
- return {
229
- flags: parsed,
230
- positionals,
231
- help: Boolean(parsed["--help"])
232
- };
233
- }
234
- //#endregion
235
- export { unknownCommand as a, suggestCommand as i, parseCommandArgs as n, unknownCommandMessage as o, wantsHelp as r, UsageError as t };
236
-
237
- //# sourceMappingURL=args-CcBphFdj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"args-CcBphFdj.js","names":[],"sources":["../src/utils/unknown-command.ts","../src/utils/args.ts"],"sourcesContent":["/**\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 { 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, from\n * `arg`'s `unknown or unexpected option: --form`: one edit or one swap away\n * (`--from`), the way the driver's flag check and `db backup` answer a typo.\n */\nfunction closestDeclaredFlag(argMessage: string, declared: readonly string[]): string | undefined {\n const typed = /option: (--[^\\s=]+)/.exec(argMessage)?.[1];\n if (!typed) 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\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 const near = closestDeclaredFlag(err.message, Object.keys({ ...GLOBAL_COMMAND_FLAGS, ...spec }));\n throw new UsageError(\n `${err.message}${near ? ` (did you mean ${near}?)` : \"\"} — 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":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-BL7bNQVu.js","names":[],"sources":["../src/commands/auth.ts"],"sourcesContent":["/**\n * CLI command: rebase auth <action>\n *\n * Subcommands:\n * reset-password — Reset a user's password\n */\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { spawn } from \"child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport {\n requireProjectRoot,\n requireBackendDir,\n findEnvFile,\n readEnvFile,\n resolveTsx,\n exitDependenciesNotInstalled\n} from \"../utils/project\";\nimport { unknownCommand } from \"../utils/unknown-command\";\n\n/** The backend was reached and refused: not a reason to fall back to the database. */\nclass ApiAnswered extends Error {}\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const AUTH_SUBCOMMANDS = [\"reset-password\"] as const;\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport { resolveBackendAddress } from \"./api-keys\";\n\n/** A user as the admin API returns it, reduced to what this command needs. */\nexport interface ResolvedUser {\n id: string;\n email: string;\n}\n\n/**\n * Pick the user with exactly this email out of a search response.\n *\n * `/api/admin/users?search=` is an `ILIKE '%…%'` over email **or display\n * name**, ordered by role count descending. This used to take row `[0]` and\n * reset it, then print the email it had been *given* as confirmation — so two\n * ordinary situations ended in a successful-looking reset of somebody else's\n * account:\n *\n * - a substring collision: `bob@example.com` also matches\n * `robert.bob@example.com`;\n * - a display name, which is user-controlled and accepted up to 255\n * characters with no constraint on its content, containing an address\n * belonging to someone else.\n *\n * The ordering makes it worse rather than better — `array_length(roles) DESC\n * NULLS LAST` puts the most privileged match first, so the account most likely\n * to be reset by mistake is an admin's.\n *\n * Returns `undefined` when nothing matched exactly, which the caller reports\n * rather than falling through to a guess. The direct-database fallback below\n * has always matched with `eq(usersTable.email, email)`; this is the same\n * definition, so the command no longer resets different accounts depending on\n * whether the backend happened to be running.\n */\nexport function selectUserForEmail(payload: unknown, email: string): ResolvedUser | undefined {\n const wanted = email.trim().toLowerCase();\n if (!wanted) return undefined;\n\n const rows: unknown[] = Array.isArray(payload)\n ? payload\n : (payload && typeof payload === \"object\" && Array.isArray((payload as { users?: unknown }).users)\n ? (payload as { users: unknown[] }).users\n : []);\n\n for (const row of rows) {\n if (!row || typeof row !== \"object\") continue;\n const record = row as Record<string, unknown>;\n const rowEmail = typeof record.email === \"string\" ? record.email.trim().toLowerCase() : undefined;\n if (!rowEmail || rowEmail !== wanted) continue;\n\n const id = typeof record.id === \"string\"\n ? record.id\n : (typeof record.uid === \"string\" ? record.uid : undefined);\n if (!id) continue;\n\n return { id, email: record.email as string };\n }\n\n return undefined;\n}\n\nexport async function authCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void> {\n // `--help` is answered here and never reaches a handler. `cli.ts` only\n // rewrites the subcommand to `\"--help\"` when no subcommand was named, so\n // `rebase auth reset-password --help` used to *run the reset*: `--help`\n // became the email, the backend was contacted, `.tmp-reset-password.ts` was\n // written into the user's `backend/`, and a database UPDATE ran for a user\n // named `--help`. A flag whose whole job is to print text cannot be allowed\n // to reach code that writes.\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printAuthHelp();\n return;\n }\n\n switch (subcommand) {\n case \"reset-password\":\n await resetPassword(rawArgs);\n break;\n default:\n unknownCommand(subcommand, AUTH_SUBCOMMANDS, \"auth\");\n }\n}\n\n/**\n * The flags `rebase auth reset-password` takes.\n *\n * `-p` was advertised in this command's own help and never declared here, so\n * `arg` — running permissively — pushed it into the positionals and the value\n * *after* it shifted out of reach: anyone following the help set the account's\n * password to the two-character string `-p`. Declared now, and `auth.test.ts`\n * asserts that the help and this spec list the same aliases.\n */\nexport const RESET_PASSWORD_FLAGS = {\n \"--email\": String,\n \"--password\": String,\n \"-e\": \"--email\",\n \"-p\": \"--password\"\n} as const;\n\n/**\n * Which account, and which password, this invocation names.\n *\n * Both may still be absent — the caller reports a missing email — but neither\n * can be a flag. `parseCommandArgs` parses the whole line strictly, so an\n * undeclared flag is an error rather than a positional. That is what stops\n * `rebase auth reset-password bob@example.com --debug` from setting Bob's\n * password to `--debug`, which is the flag the CLI itself prints after every\n * failure as the thing to re-run with.\n *\n * Exported so its tests can drive the real parser rather than a copy of it.\n */\nexport function resolveResetPasswordArgs(rawArgs: string[]): {\n email?: string;\n password?: string;\n} {\n const { flags, positionals } = parseCommandArgs({\n spec: RESET_PASSWORD_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"auth reset-password\",\n maxPositionals: 2\n });\n\n // Both spellings are supported: `<email> [password]` and `--email/--password`.\n return {\n email: flags[\"--email\"] || positionals[0],\n password: flags[\"--password\"] || positionals[1]\n };\n}\n\n/**\n * A password for a reset that was not given one.\n *\n * This used to be a constant, and `--help` printed it as the default. Reset is\n * the documented way back into an account nobody can sign in to — an admin,\n * usually — so the recovery path set every such account to a fixed string that\n * ships inside a public repository and a published npm package, and left it\n * there until somebody remembered to change it.\n *\n * base64url of 18 random bytes: 24 characters, ~144 bits, no shell-quoting\n * hazard, and nothing that reads like a placeholder somebody might keep.\n */\nexport function generatePassword(): string {\n return randomBytes(18).toString(\"base64url\");\n}\n\n/**\n * What a refusing backend said, from its `{ error: { message, code } }` body.\n *\n * The body used to be printed as it came, so a weak password read\n * `{\"error\":{\"message\":\"…\",\"code\":\"…\"}}`. A body that is not the envelope is\n * still shown, since it is the only account of the refusal there is.\n */\nasync function refusalReason(response: Response): Promise<string> {\n const text = await response.text().catch(() => \"\");\n try {\n const parsed: unknown = JSON.parse(text);\n const error = parsed && typeof parsed === \"object\" && \"error\" in parsed ? parsed.error : undefined;\n if (error && typeof error === \"object\" && \"message\" in error && typeof error.message === \"string\") {\n const code = \"code\" in error && typeof error.code === \"string\" ? ` (${error.code})` : \"\";\n return `${error.message}${code}`;\n }\n } catch {\n // Not JSON: the text is the answer.\n }\n return text.trim() || `${response.status} ${response.statusText}`.trim();\n}\n\nasync function resetPassword(rawArgs: string[]): Promise<void> {\n const { email, password: providedPassword } = resolveResetPasswordArgs(rawArgs);\n // Generated once, so both reset paths set and report the same thing.\n const wasGenerated = !providedPassword;\n const newPassword = providedPassword || generatePassword();\n\n if (!email) {\n console.error(chalk.red(\"✗ Email is required.\"));\n console.log(\"\");\n console.log(chalk.gray(\" Usage: rebase auth reset-password <email> [new-password]\"));\n console.log(chalk.gray(\" rebase auth reset-password --email user@example.com --password NewPass123!\"));\n process.exit(1);\n }\n\n const projectRoot = requireProjectRoot();\n\n // 1. Try API-first reset\n // Was a single-key regex, which did not match `export REBASE_SERVICE_KEY=…`\n // and kept a trailing `# comment` in the value. The command then fell\n // through to the direct-database path as though no key were configured.\n const envFile = findEnvFile(projectRoot);\n const envServiceKey: string | undefined = readEnvFile(projectRoot).REBASE_SERVICE_KEY;\n\n let serviceKey = process.env.REBASE_SERVICE_KEY || envServiceKey;\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 Record<string, unknown>;\n if (state && typeof state === \"object\" && typeof state.serviceKey === \"string\" && !serviceKey) {\n serviceKey = state.serviceKey;\n }\n } catch {\n // Ignore\n }\n }\n\n // Where the service key may go: a REBASE_BASE_URL the developer named, or\n // this project's backend while the pid that recorded it is alive — see\n // `resolveBackendAddress`. `.rebase/state.json`'s address on its own, and\n // `.rebase-dev-url`, outlive a killed `rebase dev`, and the port they name\n // may be another server's by now. With neither, the reset goes to the\n // database directly.\n const baseUrl = resolveBackendAddress(readEnvFile(projectRoot), projectRoot).url;\n\n if (baseUrl && serviceKey) {\n console.log(\"Trying API-first reset via running backend...\");\n try {\n const finalPass = newPassword;\n const cleanBaseUrl = baseUrl.replace(/\\/+$/, \"\");\n // Not `limit=1`: the search is fuzzy and ordered by role count, so\n // the exact match is not necessarily first — asking for one row can\n // make it unreachable. Ask for a page, then match exactly.\n const searchUrl = `${cleanBaseUrl}/api/admin/users?search=${encodeURIComponent(email)}&limit=50`;\n const searchRes = await fetch(searchUrl, {\n headers: {\n \"Authorization\": `Bearer ${serviceKey}`,\n \"Accept\": \"application/json\"\n }\n });\n if (!searchRes.ok) {\n throw new ApiAnswered(`Failed to list users: ${searchRes.status} ${searchRes.statusText}`);\n }\n const searchData = await searchRes.json() as unknown;\n if (!searchData || typeof searchData !== \"object\") {\n throw new Error(\"Invalid response format from user search API.\");\n }\n\n const matched = selectUserForEmail(searchData, email);\n if (!matched) {\n throw new ApiAnswered(`No user has the email ${email}.`);\n }\n\n const resetUrl = `${cleanBaseUrl}/api/admin/users/${matched.id}/reset-password`;\n const resetRes = await fetch(resetUrl, {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${serviceKey}`,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\"\n },\n body: JSON.stringify({ password: finalPass })\n });\n\n if (!resetRes.ok) {\n throw new ApiAnswered(`Password reset refused: ${await refusalReason(resetRes)}`);\n }\n\n console.log(\"API reset successful.\");\n console.log(chalk.bold(\" 🔑 Rebase Auth — Reset Password (via API)\"));\n console.log(\"\");\n // The address as stored, not as typed — they differ in case often\n // enough that echoing the input hides which account was touched.\n console.log(` ${chalk.gray(\"Email:\")} ${matched.email}`);\n // Echoed only when we invented it. A password the operator typed\n // is already theirs; printing it again only adds scrollback.\n console.log(` ${chalk.gray(\"Password:\")} ${wasGenerated ? finalPass : \"*\".repeat(finalPass.length)}`);\n console.log(\"\");\n return;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n // The backend answered and said no — a password too weak, a user\n // it does not have. That answer stands: writing the hash straight\n // into the database instead skipped the strength rule it had just\n // applied, and ended no sessions. Only a backend that could not be\n // reached is a reason to go round it.\n if (err instanceof ApiAnswered) {\n console.error(chalk.red(`✗ ${errMsg}`));\n process.exitCode = 1;\n return;\n }\n console.warn(chalk.yellow(\"API reset failed, falling back to direct database update...\"));\n console.warn(chalk.gray(` Details: ${errMsg}`));\n }\n }\n\n // 2. Direct-DB Fallback\n const backendDir = requireBackendDir(projectRoot);\n const tsxBin = resolveTsx(projectRoot);\n\n if (!tsxBin) {\n exitDependenciesNotInstalled(projectRoot);\n }\n\n try {\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (envFile) {\n env.DOTENV_CONFIG_PATH = envFile;\n }\n env.REBASE_RESET_EMAIL = email;\n env.REBASE_RESET_PASSWORD = newPassword;\n env.REBASE_ENV_FILE_PATH = envFile || path.join(projectRoot, \".env\");\n\n // The database the `db` family would use, resolved the same way. A\n // stock scaffold leaves DATABASE_URL commented out and runs on the\n // managed database, which only exists in a child's environment when\n // something puts it there — without this the script connected with\n // libpq's defaults, localhost:5432 as the OS user. An external\n // DATABASE_URL adds nothing here: the child already reads it.\n const { prepareDatabaseEnv } = await import(\"../dev-db/prepare\");\n const prepared = await prepareDatabaseEnv(projectRoot, {\n onProgress: (message) => console.log(chalk.gray(` ${message}`))\n });\n Object.assign(env, prepared.env);\n\n const scriptContent = resetPasswordScript(wasGenerated);\n\n const tmpScriptPath = path.join(backendDir, \".tmp-reset-password.ts\");\n fs.writeFileSync(tmpScriptPath, scriptContent, \"utf-8\");\n\n console.log(\"\");\n console.log(chalk.bold(\" 🔑 Rebase Auth — Reset Password (Direct DB Fallback)\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Email:\")} ${email}`);\n console.log(` ${chalk.gray(\"Database:\")} ${prepared.description}`);\n if (!wasGenerated) {\n console.log(` ${chalk.gray(\"Password:\")} ${\"*\".repeat(newPassword.length)}`);\n }\n console.log(\"\");\n\n const child = spawn(tsxBin, [tmpScriptPath], {\n cwd: backendDir,\n stdio: \"inherit\",\n env\n });\n\n // The script is written into the user's backend directory, so every\n // exit has to remove it. Without an `error` handler a failed spawn\n // raises an unhandled event, the process dies before `close`, and\n // `.tmp-reset-password.ts` is left behind to be committed.\n const cleanup = () => {\n try { fs.unlinkSync(tmpScriptPath); } catch { /* already gone */ }\n };\n\n return new Promise((resolve) => {\n child.on(\"error\", (err) => {\n cleanup();\n console.error(chalk.red(\"✗ Could not run the reset script.\"));\n console.error(chalk.gray(` ${err.message}`));\n process.exit(1);\n });\n child.on(\"close\", (code) => {\n cleanup();\n if (code !== 0) {\n process.exit(code ?? 1);\n }\n resolve();\n });\n });\n } catch (err) {\n console.error(chalk.red(\"✗ Direct database update failed.\"));\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n/**\n * The script the direct-database fallback runs under the project's own tsx, so\n * it resolves the project's `@rebasepro/server-postgres` and schema.\n *\n * It ends the account's sessions in the transaction that sets the password,\n * as every door through the API does (`replaceUserPassword`): the refresh\n * tokens and outstanding reset links go, and `tokens_valid_after` voids the\n * access tokens already handed out. An operator resetting a phished account\n * with the backend down is the case this exists for, and a reset that left the\n * attacker's refresh token minting access tokens did not recover anything.\n *\n * It exits 0 only when a row was updated: a missing user and a thrown error are\n * both exit 1. `echoPassword` prints the new password, for a generated one.\n *\n * Exported so its tests can run it.\n */\nexport function resetPasswordScript(echoPassword: boolean): string {\n return `\nimport { createPostgresDatabaseConnection } from \"@rebasepro/server-postgres\";\nimport { hashPassword } from \"@rebasepro/server\";\nimport { getTableConfig } from \"drizzle-orm/pg-core\";\nimport * as dotenv from \"dotenv\";\nimport path from \"path\";\nimport fs from \"fs\";\n\ndotenv.config({ path: process.env.REBASE_ENV_FILE_PATH, quiet: true });\n\n// Lowercased, as every address is stored (\\`normalizeEmail\\`): matched as\n// typed, \"Ops@Acme.test\" found no row.\nconst email = process.env.REBASE_RESET_EMAIL!.trim().toLowerCase();\nconst newPassword = process.env.REBASE_RESET_PASSWORD!;\n\nconst quote = (identifier: string) => '\"' + identifier.replace(/\"/g, '\"\"') + '\"';\n\nasync function resetPassword() {\n const { pool } = createPostgresDatabaseConnection(process.env.DATABASE_URL!);\n const hash = await hashPassword(newPassword);\n\n let usersTable;\n try {\n const schemaPath = path.resolve(\"./src/schema.generated.ts\");\n if (fs.existsSync(schemaPath)) {\n const schema = await import(\"file://\" + schemaPath);\n usersTable = schema.users || schema.tables?.users;\n }\n } catch (e) {\n // ignore and fallback\n }\n\n if (!usersTable) {\n const pgServer = await import(\"@rebasepro/server-postgres\");\n usersTable = pgServer.users;\n }\n\n // The physical names, from the table object: the collection may map its\n // properties to other columns, and the statements below are plain SQL.\n const { name: tableName, schema: tableSchema } = getTableConfig(usersTable);\n const usersSchema = tableSchema || \"public\";\n const users = quote(usersSchema) + \".\" + quote(tableName);\n const idColumn = quote(usersTable.id.name);\n const emailColumn = quote(usersTable.email.name);\n const passwordColumn = quote((usersTable.passwordHash ?? usersTable.password_hash).name);\n // Where \\`ensureAuthTablesExist\\` puts the tables that hang off the users\n // table: beside it, or in \\`rebase\\` when it lives in \\`public\\`.\n const authSchema = usersSchema === \"public\" ? \"rebase\" : usersSchema;\n\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const updated = await client.query(\n \"UPDATE \" + users + \" SET \" + passwordColumn + \" = $1 WHERE \" + emailColumn + \" = $2 \" +\n \"RETURNING \" + idColumn + \" AS id, \" + emailColumn + \" AS email\",\n [hash, email]\n );\n if (updated.rows.length === 0) {\n await client.query(\"ROLLBACK\");\n // Nothing was updated, so nothing was reset. Exiting 0 here reported\n // success for a no-op, which is what a script would have believed.\n console.error(\"✗ User not found: \" + email);\n process.exit(1);\n }\n const uid = updated.rows[0].id;\n\n // A table or column the server has not created yet (it never booted\n // against this database) holds no session to end.\n const watermark = await client.query(\n \"SELECT 1 FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND column_name = 'tokens_valid_after'\",\n [usersSchema, tableName]\n );\n if (watermark.rows.length > 0) {\n await client.query(\"UPDATE \" + users + \" SET tokens_valid_after = NOW() WHERE \" + idColumn + \" = $1\", [uid]);\n }\n for (const table of [\"refresh_tokens\", \"password_reset_tokens\"]) {\n const qualified = quote(authSchema) + \".\" + quote(table);\n const present = await client.query(\"SELECT to_regclass($1) IS NOT NULL AS present\", [qualified]);\n if (present.rows[0]?.present) {\n await client.query(\"DELETE FROM \" + qualified + \" WHERE uid = $1\", [uid]);\n }\n }\n await client.query(\"COMMIT\");\n\n console.log(\"✅ Password reset for: \" + updated.rows[0].email);\n console.log(\" Every session of this account has ended.\");\n ${echoPassword ? 'console.log(\" Password: \" + newPassword);' : \"\"}\n process.exit(0);\n } catch (error) {\n await client.query(\"ROLLBACK\").catch(() => undefined);\n throw error;\n } finally {\n client.release();\n }\n}\n\n// A thrown error is a failed reset, and exits like one — a refused connection\n// that exits 0 reads as a reset to anything checking the exit code.\nresetPassword().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n`;\n}\n\nfunction printAuthHelp() {\n console.log(`\n${chalk.bold(\"rebase auth\")} — Authentication management commands\n\n${chalk.green.bold(\"Usage\")}\n rebase auth ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.blue.bold(\"reset-password\")} Reset a user's password\n\n${chalk.green.bold(\"reset-password Options\")}\n ${chalk.blue(\"--email, -e\")} User's email address\n ${chalk.blue(\"--password, -p\")} New password (default: one is generated and printed)\n\n${chalk.green.bold(\"Examples\")}\n rebase auth reset-password user@example.com\n rebase auth reset-password --email user@example.com --password MyNewPass!\n`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,IAAM,cAAN,cAA0B,MAAM,CAAC;;AAGjC,IAAa,mBAAmB,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCjD,SAAgB,mBAAmB,SAAkB,OAAyC;CAC1F,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;CACxC,IAAI,CAAC,QAAQ,OAAO,KAAA;CAEpB,MAAM,OAAkB,MAAM,QAAQ,OAAO,IACvC,UACC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAS,QAAgC,KAAK,IAC1F,QAAiC,QAClC,CAAC;CAEX,KAAK,MAAM,OAAO,MAAM;EACpB,IAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;EACrC,MAAM,SAAS;EACf,MAAM,WAAW,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,KAAK,CAAC,CAAC,YAAY,IAAI,KAAA;EACxF,IAAI,CAAC,YAAY,aAAa,QAAQ;EAEtC,MAAM,KAAK,OAAO,OAAO,OAAO,WAC1B,OAAO,KACN,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,KAAA;EACrD,IAAI,CAAC,IAAI;EAET,OAAO;GAAE;GAAI,OAAO,OAAO;EAAgB;CAC/C;AAGJ;AAEA,eAAsB,YAAY,YAAgC,SAAkC;CAQhG,IAAI,CAAC,cAAc,eAAe,YAAY,UAAU,OAAO,GAAG;EAC9D,cAAc;EACd;CACJ;CAEA,QAAQ,YAAR;EACI,KAAK;GACD,MAAM,cAAc,OAAO;GAC3B;EACJ,SACI,eAAe,YAAY,kBAAkB,MAAM;CAC3D;AACJ;;;;;;;;;;AAWA,IAAa,uBAAuB;CAChC,WAAW;CACX,cAAc;CACd,MAAM;CACN,MAAM;AACV;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,SAGvC;CACE,MAAM,EAAE,OAAO,gBAAgB,iBAAiB;EAC5C,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAGD,OAAO;EACH,OAAO,MAAM,cAAc,YAAY;EACvC,UAAU,MAAM,iBAAiB,YAAY;CACjD;AACJ;;;;;;;;;;;;;AAcA,SAAgB,mBAA2B;CACvC,OAAO,YAAY,EAAE,CAAC,CAAC,SAAS,WAAW;AAC/C;;;;;;;;AASA,eAAe,cAAc,UAAqC;CAC9D,MAAM,OAAO,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,EAAE;CACjD,IAAI;EACA,MAAM,SAAkB,KAAK,MAAM,IAAI;EACvC,MAAM,QAAQ,UAAU,OAAO,WAAW,YAAY,WAAW,SAAS,OAAO,QAAQ,KAAA;EACzF,IAAI,SAAS,OAAO,UAAU,YAAY,aAAa,SAAS,OAAO,MAAM,YAAY,UAAU;GAC/F,MAAM,OAAO,UAAU,SAAS,OAAO,MAAM,SAAS,WAAW,KAAK,MAAM,KAAK,KAAK;GACtF,OAAO,GAAG,MAAM,UAAU;EAC9B;CACJ,QAAQ,CAER;CACA,OAAO,KAAK,KAAK,KAAK,GAAG,SAAS,OAAO,GAAG,SAAS,aAAa,KAAK;AAC3E;AAEA,eAAe,cAAc,SAAkC;CAC3D,MAAM,EAAE,OAAO,UAAU,qBAAqB,yBAAyB,OAAO;CAE9E,MAAM,eAAe,CAAC;CACtB,MAAM,cAAc,oBAAoB,iBAAiB;CAEzD,IAAI,CAAC,OAAO;EACR,QAAQ,MAAM,MAAM,IAAI,sBAAsB,CAAC;EAC/C,QAAQ,IAAI,EAAE;EACd,QAAQ,IAAI,MAAM,KAAK,4DAA4D,CAAC;EACpF,QAAQ,IAAI,MAAM,KAAK,qFAAqF,CAAC;EAC7G,QAAQ,KAAK,CAAC;CAClB;CAEA,MAAM,cAAc,mBAAmB;CAMvC,MAAM,UAAU,YAAY,WAAW;CACvC,MAAM,gBAAoC,YAAY,WAAW,CAAC,CAAC;CAEnE,IAAI,aAAa,QAAQ,IAAI,sBAAsB;CAEnD,MAAM,YAAY,KAAK,KAAK,aAAa,WAAW,YAAY;CAChE,IAAI,GAAG,WAAW,SAAS,GACvB,IAAI;EACA,MAAM,QAAQ,KAAK,MAAM,GAAG,aAAa,WAAW,MAAM,CAAC;EAC3D,IAAI,SAAS,OAAO,UAAU,YAAY,OAAO,MAAM,eAAe,YAAY,CAAC,YAC/E,aAAa,MAAM;CAE3B,QAAQ,CAER;CASJ,MAAM,UAAU,sBAAsB,YAAY,WAAW,GAAG,WAAW,CAAC,CAAC;CAE7E,IAAI,WAAW,YAAY;EACvB,QAAQ,IAAI,+CAA+C;EAC3D,IAAI;GACA,MAAM,YAAY;GAClB,MAAM,eAAe,QAAQ,QAAQ,QAAQ,EAAE;GAI/C,MAAM,YAAY,GAAG,aAAa,0BAA0B,mBAAmB,KAAK,EAAE;GACtF,MAAM,YAAY,MAAM,MAAM,WAAW,EACrC,SAAS;IACL,iBAAiB,UAAU;IAC3B,UAAU;GACd,EACJ,CAAC;GACD,IAAI,CAAC,UAAU,IACX,MAAM,IAAI,YAAY,yBAAyB,UAAU,OAAO,GAAG,UAAU,YAAY;GAE7F,MAAM,aAAa,MAAM,UAAU,KAAK;GACxC,IAAI,CAAC,cAAc,OAAO,eAAe,UACrC,MAAM,IAAI,MAAM,+CAA+C;GAGnE,MAAM,UAAU,mBAAmB,YAAY,KAAK;GACpD,IAAI,CAAC,SACD,MAAM,IAAI,YAAY,yBAAyB,MAAM,EAAE;GAG3D,MAAM,WAAW,GAAG,aAAa,mBAAmB,QAAQ,GAAG;GAC/D,MAAM,WAAW,MAAM,MAAM,UAAU;IACnC,QAAQ;IACR,SAAS;KACL,iBAAiB,UAAU;KAC3B,gBAAgB;KAChB,UAAU;IACd;IACA,MAAM,KAAK,UAAU,EAAE,UAAU,UAAU,CAAC;GAChD,CAAC;GAED,IAAI,CAAC,SAAS,IACV,MAAM,IAAI,YAAY,2BAA2B,MAAM,cAAc,QAAQ,GAAG;GAGpF,QAAQ,IAAI,uBAAuB;GACnC,QAAQ,IAAI,MAAM,KAAK,6CAA6C,CAAC;GACrE,QAAQ,IAAI,EAAE;GAGd,QAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,EAAE,GAAG,QAAQ,OAAO;GAGxD,QAAQ,IAAI,KAAK,MAAM,KAAK,WAAW,EAAE,GAAG,eAAe,YAAY,IAAI,OAAO,UAAU,MAAM,GAAG;GACrG,QAAQ,IAAI,EAAE;GACd;EACJ,SAAS,KAAK;GACV,MAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAM9D,IAAI,eAAe,aAAa;IAC5B,QAAQ,MAAM,MAAM,IAAI,KAAK,QAAQ,CAAC;IACtC,QAAQ,WAAW;IACnB;GACJ;GACA,QAAQ,KAAK,MAAM,OAAO,6DAA6D,CAAC;GACxF,QAAQ,KAAK,MAAM,KAAK,cAAc,QAAQ,CAAC;EACnD;CACJ;CAGA,MAAM,aAAa,kBAAkB,WAAW;CAChD,MAAM,SAAS,WAAW,WAAW;CAErC,IAAI,CAAC,QACD,6BAA6B,WAAW;CAG5C,IAAI;EACA,MAAM,MAA8B,EAAE,GAAG,QAAQ,IAA8B;EAC/E,IAAI,SACA,IAAI,qBAAqB;EAE7B,IAAI,qBAAqB;EACzB,IAAI,wBAAwB;EAC5B,IAAI,uBAAuB,WAAW,KAAK,KAAK,aAAa,MAAM;EAQnE,MAAM,EAAE,uBAAuB,MAAM,OAAO;EAC5C,MAAM,WAAW,MAAM,mBAAmB,aAAa,EACnD,aAAa,YAAY,QAAQ,IAAI,MAAM,KAAK,KAAK,SAAS,CAAC,EACnE,CAAC;EACD,OAAO,OAAO,KAAK,SAAS,GAAG;EAE/B,MAAM,gBAAgB,oBAAoB,YAAY;EAEtD,MAAM,gBAAgB,KAAK,KAAK,YAAY,wBAAwB;EACpE,GAAG,cAAc,eAAe,eAAe,OAAO;EAEtD,QAAQ,IAAI,EAAE;EACd,QAAQ,IAAI,MAAM,KAAK,wDAAwD,CAAC;EAChF,QAAQ,IAAI,EAAE;EACd,QAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,EAAE,GAAG,OAAO;EAChD,QAAQ,IAAI,KAAK,MAAM,KAAK,WAAW,EAAE,GAAG,SAAS,aAAa;EAClE,IAAI,CAAC,cACD,QAAQ,IAAI,KAAK,MAAM,KAAK,WAAW,EAAE,GAAG,IAAI,OAAO,YAAY,MAAM,GAAG;EAEhF,QAAQ,IAAI,EAAE;EAEd,MAAM,QAAQ,MAAM,QAAQ,CAAC,aAAa,GAAG;GACzC,KAAK;GACL,OAAO;GACP;EACJ,CAAC;EAMD,MAAM,gBAAgB;GAClB,IAAI;IAAE,GAAG,WAAW,aAAa;GAAG,QAAQ,CAAqB;EACrE;EAEA,OAAO,IAAI,SAAS,YAAY;GAC5B,MAAM,GAAG,UAAU,QAAQ;IACvB,QAAQ;IACR,QAAQ,MAAM,MAAM,IAAI,mCAAmC,CAAC;IAC5D,QAAQ,MAAM,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC;IAC5C,QAAQ,KAAK,CAAC;GAClB,CAAC;GACD,MAAM,GAAG,UAAU,SAAS;IACxB,QAAQ;IACR,IAAI,SAAS,GACT,QAAQ,KAAK,QAAQ,CAAC;IAE1B,QAAQ;GACZ,CAAC;EACL,CAAC;CACL,SAAS,KAAK;EACV,QAAQ,MAAM,MAAM,IAAI,kCAAkC,CAAC;EAC3D,QAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;EAC9D,QAAQ,KAAK,CAAC;CAClB;AACJ;;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBAAoB,cAA+B;CAC/D,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAsFD,eAAe,kDAAgD,GAAG;;;;;;;;;;;;;;;;;AAiB5E;AAEA,SAAS,gBAAgB;CACrB,QAAQ,IAAI;EACd,MAAM,KAAK,aAAa,EAAE;;EAE1B,MAAM,MAAM,KAAK,OAAO,EAAE;gBACZ,MAAM,KAAK,WAAW,EAAE;;EAEtC,MAAM,MAAM,KAAK,UAAU,EAAE;IAC3B,MAAM,KAAK,KAAK,gBAAgB,EAAE;;EAEpC,MAAM,MAAM,KAAK,wBAAwB,EAAE;IACzC,MAAM,KAAK,aAAa,EAAE;IAC1B,MAAM,KAAK,gBAAgB,EAAE;;EAE/B,MAAM,MAAM,KAAK,UAAU,EAAE;;;CAG9B;AACD"}