@tryglen/cli 0.30.0 → 0.30.1
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/dist/_utils/config.d.ts +2 -2
- package/dist/_utils/config.js +2 -2
- package/dist/_utils/config.js.map +1 -1
- package/dist/commands/login.js +99 -51
- package/dist/commands/login.js.map +1 -1
- package/package.json +1 -1
- package/dist/_utils/build-connect-url.d.ts +0 -8
- package/dist/_utils/build-connect-url.js +0 -9
- package/dist/_utils/build-connect-url.js.map +0 -1
- package/dist/_utils/loopback-server.d.ts +0 -10
- package/dist/_utils/loopback-server.js +0 -63
- package/dist/_utils/loopback-server.js.map +0 -1
package/dist/_utils/config.d.ts
CHANGED
package/dist/_utils/config.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const baseUrl = (process.env.GLEN_BASE_URL ?? "https://app.tryglen.com").replace(/\/+$/, "");
|
|
4
4
|
const config = {
|
|
5
5
|
baseUrl,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
deviceStartUrl: `${baseUrl}/api/connect/cli/device`,
|
|
7
|
+
deviceTokenUrl: `${baseUrl}/api/connect/cli/device/token`,
|
|
8
8
|
turnUrl: `${baseUrl}/api/mcp/route/turn`,
|
|
9
9
|
searchUrl: `${baseUrl}/api/mcp/route/search`,
|
|
10
10
|
forgetUrl: `${baseUrl}/api/mcp/route/forget`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,cAAc,EAAE,GAAG,OAAO,yBAAyB;IACnD,cAAc,EAAE,GAAG,OAAO,+BAA+B;IACzD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,UAAU,EAAE,GAAG,OAAO,wBAAwB;IAC9C,SAAS,EAAE,GAAG,OAAO,6BAA6B;IAClD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,gBAAgB,EAAE,GAAG,OAAO,8BAA8B;IAC1D,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,aAAa,EAAE,GAAG,OAAO,2BAA2B;IACpD,SAAS,EAAE,GAAG,OAAO,iCAAiC;IACtD,kBAAkB,EAAE,GAAG,OAAO,gCAAgC;IAC9D,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,gBAAgB,EAAE,GAAG,OAAO,8BAA8B;IAC1D,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,kBAAkB,EAAE,GAAG,OAAO,gCAAgC;IAC9D,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,eAAe,EAAE,IAAI;IACrB,eAAe,EAAE,MAAM;IACvB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,IAAI;IAC3B,oFAAoF;IACpF,mBAAmB,EAAE,MAAM;IAC3B,8EAA8E;IAC9E,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,MAAM;IAC7B,uBAAuB,EAAE,MAAM;IAC/B,sBAAsB,EAAE,IAAI;CAC7B,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,74 +1,122 @@
|
|
|
1
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
-
import { buildConnectUrl } from "../_utils/build-connect-url.js";
|
|
3
1
|
import { causeOf, cliErr } from "../_utils/cli-error.js";
|
|
4
2
|
import { config } from "../_utils/config.js";
|
|
5
3
|
import { credentialsPath, writeCredentials } from "../_utils/credentials.js";
|
|
6
4
|
import { httpJson, networkRemedy } from "../_utils/http.js";
|
|
7
|
-
import { startLoopbackServer } from "../_utils/loopback-server.js";
|
|
8
5
|
import { openBrowser } from "../_utils/open-browser.js";
|
|
9
6
|
import { reportCliInstall } from "../_utils/report-cli-install.js";
|
|
10
|
-
import { err,
|
|
7
|
+
import { err, ok } from "../_utils/result.js";
|
|
11
8
|
import { writeState } from "../_utils/state.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
9
|
+
// Fallbacks if the server payload omits pacing hints; the server currently sends
|
|
10
|
+
// expiresIn: 600 / interval: 5 and we never poll faster or longer than these caps.
|
|
11
|
+
const MAX_WAIT_S = 10 * 60;
|
|
12
|
+
const MIN_INTERVAL_S = 5;
|
|
13
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
+
// Defensively narrow the start payload — all four fields must be present and
|
|
15
|
+
// well-typed or we treat the bootstrap as failed (never openBrowser on junk).
|
|
16
|
+
const parseStart = (json) => {
|
|
17
|
+
const p = json;
|
|
18
|
+
if (!p ||
|
|
19
|
+
typeof p.userCode !== "string" ||
|
|
20
|
+
typeof p.deviceSecret !== "string" ||
|
|
21
|
+
typeof p.verificationUri !== "string" ||
|
|
22
|
+
typeof p.verificationUriComplete !== "string")
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
userCode: p.userCode,
|
|
26
|
+
deviceSecret: p.deviceSecret,
|
|
27
|
+
verificationUri: p.verificationUri,
|
|
28
|
+
verificationUriComplete: p.verificationUriComplete,
|
|
29
|
+
expiresIn: Math.min(typeof p.expiresIn === "number" && p.expiresIn > 0
|
|
30
|
+
? p.expiresIn
|
|
31
|
+
: MAX_WAIT_S, MAX_WAIT_S),
|
|
32
|
+
interval: Math.max(typeof p.interval === "number" && p.interval > 0
|
|
33
|
+
? p.interval
|
|
34
|
+
: MIN_INTERVAL_S, MIN_INTERVAL_S),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
// Poll the token endpoint until the browser approval lands, the code expires, or
|
|
38
|
+
// the deadline passes. Returns the mint payload ({ apikey, org }) on success.
|
|
39
|
+
const pollForApproval = async (input) => {
|
|
40
|
+
for (;;) {
|
|
41
|
+
if (Date.now() >= input.deadline)
|
|
42
|
+
return err(cliErr({
|
|
43
|
+
what: "login timed out waiting for browser approval",
|
|
44
|
+
remedy: "retry `glen login` and approve the code within 10 minutes",
|
|
45
|
+
}));
|
|
46
|
+
const polled = await httpJson(config.deviceTokenUrl, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "content-type": "application/json" },
|
|
49
|
+
body: JSON.stringify({ deviceSecret: input.deviceSecret }),
|
|
50
|
+
timeoutMs: 15_000,
|
|
51
|
+
});
|
|
52
|
+
if (!polled.ok)
|
|
53
|
+
return err(cliErr({
|
|
54
|
+
what: "login polling failed",
|
|
55
|
+
why: polled.error.detail,
|
|
56
|
+
remedy: networkRemedy(polled.error),
|
|
57
|
+
}));
|
|
58
|
+
if (!polled.value.isOk) {
|
|
59
|
+
// The server collapses unknown/expired/already-used to one generic
|
|
60
|
+
// invalid_grant — from here that simply means this login can't complete.
|
|
61
|
+
return err(cliErr({
|
|
62
|
+
what: "login expired or was cancelled",
|
|
63
|
+
why: polled.value.rawText.length > 0
|
|
64
|
+
? polled.value.rawText.slice(0, 200)
|
|
65
|
+
: `HTTP ${polled.value.status}`,
|
|
66
|
+
remedy: "retry `glen login`",
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
const payload = polled.value.json;
|
|
70
|
+
if (payload?.status === "pending") {
|
|
71
|
+
await sleep(input.intervalMs);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (payload?.apikey && typeof payload.apikey === "string")
|
|
75
|
+
return ok(payload);
|
|
41
76
|
return err(cliErr({
|
|
42
|
-
what: "login
|
|
43
|
-
remedy: "retry `glen login
|
|
77
|
+
what: "login returned no key",
|
|
78
|
+
remedy: "retry `glen login`; if it persists, contact support",
|
|
44
79
|
}));
|
|
45
80
|
}
|
|
46
|
-
|
|
81
|
+
};
|
|
82
|
+
const login = async () => {
|
|
83
|
+
const started = await httpJson(config.deviceStartUrl, {
|
|
47
84
|
method: "POST",
|
|
48
|
-
headers: { "content-type": "application/json" },
|
|
49
|
-
body: JSON.stringify({ code: cb.code, verifier }),
|
|
50
85
|
timeoutMs: 15_000,
|
|
51
86
|
});
|
|
52
|
-
if (!
|
|
87
|
+
if (!started.ok)
|
|
53
88
|
return err(cliErr({
|
|
54
|
-
what: "
|
|
55
|
-
why:
|
|
56
|
-
remedy: networkRemedy(
|
|
89
|
+
what: "could not start login",
|
|
90
|
+
why: started.error.detail,
|
|
91
|
+
remedy: networkRemedy(started.error),
|
|
57
92
|
}));
|
|
58
|
-
if (!
|
|
93
|
+
if (!started.value.isOk)
|
|
59
94
|
return err(cliErr({
|
|
60
|
-
what: "
|
|
61
|
-
why:
|
|
62
|
-
? exchangeResult.value.rawText.slice(0, 200)
|
|
63
|
-
: `HTTP ${exchangeResult.value.status}`,
|
|
95
|
+
what: "could not start login",
|
|
96
|
+
why: `HTTP ${started.value.status}`,
|
|
64
97
|
remedy: "retry `glen login`; if it persists, contact support",
|
|
65
98
|
}));
|
|
66
|
-
const
|
|
67
|
-
if (!
|
|
99
|
+
const start = parseStart(started.value.json);
|
|
100
|
+
if (!start)
|
|
68
101
|
return err(cliErr({
|
|
69
|
-
what: "
|
|
102
|
+
what: "login bootstrap returned an unexpected response",
|
|
70
103
|
remedy: "retry `glen login`; if it persists, contact support",
|
|
71
104
|
}));
|
|
105
|
+
// The code + URL are the flow: they work from ANY browser on ANY device (SSH,
|
|
106
|
+
// containers), while the prefilled-URL browser open is a convenience for the
|
|
107
|
+
// local case. openBrowser is fire-and-forget — failure just means typing the code.
|
|
108
|
+
process.stdout.write(`To connect glen, visit:\n\n ${start.verificationUri}\n\nand enter the code:\n\n ${start.userCode}\n\n`);
|
|
109
|
+
process.stdout.write("Opening your browser with the code prefilled…\n");
|
|
110
|
+
openBrowser(start.verificationUriComplete);
|
|
111
|
+
process.stdout.write("Waiting for approval…\n");
|
|
112
|
+
const approved = await pollForApproval({
|
|
113
|
+
deviceSecret: start.deviceSecret,
|
|
114
|
+
intervalMs: start.interval * 1000,
|
|
115
|
+
deadline: Date.now() + start.expiresIn * 1000,
|
|
116
|
+
});
|
|
117
|
+
if (!approved.ok)
|
|
118
|
+
return approved;
|
|
119
|
+
const payload = approved.value;
|
|
72
120
|
const writeResult = await writeCredentials({
|
|
73
121
|
type: "apikey",
|
|
74
122
|
key: payload.apikey,
|
|
@@ -80,7 +128,7 @@ const login = async () => {
|
|
|
80
128
|
path: credentialsPath(),
|
|
81
129
|
remedy: "check ownership of ~/.glen (e.g. `sudo chown -R $USER ~/.glen`) and retry",
|
|
82
130
|
}));
|
|
83
|
-
// Defensively parse the org from the
|
|
131
|
+
// Defensively parse the org from the mint payload.
|
|
84
132
|
// All three fields must be strings; anything else is treated as null.
|
|
85
133
|
const rawOrg = payload.org ?? null;
|
|
86
134
|
const org = rawOrg !== null &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const buildConnectUrl = (params) => {
|
|
2
|
-
const url = new URL(params.connectUrl);
|
|
3
|
-
url.searchParams.set("callback", params.callback);
|
|
4
|
-
url.searchParams.set("state", params.state);
|
|
5
|
-
url.searchParams.set("challenge", params.challenge);
|
|
6
|
-
return url.toString();
|
|
7
|
-
};
|
|
8
|
-
export { buildConnectUrl };
|
|
9
|
-
//# sourceMappingURL=build-connect-url.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-connect-url.js","sourceRoot":"","sources":["../../src/_utils/build-connect-url.ts"],"names":[],"mappings":"AAOA,MAAM,eAAe,GAAG,CAAC,MAAwB,EAAU,EAAE;IAC3D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
type CallbackResult = {
|
|
2
|
-
readonly code: string | null;
|
|
3
|
-
readonly state: string | null;
|
|
4
|
-
};
|
|
5
|
-
type LoopbackServer = {
|
|
6
|
-
readonly redirectUri: string;
|
|
7
|
-
readonly waitForCallback: () => Promise<CallbackResult>;
|
|
8
|
-
};
|
|
9
|
-
declare const startLoopbackServer: (timeoutMs?: number, expectedState?: string, port?: number) => Promise<LoopbackServer>;
|
|
10
|
-
export { startLoopbackServer };
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { createServer } from "node:http";
|
|
2
|
-
import { causeOf, cliErr } from "./cli-error.js";
|
|
3
|
-
import { renderCallbackPage } from "./render-callback-page.js";
|
|
4
|
-
// `port` exists for tests (forcing an EADDRINUSE collision); production
|
|
5
|
-
// callers always bind an ephemeral port (0).
|
|
6
|
-
const startLoopbackServer = (timeoutMs = 300_000, expectedState, port = 0) => new Promise((resolveStart, rejectStart) => {
|
|
7
|
-
const callback = {
|
|
8
|
-
settled: false,
|
|
9
|
-
resolve: (_v) => { },
|
|
10
|
-
reject: (_e) => { },
|
|
11
|
-
};
|
|
12
|
-
const promise = new Promise((res, rej) => {
|
|
13
|
-
callback.resolve = res;
|
|
14
|
-
callback.reject = rej;
|
|
15
|
-
});
|
|
16
|
-
const server = createServer((req, res) => {
|
|
17
|
-
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
18
|
-
if (url.pathname !== "/callback") {
|
|
19
|
-
res.writeHead(404).end();
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const code = url.searchParams.get("code");
|
|
23
|
-
const state = url.searchParams.get("state");
|
|
24
|
-
const stateOk = !expectedState || state === expectedState;
|
|
25
|
-
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
26
|
-
res.end(renderCallbackPage(stateOk && Boolean(code)));
|
|
27
|
-
if (!stateOk || callback.settled)
|
|
28
|
-
return;
|
|
29
|
-
callback.settled = true;
|
|
30
|
-
callback.resolve({ code, state });
|
|
31
|
-
server.closeAllConnections?.();
|
|
32
|
-
server.close();
|
|
33
|
-
});
|
|
34
|
-
const timer = setTimeout(() => {
|
|
35
|
-
if (callback.settled)
|
|
36
|
-
return;
|
|
37
|
-
callback.settled = true;
|
|
38
|
-
callback.reject(new Error("login callback timed out"));
|
|
39
|
-
server.close();
|
|
40
|
-
}, timeoutMs);
|
|
41
|
-
timer.unref();
|
|
42
|
-
// Without this handler a listen failure (EADDRINUSE/EACCES — firewall,
|
|
43
|
-
// VPN, exhausted ports) emits an uncaught 'error' event and crashes the
|
|
44
|
-
// process. Reject the start promise with a CliError instead so login can
|
|
45
|
-
// return it as a structured failure.
|
|
46
|
-
server.on("error", (e) => {
|
|
47
|
-
rejectStart(cliErr({
|
|
48
|
-
what: "could not start the local login listener on 127.0.0.1",
|
|
49
|
-
why: causeOf(e),
|
|
50
|
-
remedy: "check local firewall/VPN settings and retry `glen login`",
|
|
51
|
-
}));
|
|
52
|
-
server.close();
|
|
53
|
-
});
|
|
54
|
-
server.listen(port, "127.0.0.1", () => {
|
|
55
|
-
const addr = server.address();
|
|
56
|
-
resolveStart({
|
|
57
|
-
redirectUri: `http://127.0.0.1:${addr.port}/callback`,
|
|
58
|
-
waitForCallback: () => promise,
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
export { startLoopbackServer };
|
|
63
|
-
//# sourceMappingURL=loopback-server.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loopback-server.js","sourceRoot":"","sources":["../../src/_utils/loopback-server.ts"],"names":[],"mappings":"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"}
|