@solongate/proxy 0.81.88 → 0.81.90
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 +73 -34
- package/dist/tui/index.js +73 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8840,6 +8840,10 @@ function PoliciesPanel({ focused }) {
|
|
|
8840
8840
|
setRi(0);
|
|
8841
8841
|
}
|
|
8842
8842
|
}, [detail.data]);
|
|
8843
|
+
usePoll(() => {
|
|
8844
|
+
list6.reloadQuiet();
|
|
8845
|
+
activeQ.reloadQuiet();
|
|
8846
|
+
}, 6e3);
|
|
8843
8847
|
const mutate = (nextRules, nextMode = mode) => {
|
|
8844
8848
|
setRules(nextRules);
|
|
8845
8849
|
setMode(nextMode);
|
|
@@ -8876,6 +8880,13 @@ function PoliciesPanel({ focused }) {
|
|
|
8876
8880
|
};
|
|
8877
8881
|
useInput2(
|
|
8878
8882
|
(input, key) => {
|
|
8883
|
+
if (input === "r" && !editing) {
|
|
8884
|
+
list6.reload();
|
|
8885
|
+
activeQ.reload();
|
|
8886
|
+
detail.reload();
|
|
8887
|
+
setStatus("refreshed");
|
|
8888
|
+
return;
|
|
8889
|
+
}
|
|
8879
8890
|
if (view === "list") {
|
|
8880
8891
|
if (key.upArrow) setPi((n) => Math.max(0, n - 1));
|
|
8881
8892
|
else if (key.downArrow) setPi((n) => Math.min(policies.length - 1, n + 1));
|
|
@@ -8966,7 +8977,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8966
8977
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
8967
8978
|
] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
8968
8979
|
] }),
|
|
8969
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate
|
|
8980
|
+
/* @__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
8981
|
/* @__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
8982
|
(i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
|
|
8972
8983
|
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
@@ -9097,8 +9108,13 @@ function RateLimitPanel({ focused }) {
|
|
|
9097
9108
|
const [fi, setFi] = useState4(0);
|
|
9098
9109
|
const [status, setStatus] = useState4(null);
|
|
9099
9110
|
useEffect4(() => {
|
|
9100
|
-
if (layersQ.data && !
|
|
9101
|
-
}, [layersQ.data,
|
|
9111
|
+
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
9112
|
+
}, [layersQ.data, dirty]);
|
|
9113
|
+
usePoll(() => {
|
|
9114
|
+
if (!dirty) layersQ.reloadQuiet();
|
|
9115
|
+
historyQ.reloadQuiet();
|
|
9116
|
+
insightsQ.reloadQuiet();
|
|
9117
|
+
}, 6e3);
|
|
9102
9118
|
const adjust = (dir, step) => {
|
|
9103
9119
|
if (!draft) return;
|
|
9104
9120
|
const field = FIELDS2[fi];
|
|
@@ -9129,25 +9145,31 @@ function RateLimitPanel({ focused }) {
|
|
|
9129
9145
|
else if (key.leftArrow) adjust(-1, step);
|
|
9130
9146
|
else if (key.rightArrow) adjust(1, step);
|
|
9131
9147
|
else if (input === "s") void save();
|
|
9148
|
+
else if (input === "r") {
|
|
9149
|
+
layersQ.reload();
|
|
9150
|
+
historyQ.reload();
|
|
9151
|
+
insightsQ.reload();
|
|
9152
|
+
setStatus("refreshed");
|
|
9153
|
+
}
|
|
9132
9154
|
},
|
|
9133
9155
|
{ isActive: focused }
|
|
9134
9156
|
);
|
|
9135
9157
|
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
9136
9158
|
const lastChange = history[0];
|
|
9137
9159
|
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());
|
|
9160
|
+
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
9139
9161
|
return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
9140
9162
|
const lim = draft.perMinute;
|
|
9141
9163
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
9142
9164
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
9143
|
-
const
|
|
9165
|
+
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
9144
9166
|
const hasLoad = lim > 0;
|
|
9145
|
-
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
9167
|
+
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 5 + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
9146
9168
|
const burstBudget = Math.max(1, rows - fixed);
|
|
9147
9169
|
const shown = anomalies2.slice(0, burstBudget);
|
|
9148
9170
|
const bw = Math.max(10, cols - 30);
|
|
9149
9171
|
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" }),
|
|
9172
|
+
/* @__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
9173
|
/* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
|
|
9152
9174
|
/* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
|
|
9153
9175
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
|
|
@@ -9156,35 +9178,40 @@ function RateLimitPanel({ focused }) {
|
|
|
9156
9178
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour || "off" }) }),
|
|
9157
9179
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay || "off" }) }),
|
|
9158
9180
|
hasLoad ? /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9159
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load".padEnd(13) }),
|
|
9160
|
-
/* @__PURE__ */ jsx4(Text4, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(
|
|
9161
|
-
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0,
|
|
9181
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load now".padEnd(13) }),
|
|
9182
|
+
/* @__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))) }),
|
|
9183
|
+
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
|
|
9162
9184
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
|
|
9163
9185
|
] }) : null,
|
|
9164
|
-
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9165
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.accentBright, bold: true, children: "Busiest 7d " }),
|
|
9166
|
-
/* @__PURE__ */ jsx4(Text4, { color: peaks.minute > lim && lim > 0 ? theme.bad : theme.dim, children: `min ${peaks.minute}${peakFlag(peaks.minute)}` }),
|
|
9167
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` \xB7 hr ${peaks.hour} \xB7 day ${peaks.day}` })
|
|
9168
|
-
] }),
|
|
9169
9186
|
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9170
|
-
|
|
9171
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "
|
|
9187
|
+
"Busiest 7d",
|
|
9188
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
9189
|
+
] }),
|
|
9190
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
9191
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
9192
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
9193
|
+
/* @__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: [
|
|
9195
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9196
|
+
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
9197
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
|
|
9198
|
+
] }),
|
|
9199
|
+
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
9200
|
+
" ",
|
|
9201
|
+
insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
|
|
9202
|
+
] }) : /* @__PURE__ */ jsx4(
|
|
9203
|
+
Table,
|
|
9204
|
+
{
|
|
9205
|
+
columns: [{ header: "WHEN", width: 13 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 29) }],
|
|
9206
|
+
rows: shown.map((a) => [
|
|
9207
|
+
{ value: when(new Date(a.minute).getTime()), dim: true },
|
|
9208
|
+
{ value: a.blocked ? "Blocked" : "Bypassed", color: a.blocked ? theme.bad : theme.warn },
|
|
9209
|
+
{ value: `${a.count}/${a.limit}`, color: theme.warn },
|
|
9210
|
+
{ value: truncate2(a.agent, Math.max(8, bw - 29)), dim: true }
|
|
9211
|
+
])
|
|
9212
|
+
}
|
|
9213
|
+
)
|
|
9172
9214
|
] }),
|
|
9173
|
-
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
9174
|
-
" ",
|
|
9175
|
-
insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
|
|
9176
|
-
] }) : /* @__PURE__ */ jsx4(
|
|
9177
|
-
Table,
|
|
9178
|
-
{
|
|
9179
|
-
columns: [{ header: "WHEN", width: 13 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 29) }],
|
|
9180
|
-
rows: shown.map((a) => [
|
|
9181
|
-
{ value: when(new Date(a.minute).getTime()), dim: true },
|
|
9182
|
-
{ value: a.blocked ? "Blocked" : "Bypassed", color: a.blocked ? theme.bad : theme.warn },
|
|
9183
|
-
{ value: `${a.count}/${a.limit}`, color: theme.warn },
|
|
9184
|
-
{ value: truncate2(a.agent, Math.max(8, bw - 29)), dim: true }
|
|
9185
|
-
])
|
|
9186
|
-
}
|
|
9187
|
-
),
|
|
9188
9215
|
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9189
9216
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "limit now " }),
|
|
9190
9217
|
/* @__PURE__ */ jsx4(Text4, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
|
|
@@ -9195,6 +9222,15 @@ function RateLimitPanel({ focused }) {
|
|
|
9195
9222
|
] });
|
|
9196
9223
|
})() : null });
|
|
9197
9224
|
}
|
|
9225
|
+
function BusiestRow({ label, peak, limit }) {
|
|
9226
|
+
const ctx = limit > 0 ? peak > limit ? `over ${limit}` : peak === limit ? `at limit ${limit}` : `limit ${limit}` : "no limit set";
|
|
9227
|
+
const hot = limit > 0 && peak > limit;
|
|
9228
|
+
return /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9229
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: (" " + label).padEnd(11) }),
|
|
9230
|
+
/* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : void 0, bold: hot, children: String(peak).padStart(4) + " calls" }),
|
|
9231
|
+
/* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : theme.dim, children: " \xB7 " + ctx })
|
|
9232
|
+
] });
|
|
9233
|
+
}
|
|
9198
9234
|
function FieldRow({ label, active: active2, children }) {
|
|
9199
9235
|
return /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
9200
9236
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + label.padEnd(11) }),
|
|
@@ -9237,13 +9273,16 @@ function DlpPanel({ focused }) {
|
|
|
9237
9273
|
const [newName, setNewName] = useState5("");
|
|
9238
9274
|
const [input, setInput] = useState5("");
|
|
9239
9275
|
useEffect5(() => {
|
|
9240
|
-
if (q.data && !
|
|
9276
|
+
if (q.data && !dirty) {
|
|
9241
9277
|
setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
|
|
9242
9278
|
setAvailable(q.data.availablePatterns);
|
|
9243
9279
|
setGhostOn(q.data.layers.ghost.mode === "on");
|
|
9244
9280
|
setGhostPats([...q.data.layers.ghost.patterns]);
|
|
9245
9281
|
}
|
|
9246
|
-
}, [q.data,
|
|
9282
|
+
}, [q.data, dirty]);
|
|
9283
|
+
usePoll(() => {
|
|
9284
|
+
if (!dirty && !adding) q.reloadQuiet();
|
|
9285
|
+
}, 6e3);
|
|
9247
9286
|
const mutate = (next) => {
|
|
9248
9287
|
setDlp(next);
|
|
9249
9288
|
setDirty(true);
|
package/dist/tui/index.js
CHANGED
|
@@ -1958,6 +1958,10 @@ function PoliciesPanel({ focused }) {
|
|
|
1958
1958
|
setRi(0);
|
|
1959
1959
|
}
|
|
1960
1960
|
}, [detail.data]);
|
|
1961
|
+
usePoll(() => {
|
|
1962
|
+
list5.reloadQuiet();
|
|
1963
|
+
activeQ.reloadQuiet();
|
|
1964
|
+
}, 6e3);
|
|
1961
1965
|
const mutate = (nextRules, nextMode = mode) => {
|
|
1962
1966
|
setRules(nextRules);
|
|
1963
1967
|
setMode(nextMode);
|
|
@@ -1994,6 +1998,13 @@ function PoliciesPanel({ focused }) {
|
|
|
1994
1998
|
};
|
|
1995
1999
|
useInput2(
|
|
1996
2000
|
(input, key) => {
|
|
2001
|
+
if (input === "r" && !editing) {
|
|
2002
|
+
list5.reload();
|
|
2003
|
+
activeQ.reload();
|
|
2004
|
+
detail.reload();
|
|
2005
|
+
setStatus("refreshed");
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
1997
2008
|
if (view === "list") {
|
|
1998
2009
|
if (key.upArrow) setPi((n) => Math.max(0, n - 1));
|
|
1999
2010
|
else if (key.downArrow) setPi((n) => Math.min(policies.length - 1, n + 1));
|
|
@@ -2084,7 +2095,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2084
2095
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
2085
2096
|
] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
2086
2097
|
] }),
|
|
2087
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate
|
|
2098
|
+
/* @__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
2099
|
/* @__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
2100
|
(i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
|
|
2090
2101
|
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
@@ -2190,8 +2201,13 @@ function RateLimitPanel({ focused }) {
|
|
|
2190
2201
|
const [fi, setFi] = useState4(0);
|
|
2191
2202
|
const [status, setStatus] = useState4(null);
|
|
2192
2203
|
useEffect4(() => {
|
|
2193
|
-
if (layersQ.data && !
|
|
2194
|
-
}, [layersQ.data,
|
|
2204
|
+
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
2205
|
+
}, [layersQ.data, dirty]);
|
|
2206
|
+
usePoll(() => {
|
|
2207
|
+
if (!dirty) layersQ.reloadQuiet();
|
|
2208
|
+
historyQ.reloadQuiet();
|
|
2209
|
+
insightsQ.reloadQuiet();
|
|
2210
|
+
}, 6e3);
|
|
2195
2211
|
const adjust = (dir, step) => {
|
|
2196
2212
|
if (!draft) return;
|
|
2197
2213
|
const field = FIELDS2[fi];
|
|
@@ -2222,25 +2238,31 @@ function RateLimitPanel({ focused }) {
|
|
|
2222
2238
|
else if (key.leftArrow) adjust(-1, step);
|
|
2223
2239
|
else if (key.rightArrow) adjust(1, step);
|
|
2224
2240
|
else if (input === "s") void save();
|
|
2241
|
+
else if (input === "r") {
|
|
2242
|
+
layersQ.reload();
|
|
2243
|
+
historyQ.reload();
|
|
2244
|
+
insightsQ.reload();
|
|
2245
|
+
setStatus("refreshed");
|
|
2246
|
+
}
|
|
2225
2247
|
},
|
|
2226
2248
|
{ isActive: focused }
|
|
2227
2249
|
);
|
|
2228
2250
|
const history = (historyQ.data?.history ?? []).slice().sort((a, b) => b.ts - a.ts);
|
|
2229
2251
|
const lastChange = history[0];
|
|
2230
2252
|
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());
|
|
2253
|
+
const anomalies2 = (insightsQ.data?.["anomalies"] ?? []).slice().sort((a, b) => b.count - a.count || new Date(b.minute).getTime() - new Date(a.minute).getTime());
|
|
2232
2254
|
return /* @__PURE__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
2233
2255
|
const lim = draft.perMinute;
|
|
2234
2256
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
2235
2257
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
2236
|
-
const
|
|
2258
|
+
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
2237
2259
|
const hasLoad = lim > 0;
|
|
2238
|
-
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
2260
|
+
const fixed = 1 + 4 + (hasLoad ? 1 : 0) + 5 + 1 + 1 + 1 + 1 + (dirty || status ? 1 : 0) + 1;
|
|
2239
2261
|
const burstBudget = Math.max(1, rows - fixed);
|
|
2240
2262
|
const shown = anomalies2.slice(0, burstBudget);
|
|
2241
2263
|
const bw = Math.max(10, cols - 30);
|
|
2242
2264
|
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" }),
|
|
2265
|
+
/* @__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
2266
|
/* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
|
|
2245
2267
|
/* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
|
|
2246
2268
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
|
|
@@ -2249,35 +2271,40 @@ function RateLimitPanel({ focused }) {
|
|
|
2249
2271
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour || "off" }) }),
|
|
2250
2272
|
/* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay || "off" }) }),
|
|
2251
2273
|
hasLoad ? /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2252
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load".padEnd(13) }),
|
|
2253
|
-
/* @__PURE__ */ jsx4(Text4, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(
|
|
2254
|
-
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0,
|
|
2274
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load now".padEnd(13) }),
|
|
2275
|
+
/* @__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))) }),
|
|
2276
|
+
/* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
|
|
2255
2277
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
|
|
2256
2278
|
] }) : null,
|
|
2257
|
-
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2258
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.accentBright, bold: true, children: "Busiest 7d " }),
|
|
2259
|
-
/* @__PURE__ */ jsx4(Text4, { color: peaks.minute > lim && lim > 0 ? theme.bad : theme.dim, children: `min ${peaks.minute}${peakFlag(peaks.minute)}` }),
|
|
2260
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` \xB7 hr ${peaks.hour} \xB7 day ${peaks.day}` })
|
|
2261
|
-
] }),
|
|
2262
2279
|
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
2263
|
-
|
|
2264
|
-
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "
|
|
2280
|
+
"Busiest 7d",
|
|
2281
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
2282
|
+
] }),
|
|
2283
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
2284
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
2285
|
+
/* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
2286
|
+
/* @__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: [
|
|
2288
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
2289
|
+
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
2290
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
|
|
2291
|
+
] }),
|
|
2292
|
+
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
2293
|
+
" ",
|
|
2294
|
+
insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
|
|
2295
|
+
] }) : /* @__PURE__ */ jsx4(
|
|
2296
|
+
Table,
|
|
2297
|
+
{
|
|
2298
|
+
columns: [{ header: "WHEN", width: 13 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 29) }],
|
|
2299
|
+
rows: shown.map((a) => [
|
|
2300
|
+
{ value: when(new Date(a.minute).getTime()), dim: true },
|
|
2301
|
+
{ value: a.blocked ? "Blocked" : "Bypassed", color: a.blocked ? theme.bad : theme.warn },
|
|
2302
|
+
{ value: `${a.count}/${a.limit}`, color: theme.warn },
|
|
2303
|
+
{ value: truncate(a.agent, Math.max(8, bw - 29)), dim: true }
|
|
2304
|
+
])
|
|
2305
|
+
}
|
|
2306
|
+
)
|
|
2265
2307
|
] }),
|
|
2266
|
-
anomalies2.length === 0 ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
2267
|
-
" ",
|
|
2268
|
-
insightsQ.loading ? "loading\u2026" : "no bursts in the last 7 days"
|
|
2269
|
-
] }) : /* @__PURE__ */ jsx4(
|
|
2270
|
-
Table,
|
|
2271
|
-
{
|
|
2272
|
-
columns: [{ header: "WHEN", width: 13 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 29) }],
|
|
2273
|
-
rows: shown.map((a) => [
|
|
2274
|
-
{ value: when(new Date(a.minute).getTime()), dim: true },
|
|
2275
|
-
{ value: a.blocked ? "Blocked" : "Bypassed", color: a.blocked ? theme.bad : theme.warn },
|
|
2276
|
-
{ value: `${a.count}/${a.limit}`, color: theme.warn },
|
|
2277
|
-
{ value: truncate(a.agent, Math.max(8, bw - 29)), dim: true }
|
|
2278
|
-
])
|
|
2279
|
-
}
|
|
2280
|
-
),
|
|
2281
2308
|
/* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2282
2309
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "limit now " }),
|
|
2283
2310
|
/* @__PURE__ */ jsx4(Text4, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
|
|
@@ -2288,6 +2315,15 @@ function RateLimitPanel({ focused }) {
|
|
|
2288
2315
|
] });
|
|
2289
2316
|
})() : null });
|
|
2290
2317
|
}
|
|
2318
|
+
function BusiestRow({ label, peak, limit }) {
|
|
2319
|
+
const ctx = limit > 0 ? peak > limit ? `over ${limit}` : peak === limit ? `at limit ${limit}` : `limit ${limit}` : "no limit set";
|
|
2320
|
+
const hot = limit > 0 && peak > limit;
|
|
2321
|
+
return /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2322
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: (" " + label).padEnd(11) }),
|
|
2323
|
+
/* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : void 0, bold: hot, children: String(peak).padStart(4) + " calls" }),
|
|
2324
|
+
/* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : theme.dim, children: " \xB7 " + ctx })
|
|
2325
|
+
] });
|
|
2326
|
+
}
|
|
2291
2327
|
function FieldRow({ label, active: active2, children }) {
|
|
2292
2328
|
return /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
|
|
2293
2329
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + label.padEnd(11) }),
|
|
@@ -2315,13 +2351,16 @@ function DlpPanel({ focused }) {
|
|
|
2315
2351
|
const [newName, setNewName] = useState5("");
|
|
2316
2352
|
const [input, setInput] = useState5("");
|
|
2317
2353
|
useEffect5(() => {
|
|
2318
|
-
if (q.data && !
|
|
2354
|
+
if (q.data && !dirty) {
|
|
2319
2355
|
setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
|
|
2320
2356
|
setAvailable(q.data.availablePatterns);
|
|
2321
2357
|
setGhostOn(q.data.layers.ghost.mode === "on");
|
|
2322
2358
|
setGhostPats([...q.data.layers.ghost.patterns]);
|
|
2323
2359
|
}
|
|
2324
|
-
}, [q.data,
|
|
2360
|
+
}, [q.data, dirty]);
|
|
2361
|
+
usePoll(() => {
|
|
2362
|
+
if (!dirty && !adding) q.reloadQuiet();
|
|
2363
|
+
}, 6e3);
|
|
2325
2364
|
const mutate = (next) => {
|
|
2326
2365
|
setDlp(next);
|
|
2327
2366
|
setDirty(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.90",
|
|
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": {
|