@solongate/proxy 0.81.94 → 0.81.96
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 +46 -34
- package/dist/tui/index.js +46 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8849,7 +8849,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8849
8849
|
usePoll(() => {
|
|
8850
8850
|
list6.reloadQuiet();
|
|
8851
8851
|
activeQ.reloadQuiet();
|
|
8852
|
-
},
|
|
8852
|
+
}, 3e3);
|
|
8853
8853
|
const mutate = (nextRules, nextMode = mode) => {
|
|
8854
8854
|
setRules(nextRules);
|
|
8855
8855
|
setMode(nextMode);
|
|
@@ -8890,7 +8890,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8890
8890
|
list6.reload();
|
|
8891
8891
|
activeQ.reload();
|
|
8892
8892
|
detail.reload();
|
|
8893
|
-
setStatus(
|
|
8893
|
+
setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
|
|
8894
8894
|
return;
|
|
8895
8895
|
}
|
|
8896
8896
|
if (view === "list") {
|
|
@@ -9103,7 +9103,7 @@ var init_Policies = __esm({
|
|
|
9103
9103
|
// src/tui/panels/RateLimit.tsx
|
|
9104
9104
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
9105
9105
|
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
9106
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
9106
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
9107
9107
|
function RateLimitPanel({ focused }) {
|
|
9108
9108
|
const { cols, rows } = usePanelSize();
|
|
9109
9109
|
const layersQ = useLoader(() => api.settings.getSecurityLayers());
|
|
@@ -9113,14 +9113,17 @@ function RateLimitPanel({ focused }) {
|
|
|
9113
9113
|
const [dirty, setDirty] = useState4(false);
|
|
9114
9114
|
const [fi, setFi] = useState4(0);
|
|
9115
9115
|
const [status, setStatus] = useState4(null);
|
|
9116
|
+
const [burstOff, setBurstOff] = useState4(0);
|
|
9116
9117
|
useEffect4(() => {
|
|
9117
9118
|
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
9118
9119
|
}, [layersQ.data]);
|
|
9119
9120
|
usePoll(() => {
|
|
9120
9121
|
if (!dirty) layersQ.reloadQuiet();
|
|
9122
|
+
}, 3e3);
|
|
9123
|
+
usePoll(() => {
|
|
9121
9124
|
historyQ.reloadQuiet();
|
|
9122
9125
|
insightsQ.reloadQuiet();
|
|
9123
|
-
},
|
|
9126
|
+
}, 1e4);
|
|
9124
9127
|
const adjust = (dir, step) => {
|
|
9125
9128
|
if (!draft) return;
|
|
9126
9129
|
const field = FIELDS2[fi];
|
|
@@ -9144,10 +9147,22 @@ function RateLimitPanel({ focused }) {
|
|
|
9144
9147
|
setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
|
|
9145
9148
|
}
|
|
9146
9149
|
};
|
|
9150
|
+
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
9151
|
+
const lastChange = history[0];
|
|
9152
|
+
const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
|
|
9153
|
+
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
9154
|
+
const hasLoad = (draft?.perMinute ?? 0) > 0;
|
|
9155
|
+
const showExtras = rows >= 20;
|
|
9156
|
+
const fixed = 1 + 4 + (showExtras ? (hasLoad ? 1 : 0) + 5 : 0) + 1 + 1 + 1 + 1;
|
|
9157
|
+
const burstBudget = Math.max(1, rows - fixed);
|
|
9158
|
+
const maxOff = Math.max(0, anomalies2.length - burstBudget);
|
|
9159
|
+
const off = Math.min(burstOff, maxOff);
|
|
9147
9160
|
useInput3(
|
|
9148
9161
|
(input, key) => {
|
|
9149
9162
|
const step = key.shift ? 10 : 1;
|
|
9150
|
-
if (key.
|
|
9163
|
+
if (key.pageDown) setBurstOff((o) => Math.min(o + burstBudget, maxOff));
|
|
9164
|
+
else if (key.pageUp) setBurstOff((o) => Math.max(0, o - burstBudget));
|
|
9165
|
+
else if (key.upArrow) setFi((n) => (n - 1 + FIELDS2.length) % FIELDS2.length);
|
|
9151
9166
|
else if (key.downArrow) setFi((n) => (n + 1) % FIELDS2.length);
|
|
9152
9167
|
else if (key.leftArrow) adjust(-1, step);
|
|
9153
9168
|
else if (key.rightArrow) adjust(1, step);
|
|
@@ -9156,27 +9171,20 @@ function RateLimitPanel({ focused }) {
|
|
|
9156
9171
|
layersQ.reload();
|
|
9157
9172
|
historyQ.reload();
|
|
9158
9173
|
insightsQ.reload();
|
|
9159
|
-
setStatus(
|
|
9174
|
+
setStatus(`\u27F3 refreshed ${when(Date.now())}`);
|
|
9160
9175
|
}
|
|
9161
9176
|
},
|
|
9162
9177
|
{ isActive: focused }
|
|
9163
9178
|
);
|
|
9164
|
-
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
9165
|
-
const lastChange = history[0];
|
|
9166
|
-
const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
|
|
9167
|
-
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
9168
9179
|
return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
9169
9180
|
const lim = draft.perMinute;
|
|
9170
9181
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
9171
9182
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
9172
9183
|
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
9173
|
-
const
|
|
9174
|
-
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 5 + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
9175
|
-
const burstBudget = Math.max(1, rows - fixed);
|
|
9176
|
-
const shown = anomalies2.slice(0, burstBudget);
|
|
9184
|
+
const shown = anomalies2.slice(off, off + burstBudget);
|
|
9177
9185
|
const bw = Math.max(10, cols - 30);
|
|
9178
9186
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", height: rows, overflow: "hidden", children: [
|
|
9179
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ?
|
|
9187
|
+
/* @__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${maxOff > 0 ? " \xB7 PgUp/PgDn bursts" : ""}` : "press \u2192 to edit" }),
|
|
9180
9188
|
/* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
|
|
9181
9189
|
/* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
|
|
9182
9190
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
|
|
@@ -9184,23 +9192,26 @@ function RateLimitPanel({ focused }) {
|
|
|
9184
9192
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per minute", active: focused && fi === 1, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perMinute || "off" }) }),
|
|
9185
9193
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour || "off" }) }),
|
|
9186
9194
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay || "off" }) }),
|
|
9187
|
-
|
|
9188
|
-
/* @__PURE__ */
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9195
|
+
showExtras && /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
9196
|
+
hasLoad ? /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9197
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load now".padEnd(13) }),
|
|
9198
|
+
/* @__PURE__ */ jsx4(Text4, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(18, Math.round(now / lim * 18))) }),
|
|
9199
|
+
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
|
|
9200
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
|
|
9201
|
+
] }) : null,
|
|
9202
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9203
|
+
"Busiest 7d",
|
|
9204
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
9205
|
+
] }),
|
|
9206
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
9207
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
9208
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
9209
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` })
|
|
9196
9210
|
] }),
|
|
9197
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
9198
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
9199
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
9200
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` }),
|
|
9201
9211
|
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
9202
9212
|
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9203
9213
|
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
9214
|
+
maxOff > 0 ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: ` ${off + 1}-${Math.min(off + burstBudget, anomalies2.length)}/${anomalies2.length}` }) : null,
|
|
9204
9215
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
|
|
9205
9216
|
] }),
|
|
9206
9217
|
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
@@ -9219,6 +9230,7 @@ function RateLimitPanel({ focused }) {
|
|
|
9219
9230
|
}
|
|
9220
9231
|
)
|
|
9221
9232
|
] }),
|
|
9233
|
+
/* @__PURE__ */ jsx4(Text4, { children: " " }),
|
|
9222
9234
|
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9223
9235
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "limit now " }),
|
|
9224
9236
|
/* @__PURE__ */ jsx4(Text4, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
|
|
@@ -9289,7 +9301,7 @@ function DlpPanel({ focused }) {
|
|
|
9289
9301
|
}, [q.data]);
|
|
9290
9302
|
usePoll(() => {
|
|
9291
9303
|
if (!dirty && !adding) q.reloadQuiet();
|
|
9292
|
-
},
|
|
9304
|
+
}, 3e3);
|
|
9293
9305
|
const mutate = (next) => {
|
|
9294
9306
|
setDlp(next);
|
|
9295
9307
|
setDirty(true);
|
|
@@ -9331,7 +9343,7 @@ function DlpPanel({ focused }) {
|
|
|
9331
9343
|
if (!dlp) return;
|
|
9332
9344
|
if (key.ctrl && input2 === "r") {
|
|
9333
9345
|
q.reload();
|
|
9334
|
-
setStatus(
|
|
9346
|
+
setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
|
|
9335
9347
|
return;
|
|
9336
9348
|
}
|
|
9337
9349
|
if (key.upArrow) setSel(() => Math.max(0, selC - 1));
|
|
@@ -9667,7 +9679,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9667
9679
|
agentsQ.reload();
|
|
9668
9680
|
statsQ.reloadQuiet();
|
|
9669
9681
|
} else localQ.reload();
|
|
9670
|
-
setMsg({ text:
|
|
9682
|
+
setMsg({ text: `\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`, level: "ok" });
|
|
9671
9683
|
return;
|
|
9672
9684
|
}
|
|
9673
9685
|
if (showHelp) {
|
|
@@ -10360,7 +10372,7 @@ var init_global_install = __esm({
|
|
|
10360
10372
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
10361
10373
|
import TextInput5 from "ink-text-input";
|
|
10362
10374
|
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
10363
|
-
import { Fragment as
|
|
10375
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
10364
10376
|
function SettingsPanel({
|
|
10365
10377
|
active: active2,
|
|
10366
10378
|
focused,
|
|
@@ -10831,11 +10843,11 @@ function SettingsPanel({
|
|
|
10831
10843
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10832
10844
|
cursor(r),
|
|
10833
10845
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
10834
|
-
!guardHere ? /* @__PURE__ */ jsxs7(
|
|
10846
|
+
!guardHere ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
10835
10847
|
/* @__PURE__ */ jsx7(Text7, { color: theme.bad, bold: true, children: "removed" }),
|
|
10836
10848
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
10837
10849
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, children: "enter to install" })
|
|
10838
|
-
] }) : /* @__PURE__ */ jsxs7(
|
|
10850
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
10839
10851
|
/* @__PURE__ */ jsx7(Text7, { color: guardOld ? theme.warn : theme.ok, children: `v${guardVer ?? "?"}` }),
|
|
10840
10852
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guardOld ? " \xB7 update available \xB7 enter update" : " (latest) \xB7 enter reinstall" }),
|
|
10841
10853
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 d remove" })
|
package/dist/tui/index.js
CHANGED
|
@@ -1962,7 +1962,7 @@ function PoliciesPanel({ focused }) {
|
|
|
1962
1962
|
usePoll(() => {
|
|
1963
1963
|
list5.reloadQuiet();
|
|
1964
1964
|
activeQ.reloadQuiet();
|
|
1965
|
-
},
|
|
1965
|
+
}, 3e3);
|
|
1966
1966
|
const mutate = (nextRules, nextMode = mode) => {
|
|
1967
1967
|
setRules(nextRules);
|
|
1968
1968
|
setMode(nextMode);
|
|
@@ -2003,7 +2003,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2003
2003
|
list5.reload();
|
|
2004
2004
|
activeQ.reload();
|
|
2005
2005
|
detail.reload();
|
|
2006
|
-
setStatus(
|
|
2006
|
+
setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
|
|
2007
2007
|
return;
|
|
2008
2008
|
}
|
|
2009
2009
|
if (view === "list") {
|
|
@@ -2185,7 +2185,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2185
2185
|
// src/tui/panels/RateLimit.tsx
|
|
2186
2186
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
2187
2187
|
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
2188
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2188
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2189
2189
|
var MODES = ["off", "detect", "block"];
|
|
2190
2190
|
var FIELDS2 = ["mode", "perMinute", "perHour", "perDay"];
|
|
2191
2191
|
var when = (ms) => {
|
|
@@ -2201,14 +2201,17 @@ function RateLimitPanel({ focused }) {
|
|
|
2201
2201
|
const [dirty, setDirty] = useState4(false);
|
|
2202
2202
|
const [fi, setFi] = useState4(0);
|
|
2203
2203
|
const [status, setStatus] = useState4(null);
|
|
2204
|
+
const [burstOff, setBurstOff] = useState4(0);
|
|
2204
2205
|
useEffect4(() => {
|
|
2205
2206
|
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
2206
2207
|
}, [layersQ.data]);
|
|
2207
2208
|
usePoll(() => {
|
|
2208
2209
|
if (!dirty) layersQ.reloadQuiet();
|
|
2210
|
+
}, 3e3);
|
|
2211
|
+
usePoll(() => {
|
|
2209
2212
|
historyQ.reloadQuiet();
|
|
2210
2213
|
insightsQ.reloadQuiet();
|
|
2211
|
-
},
|
|
2214
|
+
}, 1e4);
|
|
2212
2215
|
const adjust = (dir, step) => {
|
|
2213
2216
|
if (!draft) return;
|
|
2214
2217
|
const field = FIELDS2[fi];
|
|
@@ -2232,10 +2235,22 @@ function RateLimitPanel({ focused }) {
|
|
|
2232
2235
|
setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
|
|
2233
2236
|
}
|
|
2234
2237
|
};
|
|
2238
|
+
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
2239
|
+
const lastChange = history[0];
|
|
2240
|
+
const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
|
|
2241
|
+
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
2242
|
+
const hasLoad = (draft?.perMinute ?? 0) > 0;
|
|
2243
|
+
const showExtras = rows >= 20;
|
|
2244
|
+
const fixed = 1 + 4 + (showExtras ? (hasLoad ? 1 : 0) + 5 : 0) + 1 + 1 + 1 + 1;
|
|
2245
|
+
const burstBudget = Math.max(1, rows - fixed);
|
|
2246
|
+
const maxOff = Math.max(0, anomalies2.length - burstBudget);
|
|
2247
|
+
const off = Math.min(burstOff, maxOff);
|
|
2235
2248
|
useInput3(
|
|
2236
2249
|
(input, key) => {
|
|
2237
2250
|
const step = key.shift ? 10 : 1;
|
|
2238
|
-
if (key.
|
|
2251
|
+
if (key.pageDown) setBurstOff((o) => Math.min(o + burstBudget, maxOff));
|
|
2252
|
+
else if (key.pageUp) setBurstOff((o) => Math.max(0, o - burstBudget));
|
|
2253
|
+
else if (key.upArrow) setFi((n) => (n - 1 + FIELDS2.length) % FIELDS2.length);
|
|
2239
2254
|
else if (key.downArrow) setFi((n) => (n + 1) % FIELDS2.length);
|
|
2240
2255
|
else if (key.leftArrow) adjust(-1, step);
|
|
2241
2256
|
else if (key.rightArrow) adjust(1, step);
|
|
@@ -2244,27 +2259,20 @@ function RateLimitPanel({ focused }) {
|
|
|
2244
2259
|
layersQ.reload();
|
|
2245
2260
|
historyQ.reload();
|
|
2246
2261
|
insightsQ.reload();
|
|
2247
|
-
setStatus(
|
|
2262
|
+
setStatus(`\u27F3 refreshed ${when(Date.now())}`);
|
|
2248
2263
|
}
|
|
2249
2264
|
},
|
|
2250
2265
|
{ isActive: focused }
|
|
2251
2266
|
);
|
|
2252
|
-
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
2253
|
-
const lastChange = history[0];
|
|
2254
|
-
const peaks = insightsQ.data?.["peaks"] ?? { minute: 0, hour: 0, day: 0 };
|
|
2255
|
-
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
2256
2267
|
return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
2257
2268
|
const lim = draft.perMinute;
|
|
2258
2269
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
2259
2270
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
2260
2271
|
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
2261
|
-
const
|
|
2262
|
-
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 5 + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
2263
|
-
const burstBudget = Math.max(1, rows - fixed);
|
|
2264
|
-
const shown = anomalies2.slice(0, burstBudget);
|
|
2272
|
+
const shown = anomalies2.slice(off, off + burstBudget);
|
|
2265
2273
|
const bw = Math.max(10, cols - 30);
|
|
2266
2274
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", height: rows, overflow: "hidden", children: [
|
|
2267
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ?
|
|
2275
|
+
/* @__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${maxOff > 0 ? " \xB7 PgUp/PgDn bursts" : ""}` : "press \u2192 to edit" }),
|
|
2268
2276
|
/* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
|
|
2269
2277
|
/* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
|
|
2270
2278
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
|
|
@@ -2272,23 +2280,26 @@ function RateLimitPanel({ focused }) {
|
|
|
2272
2280
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per minute", active: focused && fi === 1, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perMinute || "off" }) }),
|
|
2273
2281
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour || "off" }) }),
|
|
2274
2282
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay || "off" }) }),
|
|
2275
|
-
|
|
2276
|
-
/* @__PURE__ */
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2283
|
+
showExtras && /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
2284
|
+
hasLoad ? /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2285
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load now".padEnd(13) }),
|
|
2286
|
+
/* @__PURE__ */ jsx4(Text4, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(18, Math.round(now / lim * 18))) }),
|
|
2287
|
+
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
|
|
2288
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
|
|
2289
|
+
] }) : null,
|
|
2290
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
2291
|
+
"Busiest 7d",
|
|
2292
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
2295
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
2296
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
2297
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` })
|
|
2284
2298
|
] }),
|
|
2285
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
2286
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
2287
|
-
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
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
2299
|
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
2290
2300
|
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
2291
2301
|
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
2302
|
+
maxOff > 0 ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: ` ${off + 1}-${Math.min(off + burstBudget, anomalies2.length)}/${anomalies2.length}` }) : null,
|
|
2292
2303
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
|
|
2293
2304
|
] }),
|
|
2294
2305
|
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
@@ -2307,6 +2318,7 @@ function RateLimitPanel({ focused }) {
|
|
|
2307
2318
|
}
|
|
2308
2319
|
)
|
|
2309
2320
|
] }),
|
|
2321
|
+
/* @__PURE__ */ jsx4(Text4, { children: " " }),
|
|
2310
2322
|
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2311
2323
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "limit now " }),
|
|
2312
2324
|
/* @__PURE__ */ jsx4(Text4, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
|
|
@@ -2362,7 +2374,7 @@ function DlpPanel({ focused }) {
|
|
|
2362
2374
|
}, [q.data]);
|
|
2363
2375
|
usePoll(() => {
|
|
2364
2376
|
if (!dirty && !adding) q.reloadQuiet();
|
|
2365
|
-
},
|
|
2377
|
+
}, 3e3);
|
|
2366
2378
|
const mutate = (next) => {
|
|
2367
2379
|
setDlp(next);
|
|
2368
2380
|
setDirty(true);
|
|
@@ -2404,7 +2416,7 @@ function DlpPanel({ focused }) {
|
|
|
2404
2416
|
if (!dlp) return;
|
|
2405
2417
|
if (key.ctrl && input2 === "r") {
|
|
2406
2418
|
q.reload();
|
|
2407
|
-
setStatus(
|
|
2419
|
+
setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
|
|
2408
2420
|
return;
|
|
2409
2421
|
}
|
|
2410
2422
|
if (key.upArrow) setSel(() => Math.max(0, selC - 1));
|
|
@@ -2812,7 +2824,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2812
2824
|
agentsQ.reload();
|
|
2813
2825
|
statsQ.reloadQuiet();
|
|
2814
2826
|
} else localQ.reload();
|
|
2815
|
-
setMsg({ text:
|
|
2827
|
+
setMsg({ text: `\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`, level: "ok" });
|
|
2816
2828
|
return;
|
|
2817
2829
|
}
|
|
2818
2830
|
if (showHelp) {
|
|
@@ -3588,7 +3600,7 @@ async function tuiUpdateFlow(onStatus) {
|
|
|
3588
3600
|
}
|
|
3589
3601
|
|
|
3590
3602
|
// src/tui/panels/Settings.tsx
|
|
3591
|
-
import { Fragment as
|
|
3603
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3592
3604
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3593
3605
|
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3594
3606
|
var SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
@@ -4075,11 +4087,11 @@ function SettingsPanel({
|
|
|
4075
4087
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
4076
4088
|
cursor(r),
|
|
4077
4089
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
4078
|
-
!guardHere ? /* @__PURE__ */ jsxs7(
|
|
4090
|
+
!guardHere ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
4079
4091
|
/* @__PURE__ */ jsx7(Text7, { color: theme.bad, bold: true, children: "removed" }),
|
|
4080
4092
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
4081
4093
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, children: "enter to install" })
|
|
4082
|
-
] }) : /* @__PURE__ */ jsxs7(
|
|
4094
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
4083
4095
|
/* @__PURE__ */ jsx7(Text7, { color: guardOld ? theme.warn : theme.ok, children: `v${guardVer ?? "?"}` }),
|
|
4084
4096
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guardOld ? " \xB7 update available \xB7 enter update" : " (latest) \xB7 enter reinstall" }),
|
|
4085
4097
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 d remove" })
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.96",
|
|
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": {
|