@motherbase/cli 0.2.5 → 0.2.6
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/LICENSE +21 -0
- package/README.md +247 -247
- package/bin/motherbase.js +10 -10
- package/package.json +35 -26
- package/src/api.js +233 -241
- package/src/commands/_util.js +106 -93
- package/src/commands/backups.js +16 -16
- package/src/commands/branches.js +113 -113
- package/src/commands/completion.js +90 -90
- package/src/commands/config.js +47 -47
- package/src/commands/cron.js +65 -65
- package/src/commands/db-catalog.js +326 -326
- package/src/commands/db.js +103 -103
- package/src/commands/domains.js +124 -124
- package/src/commands/functions.js +304 -297
- package/src/commands/gen.js +172 -172
- package/src/commands/import.js +55 -55
- package/src/commands/index.js +85 -85
- package/src/commands/inspect.js +178 -178
- package/src/commands/keys.js +72 -72
- package/src/commands/link.js +35 -35
- package/src/commands/local.js +294 -273
- package/src/commands/login.js +39 -39
- package/src/commands/logout.js +16 -16
- package/src/commands/mcp.js +61 -61
- package/src/commands/migrate.js +207 -179
- package/src/commands/migration.js +108 -108
- package/src/commands/network.js +83 -83
- package/src/commands/orgs.js +40 -40
- package/src/commands/postgres-config.js +113 -113
- package/src/commands/projects.js +130 -130
- package/src/commands/queues.js +133 -133
- package/src/commands/realtime.js +35 -35
- package/src/commands/rls.js +176 -176
- package/src/commands/secrets.js +66 -66
- package/src/commands/signing.js +130 -130
- package/src/commands/snippets.js +44 -44
- package/src/commands/status.js +42 -42
- package/src/commands/storage.js +261 -261
- package/src/commands/test.js +9 -9
- package/src/commands/unlink.js +15 -15
- package/src/commands/users.js +142 -142
- package/src/commands/vault.js +82 -82
- package/src/commands/webhooks.js +62 -62
- package/src/commands/whoami.js +20 -20
- package/src/commands/wrappers.js +150 -150
- package/src/config.js +98 -98
- package/src/context.js +106 -102
- package/src/docs.js +68 -0
- package/src/edge-templates.js +194 -194
- package/src/format.js +92 -92
- package/src/inspect/csv.js +22 -22
- package/src/inspect/queries.js +562 -562
- package/src/main.js +224 -194
- package/src/mcp/platform-tools.js +233 -233
- package/src/mcp/protocol.js +152 -149
- package/src/mcp/storage-tools.js +93 -93
- package/src/mcp/tools.js +478 -478
- package/src/migration/commands.js +375 -375
- package/src/migration/files.js +245 -245
- package/src/prompt.js +91 -91
- package/src/storage/remote.js +62 -62
- package/src/ui.js +111 -111
package/src/context.js
CHANGED
|
@@ -1,102 +1,106 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Resolve the runtime context: which console, which token, which project, and
|
|
4
|
-
// whether we talk through the Console proxy ('console' mode) or straight at a
|
|
5
|
-
// single project API ('direct' mode). Precedence everywhere: flags > env > config.
|
|
6
|
-
//
|
|
7
|
-
// Resolution is LAZY: building a context never throws, so commands that need no
|
|
8
|
-
// project (login, local docker, init) work with zero configuration. The
|
|
9
|
-
// require*() helpers throw a clear, actionable error only when a value is
|
|
10
|
-
// actually needed and missing.
|
|
11
|
-
|
|
12
|
-
const config = require('./config');
|
|
13
|
-
|
|
14
|
-
class CliError extends Error {
|
|
15
|
-
constructor(message) {
|
|
16
|
-
super(message);
|
|
17
|
-
this.name = 'CliError';
|
|
18
|
-
this.isCliError = true;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function firstDefined(...vals) {
|
|
23
|
-
for (const v of vals) if (v !== undefined && v !== null && v !== '') return v;
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function createContext(flags = {}, env = process.env, cwd = process.cwd()) {
|
|
28
|
-
const link = config.readLink(cwd) || {};
|
|
29
|
-
const global = config.readGlobal();
|
|
30
|
-
|
|
31
|
-
const consoleUrl = firstDefined(
|
|
32
|
-
flags.url,
|
|
33
|
-
env.MOTHERBASE_CONSOLE_URL,
|
|
34
|
-
link.consoleUrl,
|
|
35
|
-
global.current,
|
|
36
|
-
);
|
|
37
|
-
const normConsoleUrl = consoleUrl ? config.normalizeUrl(consoleUrl) : undefined;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Resolve the runtime context: which console, which token, which project, and
|
|
4
|
+
// whether we talk through the Console proxy ('console' mode) or straight at a
|
|
5
|
+
// single project API ('direct' mode). Precedence everywhere: flags > env > config.
|
|
6
|
+
//
|
|
7
|
+
// Resolution is LAZY: building a context never throws, so commands that need no
|
|
8
|
+
// project (login, local docker, init) work with zero configuration. The
|
|
9
|
+
// require*() helpers throw a clear, actionable error only when a value is
|
|
10
|
+
// actually needed and missing.
|
|
11
|
+
|
|
12
|
+
const config = require('./config');
|
|
13
|
+
|
|
14
|
+
class CliError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'CliError';
|
|
18
|
+
this.isCliError = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function firstDefined(...vals) {
|
|
23
|
+
for (const v of vals) if (v !== undefined && v !== null && v !== '') return v;
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createContext(flags = {}, env = process.env, cwd = process.cwd()) {
|
|
28
|
+
const link = config.readLink(cwd) || {};
|
|
29
|
+
const global = config.readGlobal();
|
|
30
|
+
|
|
31
|
+
const consoleUrl = firstDefined(
|
|
32
|
+
flags.url,
|
|
33
|
+
env.MOTHERBASE_CONSOLE_URL,
|
|
34
|
+
link.consoleUrl,
|
|
35
|
+
global.current,
|
|
36
|
+
);
|
|
37
|
+
const normConsoleUrl = consoleUrl ? config.normalizeUrl(consoleUrl) : undefined;
|
|
38
|
+
|
|
39
|
+
// The link file is committed to the repo, so a URL that came only from it is
|
|
40
|
+
// not trusted with a token the user supplied for some other console.
|
|
41
|
+
const urlFromLinkOnly = !firstDefined(flags.url, env.MOTHERBASE_CONSOLE_URL) && Boolean(link.consoleUrl);
|
|
42
|
+
|
|
43
|
+
const token = firstDefined(
|
|
44
|
+
urlFromLinkOnly ? undefined : flags.token,
|
|
45
|
+
urlFromLinkOnly ? undefined : env.MOTHERBASE_TOKEN,
|
|
46
|
+
normConsoleUrl ? (config.consoleEntry(normConsoleUrl) || {}).token : undefined,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const projectId = firstDefined(flags.project, env.MOTHERBASE_PROJECT, link.projectId);
|
|
50
|
+
const projectName = firstDefined(link.projectName, projectId);
|
|
51
|
+
|
|
52
|
+
// Direct project mode: an admin JWT pointed straight at one project API. Only
|
|
53
|
+
// used as a fallback when there is no console link/flags to route through.
|
|
54
|
+
const directUrl = env.MOTHERBASE_URL ? config.normalizeUrl(env.MOTHERBASE_URL) : undefined;
|
|
55
|
+
const directToken = env.MOTHERBASE_ADMIN_TOKEN;
|
|
56
|
+
const hasConsole = Boolean(normConsoleUrl && token);
|
|
57
|
+
const hasProjectLink = Boolean(projectId);
|
|
58
|
+
const preferDirect = Boolean(directUrl && directToken) && !(hasConsole && hasProjectLink);
|
|
59
|
+
const mode = preferDirect ? 'direct' : 'console';
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
flags,
|
|
63
|
+
env,
|
|
64
|
+
cwd,
|
|
65
|
+
mode,
|
|
66
|
+
consoleUrl: normConsoleUrl,
|
|
67
|
+
token,
|
|
68
|
+
projectId,
|
|
69
|
+
projectName,
|
|
70
|
+
directUrl,
|
|
71
|
+
directToken,
|
|
72
|
+
linkedConsoleUrl: link.consoleUrl,
|
|
73
|
+
accountEmail: normConsoleUrl ? (config.consoleEntry(normConsoleUrl) || {}).email : undefined,
|
|
74
|
+
|
|
75
|
+
// Console (account / multi-project) requests need URL + session token.
|
|
76
|
+
requireConsole() {
|
|
77
|
+
if (!this.consoleUrl) {
|
|
78
|
+
throw new CliError('No console URL. Run `motherbase login --url <consoleUrl>` or set MOTHERBASE_CONSOLE_URL.');
|
|
79
|
+
}
|
|
80
|
+
if (!this.token) {
|
|
81
|
+
throw new CliError('Not logged in. Run `motherbase login` or set MOTHERBASE_TOKEN.');
|
|
82
|
+
}
|
|
83
|
+
return { consoleUrl: this.consoleUrl, token: this.token };
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Admin/resource requests: resolve either the console proxy path or a direct
|
|
87
|
+
// project API, whichever the context selected.
|
|
88
|
+
requireProject() {
|
|
89
|
+
if (this.mode === 'direct') {
|
|
90
|
+
return { mode: 'direct', baseUrl: this.directUrl, token: this.directToken };
|
|
91
|
+
}
|
|
92
|
+
this.requireConsole();
|
|
93
|
+
if (!this.projectId) {
|
|
94
|
+
throw new CliError('No project linked. Run `motherbase link` or set MOTHERBASE_PROJECT (or use direct mode via MOTHERBASE_URL + MOTHERBASE_ADMIN_TOKEN).');
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
mode: 'console',
|
|
98
|
+
consoleUrl: this.consoleUrl,
|
|
99
|
+
token: this.token,
|
|
100
|
+
projectId: this.projectId,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { createContext, CliError };
|
package/src/docs.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Renders the command registry as the Markdown table published in the docs.
|
|
4
|
+
//
|
|
5
|
+
// `main.js` already builds every help screen from `registry` + `groups`, so the
|
|
6
|
+
// terminal could never disagree with the code. The published CLI reference
|
|
7
|
+
// could, and did: thirteen whole groups (`orgs`, `branches`, `domains`,
|
|
8
|
+
// `vanity-subdomains`, `backups`, `test`, `postgres-config`, `queues`, `vault`,
|
|
9
|
+
// `wrappers`, `network-restrictions`, `ssl-enforcement`, `snippets`) existed in
|
|
10
|
+
// `motherbase --help` and not in the reference, so the documented CLI was a
|
|
11
|
+
// strict subset of the shipped one.
|
|
12
|
+
//
|
|
13
|
+
// Writing it from the same two objects the help screens use is what stops that
|
|
14
|
+
// happening again. `scripts/generate-cli-docs.js` writes the file;
|
|
15
|
+
// `test/docs.test.js` fails when the committed copy no longer matches.
|
|
16
|
+
|
|
17
|
+
const { registry, groups } = require('./commands');
|
|
18
|
+
|
|
19
|
+
/** Escape the pipe so a usage string containing one cannot break the table. */
|
|
20
|
+
const cell = value => String(value ?? '').replace(/\|/g, '\\|');
|
|
21
|
+
|
|
22
|
+
/** `motherbase db sql -e <sql>` → `` `motherbase db sql` `` plus its arguments. */
|
|
23
|
+
function usageCell(usage) {
|
|
24
|
+
return usage ? `\`${cell(usage)}\`` : '—';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Commands in group order, then whatever the registry holds that no group
|
|
29
|
+
* names. A command with no group still renders: adding one to the registry and
|
|
30
|
+
* forgetting the group list must not make it vanish from the docs.
|
|
31
|
+
*/
|
|
32
|
+
function sections() {
|
|
33
|
+
const grouped = new Set(groups.flatMap(group => group.names));
|
|
34
|
+
const ungrouped = Object.keys(registry).filter(name => !grouped.has(name));
|
|
35
|
+
const all = groups.map(group => ({ title: group.title, names: group.names }));
|
|
36
|
+
if (ungrouped.length) all.push({ title: 'Ungrouped', names: ungrouped });
|
|
37
|
+
return all;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderCommandDocs() {
|
|
41
|
+
const lines = [
|
|
42
|
+
'<!-- GENERATED by `npm run docs:cli` from packages/cli/src/commands. Do not edit by hand. -->',
|
|
43
|
+
'',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const section of sections()) {
|
|
47
|
+
const entries = section.names.map(name => [name, registry[name]]).filter(([, entry]) => entry);
|
|
48
|
+
if (!entries.length) continue;
|
|
49
|
+
|
|
50
|
+
lines.push(`### ${section.title}`, '');
|
|
51
|
+
lines.push('| Command | Usage | What it does |');
|
|
52
|
+
lines.push('|---|---|---|');
|
|
53
|
+
|
|
54
|
+
for (const [name, entry] of entries) {
|
|
55
|
+
lines.push(`| \`${cell(name)}\` | ${usageCell(entry.usage)} | ${cell(entry.summary)} |`);
|
|
56
|
+
for (const [sub, subEntry] of Object.entries(entry.subcommands ?? {})) {
|
|
57
|
+
lines.push(
|
|
58
|
+
`| \`${cell(name)} ${cell(sub)}\` | ${usageCell(subEntry.usage)} | ${cell(subEntry.summary)} |`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return lines.join('\n');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { renderCommandDocs };
|