@solongate/proxy 0.81.47 → 0.81.49
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/api-client/client.d.ts +2 -0
- package/dist/api-client/device-login.d.ts +1 -0
- package/dist/index.js +83 -22
- package/dist/login.js +1 -1
- package/dist/self-update.d.ts +20 -0
- package/dist/tui/index.js +154 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6558,7 +6558,8 @@ var init_cli_utils = __esm({
|
|
|
6558
6558
|
var self_update_exports = {};
|
|
6559
6559
|
__export(self_update_exports, {
|
|
6560
6560
|
currentVersion: () => currentVersion,
|
|
6561
|
-
maybeSelfUpdate: () => maybeSelfUpdate
|
|
6561
|
+
maybeSelfUpdate: () => maybeSelfUpdate,
|
|
6562
|
+
tuiUpdateFlow: () => tuiUpdateFlow
|
|
6562
6563
|
});
|
|
6563
6564
|
import { execFile, spawn } from "child_process";
|
|
6564
6565
|
import { mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -6647,6 +6648,51 @@ function spawnGlobalInstall(version) {
|
|
|
6647
6648
|
return false;
|
|
6648
6649
|
}
|
|
6649
6650
|
}
|
|
6651
|
+
function runGlobalInstall(version) {
|
|
6652
|
+
return new Promise((resolve10) => {
|
|
6653
|
+
try {
|
|
6654
|
+
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6655
|
+
execFile(
|
|
6656
|
+
"npm",
|
|
6657
|
+
["install", "-g", `${PKG}@${version}`],
|
|
6658
|
+
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
6659
|
+
(err2, stdout, stderr) => {
|
|
6660
|
+
try {
|
|
6661
|
+
writeFileSync3(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err2 ? "FAILED" : "ok"}
|
|
6662
|
+
${stdout}
|
|
6663
|
+
${stderr}
|
|
6664
|
+
`, { flag: "a" });
|
|
6665
|
+
} catch {
|
|
6666
|
+
}
|
|
6667
|
+
resolve10(!err2);
|
|
6668
|
+
}
|
|
6669
|
+
);
|
|
6670
|
+
} catch {
|
|
6671
|
+
resolve10(false);
|
|
6672
|
+
}
|
|
6673
|
+
});
|
|
6674
|
+
}
|
|
6675
|
+
async function tuiUpdateFlow(onStatus) {
|
|
6676
|
+
try {
|
|
6677
|
+
const current = currentVersion();
|
|
6678
|
+
const latest = await fetchLatest();
|
|
6679
|
+
const state = readState();
|
|
6680
|
+
if (latest) writeState({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
|
|
6681
|
+
if (!latest || !newerThan(latest, current)) return;
|
|
6682
|
+
const attempts = readState().attempts ?? {};
|
|
6683
|
+
const canRetry = Date.now() - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS;
|
|
6684
|
+
if (await isGlobalInstall() && canRetry) {
|
|
6685
|
+
writeState({ ...readState(), attempts: { [latest]: Date.now() } });
|
|
6686
|
+
onStatus({ kind: "updating", version: latest });
|
|
6687
|
+
if (await runGlobalInstall(latest)) {
|
|
6688
|
+
onStatus({ kind: "updated", version: latest });
|
|
6689
|
+
return;
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
onStatus({ kind: "manual", version: latest });
|
|
6693
|
+
} catch {
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6650
6696
|
function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
|
|
6651
6697
|
void (async () => {
|
|
6652
6698
|
try {
|
|
@@ -7142,7 +7188,7 @@ async function pollDeviceLogin(apiUrl, deviceCode) {
|
|
|
7142
7188
|
});
|
|
7143
7189
|
const j = await res.json().catch(() => ({}));
|
|
7144
7190
|
if (j.status === "approved" && j.api_key) {
|
|
7145
|
-
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email };
|
|
7191
|
+
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email, email: j.user?.email };
|
|
7146
7192
|
}
|
|
7147
7193
|
if (j.status === "expired" || j.status === "not_found") return { status: j.status };
|
|
7148
7194
|
return { status: "pending" };
|
|
@@ -10162,11 +10208,11 @@ function AccountsPanel({
|
|
|
10162
10208
|
if (abort.current) return;
|
|
10163
10209
|
const res = await pollDeviceLogin(DEFAULT_API_URL2, start.deviceCode);
|
|
10164
10210
|
if (res.status === "approved" && res.apiKey) {
|
|
10165
|
-
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user });
|
|
10166
|
-
setLogin({ phase: "done", msg: `\u2713 added ${res.
|
|
10211
|
+
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
|
|
10212
|
+
setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
|
|
10167
10213
|
refresh();
|
|
10168
10214
|
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
|
|
10169
|
-
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user });
|
|
10215
|
+
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
|
|
10170
10216
|
return;
|
|
10171
10217
|
}
|
|
10172
10218
|
if (res.status === "expired" || res.status === "not_found") {
|
|
@@ -10193,13 +10239,13 @@ function AccountsPanel({
|
|
|
10193
10239
|
if (a) {
|
|
10194
10240
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
10195
10241
|
onView?.(a);
|
|
10196
|
-
setMsg({ text: `viewing ${a.
|
|
10242
|
+
setMsg({ text: `viewing ${a.email || a.user || a.project || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
|
|
10197
10243
|
}
|
|
10198
10244
|
} else if (input === "m") {
|
|
10199
10245
|
const a = accounts[sel];
|
|
10200
10246
|
if (a) {
|
|
10201
10247
|
const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
10202
|
-
setMsg(ok ? { text: `\u2713 ${a.
|
|
10248
|
+
setMsg(ok ? { text: `\u2713 ${a.email || a.user || a.project || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
10203
10249
|
refresh();
|
|
10204
10250
|
}
|
|
10205
10251
|
} else if (input === "n") beginLogin();
|
|
@@ -10242,10 +10288,10 @@ function AccountsPanel({
|
|
|
10242
10288
|
const isActive = isActiveAccount(a.apiKey);
|
|
10243
10289
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
10244
10290
|
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
10245
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.
|
|
10291
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.email || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
|
|
10246
10292
|
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
10247
10293
|
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
10248
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.
|
|
10294
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.project ? truncate2(a.project, 24) : "" })
|
|
10249
10295
|
] }, a.apiKey);
|
|
10250
10296
|
}) }),
|
|
10251
10297
|
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
|
|
@@ -10299,17 +10345,29 @@ function App() {
|
|
|
10299
10345
|
const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
|
|
10300
10346
|
const [focus, setFocus] = useState9("nav");
|
|
10301
10347
|
const [help, setHelp] = useState9(false);
|
|
10348
|
+
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
10349
|
+
useEffect7(() => {
|
|
10350
|
+
let alive = true;
|
|
10351
|
+
const run12 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
10352
|
+
run12();
|
|
10353
|
+
const t = setInterval(run12, 30 * 6e4);
|
|
10354
|
+
return () => {
|
|
10355
|
+
alive = false;
|
|
10356
|
+
clearInterval(t);
|
|
10357
|
+
};
|
|
10358
|
+
}, []);
|
|
10302
10359
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
10303
10360
|
const cur = accounts[acctIdx];
|
|
10304
|
-
const acctLabel = cur ? cur.
|
|
10361
|
+
const acctLabel = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
10305
10362
|
useEffect7(() => {
|
|
10306
|
-
if (!cur || cur.
|
|
10363
|
+
if (!cur || cur.email) return;
|
|
10307
10364
|
let alive = true;
|
|
10308
10365
|
api.auth.me().then((r) => {
|
|
10309
|
-
const project = r.project?.name ||
|
|
10310
|
-
const user = r.user?.name ||
|
|
10311
|
-
|
|
10312
|
-
|
|
10366
|
+
const project = r.project?.name || cur.project;
|
|
10367
|
+
const user = r.user?.name || cur.user;
|
|
10368
|
+
const email = r.user?.email || void 0;
|
|
10369
|
+
if (!alive || !project && !user && !email) return;
|
|
10370
|
+
saveAccount({ ...cur, project, user, email });
|
|
10313
10371
|
setAccounts(listAccounts());
|
|
10314
10372
|
}).catch(() => {
|
|
10315
10373
|
});
|
|
@@ -10368,7 +10426,8 @@ function App() {
|
|
|
10368
10426
|
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
10369
10427
|
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
10370
10428
|
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
|
|
10371
|
-
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" })
|
|
10429
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
|
|
10430
|
+
update2.kind === "updating" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
10372
10431
|
] }),
|
|
10373
10432
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
10374
10433
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
@@ -10411,6 +10470,7 @@ var init_App = __esm({
|
|
|
10411
10470
|
init_hooks();
|
|
10412
10471
|
init_client();
|
|
10413
10472
|
init_api_client();
|
|
10473
|
+
init_self_update();
|
|
10414
10474
|
SECTIONS = [
|
|
10415
10475
|
{ label: "Live", Panel: LiveHint },
|
|
10416
10476
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
@@ -11806,7 +11866,7 @@ ${SHIM_END}`;
|
|
|
11806
11866
|
}
|
|
11807
11867
|
}
|
|
11808
11868
|
}
|
|
11809
|
-
async function
|
|
11869
|
+
async function runGlobalInstall2(opts = {}) {
|
|
11810
11870
|
const p = globalPaths();
|
|
11811
11871
|
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
11812
11872
|
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
@@ -11977,7 +12037,7 @@ async function main() {
|
|
|
11977
12037
|
if (data?.project?.name) {
|
|
11978
12038
|
console.log(` ${c.dim}Project:${c.reset} ${c.cyan}${data.project.name}${c.reset}`);
|
|
11979
12039
|
}
|
|
11980
|
-
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email });
|
|
12040
|
+
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email, email: data?.user?.email });
|
|
11981
12041
|
break;
|
|
11982
12042
|
}
|
|
11983
12043
|
if (data?.status === "expired" || data?.status === "not_found") {
|
|
@@ -11997,7 +12057,7 @@ async function main() {
|
|
|
11997
12057
|
return;
|
|
11998
12058
|
}
|
|
11999
12059
|
console.log("");
|
|
12000
|
-
await
|
|
12060
|
+
await runGlobalInstall2({ apiKey, apiUrl });
|
|
12001
12061
|
console.log("");
|
|
12002
12062
|
console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
12003
12063
|
console.log(" \u2502 You are logged in and protected. \u2502");
|
|
@@ -16540,9 +16600,10 @@ async function main5() {
|
|
|
16540
16600
|
const subcommand = process.argv[2];
|
|
16541
16601
|
if (IS_HUMAN_CLI) {
|
|
16542
16602
|
const tuiBound = subcommand === "dataroom" || process.argv.length <= 2 && process.stdout.isTTY && process.stdin.isTTY;
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16603
|
+
if (!tuiBound) {
|
|
16604
|
+
const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
16605
|
+
maybeSelfUpdate2();
|
|
16606
|
+
}
|
|
16546
16607
|
}
|
|
16547
16608
|
if (process.argv.length <= 2) {
|
|
16548
16609
|
if (process.stdout.isTTY && process.stdin.isTTY) {
|
package/dist/login.js
CHANGED
|
@@ -383,7 +383,7 @@ async function main() {
|
|
|
383
383
|
if (data?.project?.name) {
|
|
384
384
|
console.log(` ${c.dim}Project:${c.reset} ${c.cyan}${data.project.name}${c.reset}`);
|
|
385
385
|
}
|
|
386
|
-
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email });
|
|
386
|
+
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email, email: data?.user?.email });
|
|
387
387
|
break;
|
|
388
388
|
}
|
|
389
389
|
if (data?.status === "expired" || data?.status === "not_found") {
|
package/dist/self-update.d.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
export declare function currentVersion(): string;
|
|
2
|
+
/** What the dataroom shows about the updater. */
|
|
3
|
+
export type UpdateStatus = {
|
|
4
|
+
kind: 'idle';
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'updating';
|
|
7
|
+
version: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'updated';
|
|
10
|
+
version: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'manual';
|
|
13
|
+
version: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The dataroom's updater (Claude Code-style): check the registry EVERY time the
|
|
17
|
+
* TUI opens (and periodically while it stays open), install the new version in
|
|
18
|
+
* the background, then tell the user to restart. `onStatus` drives the in-app
|
|
19
|
+
* status line; nothing is ever written to the terminal directly.
|
|
20
|
+
*/
|
|
21
|
+
export declare function tuiUpdateFlow(onStatus: (s: UpdateStatus) => void): Promise<void>;
|
|
2
22
|
/**
|
|
3
23
|
* Fire-and-forget startup hook. `notify` writes the human-facing one-liner —
|
|
4
24
|
* callers pass a stderr writer so the notice never lands in piped stdout.
|
package/dist/tui/index.js
CHANGED
|
@@ -5,9 +5,9 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/tui/index.tsx
|
|
8
|
-
import { appendFileSync, mkdirSync as
|
|
9
|
-
import { homedir as
|
|
10
|
-
import { join as
|
|
8
|
+
import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
|
|
9
|
+
import { homedir as homedir7 } from "os";
|
|
10
|
+
import { join as join7 } from "path";
|
|
11
11
|
import { render } from "ink";
|
|
12
12
|
|
|
13
13
|
// src/tui/App.tsx
|
|
@@ -462,7 +462,7 @@ async function pollDeviceLogin(apiUrl, deviceCode) {
|
|
|
462
462
|
});
|
|
463
463
|
const j = await res.json().catch(() => ({}));
|
|
464
464
|
if (j.status === "approved" && j.api_key) {
|
|
465
|
-
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email };
|
|
465
|
+
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email, email: j.user?.email };
|
|
466
466
|
}
|
|
467
467
|
if (j.status === "expired" || j.status === "not_found") return { status: j.status };
|
|
468
468
|
return { status: "pending" };
|
|
@@ -3333,11 +3333,11 @@ function AccountsPanel({
|
|
|
3333
3333
|
if (abort.current) return;
|
|
3334
3334
|
const res = await pollDeviceLogin(DEFAULT_API_URL, start.deviceCode);
|
|
3335
3335
|
if (res.status === "approved" && res.apiKey) {
|
|
3336
|
-
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user });
|
|
3337
|
-
setLogin({ phase: "done", msg: `\u2713 added ${res.
|
|
3336
|
+
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user, email: res.email });
|
|
3337
|
+
setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
|
|
3338
3338
|
refresh();
|
|
3339
3339
|
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL });
|
|
3340
|
-
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user });
|
|
3340
|
+
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user, email: res.email });
|
|
3341
3341
|
return;
|
|
3342
3342
|
}
|
|
3343
3343
|
if (res.status === "expired" || res.status === "not_found") {
|
|
@@ -3364,13 +3364,13 @@ function AccountsPanel({
|
|
|
3364
3364
|
if (a) {
|
|
3365
3365
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3366
3366
|
onView?.(a);
|
|
3367
|
-
setMsg({ text: `viewing ${a.
|
|
3367
|
+
setMsg({ text: `viewing ${a.email || a.user || a.project || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
|
|
3368
3368
|
}
|
|
3369
3369
|
} else if (input === "m") {
|
|
3370
3370
|
const a = accounts[sel];
|
|
3371
3371
|
if (a) {
|
|
3372
3372
|
const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3373
|
-
setMsg(ok ? { text: `\u2713 ${a.
|
|
3373
|
+
setMsg(ok ? { text: `\u2713 ${a.email || a.user || a.project || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
3374
3374
|
refresh();
|
|
3375
3375
|
}
|
|
3376
3376
|
} else if (input === "n") beginLogin();
|
|
@@ -3413,16 +3413,137 @@ function AccountsPanel({
|
|
|
3413
3413
|
const isActive = isActiveAccount(a.apiKey);
|
|
3414
3414
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
3415
3415
|
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
3416
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.
|
|
3416
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.email || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
|
|
3417
3417
|
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3418
3418
|
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3419
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.
|
|
3419
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.project ? truncate(a.project, 24) : "" })
|
|
3420
3420
|
] }, a.apiKey);
|
|
3421
3421
|
}) }),
|
|
3422
3422
|
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
|
|
3423
3423
|
] });
|
|
3424
3424
|
}
|
|
3425
3425
|
|
|
3426
|
+
// src/self-update.ts
|
|
3427
|
+
import { execFile, spawn as spawn3 } from "child_process";
|
|
3428
|
+
import { mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync5 } from "fs";
|
|
3429
|
+
import { homedir as homedir6 } from "os";
|
|
3430
|
+
import { dirname, join as join6 } from "path";
|
|
3431
|
+
import { fileURLToPath } from "url";
|
|
3432
|
+
var PKG = "@solongate/proxy";
|
|
3433
|
+
var CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
3434
|
+
var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
3435
|
+
var STATE_FILE = join6(homedir6(), ".solongate", ".self-update.json");
|
|
3436
|
+
var LOG_FILE = join6(homedir6(), ".solongate", "self-update.log");
|
|
3437
|
+
function readState() {
|
|
3438
|
+
try {
|
|
3439
|
+
const s = JSON.parse(readFileSync4(STATE_FILE, "utf-8"));
|
|
3440
|
+
return s && typeof s === "object" ? s : {};
|
|
3441
|
+
} catch {
|
|
3442
|
+
return {};
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
function writeState(s) {
|
|
3446
|
+
try {
|
|
3447
|
+
mkdirSync4(join6(homedir6(), ".solongate"), { recursive: true });
|
|
3448
|
+
writeFileSync5(STATE_FILE, JSON.stringify(s));
|
|
3449
|
+
} catch {
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
function currentVersion() {
|
|
3453
|
+
try {
|
|
3454
|
+
const pkg = JSON.parse(readFileSync4(join6(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
3455
|
+
return pkg.version ?? "0.0.0";
|
|
3456
|
+
} catch {
|
|
3457
|
+
return "0.0.0";
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
function newerThan(b, a) {
|
|
3461
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
3462
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
3463
|
+
for (let i = 0; i < 3; i++) {
|
|
3464
|
+
if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
|
|
3465
|
+
if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
|
|
3466
|
+
}
|
|
3467
|
+
return false;
|
|
3468
|
+
}
|
|
3469
|
+
async function fetchLatest() {
|
|
3470
|
+
try {
|
|
3471
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, { signal: AbortSignal.timeout(2e3) });
|
|
3472
|
+
if (!res.ok) return null;
|
|
3473
|
+
const j = await res.json();
|
|
3474
|
+
return typeof j.version === "string" ? j.version : null;
|
|
3475
|
+
} catch {
|
|
3476
|
+
return null;
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
function npmGlobalRoot() {
|
|
3480
|
+
return new Promise((resolve2) => {
|
|
3481
|
+
try {
|
|
3482
|
+
execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err, stdout) => {
|
|
3483
|
+
resolve2(err ? null : stdout.trim() || null);
|
|
3484
|
+
});
|
|
3485
|
+
} catch {
|
|
3486
|
+
resolve2(null);
|
|
3487
|
+
}
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
async function isGlobalInstall() {
|
|
3491
|
+
try {
|
|
3492
|
+
const script = realpathSync(process.argv[1] ?? "");
|
|
3493
|
+
if (!script) return false;
|
|
3494
|
+
const root = await npmGlobalRoot();
|
|
3495
|
+
if (!root) return false;
|
|
3496
|
+
return script.startsWith(realpathSync(root));
|
|
3497
|
+
} catch {
|
|
3498
|
+
return false;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
function runGlobalInstall(version) {
|
|
3502
|
+
return new Promise((resolve2) => {
|
|
3503
|
+
try {
|
|
3504
|
+
mkdirSync4(join6(homedir6(), ".solongate"), { recursive: true });
|
|
3505
|
+
execFile(
|
|
3506
|
+
"npm",
|
|
3507
|
+
["install", "-g", `${PKG}@${version}`],
|
|
3508
|
+
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
3509
|
+
(err, stdout, stderr) => {
|
|
3510
|
+
try {
|
|
3511
|
+
writeFileSync5(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
|
|
3512
|
+
${stdout}
|
|
3513
|
+
${stderr}
|
|
3514
|
+
`, { flag: "a" });
|
|
3515
|
+
} catch {
|
|
3516
|
+
}
|
|
3517
|
+
resolve2(!err);
|
|
3518
|
+
}
|
|
3519
|
+
);
|
|
3520
|
+
} catch {
|
|
3521
|
+
resolve2(false);
|
|
3522
|
+
}
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
async function tuiUpdateFlow(onStatus) {
|
|
3526
|
+
try {
|
|
3527
|
+
const current = currentVersion();
|
|
3528
|
+
const latest = await fetchLatest();
|
|
3529
|
+
const state = readState();
|
|
3530
|
+
if (latest) writeState({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
|
|
3531
|
+
if (!latest || !newerThan(latest, current)) return;
|
|
3532
|
+
const attempts = readState().attempts ?? {};
|
|
3533
|
+
const canRetry = Date.now() - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS;
|
|
3534
|
+
if (await isGlobalInstall() && canRetry) {
|
|
3535
|
+
writeState({ ...readState(), attempts: { [latest]: Date.now() } });
|
|
3536
|
+
onStatus({ kind: "updating", version: latest });
|
|
3537
|
+
if (await runGlobalInstall(latest)) {
|
|
3538
|
+
onStatus({ kind: "updated", version: latest });
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
onStatus({ kind: "manual", version: latest });
|
|
3543
|
+
} catch {
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3426
3547
|
// src/tui/App.tsx
|
|
3427
3548
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3428
3549
|
function LiveHint() {
|
|
@@ -3469,17 +3590,29 @@ function App() {
|
|
|
3469
3590
|
const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
|
|
3470
3591
|
const [focus, setFocus] = useState9("nav");
|
|
3471
3592
|
const [help, setHelp] = useState9(false);
|
|
3593
|
+
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
3594
|
+
useEffect7(() => {
|
|
3595
|
+
let alive = true;
|
|
3596
|
+
const run = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
3597
|
+
run();
|
|
3598
|
+
const t = setInterval(run, 30 * 6e4);
|
|
3599
|
+
return () => {
|
|
3600
|
+
alive = false;
|
|
3601
|
+
clearInterval(t);
|
|
3602
|
+
};
|
|
3603
|
+
}, []);
|
|
3472
3604
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
3473
3605
|
const cur = accounts[acctIdx];
|
|
3474
|
-
const acctLabel = cur ? cur.
|
|
3606
|
+
const acctLabel = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
3475
3607
|
useEffect7(() => {
|
|
3476
|
-
if (!cur || cur.
|
|
3608
|
+
if (!cur || cur.email) return;
|
|
3477
3609
|
let alive = true;
|
|
3478
3610
|
api.auth.me().then((r) => {
|
|
3479
|
-
const project = r.project?.name ||
|
|
3480
|
-
const user = r.user?.name ||
|
|
3481
|
-
|
|
3482
|
-
|
|
3611
|
+
const project = r.project?.name || cur.project;
|
|
3612
|
+
const user = r.user?.name || cur.user;
|
|
3613
|
+
const email = r.user?.email || void 0;
|
|
3614
|
+
if (!alive || !project && !user && !email) return;
|
|
3615
|
+
saveAccount({ ...cur, project, user, email });
|
|
3483
3616
|
setAccounts(listAccounts());
|
|
3484
3617
|
}).catch(() => {
|
|
3485
3618
|
});
|
|
@@ -3538,7 +3671,8 @@ function App() {
|
|
|
3538
3671
|
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
3539
3672
|
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
3540
3673
|
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
|
|
3541
|
-
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" })
|
|
3674
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
|
|
3675
|
+
update2.kind === "updating" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
3542
3676
|
] }),
|
|
3543
3677
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
3544
3678
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
@@ -3584,11 +3718,11 @@ async function launchTui() {
|
|
|
3584
3718
|
return;
|
|
3585
3719
|
}
|
|
3586
3720
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
3587
|
-
const debugLog =
|
|
3721
|
+
const debugLog = join7(homedir7(), ".solongate", "dataroom-debug.log");
|
|
3588
3722
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
3589
3723
|
const toFile = (level) => (...args) => {
|
|
3590
3724
|
try {
|
|
3591
|
-
|
|
3725
|
+
mkdirSync5(join7(homedir7(), ".solongate"), { recursive: true });
|
|
3592
3726
|
appendFileSync(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
3593
3727
|
`);
|
|
3594
3728
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.49",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|