@rebasepro/cli 0.24.0 → 0.24.1-canary.g56af4a4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/bin/rebase.js +3 -0
  2. package/dist/agent-setup-B31F00DC.js +324 -0
  3. package/dist/agent-setup-B31F00DC.js.map +1 -0
  4. package/dist/api-keys-BPBi5nOF.js +524 -0
  5. package/dist/api-keys-BPBi5nOF.js.map +1 -0
  6. package/dist/apps-CPXNElX4.js +256 -0
  7. package/dist/apps-CPXNElX4.js.map +1 -0
  8. package/dist/args-BnmsEXvu.js +109 -0
  9. package/dist/args-BnmsEXvu.js.map +1 -0
  10. package/dist/atlas-dev-database-DTMuEScS.js +62 -0
  11. package/dist/atlas-dev-database-DTMuEScS.js.map +1 -0
  12. package/dist/auth-DvY94ZuL.js +395 -0
  13. package/dist/auth-DvY94ZuL.js.map +1 -0
  14. package/dist/branch-pointer-DIhKbQLp.js +2 -0
  15. package/dist/build-CFwUx-Ff.js +336 -0
  16. package/dist/build-CFwUx-Ff.js.map +1 -0
  17. package/dist/bundle-BQhP_xiA.js +1617 -0
  18. package/dist/bundle-BQhP_xiA.js.map +1 -0
  19. package/dist/cli.d.ts +2 -2
  20. package/dist/cloud-CkTr-yt0.js +9640 -0
  21. package/dist/cloud-CkTr-yt0.js.map +1 -0
  22. package/dist/collection-drift-BKj_BoMq.js +106 -0
  23. package/dist/collection-drift-BKj_BoMq.js.map +1 -0
  24. package/dist/commands/api-keys.d.ts +2 -0
  25. package/dist/commands/db.d.ts +37 -24
  26. package/dist/commands/dev.d.ts +103 -0
  27. package/dist/commands/generate_sdk.d.ts +26 -0
  28. package/dist/commands/skills.d.ts +22 -7
  29. package/dist/commands/storage.d.ts +46 -0
  30. package/dist/consent-BWHaYx5p.js +76 -0
  31. package/dist/consent-BWHaYx5p.js.map +1 -0
  32. package/dist/context-BqhRydBg.js +1234 -0
  33. package/dist/context-BqhRydBg.js.map +1 -0
  34. package/dist/daemon-DBn-shxX.js +2 -0
  35. package/dist/{daemon-entry-LTFKtpHy.js → daemon-entry-Da-D3rmH.js} +3 -4
  36. package/dist/daemon-entry-Da-D3rmH.js.map +1 -0
  37. package/dist/db-CMpBK3sv.js +1252 -0
  38. package/dist/db-CMpBK3sv.js.map +1 -0
  39. package/dist/derive-RPIsAVO4.js +474 -0
  40. package/dist/derive-RPIsAVO4.js.map +1 -0
  41. package/dist/dev-C9P5Yp9k.js +1593 -0
  42. package/dist/dev-C9P5Yp9k.js.map +1 -0
  43. package/dist/dev-db/atlas-dev-database.d.ts +32 -0
  44. package/dist/dev-db/daemon-entry.d.ts +13 -0
  45. package/dist/dev-preflight-N1evJL3S.js +2 -0
  46. package/dist/doctor-DYs-NqFI.js +771 -0
  47. package/dist/doctor-DYs-NqFI.js.map +1 -0
  48. package/dist/eject-BT6t37D0.js +335 -0
  49. package/dist/eject-BT6t37D0.js.map +1 -0
  50. package/dist/fold-static-C1EtHlfV.js +201 -0
  51. package/dist/fold-static-C1EtHlfV.js.map +1 -0
  52. package/dist/function-portability-BIvlvR9q.js +265 -0
  53. package/dist/function-portability-BIvlvR9q.js.map +1 -0
  54. package/dist/generate_sdk-UV635zSe.js +477 -0
  55. package/dist/generate_sdk-UV635zSe.js.map +1 -0
  56. package/dist/index.es.js +141 -24674
  57. package/dist/index.es.js.map +1 -1
  58. package/dist/init-fXeBcxuN.js +1042 -0
  59. package/dist/init-fXeBcxuN.js.map +1 -0
  60. package/dist/manifest-DzlC60WX.js +871 -0
  61. package/dist/manifest-DzlC60WX.js.map +1 -0
  62. package/dist/normalize-imports-CmVdE9iZ.js +100 -0
  63. package/dist/normalize-imports-CmVdE9iZ.js.map +1 -0
  64. package/dist/{package-manager-CXQevsE1.js → package-manager-DSEOwTqM.js} +2 -2
  65. package/dist/{package-manager-CXQevsE1.js.map → package-manager-DSEOwTqM.js.map} +1 -1
  66. package/dist/path-flags-DUBuI2i1.js +77 -0
  67. package/dist/path-flags-DUBuI2i1.js.map +1 -0
  68. package/dist/precompress.d.ts +17 -0
  69. package/dist/prepare-Btn9Ewbn.js +1052 -0
  70. package/dist/prepare-Btn9Ewbn.js.map +1 -0
  71. package/dist/{project-DmaGLmH2.js → project-Wp2zoyeN.js} +33 -4
  72. package/dist/project-Wp2zoyeN.js.map +1 -0
  73. package/dist/resolve-CJLkfFV0.js +2 -0
  74. package/dist/resources-DT1COn_6.js +161 -0
  75. package/dist/resources-DT1COn_6.js.map +1 -0
  76. package/dist/schema-BDBWvCHu.js +125 -0
  77. package/dist/schema-BDBWvCHu.js.map +1 -0
  78. package/dist/skills-DTFibT1m.js +642 -0
  79. package/dist/skills-DTFibT1m.js.map +1 -0
  80. package/dist/start-rU2e3Kp5.js +228 -0
  81. package/dist/start-rU2e3Kp5.js.map +1 -0
  82. package/dist/{state-C59Elrnt.js → state-Do7ZJYkF.js} +49 -4
  83. package/dist/state-Do7ZJYkF.js.map +1 -0
  84. package/dist/status-BR9oyi-y.js +351 -0
  85. package/dist/status-BR9oyi-y.js.map +1 -0
  86. package/dist/storage-DyvrSTH3.js +303 -0
  87. package/dist/storage-DyvrSTH3.js.map +1 -0
  88. package/dist/telemetry-CAWNCugs.js +338 -0
  89. package/dist/telemetry-CAWNCugs.js.map +1 -0
  90. package/dist/telemetry-DbLqGIBW.js +129 -0
  91. package/dist/telemetry-DbLqGIBW.js.map +1 -0
  92. package/dist/unknown-command-DNwDcX3w.js +98 -0
  93. package/dist/unknown-command-DNwDcX3w.js.map +1 -0
  94. package/dist/upgrade-D-5-Od96.js +1265 -0
  95. package/dist/upgrade-D-5-Od96.js.map +1 -0
  96. package/dist/utils/project.d.ts +16 -0
  97. package/dist/{version-DsgBmP22.js → version-Buyyo1ut.js} +2 -2
  98. package/dist/{version-DsgBmP22.js.map → version-Buyyo1ut.js.map} +1 -1
  99. package/package.json +7 -7
  100. package/templates/eject/backend/src/env.ts +1 -1
  101. package/templates/eject/backend/src/index.ts +10 -2
  102. package/templates/template/README.md +1 -1
  103. package/templates/template/ai-instructions.md +2 -1
  104. package/templates/template/frontend/vite.config.ts +11 -3
  105. package/templates/template/scripts/example.ts +2 -1
  106. package/dist/branch-pointer-kk9F5FBO.js +0 -111
  107. package/dist/branch-pointer-kk9F5FBO.js.map +0 -1
  108. package/dist/constraints-DKGbNfUW.js +0 -48
  109. package/dist/constraints-DKGbNfUW.js.map +0 -1
  110. package/dist/daemon-C8p32i-n.js +0 -357
  111. package/dist/daemon-C8p32i-n.js.map +0 -1
  112. package/dist/daemon-entry-LTFKtpHy.js.map +0 -1
  113. package/dist/dev-preflight-CNLl4rdo.js +0 -367
  114. package/dist/dev-preflight-CNLl4rdo.js.map +0 -1
  115. package/dist/project-DmaGLmH2.js.map +0 -1
  116. package/dist/resolve-BAeRUBhg.js +0 -74
  117. package/dist/resolve-BAeRUBhg.js.map +0 -1
  118. package/dist/state-C59Elrnt.js.map +0 -1
@@ -0,0 +1,303 @@
1
+ import { d as readEnvFile, p as requireProjectRoot } from "./project-Wp2zoyeN.js";
2
+ import { n as parseCommandArgs, r as wantsHelp, t as UsageError } from "./args-BnmsEXvu.js";
3
+ import { t as unknownCommand } from "./unknown-command-DNwDcX3w.js";
4
+ import { t as cliUserAgent } from "./version-Buyyo1ut.js";
5
+ import { describeFailure, resolveBaseUrl } from "./api-keys-BPBi5nOF.js";
6
+ import chalk from "chalk";
7
+ import { RebaseApiError } from "@rebasepro/client";
8
+ import readline from "node:readline/promises";
9
+ //#region src/commands/storage.ts
10
+ /**
11
+ * CLI command: rebase storage <action>
12
+ *
13
+ * Whole-store maintenance through the running backend's `/api/admin/storage`,
14
+ * authenticated with the service key from `.env`.
15
+ *
16
+ * Subcommands:
17
+ * orphans — Stored files no row names; `--delete` deletes them
18
+ * move — Copy a folder of files to another storage source, same keys
19
+ */
20
+ /** Everything the switch below dispatches, for the did-you-mean. */
21
+ var STORAGE_SUBCOMMANDS = ["orphans", "move"];
22
+ /** The flags `rebase storage orphans` takes. */
23
+ var ORPHANS_FLAGS = {
24
+ "--source": String,
25
+ "--older-than": Number,
26
+ "--delete": Boolean,
27
+ "--yes": Boolean,
28
+ "-y": "--yes",
29
+ "--json": Boolean
30
+ };
31
+ /** The flags `rebase storage move` takes. */
32
+ var MOVE_FLAGS = {
33
+ "--from": String,
34
+ "--to": String,
35
+ "--prefix": String,
36
+ "--delete-source": Boolean,
37
+ "--json": Boolean
38
+ };
39
+ /** The project's backend, holding the service key — the `admin` role, every scope. */
40
+ function connect() {
41
+ const projectRoot = requireProjectRoot();
42
+ const env = readEnvFile(projectRoot);
43
+ const baseUrl = resolveBaseUrl(env, projectRoot).replace(/\/+$/, "");
44
+ const serviceKey = env.SERVICE_KEY || env.REBASE_SERVICE_KEY;
45
+ if (!serviceKey) {
46
+ console.error(chalk.red("✗ REBASE_SERVICE_KEY not found in .env — required for storage maintenance."));
47
+ process.exit(1);
48
+ }
49
+ return {
50
+ baseUrl,
51
+ async request(method, path, body) {
52
+ let response;
53
+ try {
54
+ response = await fetch(`${baseUrl}/api/admin/storage${path}`, {
55
+ method,
56
+ headers: {
57
+ "Authorization": `Bearer ${serviceKey}`,
58
+ "Accept": "application/json",
59
+ "User-Agent": cliUserAgent(),
60
+ ...body === void 0 ? {} : { "Content-Type": "application/json" }
61
+ },
62
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
63
+ });
64
+ } catch (error) {
65
+ throw new RebaseApiError(error instanceof Error ? error.message : String(error), {
66
+ status: 0,
67
+ code: "NETWORK_ERROR"
68
+ });
69
+ }
70
+ const answer = await response.json().catch(() => void 0);
71
+ if (!response.ok) {
72
+ const error = answer && typeof answer === "object" && "error" in answer && answer.error && typeof answer.error === "object" ? answer.error : void 0;
73
+ throw new RebaseApiError(typeof error?.message === "string" ? error.message : `The server answered ${response.status}.`, {
74
+ status: response.status,
75
+ code: typeof error?.code === "string" ? error.code : void 0,
76
+ details: error?.details
77
+ });
78
+ }
79
+ return answer.data;
80
+ }
81
+ };
82
+ }
83
+ function fail(action, error, baseUrl) {
84
+ for (const line of describeFailure(action, error, baseUrl)) console.error(line.startsWith("✗") ? chalk.red(line) : chalk.gray(line));
85
+ if (error instanceof RebaseApiError && error.status === 404 && error.code !== "UNKNOWN_STORAGE_SOURCE") console.error(chalk.gray(" This backend has no storage maintenance routes: they arrived in 0.25, and need storage configured."));
86
+ process.exit(1);
87
+ }
88
+ /** Bytes, as a person reads them. */
89
+ function formatBytes(bytes) {
90
+ if (bytes < 1024) return `${bytes} B`;
91
+ const units = [
92
+ "KB",
93
+ "MB",
94
+ "GB",
95
+ "TB"
96
+ ];
97
+ let value = bytes / 1024;
98
+ let unit = 0;
99
+ while (value >= 1024 && unit < units.length - 1) {
100
+ value /= 1024;
101
+ unit++;
102
+ }
103
+ return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;
104
+ }
105
+ /**
106
+ * The lines that describe an orphan scan. Exported so its tests can read them
107
+ * without a server.
108
+ */
109
+ function describeOrphanReport(report, olderThanHours) {
110
+ const lines = [];
111
+ const bytes = report.orphans.reduce((sum, orphan) => sum + (orphan.size ?? 0), 0);
112
+ lines.push(` ${report.objects} file(s) in source "${report.storageId}", ${report.scanned.length} collection(s) read.`);
113
+ if (report.orphans.length === 0) lines.push(` No file older than ${olderThanHours}h is unused.`);
114
+ else {
115
+ lines.push(` ${report.orphans.length} file(s) no row names, ${formatBytes(bytes)}:`);
116
+ for (const orphan of report.orphans) lines.push(` ${orphan.key}${orphan.size !== void 0 ? ` ${formatBytes(orphan.size)}` : ""}${orphan.updated ? ` ${orphan.updated}` : ""}`);
117
+ }
118
+ if (report.recent > 0) lines.push(` ${report.recent} more no row names are newer than ${olderThanHours}h, or of unknown age, and are left out: an upload can be saved before the row that names it.`);
119
+ for (const entry of report.unscanned) lines.push(` ⚠ ${entry.collection} could not be read (${entry.reason}): a file only it names is listed above.`);
120
+ return lines;
121
+ }
122
+ async function confirm(question) {
123
+ const prompt = readline.createInterface({
124
+ input: process.stdin,
125
+ output: process.stdout
126
+ });
127
+ try {
128
+ return /^y(es)?$/i.test((await prompt.question(question)).trim());
129
+ } finally {
130
+ prompt.close();
131
+ }
132
+ }
133
+ async function orphans(rawArgs) {
134
+ const { flags } = parseCommandArgs({
135
+ spec: ORPHANS_FLAGS,
136
+ rawArgs,
137
+ commandWords: 2,
138
+ command: "storage orphans",
139
+ maxPositionals: 0
140
+ });
141
+ const olderThan = flags["--older-than"] ?? 24;
142
+ if (!Number.isFinite(olderThan) || olderThan < 0) throw new UsageError("--older-than takes a number of hours, 0 or more.");
143
+ const query = new URLSearchParams({ olderThanHours: String(olderThan) });
144
+ if (flags["--source"]) query.set("storageId", flags["--source"]);
145
+ const backend = connect();
146
+ let report;
147
+ try {
148
+ report = await backend.request("GET", `/orphans?${query}`);
149
+ } catch (error) {
150
+ fail("Failed to scan storage", error, backend.baseUrl);
151
+ }
152
+ if (!flags["--delete"]) {
153
+ if (flags["--json"]) {
154
+ console.log(JSON.stringify(report, null, 2));
155
+ return;
156
+ }
157
+ console.log("");
158
+ for (const line of describeOrphanReport(report, olderThan)) console.log(line);
159
+ if (report.orphans.length > 0) {
160
+ console.log("");
161
+ console.log(chalk.gray(" Nothing was deleted. Run again with --delete to delete them."));
162
+ }
163
+ console.log("");
164
+ return;
165
+ }
166
+ if (!flags["--json"]) {
167
+ console.log("");
168
+ for (const line of describeOrphanReport(report, olderThan)) console.log(line);
169
+ console.log("");
170
+ }
171
+ if (report.orphans.length === 0) return;
172
+ if (report.unscanned.length > 0) {
173
+ console.error(chalk.red("✗ Not deleting: some collections could not be read, so a file they name would look unused."));
174
+ process.exit(1);
175
+ }
176
+ if (!flags["--yes"]) {
177
+ if (!process.stdin.isTTY) throw new UsageError("--delete deletes files for good; pass --yes to confirm when there is no terminal to ask.");
178
+ if (!await confirm(` Delete these ${report.orphans.length} file(s) for good? [y/N] `)) {
179
+ console.log(chalk.gray(" Nothing was deleted."));
180
+ return;
181
+ }
182
+ }
183
+ let result;
184
+ try {
185
+ result = await backend.request("DELETE", `/orphans?${query}`);
186
+ } catch (error) {
187
+ fail("Failed to delete unused files", error, backend.baseUrl);
188
+ }
189
+ if (flags["--json"]) console.log(JSON.stringify(result, null, 2));
190
+ else {
191
+ console.log(chalk.green(` ✓ Deleted ${result.deleted.length} file(s).`));
192
+ for (const failure of result.failed) console.error(chalk.red(` ✗ ${failure.key}: ${failure.error}`));
193
+ console.log("");
194
+ }
195
+ if (result.failed.length > 0) process.exitCode = 1;
196
+ }
197
+ async function move(rawArgs) {
198
+ const { flags } = parseCommandArgs({
199
+ spec: MOVE_FLAGS,
200
+ rawArgs,
201
+ commandWords: 2,
202
+ command: "storage move",
203
+ maxPositionals: 0
204
+ });
205
+ const from = flags["--from"];
206
+ const to = flags["--to"];
207
+ if (!from && !to) throw new UsageError("Name the sources: --from <source> --to <source>. The default source is \"(default)\", and either may be left out for it.");
208
+ const backend = connect();
209
+ const counts = {
210
+ copied: 0,
211
+ exists: 0,
212
+ failed: 0,
213
+ deleted: 0
214
+ };
215
+ const failures = [];
216
+ let cursor;
217
+ do {
218
+ let page;
219
+ try {
220
+ page = await backend.request("POST", "/move", {
221
+ from,
222
+ to,
223
+ prefix: flags["--prefix"],
224
+ cursor,
225
+ deleteSource: flags["--delete-source"] === true
226
+ });
227
+ } catch (error) {
228
+ fail("Failed to move files", error, backend.baseUrl);
229
+ }
230
+ for (const object of page.moved) {
231
+ counts[object.outcome]++;
232
+ if (object.deleted) counts.deleted++;
233
+ if (object.outcome === "failed") failures.push(object);
234
+ }
235
+ if (!flags["--json"] && process.stdout.isTTY) process.stdout.write(`\r ${counts.copied} copied, ${counts.exists} already there, ${counts.failed} failed…`);
236
+ cursor = page.cursor;
237
+ } while (cursor);
238
+ if (flags["--json"]) console.log(JSON.stringify({
239
+ ...counts,
240
+ failures
241
+ }, null, 2));
242
+ else {
243
+ if (process.stdout.isTTY) process.stdout.write("\n");
244
+ console.log(chalk.green(` ✓ ${counts.copied} copied, ${counts.exists} already there${flags["--delete-source"] ? `, ${counts.deleted} deleted from the source` : ""}.`));
245
+ for (const failure of failures) console.error(chalk.red(` ✗ ${failure.key}: ${failure.error ?? "failed"}`));
246
+ if (counts.copied + counts.exists > 0 && !flags["--delete-source"]) console.log(chalk.gray(" The source keeps its copies. Point the property at the new source, then run again with --delete-source."));
247
+ }
248
+ if (failures.length > 0) process.exitCode = 1;
249
+ }
250
+ async function storageCommand(subcommand, rawArgs) {
251
+ if (!subcommand || subcommand === "--help" || wantsHelp(rawArgs)) {
252
+ printStorageHelp();
253
+ return;
254
+ }
255
+ switch (subcommand) {
256
+ case "orphans":
257
+ await orphans(rawArgs);
258
+ break;
259
+ case "move":
260
+ await move(rawArgs);
261
+ break;
262
+ default: unknownCommand(subcommand, STORAGE_SUBCOMMANDS, "storage");
263
+ }
264
+ }
265
+ function printStorageHelp() {
266
+ console.log(`
267
+ ${chalk.bold("rebase storage")} — Maintain stored files, through the running backend
268
+
269
+ ${chalk.green.bold("Usage")}
270
+ rebase storage ${chalk.blue("<command>")} [options]
271
+
272
+ ${chalk.green.bold("Commands")}
273
+ ${chalk.blue.bold("orphans")} List the stored files no row names
274
+ ${chalk.blue.bold("move")} Copy a folder of files to another storage source, same keys
275
+
276
+ ${chalk.green.bold("orphans Options")}
277
+ ${chalk.blue("--source")} Storage source key ${chalk.gray("(default: the default source)")}
278
+ ${chalk.blue("--older-than")} Hours a file must be old to count ${chalk.gray("(default: 24)")}
279
+ ${chalk.blue("--delete")} Delete them, after asking
280
+ ${chalk.blue("--yes, -y")} Do not ask ${chalk.gray("(required with --delete when there is no terminal)")}
281
+ ${chalk.blue("--json")} Print the report as JSON
282
+
283
+ ${chalk.green.bold("move Options")}
284
+ ${chalk.blue("--from")} Source to copy from ${chalk.gray("(default: the default source)")}
285
+ ${chalk.blue("--to")} Source to copy to ${chalk.gray("(default: the default source)")}
286
+ ${chalk.blue("--prefix")} Folder to copy ${chalk.gray("(default: everything)")}
287
+ ${chalk.blue("--delete-source")} Delete each file from the source once the target holds it
288
+ ${chalk.blue("--json")} Print the counts as JSON
289
+
290
+ ${chalk.green.bold("Notes")}
291
+ A file is unused when no string in any row of any collection names it —
292
+ a key, a URL, a ${chalk.blue("rebase-storage:")} reference in text — whatever property
293
+ or source holds it. Files newer than ${chalk.blue("--older-than")} are left out: the admin
294
+ panel uploads a file before the row that names it is saved. Files your own
295
+ tables name, outside collections, are not seen: check before deleting.
296
+
297
+ Both read ${chalk.blue("REBASE_SERVICE_KEY")} from .env and need the backend running.
298
+ `);
299
+ }
300
+ //#endregion
301
+ export { STORAGE_SUBCOMMANDS, storageCommand };
302
+
303
+ //# sourceMappingURL=storage-DyvrSTH3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-DyvrSTH3.js","names":[],"sources":["../src/commands/storage.ts"],"sourcesContent":["/**\n * CLI command: rebase storage <action>\n *\n * Whole-store maintenance through the running backend's `/api/admin/storage`,\n * authenticated with the service key from `.env`.\n *\n * Subcommands:\n * orphans — Stored files no row names; `--delete` deletes them\n * move — Copy a folder of files to another storage source, same keys\n */\nimport chalk from \"chalk\";\nimport readline from \"node:readline/promises\";\nimport { RebaseApiError } from \"@rebasepro/client\";\nimport { requireProjectRoot, readEnvFile } from \"../utils/project\";\nimport { parseCommandArgs, UsageError, wantsHelp } from \"../utils/args\";\nimport { unknownCommand } from \"../utils/unknown-command\";\nimport { cliUserAgent } from \"../utils/version\";\nimport { describeFailure, resolveBaseUrl } from \"./api-keys\";\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const STORAGE_SUBCOMMANDS = [\"orphans\", \"move\"] as const;\n\n/** The flags `rebase storage orphans` takes. */\nexport const ORPHANS_FLAGS = {\n \"--source\": String,\n \"--older-than\": Number,\n \"--delete\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\",\n \"--json\": Boolean\n} as const;\n\n/** The flags `rebase storage move` takes. */\nexport const MOVE_FLAGS = {\n \"--from\": String,\n \"--to\": String,\n \"--prefix\": String,\n \"--delete-source\": Boolean,\n \"--json\": Boolean\n} as const;\n\n/** One stored object, as the backend lists it. */\ninterface StoredObjectEntry {\n key: string;\n size?: number;\n updated?: string;\n}\n\n/** What `GET /admin/storage/orphans` answers. */\nexport interface OrphanReport {\n storageId: string;\n objects: number;\n orphans: StoredObjectEntry[];\n recent: number;\n scanned: string[];\n unscanned: { collection: string; reason: string }[];\n}\n\ninterface MovedObject {\n key: string;\n outcome: \"copied\" | \"exists\" | \"failed\";\n deleted?: boolean;\n error?: string;\n}\n\ninterface Backend {\n baseUrl: string;\n request<T>(method: string, path: string, body?: unknown): Promise<T>;\n}\n\n/** The project's backend, holding the service key — the `admin` role, every scope. */\nfunction connect(): Backend {\n const projectRoot = requireProjectRoot();\n const env = readEnvFile(projectRoot);\n const baseUrl = resolveBaseUrl(env, projectRoot).replace(/\\/+$/, \"\");\n const serviceKey = env.SERVICE_KEY || env.REBASE_SERVICE_KEY;\n if (!serviceKey) {\n console.error(chalk.red(\"✗ REBASE_SERVICE_KEY not found in .env — required for storage maintenance.\"));\n process.exit(1);\n }\n return {\n baseUrl,\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n let response: Response;\n try {\n response = await fetch(`${baseUrl}/api/admin/storage${path}`, {\n method,\n headers: {\n \"Authorization\": `Bearer ${serviceKey}`,\n \"Accept\": \"application/json\",\n \"User-Agent\": cliUserAgent(),\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" })\n },\n ...(body === undefined ? {} : { body: JSON.stringify(body) })\n });\n } catch (error: unknown) {\n throw new RebaseApiError(error instanceof Error ? error.message : String(error), { status: 0, code: \"NETWORK_ERROR\" });\n }\n const answer: unknown = await response.json().catch(() => undefined);\n if (!response.ok) {\n const error = answer && typeof answer === \"object\" && \"error\" in answer && answer.error && typeof answer.error === \"object\"\n ? answer.error as { message?: unknown; code?: unknown; details?: unknown }\n : undefined;\n throw new RebaseApiError(\n typeof error?.message === \"string\" ? error.message : `The server answered ${response.status}.`,\n { status: response.status, code: typeof error?.code === \"string\" ? error.code : undefined, details: error?.details }\n );\n }\n return (answer as { data: T }).data;\n }\n };\n}\n\nfunction fail(action: string, error: unknown, baseUrl: string): never {\n for (const line of describeFailure(action, error, baseUrl)) {\n console.error(line.startsWith(\"✗\") ? chalk.red(line) : chalk.gray(line));\n }\n if (error instanceof RebaseApiError && error.status === 404 && error.code !== \"UNKNOWN_STORAGE_SOURCE\") {\n console.error(chalk.gray(\" This backend has no storage maintenance routes: they arrived in 0.25, and need storage configured.\"));\n }\n process.exit(1);\n}\n\n/** Bytes, as a person reads them. */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n const units = [\"KB\", \"MB\", \"GB\", \"TB\"];\n let value = bytes / 1024;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit++;\n }\n return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;\n}\n\n/**\n * The lines that describe an orphan scan. Exported so its tests can read them\n * without a server.\n */\nexport function describeOrphanReport(report: OrphanReport, olderThanHours: number): string[] {\n const lines: string[] = [];\n const bytes = report.orphans.reduce((sum, orphan) => sum + (orphan.size ?? 0), 0);\n lines.push(` ${report.objects} file(s) in source \"${report.storageId}\", ${report.scanned.length} collection(s) read.`);\n if (report.orphans.length === 0) {\n lines.push(\" No file older than \" + `${olderThanHours}h is unused.`);\n } else {\n lines.push(` ${report.orphans.length} file(s) no row names, ${formatBytes(bytes)}:`);\n for (const orphan of report.orphans) {\n lines.push(` ${orphan.key}${orphan.size !== undefined ? ` ${formatBytes(orphan.size)}` : \"\"}${orphan.updated ? ` ${orphan.updated}` : \"\"}`);\n }\n }\n if (report.recent > 0) {\n lines.push(` ${report.recent} more no row names are newer than ${olderThanHours}h, or of unknown age, and are left out: ` +\n \"an upload can be saved before the row that names it.\");\n }\n for (const entry of report.unscanned) {\n lines.push(` ⚠ ${entry.collection} could not be read (${entry.reason}): a file only it names is listed above.`);\n }\n return lines;\n}\n\nasync function confirm(question: string): Promise<boolean> {\n const prompt = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n return /^y(es)?$/i.test((await prompt.question(question)).trim());\n } finally {\n prompt.close();\n }\n}\n\nasync function orphans(rawArgs: string[]): Promise<void> {\n const { flags } = parseCommandArgs({ spec: ORPHANS_FLAGS, rawArgs, commandWords: 2, command: \"storage orphans\", maxPositionals: 0 });\n const olderThan = flags[\"--older-than\"] ?? 24;\n if (!Number.isFinite(olderThan) || olderThan < 0) {\n throw new UsageError(\"--older-than takes a number of hours, 0 or more.\");\n }\n const query = new URLSearchParams({ olderThanHours: String(olderThan) });\n if (flags[\"--source\"]) query.set(\"storageId\", flags[\"--source\"]);\n const backend = connect();\n\n let report: OrphanReport;\n try {\n report = await backend.request<OrphanReport>(\"GET\", `/orphans?${query}`);\n } catch (error: unknown) {\n fail(\"Failed to scan storage\", error, backend.baseUrl);\n }\n\n if (!flags[\"--delete\"]) {\n if (flags[\"--json\"]) {\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n console.log(\"\");\n for (const line of describeOrphanReport(report, olderThan)) console.log(line);\n if (report.orphans.length > 0) {\n console.log(\"\");\n console.log(chalk.gray(\" Nothing was deleted. Run again with --delete to delete them.\"));\n }\n console.log(\"\");\n return;\n }\n\n if (!flags[\"--json\"]) {\n console.log(\"\");\n for (const line of describeOrphanReport(report, olderThan)) console.log(line);\n console.log(\"\");\n }\n if (report.orphans.length === 0) return;\n if (report.unscanned.length > 0) {\n console.error(chalk.red(\"✗ Not deleting: some collections could not be read, so a file they name would look unused.\"));\n process.exit(1);\n }\n if (!flags[\"--yes\"]) {\n if (!process.stdin.isTTY) {\n throw new UsageError(\"--delete deletes files for good; pass --yes to confirm when there is no terminal to ask.\");\n }\n if (!await confirm(` Delete these ${report.orphans.length} file(s) for good? [y/N] `)) {\n console.log(chalk.gray(\" Nothing was deleted.\"));\n return;\n }\n }\n\n let result: { deleted: string[]; failed: { key: string; error: string }[] };\n try {\n // The server finds them again before it deletes: a file a row has\n // named since the list was printed is not deleted.\n result = await backend.request(\"DELETE\", `/orphans?${query}`);\n } catch (error: unknown) {\n fail(\"Failed to delete unused files\", error, backend.baseUrl);\n }\n if (flags[\"--json\"]) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(chalk.green(` ✓ Deleted ${result.deleted.length} file(s).`));\n for (const failure of result.failed) console.error(chalk.red(` ✗ ${failure.key}: ${failure.error}`));\n console.log(\"\");\n }\n if (result.failed.length > 0) process.exitCode = 1;\n}\n\nasync function move(rawArgs: string[]): Promise<void> {\n const { flags } = parseCommandArgs({ spec: MOVE_FLAGS, rawArgs, commandWords: 2, command: \"storage move\", maxPositionals: 0 });\n const from = flags[\"--from\"];\n const to = flags[\"--to\"];\n if (!from && !to) {\n throw new UsageError(\"Name the sources: --from <source> --to <source>. The default source is \\\"(default)\\\", and either may be left out for it.\");\n }\n const backend = connect();\n const counts = { copied: 0, exists: 0, failed: 0, deleted: 0 };\n const failures: MovedObject[] = [];\n let cursor: string | undefined;\n do {\n let page: { moved: MovedObject[]; cursor?: string };\n try {\n page = await backend.request(\"POST\", \"/move\", {\n from,\n to,\n prefix: flags[\"--prefix\"],\n cursor,\n deleteSource: flags[\"--delete-source\"] === true\n });\n } catch (error: unknown) {\n fail(\"Failed to move files\", error, backend.baseUrl);\n }\n for (const object of page.moved) {\n counts[object.outcome]++;\n if (object.deleted) counts.deleted++;\n if (object.outcome === \"failed\") failures.push(object);\n }\n if (!flags[\"--json\"] && process.stdout.isTTY) {\n process.stdout.write(`\\r ${counts.copied} copied, ${counts.exists} already there, ${counts.failed} failed…`);\n }\n cursor = page.cursor;\n } while (cursor);\n\n if (flags[\"--json\"]) {\n console.log(JSON.stringify({ ...counts, failures }, null, 2));\n } else {\n if (process.stdout.isTTY) process.stdout.write(\"\\n\");\n console.log(chalk.green(` ✓ ${counts.copied} copied, ${counts.exists} already there` +\n `${flags[\"--delete-source\"] ? `, ${counts.deleted} deleted from the source` : \"\"}.`));\n for (const failure of failures) console.error(chalk.red(` ✗ ${failure.key}: ${failure.error ?? \"failed\"}`));\n if (counts.copied + counts.exists > 0 && !flags[\"--delete-source\"]) {\n console.log(chalk.gray(\" The source keeps its copies. Point the property at the new source, then run again with --delete-source.\"));\n }\n }\n if (failures.length > 0) process.exitCode = 1;\n}\n\nexport async function storageCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void> {\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printStorageHelp();\n return;\n }\n switch (subcommand) {\n case \"orphans\":\n await orphans(rawArgs);\n break;\n case \"move\":\n await move(rawArgs);\n break;\n default:\n unknownCommand(subcommand, STORAGE_SUBCOMMANDS, \"storage\");\n }\n}\n\nfunction printStorageHelp(): void {\n console.log(`\n${chalk.bold(\"rebase storage\")} — Maintain stored files, through the running backend\n\n${chalk.green.bold(\"Usage\")}\n rebase storage ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.blue.bold(\"orphans\")} List the stored files no row names\n ${chalk.blue.bold(\"move\")} Copy a folder of files to another storage source, same keys\n\n${chalk.green.bold(\"orphans Options\")}\n ${chalk.blue(\"--source\")} Storage source key ${chalk.gray(\"(default: the default source)\")}\n ${chalk.blue(\"--older-than\")} Hours a file must be old to count ${chalk.gray(\"(default: 24)\")}\n ${chalk.blue(\"--delete\")} Delete them, after asking\n ${chalk.blue(\"--yes, -y\")} Do not ask ${chalk.gray(\"(required with --delete when there is no terminal)\")}\n ${chalk.blue(\"--json\")} Print the report as JSON\n\n${chalk.green.bold(\"move Options\")}\n ${chalk.blue(\"--from\")} Source to copy from ${chalk.gray(\"(default: the default source)\")}\n ${chalk.blue(\"--to\")} Source to copy to ${chalk.gray(\"(default: the default source)\")}\n ${chalk.blue(\"--prefix\")} Folder to copy ${chalk.gray(\"(default: everything)\")}\n ${chalk.blue(\"--delete-source\")} Delete each file from the source once the target holds it\n ${chalk.blue(\"--json\")} Print the counts as JSON\n\n${chalk.green.bold(\"Notes\")}\n A file is unused when no string in any row of any collection names it —\n a key, a URL, a ${chalk.blue(\"rebase-storage:\")} reference in text — whatever property\n or source holds it. Files newer than ${chalk.blue(\"--older-than\")} are left out: the admin\n panel uploads a file before the row that names it is saved. Files your own\n tables name, outside collections, are not seen: check before deleting.\n\n Both read ${chalk.blue(\"REBASE_SERVICE_KEY\")} from .env and need the backend running.\n`);\n}\n"],"mappings":"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"}