@solongate/proxy 0.81.55 → 0.81.57
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/api-client/client.d.ts +2 -0
- package/dist/api-client/settings.d.ts +15 -0
- package/dist/commands/index.js +8 -0
- package/dist/index.js +362 -168
- package/dist/tui/index.js +361 -167
- package/package.json +1 -1
package/dist/tui/index.js
CHANGED
|
@@ -283,6 +283,20 @@ function saveAccount(acc) {
|
|
|
283
283
|
} catch {
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
+
function removeAccount(apiKey) {
|
|
287
|
+
try {
|
|
288
|
+
const list5 = (() => {
|
|
289
|
+
try {
|
|
290
|
+
const raw = JSON.parse(readFileSync3(accountsFile(), "utf-8"));
|
|
291
|
+
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
292
|
+
} catch {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
})();
|
|
296
|
+
writeFileSync2(accountsFile(), JSON.stringify(list5.filter((a) => a.apiKey !== apiKey), null, 2));
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
}
|
|
286
300
|
var viewOverride = null;
|
|
287
301
|
function setViewCredentials(creds) {
|
|
288
302
|
viewOverride = creds;
|
|
@@ -550,11 +564,13 @@ __export(settings_exports, {
|
|
|
550
564
|
getSecurityLayers: () => getSecurityLayers,
|
|
551
565
|
getSelfProtection: () => getSelfProtection,
|
|
552
566
|
getWebhooks: () => getWebhooks,
|
|
567
|
+
sendTestAlert: () => sendTestAlert,
|
|
553
568
|
sendTestWebhook: () => sendTestWebhook,
|
|
554
569
|
setAlertEnabled: () => setAlertEnabled,
|
|
555
570
|
setLocalLogs: () => setLocalLogs,
|
|
556
571
|
setSecurityLayers: () => setSecurityLayers,
|
|
557
572
|
setSelfProtection: () => setSelfProtection,
|
|
573
|
+
updateAlert: () => updateAlert,
|
|
558
574
|
updateWebhook: () => updateWebhook
|
|
559
575
|
});
|
|
560
576
|
function getSecurityLayers() {
|
|
@@ -596,6 +612,12 @@ function deleteAlert(id) {
|
|
|
596
612
|
function setAlertEnabled(id, enabled) {
|
|
597
613
|
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
598
614
|
}
|
|
615
|
+
function updateAlert(id, patch) {
|
|
616
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: patch });
|
|
617
|
+
}
|
|
618
|
+
function sendTestAlert(id) {
|
|
619
|
+
return request("POST", "/settings/denial-alerts/send-test", { body: { id } });
|
|
620
|
+
}
|
|
599
621
|
function getWebhooks() {
|
|
600
622
|
return request("GET", "/settings/denial-webhook");
|
|
601
623
|
}
|
|
@@ -3175,8 +3197,20 @@ function stopLogsServerDaemon() {
|
|
|
3175
3197
|
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3176
3198
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3177
3199
|
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3178
|
-
var
|
|
3200
|
+
var SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
3201
|
+
var SIGNAL_LABEL = { any: "any signal", deny: "denials", dlp: "dlp secrets", ratelimit: "rate-limit" };
|
|
3202
|
+
var WINDOWS = [30, 60, 300, 3600, 86400];
|
|
3203
|
+
var winLabel = (s) => s < 60 ? `${s}s` : s < 3600 ? `${s / 60}m` : s < 86400 ? `${s / 3600}h` : `${s / 86400}d`;
|
|
3204
|
+
var THRESH_MIN = 5;
|
|
3205
|
+
var THRESH_MAX = 100;
|
|
3206
|
+
var nearestWindowIdx = (s) => {
|
|
3207
|
+
let best = 0;
|
|
3208
|
+
for (let i = 1; i < WINDOWS.length; i++) if (Math.abs(WINDOWS[i] - s) < Math.abs(WINDOWS[best] - s)) best = i;
|
|
3209
|
+
return best;
|
|
3210
|
+
};
|
|
3211
|
+
var EDITOR_FIELDS = 4;
|
|
3179
3212
|
var acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
|
|
3213
|
+
var alertChannel = (r) => r.emails && r.emails.length ? "email" : r.telegram && r.telegram.length ? "telegram" : null;
|
|
3180
3214
|
function SettingsPanel({
|
|
3181
3215
|
active: active2,
|
|
3182
3216
|
focused,
|
|
@@ -3191,6 +3225,7 @@ function SettingsPanel({
|
|
|
3191
3225
|
const [confirmDel, setConfirmDel] = useState7(null);
|
|
3192
3226
|
const [msg, setMsg] = useState7(null);
|
|
3193
3227
|
const [busy, setBusy] = useState7(false);
|
|
3228
|
+
const [editor, setEditor] = useState7(null);
|
|
3194
3229
|
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
3195
3230
|
const [login, setLogin] = useState7(null);
|
|
3196
3231
|
const [tick, setTick] = useState7(0);
|
|
@@ -3210,22 +3245,30 @@ function SettingsPanel({
|
|
|
3210
3245
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
3211
3246
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
3212
3247
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
3248
|
+
const guardQ = useLoader(() => listAccounts().length ? api.settings.getGuardStatus() : Promise.resolve(null));
|
|
3249
|
+
const selfQ = useLoader(() => listAccounts().length ? api.settings.getSelfProtection() : Promise.resolve(null));
|
|
3213
3250
|
const local = localQ.data;
|
|
3251
|
+
const guard = guardQ.data;
|
|
3252
|
+
const selfProt = selfQ.data;
|
|
3214
3253
|
const [hidden, setHidden] = useState7(/* @__PURE__ */ new Set());
|
|
3215
3254
|
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
3216
3255
|
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
3256
|
+
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
3257
|
+
const hasTgAlert = alerts.some((r) => alertChannel(r) === "telegram");
|
|
3217
3258
|
const rowsAll = [
|
|
3218
3259
|
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
3219
3260
|
{ kind: "acct-add" },
|
|
3220
3261
|
...locked ? [] : [
|
|
3262
|
+
{ kind: "guard" },
|
|
3263
|
+
{ kind: "self" },
|
|
3221
3264
|
{ kind: "ll-enabled" },
|
|
3222
3265
|
{ kind: "ll-path" },
|
|
3223
3266
|
{ kind: "ll-server" },
|
|
3224
3267
|
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
3225
3268
|
{ kind: "wh-add" },
|
|
3226
3269
|
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
3227
|
-
{ kind: "alert-add-email" },
|
|
3228
|
-
{ kind: "alert-add-tg" }
|
|
3270
|
+
...hasEmailAlert ? [] : [{ kind: "alert-add-email" }],
|
|
3271
|
+
...hasTgAlert ? [] : [{ kind: "alert-add-tg" }]
|
|
3229
3272
|
]
|
|
3230
3273
|
];
|
|
3231
3274
|
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
@@ -3236,6 +3279,8 @@ function SettingsPanel({
|
|
|
3236
3279
|
localQ.reload();
|
|
3237
3280
|
whQ.reload();
|
|
3238
3281
|
alertQ.reload();
|
|
3282
|
+
guardQ.reload();
|
|
3283
|
+
selfQ.reload();
|
|
3239
3284
|
};
|
|
3240
3285
|
const run = (label, fn, reload) => {
|
|
3241
3286
|
if (busy) return;
|
|
@@ -3251,19 +3296,19 @@ function SettingsPanel({
|
|
|
3251
3296
|
abort.current = false;
|
|
3252
3297
|
setLogin({ phase: "starting" });
|
|
3253
3298
|
void (async () => {
|
|
3254
|
-
let
|
|
3299
|
+
let start;
|
|
3255
3300
|
try {
|
|
3256
|
-
|
|
3301
|
+
start = await startDeviceLogin(DEFAULT_API_URL);
|
|
3257
3302
|
} catch (e) {
|
|
3258
3303
|
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
3259
3304
|
return;
|
|
3260
3305
|
}
|
|
3261
|
-
setLogin({ phase: "waiting", url:
|
|
3262
|
-
openBrowser(
|
|
3263
|
-
while (Date.now() <
|
|
3264
|
-
await new Promise((r) => setTimeout(r,
|
|
3306
|
+
setLogin({ phase: "waiting", url: start.verifyUrl });
|
|
3307
|
+
openBrowser(start.verifyUrl);
|
|
3308
|
+
while (Date.now() < start.expiresAt && !abort.current) {
|
|
3309
|
+
await new Promise((r) => setTimeout(r, start.intervalMs));
|
|
3265
3310
|
if (abort.current) return;
|
|
3266
|
-
const res = await pollDeviceLogin(DEFAULT_API_URL,
|
|
3311
|
+
const res = await pollDeviceLogin(DEFAULT_API_URL, start.deviceCode);
|
|
3267
3312
|
if (res.status === "approved" && res.apiKey) {
|
|
3268
3313
|
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user, email: res.email });
|
|
3269
3314
|
setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
|
|
@@ -3280,6 +3325,57 @@ function SettingsPanel({
|
|
|
3280
3325
|
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
3281
3326
|
})();
|
|
3282
3327
|
};
|
|
3328
|
+
const openAlertEditor = (channel, rule) => {
|
|
3329
|
+
setEditor({
|
|
3330
|
+
id: rule?.id,
|
|
3331
|
+
channel,
|
|
3332
|
+
target: (channel === "email" ? rule?.emails?.[0] : rule?.telegram?.[0]) ?? "",
|
|
3333
|
+
signal: rule?.signal ?? "any",
|
|
3334
|
+
threshold: rule?.threshold ?? THRESH_MIN,
|
|
3335
|
+
windowSeconds: rule?.windowSeconds ?? 300,
|
|
3336
|
+
field: rule ? 1 : 0
|
|
3337
|
+
// new rule starts on the target; existing on signal
|
|
3338
|
+
});
|
|
3339
|
+
if (!rule) {
|
|
3340
|
+
setInput("");
|
|
3341
|
+
setEditing("alert-target");
|
|
3342
|
+
}
|
|
3343
|
+
};
|
|
3344
|
+
const normTarget = (channel, raw) => {
|
|
3345
|
+
const v = raw.trim();
|
|
3346
|
+
if (channel === "email") {
|
|
3347
|
+
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "");
|
|
3348
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return { value: email, error: "that does not look like an e-mail address" };
|
|
3349
|
+
return { value: email };
|
|
3350
|
+
}
|
|
3351
|
+
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "");
|
|
3352
|
+
if (!/^-?\d{5,}$/.test(tg)) return { value: tg, error: "a telegram chat id is a number \u2014 get yours from @userinfobot" };
|
|
3353
|
+
return { value: tg };
|
|
3354
|
+
};
|
|
3355
|
+
const saveEditor = () => {
|
|
3356
|
+
if (!editor) return;
|
|
3357
|
+
const t = normTarget(editor.channel, editor.target);
|
|
3358
|
+
if (t.error) {
|
|
3359
|
+
setMsg({ text: "\u2717 " + t.error, level: "bad" });
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
const channels = editor.channel === "email" ? { emails: [t.value], telegram: [] } : { telegram: [t.value], emails: [] };
|
|
3363
|
+
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, ...channels };
|
|
3364
|
+
const id = editor.id;
|
|
3365
|
+
setEditor(null);
|
|
3366
|
+
if (id) run("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
3367
|
+
else run(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "dataroom alert", ...body }), alertQ.reload);
|
|
3368
|
+
};
|
|
3369
|
+
const testAlert = (rule) => {
|
|
3370
|
+
run(
|
|
3371
|
+
"alert test sent \u2014 check your " + (alertChannel(rule) ?? "channel"),
|
|
3372
|
+
() => api.settings.sendTestAlert(rule.id).then((r) => {
|
|
3373
|
+
if (!r.delivered.telegram && !r.delivered.email) throw new Error("no channel on this rule");
|
|
3374
|
+
}),
|
|
3375
|
+
() => {
|
|
3376
|
+
}
|
|
3377
|
+
);
|
|
3378
|
+
};
|
|
3283
3379
|
const activate = (r) => {
|
|
3284
3380
|
if (r.kind === "acct") {
|
|
3285
3381
|
setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
|
|
@@ -3287,6 +3383,9 @@ function SettingsPanel({
|
|
|
3287
3383
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
3288
3384
|
} else if (r.kind === "acct-add") {
|
|
3289
3385
|
beginLogin();
|
|
3386
|
+
} else if (r.kind === "self") {
|
|
3387
|
+
if (!selfProt) return;
|
|
3388
|
+
run(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
3290
3389
|
} else if (r.kind === "ll-enabled") {
|
|
3291
3390
|
if (!local) return;
|
|
3292
3391
|
if (!local.enabled && !local.path.trim()) {
|
|
@@ -3309,13 +3408,12 @@ function SettingsPanel({
|
|
|
3309
3408
|
setInput("");
|
|
3310
3409
|
setEditing("wh-url");
|
|
3311
3410
|
} else if (r.kind === "alert") {
|
|
3312
|
-
|
|
3411
|
+
const ch = alertChannel(r.rule);
|
|
3412
|
+
if (ch) openAlertEditor(ch, r.rule);
|
|
3313
3413
|
} else if (r.kind === "alert-add-email") {
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
setInput("");
|
|
3318
|
-
setEditing("alert-tg");
|
|
3414
|
+
openAlertEditor("email");
|
|
3415
|
+
} else if (r.kind === "alert-add-tg") {
|
|
3416
|
+
openAlertEditor("telegram");
|
|
3319
3417
|
}
|
|
3320
3418
|
};
|
|
3321
3419
|
const submitInput = () => {
|
|
@@ -3333,22 +3431,8 @@ function SettingsPanel({
|
|
|
3333
3431
|
return;
|
|
3334
3432
|
}
|
|
3335
3433
|
run("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
3336
|
-
} else if (which === "alert-
|
|
3337
|
-
|
|
3338
|
-
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "").trim();
|
|
3339
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
3340
|
-
setMsg({ text: "\u2717 that does not look like an e-mail address", level: "bad" });
|
|
3341
|
-
return;
|
|
3342
|
-
}
|
|
3343
|
-
run("email alert added", () => api.settings.createAlert({ ...ALERT_BASE, emails: [email] }), alertQ.reload);
|
|
3344
|
-
} else if (which === "alert-tg") {
|
|
3345
|
-
if (!v) return;
|
|
3346
|
-
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "").trim();
|
|
3347
|
-
if (!/^-?\d{5,}$/.test(tg)) {
|
|
3348
|
-
setMsg({ text: "\u2717 a telegram chat id is a number \u2014 get yours from @userinfobot", level: "bad" });
|
|
3349
|
-
return;
|
|
3350
|
-
}
|
|
3351
|
-
run("telegram alert added", () => api.settings.createAlert({ ...ALERT_BASE, telegram: [tg] }), alertQ.reload);
|
|
3434
|
+
} else if (which === "alert-target" && editor) {
|
|
3435
|
+
setEditor({ ...editor, target: v, field: 1 });
|
|
3352
3436
|
}
|
|
3353
3437
|
};
|
|
3354
3438
|
useInput6(
|
|
@@ -3360,6 +3444,35 @@ function SettingsPanel({
|
|
|
3360
3444
|
}
|
|
3361
3445
|
return;
|
|
3362
3446
|
}
|
|
3447
|
+
if (editor) {
|
|
3448
|
+
if (key.escape) {
|
|
3449
|
+
setEditor(null);
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
if (inp === "e" || key.return && editor.field === 0) {
|
|
3453
|
+
setInput(editor.target);
|
|
3454
|
+
setEditing("alert-target");
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
if (inp === "t" && editor.id) {
|
|
3458
|
+
const rule = alerts.find((a) => a.id === editor.id);
|
|
3459
|
+
if (rule) testAlert(rule);
|
|
3460
|
+
return;
|
|
3461
|
+
}
|
|
3462
|
+
if (key.return) {
|
|
3463
|
+
saveEditor();
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
if (key.upArrow) setEditor({ ...editor, field: (editor.field + EDITOR_FIELDS - 1) % EDITOR_FIELDS });
|
|
3467
|
+
else if (key.downArrow) setEditor({ ...editor, field: (editor.field + 1) % EDITOR_FIELDS });
|
|
3468
|
+
else if (key.leftArrow || key.rightArrow) {
|
|
3469
|
+
const d = key.rightArrow ? 1 : -1;
|
|
3470
|
+
if (editor.field === 1) setEditor({ ...editor, signal: SIGNALS2[(SIGNALS2.indexOf(editor.signal) + d + SIGNALS2.length) % SIGNALS2.length] });
|
|
3471
|
+
else if (editor.field === 2) setEditor({ ...editor, threshold: Math.max(THRESH_MIN, Math.min(THRESH_MAX, editor.threshold + d * 5)) });
|
|
3472
|
+
else if (editor.field === 3) setEditor({ ...editor, windowSeconds: WINDOWS[Math.max(0, Math.min(WINDOWS.length - 1, nearestWindowIdx(editor.windowSeconds) + d))] });
|
|
3473
|
+
}
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3363
3476
|
setMsg(null);
|
|
3364
3477
|
if (key.upArrow) {
|
|
3365
3478
|
setSel((n) => Math.max(0, n - 1));
|
|
@@ -3373,28 +3486,41 @@ function SettingsPanel({
|
|
|
3373
3486
|
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
3374
3487
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
3375
3488
|
refreshAccounts();
|
|
3376
|
-
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "ll-enabled" || cur.kind === "ll-server")
|
|
3489
|
+
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
3490
|
+
if (cur.kind === "alert") run(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
3491
|
+
else activate(cur);
|
|
3492
|
+
}
|
|
3493
|
+
} else if (inp === "x" && cur.kind === "acct") {
|
|
3494
|
+
const k = "acct:" + cur.acc.apiKey;
|
|
3495
|
+
if (confirmDel !== k) {
|
|
3496
|
+
setConfirmDel(k);
|
|
3497
|
+
setMsg({ text: `press x again to remove ${acctLabel(cur.acc)} from this device (the cloud account is untouched)`, level: "bad" });
|
|
3498
|
+
return;
|
|
3499
|
+
}
|
|
3500
|
+
setConfirmDel(null);
|
|
3501
|
+
removeAccount(cur.acc.apiKey);
|
|
3502
|
+
setMsg({ text: `\u2713 removed ${acctLabel(cur.acc)} from this device`, level: "ok" });
|
|
3503
|
+
refreshAccounts();
|
|
3377
3504
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
3378
|
-
run(
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
);
|
|
3385
|
-
} else if (inp === "n") beginLogin();
|
|
3505
|
+
run("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
3506
|
+
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
3507
|
+
}), whQ.reload);
|
|
3508
|
+
} else if (inp === "t" && cur.kind === "alert") {
|
|
3509
|
+
testAlert(cur.rule);
|
|
3510
|
+
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
3386
3511
|
else if (inp === "e" && cur.kind === "wh") {
|
|
3387
3512
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
3388
3513
|
run(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
3389
|
-
} else if (inp === "e" && cur.kind === "
|
|
3514
|
+
} else if (inp === "e" && cur.kind === "alert") {
|
|
3515
|
+
const ch = alertChannel(cur.rule);
|
|
3516
|
+
if (ch) openAlertEditor(ch, cur.rule);
|
|
3517
|
+
} else if (inp === "n") beginLogin();
|
|
3390
3518
|
else if (inp === "a") {
|
|
3391
3519
|
if (cur.kind === "wh" || cur.kind === "wh-add") {
|
|
3392
3520
|
setInput("");
|
|
3393
3521
|
setEditing("wh-url");
|
|
3394
|
-
} else if (cur.kind === "alert
|
|
3395
|
-
|
|
3396
|
-
setEditing("alert-email");
|
|
3397
|
-
}
|
|
3522
|
+
} else if (cur.kind === "alert-add-email") openAlertEditor("email");
|
|
3523
|
+
else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
|
|
3398
3524
|
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
3399
3525
|
const k = keyOf(cur);
|
|
3400
3526
|
if (confirmDel !== k) {
|
|
@@ -3434,123 +3560,186 @@ function SettingsPanel({
|
|
|
3434
3560
|
] })
|
|
3435
3561
|
] });
|
|
3436
3562
|
}
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
3446
|
-
return i >= start && i < start + listBudget;
|
|
3447
|
-
};
|
|
3448
|
-
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3449
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter/m act \xB7 t test webhook \xB7 n add account \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
|
|
3450
|
-
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3451
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : editing === "alert-email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
3452
|
-
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3453
|
-
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3454
|
-
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3563
|
+
if (editor) {
|
|
3564
|
+
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3565
|
+
/* @__PURE__ */ jsx7(Text7, { color: editor.field === idx ? theme.accentBright : theme.dim, children: editor.field === idx ? "\u25B8 " : " " }),
|
|
3566
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(11) }),
|
|
3567
|
+
value,
|
|
3568
|
+
editor.field === idx && hint ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + hint }) : null
|
|
3569
|
+
] });
|
|
3570
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3455
3571
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3456
|
-
"
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
") \xB7 \u25CF viewing = shown here \xB7 ACTIVE = key the guard uses"
|
|
3461
|
-
] })
|
|
3572
|
+
editor.id ? "Edit" : "New",
|
|
3573
|
+
" ",
|
|
3574
|
+
editor.channel,
|
|
3575
|
+
" alert"
|
|
3462
3576
|
] }),
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
] })
|
|
3468
|
-
|
|
3577
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3578
|
+
"\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save",
|
|
3579
|
+
editor.id ? " \xB7 t test" : "",
|
|
3580
|
+
" \xB7 esc cancel"
|
|
3581
|
+
] }),
|
|
3582
|
+
editing === "alert-target" ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
3583
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
3584
|
+
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3585
|
+
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3586
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3587
|
+
fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(editor.target, cols - 16) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
|
|
3588
|
+
fieldRow(1, "signal", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }), "\u2190\u2192 change"),
|
|
3589
|
+
fieldRow(2, "threshold", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: `\u2265 ${editor.threshold}` }), "\u2190\u2192 \xB15"),
|
|
3590
|
+
fieldRow(3, "window", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) }), "\u2190\u2192 change")
|
|
3591
|
+
] }),
|
|
3592
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3593
|
+
"fires when ",
|
|
3594
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
|
|
3595
|
+
" reach ",
|
|
3596
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: editor.threshold }),
|
|
3597
|
+
" within",
|
|
3598
|
+
" ",
|
|
3599
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) })
|
|
3600
|
+
] }) })
|
|
3601
|
+
] });
|
|
3602
|
+
}
|
|
3603
|
+
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
|
|
3604
|
+
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
|
|
3605
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
|
|
3606
|
+
const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
3607
|
+
const isCur = (r) => keyOf(r) === keyOf(cur) && focused;
|
|
3608
|
+
const cursor = (r) => /* @__PURE__ */ jsx7(Text7, { color: isCur(r) ? theme.accentBright : theme.dim, children: isCur(r) ? "\u25B8 " : " " });
|
|
3609
|
+
const rowLine = (r) => {
|
|
3610
|
+
switch (r.kind) {
|
|
3611
|
+
case "acct": {
|
|
3612
|
+
const a = r.acc;
|
|
3469
3613
|
const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
|
|
3470
3614
|
const isActive = isActiveAccount(a.apiKey);
|
|
3471
3615
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3472
|
-
|
|
3616
|
+
cursor(r),
|
|
3473
3617
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(acctLabel(a), 30).padEnd(31) }),
|
|
3474
3618
|
isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3475
3619
|
isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3476
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate(a.project,
|
|
3477
|
-
] }
|
|
3478
|
-
}
|
|
3479
|
-
|
|
3480
|
-
/* @__PURE__ */
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
/* @__PURE__ */
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "
|
|
3620
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate(a.project, 20) : "" })
|
|
3621
|
+
] });
|
|
3622
|
+
}
|
|
3623
|
+
case "acct-add":
|
|
3624
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3625
|
+
cursor(r),
|
|
3626
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
|
|
3627
|
+
] });
|
|
3628
|
+
case "guard":
|
|
3629
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3630
|
+
cursor(r),
|
|
3631
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
3632
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3633
|
+
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
3634
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available` }),
|
|
3635
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
3636
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
3637
|
+
] });
|
|
3638
|
+
case "self":
|
|
3639
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3640
|
+
cursor(r),
|
|
3641
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "self-prot".padEnd(11) }),
|
|
3642
|
+
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2026" }),
|
|
3643
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " blocks agents editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
|
|
3644
|
+
] });
|
|
3645
|
+
case "ll-enabled":
|
|
3646
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3647
|
+
cursor(r),
|
|
3648
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(11) }),
|
|
3493
3649
|
onOff(!!local?.enabled),
|
|
3494
3650
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
3495
|
-
] })
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3651
|
+
] });
|
|
3652
|
+
case "ll-path":
|
|
3653
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3654
|
+
cursor(r),
|
|
3655
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(11) }),
|
|
3499
3656
|
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
3500
|
-
] })
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3657
|
+
] });
|
|
3658
|
+
case "ll-server":
|
|
3659
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3660
|
+
cursor(r),
|
|
3661
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(11) }),
|
|
3504
3662
|
srv.running ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "stopped" }),
|
|
3505
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? "
|
|
3506
|
-
] })
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
/* @__PURE__ */
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3518
|
-
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
3519
|
-
onOff(wh.enabled),
|
|
3520
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
3521
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(wh.url, cols - 16) })
|
|
3522
|
-
] }, wh.id)),
|
|
3523
|
-
inWindow({ kind: "wh-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3524
|
-
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
3663
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? " survives closing the dataroom \xB7 enter stops" : " enter starts the dashboard local-logs link" })
|
|
3664
|
+
] });
|
|
3665
|
+
case "wh":
|
|
3666
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3667
|
+
cursor(r),
|
|
3668
|
+
onOff(r.wh.enabled),
|
|
3669
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + r.wh.events).padEnd(9) }),
|
|
3670
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(r.wh.url, cols - 16) })
|
|
3671
|
+
] });
|
|
3672
|
+
case "wh-add":
|
|
3673
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3674
|
+
cursor(r),
|
|
3525
3675
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
3526
|
-
] })
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
/* @__PURE__ */
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
3539
|
-
onOff(rule.enabled),
|
|
3540
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
3541
|
-
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
3542
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(chanOf(rule), cols - 26) })
|
|
3543
|
-
] }, rule.id)),
|
|
3544
|
-
inWindow({ kind: "alert-add-email" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3545
|
-
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add-email" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add-email" }) }),
|
|
3676
|
+
] });
|
|
3677
|
+
case "alert":
|
|
3678
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3679
|
+
cursor(r),
|
|
3680
|
+
onOff(r.rule.enabled),
|
|
3681
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + SIGNAL_LABEL[r.rule.signal]).padEnd(13) }),
|
|
3682
|
+
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${r.rule.threshold}/${winLabel(r.rule.windowSeconds)} `.padEnd(11) }),
|
|
3683
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(chanOf(r.rule), cols - 34) })
|
|
3684
|
+
] });
|
|
3685
|
+
case "alert-add-email":
|
|
3686
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3687
|
+
cursor(r),
|
|
3546
3688
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add email alert (enter)" })
|
|
3547
|
-
] })
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3689
|
+
] });
|
|
3690
|
+
case "alert-add-tg":
|
|
3691
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3692
|
+
cursor(r),
|
|
3693
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
|
|
3694
|
+
] });
|
|
3695
|
+
}
|
|
3696
|
+
};
|
|
3697
|
+
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
3698
|
+
const SECTION_DESC = {
|
|
3699
|
+
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
3700
|
+
PROTECTION: "guard hook version + self-protection toggle",
|
|
3701
|
+
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
3702
|
+
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
3703
|
+
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 t tests`
|
|
3704
|
+
};
|
|
3705
|
+
const lineEls = [];
|
|
3706
|
+
const lineKey = [];
|
|
3707
|
+
let lastSec = "";
|
|
3708
|
+
rowsAll.forEach((r) => {
|
|
3709
|
+
const sec = sectionOf(r);
|
|
3710
|
+
if (sec !== lastSec) {
|
|
3711
|
+
lastSec = sec;
|
|
3712
|
+
lineEls.push(
|
|
3713
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3714
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: sec }),
|
|
3715
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2014 " + SECTION_DESC[sec] })
|
|
3716
|
+
] }, "h:" + sec)
|
|
3717
|
+
);
|
|
3718
|
+
lineKey.push("");
|
|
3719
|
+
}
|
|
3720
|
+
lineEls.push(/* @__PURE__ */ jsx7(Box7, { children: rowLine(r) }, keyOf(r)));
|
|
3721
|
+
lineKey.push(keyOf(r));
|
|
3722
|
+
});
|
|
3723
|
+
if (hasEmailAlert && hasTgAlert) {
|
|
3724
|
+
lineEls.push(
|
|
3725
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }, "both-note")
|
|
3726
|
+
);
|
|
3727
|
+
lineKey.push("");
|
|
3728
|
+
}
|
|
3729
|
+
const budget = Math.max(4, rows - 2);
|
|
3730
|
+
const selLine = Math.max(0, lineKey.indexOf(keyOf(cur)));
|
|
3731
|
+
const maxStart = Math.max(0, lineEls.length - budget);
|
|
3732
|
+
const startL = Math.min(Math.max(0, selLine - Math.floor(budget / 2)), maxStart);
|
|
3733
|
+
const win = lineEls.slice(startL, startL + budget);
|
|
3734
|
+
const moreAbove = startL;
|
|
3735
|
+
const moreBelow = Math.max(0, lineEls.length - (startL + budget));
|
|
3736
|
+
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3737
|
+
/* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: theme.dim, children: focused ? `\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove \xB7 d delete \xB7 n add${moreAbove ? ` \xB7 \u25B2${moreAbove}` : ""}${moreBelow ? ` \xB7 \u25BC${moreBelow}` : ""}` : "press \u2192 to configure" }),
|
|
3738
|
+
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3739
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
3740
|
+
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3741
|
+
] }) : 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: " " }),
|
|
3742
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
3554
3743
|
] }) });
|
|
3555
3744
|
}
|
|
3556
3745
|
|
|
@@ -3796,24 +3985,29 @@ function App() {
|
|
|
3796
3985
|
}
|
|
3797
3986
|
const Panel = current.Panel;
|
|
3798
3987
|
const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
|
|
3799
|
-
return
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3988
|
+
return (
|
|
3989
|
+
// height rows-1 (not rows): once total output reaches stdout.rows ink stops
|
|
3990
|
+
// diffing and clearTerminal-repaints every frame, which slides the banner.
|
|
3991
|
+
// overflow hidden makes it a hard guarantee even if a panel over-renders.
|
|
3992
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows - 1, paddingX: 1, paddingTop: 1, overflow: "hidden", children: [
|
|
3993
|
+
/* @__PURE__ */ jsx8(Banner, { cols }),
|
|
3994
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
3995
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "account: " }),
|
|
3996
|
+
/* @__PURE__ */ jsx8(Text8, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
|
|
3997
|
+
locked ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 Settings to add another" }),
|
|
3998
|
+
update2.kind === "updating" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
3999
|
+
] }),
|
|
4000
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
|
|
4001
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
4002
|
+
const isCur = i === effectiveSection;
|
|
4003
|
+
const disabled = locked && s.label !== "Settings";
|
|
4004
|
+
return /* @__PURE__ */ jsx8(Text8, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
|
|
4005
|
+
}) }),
|
|
4006
|
+
/* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, overflow: "hidden", children: panelBody })
|
|
4007
|
+
] }, viewNonce),
|
|
4008
|
+
/* @__PURE__ */ jsx8(Box8, { children: locked ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2192/enter", "open Settings"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
4009
|
+
] })
|
|
4010
|
+
);
|
|
3817
4011
|
}
|
|
3818
4012
|
var HELP = [
|
|
3819
4013
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|