@masons/agent-network 0.5.32 → 0.5.322
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/broker/broker-daemon.d.ts +17 -0
- package/dist/broker/broker-daemon.d.ts.map +1 -1
- package/dist/broker/broker-daemon.js +126 -1
- package/dist/broker/entry.d.ts.map +1 -1
- package/dist/broker/entry.js +7 -1
- package/dist/broker/network-presence-changed-event-types.d.ts +8 -0
- package/dist/broker/network-presence-changed-event-types.d.ts.map +1 -0
- package/dist/broker/network-presence-changed-event-types.js +1 -0
- package/dist/broker/network-presence-emitter.d.ts +22 -0
- package/dist/broker/network-presence-emitter.d.ts.map +1 -0
- package/dist/broker/network-presence-emitter.js +150 -0
- package/dist/broker/network-presence.d.ts.map +1 -1
- package/dist/broker/received-message-correlation-cache.d.ts +23 -0
- package/dist/broker/received-message-correlation-cache.d.ts.map +1 -0
- package/dist/broker/received-message-correlation-cache.js +114 -0
- package/dist/broker/runtime-endpoint-port.d.ts +12 -0
- package/dist/broker/runtime-endpoint-port.d.ts.map +1 -1
- package/dist/broker/undispatched-changed-event-types.d.ts +29 -0
- package/dist/broker/undispatched-changed-event-types.d.ts.map +1 -0
- package/dist/broker/undispatched-changed-event-types.js +14 -0
- package/dist/broker/undispatched-emitter.d.ts +22 -0
- package/dist/broker/undispatched-emitter.d.ts.map +1 -0
- package/dist/broker/undispatched-emitter.js +149 -0
- package/dist/runtime-endpoint-client.d.ts +10 -0
- package/dist/runtime-endpoint-client.d.ts.map +1 -1
- package/dist/runtime-endpoint-client.js +79 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -7,11 +7,13 @@ import type { ControlAck } from "./control-event-types.js";
|
|
|
7
7
|
import { type EndpointState } from "./endpoint-state-machine.js";
|
|
8
8
|
import type { BrokerLogger } from "./logger.js";
|
|
9
9
|
import { type NetworkPresence } from "./network-presence.js";
|
|
10
|
+
import type { NetworkPresenceChangedEvent } from "./network-presence-changed-event-types.js";
|
|
10
11
|
import type { BrokerPaths } from "./paths.js";
|
|
11
12
|
import { type BufferedMessage } from "./reconnecting-buffer.js";
|
|
12
13
|
import type { RuntimeEndpointPort } from "./runtime-endpoint-port.js";
|
|
13
14
|
import type { ServicesEventClient } from "./services-event-client.js";
|
|
14
15
|
import type { SpawnDriverRegistry } from "./spawn-driver.js";
|
|
16
|
+
import { type UndispatchedChangedEvent } from "./undispatched-changed-event-types.js";
|
|
15
17
|
import { type UndispatchedInbox } from "./undispatched-inbox.js";
|
|
16
18
|
export interface BrokerDaemonOptions {
|
|
17
19
|
paths: BrokerPaths;
|
|
@@ -35,6 +37,18 @@ export interface BrokerDaemonOptions {
|
|
|
35
37
|
logger: BrokerLogger;
|
|
36
38
|
}) => ServicesEventClient;
|
|
37
39
|
postControlAck?: (ack: ControlAck) => Promise<void>;
|
|
40
|
+
replyCorrelationTtlMs?: number;
|
|
41
|
+
replyCorrelationCapPerEndpoint?: number;
|
|
42
|
+
undispatchedChangedPost?: (event: UndispatchedChangedEvent) => Promise<import("./runtime-endpoint-port.js").EmitOutcome>;
|
|
43
|
+
undispatchedChangedCapacity?: number;
|
|
44
|
+
undispatchedChangedBackoffInitialMs?: number;
|
|
45
|
+
undispatchedChangedBackoffMaxMs?: number;
|
|
46
|
+
undispatchedChangedMaxRetries?: number;
|
|
47
|
+
networkPresenceChangedPost?: (event: NetworkPresenceChangedEvent) => Promise<import("./runtime-endpoint-port.js").EmitOutcome>;
|
|
48
|
+
networkPresenceChangedCapacity?: number;
|
|
49
|
+
networkPresenceChangedBackoffInitialMs?: number;
|
|
50
|
+
networkPresenceChangedBackoffMaxMs?: number;
|
|
51
|
+
networkPresenceChangedMaxRetries?: number;
|
|
38
52
|
}
|
|
39
53
|
export interface RunningBroker {
|
|
40
54
|
bearerToken: string;
|
|
@@ -47,6 +61,9 @@ export interface RunningBroker {
|
|
|
47
61
|
networkPresence(): NetworkPresence;
|
|
48
62
|
pendingSpawnCount(): number;
|
|
49
63
|
retryQueueSize(): number;
|
|
64
|
+
replyCorrelationCacheSize(endpoint_id: string): number;
|
|
65
|
+
undispatchedChangedQueueSize(): number;
|
|
66
|
+
networkPresenceChangedQueueSize(): number;
|
|
50
67
|
}
|
|
51
68
|
export declare function startBrokerDaemon(opts: BrokerDaemonOptions): Promise<RunningBroker>;
|
|
52
69
|
export declare function readPluginPidHeader(req: IncomingMessage): number | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broker-daemon.d.ts","sourceRoot":"","sources":["../../src/broker/broker-daemon.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAqB,KAAK,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,6BAA6B,CAAC;AAcrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"broker-daemon.d.ts","sourceRoot":"","sources":["../../src/broker/broker-daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,12 +7,16 @@ import { DEFAULT_GRACE_MS, transition, } from "./endpoint-state-machine.js";
|
|
|
7
7
|
import { createGraceTimerManager } from "./grace-timer.js";
|
|
8
8
|
import { BrokerHttpError, pushToPlugin, startIPCServer, } from "./ipc-server.js";
|
|
9
9
|
import { transitionPresence, } from "./network-presence.js";
|
|
10
|
+
import { createNetworkPresenceEmitter, postNetworkPresenceChangedViaPort, } from "./network-presence-emitter.js";
|
|
10
11
|
import { isPluginAlive as defaultIsPluginAlive } from "./plugin-liveness.js";
|
|
12
|
+
import { createReceivedMessageCorrelationCache, DEFAULT_TTL_MS as DEFAULT_REPLY_CORRELATION_TTL_MS, } from "./received-message-correlation-cache.js";
|
|
11
13
|
import { createReconnectingBufferManager, } from "./reconnecting-buffer.js";
|
|
12
14
|
import { RoutingTable } from "./routing-table.js";
|
|
13
15
|
import { createSpawnCorrelationManager, createSpawnRateLimiter, } from "./spawn-correlation.js";
|
|
14
16
|
import { TASK_HINT_MAX_LENGTH, updateTaskHint } from "./task-hint-handler.js";
|
|
15
17
|
import { createTransitionStateRetryQueue } from "./transition-state-retry-queue.js";
|
|
18
|
+
import { CONTENT_PREVIEW_MAX_CODEPOINTS, truncateContentPreview, } from "./undispatched-changed-event-types.js";
|
|
19
|
+
import { createUndispatchedChangedEmitter, postUndispatchedChangedViaPort, } from "./undispatched-emitter.js";
|
|
16
20
|
import { createUndispatchedInbox, } from "./undispatched-inbox.js";
|
|
17
21
|
export async function startBrokerDaemon(opts) {
|
|
18
22
|
const { paths, asNodeId: _asNodeIdReservedForA3, connector, apiPort, logger, closedEndpointLookup, livenessProbe = defaultIsPluginAlive, spawnDriverRegistry, spawnFn = spawnChild, servicesEventClientFactory, } = opts;
|
|
@@ -55,6 +59,46 @@ export async function startBrokerDaemon(opts) {
|
|
|
55
59
|
});
|
|
56
60
|
},
|
|
57
61
|
});
|
|
62
|
+
const replyCorrelationCache = createReceivedMessageCorrelationCache({
|
|
63
|
+
ttlMs: opts.replyCorrelationTtlMs,
|
|
64
|
+
capPerEndpoint: opts.replyCorrelationCapPerEndpoint,
|
|
65
|
+
});
|
|
66
|
+
const replyCorrelationTtl = opts.replyCorrelationTtlMs ?? DEFAULT_REPLY_CORRELATION_TTL_MS;
|
|
67
|
+
const replyCorrelationSweepInterval = Math.max(Math.floor(replyCorrelationTtl / 4), 60_000);
|
|
68
|
+
const replyCorrelationSweepTimer = setInterval(() => {
|
|
69
|
+
const evicted = replyCorrelationCache.sweep();
|
|
70
|
+
if (evicted > 0) {
|
|
71
|
+
logger.info("reply_correlation_cache_sweep", { evicted });
|
|
72
|
+
}
|
|
73
|
+
}, replyCorrelationSweepInterval);
|
|
74
|
+
replyCorrelationSweepTimer.unref?.();
|
|
75
|
+
const undispatchedEmitter = createUndispatchedChangedEmitter(opts.undispatchedChangedPost ?? postUndispatchedChangedViaPort(apiPort), logger, {
|
|
76
|
+
capacity: opts.undispatchedChangedCapacity,
|
|
77
|
+
backoffInitialMs: opts.undispatchedChangedBackoffInitialMs,
|
|
78
|
+
backoffMaxMs: opts.undispatchedChangedBackoffMaxMs,
|
|
79
|
+
maxRetries: opts.undispatchedChangedMaxRetries,
|
|
80
|
+
});
|
|
81
|
+
const emitUndispatched = (event) => {
|
|
82
|
+
undispatchedEmitter.enqueue(event);
|
|
83
|
+
};
|
|
84
|
+
const networkPresenceEmitter = createNetworkPresenceEmitter(opts.networkPresenceChangedPost ??
|
|
85
|
+
postNetworkPresenceChangedViaPort(apiPort), logger, {
|
|
86
|
+
capacity: opts.networkPresenceChangedCapacity,
|
|
87
|
+
backoffInitialMs: opts.networkPresenceChangedBackoffInitialMs,
|
|
88
|
+
backoffMaxMs: opts.networkPresenceChangedBackoffMaxMs,
|
|
89
|
+
maxRetries: opts.networkPresenceChangedMaxRetries,
|
|
90
|
+
});
|
|
91
|
+
const emitNetworkPresence = (event) => {
|
|
92
|
+
networkPresenceEmitter.enqueue(event);
|
|
93
|
+
};
|
|
94
|
+
const recordInboundCorrelation = (endpoint_id, metadata) => {
|
|
95
|
+
const c = metadata && typeof metadata.correlation_id === "string"
|
|
96
|
+
? metadata.correlation_id
|
|
97
|
+
: undefined;
|
|
98
|
+
if (!c)
|
|
99
|
+
return;
|
|
100
|
+
replyCorrelationCache.record(endpoint_id, c);
|
|
101
|
+
};
|
|
58
102
|
let networkPresence = "offline";
|
|
59
103
|
let presenceGraceTimer;
|
|
60
104
|
const applyPresenceTransition = (event) => {
|
|
@@ -85,6 +129,13 @@ export async function startBrokerDaemon(opts) {
|
|
|
85
129
|
presence: effect.presence,
|
|
86
130
|
reason: effect.reason,
|
|
87
131
|
});
|
|
132
|
+
emitNetworkPresence({
|
|
133
|
+
type: "network_presence_changed",
|
|
134
|
+
version: 1,
|
|
135
|
+
state: effect.presence,
|
|
136
|
+
ts: Date.now(),
|
|
137
|
+
reason: effect.reason,
|
|
138
|
+
});
|
|
88
139
|
if (effect.presence === "online") {
|
|
89
140
|
void retryQueue.flush(async (entry) => {
|
|
90
141
|
await apiPort.transitionState(entry.endpoint_id, entry.params);
|
|
@@ -175,6 +226,7 @@ export async function startBrokerDaemon(opts) {
|
|
|
175
226
|
break;
|
|
176
227
|
case "remove_from_registry":
|
|
177
228
|
registry.unregister(endpoint_id);
|
|
229
|
+
replyCorrelationCache.forgetEndpoint(endpoint_id);
|
|
178
230
|
void apiPort.unregister(endpoint_id).catch(() => {
|
|
179
231
|
});
|
|
180
232
|
break;
|
|
@@ -199,6 +251,13 @@ export async function startBrokerDaemon(opts) {
|
|
|
199
251
|
inbox_size: undispatchedInbox.size(),
|
|
200
252
|
inbox_capacity: undispatchedInbox.capacity(),
|
|
201
253
|
});
|
|
254
|
+
emitUndispatched({
|
|
255
|
+
type: "undispatched_changed",
|
|
256
|
+
version: 1,
|
|
257
|
+
action: "remove",
|
|
258
|
+
undispatched_id: event.undispatched_id,
|
|
259
|
+
remove_reason: "lost_at_capacity_during_redispatch_bounce",
|
|
260
|
+
});
|
|
202
261
|
}
|
|
203
262
|
return {
|
|
204
263
|
ok: false,
|
|
@@ -216,6 +275,7 @@ export async function startBrokerDaemon(opts) {
|
|
|
216
275
|
dispatched_by: "passport",
|
|
217
276
|
},
|
|
218
277
|
};
|
|
278
|
+
recordInboundCorrelation(target.endpoint_id, stamped.metadata);
|
|
219
279
|
if (target.state === "active") {
|
|
220
280
|
pushToPlugin(target.ipc_ws, stamped);
|
|
221
281
|
}
|
|
@@ -237,6 +297,13 @@ export async function startBrokerDaemon(opts) {
|
|
|
237
297
|
target_endpoint_id: event.target_endpoint_id,
|
|
238
298
|
target_state: target.state,
|
|
239
299
|
});
|
|
300
|
+
emitUndispatched({
|
|
301
|
+
type: "undispatched_changed",
|
|
302
|
+
version: 1,
|
|
303
|
+
action: "dispatch",
|
|
304
|
+
undispatched_id: event.undispatched_id,
|
|
305
|
+
dispatched_to_endpoint_id: event.target_endpoint_id,
|
|
306
|
+
});
|
|
240
307
|
return { ok: true };
|
|
241
308
|
});
|
|
242
309
|
controlEventDispatcher.on("spawn_request", async (event) => {
|
|
@@ -413,7 +480,27 @@ export async function startBrokerDaemon(opts) {
|
|
|
413
480
|
incoming.source_endpoint_id !== body.endpoint_id) {
|
|
414
481
|
throw new BrokerHttpError(403, "source_endpoint_id_mismatch", "metadata.source_endpoint_id must equal body.endpoint_id");
|
|
415
482
|
}
|
|
416
|
-
const
|
|
483
|
+
const inReplyTo = typeof incoming.in_reply_to === "string"
|
|
484
|
+
? incoming.in_reply_to
|
|
485
|
+
: undefined;
|
|
486
|
+
let correlationId;
|
|
487
|
+
if (inReplyTo) {
|
|
488
|
+
const resolved = replyCorrelationCache.resolve(body.endpoint_id, inReplyTo);
|
|
489
|
+
if (resolved.ok) {
|
|
490
|
+
correlationId = inReplyTo;
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
logger.warn("reply_aware_fallback", {
|
|
494
|
+
endpoint_id: body.endpoint_id,
|
|
495
|
+
in_reply_to: inReplyTo,
|
|
496
|
+
reason: resolved.reason,
|
|
497
|
+
});
|
|
498
|
+
correlationId = randomUUID();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
correlationId = randomUUID();
|
|
503
|
+
}
|
|
417
504
|
entry.correlation_ring.add(correlationId);
|
|
418
505
|
const metadata = {
|
|
419
506
|
...incoming,
|
|
@@ -547,6 +634,7 @@ export async function startBrokerDaemon(opts) {
|
|
|
547
634
|
const correlation_id = typeof meta.correlation_id === "string" ? meta.correlation_id : undefined;
|
|
548
635
|
const decision = router.route({ target_endpoint_id, correlation_id });
|
|
549
636
|
if (decision.kind === "endpoint") {
|
|
637
|
+
recordInboundCorrelation(decision.entry.endpoint_id, meta);
|
|
550
638
|
if (decision.entry.state === "active") {
|
|
551
639
|
pushToPlugin(decision.entry.ipc_ws, {
|
|
552
640
|
event: "message_received",
|
|
@@ -613,6 +701,25 @@ export async function startBrokerDaemon(opts) {
|
|
|
613
701
|
}
|
|
614
702
|
else {
|
|
615
703
|
logger.info("undispatched_added", { id: undispatched.id, reason });
|
|
704
|
+
const wireReason = undispatched.reason === "unaddressed"
|
|
705
|
+
? "no_target_endpoint"
|
|
706
|
+
: undispatched.reason;
|
|
707
|
+
emitUndispatched({
|
|
708
|
+
type: "undispatched_changed",
|
|
709
|
+
version: 1,
|
|
710
|
+
action: "add",
|
|
711
|
+
undispatched_id: undispatched.id,
|
|
712
|
+
sender_address: undispatched.sender_address,
|
|
713
|
+
content_preview: truncateContentPreview(undispatched.content, CONTENT_PREVIEW_MAX_CODEPOINTS),
|
|
714
|
+
reason: wireReason,
|
|
715
|
+
...(undispatched.original_target_endpoint_id !== undefined && {
|
|
716
|
+
target_endpoint_id_hint: undispatched.original_target_endpoint_id,
|
|
717
|
+
}),
|
|
718
|
+
...(typeof correlation_id === "string" && {
|
|
719
|
+
in_reply_to: correlation_id,
|
|
720
|
+
}),
|
|
721
|
+
arrived_at: Date.parse(undispatched.arrived_at),
|
|
722
|
+
});
|
|
616
723
|
}
|
|
617
724
|
});
|
|
618
725
|
connector.on("delivery_pending", ({ payload }) => {
|
|
@@ -660,12 +767,27 @@ export async function startBrokerDaemon(opts) {
|
|
|
660
767
|
clearTimeout(presenceGraceTimer);
|
|
661
768
|
presenceGraceTimer = undefined;
|
|
662
769
|
}
|
|
770
|
+
clearInterval(replyCorrelationSweepTimer);
|
|
663
771
|
if (retryQueue.size() > 0) {
|
|
664
772
|
logger.warn("retry_queue_dropped_on_shutdown", {
|
|
665
773
|
size: retryQueue.size(),
|
|
666
774
|
reason,
|
|
667
775
|
});
|
|
668
776
|
}
|
|
777
|
+
if (undispatchedEmitter.size() > 0) {
|
|
778
|
+
logger.warn("undispatched_changed_queue_dropped_on_shutdown", {
|
|
779
|
+
size: undispatchedEmitter.size(),
|
|
780
|
+
reason,
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
await undispatchedEmitter.shutdown();
|
|
784
|
+
if (networkPresenceEmitter.size() > 0) {
|
|
785
|
+
logger.warn("network_presence_changed_queue_dropped_on_shutdown", {
|
|
786
|
+
size: networkPresenceEmitter.size(),
|
|
787
|
+
reason,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
await networkPresenceEmitter.shutdown();
|
|
669
791
|
const endpoints = registry.list();
|
|
670
792
|
await Promise.all(endpoints.map(async (entry) => {
|
|
671
793
|
try {
|
|
@@ -700,6 +822,9 @@ export async function startBrokerDaemon(opts) {
|
|
|
700
822
|
networkPresence: () => networkPresence,
|
|
701
823
|
pendingSpawnCount: () => spawnCorrelation.size(),
|
|
702
824
|
retryQueueSize: () => retryQueue.size(),
|
|
825
|
+
undispatchedChangedQueueSize: () => undispatchedEmitter.size(),
|
|
826
|
+
networkPresenceChangedQueueSize: () => networkPresenceEmitter.size(),
|
|
827
|
+
replyCorrelationCacheSize: (endpoint_id) => replyCorrelationCache.sizeForEndpoint(endpoint_id),
|
|
703
828
|
};
|
|
704
829
|
}
|
|
705
830
|
export function readPluginPidHeader(req) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AA+EA,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,aAAa,CAAC;AAEpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAMtE,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA8F9B;AAyDD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,GACnB,mBAAmB,CAwGrB;AAYD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA8F1C"}
|
package/dist/broker/entry.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { readConfig } from "../config-fs.js";
|
|
4
4
|
import { DEFAULT_API_HOST } from "../platform-client.js";
|
|
5
|
-
import { heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
|
|
5
|
+
import { emitRuntimeNetworkPresenceChanged, emitRuntimeUndispatchedChanged, heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
|
|
6
6
|
import { startBrokerDaemon } from "./broker-daemon.js";
|
|
7
7
|
import { ClaudeCodeSpawnDriver } from "./claude-code-spawn-driver.js";
|
|
8
8
|
import { CodexSpawnDriverStub } from "./codex-spawn-driver-stub.js";
|
|
@@ -132,6 +132,12 @@ export function buildApiPort(apiHost, runtimeKey, logger) {
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
|
+
async emitUndispatchedChanged(event) {
|
|
136
|
+
return emitRuntimeUndispatchedChanged({ apiHost }, runtimeKey, event);
|
|
137
|
+
},
|
|
138
|
+
async emitNetworkPresenceChanged(event) {
|
|
139
|
+
return emitRuntimeNetworkPresenceChanged({ apiHost }, runtimeKey, event);
|
|
140
|
+
},
|
|
135
141
|
};
|
|
136
142
|
}
|
|
137
143
|
function errorStatus(err) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-presence-changed-event-types.d.ts","sourceRoot":"","sources":["../../src/broker/network-presence-changed-event-types.ts"],"names":[],"mappings":"AAqCA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,0BAA0B,CAAC;IAGjC,OAAO,EAAE,CAAC,CAAC;IAEX,KAAK,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,CAAC;IAG7C,EAAE,EAAE,MAAM,CAAC;IAMX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BrokerLogger } from "./logger.js";
|
|
2
|
+
import type { NetworkPresenceChangedEvent } from "./network-presence-changed-event-types.js";
|
|
3
|
+
import type { EmitOutcome, RuntimeEndpointPort } from "./runtime-endpoint-port.js";
|
|
4
|
+
export declare const DEFAULT_PRESENCE_EMITTER_CAPACITY = 128;
|
|
5
|
+
export declare const DEFAULT_PRESENCE_EMITTER_BACKOFF_INITIAL_MS = 500;
|
|
6
|
+
export declare const DEFAULT_PRESENCE_EMITTER_BACKOFF_MAX_MS = 30000;
|
|
7
|
+
export declare const DEFAULT_PRESENCE_EMITTER_MAX_RETRIES = 5;
|
|
8
|
+
export interface NetworkPresenceEmitterOptions {
|
|
9
|
+
capacity?: number;
|
|
10
|
+
backoffInitialMs?: number;
|
|
11
|
+
backoffMaxMs?: number;
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface NetworkPresenceEmitter {
|
|
15
|
+
enqueue(event: NetworkPresenceChangedEvent): boolean;
|
|
16
|
+
size(): number;
|
|
17
|
+
capacity(): number;
|
|
18
|
+
shutdown(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createNetworkPresenceEmitter(post: (event: NetworkPresenceChangedEvent) => Promise<EmitOutcome>, logger: BrokerLogger, opts?: NetworkPresenceEmitterOptions): NetworkPresenceEmitter;
|
|
21
|
+
export declare function postNetworkPresenceChangedViaPort(apiPort: RuntimeEndpointPort): (event: NetworkPresenceChangedEvent) => Promise<EmitOutcome>;
|
|
22
|
+
//# sourceMappingURL=network-presence-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-presence-emitter.d.ts","sourceRoot":"","sources":["../../src/broker/network-presence-emitter.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,iCAAiC,MAAM,CAAC;AACrD,eAAO,MAAM,2CAA2C,MAAM,CAAC;AAC/D,eAAO,MAAM,uCAAuC,QAAS,CAAC;AAC9D,eAAO,MAAM,oCAAoC,IAAI,CAAC;AAEtD,MAAM,WAAW,6BAA6B;IAE5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IAIrC,OAAO,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC;IAErD,IAAI,IAAI,MAAM,CAAC;IAEf,QAAQ,IAAI,MAAM,CAAC;IAGnB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,OAAO,CAAC,WAAW,CAAC,EAClE,MAAM,EAAE,YAAY,EACpB,IAAI,GAAE,6BAAkC,GACvC,sBAAsB,CAyIxB;AAcD,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,mBAAmB,GAC3B,CAAC,KAAK,EAAE,2BAA2B,KAAK,OAAO,CAAC,WAAW,CAAC,CAW9D"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export const DEFAULT_PRESENCE_EMITTER_CAPACITY = 128;
|
|
2
|
+
export const DEFAULT_PRESENCE_EMITTER_BACKOFF_INITIAL_MS = 500;
|
|
3
|
+
export const DEFAULT_PRESENCE_EMITTER_BACKOFF_MAX_MS = 30_000;
|
|
4
|
+
export const DEFAULT_PRESENCE_EMITTER_MAX_RETRIES = 5;
|
|
5
|
+
export function createNetworkPresenceEmitter(post, logger, opts = {}) {
|
|
6
|
+
const cap = opts.capacity ?? DEFAULT_PRESENCE_EMITTER_CAPACITY;
|
|
7
|
+
const initialBackoff = opts.backoffInitialMs ?? DEFAULT_PRESENCE_EMITTER_BACKOFF_INITIAL_MS;
|
|
8
|
+
const maxBackoff = opts.backoffMaxMs ?? DEFAULT_PRESENCE_EMITTER_BACKOFF_MAX_MS;
|
|
9
|
+
const maxRetries = opts.maxRetries ?? DEFAULT_PRESENCE_EMITTER_MAX_RETRIES;
|
|
10
|
+
if (cap <= 0)
|
|
11
|
+
throw new Error(`capacity must be positive: ${cap}`);
|
|
12
|
+
if (initialBackoff <= 0)
|
|
13
|
+
throw new Error(`backoffInitialMs must be positive: ${initialBackoff}`);
|
|
14
|
+
if (maxBackoff < initialBackoff)
|
|
15
|
+
throw new Error(`backoffMaxMs must be >= backoffInitialMs`);
|
|
16
|
+
if (maxRetries < 0)
|
|
17
|
+
throw new Error(`maxRetries must be non-negative: ${maxRetries}`);
|
|
18
|
+
const queue = [];
|
|
19
|
+
let draining = false;
|
|
20
|
+
let stopped = false;
|
|
21
|
+
let activeDrain = null;
|
|
22
|
+
let wakeSleep = null;
|
|
23
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
24
|
+
const t = setTimeout(() => {
|
|
25
|
+
wakeSleep = null;
|
|
26
|
+
resolve();
|
|
27
|
+
}, ms);
|
|
28
|
+
t.unref?.();
|
|
29
|
+
wakeSleep = () => {
|
|
30
|
+
clearTimeout(t);
|
|
31
|
+
wakeSleep = null;
|
|
32
|
+
resolve();
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const drain = async () => {
|
|
36
|
+
while (!stopped && queue.length > 0) {
|
|
37
|
+
const event = queue[0];
|
|
38
|
+
if (!event)
|
|
39
|
+
break;
|
|
40
|
+
let attempts = 0;
|
|
41
|
+
while (true) {
|
|
42
|
+
if (stopped)
|
|
43
|
+
return;
|
|
44
|
+
let outcome;
|
|
45
|
+
try {
|
|
46
|
+
outcome = await post(event);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
outcome = {
|
|
50
|
+
ok: false,
|
|
51
|
+
terminal: false,
|
|
52
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (outcome.ok)
|
|
56
|
+
break;
|
|
57
|
+
if (outcome.terminal) {
|
|
58
|
+
logger.warn("network_presence_changed_drop_terminal", {
|
|
59
|
+
state: event.state,
|
|
60
|
+
ts: event.ts,
|
|
61
|
+
reason: event.reason,
|
|
62
|
+
status: outcome.status,
|
|
63
|
+
detail: outcome.detail,
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
attempts++;
|
|
68
|
+
if (attempts > maxRetries) {
|
|
69
|
+
logger.warn("network_presence_changed_drop_max_retries", {
|
|
70
|
+
state: event.state,
|
|
71
|
+
ts: event.ts,
|
|
72
|
+
attempts,
|
|
73
|
+
status: outcome.status,
|
|
74
|
+
detail: outcome.detail,
|
|
75
|
+
});
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
const backoff = Math.min(initialBackoff * 2 ** (attempts - 1), maxBackoff);
|
|
79
|
+
logger.info("network_presence_changed_retry", {
|
|
80
|
+
state: event.state,
|
|
81
|
+
ts: event.ts,
|
|
82
|
+
attempt: attempts,
|
|
83
|
+
backoff_ms: backoff,
|
|
84
|
+
status: outcome.status,
|
|
85
|
+
});
|
|
86
|
+
await sleep(backoff);
|
|
87
|
+
}
|
|
88
|
+
queue.shift();
|
|
89
|
+
}
|
|
90
|
+
draining = false;
|
|
91
|
+
};
|
|
92
|
+
const kick = () => {
|
|
93
|
+
if (draining || stopped)
|
|
94
|
+
return;
|
|
95
|
+
draining = true;
|
|
96
|
+
activeDrain = drain().catch((err) => {
|
|
97
|
+
logger.error("network_presence_changed_drain_unexpected_error", {
|
|
98
|
+
err: err instanceof Error ? err.message : String(err),
|
|
99
|
+
});
|
|
100
|
+
draining = false;
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
enqueue(event) {
|
|
105
|
+
if (stopped)
|
|
106
|
+
return true;
|
|
107
|
+
let evicted = false;
|
|
108
|
+
if (queue.length >= cap) {
|
|
109
|
+
const old = queue.shift();
|
|
110
|
+
if (old) {
|
|
111
|
+
logger.warn("network_presence_changed_queue_overflow", {
|
|
112
|
+
dropped_state: old.state,
|
|
113
|
+
dropped_ts: old.ts,
|
|
114
|
+
size: queue.length,
|
|
115
|
+
capacity: cap,
|
|
116
|
+
});
|
|
117
|
+
evicted = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
queue.push(event);
|
|
121
|
+
kick();
|
|
122
|
+
return !evicted;
|
|
123
|
+
},
|
|
124
|
+
size() {
|
|
125
|
+
return queue.length;
|
|
126
|
+
},
|
|
127
|
+
capacity() {
|
|
128
|
+
return cap;
|
|
129
|
+
},
|
|
130
|
+
async shutdown() {
|
|
131
|
+
stopped = true;
|
|
132
|
+
wakeSleep?.();
|
|
133
|
+
if (activeDrain) {
|
|
134
|
+
await activeDrain.catch(() => { });
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function postNetworkPresenceChangedViaPort(apiPort) {
|
|
140
|
+
return async (event) => {
|
|
141
|
+
if (!apiPort.emitNetworkPresenceChanged) {
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
terminal: true,
|
|
145
|
+
detail: "emitNetworkPresenceChanged not implemented on this apiPort",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return apiPort.emitNetworkPresenceChanged(event);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-presence.d.ts","sourceRoot":"","sources":["../../src/broker/network-presence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"network-presence.d.ts","sourceRoot":"","sources":["../../src/broker/network-presence.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,cAAc,GAAG,SAAS,CAAC;AAEpE,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,wBAAwB,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,wBAAwB,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,aAAa,EACpB,IAAI,GAAE,yBAA8B,GACnC,wBAAwB,CAgH1B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const DEFAULT_TTL_MS = 86400000;
|
|
2
|
+
export declare const DEFAULT_CAP_PER_ENDPOINT = 1000;
|
|
3
|
+
export interface ReceivedMessageCorrelationCacheOptions {
|
|
4
|
+
ttlMs?: number;
|
|
5
|
+
capPerEndpoint?: number;
|
|
6
|
+
now?: () => number;
|
|
7
|
+
}
|
|
8
|
+
export type ReplyAwareResolve = {
|
|
9
|
+
ok: true;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
reason: "unknown_correlation_id" | "wrong_endpoint" | "ttl_expired";
|
|
13
|
+
};
|
|
14
|
+
export interface ReceivedMessageCorrelationCache {
|
|
15
|
+
record(endpoint_id: string, correlation_id: string): void;
|
|
16
|
+
resolve(endpoint_id: string, correlation_id: string): ReplyAwareResolve;
|
|
17
|
+
size(): number;
|
|
18
|
+
sizeForEndpoint(endpoint_id: string): number;
|
|
19
|
+
sweep(now?: number): number;
|
|
20
|
+
forgetEndpoint(endpoint_id: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createReceivedMessageCorrelationCache(opts?: ReceivedMessageCorrelationCacheOptions): ReceivedMessageCorrelationCache;
|
|
23
|
+
//# sourceMappingURL=received-message-correlation-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"received-message-correlation-cache.d.ts","sourceRoot":"","sources":["../../src/broker/received-message-correlation-cache.ts"],"names":[],"mappings":"AA8DA,eAAO,MAAM,cAAc,WAAa,CAAC;AAGzC,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,MAAM,WAAW,sCAAsC;IAErD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,GAAG,aAAa,CAAC;CACrE,CAAC;AAMN,MAAM,WAAW,+BAA+B;IAa9C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAQ1D,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAGxE,IAAI,IAAI,MAAM,CAAC;IAGf,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAQ7C,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAM5B,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,qCAAqC,CACnD,IAAI,GAAE,sCAA2C,GAChD,+BAA+B,CAgIjC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export const DEFAULT_TTL_MS = 86_400_000;
|
|
2
|
+
export const DEFAULT_CAP_PER_ENDPOINT = 1000;
|
|
3
|
+
export function createReceivedMessageCorrelationCache(opts = {}) {
|
|
4
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
5
|
+
const cap = opts.capPerEndpoint ?? DEFAULT_CAP_PER_ENDPOINT;
|
|
6
|
+
const clock = opts.now ?? Date.now;
|
|
7
|
+
if (ttlMs <= 0)
|
|
8
|
+
throw new Error(`ttlMs must be positive: ${ttlMs}`);
|
|
9
|
+
if (cap <= 0)
|
|
10
|
+
throw new Error(`capPerEndpoint must be positive: ${cap}`);
|
|
11
|
+
const perEndpoint = new Map();
|
|
12
|
+
const correlationOwner = new Map();
|
|
13
|
+
const evict = (endpoint_id, correlation_id) => {
|
|
14
|
+
const inner = perEndpoint.get(endpoint_id);
|
|
15
|
+
if (!inner)
|
|
16
|
+
return;
|
|
17
|
+
inner.delete(correlation_id);
|
|
18
|
+
if (inner.size === 0)
|
|
19
|
+
perEndpoint.delete(endpoint_id);
|
|
20
|
+
if (correlationOwner.get(correlation_id) === endpoint_id) {
|
|
21
|
+
correlationOwner.delete(correlation_id);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
record(endpoint_id, correlation_id) {
|
|
26
|
+
const priorOwner = correlationOwner.get(correlation_id);
|
|
27
|
+
if (priorOwner && priorOwner !== endpoint_id) {
|
|
28
|
+
const priorInner = perEndpoint.get(priorOwner);
|
|
29
|
+
priorInner?.delete(correlation_id);
|
|
30
|
+
if (priorInner && priorInner.size === 0) {
|
|
31
|
+
perEndpoint.delete(priorOwner);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
let inner = perEndpoint.get(endpoint_id);
|
|
35
|
+
if (!inner) {
|
|
36
|
+
inner = new Map();
|
|
37
|
+
perEndpoint.set(endpoint_id, inner);
|
|
38
|
+
}
|
|
39
|
+
inner.delete(correlation_id);
|
|
40
|
+
inner.set(correlation_id, { received_at: clock() });
|
|
41
|
+
correlationOwner.set(correlation_id, endpoint_id);
|
|
42
|
+
while (inner.size > cap) {
|
|
43
|
+
const oldestKey = inner.keys().next().value;
|
|
44
|
+
if (oldestKey === undefined)
|
|
45
|
+
break;
|
|
46
|
+
inner.delete(oldestKey);
|
|
47
|
+
if (correlationOwner.get(oldestKey) === endpoint_id) {
|
|
48
|
+
correlationOwner.delete(oldestKey);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
resolve(endpoint_id, correlation_id) {
|
|
53
|
+
const owner = correlationOwner.get(correlation_id);
|
|
54
|
+
if (!owner) {
|
|
55
|
+
return { ok: false, reason: "unknown_correlation_id" };
|
|
56
|
+
}
|
|
57
|
+
if (owner !== endpoint_id) {
|
|
58
|
+
return { ok: false, reason: "wrong_endpoint" };
|
|
59
|
+
}
|
|
60
|
+
const inner = perEndpoint.get(endpoint_id);
|
|
61
|
+
const entry = inner?.get(correlation_id);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
correlationOwner.delete(correlation_id);
|
|
64
|
+
return { ok: false, reason: "unknown_correlation_id" };
|
|
65
|
+
}
|
|
66
|
+
if (clock() - entry.received_at >= ttlMs) {
|
|
67
|
+
evict(endpoint_id, correlation_id);
|
|
68
|
+
return { ok: false, reason: "ttl_expired" };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true };
|
|
71
|
+
},
|
|
72
|
+
size() {
|
|
73
|
+
let total = 0;
|
|
74
|
+
for (const inner of perEndpoint.values())
|
|
75
|
+
total += inner.size;
|
|
76
|
+
return total;
|
|
77
|
+
},
|
|
78
|
+
sizeForEndpoint(endpoint_id) {
|
|
79
|
+
return perEndpoint.get(endpoint_id)?.size ?? 0;
|
|
80
|
+
},
|
|
81
|
+
sweep(now = clock()) {
|
|
82
|
+
let evicted = 0;
|
|
83
|
+
for (const [endpoint_id, inner] of perEndpoint) {
|
|
84
|
+
const expired = [];
|
|
85
|
+
for (const [correlation_id, entry] of inner) {
|
|
86
|
+
if (now - entry.received_at >= ttlMs) {
|
|
87
|
+
expired.push(correlation_id);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const correlation_id of expired) {
|
|
91
|
+
inner.delete(correlation_id);
|
|
92
|
+
if (correlationOwner.get(correlation_id) === endpoint_id) {
|
|
93
|
+
correlationOwner.delete(correlation_id);
|
|
94
|
+
}
|
|
95
|
+
evicted++;
|
|
96
|
+
}
|
|
97
|
+
if (inner.size === 0)
|
|
98
|
+
perEndpoint.delete(endpoint_id);
|
|
99
|
+
}
|
|
100
|
+
return evicted;
|
|
101
|
+
},
|
|
102
|
+
forgetEndpoint(endpoint_id) {
|
|
103
|
+
const inner = perEndpoint.get(endpoint_id);
|
|
104
|
+
if (!inner)
|
|
105
|
+
return;
|
|
106
|
+
for (const correlation_id of inner.keys()) {
|
|
107
|
+
if (correlationOwner.get(correlation_id) === endpoint_id) {
|
|
108
|
+
correlationOwner.delete(correlation_id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
perEndpoint.delete(endpoint_id);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import type { RegisterRuntimeEndpointParams, RegisterRuntimeEndpointResponse, TransitionRuntimeEndpointStateParams } from "../runtime-endpoint-client.js";
|
|
2
|
+
import type { NetworkPresenceChangedEvent } from "./network-presence-changed-event-types.js";
|
|
3
|
+
import type { UndispatchedChangedEvent } from "./undispatched-changed-event-types.js";
|
|
4
|
+
export type EmitOutcome = {
|
|
5
|
+
ok: true;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
terminal: boolean;
|
|
9
|
+
status?: number;
|
|
10
|
+
detail?: string;
|
|
11
|
+
};
|
|
2
12
|
export interface RuntimeEndpointPort {
|
|
3
13
|
register(params: RegisterRuntimeEndpointParams): Promise<RegisterRuntimeEndpointResponse>;
|
|
4
14
|
heartbeat(endpointId: string): Promise<void>;
|
|
5
15
|
unregister(endpointId: string, asNodeId?: string): Promise<void>;
|
|
6
16
|
transitionState(endpointId: string, params: TransitionRuntimeEndpointStateParams): Promise<void>;
|
|
17
|
+
emitUndispatchedChanged?(event: UndispatchedChangedEvent): Promise<EmitOutcome>;
|
|
18
|
+
emitNetworkPresenceChanged?(event: NetworkPresenceChangedEvent): Promise<EmitOutcome>;
|
|
7
19
|
}
|
|
8
20
|
//# sourceMappingURL=runtime-endpoint-port.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-endpoint-port.d.ts","sourceRoot":"","sources":["../../src/broker/runtime-endpoint-port.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,6BAA6B,EAC7B,+BAA+B,EAC/B,oCAAoC,EACrC,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-endpoint-port.d.ts","sourceRoot":"","sources":["../../src/broker/runtime-endpoint-port.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,6BAA6B,EAC7B,+BAA+B,EAC/B,oCAAoC,EACrC,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAWtF,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CACN,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAC5C,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAO7C,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAQjE,eAAe,CACb,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,oCAAoC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAAC;IAqBjB,uBAAuB,CAAC,CACtB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,WAAW,CAAC,CAAC;IAYxB,0BAA0B,CAAC,CACzB,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const CONTENT_PREVIEW_MAX_CODEPOINTS = 80;
|
|
2
|
+
export type UndispatchedReason = "no_target_endpoint" | "closed_session_continuation";
|
|
3
|
+
export type UndispatchedRemoveReason = "lost_at_capacity_during_redispatch_bounce";
|
|
4
|
+
interface UndispatchedChangedEventBase {
|
|
5
|
+
type: "undispatched_changed";
|
|
6
|
+
version: 1;
|
|
7
|
+
undispatched_id: string;
|
|
8
|
+
}
|
|
9
|
+
export interface UndispatchedAddEvent extends UndispatchedChangedEventBase {
|
|
10
|
+
action: "add";
|
|
11
|
+
sender_address: string;
|
|
12
|
+
content_preview: string;
|
|
13
|
+
reason: UndispatchedReason;
|
|
14
|
+
target_endpoint_id_hint?: string;
|
|
15
|
+
in_reply_to?: string;
|
|
16
|
+
arrived_at: number;
|
|
17
|
+
}
|
|
18
|
+
export interface UndispatchedDispatchEvent extends UndispatchedChangedEventBase {
|
|
19
|
+
action: "dispatch";
|
|
20
|
+
dispatched_to_endpoint_id: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UndispatchedRemoveEvent extends UndispatchedChangedEventBase {
|
|
23
|
+
action: "remove";
|
|
24
|
+
remove_reason: UndispatchedRemoveReason;
|
|
25
|
+
}
|
|
26
|
+
export type UndispatchedChangedEvent = UndispatchedAddEvent | UndispatchedDispatchEvent | UndispatchedRemoveEvent;
|
|
27
|
+
export declare function truncateContentPreview(raw: string, n?: number): string;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=undispatched-changed-event-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undispatched-changed-event-types.d.ts","sourceRoot":"","sources":["../../src/broker/undispatched-changed-event-types.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAMjD,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,6BAA6B,CAAC;AAOlC,MAAM,MAAM,wBAAwB,GAWlC,2CAA2C,CAAC;AAG9C,UAAU,4BAA4B;IACpC,IAAI,EAAE,sBAAsB,CAAC;IAG7B,OAAO,EAAE,CAAC,CAAC;IAEX,eAAe,EAAE,MAAM,CAAC;CACzB;AAGD,MAAM,WAAW,oBAAqB,SAAQ,4BAA4B;IACxE,MAAM,EAAE,KAAK,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IASvB,eAAe,EAAE,MAAM,CAAC;IAExB,MAAM,EAAE,kBAAkB,CAAC;IAO3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAMjC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,WAAW,yBACf,SAAQ,4BAA4B;IACpC,MAAM,EAAE,UAAU,CAAC;IAQnB,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAID,MAAM,WAAW,uBAAwB,SAAQ,4BAA4B;IAC3E,MAAM,EAAE,QAAQ,CAAC;IACjB,aAAa,EAAE,wBAAwB,CAAC;CACzC;AAED,MAAM,MAAM,wBAAwB,GAChC,oBAAoB,GACpB,yBAAyB,GACzB,uBAAuB,CAAC;AAqB5B,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,CAAC,GAAE,MAAuC,GACzC,MAAM,CAYR"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const CONTENT_PREVIEW_MAX_CODEPOINTS = 80;
|
|
2
|
+
export function truncateContentPreview(raw, n = CONTENT_PREVIEW_MAX_CODEPOINTS) {
|
|
3
|
+
if (raw.length <= n)
|
|
4
|
+
return raw;
|
|
5
|
+
let out = "";
|
|
6
|
+
let count = 0;
|
|
7
|
+
for (const cp of raw) {
|
|
8
|
+
if (count >= n)
|
|
9
|
+
break;
|
|
10
|
+
out += cp;
|
|
11
|
+
count++;
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BrokerLogger } from "./logger.js";
|
|
2
|
+
import type { EmitOutcome, RuntimeEndpointPort } from "./runtime-endpoint-port.js";
|
|
3
|
+
import type { UndispatchedChangedEvent } from "./undispatched-changed-event-types.js";
|
|
4
|
+
export declare const DEFAULT_EMITTER_CAPACITY = 1024;
|
|
5
|
+
export declare const DEFAULT_EMITTER_BACKOFF_INITIAL_MS = 500;
|
|
6
|
+
export declare const DEFAULT_EMITTER_BACKOFF_MAX_MS = 30000;
|
|
7
|
+
export declare const DEFAULT_EMITTER_MAX_RETRIES = 5;
|
|
8
|
+
export interface UndispatchedChangedEmitterOptions {
|
|
9
|
+
capacity?: number;
|
|
10
|
+
backoffInitialMs?: number;
|
|
11
|
+
backoffMaxMs?: number;
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface UndispatchedChangedEmitter {
|
|
15
|
+
enqueue(event: UndispatchedChangedEvent): boolean;
|
|
16
|
+
size(): number;
|
|
17
|
+
capacity(): number;
|
|
18
|
+
shutdown(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createUndispatchedChangedEmitter(post: (event: UndispatchedChangedEvent) => Promise<EmitOutcome>, logger: BrokerLogger, opts?: UndispatchedChangedEmitterOptions): UndispatchedChangedEmitter;
|
|
21
|
+
export declare function postUndispatchedChangedViaPort(apiPort: RuntimeEndpointPort): (event: UndispatchedChangedEvent) => Promise<EmitOutcome>;
|
|
22
|
+
//# sourceMappingURL=undispatched-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undispatched-emitter.d.ts","sourceRoot":"","sources":["../../src/broker/undispatched-emitter.ts"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAEtF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,kCAAkC,MAAM,CAAC;AACtD,eAAO,MAAM,8BAA8B,QAAS,CAAC;AACrD,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,MAAM,WAAW,iCAAiC;IAEhD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IAIzC,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC;IAElD,IAAI,IAAI,MAAM,CAAC;IAEf,QAAQ,IAAI,MAAM,CAAC;IAGnB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,WAAW,CAAC,EAC/D,MAAM,EAAE,YAAY,EACpB,IAAI,GAAE,iCAAsC,GAC3C,0BAA0B,CA8J5B;AAaD,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,mBAAmB,GAC3B,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,WAAW,CAAC,CAW3D"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export const DEFAULT_EMITTER_CAPACITY = 1024;
|
|
2
|
+
export const DEFAULT_EMITTER_BACKOFF_INITIAL_MS = 500;
|
|
3
|
+
export const DEFAULT_EMITTER_BACKOFF_MAX_MS = 30_000;
|
|
4
|
+
export const DEFAULT_EMITTER_MAX_RETRIES = 5;
|
|
5
|
+
export function createUndispatchedChangedEmitter(post, logger, opts = {}) {
|
|
6
|
+
const cap = opts.capacity ?? DEFAULT_EMITTER_CAPACITY;
|
|
7
|
+
const initialBackoff = opts.backoffInitialMs ?? DEFAULT_EMITTER_BACKOFF_INITIAL_MS;
|
|
8
|
+
const maxBackoff = opts.backoffMaxMs ?? DEFAULT_EMITTER_BACKOFF_MAX_MS;
|
|
9
|
+
const maxRetries = opts.maxRetries ?? DEFAULT_EMITTER_MAX_RETRIES;
|
|
10
|
+
if (cap <= 0)
|
|
11
|
+
throw new Error(`capacity must be positive: ${cap}`);
|
|
12
|
+
if (initialBackoff <= 0)
|
|
13
|
+
throw new Error(`backoffInitialMs must be positive: ${initialBackoff}`);
|
|
14
|
+
if (maxBackoff < initialBackoff)
|
|
15
|
+
throw new Error(`backoffMaxMs must be >= backoffInitialMs`);
|
|
16
|
+
if (maxRetries < 0)
|
|
17
|
+
throw new Error(`maxRetries must be non-negative: ${maxRetries}`);
|
|
18
|
+
const queue = [];
|
|
19
|
+
let draining = false;
|
|
20
|
+
let stopped = false;
|
|
21
|
+
let activeDrain = null;
|
|
22
|
+
let wakeSleep = null;
|
|
23
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
24
|
+
const t = setTimeout(() => {
|
|
25
|
+
wakeSleep = null;
|
|
26
|
+
resolve();
|
|
27
|
+
}, ms);
|
|
28
|
+
t.unref?.();
|
|
29
|
+
wakeSleep = () => {
|
|
30
|
+
clearTimeout(t);
|
|
31
|
+
wakeSleep = null;
|
|
32
|
+
resolve();
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const drain = async () => {
|
|
36
|
+
while (!stopped && queue.length > 0) {
|
|
37
|
+
const event = queue[0];
|
|
38
|
+
if (!event)
|
|
39
|
+
break;
|
|
40
|
+
let attempts = 0;
|
|
41
|
+
while (true) {
|
|
42
|
+
if (stopped)
|
|
43
|
+
return;
|
|
44
|
+
let outcome;
|
|
45
|
+
try {
|
|
46
|
+
outcome = await post(event);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
outcome = {
|
|
50
|
+
ok: false,
|
|
51
|
+
terminal: false,
|
|
52
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (outcome.ok)
|
|
56
|
+
break;
|
|
57
|
+
if (outcome.terminal) {
|
|
58
|
+
logger.warn("undispatched_changed_drop_terminal", {
|
|
59
|
+
action: event.action,
|
|
60
|
+
undispatched_id: event.undispatched_id,
|
|
61
|
+
status: outcome.status,
|
|
62
|
+
detail: outcome.detail,
|
|
63
|
+
});
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
attempts++;
|
|
67
|
+
if (attempts > maxRetries) {
|
|
68
|
+
logger.warn("undispatched_changed_drop_max_retries", {
|
|
69
|
+
action: event.action,
|
|
70
|
+
undispatched_id: event.undispatched_id,
|
|
71
|
+
attempts,
|
|
72
|
+
status: outcome.status,
|
|
73
|
+
detail: outcome.detail,
|
|
74
|
+
});
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
const backoff = Math.min(initialBackoff * 2 ** (attempts - 1), maxBackoff);
|
|
78
|
+
logger.info("undispatched_changed_retry", {
|
|
79
|
+
action: event.action,
|
|
80
|
+
undispatched_id: event.undispatched_id,
|
|
81
|
+
attempt: attempts,
|
|
82
|
+
backoff_ms: backoff,
|
|
83
|
+
status: outcome.status,
|
|
84
|
+
});
|
|
85
|
+
await sleep(backoff);
|
|
86
|
+
}
|
|
87
|
+
queue.shift();
|
|
88
|
+
}
|
|
89
|
+
draining = false;
|
|
90
|
+
};
|
|
91
|
+
const kick = () => {
|
|
92
|
+
if (draining || stopped)
|
|
93
|
+
return;
|
|
94
|
+
draining = true;
|
|
95
|
+
activeDrain = drain().catch((err) => {
|
|
96
|
+
logger.error("undispatched_changed_drain_unexpected_error", {
|
|
97
|
+
err: err instanceof Error ? err.message : String(err),
|
|
98
|
+
});
|
|
99
|
+
draining = false;
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
enqueue(event) {
|
|
104
|
+
if (stopped)
|
|
105
|
+
return true;
|
|
106
|
+
let evicted = false;
|
|
107
|
+
if (queue.length >= cap) {
|
|
108
|
+
const old = queue.shift();
|
|
109
|
+
if (old) {
|
|
110
|
+
logger.warn("undispatched_changed_queue_overflow", {
|
|
111
|
+
dropped_action: old.action,
|
|
112
|
+
dropped_undispatched_id: old.undispatched_id,
|
|
113
|
+
size: queue.length,
|
|
114
|
+
capacity: cap,
|
|
115
|
+
});
|
|
116
|
+
evicted = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
queue.push(event);
|
|
120
|
+
kick();
|
|
121
|
+
return !evicted;
|
|
122
|
+
},
|
|
123
|
+
size() {
|
|
124
|
+
return queue.length;
|
|
125
|
+
},
|
|
126
|
+
capacity() {
|
|
127
|
+
return cap;
|
|
128
|
+
},
|
|
129
|
+
async shutdown() {
|
|
130
|
+
stopped = true;
|
|
131
|
+
wakeSleep?.();
|
|
132
|
+
if (activeDrain) {
|
|
133
|
+
await activeDrain.catch(() => { });
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function postUndispatchedChangedViaPort(apiPort) {
|
|
139
|
+
return async (event) => {
|
|
140
|
+
if (!apiPort.emitUndispatchedChanged) {
|
|
141
|
+
return {
|
|
142
|
+
ok: false,
|
|
143
|
+
terminal: true,
|
|
144
|
+
detail: "emitUndispatchedChanged not implemented on this apiPort",
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return apiPort.emitUndispatchedChanged(event);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -61,4 +61,14 @@ export declare function transitionRuntimeEndpointState(cfg: PlatformClientConfig
|
|
|
61
61
|
export declare function unregisterRuntimeEndpoint(cfg: PlatformClientConfig, runtimeKey: string, endpointId: string, asNodeId?: string): Promise<UnregisterRuntimeEndpointResponse>;
|
|
62
62
|
export declare function listOwnedRuntimeEndpoints(cfg: PlatformClientConfig, runtimeKey: string, asNodeId: string): Promise<ListOwnedRuntimeEndpointsResponse>;
|
|
63
63
|
export declare function getOwnedRuntimeEndpoint(cfg: PlatformClientConfig, runtimeKey: string, endpointId: string, asNodeId: string): Promise<OwnedRuntimeEndpointView>;
|
|
64
|
+
export declare function emitRuntimeUndispatchedChanged(cfg: PlatformClientConfig, runtimeKey: string, event: Readonly<Record<string, unknown>>): Promise<EmitUndispatchedChangedOutcome>;
|
|
65
|
+
export type EmitUndispatchedChangedOutcome = {
|
|
66
|
+
ok: true;
|
|
67
|
+
} | {
|
|
68
|
+
ok: false;
|
|
69
|
+
terminal: boolean;
|
|
70
|
+
status?: number;
|
|
71
|
+
detail?: string;
|
|
72
|
+
};
|
|
73
|
+
export declare function emitRuntimeNetworkPresenceChanged(cfg: PlatformClientConfig, runtimeKey: string, event: Readonly<Record<string, unknown>>): Promise<EmitUndispatchedChangedOutcome>;
|
|
64
74
|
//# sourceMappingURL=runtime-endpoint-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-endpoint-client.d.ts","sourceRoot":"","sources":["../src/runtime-endpoint-client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime-endpoint-client.d.ts","sourceRoot":"","sources":["../src/runtime-endpoint-client.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,gBAAgB,EAChB,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,CAAC;AAmBvD,MAAM,MAAM,WAAW,GACnB,aAAa,GACb,UAAU,GACV,OAAO,GACP,UAAU,GACV,QAAQ,GACR,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAalB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,cAAc,GACd,oBAAoB,GACpB,aAAa,GACb,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAUlB,MAAM,WAAW,6BAA6B;IAQ5C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,WAAW,CAAC;IAO1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,cAAc,EAAE,MAAM,CAAC;IAEvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAE9B,YAAY,CAAC,EAAE,MAAM,CAAC;IAKtB,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACxC;AAcD,MAAM,WAAW,+BAA+B;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;CACvB;AAeD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IAKpB,OAAO,EAAE,MAAM,CAAC;IAUhB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,WAAW,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAQ5B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IAYtB,WAAW,CAAC,EAAE;QACZ,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClD,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IAOpB,OAAO,EAAE,OAAO,CAAC;CAClB;AASD,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,wBAAwB,EAAE,CAAC;CACnC;AAUD,MAAM,MAAM,gCAAgC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAQvE,MAAM,MAAM,iCAAiC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAYxE,MAAM,WAAW,oCAAoC;IAEnD,KAAK,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,CAAC;IAG5C,MAAM,EAAE,MAAM,CAAC;IAEf,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,sCAAsC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA4D7E,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAQ1C;AAiBD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,gCAAgC,CAAC,CAY3C;AA0BD,wBAAsB,8BAA8B,CAClD,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,oCAAoC,GAC3C,OAAO,CAAC,sCAAsC,CAAC,CAYjD;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iCAAiC,CAAC,CAc5C;AAgBD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,iCAAiC,CAAC,CAO5C;AAWD,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CAUnC;AA0BD,wBAAsB,8BAA8B,CAClD,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAOlB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,OAAO,CAAC,8BAA8B,CAAC,CAoCzC;AAED,MAAM,MAAM,8BAA8B,GACtC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAqBvE,wBAAsB,iCAAiC,CACrD,GAAG,EAAE,oBAAoB,EACzB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,OAAO,CAAC,8BAA8B,CAAC,CA8BzC"}
|
|
@@ -82,3 +82,82 @@ export async function getOwnedRuntimeEndpoint(cfg, runtimeKey, endpointId, asNod
|
|
|
82
82
|
return handleError(res);
|
|
83
83
|
return (await res.json());
|
|
84
84
|
}
|
|
85
|
+
export async function emitRuntimeUndispatchedChanged(cfg, runtimeKey, event) {
|
|
86
|
+
let res;
|
|
87
|
+
try {
|
|
88
|
+
res = await fetch(`${baseUrl(cfg)}/runtime/undispatched-changed`, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: jsonHeaders(runtimeKey),
|
|
91
|
+
body: JSON.stringify(event),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
terminal: false,
|
|
98
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (res.status === 204)
|
|
102
|
+
return { ok: true };
|
|
103
|
+
if (res.status === 401 || res.status === 422) {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
terminal: true,
|
|
107
|
+
status: res.status,
|
|
108
|
+
detail: await readErrorDetail(res),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
terminal: false,
|
|
114
|
+
status: res.status,
|
|
115
|
+
detail: await readErrorDetail(res),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export async function emitRuntimeNetworkPresenceChanged(cfg, runtimeKey, event) {
|
|
119
|
+
let res;
|
|
120
|
+
try {
|
|
121
|
+
res = await fetch(`${baseUrl(cfg)}/runtime/network-presence-changed`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: jsonHeaders(runtimeKey),
|
|
124
|
+
body: JSON.stringify(event),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
terminal: false,
|
|
131
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (res.status === 204)
|
|
135
|
+
return { ok: true };
|
|
136
|
+
if (res.status === 401 || res.status === 422) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
terminal: true,
|
|
140
|
+
status: res.status,
|
|
141
|
+
detail: await readErrorDetail(res),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
terminal: false,
|
|
147
|
+
status: res.status,
|
|
148
|
+
detail: await readErrorDetail(res),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function readErrorDetail(res) {
|
|
152
|
+
try {
|
|
153
|
+
const body = (await res.json().catch(() => null));
|
|
154
|
+
if (!body)
|
|
155
|
+
return undefined;
|
|
156
|
+
const code = typeof body.error === "string" ? body.error : undefined;
|
|
157
|
+
const message = typeof body.message === "string" ? body.message : undefined;
|
|
158
|
+
return [code, message].filter(Boolean).join(": ") || undefined;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "0.5.
|
|
1
|
+
export declare const PLUGIN_VERSION = "0.5.322";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc,YAAY,CAAC"}
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PLUGIN_VERSION = "0.5.
|
|
1
|
+
export const PLUGIN_VERSION = "0.5.322";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@masons/agent-network",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.322",
|
|
4
4
|
"description": "MASONS Agent Network — connects agent runtimes to the Agent Network over MSTP. Ships an OpenClaw channel plugin (root export) and subpath exports consumed by the Claude Code plugin today (planned: Codex and future hosts).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
|