@solongate/proxy 0.81.90 → 0.81.92

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.
@@ -134,6 +134,7 @@ async function request(method, path, opts = {}) {
134
134
  }
135
135
  if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
136
136
  if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
137
+ if (res.status >= 500) throw new ApiError(res.status, "SERVER_ERROR", text || "SolonGate API had a problem (server error). Please try again in a moment.");
137
138
  throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
138
139
  }
139
140
  return json;
package/dist/index.js CHANGED
@@ -6558,7 +6558,9 @@ var init_cli_utils = __esm({
6558
6558
  var self_update_exports = {};
6559
6559
  __export(self_update_exports, {
6560
6560
  currentVersion: () => currentVersion,
6561
+ latestVersion: () => latestVersion,
6561
6562
  maybeSelfUpdate: () => maybeSelfUpdate,
6563
+ newerThan: () => newerThan,
6562
6564
  tuiUpdateFlow: () => tuiUpdateFlow
6563
6565
  });
6564
6566
  import { execFile, spawn } from "child_process";
@@ -6598,6 +6600,9 @@ function newerThan(b, a) {
6598
6600
  }
6599
6601
  return false;
6600
6602
  }
6603
+ async function latestVersion() {
6604
+ return fetchLatest();
6605
+ }
6601
6606
  async function fetchLatest() {
6602
6607
  try {
6603
6608
  const res = await fetch(`https://registry.npmjs.org/${PKG}`, {
@@ -7274,6 +7279,7 @@ async function request(method, path, opts = {}) {
7274
7279
  }
7275
7280
  if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
7276
7281
  if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
7282
+ if (res.status >= 500) throw new ApiError(res.status, "SERVER_ERROR", text || "SolonGate API had a problem (server error). Please try again in a moment.");
7277
7283
  throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
7278
7284
  }
7279
7285
  return json;
@@ -9109,7 +9115,7 @@ function RateLimitPanel({ focused }) {
9109
9115
  const [status, setStatus] = useState4(null);
9110
9116
  useEffect4(() => {
9111
9117
  if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
9112
- }, [layersQ.data, dirty]);
9118
+ }, [layersQ.data]);
9113
9119
  usePoll(() => {
9114
9120
  if (!dirty) layersQ.reloadQuiet();
9115
9121
  historyQ.reloadQuiet();
@@ -9131,6 +9137,7 @@ function RateLimitPanel({ focused }) {
9131
9137
  setDraft({ ...res.layers.rateLimit });
9132
9138
  setDirty(false);
9133
9139
  setStatus("\u2713 Saved");
9140
+ layersQ.reload();
9134
9141
  historyQ.reload();
9135
9142
  insightsQ.reload();
9136
9143
  } catch (e) {
@@ -9191,14 +9198,14 @@ function RateLimitPanel({ focused }) {
9191
9198
  /* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
9192
9199
  /* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
9193
9200
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` }),
9194
- /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
9201
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
9195
9202
  /* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
9196
9203
  `Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
9197
9204
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
9198
9205
  ] }),
9199
9206
  anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
9200
9207
  " ",
9201
- insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
9208
+ insightsQ.loading ? "loading\u2026" : insightsQ.error ? `couldn't load bursts: ${String(insightsQ.error).slice(0, 60)}` : "no bursts in the last 7 days"
9202
9209
  ] }) : /* @__PURE__ */ jsx4(
9203
9210
  Table,
9204
9211
  {
@@ -9279,7 +9286,7 @@ function DlpPanel({ focused }) {
9279
9286
  setGhostOn(q.data.layers.ghost.mode === "on");
9280
9287
  setGhostPats([...q.data.layers.ghost.patterns]);
9281
9288
  }
9282
- }, [q.data, dirty]);
9289
+ }, [q.data]);
9283
9290
  usePoll(() => {
9284
9291
  if (!dirty && !adding) q.reloadQuiet();
9285
9292
  }, 6e3);
@@ -9299,6 +9306,7 @@ function DlpPanel({ focused }) {
9299
9306
  setGhostPats([...res.layers.ghost.patterns]);
9300
9307
  setDirty(false);
9301
9308
  setStatus("\u2713 Saved");
9309
+ q.reload();
9302
9310
  } catch (e) {
9303
9311
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
9304
9312
  }
@@ -10355,6 +10363,18 @@ function SettingsPanel({
10355
10363
  const [msg, setMsg] = useState7(null);
10356
10364
  const [busy, setBusy] = useState7(false);
10357
10365
  const [editor, setEditor] = useState7(null);
10366
+ const [latest, setLatest] = useState7(null);
10367
+ const ver = currentVersion();
10368
+ useEffect6(() => {
10369
+ let live2 = true;
10370
+ latestVersion().then((v) => {
10371
+ if (live2) setLatest(v);
10372
+ }).catch(() => {
10373
+ });
10374
+ return () => {
10375
+ live2 = false;
10376
+ };
10377
+ }, []);
10358
10378
  const [accounts, setAccounts] = useState7(() => listAccounts());
10359
10379
  const [login, setLogin] = useState7(null);
10360
10380
  const [tick, setTick] = useState7(0);
@@ -10908,7 +10928,7 @@ function SettingsPanel({
10908
10928
  );
10909
10929
  lineKey.push("");
10910
10930
  }
10911
- const budget = Math.max(4, rows - 2);
10931
+ const budget = Math.max(4, rows - 3);
10912
10932
  const selLine = Math.max(0, lineKey.indexOf(keyOf(cur)));
10913
10933
  const maxStart = Math.max(0, lineEls.length - budget);
10914
10934
  const startL = Math.min(Math.max(0, selLine - Math.floor(budget / 2)), maxStart);
@@ -10921,7 +10941,11 @@ function SettingsPanel({
10921
10941
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
10922
10942
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
10923
10943
  ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10924
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
10944
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win }),
10945
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", color: theme.dim, children: [
10946
+ `solongate v${ver}`,
10947
+ latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: " \xB7 latest" }) : null
10948
+ ] })
10925
10949
  ] }) });
10926
10950
  }
10927
10951
  var EVENTS, SPIN2, SIGNALS2, SIGNAL_LABEL, WINDOWS, winLabel, THRESH_MIN, THRESH_MAX, nearestWindowIdx, editorFieldCount, acctLabel, alertChannel;
@@ -10933,6 +10957,7 @@ var init_Settings = __esm({
10933
10957
  init_device_login();
10934
10958
  init_global_install();
10935
10959
  init_logs_server_daemon();
10960
+ init_self_update();
10936
10961
  init_components();
10937
10962
  init_hooks();
10938
10963
  init_theme();
@@ -14973,9 +14998,9 @@ var PolicyStore = class {
14973
14998
  saveVersion(policySet, reason, createdBy) {
14974
14999
  const id = policySet.id;
14975
15000
  const history = this.versions.get(id) ?? [];
14976
- const latestVersion = history.length > 0 ? history[history.length - 1].version : 0;
15001
+ const latestVersion2 = history.length > 0 ? history[history.length - 1].version : 0;
14977
15002
  const version = {
14978
- version: latestVersion + 1,
15003
+ version: latestVersion2 + 1,
14979
15004
  policySet: Object.freeze({ ...policySet }),
14980
15005
  hash: this.computeHash(policySet),
14981
15006
  reason,
@@ -1,4 +1,8 @@
1
1
  export declare function currentVersion(): string;
2
+ /** true when `b` is a strictly newer semver than `a` (numeric triples only). */
3
+ export declare function newerThan(b: string, a: string): boolean;
4
+ /** The latest version published to npm, or null if it can't be reached. */
5
+ export declare function latestVersion(): Promise<string | null>;
2
6
  /** What the dataroom shows about the updater. */
3
7
  export type UpdateStatus = {
4
8
  kind: 'idle';
package/dist/tui/index.js CHANGED
@@ -504,6 +504,7 @@ async function request(method, path, opts = {}) {
504
504
  }
505
505
  if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
506
506
  if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
507
+ if (res.status >= 500) throw new ApiError(res.status, "SERVER_ERROR", text || "SolonGate API had a problem (server error). Please try again in a moment.");
507
508
  throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
508
509
  }
509
510
  return json;
@@ -2202,7 +2203,7 @@ function RateLimitPanel({ focused }) {
2202
2203
  const [status, setStatus] = useState4(null);
2203
2204
  useEffect4(() => {
2204
2205
  if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
2205
- }, [layersQ.data, dirty]);
2206
+ }, [layersQ.data]);
2206
2207
  usePoll(() => {
2207
2208
  if (!dirty) layersQ.reloadQuiet();
2208
2209
  historyQ.reloadQuiet();
@@ -2224,6 +2225,7 @@ function RateLimitPanel({ focused }) {
2224
2225
  setDraft({ ...res.layers.rateLimit });
2225
2226
  setDirty(false);
2226
2227
  setStatus("\u2713 Saved");
2228
+ layersQ.reload();
2227
2229
  historyQ.reload();
2228
2230
  insightsQ.reload();
2229
2231
  } catch (e) {
@@ -2284,14 +2286,14 @@ function RateLimitPanel({ focused }) {
2284
2286
  /* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
2285
2287
  /* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
2286
2288
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` }),
2287
- /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
2289
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
2288
2290
  /* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
2289
2291
  `Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
2290
2292
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
2291
2293
  ] }),
2292
2294
  anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
2293
2295
  " ",
2294
- insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
2296
+ insightsQ.loading ? "loading\u2026" : insightsQ.error ? `couldn't load bursts: ${String(insightsQ.error).slice(0, 60)}` : "no bursts in the last 7 days"
2295
2297
  ] }) : /* @__PURE__ */ jsx4(
2296
2298
  Table,
2297
2299
  {
@@ -2357,7 +2359,7 @@ function DlpPanel({ focused }) {
2357
2359
  setGhostOn(q.data.layers.ghost.mode === "on");
2358
2360
  setGhostPats([...q.data.layers.ghost.patterns]);
2359
2361
  }
2360
- }, [q.data, dirty]);
2362
+ }, [q.data]);
2361
2363
  usePoll(() => {
2362
2364
  if (!dirty && !adding) q.reloadQuiet();
2363
2365
  }, 6e3);
@@ -2377,6 +2379,7 @@ function DlpPanel({ focused }) {
2377
2379
  setGhostPats([...res.layers.ghost.patterns]);
2378
2380
  setDirty(false);
2379
2381
  setStatus("\u2713 Saved");
2382
+ q.reload();
2380
2383
  } catch (e) {
2381
2384
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
2382
2385
  }
@@ -3464,6 +3467,112 @@ function stopLogsServerDaemon() {
3464
3467
  return { desired: "off", running: false, port: s.port || LOGS_SERVER_PORT };
3465
3468
  }
3466
3469
 
3470
+ // src/self-update.ts
3471
+ import { execFile, spawn as spawn4 } from "child_process";
3472
+ import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
3473
+ import { homedir as homedir8 } from "os";
3474
+ import { dirname as dirname3, join as join8 } from "path";
3475
+ import { fileURLToPath as fileURLToPath3 } from "url";
3476
+ var PKG = "@solongate/proxy";
3477
+ var CHECK_EVERY_MS = 30 * 60 * 1e3;
3478
+ var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
3479
+ var STATE_FILE2 = join8(homedir8(), ".solongate", ".self-update.json");
3480
+ var LOG_FILE2 = join8(homedir8(), ".solongate", "self-update.log");
3481
+ function readState2() {
3482
+ try {
3483
+ const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
3484
+ return s && typeof s === "object" ? s : {};
3485
+ } catch {
3486
+ return {};
3487
+ }
3488
+ }
3489
+ function writeState2(s) {
3490
+ try {
3491
+ mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
3492
+ writeFileSync7(STATE_FILE2, JSON.stringify(s));
3493
+ } catch {
3494
+ }
3495
+ }
3496
+ function currentVersion() {
3497
+ try {
3498
+ const pkg = JSON.parse(readFileSync6(join8(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
3499
+ return pkg.version ?? "0.0.0";
3500
+ } catch {
3501
+ return "0.0.0";
3502
+ }
3503
+ }
3504
+ function newerThan(b, a) {
3505
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
3506
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
3507
+ for (let i = 0; i < 3; i++) {
3508
+ if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
3509
+ if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
3510
+ }
3511
+ return false;
3512
+ }
3513
+ async function latestVersion() {
3514
+ return fetchLatest();
3515
+ }
3516
+ async function fetchLatest() {
3517
+ try {
3518
+ const res = await fetch(`https://registry.npmjs.org/${PKG}`, {
3519
+ headers: { accept: "application/vnd.npm.install-v1+json" },
3520
+ signal: AbortSignal.timeout(3e3)
3521
+ });
3522
+ if (!res.ok) return null;
3523
+ const j = await res.json();
3524
+ const latest = j["dist-tags"]?.latest;
3525
+ if (typeof latest !== "string") return null;
3526
+ if (!j.versions || !(latest in j.versions)) return null;
3527
+ return latest;
3528
+ } catch {
3529
+ return null;
3530
+ }
3531
+ }
3532
+ function runGlobalInstall(version) {
3533
+ return new Promise((resolve3) => {
3534
+ try {
3535
+ mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
3536
+ execFile(
3537
+ "npm",
3538
+ ["install", "-g", `${PKG}@${version}`],
3539
+ { timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
3540
+ (err, stdout, stderr) => {
3541
+ try {
3542
+ writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
3543
+ ${stdout}
3544
+ ${stderr}
3545
+ `, { flag: "a" });
3546
+ } catch {
3547
+ }
3548
+ resolve3(!err);
3549
+ }
3550
+ );
3551
+ } catch {
3552
+ resolve3(false);
3553
+ }
3554
+ });
3555
+ }
3556
+ async function tuiUpdateFlow(onStatus) {
3557
+ try {
3558
+ const current = currentVersion();
3559
+ const latest = await fetchLatest();
3560
+ const state = readState2();
3561
+ if (latest) writeState2({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
3562
+ if (!latest || !newerThan(latest, current)) return;
3563
+ if (readState2().installed === latest) {
3564
+ onStatus({ kind: "updated", version: latest });
3565
+ return;
3566
+ }
3567
+ onStatus({ kind: "updating", version: latest });
3568
+ if (await runGlobalInstall(latest)) {
3569
+ writeState2({ ...readState2(), installed: latest });
3570
+ onStatus({ kind: "updated", version: latest });
3571
+ }
3572
+ } catch {
3573
+ }
3574
+ }
3575
+
3467
3576
  // src/tui/panels/Settings.tsx
3468
3577
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3469
3578
  var EVENTS = ["denials", "allowed", "all"];
@@ -3498,6 +3607,18 @@ function SettingsPanel({
3498
3607
  const [msg, setMsg] = useState7(null);
3499
3608
  const [busy, setBusy] = useState7(false);
3500
3609
  const [editor, setEditor] = useState7(null);
3610
+ const [latest, setLatest] = useState7(null);
3611
+ const ver = currentVersion();
3612
+ useEffect6(() => {
3613
+ let live2 = true;
3614
+ latestVersion().then((v) => {
3615
+ if (live2) setLatest(v);
3616
+ }).catch(() => {
3617
+ });
3618
+ return () => {
3619
+ live2 = false;
3620
+ };
3621
+ }, []);
3501
3622
  const [accounts, setAccounts] = useState7(() => listAccounts());
3502
3623
  const [login, setLogin] = useState7(null);
3503
3624
  const [tick, setTick] = useState7(0);
@@ -4051,7 +4172,7 @@ function SettingsPanel({
4051
4172
  );
4052
4173
  lineKey.push("");
4053
4174
  }
4054
- const budget = Math.max(4, rows - 2);
4175
+ const budget = Math.max(4, rows - 3);
4055
4176
  const selLine = Math.max(0, lineKey.indexOf(keyOf(cur)));
4056
4177
  const maxStart = Math.max(0, lineEls.length - budget);
4057
4178
  const startL = Math.min(Math.max(0, selLine - Math.floor(budget / 2)), maxStart);
@@ -4064,113 +4185,14 @@ function SettingsPanel({
4064
4185
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
4065
4186
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
4066
4187
  ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
4067
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
4188
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win }),
4189
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", color: theme.dim, children: [
4190
+ `solongate v${ver}`,
4191
+ latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: " \xB7 latest" }) : null
4192
+ ] })
4068
4193
  ] }) });
4069
4194
  }
4070
4195
 
4071
- // src/self-update.ts
4072
- import { execFile, spawn as spawn4 } from "child_process";
4073
- import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
4074
- import { homedir as homedir8 } from "os";
4075
- import { dirname as dirname3, join as join8 } from "path";
4076
- import { fileURLToPath as fileURLToPath3 } from "url";
4077
- var PKG = "@solongate/proxy";
4078
- var CHECK_EVERY_MS = 30 * 60 * 1e3;
4079
- var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
4080
- var STATE_FILE2 = join8(homedir8(), ".solongate", ".self-update.json");
4081
- var LOG_FILE2 = join8(homedir8(), ".solongate", "self-update.log");
4082
- function readState2() {
4083
- try {
4084
- const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
4085
- return s && typeof s === "object" ? s : {};
4086
- } catch {
4087
- return {};
4088
- }
4089
- }
4090
- function writeState2(s) {
4091
- try {
4092
- mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
4093
- writeFileSync7(STATE_FILE2, JSON.stringify(s));
4094
- } catch {
4095
- }
4096
- }
4097
- function currentVersion() {
4098
- try {
4099
- const pkg = JSON.parse(readFileSync6(join8(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
4100
- return pkg.version ?? "0.0.0";
4101
- } catch {
4102
- return "0.0.0";
4103
- }
4104
- }
4105
- function newerThan(b, a) {
4106
- const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
4107
- const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
4108
- for (let i = 0; i < 3; i++) {
4109
- if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
4110
- if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
4111
- }
4112
- return false;
4113
- }
4114
- async function fetchLatest() {
4115
- try {
4116
- const res = await fetch(`https://registry.npmjs.org/${PKG}`, {
4117
- headers: { accept: "application/vnd.npm.install-v1+json" },
4118
- signal: AbortSignal.timeout(3e3)
4119
- });
4120
- if (!res.ok) return null;
4121
- const j = await res.json();
4122
- const latest = j["dist-tags"]?.latest;
4123
- if (typeof latest !== "string") return null;
4124
- if (!j.versions || !(latest in j.versions)) return null;
4125
- return latest;
4126
- } catch {
4127
- return null;
4128
- }
4129
- }
4130
- function runGlobalInstall(version) {
4131
- return new Promise((resolve3) => {
4132
- try {
4133
- mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
4134
- execFile(
4135
- "npm",
4136
- ["install", "-g", `${PKG}@${version}`],
4137
- { timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
4138
- (err, stdout, stderr) => {
4139
- try {
4140
- writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
4141
- ${stdout}
4142
- ${stderr}
4143
- `, { flag: "a" });
4144
- } catch {
4145
- }
4146
- resolve3(!err);
4147
- }
4148
- );
4149
- } catch {
4150
- resolve3(false);
4151
- }
4152
- });
4153
- }
4154
- async function tuiUpdateFlow(onStatus) {
4155
- try {
4156
- const current = currentVersion();
4157
- const latest = await fetchLatest();
4158
- const state = readState2();
4159
- if (latest) writeState2({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
4160
- if (!latest || !newerThan(latest, current)) return;
4161
- if (readState2().installed === latest) {
4162
- onStatus({ kind: "updated", version: latest });
4163
- return;
4164
- }
4165
- onStatus({ kind: "updating", version: latest });
4166
- if (await runGlobalInstall(latest)) {
4167
- writeState2({ ...readState2(), installed: latest });
4168
- onStatus({ kind: "updated", version: latest });
4169
- }
4170
- } catch {
4171
- }
4172
- }
4173
-
4174
4196
  // src/tui/App.tsx
4175
4197
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
4176
4198
  function LiveHint() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.90",
3
+ "version": "0.81.92",
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": {