@solongate/proxy 0.81.91 → 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.
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}`, {
@@ -9193,14 +9198,14 @@ function RateLimitPanel({ focused }) {
9193
9198
  /* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
9194
9199
  /* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
9195
9200
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` }),
9196
- /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
9201
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
9197
9202
  /* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
9198
9203
  `Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
9199
9204
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
9200
9205
  ] }),
9201
9206
  anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
9202
9207
  " ",
9203
- 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"
9204
9209
  ] }) : /* @__PURE__ */ jsx4(
9205
9210
  Table,
9206
9211
  {
@@ -10358,6 +10363,18 @@ function SettingsPanel({
10358
10363
  const [msg, setMsg] = useState7(null);
10359
10364
  const [busy, setBusy] = useState7(false);
10360
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
+ }, []);
10361
10378
  const [accounts, setAccounts] = useState7(() => listAccounts());
10362
10379
  const [login, setLogin] = useState7(null);
10363
10380
  const [tick, setTick] = useState7(0);
@@ -10911,7 +10928,7 @@ function SettingsPanel({
10911
10928
  );
10912
10929
  lineKey.push("");
10913
10930
  }
10914
- const budget = Math.max(4, rows - 2);
10931
+ const budget = Math.max(4, rows - 3);
10915
10932
  const selLine = Math.max(0, lineKey.indexOf(keyOf(cur)));
10916
10933
  const maxStart = Math.max(0, lineEls.length - budget);
10917
10934
  const startL = Math.min(Math.max(0, selLine - Math.floor(budget / 2)), maxStart);
@@ -10924,7 +10941,11 @@ function SettingsPanel({
10924
10941
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
10925
10942
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
10926
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: " " }),
10927
- /* @__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
+ ] })
10928
10949
  ] }) });
10929
10950
  }
10930
10951
  var EVENTS, SPIN2, SIGNALS2, SIGNAL_LABEL, WINDOWS, winLabel, THRESH_MIN, THRESH_MAX, nearestWindowIdx, editorFieldCount, acctLabel, alertChannel;
@@ -10936,6 +10957,7 @@ var init_Settings = __esm({
10936
10957
  init_device_login();
10937
10958
  init_global_install();
10938
10959
  init_logs_server_daemon();
10960
+ init_self_update();
10939
10961
  init_components();
10940
10962
  init_hooks();
10941
10963
  init_theme();
@@ -14976,9 +14998,9 @@ var PolicyStore = class {
14976
14998
  saveVersion(policySet, reason, createdBy) {
14977
14999
  const id = policySet.id;
14978
15000
  const history = this.versions.get(id) ?? [];
14979
- const latestVersion = history.length > 0 ? history[history.length - 1].version : 0;
15001
+ const latestVersion2 = history.length > 0 ? history[history.length - 1].version : 0;
14980
15002
  const version = {
14981
- version: latestVersion + 1,
15003
+ version: latestVersion2 + 1,
14982
15004
  policySet: Object.freeze({ ...policySet }),
14983
15005
  hash: this.computeHash(policySet),
14984
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
@@ -2286,14 +2286,14 @@ function RateLimitPanel({ focused }) {
2286
2286
  /* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
2287
2287
  /* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
2288
2288
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` }),
2289
- /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
2289
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
2290
2290
  /* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
2291
2291
  `Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
2292
2292
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
2293
2293
  ] }),
2294
2294
  anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
2295
2295
  " ",
2296
- 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"
2297
2297
  ] }) : /* @__PURE__ */ jsx4(
2298
2298
  Table,
2299
2299
  {
@@ -3467,6 +3467,112 @@ function stopLogsServerDaemon() {
3467
3467
  return { desired: "off", running: false, port: s.port || LOGS_SERVER_PORT };
3468
3468
  }
3469
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
+
3470
3576
  // src/tui/panels/Settings.tsx
3471
3577
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3472
3578
  var EVENTS = ["denials", "allowed", "all"];
@@ -3501,6 +3607,18 @@ function SettingsPanel({
3501
3607
  const [msg, setMsg] = useState7(null);
3502
3608
  const [busy, setBusy] = useState7(false);
3503
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
+ }, []);
3504
3622
  const [accounts, setAccounts] = useState7(() => listAccounts());
3505
3623
  const [login, setLogin] = useState7(null);
3506
3624
  const [tick, setTick] = useState7(0);
@@ -4054,7 +4172,7 @@ function SettingsPanel({
4054
4172
  );
4055
4173
  lineKey.push("");
4056
4174
  }
4057
- const budget = Math.max(4, rows - 2);
4175
+ const budget = Math.max(4, rows - 3);
4058
4176
  const selLine = Math.max(0, lineKey.indexOf(keyOf(cur)));
4059
4177
  const maxStart = Math.max(0, lineEls.length - budget);
4060
4178
  const startL = Math.min(Math.max(0, selLine - Math.floor(budget / 2)), maxStart);
@@ -4067,113 +4185,14 @@ function SettingsPanel({
4067
4185
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
4068
4186
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
4069
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: " " }),
4070
- /* @__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
+ ] })
4071
4193
  ] }) });
4072
4194
  }
4073
4195
 
4074
- // src/self-update.ts
4075
- import { execFile, spawn as spawn4 } from "child_process";
4076
- import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
4077
- import { homedir as homedir8 } from "os";
4078
- import { dirname as dirname3, join as join8 } from "path";
4079
- import { fileURLToPath as fileURLToPath3 } from "url";
4080
- var PKG = "@solongate/proxy";
4081
- var CHECK_EVERY_MS = 30 * 60 * 1e3;
4082
- var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
4083
- var STATE_FILE2 = join8(homedir8(), ".solongate", ".self-update.json");
4084
- var LOG_FILE2 = join8(homedir8(), ".solongate", "self-update.log");
4085
- function readState2() {
4086
- try {
4087
- const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
4088
- return s && typeof s === "object" ? s : {};
4089
- } catch {
4090
- return {};
4091
- }
4092
- }
4093
- function writeState2(s) {
4094
- try {
4095
- mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
4096
- writeFileSync7(STATE_FILE2, JSON.stringify(s));
4097
- } catch {
4098
- }
4099
- }
4100
- function currentVersion() {
4101
- try {
4102
- const pkg = JSON.parse(readFileSync6(join8(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
4103
- return pkg.version ?? "0.0.0";
4104
- } catch {
4105
- return "0.0.0";
4106
- }
4107
- }
4108
- function newerThan(b, a) {
4109
- const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
4110
- const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
4111
- for (let i = 0; i < 3; i++) {
4112
- if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
4113
- if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
4114
- }
4115
- return false;
4116
- }
4117
- async function fetchLatest() {
4118
- try {
4119
- const res = await fetch(`https://registry.npmjs.org/${PKG}`, {
4120
- headers: { accept: "application/vnd.npm.install-v1+json" },
4121
- signal: AbortSignal.timeout(3e3)
4122
- });
4123
- if (!res.ok) return null;
4124
- const j = await res.json();
4125
- const latest = j["dist-tags"]?.latest;
4126
- if (typeof latest !== "string") return null;
4127
- if (!j.versions || !(latest in j.versions)) return null;
4128
- return latest;
4129
- } catch {
4130
- return null;
4131
- }
4132
- }
4133
- function runGlobalInstall(version) {
4134
- return new Promise((resolve3) => {
4135
- try {
4136
- mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
4137
- execFile(
4138
- "npm",
4139
- ["install", "-g", `${PKG}@${version}`],
4140
- { timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
4141
- (err, stdout, stderr) => {
4142
- try {
4143
- writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
4144
- ${stdout}
4145
- ${stderr}
4146
- `, { flag: "a" });
4147
- } catch {
4148
- }
4149
- resolve3(!err);
4150
- }
4151
- );
4152
- } catch {
4153
- resolve3(false);
4154
- }
4155
- });
4156
- }
4157
- async function tuiUpdateFlow(onStatus) {
4158
- try {
4159
- const current = currentVersion();
4160
- const latest = await fetchLatest();
4161
- const state = readState2();
4162
- if (latest) writeState2({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
4163
- if (!latest || !newerThan(latest, current)) return;
4164
- if (readState2().installed === latest) {
4165
- onStatus({ kind: "updated", version: latest });
4166
- return;
4167
- }
4168
- onStatus({ kind: "updating", version: latest });
4169
- if (await runGlobalInstall(latest)) {
4170
- writeState2({ ...readState2(), installed: latest });
4171
- onStatus({ kind: "updated", version: latest });
4172
- }
4173
- } catch {
4174
- }
4175
- }
4176
-
4177
4196
  // src/tui/App.tsx
4178
4197
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
4179
4198
  function LiveHint() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.91",
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": {