@motherbase/cli 0.2.6 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +8 -1
  3. package/bin/.motherbase/config.json +5 -0
  4. package/bin/motherbase.js +10 -10
  5. package/package.json +4 -4
  6. package/src/api.js +39 -16
  7. package/src/commands/_util.js +106 -106
  8. package/src/commands/backups.js +16 -16
  9. package/src/commands/branches.js +113 -113
  10. package/src/commands/completion.js +90 -90
  11. package/src/commands/config.js +47 -47
  12. package/src/commands/cron.js +65 -65
  13. package/src/commands/db-catalog.js +39 -1
  14. package/src/commands/db.js +103 -103
  15. package/src/commands/domains.js +124 -124
  16. package/src/commands/gen.js +178 -172
  17. package/src/commands/import.js +55 -55
  18. package/src/commands/index.js +86 -85
  19. package/src/commands/inspect.js +178 -178
  20. package/src/commands/keys.js +72 -72
  21. package/src/commands/link.js +35 -35
  22. package/src/commands/local.js +101 -24
  23. package/src/commands/login.js +9 -3
  24. package/src/commands/logout.js +16 -16
  25. package/src/commands/mcp.js +61 -61
  26. package/src/commands/migrate.js +0 -5
  27. package/src/commands/migration.js +1 -1
  28. package/src/commands/network.js +83 -83
  29. package/src/commands/orgs.js +40 -40
  30. package/src/commands/postgres-config.js +113 -113
  31. package/src/commands/projects.js +131 -130
  32. package/src/commands/queues.js +133 -133
  33. package/src/commands/realtime.js +35 -35
  34. package/src/commands/rls.js +176 -176
  35. package/src/commands/secrets.js +66 -66
  36. package/src/commands/signing.js +130 -130
  37. package/src/commands/snippets.js +44 -44
  38. package/src/commands/status.js +42 -42
  39. package/src/commands/storage.js +261 -261
  40. package/src/commands/test.js +9 -9
  41. package/src/commands/unlink.js +15 -15
  42. package/src/commands/users.js +29 -1
  43. package/src/commands/vault.js +82 -82
  44. package/src/commands/webhooks.js +62 -62
  45. package/src/commands/whoami.js +20 -20
  46. package/src/commands/wrappers.js +150 -150
  47. package/src/config.js +98 -98
  48. package/src/context.js +106 -106
  49. package/src/edge-templates.js +194 -194
  50. package/src/format.js +92 -92
  51. package/src/inspect/csv.js +22 -22
  52. package/src/inspect/queries.js +562 -562
  53. package/src/main.js +145 -66
  54. package/src/mcp/platform-tools.js +233 -233
  55. package/src/mcp/protocol.js +152 -152
  56. package/src/mcp/storage-tools.js +93 -93
  57. package/src/mcp/tools.js +478 -478
  58. package/src/migration/commands.js +2 -2
  59. package/src/migration/files.js +13 -0
  60. package/src/prompt.js +91 -91
  61. package/src/storage/remote.js +62 -62
  62. package/src/ui.js +111 -111
package/src/config.js CHANGED
@@ -1,98 +1,98 @@
1
- 'use strict';
2
-
3
- // Config persistence. Two files:
4
- // Global creds : ~/.motherbase/config.json (contains tokens; written 0o600)
5
- // { "consoles": { "<url>": { "token": "...", "email": "..." } }, "current": "<url>" }
6
- // Project link : ./.motherbase/config.json (versionable, non-secret)
7
- // { "consoleUrl": "<url>", "projectId": "abc", "projectName": "my-app" }
8
-
9
- const fs = require('fs');
10
- const os = require('os');
11
- const path = require('path');
12
-
13
- const GLOBAL_DIR = path.join(os.homedir(), '.motherbase');
14
- const GLOBAL_FILE = path.join(GLOBAL_DIR, 'config.json');
15
- const LINK_DIRNAME = '.motherbase';
16
- const LINK_BASENAME = 'config.json';
17
-
18
- function normalizeUrl(url) {
19
- return String(url || '').replace(/\/+$/, '');
20
- }
21
-
22
- function readJson(file) {
23
- try {
24
- return JSON.parse(fs.readFileSync(file, 'utf8'));
25
- } catch {
26
- return null;
27
- }
28
- }
29
-
30
- // ── Global credentials ───────────────────────────────────────────────────────
31
-
32
- function readGlobal() {
33
- return readJson(GLOBAL_FILE) || { consoles: {}, current: null };
34
- }
35
-
36
- function writeGlobal(cfg) {
37
- fs.mkdirSync(GLOBAL_DIR, { recursive: true });
38
- fs.writeFileSync(GLOBAL_FILE, JSON.stringify(cfg, null, 2) + '\n', { mode: 0o600 });
39
- // Best-effort tighten perms even if the file already existed with looser mode.
40
- try { fs.chmodSync(GLOBAL_FILE, 0o600); } catch { /* windows / noop */ }
41
- }
42
-
43
- function saveConsoleToken(url, token, email) {
44
- const u = normalizeUrl(url);
45
- const cfg = readGlobal();
46
- cfg.consoles = cfg.consoles || {};
47
- cfg.consoles[u] = { ...(cfg.consoles[u] || {}), token, email };
48
- cfg.current = u;
49
- writeGlobal(cfg);
50
- return u;
51
- }
52
-
53
- function clearConsoleToken(url) {
54
- const cfg = readGlobal();
55
- const u = normalizeUrl(url);
56
- if (cfg.consoles && cfg.consoles[u]) delete cfg.consoles[u];
57
- if (cfg.current === u) cfg.current = null;
58
- writeGlobal(cfg);
59
- }
60
-
61
- function consoleEntry(url) {
62
- const cfg = readGlobal();
63
- return (cfg.consoles && cfg.consoles[normalizeUrl(url)]) || null;
64
- }
65
-
66
- // ── Per-project link ─────────────────────────────────────────────────────────
67
-
68
- function linkPath(cwd) {
69
- return path.join(cwd || process.cwd(), LINK_DIRNAME, LINK_BASENAME);
70
- }
71
-
72
- function readLink(cwd) {
73
- return readJson(linkPath(cwd));
74
- }
75
-
76
- function writeLink(cwd, data) {
77
- const dir = path.join(cwd || process.cwd(), LINK_DIRNAME);
78
- fs.mkdirSync(dir, { recursive: true });
79
- fs.writeFileSync(linkPath(cwd), JSON.stringify(data, null, 2) + '\n');
80
- }
81
-
82
- function removeLink(cwd) {
83
- try { fs.unlinkSync(linkPath(cwd)); return true; } catch { return false; }
84
- }
85
-
86
- module.exports = {
87
- GLOBAL_FILE,
88
- normalizeUrl,
89
- readGlobal,
90
- writeGlobal,
91
- saveConsoleToken,
92
- clearConsoleToken,
93
- consoleEntry,
94
- readLink,
95
- writeLink,
96
- removeLink,
97
- linkPath,
98
- };
1
+ 'use strict';
2
+
3
+ // Config persistence. Two files:
4
+ // Global creds : ~/.motherbase/config.json (contains tokens; written 0o600)
5
+ // { "consoles": { "<url>": { "token": "...", "email": "..." } }, "current": "<url>" }
6
+ // Project link : ./.motherbase/config.json (versionable, non-secret)
7
+ // { "consoleUrl": "<url>", "projectId": "abc", "projectName": "my-app" }
8
+
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+ const path = require('path');
12
+
13
+ const GLOBAL_DIR = path.join(os.homedir(), '.motherbase');
14
+ const GLOBAL_FILE = path.join(GLOBAL_DIR, 'config.json');
15
+ const LINK_DIRNAME = '.motherbase';
16
+ const LINK_BASENAME = 'config.json';
17
+
18
+ function normalizeUrl(url) {
19
+ return String(url || '').replace(/\/+$/, '');
20
+ }
21
+
22
+ function readJson(file) {
23
+ try {
24
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ // ── Global credentials ───────────────────────────────────────────────────────
31
+
32
+ function readGlobal() {
33
+ return readJson(GLOBAL_FILE) || { consoles: {}, current: null };
34
+ }
35
+
36
+ function writeGlobal(cfg) {
37
+ fs.mkdirSync(GLOBAL_DIR, { recursive: true });
38
+ fs.writeFileSync(GLOBAL_FILE, JSON.stringify(cfg, null, 2) + '\n', { mode: 0o600 });
39
+ // Best-effort tighten perms even if the file already existed with looser mode.
40
+ try { fs.chmodSync(GLOBAL_FILE, 0o600); } catch { /* windows / noop */ }
41
+ }
42
+
43
+ function saveConsoleToken(url, token, email) {
44
+ const u = normalizeUrl(url);
45
+ const cfg = readGlobal();
46
+ cfg.consoles = cfg.consoles || {};
47
+ cfg.consoles[u] = { ...(cfg.consoles[u] || {}), token, email };
48
+ cfg.current = u;
49
+ writeGlobal(cfg);
50
+ return u;
51
+ }
52
+
53
+ function clearConsoleToken(url) {
54
+ const cfg = readGlobal();
55
+ const u = normalizeUrl(url);
56
+ if (cfg.consoles && cfg.consoles[u]) delete cfg.consoles[u];
57
+ if (cfg.current === u) cfg.current = null;
58
+ writeGlobal(cfg);
59
+ }
60
+
61
+ function consoleEntry(url) {
62
+ const cfg = readGlobal();
63
+ return (cfg.consoles && cfg.consoles[normalizeUrl(url)]) || null;
64
+ }
65
+
66
+ // ── Per-project link ─────────────────────────────────────────────────────────
67
+
68
+ function linkPath(cwd) {
69
+ return path.join(cwd || process.cwd(), LINK_DIRNAME, LINK_BASENAME);
70
+ }
71
+
72
+ function readLink(cwd) {
73
+ return readJson(linkPath(cwd));
74
+ }
75
+
76
+ function writeLink(cwd, data) {
77
+ const dir = path.join(cwd || process.cwd(), LINK_DIRNAME);
78
+ fs.mkdirSync(dir, { recursive: true });
79
+ fs.writeFileSync(linkPath(cwd), JSON.stringify(data, null, 2) + '\n');
80
+ }
81
+
82
+ function removeLink(cwd) {
83
+ try { fs.unlinkSync(linkPath(cwd)); return true; } catch { return false; }
84
+ }
85
+
86
+ module.exports = {
87
+ GLOBAL_FILE,
88
+ normalizeUrl,
89
+ readGlobal,
90
+ writeGlobal,
91
+ saveConsoleToken,
92
+ clearConsoleToken,
93
+ consoleEntry,
94
+ readLink,
95
+ writeLink,
96
+ removeLink,
97
+ linkPath,
98
+ };
package/src/context.js CHANGED
@@ -1,106 +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
- // 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 };
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 };