@solongate/proxy 0.81.89 → 0.81.91

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
@@ -7274,6 +7274,7 @@ async function request(method, path, opts = {}) {
7274
7274
  }
7275
7275
  if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
7276
7276
  if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
7277
+ 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
7278
  throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
7278
7279
  }
7279
7280
  return json;
@@ -8840,6 +8841,10 @@ function PoliciesPanel({ focused }) {
8840
8841
  setRi(0);
8841
8842
  }
8842
8843
  }, [detail.data]);
8844
+ usePoll(() => {
8845
+ list6.reloadQuiet();
8846
+ activeQ.reloadQuiet();
8847
+ }, 6e3);
8843
8848
  const mutate = (nextRules, nextMode = mode) => {
8844
8849
  setRules(nextRules);
8845
8850
  setMode(nextMode);
@@ -8876,6 +8881,13 @@ function PoliciesPanel({ focused }) {
8876
8881
  };
8877
8882
  useInput2(
8878
8883
  (input, key) => {
8884
+ if (input === "r" && !editing) {
8885
+ list6.reload();
8886
+ activeQ.reload();
8887
+ detail.reload();
8888
+ setStatus("refreshed");
8889
+ return;
8890
+ }
8879
8891
  if (view === "list") {
8880
8892
  if (key.upArrow) setPi((n) => Math.max(0, n - 1));
8881
8893
  else if (key.downArrow) setPi((n) => Math.min(policies.length - 1, n + 1));
@@ -8966,7 +8978,7 @@ function PoliciesPanel({ focused }) {
8966
8978
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
8967
8979
  ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
8968
8980
  ] }),
8969
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate (none)" : "press \u2192 to browse" }),
8981
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 r refresh" : "press \u2192 to browse" }),
8970
8982
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
8971
8983
  (i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
8972
8984
  /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
@@ -9097,8 +9109,13 @@ function RateLimitPanel({ focused }) {
9097
9109
  const [fi, setFi] = useState4(0);
9098
9110
  const [status, setStatus] = useState4(null);
9099
9111
  useEffect4(() => {
9100
- if (layersQ.data && !draft) setDraft({ ...layersQ.data.layers.rateLimit });
9101
- }, [layersQ.data, draft]);
9112
+ if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
9113
+ }, [layersQ.data]);
9114
+ usePoll(() => {
9115
+ if (!dirty) layersQ.reloadQuiet();
9116
+ historyQ.reloadQuiet();
9117
+ insightsQ.reloadQuiet();
9118
+ }, 6e3);
9102
9119
  const adjust = (dir, step) => {
9103
9120
  if (!draft) return;
9104
9121
  const field = FIELDS2[fi];
@@ -9115,6 +9132,7 @@ function RateLimitPanel({ focused }) {
9115
9132
  setDraft({ ...res.layers.rateLimit });
9116
9133
  setDirty(false);
9117
9134
  setStatus("\u2713 Saved");
9135
+ layersQ.reload();
9118
9136
  historyQ.reload();
9119
9137
  insightsQ.reload();
9120
9138
  } catch (e) {
@@ -9129,13 +9147,19 @@ function RateLimitPanel({ focused }) {
9129
9147
  else if (key.leftArrow) adjust(-1, step);
9130
9148
  else if (key.rightArrow) adjust(1, step);
9131
9149
  else if (input === "s") void save();
9150
+ else if (input === "r") {
9151
+ layersQ.reload();
9152
+ historyQ.reload();
9153
+ insightsQ.reload();
9154
+ setStatus("refreshed");
9155
+ }
9132
9156
  },
9133
9157
  { isActive: focused }
9134
9158
  );
9135
9159
  const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
9136
9160
  const lastChange = history[0];
9137
9161
  const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
9138
- const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => new Date(b.minute).getTime() - new Date(a.minute).getTime());
9162
+ const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
9139
9163
  return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
9140
9164
  const lim = draft.perMinute;
9141
9165
  const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
@@ -9147,7 +9171,7 @@ function RateLimitPanel({ focused }) {
9147
9171
  const shown = anomalies2.slice(0, burstBudget);
9148
9172
  const bw = Math.max(10, cols - 30);
9149
9173
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", height: rows, overflow: "hidden", children: [
9150
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 field \xB7 \u2190\u2192 \xB11 \xB7 shift+\u2190\u2192 \xB110 \xB7 s save" : "press \u2192 to edit" }),
9174
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 field \xB7 \u2190\u2192 \xB11 \xB7 shift+\u2190\u2192 \xB110 \xB7 s save \xB7 r refresh" : "press \u2192 to edit" }),
9151
9175
  /* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
9152
9176
  /* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
9153
9177
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
@@ -9251,13 +9275,16 @@ function DlpPanel({ focused }) {
9251
9275
  const [newName, setNewName] = useState5("");
9252
9276
  const [input, setInput] = useState5("");
9253
9277
  useEffect5(() => {
9254
- if (q.data && !dlp) {
9278
+ if (q.data && !dirty) {
9255
9279
  setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
9256
9280
  setAvailable(q.data.availablePatterns);
9257
9281
  setGhostOn(q.data.layers.ghost.mode === "on");
9258
9282
  setGhostPats([...q.data.layers.ghost.patterns]);
9259
9283
  }
9260
- }, [q.data, dlp]);
9284
+ }, [q.data]);
9285
+ usePoll(() => {
9286
+ if (!dirty && !adding) q.reloadQuiet();
9287
+ }, 6e3);
9261
9288
  const mutate = (next) => {
9262
9289
  setDlp(next);
9263
9290
  setDirty(true);
@@ -9274,6 +9301,7 @@ function DlpPanel({ focused }) {
9274
9301
  setGhostPats([...res.layers.ghost.patterns]);
9275
9302
  setDirty(false);
9276
9303
  setStatus("\u2713 Saved");
9304
+ q.reload();
9277
9305
  } catch (e) {
9278
9306
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
9279
9307
  }
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;
@@ -1958,6 +1959,10 @@ function PoliciesPanel({ focused }) {
1958
1959
  setRi(0);
1959
1960
  }
1960
1961
  }, [detail.data]);
1962
+ usePoll(() => {
1963
+ list5.reloadQuiet();
1964
+ activeQ.reloadQuiet();
1965
+ }, 6e3);
1961
1966
  const mutate = (nextRules, nextMode = mode) => {
1962
1967
  setRules(nextRules);
1963
1968
  setMode(nextMode);
@@ -1994,6 +1999,13 @@ function PoliciesPanel({ focused }) {
1994
1999
  };
1995
2000
  useInput2(
1996
2001
  (input, key) => {
2002
+ if (input === "r" && !editing) {
2003
+ list5.reload();
2004
+ activeQ.reload();
2005
+ detail.reload();
2006
+ setStatus("refreshed");
2007
+ return;
2008
+ }
1997
2009
  if (view === "list") {
1998
2010
  if (key.upArrow) setPi((n) => Math.max(0, n - 1));
1999
2011
  else if (key.downArrow) setPi((n) => Math.min(policies.length - 1, n + 1));
@@ -2084,7 +2096,7 @@ function PoliciesPanel({ focused }) {
2084
2096
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
2085
2097
  ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
2086
2098
  ] }),
2087
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate (none)" : "press \u2192 to browse" }),
2099
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 r refresh" : "press \u2192 to browse" }),
2088
2100
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
2089
2101
  (i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
2090
2102
  /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
@@ -2190,8 +2202,13 @@ function RateLimitPanel({ focused }) {
2190
2202
  const [fi, setFi] = useState4(0);
2191
2203
  const [status, setStatus] = useState4(null);
2192
2204
  useEffect4(() => {
2193
- if (layersQ.data && !draft) setDraft({ ...layersQ.data.layers.rateLimit });
2194
- }, [layersQ.data, draft]);
2205
+ if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
2206
+ }, [layersQ.data]);
2207
+ usePoll(() => {
2208
+ if (!dirty) layersQ.reloadQuiet();
2209
+ historyQ.reloadQuiet();
2210
+ insightsQ.reloadQuiet();
2211
+ }, 6e3);
2195
2212
  const adjust = (dir, step) => {
2196
2213
  if (!draft) return;
2197
2214
  const field = FIELDS2[fi];
@@ -2208,6 +2225,7 @@ function RateLimitPanel({ focused }) {
2208
2225
  setDraft({ ...res.layers.rateLimit });
2209
2226
  setDirty(false);
2210
2227
  setStatus("\u2713 Saved");
2228
+ layersQ.reload();
2211
2229
  historyQ.reload();
2212
2230
  insightsQ.reload();
2213
2231
  } catch (e) {
@@ -2222,13 +2240,19 @@ function RateLimitPanel({ focused }) {
2222
2240
  else if (key.leftArrow) adjust(-1, step);
2223
2241
  else if (key.rightArrow) adjust(1, step);
2224
2242
  else if (input === "s") void save();
2243
+ else if (input === "r") {
2244
+ layersQ.reload();
2245
+ historyQ.reload();
2246
+ insightsQ.reload();
2247
+ setStatus("refreshed");
2248
+ }
2225
2249
  },
2226
2250
  { isActive: focused }
2227
2251
  );
2228
2252
  const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
2229
2253
  const lastChange = history[0];
2230
2254
  const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
2231
- const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => new Date(b.minute).getTime() - new Date(a.minute).getTime());
2255
+ const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
2232
2256
  return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
2233
2257
  const lim = draft.perMinute;
2234
2258
  const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
@@ -2240,7 +2264,7 @@ function RateLimitPanel({ focused }) {
2240
2264
  const shown = anomalies2.slice(0, burstBudget);
2241
2265
  const bw = Math.max(10, cols - 30);
2242
2266
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", height: rows, overflow: "hidden", children: [
2243
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 field \xB7 \u2190\u2192 \xB11 \xB7 shift+\u2190\u2192 \xB110 \xB7 s save" : "press \u2192 to edit" }),
2267
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 field \xB7 \u2190\u2192 \xB11 \xB7 shift+\u2190\u2192 \xB110 \xB7 s save \xB7 r refresh" : "press \u2192 to edit" }),
2244
2268
  /* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
2245
2269
  /* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
2246
2270
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
@@ -2329,13 +2353,16 @@ function DlpPanel({ focused }) {
2329
2353
  const [newName, setNewName] = useState5("");
2330
2354
  const [input, setInput] = useState5("");
2331
2355
  useEffect5(() => {
2332
- if (q.data && !dlp) {
2356
+ if (q.data && !dirty) {
2333
2357
  setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
2334
2358
  setAvailable(q.data.availablePatterns);
2335
2359
  setGhostOn(q.data.layers.ghost.mode === "on");
2336
2360
  setGhostPats([...q.data.layers.ghost.patterns]);
2337
2361
  }
2338
- }, [q.data, dlp]);
2362
+ }, [q.data]);
2363
+ usePoll(() => {
2364
+ if (!dirty && !adding) q.reloadQuiet();
2365
+ }, 6e3);
2339
2366
  const mutate = (next) => {
2340
2367
  setDlp(next);
2341
2368
  setDirty(true);
@@ -2352,6 +2379,7 @@ function DlpPanel({ focused }) {
2352
2379
  setGhostPats([...res.layers.ghost.patterns]);
2353
2380
  setDirty(false);
2354
2381
  setStatus("\u2713 Saved");
2382
+ q.reload();
2355
2383
  } catch (e) {
2356
2384
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
2357
2385
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.89",
3
+ "version": "0.81.91",
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": {