@schlessera/brain-ui-server 0.34.0 → 0.35.0
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 +28 -0
- package/dist/activity/notify.d.ts.map +1 -1
- package/dist/activity/notify.js +18 -8
- package/dist/activity/notify.js.map +1 -1
- package/dist/activity/push-sender.d.ts +7 -3
- package/dist/activity/push-sender.d.ts.map +1 -1
- package/dist/activity/push-sender.js +45 -11
- package/dist/activity/push-sender.js.map +1 -1
- package/dist/activity/query.d.ts.map +1 -1
- package/dist/activity/query.js +8 -0
- package/dist/activity/query.js.map +1 -1
- package/dist/activity/recorder.d.ts +11 -1
- package/dist/activity/recorder.d.ts.map +1 -1
- package/dist/activity/recorder.js +52 -2
- package/dist/activity/recorder.js.map +1 -1
- package/dist/activity/runtime.d.ts.map +1 -1
- package/dist/activity/runtime.js +2 -5
- package/dist/activity/runtime.js.map +1 -1
- package/dist/activity/sql.d.ts +34 -0
- package/dist/activity/sql.d.ts.map +1 -0
- package/dist/activity/sql.js +114 -0
- package/dist/activity/sql.js.map +1 -0
- package/dist/activity/store.d.ts +7 -0
- package/dist/activity/store.d.ts.map +1 -1
- package/dist/activity/store.js +48 -113
- package/dist/activity/store.js.map +1 -1
- package/dist/activity/stream.d.ts +3 -1
- package/dist/activity/stream.d.ts.map +1 -1
- package/dist/activity/stream.js +32 -17
- package/dist/activity/stream.js.map +1 -1
- package/dist/app-env.d.ts +8 -0
- package/dist/app-env.d.ts.map +1 -0
- package/dist/app-env.js +2 -0
- package/dist/app-env.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +28 -3
- package/dist/app.js.map +1 -1
- package/dist/brain/client.d.ts +4 -2
- package/dist/brain/client.d.ts.map +1 -1
- package/dist/brain/client.js +60 -20
- package/dist/brain/client.js.map +1 -1
- package/dist/brain/types.d.ts +9 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/cron/run-job.d.ts.map +1 -1
- package/dist/cron/run-job.js +60 -10
- package/dist/cron/run-job.js.map +1 -1
- package/dist/db/principals.d.ts +72 -0
- package/dist/db/principals.d.ts.map +1 -0
- package/dist/db/principals.js +294 -0
- package/dist/db/principals.js.map +1 -0
- package/dist/files/walker.d.ts.map +1 -1
- package/dist/files/walker.js +6 -1
- package/dist/files/walker.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +37 -9
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +148 -74
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/passkeys.d.ts +9 -7
- package/dist/middleware/passkeys.d.ts.map +1 -1
- package/dist/middleware/passkeys.js +25 -7
- package/dist/middleware/passkeys.js.map +1 -1
- package/dist/middleware/principals.d.ts +18 -0
- package/dist/middleware/principals.d.ts.map +1 -0
- package/dist/middleware/principals.js +138 -0
- package/dist/middleware/principals.js.map +1 -0
- package/dist/middleware/require-owner.d.ts +5 -0
- package/dist/middleware/require-owner.d.ts.map +1 -0
- package/dist/middleware/require-owner.js +10 -0
- package/dist/middleware/require-owner.js.map +1 -0
- package/dist/observability/loggers.js +1 -1
- package/dist/observability/loggers.js.map +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +3 -0
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/brain.d.ts.map +1 -1
- package/dist/routes/brain.js +102 -63
- package/dist/routes/brain.js.map +1 -1
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +7 -2
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/push.d.ts +61 -2
- package/dist/routes/push.d.ts.map +1 -1
- package/dist/routes/push.js +8 -3
- package/dist/routes/push.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +30 -4
- package/dist/routes/sessions.js.map +1 -1
- package/dist/share/staging.d.ts.map +1 -1
- package/dist/share/staging.js +11 -4
- package/dist/share/staging.js.map +1 -1
- package/dist/ws/bridge.d.ts.map +1 -1
- package/dist/ws/bridge.js +6 -2
- package/dist/ws/bridge.js.map +1 -1
- package/dist/ws/clients.d.ts +9 -2
- package/dist/ws/clients.d.ts.map +1 -1
- package/dist/ws/clients.js +44 -6
- package/dist/ws/clients.js.map +1 -1
- package/dist/ws/connection.d.ts +7 -4
- package/dist/ws/connection.d.ts.map +1 -1
- package/dist/ws/connection.js +83 -12
- package/dist/ws/connection.js.map +1 -1
- package/dist/ws/dispatch.d.ts +12 -1
- package/dist/ws/dispatch.d.ts.map +1 -1
- package/dist/ws/dispatch.js +46 -6
- package/dist/ws/dispatch.js.map +1 -1
- package/dist/ws/history.d.ts.map +1 -1
- package/dist/ws/history.js +7 -5
- package/dist/ws/history.js.map +1 -1
- package/dist/ws/host.d.ts +22 -0
- package/dist/ws/host.d.ts.map +1 -1
- package/dist/ws/host.js +39 -1
- package/dist/ws/host.js.map +1 -1
- package/dist/ws/run-session.d.ts +7 -7
- package/dist/ws/run-session.d.ts.map +1 -1
- package/dist/ws/run-session.js +208 -52
- package/dist/ws/run-session.js.map +1 -1
- package/dist/ws/shrink.d.ts +3 -1
- package/dist/ws/shrink.d.ts.map +1 -1
- package/dist/ws/shrink.js +46 -16
- package/dist/ws/shrink.js.map +1 -1
- package/dist/ws/turns.d.ts +58 -3
- package/dist/ws/turns.d.ts.map +1 -1
- package/dist/ws/turns.js +101 -2
- package/dist/ws/turns.js.map +1 -1
- package/migrations/011_principals.sql +13 -0
- package/migrations/012_activity_principals.sql +12 -0
- package/migrations/013_push_subscription_principals.sql +7 -0
- package/migrations/014_invalidate_legacy_sessions.sql +14 -0
- package/package.json +3 -3
- package/src/activity/notify.ts +16 -7
- package/src/activity/push-sender.ts +79 -16
- package/src/activity/query.ts +8 -0
- package/src/activity/recorder.ts +68 -3
- package/src/activity/runtime.ts +2 -5
- package/src/activity/sql.ts +122 -0
- package/src/activity/store.ts +73 -155
- package/src/activity/stream.ts +37 -17
- package/src/app-env.ts +8 -0
- package/src/app.ts +33 -4
- package/src/brain/client.ts +61 -20
- package/src/brain/types.ts +10 -0
- package/src/cron/run-job.ts +41 -17
- package/src/db/principals.ts +452 -0
- package/src/files/walker.ts +5 -1
- package/src/index.ts +6 -1
- package/src/middleware/auth.ts +241 -81
- package/src/middleware/passkeys.ts +35 -14
- package/src/middleware/principals.ts +189 -0
- package/src/middleware/require-owner.ts +13 -0
- package/src/observability/loggers.ts +1 -1
- package/src/routes/activity.ts +3 -0
- package/src/routes/brain.ts +107 -70
- package/src/routes/files.ts +10 -5
- package/src/routes/push.ts +11 -5
- package/src/routes/sessions.ts +45 -20
- package/src/share/staging.ts +11 -4
- package/src/ws/bridge.ts +14 -2
- package/src/ws/clients.ts +52 -7
- package/src/ws/connection.ts +98 -20
- package/src/ws/dispatch.ts +66 -6
- package/src/ws/history.ts +7 -5
- package/src/ws/host.ts +59 -1
- package/src/ws/run-session.ts +247 -74
- package/src/ws/shrink.ts +48 -14
- package/src/ws/turns.ts +136 -5
package/dist/ws/connection.js
CHANGED
|
@@ -31,6 +31,8 @@ import { handleClientMessage } from "./dispatch.js";
|
|
|
31
31
|
export { websocket };
|
|
32
32
|
const CONNECTION_LIMIT_CLOSE_CODE = 4008;
|
|
33
33
|
const CONNECTION_LIMIT_CLOSE_REASON = "Connection limit reached";
|
|
34
|
+
const REVOKED_BEFORE_ADMISSION_CLOSE_CODE = 1008;
|
|
35
|
+
const REVOKED_BEFORE_ADMISSION_CLOSE_REASON = "Sessions invalidated";
|
|
34
36
|
/**
|
|
35
37
|
* The socket lifecycle handlers for one host, separate from the Hono upgrade
|
|
36
38
|
* that wraps them.
|
|
@@ -40,16 +42,33 @@ const CONNECTION_LIMIT_CLOSE_REASON = "Connection limit reached";
|
|
|
40
42
|
* production runs, which is what makes an assertion about a dropped frame an
|
|
41
43
|
* assertion about the shipped code rather than about a re-implementation.
|
|
42
44
|
*/
|
|
43
|
-
export function createWsHandlers(host) {
|
|
45
|
+
export function createWsHandlers(host, principal) {
|
|
44
46
|
// One bucket per connection, created here so it lives and dies with the
|
|
45
47
|
// socket rather than in a map keyed by something a peer controls.
|
|
46
48
|
const limiter = host.newRateLimiter();
|
|
49
|
+
// Authentication can await before it reaches this handler. Re-read durable
|
|
50
|
+
// validity as the coordinator constructs and synchronously registers the
|
|
51
|
+
// context, so there is no unregistered authorization state to lose.
|
|
52
|
+
const authorization = host.coordinator.openAuthorization({
|
|
53
|
+
principalId: principal.id,
|
|
54
|
+
expiresAt: principal.expiresAt,
|
|
55
|
+
valid: host.isPrincipalValid(principal),
|
|
56
|
+
});
|
|
47
57
|
// Per-connection negotiation state: what revision this client declared.
|
|
48
58
|
// Lives with the socket, like the limiter.
|
|
49
|
-
const connection = {
|
|
59
|
+
const connection = {
|
|
60
|
+
principal,
|
|
61
|
+
authorization,
|
|
62
|
+
};
|
|
50
63
|
return {
|
|
51
64
|
async onOpen(_evt, ws) {
|
|
52
|
-
if (!
|
|
65
|
+
if (!connection.authorization.valid) {
|
|
66
|
+
connection.authorization.release();
|
|
67
|
+
ws.close(REVOKED_BEFORE_ADMISSION_CLOSE_CODE, REVOKED_BEFORE_ADMISSION_CLOSE_REASON);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!host.clients.add(ws, principal.id, { onRemove: connection.authorization.release })) {
|
|
71
|
+
connection.authorization.release();
|
|
53
72
|
host.reportRefusedConnection();
|
|
54
73
|
// Hono's WSContext always exposes close(); the local structural socket
|
|
55
74
|
// type keeps it optional because send-only test/dispatch fakes never
|
|
@@ -92,11 +111,15 @@ export function createWsHandlers(host) {
|
|
|
92
111
|
providerId: turn.providerId ?? catalog.getStoredProviderId(sid) ?? undefined,
|
|
93
112
|
backendId: catalog.getStoredBackendId(sid) ?? turn.backend.id,
|
|
94
113
|
}, turn));
|
|
114
|
+
// Snapshot-on-connect owns a lease separate from the socket: a close
|
|
115
|
+
// while history loads must not make this work invisible to revocation.
|
|
116
|
+
const releaseAuthorization = connection.authorization.retain();
|
|
95
117
|
try {
|
|
96
118
|
const backend = await host.registry.getBackendForSession(catalog.getStoredBackendId(sid) ?? turn.backend.id);
|
|
97
119
|
const history = await backend.getHistory(sid);
|
|
98
|
-
if (history.length > 0)
|
|
120
|
+
if (connection.authorization.valid && history.length > 0) {
|
|
99
121
|
sendSessionHistory(ws, sid, history);
|
|
122
|
+
}
|
|
100
123
|
}
|
|
101
124
|
catch (err) {
|
|
102
125
|
host.log.emit({
|
|
@@ -106,13 +129,16 @@ export function createWsHandlers(host) {
|
|
|
106
129
|
});
|
|
107
130
|
}
|
|
108
131
|
finally {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
132
|
+
releaseAuthorization();
|
|
133
|
+
if (connection.authorization.valid) {
|
|
134
|
+
host.sendMessage(ws, withTurnScope({
|
|
135
|
+
type: "status",
|
|
136
|
+
status: "thinking",
|
|
137
|
+
detail: "Session in progress",
|
|
138
|
+
sessionId: sid,
|
|
139
|
+
}, turn));
|
|
140
|
+
resendPendingInteractive(host, ws);
|
|
141
|
+
}
|
|
116
142
|
}
|
|
117
143
|
return;
|
|
118
144
|
}
|
|
@@ -124,6 +150,14 @@ export function createWsHandlers(host) {
|
|
|
124
150
|
resendPendingInteractive(host, ws);
|
|
125
151
|
},
|
|
126
152
|
onMessage(evt, ws) {
|
|
153
|
+
if (connection.authorization.valid &&
|
|
154
|
+
connection.authorization.expiresAt <= Date.now()) {
|
|
155
|
+
host.expireAuthorizationContexts();
|
|
156
|
+
}
|
|
157
|
+
if (!connection.authorization.valid) {
|
|
158
|
+
host.reportDroppedFrame("revoked_principal");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
127
161
|
// Boundary validation (rev 2): byte cap + JSON decode + schema, in one
|
|
128
162
|
// place. No more casting client JSON to ClientMessage.
|
|
129
163
|
//
|
|
@@ -160,6 +194,12 @@ export function createWsHandlers(host) {
|
|
|
160
194
|
host.sendMessage(ws, { type: "error", code: "PARSE_ERROR", message: parsed.error });
|
|
161
195
|
return;
|
|
162
196
|
}
|
|
197
|
+
// Parsing is synchronous, but dispatch deliberately starts on a
|
|
198
|
+
// microtask. Keep this shared authority discoverable across that gap —
|
|
199
|
+
// including after an ordinary disconnect removes the admitted client.
|
|
200
|
+
// runSession adds its own reference before this one is released, so a
|
|
201
|
+
// chat startup remains continuously revocable through routing/billing.
|
|
202
|
+
const releaseAuthorization = connection.authorization.retain();
|
|
163
203
|
// handleClientMessage is async — a rejection must not escape as an
|
|
164
204
|
// unhandled rejection with no frame sent.
|
|
165
205
|
void Promise.resolve()
|
|
@@ -180,9 +220,18 @@ export function createWsHandlers(host) {
|
|
|
180
220
|
code: "INTERNAL_ERROR",
|
|
181
221
|
message: "Failed to handle message",
|
|
182
222
|
});
|
|
223
|
+
})
|
|
224
|
+
.finally(() => {
|
|
225
|
+
releaseAuthorization();
|
|
183
226
|
});
|
|
184
227
|
},
|
|
185
228
|
onClose(evt, ws) {
|
|
229
|
+
// Closure is not authorization: a frame parsed before this callback can
|
|
230
|
+
// still be mid-dispatch, and an activity_subscribe landing after the
|
|
231
|
+
// cleanup below would re-register the dead socket and keep the activity
|
|
232
|
+
// poller awake. Authorization stays whatever it is; this says the
|
|
233
|
+
// transport is gone.
|
|
234
|
+
connection.closed = true;
|
|
186
235
|
host.log.emit({ severityText: "INFO", body: "client disconnected" });
|
|
187
236
|
// No onError here on purpose: hono's Bun adapter never dispatches it
|
|
188
237
|
// (only open/message/close reach these handlers), so a transport failure
|
|
@@ -194,6 +243,7 @@ export function createWsHandlers(host) {
|
|
|
194
243
|
host.reportAbnormalClose(code);
|
|
195
244
|
}
|
|
196
245
|
host.clients.remove(ws);
|
|
246
|
+
connection.authorization.release();
|
|
197
247
|
host.activity?.stream.dropConnection(ws);
|
|
198
248
|
// Turns keep running in the background. Once the LAST client leaves,
|
|
199
249
|
// reject only the requests that need a live client RIGHT NOW (location,
|
|
@@ -207,10 +257,31 @@ export function createWsHandlers(host) {
|
|
|
207
257
|
host.coordinator.drainClientBoundForTurn(turn, "Client disconnected");
|
|
208
258
|
}
|
|
209
259
|
},
|
|
260
|
+
/** The HTTP upgrade failed, so no socket lifecycle callback will clean up. */
|
|
261
|
+
onUpgradeFailed() {
|
|
262
|
+
connection.authorization.release();
|
|
263
|
+
},
|
|
210
264
|
};
|
|
211
265
|
}
|
|
212
266
|
/** Build the Hono WebSocket upgrade handler bound to one host. */
|
|
213
267
|
export function createWsUpgrade(host) {
|
|
214
|
-
return
|
|
268
|
+
return async (c, next) => {
|
|
269
|
+
const principal = c.get("principal");
|
|
270
|
+
if (!principal) {
|
|
271
|
+
return c.json({ error: "Authentication required" }, 401);
|
|
272
|
+
}
|
|
273
|
+
const handlers = createWsHandlers(host, principal);
|
|
274
|
+
const upgrade = upgradeWebSocket(() => handlers);
|
|
275
|
+
try {
|
|
276
|
+
return await upgrade(c, async () => {
|
|
277
|
+
handlers.onUpgradeFailed();
|
|
278
|
+
await next();
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
handlers.onUpgradeFailed();
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
215
286
|
}
|
|
216
287
|
//# sourceMappingURL=connection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/ws/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/ws/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/dispatch.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import type { ClientMessage } from "@schlessera/brain-ui-sdk/protocol";
|
|
2
2
|
import type { WSContext } from "./clients.js";
|
|
3
|
+
import type { AuthorizationContext } from "./turns.js";
|
|
3
4
|
import type { WsHost } from "./host.js";
|
|
4
5
|
/** Per-connection negotiation state, owned by the socket handler. */
|
|
5
6
|
export interface ConnectionState {
|
|
7
|
+
/**
|
|
8
|
+
* The transport is gone. Set by onClose, and separate from `authorization`
|
|
9
|
+
* because a disconnect is not a revocation: work already underway keeps its
|
|
10
|
+
* authority, but nothing may register new per-connection state afterwards.
|
|
11
|
+
*/
|
|
12
|
+
closed?: boolean;
|
|
13
|
+
/** Principal resolved once at the WebSocket upgrade boundary. */
|
|
14
|
+
principal: import("../db/principals.js").Principal;
|
|
15
|
+
/** Mutable in-memory decision invalidated synchronously by revocation. */
|
|
16
|
+
authorization: AuthorizationContext;
|
|
6
17
|
/** Revision the client declared via `client_hello`; absent means rev 2. */
|
|
7
18
|
protocolRev?: number;
|
|
8
19
|
}
|
|
@@ -22,5 +33,5 @@ export interface ConnectionState {
|
|
|
22
33
|
export declare function turnIdMatches(pending: {
|
|
23
34
|
turnId: string;
|
|
24
35
|
}, echoed: string | undefined, requireEcho: boolean): boolean;
|
|
25
|
-
export declare function handleClientMessage(host: WsHost, ws: WSContext, msg: ClientMessage, connection
|
|
36
|
+
export declare function handleClientMessage(host: WsHost, ws: WSContext, msg: ClientMessage, connection: ConnectionState): Promise<void>;
|
|
26
37
|
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/ws/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/ws/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,SAAS,EAAE,OAAO,qBAAqB,EAAE,SAAS,CAAC;IACnD,0EAA0E;IAC1E,aAAa,EAAE,oBAAoB,CAAC;IACpC,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,OAAO,GACnB,OAAO,CAGT;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,SAAS,EACb,GAAG,EAAE,aAAa,EAClB,UAAU,EAAE,eAAe,GAC1B,OAAO,CAAC,IAAI,CAAC,CAkPf"}
|
package/dist/ws/dispatch.js
CHANGED
|
@@ -21,7 +21,18 @@ export function turnIdMatches(pending, echoed, requireEcho) {
|
|
|
21
21
|
return !requireEcho;
|
|
22
22
|
return echoed === pending.turnId;
|
|
23
23
|
}
|
|
24
|
-
export async function handleClientMessage(host, ws, msg, connection
|
|
24
|
+
export async function handleClientMessage(host, ws, msg, connection) {
|
|
25
|
+
// The socket callback schedules dispatch on a microtask. Revocation may land
|
|
26
|
+
// after parsing but before this function begins, so repeat the in-memory
|
|
27
|
+
// check at the actual dispatch boundary.
|
|
28
|
+
if (connection.authorization.valid &&
|
|
29
|
+
connection.authorization.expiresAt <= Date.now()) {
|
|
30
|
+
host.expireAuthorizationContexts();
|
|
31
|
+
}
|
|
32
|
+
if (!connection.authorization.valid) {
|
|
33
|
+
host.reportDroppedFrame("revoked_principal");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
25
36
|
const { coordinator, catalog } = host;
|
|
26
37
|
const requireEcho = (connection.protocolRev ?? 2) >= PROTOCOL_REV_CLIENT_ECHO;
|
|
27
38
|
switch (msg.type) {
|
|
@@ -44,11 +55,13 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
44
55
|
return;
|
|
45
56
|
}
|
|
46
57
|
await handleChatMessage(host, ws, {
|
|
58
|
+
authorization: connection.authorization,
|
|
47
59
|
text: msg.text,
|
|
48
60
|
sessionId: msg.sessionId,
|
|
49
61
|
attachments: attachmentResult.attachments,
|
|
50
62
|
providerId: msg.providerId,
|
|
51
63
|
client: msg.client,
|
|
64
|
+
draftId: msg.draftId,
|
|
52
65
|
});
|
|
53
66
|
break;
|
|
54
67
|
}
|
|
@@ -56,6 +69,7 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
56
69
|
const pending = coordinator.pendingAskUser.get(msg.requestId);
|
|
57
70
|
if (pending && turnIdMatches(pending, msg.turnId, requireEcho)) {
|
|
58
71
|
coordinator.pendingAskUser.delete(msg.requestId);
|
|
72
|
+
pending.turn.recorder?.recordAskUserResponse(connection.authorization.principalId);
|
|
59
73
|
pending.resolve({ answers: msg.answers, annotations: msg.annotations });
|
|
60
74
|
}
|
|
61
75
|
break;
|
|
@@ -64,6 +78,7 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
64
78
|
const pending = coordinator.pendingAskUser.get(msg.requestId);
|
|
65
79
|
if (pending && turnIdMatches(pending, msg.turnId, requireEcho)) {
|
|
66
80
|
coordinator.pendingAskUser.delete(msg.requestId);
|
|
81
|
+
pending.turn.recorder?.recordCancellation(connection.authorization.principalId, "ask_user");
|
|
67
82
|
pending.reject(new Error(msg.reason || "User cancelled the question"));
|
|
68
83
|
}
|
|
69
84
|
break;
|
|
@@ -115,7 +130,10 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
115
130
|
}
|
|
116
131
|
pending.resolve(msg.updatedInput
|
|
117
132
|
? { behavior: "allow", updatedInput: msg.updatedInput }
|
|
118
|
-
: { behavior: "allow" }
|
|
133
|
+
: { behavior: "allow" }, {
|
|
134
|
+
principalId: connection.authorization.principalId,
|
|
135
|
+
...(msg.always && pending.request.kind !== "command" ? { always: true } : {}),
|
|
136
|
+
});
|
|
119
137
|
}
|
|
120
138
|
break;
|
|
121
139
|
}
|
|
@@ -123,15 +141,26 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
123
141
|
const pending = coordinator.pendingApprovals.get(msg.toolUseId);
|
|
124
142
|
if (pending && turnIdMatches(pending, msg.turnId, requireEcho)) {
|
|
125
143
|
coordinator.pendingApprovals.delete(msg.toolUseId);
|
|
126
|
-
pending.resolve({ behavior: "deny", message: msg.message });
|
|
144
|
+
pending.resolve({ behavior: "deny", message: msg.message }, { principalId: connection.authorization.principalId });
|
|
127
145
|
}
|
|
128
146
|
break;
|
|
129
147
|
}
|
|
130
148
|
case "cancel": {
|
|
131
149
|
if (msg.sessionId) {
|
|
132
150
|
const turn = coordinator.bySession.get(msg.sessionId);
|
|
133
|
-
if (turn)
|
|
151
|
+
if (turn) {
|
|
152
|
+
coordinator.recordCancellation(turn, connection.authorization.principalId);
|
|
134
153
|
coordinator.cancelTurn(turn, "Cancelled by user");
|
|
154
|
+
}
|
|
155
|
+
const starting = coordinator.startingBySession.get(msg.sessionId);
|
|
156
|
+
if (starting) {
|
|
157
|
+
starting.cancelled = true;
|
|
158
|
+
// Releasing here, not in runSession: a start cancelled before it
|
|
159
|
+
// becomes a turn never reaches the loop that would drain its queue.
|
|
160
|
+
for (const entry of starting.queue.splice(0))
|
|
161
|
+
entry.releaseAuthorization();
|
|
162
|
+
host.sendToClients({ type: "status", status: "idle", sessionId: msg.sessionId, detail: "Cancelled before starting" });
|
|
163
|
+
}
|
|
135
164
|
return;
|
|
136
165
|
}
|
|
137
166
|
// No sessionId: cancel the sole running session; ambiguous if several run.
|
|
@@ -145,14 +174,23 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
145
174
|
});
|
|
146
175
|
return;
|
|
147
176
|
}
|
|
148
|
-
|
|
177
|
+
const turn = [...coordinator.running][0];
|
|
178
|
+
coordinator.recordCancellation(turn, connection.authorization.principalId);
|
|
179
|
+
coordinator.cancelTurn(turn, "Cancelled by user");
|
|
149
180
|
break;
|
|
150
181
|
}
|
|
151
182
|
case "activity_subscribe": {
|
|
152
183
|
// View-scoped opt-in: without a subscription this connection never
|
|
153
184
|
// receives an activity frame. No turn correlation — subscriptions are
|
|
154
185
|
// connection state, not turn state.
|
|
155
|
-
|
|
186
|
+
//
|
|
187
|
+
// Dispatch starts on a microtask, so this can run after onClose already
|
|
188
|
+
// dropped the connection's subscriptions. Registering here would resurrect
|
|
189
|
+
// a dead socket in the registry and keep the activity poller alive for the
|
|
190
|
+
// life of the process.
|
|
191
|
+
if (connection.closed)
|
|
192
|
+
break;
|
|
193
|
+
host.activity?.stream.handleSubscribe(ws, msg, connection.authorization.principalId);
|
|
156
194
|
break;
|
|
157
195
|
}
|
|
158
196
|
case "activity_unsubscribe": {
|
|
@@ -170,6 +208,8 @@ export async function handleClientMessage(host, ws, msg, connection = {}) {
|
|
|
170
208
|
try {
|
|
171
209
|
const backend = await host.registry.getBackendForSession(catalog.getStoredBackendId(msg.sessionId));
|
|
172
210
|
const messages = await backend.getHistory(msg.sessionId);
|
|
211
|
+
if (!connection.authorization.valid)
|
|
212
|
+
return;
|
|
173
213
|
sendSessionHistory(ws, msg.sessionId, messages);
|
|
174
214
|
// A resume of a RUNNING session (reattach) must not report idle: idle
|
|
175
215
|
// would clear the client's running badge and finish its streaming
|
package/dist/ws/dispatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/ws/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/ws/dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/history.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/ws/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,cAAc,CAAC;AAGtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,qBAAqB,EAAE,GAChC,IAAI,
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/ws/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,cAAc,CAAC;AAGtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,qBAAqB,EAAE,GAChC,IAAI,CA+BN"}
|
package/dist/ws/history.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sendTo } from "./clients.js";
|
|
2
|
-
import { HISTORY_CHUNK_BYTES, shrinkForReplication } from "./shrink.js";
|
|
2
|
+
import { HISTORY_CHUNK_BYTES, jsonBytes, shrinkForReplication } from "./shrink.js";
|
|
3
3
|
/**
|
|
4
4
|
* Send a structured history to one socket as one or more `session_history`
|
|
5
5
|
* frames. Each message is size-bounded, then batched into byte-limited chunks
|
|
@@ -14,8 +14,7 @@ import { HISTORY_CHUNK_BYTES, shrinkForReplication } from "./shrink.js";
|
|
|
14
14
|
* silently overwrites the wrong pane).
|
|
15
15
|
*/
|
|
16
16
|
export function sendSessionHistory(ws, sessionId, messages) {
|
|
17
|
-
|
|
18
|
-
if (bounded.length === 0) {
|
|
17
|
+
if (messages.length === 0) {
|
|
19
18
|
sendTo(ws, { type: "session_history", sessionId, messages: [] });
|
|
20
19
|
return;
|
|
21
20
|
}
|
|
@@ -33,8 +32,11 @@ export function sendSessionHistory(ws, sessionId, messages) {
|
|
|
33
32
|
batch = [];
|
|
34
33
|
batchBytes = 0;
|
|
35
34
|
};
|
|
36
|
-
for (const
|
|
37
|
-
|
|
35
|
+
for (const original of messages) {
|
|
36
|
+
// Reserve the frame wrapper separately: bounding a message to the entire
|
|
37
|
+
// frame cap caused sendTo to shrink its parent history array a second time.
|
|
38
|
+
const message = shrinkForReplication(original, HISTORY_CHUNK_BYTES);
|
|
39
|
+
const size = jsonBytes(message) + 1; // comma between messages
|
|
38
40
|
if (batch.length > 0 && batchBytes + size > HISTORY_CHUNK_BYTES)
|
|
39
41
|
flush();
|
|
40
42
|
batch.push(message);
|
package/dist/ws/history.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/ws/history.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/ws/history.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,EAAa,EACb,SAAiB,EACjB,QAAiC;IAEjC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,IAAI,KAAK,GAA4B,EAAE,CAAC;IACxC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,MAAM,CAAC,EAAE,EAAE;YACT,IAAI,EAAE,iBAAiB;YACvB,SAAS;YACT,QAAQ,EAAE,KAAK;YACf,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SACrC,CAAC,CAAC;QACH,OAAO,GAAG,KAAK,CAAC;QAChB,KAAK,GAAG,EAAE,CAAC;QACX,UAAU,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAChC,yEAAyE;QACzE,4EAA4E;QAC5E,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,yBAAyB;QAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,GAAG,IAAI,GAAG,mBAAmB;YAAE,KAAK,EAAE,CAAC;QACzE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,UAAU,IAAI,IAAI,CAAC;IACrB,CAAC;IACD,KAAK,EAAE,CAAC;AACV,CAAC"}
|
package/dist/ws/host.d.ts
CHANGED
|
@@ -7,10 +7,14 @@ import { type Observability } from "../observability/index.js";
|
|
|
7
7
|
import { FrameRateLimiter } from "./rate-limit.js";
|
|
8
8
|
import type { ActivityStore } from "../activity/store.js";
|
|
9
9
|
import type { ActivityStream } from "../activity/stream.js";
|
|
10
|
+
import type { PushSender } from "../activity/push-sender.js";
|
|
11
|
+
import type { Principal } from "../db/principals.js";
|
|
10
12
|
/** The activity record and its live stream, when the host records activity. */
|
|
11
13
|
export interface ActivityRuntime {
|
|
12
14
|
store: ActivityStore;
|
|
13
15
|
stream: ActivityStream;
|
|
16
|
+
/** Push bindings invalidated through the same principal-revocation boundary. */
|
|
17
|
+
pushSender?: Pick<PushSender, "unbindPrincipal">;
|
|
14
18
|
/** Read seam for the agent-facing query tool (bridge.queryActivity). */
|
|
15
19
|
query?: (query: import("@schlessera/brain-ui-sdk/server").ActivityQuery) => Record<string, unknown>;
|
|
16
20
|
}
|
|
@@ -70,6 +74,13 @@ export interface WsHostOptions {
|
|
|
70
74
|
};
|
|
71
75
|
/** Maximum WebSocket connections accepted by this host (default 32). */
|
|
72
76
|
wsMaxConnections?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Final synchronous check before a resolved principal becomes discoverable
|
|
79
|
+
* to in-memory revocation. Production re-reads the principal row here; a
|
|
80
|
+
* host without durable authentication (including focused tests) accepts the
|
|
81
|
+
* already-resolved principal.
|
|
82
|
+
*/
|
|
83
|
+
isPrincipalValid?: (principal: Principal) => boolean;
|
|
73
84
|
/**
|
|
74
85
|
* Activity recording (span store + live stream). Optional: a host without
|
|
75
86
|
* one records nothing and never sends activity frames — which is also what
|
|
@@ -120,6 +131,7 @@ export declare class WsHost {
|
|
|
120
131
|
ratePerSecond: number;
|
|
121
132
|
burst: number;
|
|
122
133
|
} | null;
|
|
134
|
+
readonly isPrincipalValid: (principal: Principal) => boolean;
|
|
123
135
|
readonly activity: ActivityRuntime | null;
|
|
124
136
|
readonly toolPermissions: ToolPermissions | null;
|
|
125
137
|
/** Scoped instruments, resolved once — `[ws]` is the existing log prefix. */
|
|
@@ -130,6 +142,7 @@ export declare class WsHost {
|
|
|
130
142
|
private readonly turnsFailed;
|
|
131
143
|
private readonly wsErrors;
|
|
132
144
|
private readonly connectionsRefused;
|
|
145
|
+
private readonly authorizationExpiryTimer;
|
|
133
146
|
constructor(options: WsHostOptions);
|
|
134
147
|
/** A metering bucket for one new connection, or null when metering is off. */
|
|
135
148
|
newRateLimiter(): FrameRateLimiter | null;
|
|
@@ -167,6 +180,15 @@ export declare class WsHost {
|
|
|
167
180
|
reportAbnormalClose(code: number): void;
|
|
168
181
|
/** Fan a frame out to every attached client (size-bounded per frame). */
|
|
169
182
|
sendToClients(msg: ServerMessage): void;
|
|
183
|
+
/**
|
|
184
|
+
* Apply principal-store revocation to every in-memory authority boundary.
|
|
185
|
+
* Running turns are marked but deliberately not aborted.
|
|
186
|
+
*/
|
|
187
|
+
revokePrincipals(principalIds: readonly string[], code: number, reason: string): void;
|
|
188
|
+
/** Route expiry through the same full boundary as explicit revocation. */
|
|
189
|
+
expireAuthorizationContexts(now?: number): void;
|
|
190
|
+
/** Stop host-owned timers during application/test teardown. */
|
|
191
|
+
close(): void;
|
|
170
192
|
/** Send a frame to one specific socket (size-bounded). */
|
|
171
193
|
sendMessage(ws: WSContext, msg: ServerMessage): void;
|
|
172
194
|
}
|
package/dist/ws/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,SAAS,EAAU,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/ws/host.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/host.js
CHANGED
|
@@ -6,6 +6,9 @@ import { FrameRateLimiter } from "./rate-limit.js";
|
|
|
6
6
|
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
7
7
|
/** Default cap on concurrently RUNNING sessions (MAX_CONCURRENT_SESSIONS). */
|
|
8
8
|
const DEFAULT_MAX_CONCURRENT_SESSIONS = 3;
|
|
9
|
+
const AUTHORIZATION_EXPIRY_SWEEP_MS = 1_000;
|
|
10
|
+
const SESSION_EXPIRED_CLOSE_CODE = 1008;
|
|
11
|
+
const SESSION_EXPIRED_CLOSE_REASON = "Session expired";
|
|
9
12
|
/**
|
|
10
13
|
* Budget for the host-side follow-up queue of ONE session (backends without a
|
|
11
14
|
* native `followUp`; with one, messages go into the running turn and none of
|
|
@@ -56,6 +59,7 @@ export class WsHost {
|
|
|
56
59
|
maxConcurrentSessions;
|
|
57
60
|
observability;
|
|
58
61
|
wsRate;
|
|
62
|
+
isPrincipalValid;
|
|
59
63
|
activity;
|
|
60
64
|
toolPermissions;
|
|
61
65
|
/** Scoped instruments, resolved once — `[ws]` is the existing log prefix. */
|
|
@@ -66,8 +70,11 @@ export class WsHost {
|
|
|
66
70
|
turnsFailed;
|
|
67
71
|
wsErrors;
|
|
68
72
|
connectionsRefused;
|
|
73
|
+
authorizationExpiryTimer;
|
|
69
74
|
constructor(options) {
|
|
70
|
-
this.clients = new ClientSet(options.wsMaxConnections)
|
|
75
|
+
this.clients = new ClientSet(options.wsMaxConnections, (principalIds) => {
|
|
76
|
+
this.coordinator.invalidateAuthorizations(principalIds);
|
|
77
|
+
});
|
|
71
78
|
this.registry = options.registry;
|
|
72
79
|
this.catalog = options.catalog;
|
|
73
80
|
this.appName = options.appName ?? "Brain UI";
|
|
@@ -77,6 +84,7 @@ export class WsHost {
|
|
|
77
84
|
this.observability = options.observability ?? createSilentObservability();
|
|
78
85
|
this.wsRate =
|
|
79
86
|
options.wsRate && options.wsRate.ratePerSecond > 0 ? options.wsRate : null;
|
|
87
|
+
this.isPrincipalValid = options.isPrincipalValid ?? (() => true);
|
|
80
88
|
this.activity = options.activity ?? null;
|
|
81
89
|
this.toolPermissions = options.toolPermissions ?? null;
|
|
82
90
|
this.log = this.observability.logger("ws");
|
|
@@ -100,6 +108,8 @@ export class WsHost {
|
|
|
100
108
|
description: "WebSocket connections refused before admission",
|
|
101
109
|
});
|
|
102
110
|
this.coordinator.log = this.log;
|
|
111
|
+
this.authorizationExpiryTimer = setInterval(() => this.expireAuthorizationContexts(), AUTHORIZATION_EXPIRY_SWEEP_MS);
|
|
112
|
+
this.authorizationExpiryTimer.unref?.();
|
|
103
113
|
}
|
|
104
114
|
/** A metering bucket for one new connection, or null when metering is off. */
|
|
105
115
|
newRateLimiter() {
|
|
@@ -200,6 +210,34 @@ export class WsHost {
|
|
|
200
210
|
});
|
|
201
211
|
});
|
|
202
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Apply principal-store revocation to every in-memory authority boundary.
|
|
215
|
+
* Running turns are marked but deliberately not aborted.
|
|
216
|
+
*/
|
|
217
|
+
revokePrincipals(principalIds, code, reason) {
|
|
218
|
+
const revoked = new Set(principalIds);
|
|
219
|
+
if (revoked.size === 0)
|
|
220
|
+
return;
|
|
221
|
+
const affectedRunning = this.coordinator.revokePrincipals(revoked);
|
|
222
|
+
for (const principalId of revoked) {
|
|
223
|
+
this.clients.closeFor(principalId, code, reason);
|
|
224
|
+
this.activity?.stream.dropFor(principalId);
|
|
225
|
+
this.activity?.pushSender?.unbindPrincipal(principalId);
|
|
226
|
+
}
|
|
227
|
+
for (const turn of affectedRunning) {
|
|
228
|
+
turn.recorder?.recordPrincipalRevocation(turn.principalId);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Route expiry through the same full boundary as explicit revocation. */
|
|
232
|
+
expireAuthorizationContexts(now = Date.now()) {
|
|
233
|
+
const expired = new Set();
|
|
234
|
+
this.coordinator.collectExpiredPrincipalIds(now, expired);
|
|
235
|
+
this.revokePrincipals([...expired], SESSION_EXPIRED_CLOSE_CODE, SESSION_EXPIRED_CLOSE_REASON);
|
|
236
|
+
}
|
|
237
|
+
/** Stop host-owned timers during application/test teardown. */
|
|
238
|
+
close() {
|
|
239
|
+
clearInterval(this.authorizationExpiryTimer);
|
|
240
|
+
}
|
|
203
241
|
/** Send a frame to one specific socket (size-bounded). */
|
|
204
242
|
sendMessage(ws, msg) {
|
|
205
243
|
sendTo(ws, msg);
|