@rebasepro/cli 0.25.0-canary.ge06257e → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/rebase.js +9 -5
- package/dist/{agent-setup-C83DXnlx.js → agent-setup-B5AKHOgt.js} +2 -2
- package/dist/{agent-setup-C83DXnlx.js.map → agent-setup-B5AKHOgt.js.map} +1 -1
- package/dist/{api-keys-Bc4FJKYp.js → api-keys-Tm7zvAPe.js} +27 -20
- package/dist/api-keys-Tm7zvAPe.js.map +1 -0
- package/dist/{apps-wG-ZTryA.js → apps-BsU_ILbP.js} +4 -4
- package/dist/{apps-wG-ZTryA.js.map → apps-BsU_ILbP.js.map} +1 -1
- package/dist/{args-CcBphFdj.js → args-BX0YD14a.js} +45 -16
- package/dist/args-BX0YD14a.js.map +1 -0
- package/dist/{atlas-dev-database-DeK3Sa4h.js → atlas-dev-database-OWtqnG7W.js} +2 -2
- package/dist/{atlas-dev-database-DeK3Sa4h.js.map → atlas-dev-database-OWtqnG7W.js.map} +1 -1
- package/dist/{auth-BL7bNQVu.js → auth-Vl2hFKXP.js} +77 -10
- package/dist/auth-Vl2hFKXP.js.map +1 -0
- package/dist/{branch-pointer-DTQNLFtb.js → branch-pointer-9DnwkFJJ.js} +1 -1
- package/dist/{build-h_7Re-67.js → build-BBgT8EJZ.js} +5 -5
- package/dist/{build-h_7Re-67.js.map → build-BBgT8EJZ.js.map} +1 -1
- package/dist/{bundle-CqURVN-K.js → bundle-DtCCCr4w.js} +4 -19
- package/dist/bundle-DtCCCr4w.js.map +1 -0
- package/dist/{cloud-DVV_5GPG.js → cloud-BpH0_bmV.js} +7 -7
- package/dist/{cloud-DVV_5GPG.js.map → cloud-BpH0_bmV.js.map} +1 -1
- package/dist/commands/api-keys.d.ts +4 -1
- package/dist/commands/auth.d.ts +3 -2
- package/dist/connection-banner-DbLJzWf4.js +128 -0
- package/dist/connection-banner-DbLJzWf4.js.map +1 -0
- package/dist/{console-Dw3HLdUs.js → console-CEGm0XNc.js} +4 -4
- package/dist/{console-Dw3HLdUs.js.map → console-CEGm0XNc.js.map} +1 -1
- package/dist/{context-BM-oOMNX.js → context-CyflUrKg.js} +2 -2
- package/dist/{context-BM-oOMNX.js.map → context-CyflUrKg.js.map} +1 -1
- package/dist/{daemon-entry-C6pxdily.js → daemon-entry-CbLRrgzy.js} +199 -3
- package/dist/daemon-entry-CbLRrgzy.js.map +1 -0
- package/dist/{db-Dkn9XhT-.js → db-CRNpA5mH.js} +171 -60
- package/dist/db-CRNpA5mH.js.map +1 -0
- package/dist/{derive-Dl0z2OWi.js → derive-CsoFGAnK.js} +28 -13
- package/dist/{derive-Dl0z2OWi.js.map → derive-CsoFGAnK.js.map} +1 -1
- package/dist/{dev-DAcZR4Pp.js → dev-C0pbMmhS.js} +6 -6
- package/dist/{dev-DAcZR4Pp.js.map → dev-C0pbMmhS.js.map} +1 -1
- package/dist/dev-db/connection-banner.d.ts +47 -0
- package/dist/dev-db/notification-proxy.d.ts +82 -1
- package/dist/{dev-preflight-CorMg7Ub.js → dev-preflight-unHpiYO1.js} +26 -3
- package/dist/dev-preflight-unHpiYO1.js.map +1 -0
- package/dist/{doctor-Ds_lzc9p.js → doctor-CATRdWm6.js} +4 -4
- package/dist/{doctor-Ds_lzc9p.js.map → doctor-CATRdWm6.js.map} +1 -1
- package/dist/{eject-CJHkfnat.js → eject-DuasTr-F.js} +2 -2
- package/dist/{eject-CJHkfnat.js.map → eject-DuasTr-F.js.map} +1 -1
- package/dist/{fold-static-BC9CYicw.js → fold-static-hDHtDfTq.js} +2 -2
- package/dist/{fold-static-BC9CYicw.js.map → fold-static-hDHtDfTq.js.map} +1 -1
- package/dist/{generate_sdk-kfkZmG-d.js → generate_sdk-Cvg5jjJF.js} +3 -3
- package/dist/{generate_sdk-kfkZmG-d.js.map → generate_sdk-Cvg5jjJF.js.map} +1 -1
- package/dist/index.es.js +34 -34
- package/dist/{init-CjoJoThg.js → init-BWAwHPtz.js} +8 -7
- package/dist/init-BWAwHPtz.js.map +1 -0
- package/dist/last-dev-database-c_dKz1S3.js +2 -0
- package/dist/{normalize-imports-BHxL2d05.js → normalize-imports-BoBVh5tU.js} +3 -3
- package/dist/{normalize-imports-BHxL2d05.js.map → normalize-imports-BoBVh5tU.js.map} +1 -1
- package/dist/precompress.d.ts +0 -7
- package/dist/{prepare-C1iaiTC4.js → prepare-DdnU70z8.js} +4 -4
- package/dist/prepare-DdnU70z8.js.map +1 -0
- package/dist/{pull-COpNJFzY.js → pull-C3PXduzl.js} +13 -40
- package/dist/pull-C3PXduzl.js.map +1 -0
- package/dist/resolve-CNQjsatH.js +2 -0
- package/dist/resources/derive.d.ts +9 -0
- package/dist/{resources-CLm6g0br.js → resources-BdNRDEAy.js} +3 -3
- package/dist/{resources-CLm6g0br.js.map → resources-BdNRDEAy.js.map} +1 -1
- package/dist/{schema-BKdh6UoE.js → schema-B0-p6T1O.js} +4 -4
- package/dist/{schema-BKdh6UoE.js.map → schema-B0-p6T1O.js.map} +1 -1
- package/dist/{skills-DEhYiPeO.js → skills-DfnTeyRz.js} +3 -3
- package/dist/{skills-DEhYiPeO.js.map → skills-DfnTeyRz.js.map} +1 -1
- package/dist/{start-BsPJedPQ.js → start-BmEZkS0n.js} +4 -4
- package/dist/{start-BsPJedPQ.js.map → start-BmEZkS0n.js.map} +1 -1
- package/dist/{status-D_B3tlDy.js → status-BJ26yZOo.js} +9 -9
- package/dist/{status-D_B3tlDy.js.map → status-BJ26yZOo.js.map} +1 -1
- package/dist/{storage-CtB8polS.js → storage-DKPUBTWG.js} +3 -3
- package/dist/{storage-CtB8polS.js.map → storage-DKPUBTWG.js.map} +1 -1
- package/dist/{telemetry-BYmPU-Ji.js → telemetry-m9czTNGR.js} +2 -2
- package/dist/{telemetry-BYmPU-Ji.js.map → telemetry-m9czTNGR.js.map} +1 -1
- package/dist/{upgrade-DbuKX9lv.js → upgrade-DjihWuZL.js} +5 -4
- package/dist/{upgrade-DbuKX9lv.js.map → upgrade-DjihWuZL.js.map} +1 -1
- package/dist/utils/args.d.ts +13 -0
- package/dist/utils/redact.d.ts +10 -0
- package/dist/utils/refusal.d.ts +18 -0
- package/package.json +7 -7
- package/templates/overlays/baas/README.md +2 -1
- package/templates/template/.env.example +6 -0
- package/templates/template/frontend/vite.config.ts +7 -73
- package/dist/api-keys-Bc4FJKYp.js.map +0 -1
- package/dist/args-CcBphFdj.js.map +0 -1
- package/dist/auth-BL7bNQVu.js.map +0 -1
- package/dist/bundle-CqURVN-K.js.map +0 -1
- package/dist/daemon-entry-C6pxdily.js.map +0 -1
- package/dist/db-Dkn9XhT-.js.map +0 -1
- package/dist/dev-preflight-CorMg7Ub.js.map +0 -1
- package/dist/init-CjoJoThg.js.map +0 -1
- package/dist/last-dev-database-BEBPfAMY.js +0 -2
- package/dist/prepare-C1iaiTC4.js.map +0 -1
- package/dist/pull-COpNJFzY.js.map +0 -1
- package/dist/resolve-b_p9bmdH.js +0 -2
|
@@ -3,7 +3,7 @@ import { defineConfig } from "vite";
|
|
|
3
3
|
import react from "@vitejs/plugin-react";
|
|
4
4
|
import svgr from "vite-plugin-svgr";
|
|
5
5
|
import tailwindcss from "@tailwindcss/vite";
|
|
6
|
-
import { rebaseCollectionsPlugin } from "@rebasepro/app/vitePlugin";
|
|
6
|
+
import { rebaseCollectionsPlugin, rebaseManualChunks } from "@rebasepro/app/vitePlugin";
|
|
7
7
|
|
|
8
8
|
export default defineConfig({
|
|
9
9
|
// `import.meta.dirname`, not `__dirname`: vite 8 warns that the latter is
|
|
@@ -46,78 +46,12 @@ export default defineConfig({
|
|
|
46
46
|
chunkSizeWarningLimit: Infinity,
|
|
47
47
|
rollupOptions: {
|
|
48
48
|
output: {
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
// that. Switch to the import in the first release that
|
|
56
|
-
// publishes it.
|
|
57
|
-
manualChunks(id) {
|
|
58
|
-
// Heavy vendor libraries — split into individually cached chunks.
|
|
59
|
-
//
|
|
60
|
-
// A name here says these modules travel TOGETHER. It does not
|
|
61
|
-
// say they travel late: a chunk becomes a static dependency of
|
|
62
|
-
// the entry — and so a `modulepreload` in index.html — the
|
|
63
|
-
// moment any one module in it is statically reachable. Naming
|
|
64
|
-
// a library that is only partly lazy therefore drags the lazy
|
|
65
|
-
// part onto the critical path. Read the two exceptions below
|
|
66
|
-
// before adding a line.
|
|
67
|
-
|
|
68
|
-
// @rollup/plugin-commonjs emits its shared helpers as two
|
|
69
|
-
// virtual modules ("\0commonjsHelpers.js" and
|
|
70
|
-
// "\0commonjs-dynamic-modules") that every CommonJS
|
|
71
|
-
// dependency reaches, the entry's included. They match no
|
|
72
|
-
// rule below, so Rollup parks them in one of the chunks
|
|
73
|
-
// that use them — and it chose `vendor-exceljs`, which
|
|
74
|
-
// meant the entry statically imported 940 kB of
|
|
75
|
-
// spreadsheet reader to get a ten-line `require` shim.
|
|
76
|
-
// Give the helpers a chunk of their own so they can never
|
|
77
|
-
// anchor a heavy one to the critical path.
|
|
78
|
-
if (id.includes("commonjsHelpers") || id.includes("commonjs-dynamic-modules")) return "vendor-commonjs-helpers";
|
|
79
|
-
|
|
80
|
-
// Small libraries the entry needs, named before the heavy groups. A name
|
|
81
|
-
// takes the unassigned dependencies of its modules with it, so
|
|
82
|
-
// `prism-react-renderer` took `clsx` — which the kit imports statically — and
|
|
83
|
-
// the entry imported 85 kB of syntax highlighter for a 633-byte helper;
|
|
84
|
-
// React core landed in `vendor-dnd` the same way.
|
|
85
|
-
if (/[\\/]node_modules[\\/](react|scheduler|use-sync-external-store)[\\/]/.test(id)) return "vendor-react";
|
|
86
|
-
if (/[\\/]node_modules[\\/]clsx[\\/]/.test(id)) return "vendor-clsx";
|
|
87
|
-
|
|
88
|
-
if (id.includes("exceljs")) return "vendor-exceljs";
|
|
89
|
-
if (id.includes("prosemirror")) return "vendor-prosemirror";
|
|
90
|
-
if (id.includes("monaco-editor") || id.includes("@monaco-editor")) return "vendor-monaco";
|
|
91
|
-
if (id.includes("@xyflow") || id.includes("dagre")) return "vendor-xyflow";
|
|
92
|
-
if (id.includes("@dnd-kit")) return "vendor-dnd";
|
|
93
|
-
if (id.includes("prism-react-renderer")) return "vendor-prism";
|
|
94
|
-
if (id.includes("markdown-it")) return "vendor-markdown";
|
|
95
|
-
if (id.includes("react-dropzone")) return "vendor-dropzone";
|
|
96
|
-
// date-fns core only. The ~77 locales are imported one at a
|
|
97
|
-
// time by the admin's date preview; sharing a chunk name with
|
|
98
|
-
// the core would make all of them eager again.
|
|
99
|
-
if (id.includes("date-fns/locale")) return undefined;
|
|
100
|
-
if (id.includes("date-fns")) return "vendor-datefns";
|
|
101
|
-
if (id.includes("fuse.js")) return "vendor-fuse";
|
|
102
|
-
if (id.includes("node_modules/react-dom/")) return "vendor-react-dom";
|
|
103
|
-
if (id.includes("node_modules/react-router") || id.includes("node_modules/@remix-run")) return "vendor-react-router";
|
|
104
|
-
if (id.includes("node_modules/@radix-ui/")) return "vendor-radix";
|
|
105
|
-
if (id.includes("node_modules/framer-motion/")) return "vendor-framer-motion";
|
|
106
|
-
if (id.includes("node_modules/zod/")) return "vendor-zod";
|
|
107
|
-
if (id.includes("node_modules/i18next") || id.includes("node_modules/react-i18next")) return "vendor-i18next";
|
|
108
|
-
if (id.includes("node_modules/@floating-ui/")) return "vendor-floating-ui";
|
|
109
|
-
if (id.includes("node_modules/tailwind-merge/")) return "vendor-tailwind-merge";
|
|
110
|
-
if (id.includes("node_modules/notistack/")) return "vendor-notistack";
|
|
111
|
-
|
|
112
|
-
// lucide-react has no line on purpose. The ~130 icons the
|
|
113
|
-
// chrome imports by name are static; the by-name lookup map
|
|
114
|
-
// is fetched on demand. One chunk name cannot hold both apart,
|
|
115
|
-
// and naming it welded 822 kB of icons into the preload set.
|
|
116
|
-
// Left to Rollup, the named icons land in the entry and the
|
|
117
|
-
// map gets its own async chunk.
|
|
118
|
-
|
|
119
|
-
return undefined;
|
|
120
|
-
}
|
|
49
|
+
// How the admin's dependencies are split into cached chunks,
|
|
50
|
+
// from the package rather than copied in, so an upgrade of
|
|
51
|
+
// `@rebasepro/app` brings its improvements with it. Write your
|
|
52
|
+
// own function here if you need to split this app's code too,
|
|
53
|
+
// and return `rebaseManualChunks(id)` for the rest.
|
|
54
|
+
manualChunks: rebaseManualChunks
|
|
121
55
|
}
|
|
122
56
|
}
|
|
123
57
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys-Bc4FJKYp.js","names":[],"sources":["../src/commands/api-keys.ts"],"sourcesContent":["/**\n * CLI command: rebase api-keys <action>\n *\n * The project's service keys, through `/api/admin/api-keys`, authenticated with\n * the service key from `.env`.\n *\n * Subcommands:\n * list — List the service keys (masked): kind, scopes, roles\n * get — Show one key\n * create — Create a service key holding the scopes named on the line\n * revoke — Revoke a key\n * scopes — List the scopes this backend knows, and which the caller holds\n */\nimport chalk from \"chalk\";\nimport type arg from \"arg\";\nimport { createRebaseClient, RebaseApiError } from \"@rebasepro/client\";\nimport {\n ADMIN_SCOPES,\n DATA_PLANE_SCOPES,\n KEY_MANAGEMENT_SCOPES,\n parseScope,\n type ApiKeyMasked,\n type ApiKeyWithSecret,\n type CreateApiKeyRequest,\n type ScopeSummary\n} from \"@rebasepro/types\";\nimport {\n requireProjectRoot,\n readEnvFile\n} from \"../utils/project\";\nimport { parseCommandArgs, UsageError, wantsHelp } from \"../utils/args\";\nimport { unknownCommand } from \"../utils/unknown-command\";\nimport { cliUserAgent } from \"../utils/version\";\nimport { serverUnreachableHint } from \"../utils/dev-server\";\nimport fs from \"fs\";\nimport path from \"path\";\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const API_KEYS_SUBCOMMANDS = [\"list\", \"get\", \"create\", \"revoke\", \"scopes\"] as const;\n\n/* ═══════════════════════════════════════════════════════════════\n Env helper — reads SERVICE_KEY and PORT from .env\n ═══════════════════════════════════════════════════════════════ */\n\n/**\n * Was a hand-rolled `indexOf(\"=\")` loop. It keyed `export KEY=value` as\n * `export KEY` and carried a trailing `# comment` into the value — so a key\n * that was present read as absent, or reached an `Authorization` header with a\n * comment attached and came back 401. See `readEnvFile`.\n */\nconst loadEnv = readEnvFile;\n\n/**\n * Where this project's backend is — or why the CLI will not say.\n *\n * `configured` is an address the developer named; `running` is the one this\n * project's backend recorded when it bound, and is still serving on. There is\n * no third, guessed, answer: the request carries the project's service key —\n * the `admin` role, every scope — and an address the CLI only guessed is one it\n * would hand that key to without knowing whose server answers.\n */\nexport type BackendAddress =\n | { url: string; source: \"configured\" | \"running\" }\n | { url: null; reason: string };\n\n/** Whether a process with this pid is alive and ours to signal. */\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n // ESRCH: gone. EPERM: alive, but another user's — not this project's backend.\n return false;\n }\n}\n\n/**\n * The address the service key may be sent to. Shared with `rebase storage`.\n *\n * In order:\n *\n * 1. `REBASE_BASE_URL`, in the shell or in `.env` — the developer said where.\n * 2. `.rebase/state.json`, which this project's backend writes when it binds\n * and removes when it stops — and only while the pid it names is alive,\n * because a backend that was killed leaves the file behind.\n *\n * Nothing else. `.env`'s `PORT` was the fallback, and every scaffold writes\n * `PORT=3001`: with `rebase dev` stopped, `rebase api-keys list` sent this\n * project's service key to whatever listened on 3001 — on the tester's machine,\n * another project's server. `.rebase-dev-url` is not enough on its own either:\n * a `rebase dev` that was killed leaves it behind, pointing at a port some\n * other server may have taken since.\n */\nexport function resolveBackendAddress(env: Record<string, string>, projectRoot: string): BackendAddress {\n const configured = process.env.REBASE_BASE_URL?.trim() || env.REBASE_BASE_URL?.trim();\n if (configured) return { url: configured, source: \"configured\" };\n\n const state = readBackendState(projectRoot);\n if (state && isAlive(state.pid)) return { url: state.url, source: \"running\" };\n\n const last = state ? ` The last one recorded here, at ${state.url} (pid ${state.pid}), has stopped.` : \"\";\n return {\n url: null,\n reason: `This project's server is not running, so the service key was not sent anywhere.${last} ` +\n \"Start it with `rebase dev`. If it runs some other way — `rebase start`, a container — \" +\n \"set REBASE_BASE_URL in .env to its address.\"\n };\n}\n\n/** What `.rebase/state.json` says about the backend that wrote it, or null. */\nfunction readBackendState(projectRoot: string): { url: string; pid: number } | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(fs.readFileSync(path.join(projectRoot, \".rebase\", \"state.json\"), \"utf-8\"));\n } catch {\n return null;\n }\n if (!isRecord(parsed) || typeof parsed.pid !== \"number\" || !Number.isInteger(parsed.pid) || parsed.pid <= 0) return null;\n const url = typeof parsed.baseUrl === \"string\" && parsed.baseUrl.trim()\n ? parsed.baseUrl.trim()\n : typeof parsed.port === \"number\" ? `http://localhost:${parsed.port}` : null;\n\n return url ? { url, pid: parsed.pid } : null;\n}\n\n/**\n * The address to send the service key to, or the end of the command.\n *\n * Exits before any request is made: the refusal is the point.\n */\nexport function requireBackendUrl(env: Record<string, string>, projectRoot: string): string {\n const address = resolveBackendAddress(env, projectRoot);\n if (address.url !== null) return address.url;\n\n console.error(chalk.red(\"✗ No server to send the request to.\"));\n console.error(chalk.gray(` ${address.reason}`));\n process.exit(1);\n}\n\n/* ═══════════════════════════════════════════════════════════════\n The backend, through the SDK\n ═══════════════════════════════════════════════════════════════ */\n\ntype ProjectClient = ReturnType<typeof createRebaseClient>;\n\ninterface Connection {\n client: ProjectClient;\n baseUrl: string;\n}\n\n/**\n * An SDK client for this project's backend, holding the service key.\n *\n * The service key is the project's own machine identity — the `admin` role,\n * every scope — so it is what may list, mint and revoke service keys. It is a\n * static bearer token: no session to restore or refresh, and no socket.\n */\nfunction connect(): Connection {\n const projectRoot = requireProjectRoot();\n const env = loadEnv(projectRoot);\n const serviceKey = env.SERVICE_KEY || env.REBASE_SERVICE_KEY;\n\n if (!serviceKey) {\n console.error(chalk.red(\"✗ SERVICE_KEY not found in .env — required to manage API keys.\"));\n process.exit(1);\n }\n const baseUrl = requireBackendUrl(env, projectRoot);\n\n const client = createRebaseClient({\n baseUrl,\n token: serviceKey,\n realtime: false,\n headers: { \"User-Agent\": cliUserAgent() },\n auth: { persistSession: false, autoRefresh: false }\n });\n return { client, baseUrl };\n}\n\n/**\n * What to print when a request fails: the server's error code and message,\n * which is what says why — `SCOPE_EXCEEDS_CREATOR`, `INVALID_SCOPES`,\n * `ROLE_EXCEEDS_CREATOR`, `KEY_MANAGEMENT_SCOPE` — and a hint where one helps.\n *\n * Exported so its tests can read the lines without a server.\n */\nexport function describeFailure(action: string, error: unknown, baseUrl: string): string[] {\n if (!(error instanceof RebaseApiError)) {\n return [`✗ ${action}: ${error instanceof Error ? error.message : String(error)}`];\n }\n if (error.status === 0 || error.code === \"NETWORK_ERROR\") {\n return [`✗ ${action}: ${error.message}`, ...serverUnreachableHint(baseUrl)];\n }\n\n const label = [error.code, error.status ? `(${error.status})` : undefined].filter(Boolean).join(\" \");\n const lines = [`✗ ${action}${label ? ` — ${label}` : \"\"}: ${error.message}`];\n\n if (error.status === 401) {\n lines.push(` The server at ${baseUrl} did not accept SERVICE_KEY from .env — is it this project's server?`);\n }\n // The message names the target that is not there; what *is* there rides\n // in `details`, and is the thing to pick from.\n if (error.code === \"UNKNOWN_SCOPE_TARGET\" && isRecord(error.details)) {\n for (const [kind, title] of [[\"collections\", \"Collections\"], [\"buckets\", \"Buckets\"], [\"functions\", \"Functions\"]] as const) {\n const names = error.details[kind];\n if (Array.isArray(names) && names.length > 0) {\n lines.push(` ${title}: ${names.map(String).join(\", \")}`);\n }\n }\n }\n return lines;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\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 process.exit(1);\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Entry\n ═══════════════════════════════════════════════════════════════ */\n\nexport async function apiKeysCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void> {\n // `--help` is answered before dispatch, never by a handler. `cli.ts` only\n // rewrites the subcommand to `\"--help\"` when none was named, so\n // `rebase api-keys list --help` used to *list the keys* and\n // `rebase api-keys revoke --help` sent `DELETE /api/admin/api-keys/--help`.\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printApiKeysHelp();\n return;\n }\n\n switch (subcommand) {\n case \"list\":\n await listKeys(rawArgs);\n break;\n case \"get\":\n await getKey(rawArgs);\n break;\n case \"create\":\n await createKey(rawArgs);\n break;\n case \"revoke\":\n await revokeKey(rawArgs);\n break;\n case \"scopes\":\n await listScopes(rawArgs);\n break;\n default:\n // The shape every other family uses. This one printed a bare line\n // to stderr *and* the whole help page to stdout, so a typo wrote\n // twenty lines to a stream a `--json` caller reads, with no `✗`, no\n // pointer at `--help`, and no did-you-mean — `craete` is one\n // transposition from `create`.\n unknownCommand(subcommand, API_KEYS_SUBCOMMANDS, \"api-keys\");\n }\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Showing a key\n ═══════════════════════════════════════════════════════════════ */\n\nfunction keyStatus(key: ApiKeyMasked, now: Date): string {\n if (key.revoked_at) return chalk.red(\"revoked\");\n if (key.expires_at && new Date(key.expires_at) < now) return chalk.yellow(\"expired\");\n return chalk.green(\"active\");\n}\n\n/**\n * The lines that describe one key: what it is, what it may do and whom it\n * runs as.\n *\n * A service key runs as the RLS role `service` plus its own `roles`; a\n * personal key runs as its owner's roles as they are when it is used, so it\n * has none of its own to show.\n *\n * Exported so its tests can read the lines without a server.\n */\nexport function describeKey(key: ApiKeyMasked, now: Date = new Date()): string[] {\n const field = (label: string, value: string) => ` ${chalk.gray(`${label}:`.padEnd(12))}${value}`;\n const roles = key.kind === \"personal\"\n ? `its owner's (${key.owner_uid ?? \"unknown\"})`\n : [\"service\", ...key.roles].join(\", \");\n\n const lines = [\n ` ${chalk.bold(key.name)} ${chalk.gray(`[${key.key_prefix}•••]`)} ${keyStatus(key, now)}`,\n field(\"ID\", key.id),\n field(\"Kind\", key.kind),\n field(\"Scopes\", key.scopes.length > 0 ? key.scopes.join(\", \") : chalk.gray(\"none\")),\n field(\"Roles\", roles)\n ];\n if (key.rate_limit !== null) lines.push(field(\"Rate limit\", `${key.rate_limit} requests / 15 min`));\n if (key.expires_at) lines.push(field(\"Expires\", new Date(key.expires_at).toLocaleDateString()));\n lines.push(field(\"Created\", new Date(key.created_at).toLocaleDateString()));\n if (key.last_used_at) lines.push(field(\"Last used\", new Date(key.last_used_at).toLocaleDateString()));\n return lines;\n}\n\n/* ═══════════════════════════════════════════════════════════════\n list\n ═══════════════════════════════════════════════════════════════ */\n\n/** The flags `rebase api-keys list` takes: none of its own. */\nexport const LIST_KEYS_FLAGS = {} as const;\n\nasync function listKeys(rawArgs: string[]): Promise<void> {\n parseCommandArgs({\n spec: LIST_KEYS_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"api-keys list\",\n maxPositionals: 0\n });\n\n const { client, baseUrl } = connect();\n let keys: ApiKeyMasked[];\n try {\n ({ keys } = await client.apiKeys.listKeys());\n } catch (e: unknown) {\n fail(\"Failed to list API keys\", e, baseUrl);\n }\n\n console.log(\"\");\n console.log(chalk.bold(\" 🔑 API Keys\"));\n console.log(\"\");\n\n if (keys.length === 0) {\n console.log(chalk.gray(\" No API keys found.\"));\n console.log(\"\");\n return;\n }\n\n const now = new Date();\n for (const key of keys) {\n for (const line of describeKey(key, now)) console.log(line);\n console.log(\"\");\n }\n}\n\n/* ═══════════════════════════════════════════════════════════════\n get\n ═══════════════════════════════════════════════════════════════ */\n\n/** The flags `rebase api-keys get` takes. */\nexport const GET_KEY_FLAGS = {\n \"--id\": String\n} as const;\n\n/**\n * Which key this invocation names, as a positional or as `--id`.\n *\n * Exported so its tests can drive the real parser rather than a copy of it.\n */\nexport function resolveGetKeyArgs(rawArgs: string[]): { id?: string } {\n const { flags, positionals } = parseCommandArgs({\n spec: GET_KEY_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"api-keys get\",\n maxPositionals: 1\n });\n\n return { id: flags[\"--id\"] || positionals[0] };\n}\n\nasync function getKey(rawArgs: string[]): Promise<void> {\n const { id } = resolveGetKeyArgs(rawArgs);\n if (!id) {\n throw new UsageError(\"Key ID is required: rebase api-keys get <key-id> (`rebase api-keys list` shows them).\");\n }\n\n const { client, baseUrl } = connect();\n let key: ApiKeyMasked;\n try {\n ({ key } = await client.apiKeys.getKey(id));\n } catch (e: unknown) {\n fail(\"Failed to read API key\", e, baseUrl);\n }\n\n console.log(\"\");\n for (const line of describeKey(key)) console.log(line);\n console.log(\"\");\n}\n\n/* ═══════════════════════════════════════════════════════════════\n create\n ═══════════════════════════════════════════════════════════════ */\n\n/** The flags `rebase api-keys create` takes. */\nexport const CREATE_KEY_FLAGS = {\n \"--name\": String,\n \"--scopes\": [String],\n \"--full-access\": Boolean,\n \"--roles\": [String],\n \"--rate-limit\": Number,\n \"--expires-in\": String,\n \"--expires-at\": String,\n \"-n\": \"--name\"\n} satisfies arg.Spec;\n\n/**\n * Options `create` refuses by name, each with the flag that does that job.\n *\n * Checked before the line is parsed: the strict parser would answer them\n * \"unknown option\", which does not say what to type instead.\n */\nexport const RETIRED_CREATE_OPTIONS: Readonly<Record<string, string>> = {\n \"--permissions\":\n \"--permissions is gone: name what the key may do with --scopes, e.g. \" +\n \"--scopes data:read:posts,data:write:posts (`rebase api-keys scopes` lists them).\",\n \"--admin\":\n \"--admin is gone: give the key the RLS role with --roles admin, and the admin-plane scopes it needs \" +\n \"with --scopes, e.g. --scopes users:read,schema:read.\",\n \"--expires\":\n \"--expires is gone: use --expires-in <days> (e.g. --expires-in 90) or --expires-at <ISO date>.\"\n};\n\n/** Refuse a retired option, wherever on the line and however it is spelled. */\nfunction refuseRetiredOptions(rawArgs: string[]): void {\n for (const token of rawArgs.slice(2)) {\n // Past `--` everything is a value, never an option.\n if (token === \"--\") return;\n const name = token.split(\"=\", 1)[0];\n const replacement = Object.prototype.hasOwnProperty.call(RETIRED_CREATE_OPTIONS, name)\n ? RETIRED_CREATE_OPTIONS[name]\n : undefined;\n if (replacement) throw new UsageError(replacement);\n }\n}\n\n/**\n * A list flag's values, whether repeated (`--scopes a --scopes b`) or\n * comma-separated (`--scopes a,b`) — or both — trimmed and deduplicated.\n * Whitespace separates too: no scope or role name contains any.\n */\nfunction splitList(values: readonly string[] | undefined): string[] {\n const out = new Set<string>();\n for (const value of values ?? []) {\n for (const entry of value.split(/[\\s,]+/)) {\n if (entry) out.add(entry);\n }\n }\n return [...out];\n}\n\nconst DAY_MS = 86_400_000;\n\nfunction resolveExpiry(expiresIn: string | undefined, expiresAt: string | undefined, now: Date): string | null {\n if (expiresIn !== undefined && expiresAt !== undefined) {\n throw new UsageError(\"Pass --expires-in or --expires-at, not both.\");\n }\n if (expiresIn !== undefined) {\n const days = /^\\d+$/.test(expiresIn.trim()) ? Number(expiresIn.trim()) : NaN;\n if (!Number.isSafeInteger(days) || days < 1) {\n throw new UsageError(`--expires-in takes a whole number of days, e.g. --expires-in 90 (got \"${expiresIn}\").`);\n }\n return new Date(now.getTime() + days * DAY_MS).toISOString();\n }\n if (expiresAt !== undefined) {\n const parsed = new Date(expiresAt);\n if (isNaN(parsed.getTime())) {\n throw new UsageError(`--expires-at takes an ISO date, e.g. --expires-at 2027-01-31 (got \"${expiresAt}\").`);\n }\n if (parsed.getTime() <= now.getTime()) {\n throw new UsageError(`--expires-at must be in the future (got ${parsed.toISOString()}).`);\n }\n return parsed.toISOString();\n }\n return null;\n}\n\n/** What `rebase api-keys create` was asked to mint. */\nexport interface CreateKeyPlan {\n name: string;\n /** The scopes named with `--scopes`, or `\"held\"` for `--full-access`. */\n scopes: string[] | \"held\";\n /** RLS roles beside `service`. */\n roles: string[];\n rate_limit: number | null;\n expires_at: string | null;\n}\n\n/**\n * What this invocation asks to be created.\n *\n * The name may be given either way — `--name \"My Key\"` or as the single\n * positional — and under the old permissive parse an undeclared flag became\n * that positional: `rebase api-keys create --debug --full-access` created a\n * key called `--debug` with access to everything, and `--debug` is what the\n * CLI prints after every failure as the thing to re-run with. Strict parsing\n * makes the flag an error instead of a name.\n *\n * What the key may do has to be asked for by name — `--scopes` or\n * `--full-access` — never defaulted: a forgotten flag must not mint a key that\n * reaches everything.\n *\n * Exported so its tests can drive the real parser rather than a copy of it.\n */\nexport function resolveCreateKeyArgs(rawArgs: string[], now: Date = new Date()): CreateKeyPlan {\n refuseRetiredOptions(rawArgs);\n\n const { flags, positionals } = parseCommandArgs({\n spec: CREATE_KEY_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"api-keys create\",\n maxPositionals: 1\n });\n\n const name = (flags[\"--name\"] || positionals[0] || \"\").trim();\n if (!name) {\n throw new UsageError('A key needs a name: rebase api-keys create \"CI\" --scopes data:read');\n }\n\n const named = splitList(flags[\"--scopes\"]);\n const fullAccess = flags[\"--full-access\"] === true;\n if (fullAccess && named.length > 0) {\n throw new UsageError(\"Pass --scopes or --full-access, not both: --full-access already means every scope you hold.\");\n }\n if (!fullAccess && named.length === 0) {\n throw new UsageError(\n \"Name what the key may do: --scopes data:read:posts,data:write:posts, or --full-access for every \" +\n \"scope you hold. `rebase api-keys scopes` lists them.\"\n );\n }\n\n const rateLimit = flags[\"--rate-limit\"];\n if (rateLimit !== undefined && (!Number.isSafeInteger(rateLimit) || rateLimit < 1)) {\n throw new UsageError(\"--rate-limit takes a whole number of requests per 15-minute window, e.g. --rate-limit 500.\");\n }\n\n return {\n name,\n scopes: fullAccess ? \"held\" : named,\n roles: splitList(flags[\"--roles\"]),\n rate_limit: rateLimit ?? null,\n expires_at: resolveExpiry(flags[\"--expires-in\"], flags[\"--expires-at\"], now)\n };\n}\n\n/**\n * The scopes `--full-access` puts on a key: every one the caller holds, less\n * key management, which no key may hold.\n *\n * Exported so its tests can check the subtraction without a server.\n */\nexport function grantableScopes(held: readonly string[]): string[] {\n const management: readonly string[] = KEY_MANAGEMENT_SCOPES;\n return held.filter(entry => !management.includes(parseScope(entry)?.scope ?? entry));\n}\n\nasync function createKey(rawArgs: string[]): Promise<void> {\n const plan = resolveCreateKeyArgs(rawArgs);\n const { client, baseUrl } = connect();\n\n let scopes: string[];\n if (plan.scopes === \"held\") {\n let held: string[];\n try {\n ({ held } = await client.personalKeys.listScopes());\n } catch (e: unknown) {\n fail(\"Failed to read the scopes you hold\", e, baseUrl);\n }\n scopes = grantableScopes(held);\n if (scopes.length === 0) {\n console.error(chalk.red(\"✗ You hold no scope a key may carry, so --full-access has nothing to grant.\"));\n process.exit(1);\n }\n } else {\n scopes = plan.scopes;\n }\n\n const request: CreateApiKeyRequest = {\n name: plan.name,\n scopes,\n ...(plan.roles.length > 0 ? { roles: plan.roles } : {}),\n ...(plan.rate_limit !== null ? { rate_limit: plan.rate_limit } : {}),\n ...(plan.expires_at !== null ? { expires_at: plan.expires_at } : {})\n };\n\n let created: ApiKeyWithSecret;\n try {\n ({ key: created } = await client.apiKeys.createKey(request));\n } catch (e: unknown) {\n fail(\"Failed to create API key\", e, baseUrl);\n }\n\n console.log(\"\");\n console.log(chalk.bold.green(\" ✓ API key created\"));\n console.log(\"\");\n for (const line of describeKey(created)) console.log(line);\n console.log(\"\");\n console.log(chalk.bold.yellow(\" ⚠ Copy your key now — it won't be shown again:\"));\n console.log(\"\");\n console.log(` ${chalk.cyan(created.key)}`);\n console.log(\"\");\n}\n\n/* ═══════════════════════════════════════════════════════════════\n revoke\n ═══════════════════════════════════════════════════════════════ */\n\n/** The flags `rebase api-keys revoke` takes. */\nexport const REVOKE_KEY_FLAGS = {\n \"--id\": String\n} as const;\n\n/**\n * Which key this invocation names.\n *\n * The id is a positional, so the permissive parse handed one straight to the\n * DELETE: `rebase api-keys revoke --foo` sent\n * `DELETE /api/admin/api-keys/--foo`, and `rebase --debug api-keys revoke <id>`\n * shifted the words along and revoked the key named `revoke`.\n *\n * Exported so its tests can drive the real parser rather than a copy of it.\n */\nexport function resolveRevokeKeyArgs(rawArgs: string[]): { id?: string } {\n const { flags, positionals } = parseCommandArgs({\n spec: REVOKE_KEY_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"api-keys revoke\",\n maxPositionals: 1\n });\n\n return { id: flags[\"--id\"] || positionals[0] };\n}\n\nasync function revokeKey(rawArgs: string[]): Promise<void> {\n const { id } = resolveRevokeKeyArgs(rawArgs);\n\n if (!id) {\n throw new UsageError(\"Key ID is required: rebase api-keys revoke <key-id> (`rebase api-keys list` shows them).\");\n }\n\n const { client, baseUrl } = connect();\n try {\n await client.apiKeys.revokeKey(id);\n } catch (e: unknown) {\n fail(\"Failed to revoke API key\", e, baseUrl);\n }\n\n console.log(\"\");\n console.log(chalk.bold.green(\" ✓ API key revoked\"));\n console.log(` ${chalk.gray(\"ID:\")} ${id}`);\n console.log(\"\");\n}\n\n/* ═══════════════════════════════════════════════════════════════\n scopes\n ═══════════════════════════════════════════════════════════════ */\n\n/** The flags `rebase api-keys scopes` takes: none of its own. */\nexport const SCOPES_LIST_FLAGS = {} as const;\n\nconst PLANES: ReadonlyArray<{ plane: ScopeSummary[\"plane\"]; title: string; note: string }> = [\n { plane: \"data\", title: \"Data\", note: \"narrow what a key reaches; row-level security still decides the rows\" },\n { plane: \"admin\", title: \"Admin\", note: \"nobody holds these unless a role grants them; the admin role holds all\" },\n { plane: \"app\", title: \"App\", note: \"declared by this app under auth.scopes on the users collection\" }\n];\n\n/**\n * The scope catalogue as printed lines: one section per plane, each scope with\n * its label and what its target names, marked when the caller holds it.\n *\n * Exported so its tests can read the lines without a server.\n */\nexport function describeScopes(scopes: readonly ScopeSummary[], held: readonly string[]): string[] {\n const management: readonly string[] = KEY_MANAGEMENT_SCOPES;\n const width = Math.max(0, ...scopes.map(s => s.scope.length)) + 2;\n const labelWidth = Math.max(0, ...scopes.map(s => s.label.length)) + 2;\n const lines: string[] = [];\n for (const { plane, title, note } of PLANES) {\n const inPlane = scopes.filter(s => s.plane === plane);\n if (inPlane.length === 0) continue;\n lines.push(` ${chalk.bold(title)} ${chalk.gray(`— ${note}`)}`);\n for (const s of inPlane) {\n const mark = held.includes(s.scope) ? chalk.green(\"✓\") : \" \";\n const extra = management.includes(s.scope)\n ? chalk.gray(\"never on a key\")\n : s.target ? chalk.gray(`:<${s.target}>`) : \"\";\n lines.push(` ${mark} ${s.scope.padEnd(width)}${extra ? s.label.padEnd(labelWidth) : s.label}${extra}`);\n }\n lines.push(\"\");\n }\n return lines;\n}\n\nasync function listScopes(rawArgs: string[]): Promise<void> {\n parseCommandArgs({\n spec: SCOPES_LIST_FLAGS,\n rawArgs,\n commandWords: 2,\n command: \"api-keys scopes\",\n maxPositionals: 0\n });\n\n const { client, baseUrl } = connect();\n let catalogue: { scopes: ScopeSummary[]; held: string[] };\n try {\n catalogue = await client.personalKeys.listScopes();\n } catch (e: unknown) {\n fail(\"Failed to read the scopes\", e, baseUrl);\n }\n\n console.log(\"\");\n console.log(chalk.bold(\" Scopes\") + chalk.gray(\" (✓ = you hold it; :<target> narrows it to one)\"));\n console.log(\"\");\n for (const line of describeScopes(catalogue.scopes, catalogue.held)) console.log(line);\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Help\n ═══════════════════════════════════════════════════════════════ */\n\nfunction printApiKeysHelp() {\n const keyable = ADMIN_SCOPES.filter(scope => !(KEY_MANAGEMENT_SCOPES as readonly string[]).includes(scope));\n console.log(`\n${chalk.bold(\"rebase api-keys\")} — Manage service API keys\n\n${chalk.green.bold(\"Usage\")}\n rebase api-keys ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.blue.bold(\"list\")} List the service keys: kind, scopes, roles\n ${chalk.blue.bold(\"get\")} ${chalk.gray(\"<id>\")} Show one key\n ${chalk.blue.bold(\"create\")} Create a service key\n ${chalk.blue.bold(\"revoke\")} ${chalk.gray(\"<id>\")} Revoke a key\n ${chalk.blue.bold(\"scopes\")} List the scopes this backend knows, and which you hold\n\n${chalk.green.bold(\"create Options\")}\n ${chalk.blue(\"--name, -n\")} Key name ${chalk.gray(\"(required; or the first argument)\")}\n ${chalk.blue(\"--scopes\")} What the key may do, comma-separated or repeated\n ${chalk.gray(\"(required unless --full-access)\")}\n ${chalk.blue(\"--full-access\")} Every scope you hold, less keys:read and keys:write\n ${chalk.blue(\"--roles\")} RLS roles the key runs as beside ${chalk.gray(\"service\")}, e.g. admin\n ${chalk.blue(\"--rate-limit\")} Requests per 15-min window ${chalk.gray(\"(default: the server's API-key limit)\")}\n ${chalk.blue(\"--expires-in\")} Days until the key expires\n ${chalk.blue(\"--expires-at\")} Expiry as an ISO date, e.g. 2027-01-31\n\n${chalk.green.bold(\"get / revoke Options\")}\n ${chalk.blue(\"--id\")} API key ID ${chalk.gray(\"(or the first argument)\")}\n\n${chalk.green.bold(\"Scopes\")}\n A scope is ${chalk.blue(\"resource:action\")}, optionally narrowed to one target:\n ${chalk.blue(\"data:read:posts\")} reads the posts collection and nothing else.\n Data ${DATA_PLANE_SCOPES.join(\", \")}\n ${chalk.gray(\"target: a collection slug, a storage source id (default), a function name\")}\n Admin ${keyable.join(\", \")}\n App whatever the app declares under auth.scopes ${chalk.gray(\"(rebase api-keys scopes)\")}\n\n${chalk.green.bold(\"Examples\")}\n rebase api-keys list\n rebase api-keys create \"Analytics\" --scopes data:read:events\n rebase api-keys create -n \"Blog CI\" --scopes data:read:posts,data:write:posts --expires-in 90\n rebase api-keys create -n \"Mailer\" --scopes \"functions:invoke:send-email,storage:read:(default)\"\n rebase api-keys create -n \"Ops\" --full-access --roles admin --expires-at 2027-01-31\n rebase api-keys get abc123-def456\n rebase api-keys revoke abc123-def456\n`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCA,IAAa,uBAAuB;CAAC;CAAQ;CAAO;CAAU;CAAU;AAAQ;;;;;;;AAYhF,IAAM,UAAU;;AAgBhB,SAAS,QAAQ,KAAsB;CACnC,IAAI;EACA,QAAQ,KAAK,KAAK,CAAC;EACnB,OAAO;CACX,QAAQ;EAEJ,OAAO;CACX;AACJ;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,sBAAsB,KAA6B,aAAqC;CACpG,MAAM,aAAa,QAAQ,IAAI,iBAAiB,KAAK,KAAK,IAAI,iBAAiB,KAAK;CACpF,IAAI,YAAY,OAAO;EAAE,KAAK;EAAY,QAAQ;CAAa;CAE/D,MAAM,QAAQ,iBAAiB,WAAW;CAC1C,IAAI,SAAS,QAAQ,MAAM,GAAG,GAAG,OAAO;EAAE,KAAK,MAAM;EAAK,QAAQ;CAAU;CAG5E,OAAO;EACH,KAAK;EACL,QAAQ,kFAHC,QAAQ,mCAAmC,MAAM,IAAI,QAAQ,MAAM,IAAI,mBAAmB,GAGJ;CAGnG;AACJ;;AAGA,SAAS,iBAAiB,aAA0D;CAChF,IAAI;CACJ,IAAI;EACA,SAAS,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,aAAa,WAAW,YAAY,GAAG,OAAO,CAAC;CACjG,QAAQ;EACJ,OAAO;CACX;CACA,IAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO,QAAQ,YAAY,CAAC,OAAO,UAAU,OAAO,GAAG,KAAK,OAAO,OAAO,GAAG,OAAO;CACpH,MAAM,MAAM,OAAO,OAAO,YAAY,YAAY,OAAO,QAAQ,KAAK,IAChE,OAAO,QAAQ,KAAK,IACpB,OAAO,OAAO,SAAS,WAAW,oBAAoB,OAAO,SAAS;CAE5E,OAAO,MAAM;EAAE;EAAK,KAAK,OAAO;CAAI,IAAI;AAC5C;;;;;;AAOA,SAAgB,kBAAkB,KAA6B,aAA6B;CACxF,MAAM,UAAU,sBAAsB,KAAK,WAAW;CACtD,IAAI,QAAQ,QAAQ,MAAM,OAAO,QAAQ;CAEzC,QAAQ,MAAM,MAAM,IAAI,qCAAqC,CAAC;CAC9D,QAAQ,MAAM,MAAM,KAAK,KAAK,QAAQ,QAAQ,CAAC;CAC/C,QAAQ,KAAK,CAAC;AAClB;;;;;;;;AAoBA,SAAS,UAAsB;CAC3B,MAAM,cAAc,mBAAmB;CACvC,MAAM,MAAM,QAAQ,WAAW;CAC/B,MAAM,aAAa,IAAI,eAAe,IAAI;CAE1C,IAAI,CAAC,YAAY;EACb,QAAQ,MAAM,MAAM,IAAI,gEAAgE,CAAC;EACzF,QAAQ,KAAK,CAAC;CAClB;CACA,MAAM,UAAU,kBAAkB,KAAK,WAAW;CASlD,OAAO;EAAE,QAPM,mBAAmB;GAC9B;GACA,OAAO;GACP,UAAU;GACV,SAAS,EAAE,cAAc,aAAa,EAAE;GACxC,MAAM;IAAE,gBAAgB;IAAO,aAAa;GAAM;EACtD,CACS;EAAQ;CAAQ;AAC7B;;;;;;;;AASA,SAAgB,gBAAgB,QAAgB,OAAgB,SAA2B;CACvF,IAAI,EAAE,iBAAiB,iBACnB,OAAO,CAAC,KAAK,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CAEpF,IAAI,MAAM,WAAW,KAAK,MAAM,SAAS,iBACrC,OAAO,CAAC,KAAK,OAAO,IAAI,MAAM,WAAW,GAAG,sBAAsB,OAAO,CAAC;CAG9E,MAAM,QAAQ,CAAC,MAAM,MAAM,MAAM,SAAS,IAAI,MAAM,OAAO,KAAK,KAAA,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CACnG,MAAM,QAAQ,CAAC,KAAK,SAAS,QAAQ,MAAM,UAAU,GAAG,IAAI,MAAM,SAAS;CAE3E,IAAI,MAAM,WAAW,KACjB,MAAM,KAAK,mBAAmB,QAAQ,qEAAqE;CAI/G,IAAI,MAAM,SAAS,0BAA0B,SAAS,MAAM,OAAO,GAC/D,KAAK,MAAM,CAAC,MAAM,UAAU;EAAC,CAAC,eAAe,aAAa;EAAG,CAAC,WAAW,SAAS;EAAG,CAAC,aAAa,WAAW;CAAC,GAAY;EACvH,MAAM,QAAQ,MAAM,QAAQ;EAC5B,IAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,GACvC,MAAM,KAAK,KAAK,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,IAAI,GAAG;CAEhE;CAEJ,OAAO;AACX;AAEA,SAAS,SAAS,OAAkD;CAChE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;AAEA,SAAS,KAAK,QAAgB,OAAgB,SAAwB;CAClE,KAAK,MAAM,QAAQ,gBAAgB,QAAQ,OAAO,OAAO,GACrD,QAAQ,MAAM,KAAK,WAAW,GAAG,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC;CAE3E,QAAQ,KAAK,CAAC;AAClB;AAMA,eAAsB,eAAe,YAAgC,SAAkC;CAKnG,IAAI,CAAC,cAAc,eAAe,YAAY,UAAU,OAAO,GAAG;EAC9D,iBAAiB;EACjB;CACJ;CAEA,QAAQ,YAAR;EACI,KAAK;GACD,MAAM,SAAS,OAAO;GACtB;EACJ,KAAK;GACD,MAAM,OAAO,OAAO;GACpB;EACJ,KAAK;GACD,MAAM,UAAU,OAAO;GACvB;EACJ,KAAK;GACD,MAAM,UAAU,OAAO;GACvB;EACJ,KAAK;GACD,MAAM,WAAW,OAAO;GACxB;EACJ,SAMI,eAAe,YAAY,sBAAsB,UAAU;CACnE;AACJ;AAMA,SAAS,UAAU,KAAmB,KAAmB;CACrD,IAAI,IAAI,YAAY,OAAO,MAAM,IAAI,SAAS;CAC9C,IAAI,IAAI,cAAc,IAAI,KAAK,IAAI,UAAU,IAAI,KAAK,OAAO,MAAM,OAAO,SAAS;CACnF,OAAO,MAAM,MAAM,QAAQ;AAC/B;;;;;;;;;;;AAYA,SAAgB,YAAY,KAAmB,sBAAY,IAAI,KAAK,GAAa;CAC7E,MAAM,SAAS,OAAe,UAAkB,KAAK,MAAM,KAAK,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC,IAAI;CAC1F,MAAM,QAAQ,IAAI,SAAS,aACrB,gBAAgB,IAAI,aAAa,UAAU,KAC3C,CAAC,WAAW,GAAG,IAAI,KAAK,CAAC,CAAC,KAAK,IAAI;CAEzC,MAAM,QAAQ;EACV,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,KAAK,IAAI,IAAI,WAAW,KAAK,EAAE,GAAG,UAAU,KAAK,GAAG;EACvF,MAAM,MAAM,IAAI,EAAE;EAClB,MAAM,QAAQ,IAAI,IAAI;EACtB,MAAM,UAAU,IAAI,OAAO,SAAS,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC;EAClF,MAAM,SAAS,KAAK;CACxB;CACA,IAAI,IAAI,eAAe,MAAM,MAAM,KAAK,MAAM,cAAc,GAAG,IAAI,WAAW,mBAAmB,CAAC;CAClG,IAAI,IAAI,YAAY,MAAM,KAAK,MAAM,WAAW,IAAI,KAAK,IAAI,UAAU,CAAC,CAAC,mBAAmB,CAAC,CAAC;CAC9F,MAAM,KAAK,MAAM,WAAW,IAAI,KAAK,IAAI,UAAU,CAAC,CAAC,mBAAmB,CAAC,CAAC;CAC1E,IAAI,IAAI,cAAc,MAAM,KAAK,MAAM,aAAa,IAAI,KAAK,IAAI,YAAY,CAAC,CAAC,mBAAmB,CAAC,CAAC;CACpG,OAAO;AACX;;AAOA,IAAa,kBAAkB,CAAC;AAEhC,eAAe,SAAS,SAAkC;CACtD,iBAAiB;EACb,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,MAAM,EAAE,QAAQ,YAAY,QAAQ;CACpC,IAAI;CACJ,IAAI;EACA,CAAC,CAAE,QAAS,MAAM,OAAO,QAAQ,SAAS;CAC9C,SAAS,GAAY;EACjB,KAAK,2BAA2B,GAAG,OAAO;CAC9C;CAEA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,eAAe,CAAC;CACvC,QAAQ,IAAI,EAAE;CAEd,IAAI,KAAK,WAAW,GAAG;EACnB,QAAQ,IAAI,MAAM,KAAK,sBAAsB,CAAC;EAC9C,QAAQ,IAAI,EAAE;EACd;CACJ;CAEA,MAAM,sBAAM,IAAI,KAAK;CACrB,KAAK,MAAM,OAAO,MAAM;EACpB,KAAK,MAAM,QAAQ,YAAY,KAAK,GAAG,GAAG,QAAQ,IAAI,IAAI;EAC1D,QAAQ,IAAI,EAAE;CAClB;AACJ;;AAOA,IAAa,gBAAgB,EACzB,QAAQ,OACZ;;;;;;AAOA,SAAgB,kBAAkB,SAAoC;CAClE,MAAM,EAAE,OAAO,gBAAgB,iBAAiB;EAC5C,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,OAAO,EAAE,IAAI,MAAM,WAAW,YAAY,GAAG;AACjD;AAEA,eAAe,OAAO,SAAkC;CACpD,MAAM,EAAE,OAAO,kBAAkB,OAAO;CACxC,IAAI,CAAC,IACD,MAAM,IAAI,WAAW,uFAAuF;CAGhH,MAAM,EAAE,QAAQ,YAAY,QAAQ;CACpC,IAAI;CACJ,IAAI;EACA,CAAC,CAAE,OAAQ,MAAM,OAAO,QAAQ,OAAO,EAAE;CAC7C,SAAS,GAAY;EACjB,KAAK,0BAA0B,GAAG,OAAO;CAC7C;CAEA,QAAQ,IAAI,EAAE;CACd,KAAK,MAAM,QAAQ,YAAY,GAAG,GAAG,QAAQ,IAAI,IAAI;CACrD,QAAQ,IAAI,EAAE;AAClB;;AAOA,IAAa,mBAAmB;CAC5B,UAAU;CACV,YAAY,CAAC,MAAM;CACnB,iBAAiB;CACjB,WAAW,CAAC,MAAM;CAClB,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,MAAM;AACV;;;;;;;AAQA,IAAa,yBAA2D;CACpE,iBACI;CAEJ,WACI;CAEJ,aACI;AACR;;AAGA,SAAS,qBAAqB,SAAyB;CACnD,KAAK,MAAM,SAAS,QAAQ,MAAM,CAAC,GAAG;EAElC,IAAI,UAAU,MAAM;EACpB,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC,CAAC,CAAC;EACjC,MAAM,cAAc,OAAO,UAAU,eAAe,KAAK,wBAAwB,IAAI,IAC/E,uBAAuB,QACvB,KAAA;EACN,IAAI,aAAa,MAAM,IAAI,WAAW,WAAW;CACrD;AACJ;;;;;;AAOA,SAAS,UAAU,QAAiD;CAChE,MAAM,sBAAM,IAAI,IAAY;CAC5B,KAAK,MAAM,SAAS,UAAU,CAAC,GAC3B,KAAK,MAAM,SAAS,MAAM,MAAM,QAAQ,GACpC,IAAI,OAAO,IAAI,IAAI,KAAK;CAGhC,OAAO,CAAC,GAAG,GAAG;AAClB;AAEA,IAAM,SAAS;AAEf,SAAS,cAAc,WAA+B,WAA+B,KAA0B;CAC3G,IAAI,cAAc,KAAA,KAAa,cAAc,KAAA,GACzC,MAAM,IAAI,WAAW,8CAA8C;CAEvE,IAAI,cAAc,KAAA,GAAW;EACzB,MAAM,OAAO,QAAQ,KAAK,UAAU,KAAK,CAAC,IAAI,OAAO,UAAU,KAAK,CAAC,IAAI;EACzE,IAAI,CAAC,OAAO,cAAc,IAAI,KAAK,OAAO,GACtC,MAAM,IAAI,WAAW,yEAAyE,UAAU,IAAI;EAEhH,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,OAAO,MAAM,CAAC,CAAC,YAAY;CAC/D;CACA,IAAI,cAAc,KAAA,GAAW;EACzB,MAAM,SAAS,IAAI,KAAK,SAAS;EACjC,IAAI,MAAM,OAAO,QAAQ,CAAC,GACtB,MAAM,IAAI,WAAW,sEAAsE,UAAU,IAAI;EAE7G,IAAI,OAAO,QAAQ,KAAK,IAAI,QAAQ,GAChC,MAAM,IAAI,WAAW,2CAA2C,OAAO,YAAY,EAAE,GAAG;EAE5F,OAAO,OAAO,YAAY;CAC9B;CACA,OAAO;AACX;;;;;;;;;;;;;;;;;AA6BA,SAAgB,qBAAqB,SAAmB,sBAAY,IAAI,KAAK,GAAkB;CAC3F,qBAAqB,OAAO;CAE5B,MAAM,EAAE,OAAO,gBAAgB,iBAAiB;EAC5C,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,MAAM,QAAQ,MAAM,aAAa,YAAY,MAAM,GAAA,CAAI,KAAK;CAC5D,IAAI,CAAC,MACD,MAAM,IAAI,WAAW,sEAAoE;CAG7F,MAAM,QAAQ,UAAU,MAAM,WAAW;CACzC,MAAM,aAAa,MAAM,qBAAqB;CAC9C,IAAI,cAAc,MAAM,SAAS,GAC7B,MAAM,IAAI,WAAW,6FAA6F;CAEtH,IAAI,CAAC,cAAc,MAAM,WAAW,GAChC,MAAM,IAAI,WACN,sJAEJ;CAGJ,MAAM,YAAY,MAAM;CACxB,IAAI,cAAc,KAAA,MAAc,CAAC,OAAO,cAAc,SAAS,KAAK,YAAY,IAC5E,MAAM,IAAI,WAAW,4FAA4F;CAGrH,OAAO;EACH;EACA,QAAQ,aAAa,SAAS;EAC9B,OAAO,UAAU,MAAM,UAAU;EACjC,YAAY,aAAa;EACzB,YAAY,cAAc,MAAM,iBAAiB,MAAM,iBAAiB,GAAG;CAC/E;AACJ;;;;;;;AAQA,SAAgB,gBAAgB,MAAmC;CAC/D,MAAM,aAAgC;CACtC,OAAO,KAAK,QAAO,UAAS,CAAC,WAAW,SAAS,WAAW,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC;AACvF;AAEA,eAAe,UAAU,SAAkC;CACvD,MAAM,OAAO,qBAAqB,OAAO;CACzC,MAAM,EAAE,QAAQ,YAAY,QAAQ;CAEpC,IAAI;CACJ,IAAI,KAAK,WAAW,QAAQ;EACxB,IAAI;EACJ,IAAI;GACA,CAAC,CAAE,QAAS,MAAM,OAAO,aAAa,WAAW;EACrD,SAAS,GAAY;GACjB,KAAK,sCAAsC,GAAG,OAAO;EACzD;EACA,SAAS,gBAAgB,IAAI;EAC7B,IAAI,OAAO,WAAW,GAAG;GACrB,QAAQ,MAAM,MAAM,IAAI,6EAA6E,CAAC;GACtG,QAAQ,KAAK,CAAC;EAClB;CACJ,OACI,SAAS,KAAK;CAGlB,MAAM,UAA+B;EACjC,MAAM,KAAK;EACX;EACA,GAAI,KAAK,MAAM,SAAS,IAAI,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EACrD,GAAI,KAAK,eAAe,OAAO,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EAClE,GAAI,KAAK,eAAe,OAAO,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;CACtE;CAEA,IAAI;CACJ,IAAI;EACA,CAAC,CAAE,KAAK,WAAY,MAAM,OAAO,QAAQ,UAAU,OAAO;CAC9D,SAAS,GAAY;EACjB,KAAK,4BAA4B,GAAG,OAAO;CAC/C;CAEA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,MAAM,qBAAqB,CAAC;CACnD,QAAQ,IAAI,EAAE;CACd,KAAK,MAAM,QAAQ,YAAY,OAAO,GAAG,QAAQ,IAAI,IAAI;CACzD,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,OAAO,kDAAkD,CAAC;CACjF,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,GAAG,GAAG;CAC1C,QAAQ,IAAI,EAAE;AAClB;;AAOA,IAAa,mBAAmB,EAC5B,QAAQ,OACZ;;;;;;;;;;;AAYA,SAAgB,qBAAqB,SAAoC;CACrE,MAAM,EAAE,OAAO,gBAAgB,iBAAiB;EAC5C,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,OAAO,EAAE,IAAI,MAAM,WAAW,YAAY,GAAG;AACjD;AAEA,eAAe,UAAU,SAAkC;CACvD,MAAM,EAAE,OAAO,qBAAqB,OAAO;CAE3C,IAAI,CAAC,IACD,MAAM,IAAI,WAAW,0FAA0F;CAGnH,MAAM,EAAE,QAAQ,YAAY,QAAQ;CACpC,IAAI;EACA,MAAM,OAAO,QAAQ,UAAU,EAAE;CACrC,SAAS,GAAY;EACjB,KAAK,4BAA4B,GAAG,OAAO;CAC/C;CAEA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,MAAM,qBAAqB,CAAC;CACnD,QAAQ,IAAI,KAAK,MAAM,KAAK,KAAK,EAAE,GAAG,IAAI;CAC1C,QAAQ,IAAI,EAAE;AAClB;;AAOA,IAAa,oBAAoB,CAAC;AAElC,IAAM,SAAuF;CACzF;EAAE,OAAO;EAAQ,OAAO;EAAQ,MAAM;CAAuE;CAC7G;EAAE,OAAO;EAAS,OAAO;EAAS,MAAM;CAAyE;CACjH;EAAE,OAAO;EAAO,OAAO;EAAO,MAAM;CAAiE;AACzG;;;;;;;AAQA,SAAgB,eAAe,QAAiC,MAAmC;CAC/F,MAAM,aAAgC;CACtC,MAAM,QAAQ,KAAK,IAAI,GAAG,GAAG,OAAO,KAAI,MAAK,EAAE,MAAM,MAAM,CAAC,IAAI;CAChE,MAAM,aAAa,KAAK,IAAI,GAAG,GAAG,OAAO,KAAI,MAAK,EAAE,MAAM,MAAM,CAAC,IAAI;CACrE,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,EAAE,OAAO,OAAO,UAAU,QAAQ;EACzC,MAAM,UAAU,OAAO,QAAO,MAAK,EAAE,UAAU,KAAK;EACpD,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,KAAK,KAAK,MAAM,KAAK,KAAK,EAAE,GAAG,MAAM,KAAK,KAAK,MAAM,GAAG;EAC9D,KAAK,MAAM,KAAK,SAAS;GACrB,MAAM,OAAO,KAAK,SAAS,EAAE,KAAK,IAAI,MAAM,MAAM,GAAG,IAAI;GACzD,MAAM,QAAQ,WAAW,SAAS,EAAE,KAAK,IACnC,MAAM,KAAK,gBAAgB,IAC3B,EAAE,SAAS,MAAM,KAAK,KAAK,EAAE,OAAO,EAAE,IAAI;GAChD,MAAM,KAAK,KAAK,KAAK,GAAG,EAAE,MAAM,OAAO,KAAK,IAAI,QAAQ,EAAE,MAAM,OAAO,UAAU,IAAI,EAAE,QAAQ,OAAO;EAC1G;EACA,MAAM,KAAK,EAAE;CACjB;CACA,OAAO;AACX;AAEA,eAAe,WAAW,SAAkC;CACxD,iBAAiB;EACb,MAAM;EACN;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,MAAM,EAAE,QAAQ,YAAY,QAAQ;CACpC,IAAI;CACJ,IAAI;EACA,YAAY,MAAM,OAAO,aAAa,WAAW;CACrD,SAAS,GAAY;EACjB,KAAK,6BAA6B,GAAG,OAAO;CAChD;CAEA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,kDAAkD,CAAC;CACnG,QAAQ,IAAI,EAAE;CACd,KAAK,MAAM,QAAQ,eAAe,UAAU,QAAQ,UAAU,IAAI,GAAG,QAAQ,IAAI,IAAI;AACzF;AAMA,SAAS,mBAAmB;CACxB,MAAM,UAAU,aAAa,QAAO,UAAS,CAAE,sBAA4C,SAAS,KAAK,CAAC;CAC1G,QAAQ,IAAI;EACd,MAAM,KAAK,iBAAiB,EAAE;;EAE9B,MAAM,MAAM,KAAK,OAAO,EAAE;oBACR,MAAM,KAAK,WAAW,EAAE;;EAE1C,MAAM,MAAM,KAAK,UAAU,EAAE;IAC3B,MAAM,KAAK,KAAK,MAAM,EAAE;IACxB,MAAM,KAAK,KAAK,KAAK,EAAE,GAAG,MAAM,KAAK,MAAM,EAAE;IAC7C,MAAM,KAAK,KAAK,QAAQ,EAAE;IAC1B,MAAM,KAAK,KAAK,QAAQ,EAAE,GAAG,MAAM,KAAK,MAAM,EAAE;IAChD,MAAM,KAAK,KAAK,QAAQ,EAAE;;EAE5B,MAAM,MAAM,KAAK,gBAAgB,EAAE;IACjC,MAAM,KAAK,YAAY,EAAE,mBAAmB,MAAM,KAAK,mCAAmC,EAAE;IAC5F,MAAM,KAAK,UAAU,EAAE;sBACL,MAAM,KAAK,iCAAiC,EAAE;IAChE,MAAM,KAAK,eAAe,EAAE;IAC5B,MAAM,KAAK,SAAS,EAAE,8CAA8C,MAAM,KAAK,SAAS,EAAE;IAC1F,MAAM,KAAK,cAAc,EAAE,mCAAmC,MAAM,KAAK,uCAAuC,EAAE;IAClH,MAAM,KAAK,cAAc,EAAE;IAC3B,MAAM,KAAK,cAAc,EAAE;;EAE7B,MAAM,MAAM,KAAK,sBAAsB,EAAE;IACvC,MAAM,KAAK,MAAM,EAAE,2BAA2B,MAAM,KAAK,yBAAyB,EAAE;;EAEtF,MAAM,MAAM,KAAK,QAAQ,EAAE;eACd,MAAM,KAAK,iBAAiB,EAAE;IACzC,MAAM,KAAK,iBAAiB,EAAE;WACvB,kBAAkB,KAAK,IAAI,EAAE;WAC7B,MAAM,KAAK,2EAA2E,EAAE;WACxF,QAAQ,KAAK,IAAI,EAAE;uDACyB,MAAM,KAAK,0BAA0B,EAAE;;EAE5F,MAAM,MAAM,KAAK,UAAU,EAAE;;;;;;;;CAQ9B;AACD"}
|
|
@@ -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":"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"}
|