@mostly-good-metrics/cli 0.1.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/LICENSE +21 -0
- package/README.md +126 -0
- package/bin/mgm.js +2 -0
- package/dist/auth.d.ts +8 -0
- package/dist/auth.js +146 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +287 -0
- package/dist/client.js +123 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +286 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/dashboard.d.ts +2 -0
- package/dist/commands/dashboard.js +74 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/discovery.d.ts +2 -0
- package/dist/commands/discovery.js +94 -0
- package/dist/commands/discovery.js.map +1 -0
- package/dist/commands/events.d.ts +2 -0
- package/dist/commands/events.js +100 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/experiments.d.ts +2 -0
- package/dist/commands/experiments.js +191 -0
- package/dist/commands/experiments.js.map +1 -0
- package/dist/commands/funnels.d.ts +2 -0
- package/dist/commands/funnels.js +186 -0
- package/dist/commands/funnels.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +127 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/keys.d.ts +2 -0
- package/dist/commands/keys.js +71 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/orgs.d.ts +2 -0
- package/dist/commands/orgs.js +92 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/projects.d.ts +2 -0
- package/dist/commands/projects.js +71 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/queries.d.ts +2 -0
- package/dist/commands/queries.js +177 -0
- package/dist/commands/queries.js.map +1 -0
- package/dist/commands/retention.d.ts +2 -0
- package/dist/commands/retention.js +162 -0
- package/dist/commands/retention.js.map +1 -0
- package/dist/commands/widgets.d.ts +2 -0
- package/dist/commands/widgets.js +92 -0
- package/dist/commands/widgets.js.map +1 -0
- package/dist/context.d.ts +9 -0
- package/dist/context.js +42 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +5 -0
- package/dist/output.js +42 -0
- package/dist/output.js.map +1 -0
- package/dist/program.d.ts +3 -0
- package/dist/program.js +44 -0
- package/dist/program.js.map +1 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.js +35 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +52 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { getToken } from "./auth.js";
|
|
2
|
+
const BASE_URL = process.env.MGM_API_URL ?? "https://api.mostlygoodmetrics.com/api/v2";
|
|
3
|
+
export class ApiError extends Error {
|
|
4
|
+
status;
|
|
5
|
+
code;
|
|
6
|
+
constructor(status, code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.name = "ApiError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async function request(method, path, options = {}) {
|
|
14
|
+
const token = options.token ?? getToken();
|
|
15
|
+
const url = new URL(`${BASE_URL}${path}`);
|
|
16
|
+
if (options.params) {
|
|
17
|
+
for (const [k, v] of Object.entries(options.params)) {
|
|
18
|
+
if (v !== undefined)
|
|
19
|
+
url.searchParams.set(k, v);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const headers = {
|
|
23
|
+
Accept: "application/json",
|
|
24
|
+
};
|
|
25
|
+
if (token)
|
|
26
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
27
|
+
if (options.body)
|
|
28
|
+
headers["Content-Type"] = "application/json";
|
|
29
|
+
const res = await fetch(url.toString(), {
|
|
30
|
+
method,
|
|
31
|
+
headers,
|
|
32
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
let code = "unknown";
|
|
36
|
+
let message = `HTTP ${res.status}`;
|
|
37
|
+
try {
|
|
38
|
+
const err = (await res.json());
|
|
39
|
+
code = err.error ?? code;
|
|
40
|
+
message = err.message ?? message;
|
|
41
|
+
}
|
|
42
|
+
catch { }
|
|
43
|
+
throw new ApiError(res.status, code, message);
|
|
44
|
+
}
|
|
45
|
+
if (res.status === 204)
|
|
46
|
+
return {};
|
|
47
|
+
return (await res.json());
|
|
48
|
+
}
|
|
49
|
+
// Auth
|
|
50
|
+
export const sendMagicLink = (email) => request("POST", "/auth/magic-link", {
|
|
51
|
+
body: { email },
|
|
52
|
+
});
|
|
53
|
+
export const verifyMagicLink = (token) => request("GET", `/auth/magic-link/${token}`);
|
|
54
|
+
export const completeRegistration = (token) => request("GET", `/auth/register/${token}`);
|
|
55
|
+
export const getMe = () => request("GET", "/auth/me");
|
|
56
|
+
export const logout = () => request("DELETE", "/auth/session");
|
|
57
|
+
// Organizations
|
|
58
|
+
export const listOrganizations = () => request("GET", "/organizations");
|
|
59
|
+
export const getOrganization = (slug) => request("GET", `/organizations/${slug}`);
|
|
60
|
+
export const createOrganization = (name) => request("POST", "/organizations", { body: { name } });
|
|
61
|
+
export const inviteMember = (orgSlug, email, role = "member") => request("POST", `/organizations/${orgSlug}/invitations`, {
|
|
62
|
+
body: { email, role },
|
|
63
|
+
});
|
|
64
|
+
// Projects
|
|
65
|
+
export const listProjects = () => request("GET", "/projects");
|
|
66
|
+
export const getProject = (id) => request("GET", `/projects/${id}`);
|
|
67
|
+
export const createProject = (orgSlug, name, timezone) => request("POST", `/organizations/${orgSlug}/projects`, {
|
|
68
|
+
body: { name, ...(timezone ? { timezone } : {}) },
|
|
69
|
+
});
|
|
70
|
+
export const updateProject = (id, attrs) => request("PATCH", `/projects/${id}`, { body: attrs });
|
|
71
|
+
export const deleteProject = (id) => request("DELETE", `/projects/${id}`);
|
|
72
|
+
// API Keys
|
|
73
|
+
export const listApiKeys = (projectId) => request("GET", `/projects/${projectId}/api-keys`);
|
|
74
|
+
export const createApiKey = (projectId, name) => request("POST", `/projects/${projectId}/api-keys`, {
|
|
75
|
+
body: { name },
|
|
76
|
+
});
|
|
77
|
+
export const revokeApiKey = (projectId, keyId) => request("DELETE", `/projects/${projectId}/api-keys/${keyId}`);
|
|
78
|
+
// Dashboard
|
|
79
|
+
export const getDashboard = (projectId, params) => request("GET", `/projects/${projectId}/dashboard`, { params });
|
|
80
|
+
export const getDashboardFilters = (projectId) => request("GET", `/projects/${projectId}/dashboard/filters`);
|
|
81
|
+
// Events
|
|
82
|
+
export const listEvents = (projectId, params) => request("GET", `/projects/${projectId}/events`, { params });
|
|
83
|
+
export const listEventTypes = (projectId, params) => request("GET", `/projects/${projectId}/events/types`, { params });
|
|
84
|
+
export const listEventDefinitions = (projectId) => request("GET", `/projects/${projectId}/events/definitions`);
|
|
85
|
+
// Insights (Saved Queries)
|
|
86
|
+
export const listInsights = (projectId) => request("GET", `/projects/${projectId}/insights`);
|
|
87
|
+
export const getInsight = (projectId, id) => request("GET", `/projects/${projectId}/insights/${id}`);
|
|
88
|
+
export const createInsight = (projectId, attrs) => request("POST", `/projects/${projectId}/insights`, { body: attrs });
|
|
89
|
+
export const updateInsight = (projectId, id, attrs) => request("PATCH", `/projects/${projectId}/insights/${id}`, { body: attrs });
|
|
90
|
+
export const deleteInsight = (projectId, id) => request("DELETE", `/projects/${projectId}/insights/${id}`);
|
|
91
|
+
export const executeInsight = (projectId, id) => request("GET", `/projects/${projectId}/insights/${id}/execute`);
|
|
92
|
+
export const executeAdHocQuery = (projectId, query) => request("POST", `/projects/${projectId}/insights/execute`, { body: query });
|
|
93
|
+
// Funnels
|
|
94
|
+
export const listFunnels = (projectId) => request("GET", `/projects/${projectId}/funnels`);
|
|
95
|
+
export const getFunnel = (projectId, id) => request("GET", `/projects/${projectId}/funnels/${id}`);
|
|
96
|
+
export const createFunnel = (projectId, attrs) => request("POST", `/projects/${projectId}/funnels`, { body: attrs });
|
|
97
|
+
export const updateFunnel = (projectId, id, attrs) => request("PATCH", `/projects/${projectId}/funnels/${id}`, { body: attrs });
|
|
98
|
+
export const deleteFunnel = (projectId, id) => request("DELETE", `/projects/${projectId}/funnels/${id}`);
|
|
99
|
+
export const executeFunnel = (projectId, id) => request("GET", `/projects/${projectId}/funnels/${id}/execute`);
|
|
100
|
+
export const executeAdHocFunnel = (projectId, funnel) => request("POST", `/projects/${projectId}/funnels/execute`, { body: funnel });
|
|
101
|
+
// Retention
|
|
102
|
+
export const listRetentions = (projectId) => request("GET", `/projects/${projectId}/retention`);
|
|
103
|
+
export const getRetention = (projectId, id) => request("GET", `/projects/${projectId}/retention/${id}`);
|
|
104
|
+
export const createRetention = (projectId, attrs) => request("POST", `/projects/${projectId}/retention`, { body: attrs });
|
|
105
|
+
export const updateRetention = (projectId, id, attrs) => request("PATCH", `/projects/${projectId}/retention/${id}`, { body: attrs });
|
|
106
|
+
export const deleteRetention = (projectId, id) => request("DELETE", `/projects/${projectId}/retention/${id}`);
|
|
107
|
+
export const executeRetention = (projectId, id) => request("GET", `/projects/${projectId}/retention/${id}/execute`);
|
|
108
|
+
export const executeAdHocRetention = (projectId, retention) => request("POST", `/projects/${projectId}/retention/execute`, { body: retention });
|
|
109
|
+
// Experiments
|
|
110
|
+
export const listExperiments = (projectId) => request("GET", `/projects/${projectId}/experiments`);
|
|
111
|
+
export const getExperiment = (projectId, id, params) => request("GET", `/projects/${projectId}/experiments/${id}`, { params });
|
|
112
|
+
export const createExperiment = (projectId, attrs) => request("POST", `/projects/${projectId}/experiments`, { body: attrs });
|
|
113
|
+
export const updateExperiment = (projectId, id, attrs) => request("PATCH", `/projects/${projectId}/experiments/${id}`, { body: attrs });
|
|
114
|
+
export const deleteExperiment = (projectId, id) => request("DELETE", `/projects/${projectId}/experiments/${id}`);
|
|
115
|
+
export const startExperiment = (projectId, id) => request("POST", `/projects/${projectId}/experiments/${id}/start`);
|
|
116
|
+
export const stopExperiment = (projectId, id) => request("POST", `/projects/${projectId}/experiments/${id}/stop`);
|
|
117
|
+
// Widgets
|
|
118
|
+
export const listWidgets = (projectId) => request("GET", `/projects/${projectId}/widgets`);
|
|
119
|
+
export const createWidget = (projectId, attrs) => request("POST", `/projects/${projectId}/widgets`, { body: attrs });
|
|
120
|
+
export const updateWidget = (projectId, id, attrs) => request("PATCH", `/projects/${projectId}/widgets/${id}`, { body: attrs });
|
|
121
|
+
export const deleteWidget = (projectId, id) => request("DELETE", `/projects/${projectId}/widgets/${id}`);
|
|
122
|
+
export const resetWidgets = (projectId) => request("POST", `/projects/${projectId}/widgets/reset`);
|
|
123
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import * as client from "../client.js";
|
|
5
|
+
import * as auth from "../auth.js";
|
|
6
|
+
import * as output from "../output.js";
|
|
7
|
+
import { CliUsageError, isNoInput } from "../runtime.js";
|
|
8
|
+
const CLIENT_NAME = "MostlyGoodMetrics CLI";
|
|
9
|
+
function getAppUrl() {
|
|
10
|
+
const configuredUrl = process.env.MGM_APP_URL ?? "https://app.mostlygoodmetrics.com";
|
|
11
|
+
let appUrl;
|
|
12
|
+
try {
|
|
13
|
+
appUrl = new URL(configuredUrl);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
throw new CliUsageError("MGM_APP_URL must be a valid URL.");
|
|
17
|
+
}
|
|
18
|
+
const localHttp = appUrl.protocol === "http:" &&
|
|
19
|
+
(appUrl.hostname === "localhost" || appUrl.hostname === "127.0.0.1" || appUrl.hostname === "::1");
|
|
20
|
+
if (appUrl.protocol !== "https:" && !localHttp) {
|
|
21
|
+
throw new CliUsageError("MGM_APP_URL must use HTTPS (except localhost development URLs).");
|
|
22
|
+
}
|
|
23
|
+
return appUrl;
|
|
24
|
+
}
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// PKCE helpers
|
|
27
|
+
// ============================================================================
|
|
28
|
+
function generatePKCE() {
|
|
29
|
+
const verifier = crypto.randomBytes(32).toString("base64url");
|
|
30
|
+
const challenge = crypto
|
|
31
|
+
.createHash("sha256")
|
|
32
|
+
.update(verifier)
|
|
33
|
+
.digest("base64url");
|
|
34
|
+
return { verifier, challenge };
|
|
35
|
+
}
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Browser-based OAuth login
|
|
38
|
+
// ============================================================================
|
|
39
|
+
async function browserLogin(opts = {}) {
|
|
40
|
+
const appUrl = getAppUrl();
|
|
41
|
+
// 1. Start a local HTTP server to receive the callback
|
|
42
|
+
const { port, waitForCallback, server } = await startCallbackServer();
|
|
43
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
44
|
+
// 2. Register as an OAuth client (or reuse cached if same redirect_uri)
|
|
45
|
+
let clientId = auth.getClientId();
|
|
46
|
+
const cachedRedirectUri = auth.getRedirectUri();
|
|
47
|
+
if (!clientId || cachedRedirectUri !== redirectUri) {
|
|
48
|
+
console.log("Registering CLI with MostlyGoodMetrics...");
|
|
49
|
+
const res = await fetch(new URL("/oauth/register", appUrl), {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
client_name: CLIENT_NAME,
|
|
54
|
+
redirect_uris: [redirectUri],
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
const err = await res.json().catch(() => ({}));
|
|
59
|
+
console.error(`Registration failed: ${err.error ?? res.statusText}`);
|
|
60
|
+
server.close();
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
const data = (await res.json());
|
|
64
|
+
clientId = data.client_id;
|
|
65
|
+
auth.saveClientId(clientId, redirectUri);
|
|
66
|
+
}
|
|
67
|
+
// 3. Generate PKCE challenge
|
|
68
|
+
const { verifier, challenge } = generatePKCE();
|
|
69
|
+
// 4. Build authorization URL and open browser
|
|
70
|
+
const state = crypto.randomBytes(16).toString("hex");
|
|
71
|
+
const params = new URLSearchParams({
|
|
72
|
+
client_id: clientId,
|
|
73
|
+
redirect_uri: redirectUri,
|
|
74
|
+
response_type: "code",
|
|
75
|
+
code_challenge: challenge,
|
|
76
|
+
code_challenge_method: "S256",
|
|
77
|
+
state,
|
|
78
|
+
scope: "mcp:tools",
|
|
79
|
+
});
|
|
80
|
+
if (opts.signup)
|
|
81
|
+
params.set("signup", "true");
|
|
82
|
+
const authorizeUrl = new URL("/oauth/authorize", appUrl);
|
|
83
|
+
authorizeUrl.search = params.toString();
|
|
84
|
+
console.log(opts.signup ? "Opening browser to create an account..." : "Opening browser to log in...");
|
|
85
|
+
console.log();
|
|
86
|
+
openBrowser(authorizeUrl.toString());
|
|
87
|
+
console.log("Waiting for authorization...");
|
|
88
|
+
console.log("(If your browser didn't open, visit this URL:)");
|
|
89
|
+
console.log(authorizeUrl.toString());
|
|
90
|
+
console.log();
|
|
91
|
+
// 5. Wait for the callback
|
|
92
|
+
const callbackResult = await waitForCallback();
|
|
93
|
+
server.close();
|
|
94
|
+
if (callbackResult.error) {
|
|
95
|
+
console.error(`Authorization failed: ${callbackResult.error}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
if (callbackResult.state !== state) {
|
|
99
|
+
console.error("State mismatch — possible CSRF attack. Aborting.");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
// 6. Exchange code for token
|
|
103
|
+
const tokenRes = await fetch(new URL("/oauth/token", appUrl), {
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers: { "Content-Type": "application/json" },
|
|
106
|
+
body: JSON.stringify({
|
|
107
|
+
grant_type: "authorization_code",
|
|
108
|
+
code: callbackResult.code,
|
|
109
|
+
code_verifier: verifier,
|
|
110
|
+
client_id: clientId,
|
|
111
|
+
redirect_uri: redirectUri,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
if (!tokenRes.ok) {
|
|
115
|
+
const err = (await tokenRes.json().catch(() => ({})));
|
|
116
|
+
console.error(`Token exchange failed: ${err.error ?? tokenRes.statusText}`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
const tokenData = (await tokenRes.json());
|
|
120
|
+
auth.saveToken(tokenData.access_token);
|
|
121
|
+
// Fetch user info
|
|
122
|
+
try {
|
|
123
|
+
const { user } = await client.getMe();
|
|
124
|
+
auth.saveToken(tokenData.access_token, user.email);
|
|
125
|
+
console.log(`Logged in as ${user.email}`);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
console.log("Logged in. Run `mgm whoami` to verify.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// Local callback server
|
|
133
|
+
// ============================================================================
|
|
134
|
+
function escapeHtml(text) {
|
|
135
|
+
return text
|
|
136
|
+
.replace(/&/g, "&")
|
|
137
|
+
.replace(/</g, "<")
|
|
138
|
+
.replace(/>/g, ">")
|
|
139
|
+
.replace(/"/g, """);
|
|
140
|
+
}
|
|
141
|
+
function startCallbackServer() {
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
let onCallback;
|
|
144
|
+
const callbackPromise = new Promise((res) => {
|
|
145
|
+
onCallback = res;
|
|
146
|
+
});
|
|
147
|
+
const server = http.createServer((req, res) => {
|
|
148
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
149
|
+
if (url.pathname === "/callback") {
|
|
150
|
+
const code = url.searchParams.get("code") ?? undefined;
|
|
151
|
+
const state = url.searchParams.get("state") ?? undefined;
|
|
152
|
+
const error = url.searchParams.get("error") ?? undefined;
|
|
153
|
+
// Show a nice page in the browser
|
|
154
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
155
|
+
if (code) {
|
|
156
|
+
res.end(`
|
|
157
|
+
<html><head><meta charset="utf-8"></head><body style="font-family: system-ui; text-align: center; padding: 60px;">
|
|
158
|
+
<h1 style="color: #667eea;">✓ Logged in!</h1>
|
|
159
|
+
<p>You can close this tab and return to the terminal.</p>
|
|
160
|
+
</body></html>
|
|
161
|
+
`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
res.end(`
|
|
165
|
+
<html><head><meta charset="utf-8"></head><body style="font-family: system-ui; text-align: center; padding: 60px;">
|
|
166
|
+
<h1 style="color: #ef4444;">Authorization failed</h1>
|
|
167
|
+
<p>${escapeHtml(error ?? "Unknown error")}. Return to the terminal.</p>
|
|
168
|
+
</body></html>
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
onCallback({ code, state, error });
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
res.writeHead(404);
|
|
175
|
+
res.end();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
// Try fixed port first (so cached client_id works), fall back to random
|
|
179
|
+
server.on("error", () => {
|
|
180
|
+
server.listen(0, "127.0.0.1", () => {
|
|
181
|
+
const addr = server.address();
|
|
182
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
183
|
+
resolve({ port, waitForCallback: () => callbackPromise, server });
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
server.listen(19891, "127.0.0.1", () => {
|
|
187
|
+
resolve({ port: 19891, waitForCallback: () => callbackPromise, server });
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Open browser (cross-platform)
|
|
193
|
+
// ============================================================================
|
|
194
|
+
function openBrowser(url) {
|
|
195
|
+
try {
|
|
196
|
+
const platform = process.platform;
|
|
197
|
+
if (platform === "darwin") {
|
|
198
|
+
execFileSync("/usr/bin/open", [url], { stdio: "ignore" });
|
|
199
|
+
}
|
|
200
|
+
else if (platform === "win32") {
|
|
201
|
+
execFileSync("rundll32.exe", ["url.dll,FileProtocolHandler", url], { stdio: "ignore" });
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// Browser open failed — user will use the printed URL
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ============================================================================
|
|
212
|
+
// Commands
|
|
213
|
+
// ============================================================================
|
|
214
|
+
export function registerAuthCommands(program) {
|
|
215
|
+
program
|
|
216
|
+
.command("login")
|
|
217
|
+
.description("Log in via browser (opens authorization page)")
|
|
218
|
+
.option("--token <token>", "Use an existing session token directly")
|
|
219
|
+
.action(async (opts) => {
|
|
220
|
+
if (opts.token) {
|
|
221
|
+
// Direct token login (for CI, scripts, etc.)
|
|
222
|
+
auth.saveToken(opts.token);
|
|
223
|
+
try {
|
|
224
|
+
const { user } = await client.getMe();
|
|
225
|
+
auth.saveToken(opts.token, user.email);
|
|
226
|
+
console.log(`Logged in as ${user.email}`);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
console.log("Token saved. Could not verify — check with `mgm whoami`.");
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (isNoInput()) {
|
|
234
|
+
throw new CliUsageError("login requires --token when --no-input is set.");
|
|
235
|
+
}
|
|
236
|
+
await browserLogin();
|
|
237
|
+
});
|
|
238
|
+
program
|
|
239
|
+
.command("signup")
|
|
240
|
+
.description("Create a new MostlyGoodMetrics account (opens browser)")
|
|
241
|
+
.action(async () => {
|
|
242
|
+
if (isNoInput()) {
|
|
243
|
+
throw new CliUsageError("signup cannot run with --no-input. Create an account in the browser first.");
|
|
244
|
+
}
|
|
245
|
+
await browserLogin({ signup: true });
|
|
246
|
+
});
|
|
247
|
+
program
|
|
248
|
+
.command("whoami")
|
|
249
|
+
.description("Show current user and organization")
|
|
250
|
+
.option("--json", "Output as JSON")
|
|
251
|
+
.action(async (opts) => {
|
|
252
|
+
auth.requireToken();
|
|
253
|
+
const data = await client.getMe();
|
|
254
|
+
if (opts.json) {
|
|
255
|
+
output.json(data);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
console.log(`Email: ${data.user.email}`);
|
|
259
|
+
console.log(`User ID: ${data.user.id}`);
|
|
260
|
+
if (data.organizations.length > 0) {
|
|
261
|
+
console.log();
|
|
262
|
+
console.log("Organizations:");
|
|
263
|
+
output.table(["Name", "Slug", "Plan", "Role"], data.organizations.map((o) => [o.name, o.slug, o.plan ?? "-", o.role ?? "-"]));
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
program
|
|
267
|
+
.command("logout")
|
|
268
|
+
.description("Clear stored session token")
|
|
269
|
+
.option("--json", "Output as JSON")
|
|
270
|
+
.action(async (opts) => {
|
|
271
|
+
const token = auth.getToken();
|
|
272
|
+
if (token) {
|
|
273
|
+
try {
|
|
274
|
+
await client.logout();
|
|
275
|
+
}
|
|
276
|
+
catch { }
|
|
277
|
+
}
|
|
278
|
+
auth.clearToken();
|
|
279
|
+
if (opts.json) {
|
|
280
|
+
output.json({ status: "logged_out" });
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
console.log("Logged out.");
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as client from "../client.js";
|
|
2
|
+
import * as auth from "../auth.js";
|
|
3
|
+
import * as output from "../output.js";
|
|
4
|
+
import { requireProjectId } from "../context.js";
|
|
5
|
+
export function registerDashboardCommands(program) {
|
|
6
|
+
const dashboard = program
|
|
7
|
+
.command("dashboard")
|
|
8
|
+
.description("Show dashboard stats for current project");
|
|
9
|
+
dashboard
|
|
10
|
+
.option("--project <id>", "Project ID")
|
|
11
|
+
.option("--range <range>", "Date range (e.g. 7d, 30d, 90d)")
|
|
12
|
+
.option("--start <date>", "Start date (YYYY-MM-DD)")
|
|
13
|
+
.option("--end <date>", "End date (YYYY-MM-DD)")
|
|
14
|
+
.option("--environment <env>", "Filter by environment")
|
|
15
|
+
.option("--platform <platform>", "Filter by platform")
|
|
16
|
+
.option("--event <name>", "Filter by event name")
|
|
17
|
+
.option("--json", "Output as JSON")
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
auth.requireToken();
|
|
20
|
+
const projectId = requireProjectId(opts.project);
|
|
21
|
+
const params = {};
|
|
22
|
+
if (opts.range)
|
|
23
|
+
params.date_range = opts.range;
|
|
24
|
+
if (opts.start)
|
|
25
|
+
params.start_date = opts.start;
|
|
26
|
+
if (opts.end)
|
|
27
|
+
params.end_date = opts.end;
|
|
28
|
+
if (opts.environment)
|
|
29
|
+
params.environment = opts.environment;
|
|
30
|
+
if (opts.platform)
|
|
31
|
+
params.platform = opts.platform;
|
|
32
|
+
if (opts.event)
|
|
33
|
+
params.event_name = opts.event;
|
|
34
|
+
const data = await client.getDashboard(projectId, params);
|
|
35
|
+
if (opts.json) {
|
|
36
|
+
output.json(data);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { stats } = data;
|
|
40
|
+
console.log("Dashboard Stats");
|
|
41
|
+
console.log("===============");
|
|
42
|
+
console.log(`Total Events: ${output.formatNumber(stats.total_events)} (${output.formatTrend(stats.events_trend)})`);
|
|
43
|
+
console.log(`Unique Users: ${output.formatNumber(stats.unique_users)} (${output.formatTrend(stats.users_trend)})`);
|
|
44
|
+
if (data.top_events.length > 0) {
|
|
45
|
+
console.log();
|
|
46
|
+
console.log("Top Events");
|
|
47
|
+
output.table(["Event", "Count"], data.top_events.map((e) => [e.name, output.formatNumber(e.count)]));
|
|
48
|
+
}
|
|
49
|
+
if (data.events_by_day.length > 0) {
|
|
50
|
+
console.log();
|
|
51
|
+
console.log("Events by Day");
|
|
52
|
+
output.table(["Date", "Count"], data.events_by_day.map((d) => [d.date, output.formatNumber(d.count)]));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
dashboard
|
|
56
|
+
.command("filters")
|
|
57
|
+
.description("List available dashboard filter values")
|
|
58
|
+
.option("--project <id>", "Project ID")
|
|
59
|
+
.option("--json", "Output as JSON")
|
|
60
|
+
.action(async (opts, command) => {
|
|
61
|
+
auth.requireToken();
|
|
62
|
+
// Commander assigns duplicate parent/child options to the parent command
|
|
63
|
+
// when they appear after the subcommand, so accept either location.
|
|
64
|
+
const parentOpts = command.parent?.opts();
|
|
65
|
+
const projectId = requireProjectId(opts.project ?? parentOpts?.project);
|
|
66
|
+
const data = await client.getDashboardFilters(projectId);
|
|
67
|
+
if (opts.json ?? parentOpts?.json) {
|
|
68
|
+
output.json(data);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
output.json(data);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as output from "../output.js";
|
|
2
|
+
function schemaFor(command, path, root) {
|
|
3
|
+
const effectiveOptions = () => {
|
|
4
|
+
const commands = [];
|
|
5
|
+
let current = command;
|
|
6
|
+
while (current) {
|
|
7
|
+
commands.unshift(current);
|
|
8
|
+
if (current === root)
|
|
9
|
+
break;
|
|
10
|
+
current = current.parent;
|
|
11
|
+
}
|
|
12
|
+
const seen = new Set();
|
|
13
|
+
return commands.flatMap((item) => item.options).filter((option) => {
|
|
14
|
+
if (seen.has(option.flags))
|
|
15
|
+
return false;
|
|
16
|
+
seen.add(option.flags);
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
path: path.join(" "),
|
|
22
|
+
description: command.description(),
|
|
23
|
+
arguments: command.registeredArguments.map((arg) => ({
|
|
24
|
+
name: arg.name(),
|
|
25
|
+
description: arg.description,
|
|
26
|
+
required: arg.required,
|
|
27
|
+
variadic: arg.variadic,
|
|
28
|
+
})),
|
|
29
|
+
options: effectiveOptions().map((option) => ({
|
|
30
|
+
flags: option.flags,
|
|
31
|
+
description: option.description,
|
|
32
|
+
required: option.mandatory,
|
|
33
|
+
...(option.defaultValue !== undefined ? { default: option.defaultValue } : {}),
|
|
34
|
+
})),
|
|
35
|
+
subcommands: command.commands.map((subcommand) => subcommand.name()),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function findCommand(root, path) {
|
|
39
|
+
let command = root;
|
|
40
|
+
for (const name of path) {
|
|
41
|
+
const next = command.commands.find((subcommand) => subcommand.name() === name);
|
|
42
|
+
if (!next)
|
|
43
|
+
return undefined;
|
|
44
|
+
command = next;
|
|
45
|
+
}
|
|
46
|
+
return command;
|
|
47
|
+
}
|
|
48
|
+
function allSchemas(command, root, path = []) {
|
|
49
|
+
return command.commands
|
|
50
|
+
.flatMap((subcommand) => {
|
|
51
|
+
const subcommandPath = [...path, subcommand.name()];
|
|
52
|
+
return [schemaFor(subcommand, subcommandPath, root), ...allSchemas(subcommand, root, subcommandPath)];
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export function registerDiscoveryCommands(program) {
|
|
56
|
+
program
|
|
57
|
+
.command("commands")
|
|
58
|
+
.description("List every available command and its capabilities")
|
|
59
|
+
.option("--json", "Output as JSON")
|
|
60
|
+
.action((opts) => {
|
|
61
|
+
const commands = allSchemas(program, program);
|
|
62
|
+
if (opts.json) {
|
|
63
|
+
output.json(commands);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
output.table(["Command", "Description"], commands.map((command) => [command.path, command.description]));
|
|
67
|
+
});
|
|
68
|
+
program
|
|
69
|
+
.command("schema <command...>")
|
|
70
|
+
.description("Show arguments, flags, and subcommands for a command path")
|
|
71
|
+
.option("--json", "Output as JSON")
|
|
72
|
+
.action((commandPath, opts) => {
|
|
73
|
+
const command = findCommand(program, commandPath);
|
|
74
|
+
if (!command) {
|
|
75
|
+
throw new Error(`Unknown command: mgm ${commandPath.join(" ")}`);
|
|
76
|
+
}
|
|
77
|
+
const schema = schemaFor(command, commandPath, program);
|
|
78
|
+
if (opts.json) {
|
|
79
|
+
output.json(schema);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log(`mgm ${schema.path}`);
|
|
83
|
+
console.log(schema.description);
|
|
84
|
+
if (schema.arguments.length > 0) {
|
|
85
|
+
console.log("\nArguments:");
|
|
86
|
+
output.table(["Name", "Required", "Description"], schema.arguments.map((arg) => [arg.name, arg.required ? "yes" : "no", arg.description]));
|
|
87
|
+
}
|
|
88
|
+
if (schema.options.length > 0) {
|
|
89
|
+
console.log("\nOptions:");
|
|
90
|
+
output.table(["Flags", "Required", "Description"], schema.options.map((option) => [option.flags, option.required ? "yes" : "no", option.description]));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/commands/discovery.ts"],"names":[],"mappings":"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"}
|