@securecoms/agent-bridge 0.30.0 → 0.30.2
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/README.md +77 -6
- package/dist/bin.d.ts +101 -0
- package/dist/bin.js +1102 -161
- package/dist/bridge-agent.d.ts +60 -0
- package/dist/config.d.ts +13 -0
- package/dist/errors.d.ts +1 -1
- package/dist/index.js +335 -27
- package/dist/preflight-upgrade.d.cts +0 -2
- package/dist/preflight.cjs +51 -49
- package/dist/preflight.d.cts +14 -0
- package/dist/service/credential-arg.d.ts +23 -0
- package/dist/service/install-prep.d.ts +21 -1
- package/dist/service/install.d.ts +7 -0
- package/dist/service/instance-lock.d.ts +88 -0
- package/dist/service/launchd.d.ts +1 -1
- package/dist/service/resolve-node.d.ts +1 -0
- package/dist/service/status.d.ts +3 -5
- package/dist/service/systemd.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/ws-server.d.ts +4 -0
- package/package.json +2 -2
package/dist/bridge-agent.d.ts
CHANGED
|
@@ -353,6 +353,9 @@ export interface BridgeAgentDeps {
|
|
|
353
353
|
transport?: any;
|
|
354
354
|
backend?: any;
|
|
355
355
|
fetchImpl?: typeof fetch;
|
|
356
|
+
/** TEST SEAM: WebSocket constructor for the real RestTransport's delivery-ping
|
|
357
|
+
* socket. Production leaves it undefined (globalThis.WebSocket). */
|
|
358
|
+
wsImpl?: typeof WebSocket;
|
|
356
359
|
/**
|
|
357
360
|
* Round 5 (runtime config delivery): the home directory under which the
|
|
358
361
|
* managed runtime-config directory lives. Injected only by tests, so they can
|
|
@@ -714,6 +717,15 @@ export declare class RoomClassChangedSendError extends SendForbiddenError {
|
|
|
714
717
|
* `activeGroupId` is the group the backend named, or null when the channel has
|
|
715
718
|
* no active group (fail closed: nothing to converge to).
|
|
716
719
|
*/
|
|
720
|
+
/**
|
|
721
|
+
* C10 (spec P-15, §4.1.6): start() was superseded (4409) before it finished.
|
|
722
|
+
* start() has already run the memoized close() quiesce when this is thrown, and
|
|
723
|
+
* armed none of its timers or the receive pump. runMode catches it: the process
|
|
724
|
+
* stays alive holding the lock and the port, and serves no route.
|
|
725
|
+
*/
|
|
726
|
+
export declare class SessionSupersededError extends Error {
|
|
727
|
+
constructor();
|
|
728
|
+
}
|
|
717
729
|
export declare class GroupSupersededSendError extends Error {
|
|
718
730
|
readonly channelId: string;
|
|
719
731
|
readonly activeGroupId: string | null;
|
|
@@ -780,6 +792,13 @@ export declare class BridgeAgent {
|
|
|
780
792
|
private readonly backend;
|
|
781
793
|
private readonly custody;
|
|
782
794
|
private readonly fetchImpl;
|
|
795
|
+
/** P-1: set once a 4409 close says another copy took this agent's session.
|
|
796
|
+
* The gated fetch built in the constructor refuses every request after it. */
|
|
797
|
+
private sessionSuperseded;
|
|
798
|
+
/** C9: who hears `session_superseded` (runMode's quiesce). */
|
|
799
|
+
private readonly sessionSupersededListeners;
|
|
800
|
+
/** C9 (spec §4.1.6, low 3): the one close() run every caller shares. */
|
|
801
|
+
private closing;
|
|
783
802
|
/** Round 5: home for the managed runtime-config directory (test seam). */
|
|
784
803
|
private readonly home;
|
|
785
804
|
private readonly grantWriters;
|
|
@@ -1243,6 +1262,12 @@ export declare class BridgeAgent {
|
|
|
1243
1262
|
readonly action: AgentActionAPI;
|
|
1244
1263
|
private readonly waiters;
|
|
1245
1264
|
private pingHandle?;
|
|
1265
|
+
/** C10 (P-15): the delivery-ping subscription start() opens at its top,
|
|
1266
|
+
* held unconsumed until startReceivePump() takes it. */
|
|
1267
|
+
private earlyPings;
|
|
1268
|
+
/** C10 fix round 1: settles (never rejects) when start()'s body does; close()
|
|
1269
|
+
* awaits it, bounded, so the store never closes under a start() step. */
|
|
1270
|
+
private startInFlight;
|
|
1246
1271
|
private safetyTimer?;
|
|
1247
1272
|
/** The ingest cycle now running, if any (see ingestOnce: single-flight). */
|
|
1248
1273
|
private ingestInFlight;
|
|
@@ -1490,7 +1515,24 @@ export declare class BridgeAgent {
|
|
|
1490
1515
|
* shed so a silently-dropping daemon stays observable (item 3 / ADR-0002).
|
|
1491
1516
|
*/
|
|
1492
1517
|
private capBuffer;
|
|
1518
|
+
/**
|
|
1519
|
+
* C10 (spec P-15, OQ-8 (b)): subscribe early, consume late. The
|
|
1520
|
+
* delivery-ping socket opens here, before anything else, so this copy claims
|
|
1521
|
+
* the device's session (and another copy gets its 4409) BEFORE this copy's
|
|
1522
|
+
* boot drain runs. The pings it carries are NOT consumed until
|
|
1523
|
+
* startReceivePump(), the same place as before: starting the pump first is
|
|
1524
|
+
* still forbidden (DRAIN BEFORE ROTATE, startBody).
|
|
1525
|
+
*
|
|
1526
|
+
* A 4409 during start() (audit H-3): the gated fetch is already set (C9 step
|
|
1527
|
+
* 0). start() then arms nothing more (supersededDuringStart before each
|
|
1528
|
+
* timer and before the pump), runs the memoized close() quiesce, and rejects
|
|
1529
|
+
* with SessionSupersededError. A step that FAILED because of the supersede
|
|
1530
|
+
* (a refused fetch, a store the quiesce closed) is the same outcome.
|
|
1531
|
+
*/
|
|
1493
1532
|
start(): Promise<void>;
|
|
1533
|
+
/** C10: true once a 4409 landed; checked before each arming step of start(). */
|
|
1534
|
+
private supersededDuringStart;
|
|
1535
|
+
private startBody;
|
|
1494
1536
|
/**
|
|
1495
1537
|
* #811 L-1: send the re-Welcome signal ONCE for each channel whose onWedged
|
|
1496
1538
|
* heal the boot drain refused. Runs after the drain settled and after the
|
|
@@ -3485,5 +3527,23 @@ export declare class BridgeAgent {
|
|
|
3485
3527
|
* and zero on restart (spec §5.5). */
|
|
3486
3528
|
build: string;
|
|
3487
3529
|
};
|
|
3530
|
+
/** C9: `session_superseded` once a 4409 said another copy took this
|
|
3531
|
+
* agent's session (the gated fetch already refuses every request). The
|
|
3532
|
+
* local HTTP routes read it: every route but `/healthz` answers 503. */
|
|
3533
|
+
get sessionState(): "live" | "session_superseded";
|
|
3534
|
+
/** C9: subscribe to `session_superseded`. runMode subscribes right after
|
|
3535
|
+
* construction, before start(), so a 4409 during start() is heard too. */
|
|
3536
|
+
on(event: "session_superseded", listener: () => void): () => void;
|
|
3537
|
+
/** P-1 step 0, then the event (spec §4.1.6): another copy of this agent took
|
|
3538
|
+
* the session (4409). The gated-fetch switch is set FIRST, so no HTTP
|
|
3539
|
+
* request leaves the process after this, whatever a listener does. */
|
|
3540
|
+
private onSessionSuperseded;
|
|
3541
|
+
/**
|
|
3542
|
+
* Idempotent (C9, spec §4.1.6 low 3): every call returns the FIRST call's
|
|
3543
|
+
* promise, so a SIGTERM during or after the supersede quiesce never runs
|
|
3544
|
+
* store.close() twice. A rejected close stays rejected: a retry would close
|
|
3545
|
+
* the store a second time.
|
|
3546
|
+
*/
|
|
3488
3547
|
close(): Promise<void>;
|
|
3548
|
+
private closeOnce;
|
|
3489
3549
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -56,6 +56,19 @@ export interface BridgeConfig {
|
|
|
56
56
|
ownerGrantPin?: OwnerGrantPinResult;
|
|
57
57
|
}
|
|
58
58
|
export declare const REQUIRED: readonly ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
|
|
59
|
+
export type ConfigErrorReason = "credential_not_found" | "credential_unreadable" | "credential_not_json" | "credential_missing_field" | "credential_voice_invalid";
|
|
60
|
+
/**
|
|
61
|
+
* A key-file load failure with a fixed reason code, set by the step that
|
|
62
|
+
* failed (spec 2026-10-15 §5.2). Callers map the code to a log field and a
|
|
63
|
+
* fixed human line; nothing reads `message`, which carries no path, no
|
|
64
|
+
* identifier and no upstream error text.
|
|
65
|
+
*/
|
|
66
|
+
export declare class ConfigError extends Error {
|
|
67
|
+
readonly reason: ConfigErrorReason;
|
|
68
|
+
readonly field?: (typeof REQUIRED)[number] | undefined;
|
|
69
|
+
readonly source?: "file" | "env" | undefined;
|
|
70
|
+
constructor(reason: ConfigErrorReason, field?: (typeof REQUIRED)[number] | undefined, source?: "file" | "env" | undefined);
|
|
71
|
+
}
|
|
59
72
|
export declare function loadConfig(opts: {
|
|
60
73
|
credentialPath: string;
|
|
61
74
|
storePath?: string;
|
package/dist/errors.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* WebSocket returns `{type:"error", error, message, detail?}`. A client gets the
|
|
7
7
|
* same `error` code regardless of which transport it used. (A2A §9.5/§10.6 pattern.)
|
|
8
8
|
*/
|
|
9
|
-
export type BridgeErrorCode = "unauthorized" | "forbidden_origin" | "not_found" | "invalid_request" | "invalid_json" | "body_too_large" | "channel_pending" | "rate_limited" | "agent_paused" | "send_forbidden" | "group_superseded" | "unknown_action_run" | "vault_integrity_failed" | "vault_ref_changed" | "internal";
|
|
9
|
+
export type BridgeErrorCode = "unauthorized" | "forbidden_origin" | "not_found" | "invalid_request" | "invalid_json" | "body_too_large" | "channel_pending" | "rate_limited" | "agent_paused" | "send_forbidden" | "group_superseded" | "unknown_action_run" | "vault_integrity_failed" | "vault_ref_changed" | "session_superseded" | "internal";
|
|
10
10
|
export interface BridgeErrorSpec {
|
|
11
11
|
/** HTTP status this code maps to (the WS binding ignores it). */
|
|
12
12
|
http: number;
|