@scp-dev/broker 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import * as _scp_dev_core from '@scp-dev/core';
2
- import { ScopePreset, Claim, EndpointView, ScopeView, ScopeChange, Envelope, StopWaitResult, PeerView, WhyResult, SendParams, SendResult, ActivityRow, XListed, Selector, Sql, JudgeModelConfig, JudgeClient, JudgePolicy, Verdict } from '@scp-dev/core';
3
- import { FederatedCore } from '@scp-dev/hub';
1
+ import { ScopePreset, Claim, EndpointView, ScopeView, ScopeChange, Envelope, StopWaitResult, PeerView, WhyResult, SendParams, SendResult, ActivityRow, XListed, Selector } from '@scp-dev/core';
2
+ import { JudgeGate as JudgeGate$1, JudgeGateOptions, FederatedCore, Deliver, JudgeClientFactory } from '@scp-dev/hub';
3
+ export { Deliver } from '@scp-dev/hub';
4
4
 
5
5
  interface Hello {
6
6
  claim?: Claim;
@@ -10,6 +10,11 @@ interface Hello {
10
10
  tty?: boolean;
11
11
  /** a hook's connection: it claims like an agent but never counts as connected, and posts only event and status */
12
12
  transient?: boolean;
13
+ /** with `transient`: the session joins the relay on demand, taking `handle` when given, and links itself under the agent `under` */
14
+ join?: {
15
+ handle?: string;
16
+ under?: string;
17
+ };
13
18
  /** a one-shot command: the broker announces no presence change when it connects or goes */
14
19
  brief?: boolean;
15
20
  /** no identity: list, status, watch, log and policy only */
@@ -172,6 +177,16 @@ declare class BrokerUnavailable extends Error {
172
177
  */
173
178
  declare function connectBroker(dir: string, start?: () => void, timeoutMs?: number): Promise<RelayClient>;
174
179
 
180
+ /** what the broker gives the bridge: waking local waiters, telling local watchers, the local policy's state */
181
+ interface BridgeHooks {
182
+ /** a local endpoint got a message */
183
+ wake(endpoint: string): void;
184
+ /** a fleet event for local watchers only; never forwarded back */
185
+ fleet(event: Record<string, unknown>): void;
186
+ /** loads the local policy; a reason when it is unusable */
187
+ policyError(): string | null;
188
+ log?(line: string): void;
189
+ }
175
190
  interface BridgeConfig {
176
191
  /** the hub's https origin, from the caller; the socket is <origin>/v1/relay/ws */
177
192
  url: string;
@@ -217,6 +232,8 @@ interface Bridge {
217
232
  changed(endpoint: string): void;
218
233
  /** rules, caps, groups or a title changed, which can touch several endpoints: every mirrored endpoint is sent again */
219
234
  resync(): void;
235
+ /** a local endpoint took another handle: the hub renames its mirror in place, keeping what queued for it */
236
+ renamed(endpoint: string, was: string): void;
220
237
  /** a local endpoint's activity, posted to the hub */
221
238
  activity(endpoint: string, row: ActivityRow): void;
222
239
  /** the endpoints of other accounts this account's contacts let it reach */
@@ -268,116 +285,9 @@ declare function privateDir(path: string): string;
268
285
  */
269
286
  declare function socketPath(dir: string): string;
270
287
 
271
- type JudgeClientFactory = (model: JudgeModelConfig, key: () => Promise<string>) => JudgeClient;
272
- type Origin = {
273
- tty?: boolean;
274
- unverified?: boolean;
275
- };
276
- /** sends as `from` through the same path an unjudged send takes, waking recipients */
277
- type Deliver = (from: string, params: SendParams, origin: Origin) => Promise<SendResult>;
278
- interface JudgeGateOptions {
279
- sql: Sql;
280
- core: FederatedCore;
281
- now: () => number;
282
- /** where key_env is read */
283
- env: Record<string, string | undefined>;
284
- client?: JudgeClientFactory | undefined;
285
- log: (line: string) => void;
286
- /** an endpoint got a notice */
287
- wake: (endpoint: string) => void;
288
- }
289
- interface HoldRow {
290
- id: string;
291
- from_ep: string;
292
- params: string;
293
- origin: string;
294
- verdict: string;
295
- created_at: number;
296
- expires_at: number;
297
- state: "held" | "releasing" | "released" | "refused" | "expired";
298
- by: string | null;
299
- resolved_at: number | null;
300
- }
301
- /** a hold as the human's review lists it: never the body */
302
- interface HoldView {
303
- id: string;
304
- from: string;
305
- to: string[];
306
- state: HoldRow["state"];
307
- created_at: string;
308
- expires_at: string;
309
- categories: string[];
310
- reason: string;
311
- boundary: string;
312
- source: Verdict["source"];
313
- bytes: number;
314
- by: string | null;
315
- resolved_at: string | null;
316
- }
317
- /**
318
- * the broker's local judge (policy `judge`): shadow judges after delivery and only audits; enforce judges before delivery and passes,
319
- * redacts, refuses or holds. Holds wait in `judge_holds` for the human at a terminal; their body is purged once resolved or expired
320
- */
321
- declare class JudgeGate {
322
- private readonly o;
323
- readonly stats: _scp_dev_core.JudgeStats;
324
- private policy;
325
- private version;
326
- private client;
327
- private readonly cache;
328
- private readonly shadows;
329
- /** judged sends in the last hour per budget: `ep:<id>`, `tree:<root id>` and `*` for the whole broker */
330
- private readonly spent;
331
- constructor(o: JudgeGateOptions);
332
- /** the policy's judge section; a model client only when its key is readable, else the prefilter alone */
333
- configure(policy: JudgePolicy | undefined): void;
334
- private keyReader;
335
- /** resolves once every shadow judgement started so far finished */
336
- settled(): Promise<void>;
337
- /** a send or ask through the judge; an unjudged one goes straight to `deliver` */
338
- send(from: string, params: SendParams, origin: Origin, deliver: Deliver): Promise<SendResult>;
339
- /** an earlier judged send or waiting hold under the send's client_id: the same message is answered as before, another one refused as core refuses it */
340
- private seen;
341
- private remember;
342
- /**
343
- * a judged send counts before any model call against its sender's, its lineage tree's and the whole broker's budget, since refused and
344
- * held sends never reach the send's own limits, and a new handle or a helper process must not bring a fresh budget
345
- */
346
- private spend;
347
- /** how many budgets are tracked (idle ones are evicted by the sweep) */
348
- budgetKeys(): number;
349
- /** the held messages, newest first, without bodies */
350
- holds(state?: string): HoldView[];
351
- /** one hold with its body and the judge's redactions while it waits */
352
- show(id: string): HoldView & {
353
- body?: string;
354
- redactions?: {
355
- quote?: string;
356
- kind: string;
357
- }[];
358
- };
359
- /** delivers a held message as its sender, as stored or redacted: scope, policy and limits are checked again by the send itself */
360
- release(id: string, options: {
361
- redacted?: boolean;
362
- by: string;
363
- }, deliver: Deliver): Promise<SendResult>;
364
- /** refuses a held message: it is never delivered, and its sender hears the human's reason */
365
- refuse(id: string, reason: string, by: string): HoldView;
366
- /** expires holds past their message TTL (body purged, sender told) and drops resolved ones past the audit window */
367
- sweep(): void;
368
- private expire;
369
- /** the recipients by the boundary their message crosses; throws as send does for a target the sender cannot reach */
370
- private boundaries;
371
- private judge;
372
- private shadow;
373
- private hold;
374
- private detail;
375
- private storedDetail;
376
- /** marks a hold resolved and purges its body and the judge's quotes of it */
377
- private resolve;
378
- private tell;
379
- private row;
380
- private view;
288
+ /** the hub's judge gate reading `key_file` keys from disk */
289
+ declare class JudgeGate extends JudgeGate$1 {
290
+ constructor(options: JudgeGateOptions);
381
291
  }
382
292
 
383
293
  interface BrokerOptions {
@@ -405,6 +315,8 @@ interface BrokerOptions {
405
315
  bridge?: BridgeConfig | undefined;
406
316
  /** reads the bridge configuration again for bridge_relink; one that appeared or names another hub or machine restarts the broker */
407
317
  bridgeConfig?: (() => Promise<BridgeConfig | undefined>) | undefined;
318
+ /** experimental: another link to other machines in place of the hub's, started only when `bridge` is unset */
319
+ link?: LinkFactory | undefined;
408
320
  /** how often presence that decays without a request (a hook-only endpoint) is checked for changes (default 60 s) */
409
321
  presenceEveryMs?: number | undefined;
410
322
  /** where a judge model's key_env is read (default the broker's environment) */
@@ -412,6 +324,13 @@ interface BrokerOptions {
412
324
  /** the judge model client for a policy's `judge.model` (default the provider's HTTP API) */
413
325
  judgeClient?: JudgeClientFactory | undefined;
414
326
  }
327
+ /** what a link gets from the broker: its core, the remote hooks a bridge gets, and a send as a local endpoint or a mirrored one through the judge */
328
+ interface LinkContext {
329
+ core: FederatedCore;
330
+ hooks: BridgeHooks;
331
+ send: Deliver;
332
+ }
333
+ type LinkFactory = (context: LinkContext) => Bridge;
415
334
  interface Broker {
416
335
  socket: string;
417
336
  core: FederatedCore;
@@ -423,4 +342,16 @@ interface Broker {
423
342
  }
424
343
  declare function startBroker(options: BrokerOptions): Promise<Broker>;
425
344
 
426
- export { type Bridge, type BridgeConfig, type BridgeStatus, type Broker, type BrokerInfo, type BrokerOptions, BrokerRunning, BrokerUnavailable, type GrantParams, type GroupParams, type Hello, type HelloResult, MAX_LINE, RelayClient, accountHome, connectBroker, localHostName, policyPath, privateDir, relayDir, relaySocketUrl, shortHostname, socketPath, startBroker, systemHostname, thisHostname };
345
+ /**
346
+ * What the broker last decided about a harness session, by its session key: whether it joined or left, and the handle it goes by. Hooks and
347
+ * the MCP shim read it before they claim, so a session that never joined (manual join mode) or left stays off the relay without a broker
348
+ * round trip, and a renamed session claims its own name. The broker writes it; the endpoint rows stay the source of truth.
349
+ */
350
+ interface SessionMarker {
351
+ joined: boolean;
352
+ handle?: string;
353
+ }
354
+ declare function readSessionMarker(dir: string, session: string): SessionMarker | undefined;
355
+ declare function writeSessionMarker(dir: string, session: string, marker: SessionMarker): void;
356
+
357
+ export { type Bridge, type BridgeConfig, type BridgeHooks, type BridgeStatus, type Broker, type BrokerInfo, type BrokerOptions, BrokerRunning, BrokerUnavailable, type GrantParams, type GroupParams, type Hello, type HelloResult, type LinkContext, type LinkFactory, MAX_LINE, RelayClient, type SessionMarker, accountHome, connectBroker, localHostName, policyPath, privateDir, readSessionMarker, relayDir, relaySocketUrl, shortHostname, socketPath, startBroker, systemHostname, thisHostname, writeSessionMarker };