@wrongstack/cli 1.1.4 → 1.1.6
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/{acp-MZ5MQBFN.js → acp-CZBSFQB7.js} +6 -5
- package/dist/acp-leader/acp-leader-confirm.d.ts +2 -0
- package/dist/acp-leader/acp-leader-host-binding.d.ts +1 -0
- package/dist/acp-leader/acp-leader-host.d.ts +9 -0
- package/dist/acp-leader/acp-leader-picker.d.ts +6 -3
- package/dist/acp-leader/acp-leader-provider.d.ts +10 -0
- package/dist/acp-leader/acp-leader-skills.d.ts +5 -0
- package/dist/acp-leader/acp-leader-stream.d.ts +9 -0
- package/dist/{auth-IHQS6AFW.js → auth-2ZG5DBHS.js} +4 -4
- package/dist/boot/launch-menu-arrow.d.ts +20 -0
- package/dist/boot/launch-menu-types.d.ts +36 -0
- package/dist/boot/launch-menu.d.ts +1 -57
- package/dist/boot/tui-session-resume-rollback.d.ts +31 -0
- package/dist/{boot-auto-thin-7D4OVEWA.js → boot-auto-thin-N2CIGTXE.js} +3 -3
- package/dist/{chunk-TZPKOS5G.js → chunk-2XQ6SRKG.js} +2 -2
- package/dist/{chunk-3EXRPTAU.js → chunk-5TQ65PXQ.js} +17 -17
- package/dist/{chunk-VAQXOZKP.js → chunk-AJM4EFCM.js} +139 -136
- package/dist/{chunk-C2BBH4S4.js → chunk-E3MJFAFR.js} +2 -2
- package/dist/{chunk-COGI7EQU.js → chunk-EAATL6FL.js} +713 -21
- package/dist/{chunk-AWRZWPJ3.js → chunk-FWUIKCCO.js} +152 -123
- package/dist/{chunk-TAE3EGBM.js → chunk-H5DCQFUI.js} +5 -5
- package/dist/{chunk-BIGSVBPI.js → chunk-KNYIEQAY.js} +64 -61
- package/dist/chunk-LYWOV4OX.js +252 -0
- package/dist/{chunk-75OLD563.js → chunk-M7PSENGF.js} +3 -1
- package/dist/{chunk-I5LJLKA3.js → chunk-MKMM5RIW.js} +12 -5
- package/dist/{chunk-ZF4HRR5F.js → chunk-P7MEEUGT.js} +275 -250
- package/dist/chunk-PGC44T7N.js +255 -0
- package/dist/chunk-QLYPIJ7X.js +258 -0
- package/dist/{chunk-JKTJSLUT.js → chunk-QRWXHGLB.js} +242 -18
- package/dist/chunk-RN5CFAVQ.js +292 -0
- package/dist/{chunk-WDXNBYGD.js → chunk-TDP7CZGE.js} +6 -1
- package/dist/{chunk-6VPWQ4TG.js → chunk-UROB7MK5.js} +2 -1
- package/dist/{chunk-IJLIAPCW.js → chunk-VPSAKGLK.js} +47 -47
- package/dist/{chunk-2LTHDKZX.js → chunk-W7X23HI6.js} +18 -18
- package/dist/{chunk-GKGWPFW2.js → chunk-X4DEQLAZ.js} +1 -1
- package/dist/{cli-context-E44HQ4ZO.js → cli-context-6KS3HV5R.js} +247 -236
- package/dist/{cli-main-OT63I2FX.js → cli-main-NF3YGDME.js} +1779 -1494
- package/dist/cli-main-boot.d.ts +1 -1
- package/dist/config-doctor-known-keys.d.ts +33 -0
- package/dist/config-doctor.d.ts +2 -47
- package/dist/config-history-support.d.ts +36 -0
- package/dist/config-history.d.ts +1 -1
- package/dist/{config-transfer-Y7XJMJRN.js → config-transfer-B4GOZTFC.js} +2 -2
- package/dist/{execution-OK34CJKJ.js → execution-RVDUXLNT.js} +6522 -6426
- package/dist/execution-tui.d.ts +30 -0
- package/dist/fleet/acp-wrongstack-bridge.d.ts +11 -3
- package/dist/fleet/host-acp.d.ts +3 -0
- package/dist/fleet/wrongforge-client.d.ts +116 -0
- package/dist/fleet/wrongforge-gateway.d.ts +20 -0
- package/dist/fleet/wrongforge-info.d.ts +32 -0
- package/dist/fleet/wrongforge-quota.d.ts +10 -0
- package/dist/fleet/wrongforge-runner.d.ts +37 -0
- package/dist/fleet/wrongforge-runtime.d.ts +10 -0
- package/dist/{hq-JD5AZVMG.js → hq-V2M4IYCI.js} +320 -306
- package/dist/hq-server/login-attempt-store.d.ts +2 -0
- package/dist/hq-server/sweeps.d.ts +28 -0
- package/dist/{hq-server-BI23EPM7.js → hq-server-QM7EIVGJ.js} +3 -3
- package/dist/index.js +5 -5
- package/dist/mcp-22CFBX4H.js +236 -0
- package/dist/mcp-serve.d.ts +0 -63
- package/dist/{modeldiag-HDIKG37X.js → modeldiag-5PBB777J.js} +4 -4
- package/dist/{per-subcommand-help-4GYSCMLU.js → per-subcommand-help-MQGERD4E.js} +2 -2
- package/dist/plugin-llm-command.d.ts +9 -0
- package/dist/{plugin-usage-TYF5HY4K.js → plugin-usage-UWKYMNQU.js} +3 -3
- package/dist/{plugins-XGAXDLPT.js → plugins-VP7JQH47.js} +4 -4
- package/dist/{sdd-runtime-6MFUXWJK.js → sdd-runtime-HIJ4Z5TF.js} +2 -2
- package/dist/services/sdd/state.d.ts +2 -0
- package/dist/session-event-wiring-types.d.ts +62 -0
- package/dist/session-event-wiring.d.ts +2 -52
- package/dist/{sessions-config-SJVQXCIE.js → sessions-config-7MK742OW.js} +2 -2
- package/dist/short-circuit-flags-276OLPIN.js +11 -0
- package/dist/slash-commands/command-context-fleet.d.ts +187 -0
- package/dist/slash-commands/command-context-sdd-goal.d.ts +102 -0
- package/dist/slash-commands/command-context.d.ts +3 -282
- package/dist/slash-commands/project-switch-interactive.d.ts +11 -0
- package/dist/slash-commands/setmodel-helpers.d.ts +36 -0
- package/dist/subcommands/handlers/hq-token.d.ts +3 -0
- package/dist/subcommands/handlers/hq.d.ts +0 -21
- package/dist/subcommands/handlers/per-subcommand-help-operations.d.ts +8 -0
- package/dist/subcommands/handlers/tools-cli-args.d.ts +57 -0
- package/dist/subcommands/handlers/tools-cli.d.ts +5 -0
- package/dist/subcommands/handlers/tools-serve.d.ts +4 -0
- package/dist/{subcommands-YADUV7IJ.js → subcommands-SKJPUJ7N.js} +2 -2
- package/dist/tool-gateway-http.d.ts +30 -0
- package/dist/tool-gateway.d.ts +185 -0
- package/dist/tools-cli-44MLIUQO.js +509 -0
- package/dist/tools-serve-TRCET2M7.js +102 -0
- package/dist/{tools-skills-55QVTMSK.js → tools-skills-WDTMCE46.js} +7 -2
- package/dist/tuneup-runtime-checks.d.ts +7 -0
- package/dist/tuneup-types.d.ts +118 -0
- package/dist/tuneup.d.ts +3 -122
- package/dist/{typesafe-YBEADNAH.js → typesafe-QLSMFU7J.js} +1 -1
- package/dist/{version-help-RBZC5GZZ.js → version-help-X6CC4CFY.js} +2 -2
- package/dist/{webui-server-CB64CFDG.js → webui-server-6I6QOECV.js} +44 -6
- package/dist/wiring/provider-runtime-setup.d.ts +3 -1
- package/dist/wiring/session-runtime.d.ts +1 -1
- package/dist/wrongforge-gateway-UOFBK56J.js +92 -0
- package/dist/wrongforge-leader/wrongforge-leader-gateway.d.ts +9 -0
- package/dist/wrongforge-leader/wrongforge-leader-picker.d.ts +12 -0
- package/dist/wrongforge-leader/wrongforge-leader-provider.d.ts +56 -0
- package/package.json +1 -1
- package/dist/mcp-W7A5HUXV.js +0 -560
- package/dist/short-circuit-flags-QEXUS3BY.js +0 -11
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
normalizeHqPublicOrigin,
|
|
9
9
|
resolveAuditActor
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5TQ65PXQ.js";
|
|
11
11
|
import {
|
|
12
12
|
parseHqIpAllowlist
|
|
13
13
|
} from "./chunk-OGVSKS4Q.js";
|
|
@@ -18,13 +18,8 @@ import {
|
|
|
18
18
|
HQ_AUTH_FILE_VERSION,
|
|
19
19
|
HQ_CLI_DEFAULT_HOST,
|
|
20
20
|
HqInsecureExposureError,
|
|
21
|
-
isLoopbackHost
|
|
22
|
-
logHqAuthAudit,
|
|
23
|
-
mintHqToken,
|
|
24
|
-
mutateHqAuthFile,
|
|
25
|
-
readHqAuthFile as readHqAuthFile2
|
|
21
|
+
isLoopbackHost
|
|
26
22
|
} from "@wrongstack/core/hq";
|
|
27
|
-
import { expectDefined } from "@wrongstack/core/utils";
|
|
28
23
|
|
|
29
24
|
// src/subcommands/handlers/hq-alerts.ts
|
|
30
25
|
import * as fs from "node:fs/promises";
|
|
@@ -297,243 +292,14 @@ function printAuditHelp(deps) {
|
|
|
297
292
|
`);
|
|
298
293
|
}
|
|
299
294
|
|
|
300
|
-
// src/subcommands/handlers/hq.ts
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return startServer(deps);
|
|
309
|
-
}
|
|
310
|
-
if (sub === "token") {
|
|
311
|
-
return hqTokenCmd(args.slice(1), deps);
|
|
312
|
-
}
|
|
313
|
-
if (sub === "audit") {
|
|
314
|
-
return hqAuditCmd(args.slice(1), deps);
|
|
315
|
-
}
|
|
316
|
-
if (sub === "alerts") {
|
|
317
|
-
return hqAlertsCmd(args.slice(1), deps);
|
|
318
|
-
}
|
|
319
|
-
if (sub === "service") {
|
|
320
|
-
const { hqServiceCmd } = await import("./hq-service-TQNPIRHL.js");
|
|
321
|
-
return hqServiceCmd(args.slice(1), deps);
|
|
322
|
-
}
|
|
323
|
-
if (sub === "help" || sub === "--help") {
|
|
324
|
-
printHelp(deps);
|
|
325
|
-
return 0;
|
|
326
|
-
}
|
|
327
|
-
deps.renderer.writeError(`Unknown hq subcommand: ${sub}
|
|
328
|
-
`);
|
|
329
|
-
printHelp(deps);
|
|
330
|
-
return 1;
|
|
331
|
-
};
|
|
332
|
-
async function startServer(deps) {
|
|
333
|
-
const { startHqServer } = await import("./hq-server-BI23EPM7.js");
|
|
334
|
-
const dataDir = resolveDataDir(deps);
|
|
335
|
-
const flags = deps.flags ?? {};
|
|
336
|
-
const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
|
|
337
|
-
let publicOrigin;
|
|
338
|
-
if (rawPublicUrl !== void 0 && rawPublicUrl.trim() !== "") {
|
|
339
|
-
try {
|
|
340
|
-
publicOrigin = normalizeHqPublicOrigin(rawPublicUrl);
|
|
341
|
-
} catch (cause) {
|
|
342
|
-
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
343
|
-
`);
|
|
344
|
-
return 1;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
const host = typeof flags["host"] === "string" ? flags["host"] : publicOrigin !== void 0 ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST;
|
|
348
|
-
const rawPort = typeof flags["port"] === "string" ? flags["port"].trim() : void 0;
|
|
349
|
-
const port = rawPort === void 0 ? 3499 : /^\d+$/.test(rawPort) ? Number(rawPort) : Number.NaN;
|
|
350
|
-
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
351
|
-
deps.renderer.writeError(`Invalid --port value: ${String(flags["port"])}
|
|
352
|
-
`);
|
|
353
|
-
return 1;
|
|
354
|
-
}
|
|
355
|
-
if (publicOrigin !== void 0 && !isLoopbackHost(host)) {
|
|
356
|
-
deps.renderer.writeError(
|
|
357
|
-
"Persistent public HQ requires a loopback bind. Remove --host or use --host 127.0.0.1.\n"
|
|
358
|
-
);
|
|
359
|
-
return 1;
|
|
360
|
-
}
|
|
361
|
-
const strictPort = flags["strict-port"] === true;
|
|
362
|
-
const open = flags["open"] === true;
|
|
363
|
-
let password;
|
|
364
|
-
try {
|
|
365
|
-
password = await resolveHqPasswordInput({
|
|
366
|
-
...typeof flags["password"] === "string" ? { explicitPassword: flags["password"] } : {}
|
|
367
|
-
});
|
|
368
|
-
} catch (cause) {
|
|
369
|
-
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
370
|
-
`);
|
|
371
|
-
return 1;
|
|
372
|
-
}
|
|
373
|
-
const bootstrapPasswordOnly = /^(?:1|true)$/i.test(
|
|
374
|
-
process.env.WRONGSTACK_HQ_BOOTSTRAP_PASSWORD_ONLY?.trim() ?? ""
|
|
375
|
-
);
|
|
376
|
-
const allowInsecureOpen = flags["insecure-open"] === true;
|
|
377
|
-
const rawAllowlist = typeof flags["hq-allowlist"] === "string" ? flags["hq-allowlist"] : process.env.WRONGSTACK_HQ_ALLOWLIST;
|
|
378
|
-
let ipAllowlist;
|
|
379
|
-
try {
|
|
380
|
-
ipAllowlist = parseHqIpAllowlist(rawAllowlist);
|
|
381
|
-
} catch (cause) {
|
|
382
|
-
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
383
|
-
`);
|
|
384
|
-
return 1;
|
|
385
|
-
}
|
|
386
|
-
const rawTtl = typeof flags["hq-token-ttl"] === "string" ? flags["hq-token-ttl"] : void 0;
|
|
387
|
-
let tokenTtlMs;
|
|
388
|
-
if (rawTtl !== void 0 && rawTtl.length > 0) {
|
|
389
|
-
const parsed = parseTokenTtlValue(rawTtl);
|
|
390
|
-
if (parsed.error) {
|
|
391
|
-
deps.renderer.writeError(`Invalid --hq-token-ttl: ${parsed.error}
|
|
392
|
-
`);
|
|
393
|
-
return 1;
|
|
394
|
-
}
|
|
395
|
-
tokenTtlMs = parsed.value;
|
|
396
|
-
}
|
|
397
|
-
const rawHops = typeof flags["hq-trusted-proxy-hops"] === "string" ? flags["hq-trusted-proxy-hops"] : void 0;
|
|
398
|
-
let trustedProxyHops;
|
|
399
|
-
if (rawHops !== void 0 && rawHops.length > 0) {
|
|
400
|
-
const parsed = Number.parseInt(rawHops, 10);
|
|
401
|
-
if (!Number.isFinite(parsed) || parsed < 0 || String(parsed) !== rawHops.trim()) {
|
|
402
|
-
deps.renderer.writeError(
|
|
403
|
-
"--hq-trusted-proxy-hops must be a non-negative integer (0 = ignore X-Forwarded-For).\n"
|
|
404
|
-
);
|
|
405
|
-
return 1;
|
|
406
|
-
}
|
|
407
|
-
trustedProxyHops = parsed;
|
|
408
|
-
}
|
|
409
|
-
if (password !== void 0 && password.length < 8) {
|
|
410
|
-
deps.renderer.writeError("HQ password must be at least 8 characters.\n");
|
|
411
|
-
return 1;
|
|
412
|
-
}
|
|
413
|
-
let handle;
|
|
414
|
-
try {
|
|
415
|
-
handle = await startHqServer({
|
|
416
|
-
host,
|
|
417
|
-
port,
|
|
418
|
-
strictPort,
|
|
419
|
-
dataDir,
|
|
420
|
-
allowInsecureOpen,
|
|
421
|
-
secureCookies: publicOrigin !== void 0,
|
|
422
|
-
requireBrowserAuth: publicOrigin !== void 0,
|
|
423
|
-
...password !== void 0 ? { password } : {},
|
|
424
|
-
...bootstrapPasswordOnly ? { bootstrapPasswordOnly: true } : {},
|
|
425
|
-
...tokenTtlMs !== void 0 ? { tokenTtlMs } : {},
|
|
426
|
-
...trustedProxyHops !== void 0 ? { trustedProxyHops } : {},
|
|
427
|
-
...ipAllowlist !== void 0 ? { ipAllowlist } : {}
|
|
428
|
-
});
|
|
429
|
-
} catch (err) {
|
|
430
|
-
if (err instanceof HqInsecureExposureError) {
|
|
431
|
-
deps.renderer.writeError(`${err.message}
|
|
432
|
-
`);
|
|
433
|
-
return 1;
|
|
434
|
-
}
|
|
435
|
-
throw err;
|
|
436
|
-
}
|
|
437
|
-
if (publicOrigin !== void 0) {
|
|
438
|
-
if (handle.firstRunSetup?.passwordMode !== true) {
|
|
439
|
-
await handle.close();
|
|
440
|
-
deps.renderer.writeError(
|
|
441
|
-
"Persistent public HQ requires password mode. Set WRONGSTACK_HQ_PASSWORD and retry.\n"
|
|
442
|
-
);
|
|
443
|
-
return 1;
|
|
444
|
-
}
|
|
445
|
-
handle.trustPublicOrigin(publicOrigin);
|
|
446
|
-
deps.renderer.write(`Public endpoint: ${publicOrigin}/
|
|
447
|
-
`);
|
|
448
|
-
deps.renderer.write(`Public mobile: ${publicOrigin}/mobile
|
|
449
|
-
`);
|
|
450
|
-
}
|
|
451
|
-
if (open) {
|
|
452
|
-
try {
|
|
453
|
-
const { openBrowser } = await import("@wrongstack/webui-server");
|
|
454
|
-
openBrowser(
|
|
455
|
-
publicOrigin ?? handle.firstRunSetup?.browserUrl ?? `http://${handle.host}:${handle.port}`
|
|
456
|
-
);
|
|
457
|
-
} catch {
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
writeStartupInfo(deps, handle);
|
|
461
|
-
deps.renderer.write(
|
|
462
|
-
ipAllowlist === void 0 ? "Network allowlist: disabled (authentication remains required when configured).\n" : `Network allowlist: active (${ipAllowlist.length} configured rule${ipAllowlist.length === 1 ? "" : "s"} + loopback).
|
|
463
|
-
`
|
|
464
|
-
);
|
|
465
|
-
await new Promise((resolve2) => {
|
|
466
|
-
const shutdown = async () => {
|
|
467
|
-
try {
|
|
468
|
-
await handle.close();
|
|
469
|
-
} catch (err) {
|
|
470
|
-
deps.renderer.write(`HQ server close error: ${String(err)}
|
|
471
|
-
`);
|
|
472
|
-
}
|
|
473
|
-
resolve2();
|
|
474
|
-
};
|
|
475
|
-
process.on("SIGINT", shutdown);
|
|
476
|
-
process.on("SIGTERM", shutdown);
|
|
477
|
-
});
|
|
478
|
-
return 0;
|
|
479
|
-
}
|
|
480
|
-
function writeStartupInfo(deps, handle) {
|
|
481
|
-
deps.renderer.write(`WrongStack HQ listening on http://${handle.host}:${handle.port}
|
|
482
|
-
`);
|
|
483
|
-
if (!handle.firstRunSetup) {
|
|
484
|
-
deps.renderer.write(`Client endpoint: ws://${handle.host}:${handle.port}/ws/client
|
|
485
|
-
`);
|
|
486
|
-
deps.renderer.write(`Browser endpoint: http://${handle.host}:${handle.port}
|
|
487
|
-
`);
|
|
488
|
-
deps.renderer.write(
|
|
489
|
-
`Mobile endpoint: http://${handle.host}:${handle.port}/mobile (password required)
|
|
490
|
-
`
|
|
491
|
-
);
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
if (process.env.WRONGSTACK_HQ_SUPPRESS_STARTUP_SECRETS === "1") {
|
|
495
|
-
deps.renderer.write(`Browser endpoint: http://${handle.host}:${handle.port}
|
|
496
|
-
`);
|
|
497
|
-
deps.renderer.write(
|
|
498
|
-
`Mobile endpoint: http://${handle.host}:${handle.port}/mobile (password required)
|
|
499
|
-
`
|
|
500
|
-
);
|
|
501
|
-
deps.renderer.write(`Client endpoint: ws://${handle.host}:${handle.port}/ws/client
|
|
502
|
-
`);
|
|
503
|
-
deps.renderer.write(
|
|
504
|
-
`Startup credentials suppressed; auth state is stored in ${handle.firstRunSetup.dataDir}.
|
|
505
|
-
`
|
|
506
|
-
);
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
const mobileUrl = new URL(handle.firstRunSetup.browserUrl);
|
|
510
|
-
mobileUrl.pathname = "/mobile";
|
|
511
|
-
mobileUrl.search = "";
|
|
512
|
-
mobileUrl.hash = "";
|
|
513
|
-
deps.renderer.write(`Browser endpoint: ${handle.firstRunSetup.browserUrl}
|
|
514
|
-
`);
|
|
515
|
-
deps.renderer.write(`Mobile endpoint: ${mobileUrl.toString()} (password required)
|
|
516
|
-
`);
|
|
517
|
-
deps.renderer.write(`Client endpoint: ${handle.firstRunSetup.clientUrl}
|
|
518
|
-
`);
|
|
519
|
-
deps.renderer.write(
|
|
520
|
-
handle.firstRunSetup.createdAuth ? `
|
|
521
|
-
First-run HQ auth created in ${handle.firstRunSetup.dataDir}
|
|
522
|
-
` : `
|
|
523
|
-
HQ auth loaded from ${handle.firstRunSetup.dataDir}
|
|
524
|
-
`
|
|
525
|
-
);
|
|
526
|
-
deps.renderer.write(`Start clients with:
|
|
527
|
-
`);
|
|
528
|
-
deps.renderer.write(` WRONGSTACK_HQ_URL=${handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_URL}
|
|
529
|
-
`);
|
|
530
|
-
if (handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_TOKEN) {
|
|
531
|
-
deps.renderer.write(
|
|
532
|
-
` WRONGSTACK_HQ_TOKEN=${handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_TOKEN}
|
|
533
|
-
`
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
295
|
+
// src/subcommands/handlers/hq-token.ts
|
|
296
|
+
import {
|
|
297
|
+
logHqAuthAudit,
|
|
298
|
+
mintHqToken,
|
|
299
|
+
mutateHqAuthFile,
|
|
300
|
+
readHqAuthFile as readHqAuthFile2
|
|
301
|
+
} from "@wrongstack/core/hq";
|
|
302
|
+
import { expectDefined } from "@wrongstack/core/utils";
|
|
537
303
|
async function hqTokenCmd(args, deps) {
|
|
538
304
|
const action = args[0];
|
|
539
305
|
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
@@ -786,18 +552,21 @@ async function tokenRevoke(args, deps) {
|
|
|
786
552
|
const dataDir = resolveDataDir(deps);
|
|
787
553
|
const tokenField = scope === "client" ? "clientTokens" : "browserTokens";
|
|
788
554
|
let revoked;
|
|
555
|
+
let ambiguous = [];
|
|
789
556
|
try {
|
|
790
557
|
await mutateHqAuthFile(
|
|
791
558
|
dataDir,
|
|
792
559
|
(current) => {
|
|
793
560
|
const tokens = current[tokenField] ?? [];
|
|
794
561
|
const matches = tokens.filter((t) => t.id.startsWith(idPrefix));
|
|
562
|
+
ambiguous = [];
|
|
795
563
|
if (matches.length === 0) {
|
|
796
564
|
revoked = void 0;
|
|
797
565
|
return current;
|
|
798
566
|
}
|
|
799
567
|
if (matches.length > 1) {
|
|
800
|
-
revoked =
|
|
568
|
+
revoked = void 0;
|
|
569
|
+
ambiguous = matches;
|
|
801
570
|
return current;
|
|
802
571
|
}
|
|
803
572
|
revoked = matches[0];
|
|
@@ -814,6 +583,13 @@ async function tokenRevoke(args, deps) {
|
|
|
814
583
|
`);
|
|
815
584
|
return 1;
|
|
816
585
|
}
|
|
586
|
+
if (ambiguous.length > 0) {
|
|
587
|
+
deps.renderer.writeError(
|
|
588
|
+
`Id-prefix "${idPrefix}" matches ${ambiguous.length} ${scope} tokens (${ambiguous.map((t) => t.id).join(", ")}); nothing revoked. Use a longer prefix.
|
|
589
|
+
`
|
|
590
|
+
);
|
|
591
|
+
return 1;
|
|
592
|
+
}
|
|
817
593
|
if (!revoked) {
|
|
818
594
|
deps.renderer.writeError(`No ${scope} token found matching id-prefix "${idPrefix}".
|
|
819
595
|
`);
|
|
@@ -846,8 +622,304 @@ async function tokenRevoke(args, deps) {
|
|
|
846
622
|
);
|
|
847
623
|
return 0;
|
|
848
624
|
}
|
|
849
|
-
function
|
|
850
|
-
deps.renderer.write(`Usage: wstack hq <
|
|
625
|
+
function printTokenHelp(deps) {
|
|
626
|
+
deps.renderer.write(`Usage: wstack hq token <create | list | revoke>
|
|
627
|
+
`);
|
|
628
|
+
deps.renderer.write("\n");
|
|
629
|
+
deps.renderer.write(
|
|
630
|
+
` wstack hq token create [label] [--ttl <dur>] Mint a browser token (enters token mode).
|
|
631
|
+
`
|
|
632
|
+
);
|
|
633
|
+
deps.renderer.write(
|
|
634
|
+
` wstack hq token create --client [label] [--ttl <dur>] Mint a client token (/ws/client).
|
|
635
|
+
`
|
|
636
|
+
);
|
|
637
|
+
deps.renderer.write(
|
|
638
|
+
` wstack hq token list List issued browser tokens (alias: ls).
|
|
639
|
+
`
|
|
640
|
+
);
|
|
641
|
+
deps.renderer.write(
|
|
642
|
+
` wstack hq token list --client List issued client tokens.
|
|
643
|
+
`
|
|
644
|
+
);
|
|
645
|
+
deps.renderer.write(
|
|
646
|
+
` wstack hq token revoke <id> Revoke a browser token (id prefix match).
|
|
647
|
+
`
|
|
648
|
+
);
|
|
649
|
+
deps.renderer.write(
|
|
650
|
+
` wstack hq token revoke --client <id> Revoke a client token.
|
|
651
|
+
`
|
|
652
|
+
);
|
|
653
|
+
deps.renderer.write("\n");
|
|
654
|
+
deps.renderer.write(`The token secret is printed once at create time and cannot be recovered
|
|
655
|
+
`);
|
|
656
|
+
deps.renderer.write(`from auth.json (only its SHA-256 verifier is persisted). Tokens live in
|
|
657
|
+
`);
|
|
658
|
+
deps.renderer.write(`<dataDir>/auth.json (default ~/.wrongstack/hq/auth.json).
|
|
659
|
+
`);
|
|
660
|
+
deps.renderer.write("\n");
|
|
661
|
+
deps.renderer.write(`Flags:
|
|
662
|
+
`);
|
|
663
|
+
deps.renderer.write(
|
|
664
|
+
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
665
|
+
`
|
|
666
|
+
);
|
|
667
|
+
deps.renderer.write(
|
|
668
|
+
` --client, -c Operate on client tokens instead of browser tokens.
|
|
669
|
+
`
|
|
670
|
+
);
|
|
671
|
+
deps.renderer.write(
|
|
672
|
+
` --capabilities <csv> Comma-separated capability grants (browser: control.enqueue,control.approve; client: telemetry.publish,control.execute).
|
|
673
|
+
`
|
|
674
|
+
);
|
|
675
|
+
deps.renderer.write(
|
|
676
|
+
` --ttl <duration> Stamp an expiresAt on the token (e.g. --ttl 1h, --ttl 7d, --ttl 3600s).
|
|
677
|
+
`
|
|
678
|
+
);
|
|
679
|
+
deps.renderer.write("\n");
|
|
680
|
+
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
681
|
+
`);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/subcommands/handlers/hq.ts
|
|
685
|
+
var hqCmd = async (args, deps) => {
|
|
686
|
+
const sub = args[0];
|
|
687
|
+
if (deps.flags?.["help"] === true && (!sub || sub === "serve")) {
|
|
688
|
+
printHelp(deps);
|
|
689
|
+
return 0;
|
|
690
|
+
}
|
|
691
|
+
if (!sub || sub === "serve") {
|
|
692
|
+
return startServer(deps);
|
|
693
|
+
}
|
|
694
|
+
if (sub === "token") {
|
|
695
|
+
return hqTokenCmd(args.slice(1), deps);
|
|
696
|
+
}
|
|
697
|
+
if (sub === "audit") {
|
|
698
|
+
return hqAuditCmd(args.slice(1), deps);
|
|
699
|
+
}
|
|
700
|
+
if (sub === "alerts") {
|
|
701
|
+
return hqAlertsCmd(args.slice(1), deps);
|
|
702
|
+
}
|
|
703
|
+
if (sub === "service") {
|
|
704
|
+
const { hqServiceCmd } = await import("./hq-service-TQNPIRHL.js");
|
|
705
|
+
return hqServiceCmd(args.slice(1), deps);
|
|
706
|
+
}
|
|
707
|
+
if (sub === "help" || sub === "--help") {
|
|
708
|
+
printHelp(deps);
|
|
709
|
+
return 0;
|
|
710
|
+
}
|
|
711
|
+
deps.renderer.writeError(`Unknown hq subcommand: ${sub}
|
|
712
|
+
`);
|
|
713
|
+
printHelp(deps);
|
|
714
|
+
return 1;
|
|
715
|
+
};
|
|
716
|
+
async function startServer(deps) {
|
|
717
|
+
const { startHqServer } = await import("./hq-server-QM7EIVGJ.js");
|
|
718
|
+
const dataDir = resolveDataDir(deps);
|
|
719
|
+
const flags = deps.flags ?? {};
|
|
720
|
+
const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
|
|
721
|
+
let publicOrigin;
|
|
722
|
+
if (rawPublicUrl !== void 0 && rawPublicUrl.trim() !== "") {
|
|
723
|
+
try {
|
|
724
|
+
publicOrigin = normalizeHqPublicOrigin(rawPublicUrl);
|
|
725
|
+
} catch (cause) {
|
|
726
|
+
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
727
|
+
`);
|
|
728
|
+
return 1;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
const host = typeof flags["host"] === "string" ? flags["host"] : publicOrigin !== void 0 ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST;
|
|
732
|
+
const rawPort = typeof flags["port"] === "string" ? flags["port"].trim() : void 0;
|
|
733
|
+
const port = rawPort === void 0 ? 3499 : /^\d+$/.test(rawPort) ? Number(rawPort) : Number.NaN;
|
|
734
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
735
|
+
deps.renderer.writeError(`Invalid --port value: ${String(flags["port"])}
|
|
736
|
+
`);
|
|
737
|
+
return 1;
|
|
738
|
+
}
|
|
739
|
+
if (publicOrigin !== void 0 && !isLoopbackHost(host)) {
|
|
740
|
+
deps.renderer.writeError(
|
|
741
|
+
"Persistent public HQ requires a loopback bind. Remove --host or use --host 127.0.0.1.\n"
|
|
742
|
+
);
|
|
743
|
+
return 1;
|
|
744
|
+
}
|
|
745
|
+
const strictPort = flags["strict-port"] === true;
|
|
746
|
+
const open = flags["open"] === true;
|
|
747
|
+
let password;
|
|
748
|
+
try {
|
|
749
|
+
password = await resolveHqPasswordInput({
|
|
750
|
+
...typeof flags["password"] === "string" ? { explicitPassword: flags["password"] } : {}
|
|
751
|
+
});
|
|
752
|
+
} catch (cause) {
|
|
753
|
+
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
754
|
+
`);
|
|
755
|
+
return 1;
|
|
756
|
+
}
|
|
757
|
+
const bootstrapPasswordOnly = /^(?:1|true)$/i.test(
|
|
758
|
+
process.env.WRONGSTACK_HQ_BOOTSTRAP_PASSWORD_ONLY?.trim() ?? ""
|
|
759
|
+
);
|
|
760
|
+
const allowInsecureOpen = flags["insecure-open"] === true;
|
|
761
|
+
const rawAllowlist = typeof flags["hq-allowlist"] === "string" ? flags["hq-allowlist"] : process.env.WRONGSTACK_HQ_ALLOWLIST;
|
|
762
|
+
let ipAllowlist;
|
|
763
|
+
try {
|
|
764
|
+
ipAllowlist = parseHqIpAllowlist(rawAllowlist);
|
|
765
|
+
} catch (cause) {
|
|
766
|
+
deps.renderer.writeError(`${cause instanceof Error ? cause.message : String(cause)}
|
|
767
|
+
`);
|
|
768
|
+
return 1;
|
|
769
|
+
}
|
|
770
|
+
const rawTtl = typeof flags["hq-token-ttl"] === "string" ? flags["hq-token-ttl"] : void 0;
|
|
771
|
+
let tokenTtlMs;
|
|
772
|
+
if (rawTtl !== void 0 && rawTtl.length > 0) {
|
|
773
|
+
const parsed = parseTokenTtlValue(rawTtl);
|
|
774
|
+
if (parsed.error) {
|
|
775
|
+
deps.renderer.writeError(`Invalid --hq-token-ttl: ${parsed.error}
|
|
776
|
+
`);
|
|
777
|
+
return 1;
|
|
778
|
+
}
|
|
779
|
+
tokenTtlMs = parsed.value;
|
|
780
|
+
}
|
|
781
|
+
const rawHops = typeof flags["hq-trusted-proxy-hops"] === "string" ? flags["hq-trusted-proxy-hops"] : void 0;
|
|
782
|
+
let trustedProxyHops;
|
|
783
|
+
if (rawHops !== void 0 && rawHops.length > 0) {
|
|
784
|
+
const parsed = Number.parseInt(rawHops, 10);
|
|
785
|
+
if (!Number.isFinite(parsed) || parsed < 0 || String(parsed) !== rawHops.trim()) {
|
|
786
|
+
deps.renderer.writeError(
|
|
787
|
+
"--hq-trusted-proxy-hops must be a non-negative integer (0 = ignore X-Forwarded-For).\n"
|
|
788
|
+
);
|
|
789
|
+
return 1;
|
|
790
|
+
}
|
|
791
|
+
trustedProxyHops = parsed;
|
|
792
|
+
}
|
|
793
|
+
if (password !== void 0 && password.length < 8) {
|
|
794
|
+
deps.renderer.writeError("HQ password must be at least 8 characters.\n");
|
|
795
|
+
return 1;
|
|
796
|
+
}
|
|
797
|
+
let handle;
|
|
798
|
+
try {
|
|
799
|
+
handle = await startHqServer({
|
|
800
|
+
host,
|
|
801
|
+
port,
|
|
802
|
+
strictPort,
|
|
803
|
+
dataDir,
|
|
804
|
+
allowInsecureOpen,
|
|
805
|
+
secureCookies: publicOrigin !== void 0,
|
|
806
|
+
requireBrowserAuth: publicOrigin !== void 0,
|
|
807
|
+
...password !== void 0 ? { password } : {},
|
|
808
|
+
...bootstrapPasswordOnly ? { bootstrapPasswordOnly: true } : {},
|
|
809
|
+
...tokenTtlMs !== void 0 ? { tokenTtlMs } : {},
|
|
810
|
+
...trustedProxyHops !== void 0 ? { trustedProxyHops } : {},
|
|
811
|
+
...ipAllowlist !== void 0 ? { ipAllowlist } : {}
|
|
812
|
+
});
|
|
813
|
+
} catch (err) {
|
|
814
|
+
if (err instanceof HqInsecureExposureError) {
|
|
815
|
+
deps.renderer.writeError(`${err.message}
|
|
816
|
+
`);
|
|
817
|
+
return 1;
|
|
818
|
+
}
|
|
819
|
+
throw err;
|
|
820
|
+
}
|
|
821
|
+
if (publicOrigin !== void 0) {
|
|
822
|
+
if (handle.firstRunSetup?.passwordMode !== true) {
|
|
823
|
+
await handle.close();
|
|
824
|
+
deps.renderer.writeError(
|
|
825
|
+
"Persistent public HQ requires password mode. Set WRONGSTACK_HQ_PASSWORD and retry.\n"
|
|
826
|
+
);
|
|
827
|
+
return 1;
|
|
828
|
+
}
|
|
829
|
+
handle.trustPublicOrigin(publicOrigin);
|
|
830
|
+
deps.renderer.write(`Public endpoint: ${publicOrigin}/
|
|
831
|
+
`);
|
|
832
|
+
deps.renderer.write(`Public mobile: ${publicOrigin}/mobile
|
|
833
|
+
`);
|
|
834
|
+
}
|
|
835
|
+
if (open) {
|
|
836
|
+
try {
|
|
837
|
+
const { openBrowser } = await import("@wrongstack/webui-server");
|
|
838
|
+
openBrowser(
|
|
839
|
+
publicOrigin ?? handle.firstRunSetup?.browserUrl ?? `http://${handle.host}:${handle.port}`
|
|
840
|
+
);
|
|
841
|
+
} catch {
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
writeStartupInfo(deps, handle);
|
|
845
|
+
deps.renderer.write(
|
|
846
|
+
ipAllowlist === void 0 ? "Network allowlist: disabled (authentication remains required when configured).\n" : `Network allowlist: active (${ipAllowlist.length} configured rule${ipAllowlist.length === 1 ? "" : "s"} + loopback).
|
|
847
|
+
`
|
|
848
|
+
);
|
|
849
|
+
await new Promise((resolve2) => {
|
|
850
|
+
const shutdown = async () => {
|
|
851
|
+
try {
|
|
852
|
+
await handle.close();
|
|
853
|
+
} catch (err) {
|
|
854
|
+
deps.renderer.write(`HQ server close error: ${String(err)}
|
|
855
|
+
`);
|
|
856
|
+
}
|
|
857
|
+
resolve2();
|
|
858
|
+
};
|
|
859
|
+
process.on("SIGINT", shutdown);
|
|
860
|
+
process.on("SIGTERM", shutdown);
|
|
861
|
+
});
|
|
862
|
+
return 0;
|
|
863
|
+
}
|
|
864
|
+
function writeStartupInfo(deps, handle) {
|
|
865
|
+
deps.renderer.write(`WrongStack HQ listening on http://${handle.host}:${handle.port}
|
|
866
|
+
`);
|
|
867
|
+
if (!handle.firstRunSetup) {
|
|
868
|
+
deps.renderer.write(`Client endpoint: ws://${handle.host}:${handle.port}/ws/client
|
|
869
|
+
`);
|
|
870
|
+
deps.renderer.write(`Browser endpoint: http://${handle.host}:${handle.port}
|
|
871
|
+
`);
|
|
872
|
+
deps.renderer.write(
|
|
873
|
+
`Mobile endpoint: http://${handle.host}:${handle.port}/mobile (password required)
|
|
874
|
+
`
|
|
875
|
+
);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (process.env.WRONGSTACK_HQ_SUPPRESS_STARTUP_SECRETS === "1") {
|
|
879
|
+
deps.renderer.write(`Browser endpoint: http://${handle.host}:${handle.port}
|
|
880
|
+
`);
|
|
881
|
+
deps.renderer.write(
|
|
882
|
+
`Mobile endpoint: http://${handle.host}:${handle.port}/mobile (password required)
|
|
883
|
+
`
|
|
884
|
+
);
|
|
885
|
+
deps.renderer.write(`Client endpoint: ws://${handle.host}:${handle.port}/ws/client
|
|
886
|
+
`);
|
|
887
|
+
deps.renderer.write(
|
|
888
|
+
`Startup credentials suppressed; auth state is stored in ${handle.firstRunSetup.dataDir}.
|
|
889
|
+
`
|
|
890
|
+
);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
const mobileUrl = new URL(handle.firstRunSetup.browserUrl);
|
|
894
|
+
mobileUrl.pathname = "/mobile";
|
|
895
|
+
mobileUrl.search = "";
|
|
896
|
+
mobileUrl.hash = "";
|
|
897
|
+
deps.renderer.write(`Browser endpoint: ${handle.firstRunSetup.browserUrl}
|
|
898
|
+
`);
|
|
899
|
+
deps.renderer.write(`Mobile endpoint: ${mobileUrl.toString()} (password required)
|
|
900
|
+
`);
|
|
901
|
+
deps.renderer.write(`Client endpoint: ${handle.firstRunSetup.clientUrl}
|
|
902
|
+
`);
|
|
903
|
+
deps.renderer.write(
|
|
904
|
+
handle.firstRunSetup.createdAuth ? `
|
|
905
|
+
First-run HQ auth created in ${handle.firstRunSetup.dataDir}
|
|
906
|
+
` : `
|
|
907
|
+
HQ auth loaded from ${handle.firstRunSetup.dataDir}
|
|
908
|
+
`
|
|
909
|
+
);
|
|
910
|
+
deps.renderer.write(`Start clients with:
|
|
911
|
+
`);
|
|
912
|
+
deps.renderer.write(` WRONGSTACK_HQ_URL=${handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_URL}
|
|
913
|
+
`);
|
|
914
|
+
if (handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_TOKEN) {
|
|
915
|
+
deps.renderer.write(
|
|
916
|
+
` WRONGSTACK_HQ_TOKEN=${handle.firstRunSetup.clientEnv.WRONGSTACK_HQ_TOKEN}
|
|
917
|
+
`
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
function printHelp(deps) {
|
|
922
|
+
deps.renderer.write(`Usage: wstack hq <serve | token | audit | service>
|
|
851
923
|
`);
|
|
852
924
|
deps.renderer.write("\n");
|
|
853
925
|
deps.renderer.write(` wstack hq Start the HQ command center server.
|
|
@@ -949,65 +1021,7 @@ function printHelp(deps) {
|
|
|
949
1021
|
deps.renderer.write(`auth.json schema version: ${HQ_AUTH_FILE_VERSION}.
|
|
950
1022
|
`);
|
|
951
1023
|
}
|
|
952
|
-
function printTokenHelp(deps) {
|
|
953
|
-
deps.renderer.write(`Usage: wstack hq token <create | list | revoke>
|
|
954
|
-
`);
|
|
955
|
-
deps.renderer.write("\n");
|
|
956
|
-
deps.renderer.write(
|
|
957
|
-
` wstack hq token create [label] [--ttl <dur>] Mint a browser token (enters token mode).
|
|
958
|
-
`
|
|
959
|
-
);
|
|
960
|
-
deps.renderer.write(
|
|
961
|
-
` wstack hq token create --client [label] [--ttl <dur>] Mint a client token (/ws/client).
|
|
962
|
-
`
|
|
963
|
-
);
|
|
964
|
-
deps.renderer.write(
|
|
965
|
-
` wstack hq token list List issued browser tokens (alias: ls).
|
|
966
|
-
`
|
|
967
|
-
);
|
|
968
|
-
deps.renderer.write(
|
|
969
|
-
` wstack hq token list --client List issued client tokens.
|
|
970
|
-
`
|
|
971
|
-
);
|
|
972
|
-
deps.renderer.write(
|
|
973
|
-
` wstack hq token revoke <id> Revoke a browser token (id prefix match).
|
|
974
|
-
`
|
|
975
|
-
);
|
|
976
|
-
deps.renderer.write(
|
|
977
|
-
` wstack hq token revoke --client <id> Revoke a client token.
|
|
978
|
-
`
|
|
979
|
-
);
|
|
980
|
-
deps.renderer.write("\n");
|
|
981
|
-
deps.renderer.write(`The token secret is printed once at create time and cannot be recovered
|
|
982
|
-
`);
|
|
983
|
-
deps.renderer.write(`from auth.json (only its SHA-256 verifier is persisted). Tokens live in
|
|
984
|
-
`);
|
|
985
|
-
deps.renderer.write(`<dataDir>/auth.json (default ~/.wrongstack/hq/auth.json).
|
|
986
|
-
`);
|
|
987
|
-
deps.renderer.write("\n");
|
|
988
|
-
deps.renderer.write(`Flags:
|
|
989
|
-
`);
|
|
990
|
-
deps.renderer.write(
|
|
991
|
-
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
992
|
-
`
|
|
993
|
-
);
|
|
994
|
-
deps.renderer.write(
|
|
995
|
-
` --client, -c Operate on client tokens instead of browser tokens.
|
|
996
|
-
`
|
|
997
|
-
);
|
|
998
|
-
deps.renderer.write(
|
|
999
|
-
` --capabilities <csv> Comma-separated capability grants (browser: control.enqueue,control.approve; client: telemetry.publish,control.execute).
|
|
1000
|
-
`
|
|
1001
|
-
);
|
|
1002
|
-
deps.renderer.write(
|
|
1003
|
-
` --ttl <duration> Stamp an expiresAt on the token (e.g. --ttl 1h, --ttl 7d, --ttl 3600s).
|
|
1004
|
-
`
|
|
1005
|
-
);
|
|
1006
|
-
deps.renderer.write("\n");
|
|
1007
|
-
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
1008
|
-
`);
|
|
1009
|
-
}
|
|
1010
1024
|
export {
|
|
1011
1025
|
hqCmd
|
|
1012
1026
|
};
|
|
1013
|
-
//# sourceMappingURL=hq-
|
|
1027
|
+
//# sourceMappingURL=hq-V2M4IYCI.js.map
|
|
@@ -22,6 +22,7 @@ export declare class LoginAttemptStore {
|
|
|
22
22
|
private store;
|
|
23
23
|
private writeTimer;
|
|
24
24
|
private dirty;
|
|
25
|
+
private writeTail;
|
|
25
26
|
private readonly filePath;
|
|
26
27
|
private readonly debounceMs;
|
|
27
28
|
private readonly retentionMs;
|
|
@@ -92,6 +93,7 @@ export declare class LoginAttemptStore {
|
|
|
92
93
|
flush(): Promise<void>;
|
|
93
94
|
private scheduleWrite;
|
|
94
95
|
private writeToDisk;
|
|
96
|
+
private writeSnapshotToDisk;
|
|
95
97
|
/** Iterate entries (for cleanup timers). */
|
|
96
98
|
entries(): IterableIterator<[string, LoginAttemptEntry]>;
|
|
97
99
|
}
|