@masons/runtime-broker 0.2.0 → 0.2.1

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.
Files changed (47) hide show
  1. package/dist/broker/broker-daemon.d.ts +7 -0
  2. package/dist/broker/broker-daemon.d.ts.map +1 -1
  3. package/dist/broker/broker-daemon.js +223 -28
  4. package/dist/broker/connector-ws.d.ts +4 -0
  5. package/dist/broker/connector-ws.d.ts.map +1 -1
  6. package/dist/broker/connector-ws.js +12 -0
  7. package/dist/broker/delivery-cursor-file.d.ts +8 -0
  8. package/dist/broker/delivery-cursor-file.d.ts.map +1 -0
  9. package/dist/broker/delivery-cursor-file.js +71 -0
  10. package/dist/broker/entry.d.ts.map +1 -1
  11. package/dist/broker/entry.js +4 -1
  12. package/dist/broker/ipc-server.d.ts +2 -1
  13. package/dist/broker/ipc-server.d.ts.map +1 -1
  14. package/dist/broker/ipc-server.js +2 -1
  15. package/dist/broker/paths.d.ts +1 -0
  16. package/dist/broker/paths.d.ts.map +1 -1
  17. package/dist/broker/paths.js +1 -0
  18. package/dist/broker/reconnecting-buffer.d.ts +1 -0
  19. package/dist/broker/reconnecting-buffer.d.ts.map +1 -1
  20. package/dist/broker/runtime-endpoint-port.d.ts +2 -0
  21. package/dist/broker/runtime-endpoint-port.d.ts.map +1 -1
  22. package/dist/broker/runtime-inbound-routed-emitter.d.ts +22 -0
  23. package/dist/broker/runtime-inbound-routed-emitter.d.ts.map +1 -0
  24. package/dist/broker/runtime-inbound-routed-emitter.js +147 -0
  25. package/dist/broker/runtime-inbound-routed-event-types.d.ts +10 -0
  26. package/dist/broker/runtime-inbound-routed-event-types.d.ts.map +1 -0
  27. package/dist/broker/runtime-inbound-routed-event-types.js +1 -0
  28. package/dist/broker/undispatched-changed-event-types.d.ts +1 -0
  29. package/dist/broker/undispatched-changed-event-types.d.ts.map +1 -1
  30. package/dist/broker/undispatched-inbox.d.ts +1 -0
  31. package/dist/broker/undispatched-inbox.d.ts.map +1 -1
  32. package/dist/broker/version-handshake.js +1 -1
  33. package/dist/broker-client/broker-client.d.ts +1 -0
  34. package/dist/broker-client/broker-client.d.ts.map +1 -1
  35. package/dist/broker-client/broker-client.js +3 -0
  36. package/dist/connector-client.d.ts +5 -0
  37. package/dist/connector-client.d.ts.map +1 -1
  38. package/dist/connector-client.js +47 -5
  39. package/dist/runtime-endpoint-client.d.ts +4 -0
  40. package/dist/runtime-endpoint-client.d.ts.map +1 -1
  41. package/dist/runtime-endpoint-client.js +33 -0
  42. package/dist/types.d.ts +2 -0
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js +1 -0
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +13 -12
@@ -11,6 +11,7 @@ import type { NetworkPresenceChangedEvent } from "./network-presence-changed-eve
11
11
  import type { BrokerPaths } from "./paths.js";
12
12
  import { type BufferedMessage } from "./reconnecting-buffer.js";
13
13
  import type { RuntimeEndpointPort } from "./runtime-endpoint-port.js";
14
+ import type { RuntimeInboundRoutedEvent } from "./runtime-inbound-routed-event-types.js";
14
15
  import type { ServicesEventClient } from "./services-event-client.js";
15
16
  import type { SpawnDriverRegistry } from "./spawn-driver.js";
16
17
  import { type UndispatchedChangedEvent } from "./undispatched-changed-event-types.js";
@@ -49,6 +50,11 @@ export interface BrokerDaemonOptions {
49
50
  networkPresenceChangedBackoffInitialMs?: number;
50
51
  networkPresenceChangedBackoffMaxMs?: number;
51
52
  networkPresenceChangedMaxRetries?: number;
53
+ runtimeInboundRoutedPost?: (event: RuntimeInboundRoutedEvent) => Promise<import("./runtime-endpoint-port.js").EmitOutcome>;
54
+ runtimeInboundRoutedCapacity?: number;
55
+ runtimeInboundRoutedBackoffInitialMs?: number;
56
+ runtimeInboundRoutedBackoffMaxMs?: number;
57
+ runtimeInboundRoutedMaxRetries?: number;
52
58
  }
53
59
  export interface RunningBroker {
54
60
  bearerToken: string;
@@ -64,6 +70,7 @@ export interface RunningBroker {
64
70
  replyCorrelationCacheSize(endpoint_id: string): number;
65
71
  undispatchedChangedQueueSize(): number;
66
72
  networkPresenceChangedQueueSize(): number;
73
+ runtimeInboundRoutedQueueSize(): number;
67
74
  }
68
75
  export declare function startBrokerDaemon(opts: BrokerDaemonOptions): Promise<RunningBroker>;
69
76
  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":"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"}
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;AAIjD,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;AAWlC,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,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AAM7F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAO9C,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAEV,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AAMpC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAKtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,uCAAuC,CAAC;AAM/C,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,WAAW,CAAC;IACvB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,YAAY,CAAC;IAGrB,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAE5C,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAKhD,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAG1C,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC;IAG5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAGhC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAGnC,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAK5B,0BAA0B,CAAC,EAAE,CAAC,IAAI,EAAE;QAClC,UAAU,EAAE,sBAAsB,CAAC;QACnC,MAAM,EAAE,YAAY,CAAC;KACtB,KAAK,mBAAmB,CAAC;IAK1B,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAQpD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAI/B,8BAA8B,CAAC,EAAE,MAAM,CAAC;IAIxC,uBAAuB,CAAC,EAAE,CACxB,KAAK,EAAE,wBAAwB,KAC5B,OAAO,CAAC,OAAO,4BAA4B,EAAE,WAAW,CAAC,CAAC;IAG/D,2BAA2B,CAAC,EAAE,MAAM,CAAC;IAErC,mCAAmC,CAAC,EAAE,MAAM,CAAC;IAE7C,+BAA+B,CAAC,EAAE,MAAM,CAAC;IAEzC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAIvC,0BAA0B,CAAC,EAAE,CAC3B,KAAK,EAAE,2BAA2B,KAC/B,OAAO,CAAC,OAAO,4BAA4B,EAAE,WAAW,CAAC,CAAC;IAI/D,8BAA8B,CAAC,EAAE,MAAM,CAAC;IAExC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IAEhD,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAE5C,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAG1C,wBAAwB,CAAC,EAAE,CACzB,KAAK,EAAE,yBAAyB,KAC7B,OAAO,CAAC,OAAO,4BAA4B,EAAE,WAAW,CAAC,CAAC;IAE/D,4BAA4B,CAAC,EAAE,MAAM,CAAC;IAEtC,oCAAoC,CAAC,EAAE,MAAM,CAAC;IAE9C,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAE1C,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACzC;AAgBD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,YAAY,IAAI,MAAM,CAAC;IAGvB,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;IAEtD,iBAAiB,EAAE,iBAAiB,CAAC;IAErC,sBAAsB,EAAE,sBAAsB,CAAC;IAE/C,eAAe,IAAI,eAAe,CAAC;IAEnC,iBAAiB,IAAI,MAAM,CAAC;IAE5B,cAAc,IAAI,MAAM,CAAC;IAGzB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAGvD,4BAA4B,IAAI,MAAM,CAAC;IAGvC,+BAA+B,IAAI,MAAM,CAAC;IAE1C,6BAA6B,IAAI,MAAM,CAAC;CACzC;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,CAy/CxB;AAGD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -2,6 +2,7 @@ import { spawn as spawnChild } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { basename } from "node:path";
4
4
  import { createControlEventDispatcher, } from "./control-event-dispatcher.js";
5
+ import { readDeliveryCursorFile, writeDeliveryCursorFile, } from "./delivery-cursor-file.js";
5
6
  import { deleteDiscoveryFile, mintBearerToken, writeDiscoveryFile, } from "./discovery-file.js";
6
7
  import { EndpointRegistry } from "./endpoint-registry.js";
7
8
  import { DEFAULT_GRACE_MS, transition, } from "./endpoint-state-machine.js";
@@ -13,12 +14,14 @@ import { isPluginAlive as defaultIsPluginAlive } from "./plugin-liveness.js";
13
14
  import { createReceivedMessageCorrelationCache, DEFAULT_TTL_MS as DEFAULT_REPLY_CORRELATION_TTL_MS, } from "./received-message-correlation-cache.js";
14
15
  import { createReconnectingBufferManager, } from "./reconnecting-buffer.js";
15
16
  import { RoutingTable } from "./routing-table.js";
17
+ import { createRuntimeInboundRoutedEmitter, postRuntimeInboundRoutedViaPort, } from "./runtime-inbound-routed-emitter.js";
16
18
  import { createSpawnCorrelationManager, createSpawnRateLimiter, } from "./spawn-correlation.js";
17
19
  import { TASK_HINT_MAX_LENGTH, updateTaskHint } from "./task-hint-handler.js";
18
20
  import { createTransitionStateRetryQueue } from "./transition-state-retry-queue.js";
19
21
  import { CONTENT_PREVIEW_MAX_CODEPOINTS, truncateContentPreview, } from "./undispatched-changed-event-types.js";
20
22
  import { createUndispatchedChangedEmitter, postUndispatchedChangedViaPort, } from "./undispatched-emitter.js";
21
23
  import { createUndispatchedInbox, } from "./undispatched-inbox.js";
24
+ const REMOTE_SPAWN_CAPABILITY = "remote_spawn_v1";
22
25
  function derivePublicDisplayLabel(body) {
23
26
  const parts = [
24
27
  body.kind,
@@ -40,6 +43,11 @@ export async function startBrokerDaemon(opts) {
40
43
  (async () => {
41
44
  });
42
45
  void _asNodeIdReservedForA3;
46
+ const persistedDeliveryCursor = readDeliveryCursorFile(paths.deliveryCursorFile) ?? 0;
47
+ connector.setDeliveryCursor(persistedDeliveryCursor);
48
+ logger.info("delivery_cursor_loaded", {
49
+ lastKnownSeq: persistedDeliveryCursor,
50
+ });
43
51
  logger.info("connecting_to_connector");
44
52
  await connector.connect();
45
53
  logger.info("connector_connected");
@@ -86,7 +94,8 @@ export async function startBrokerDaemon(opts) {
86
94
  }
87
95
  }, replyCorrelationSweepInterval);
88
96
  replyCorrelationSweepTimer.unref?.();
89
- const undispatchedEmitter = createUndispatchedChangedEmitter(opts.undispatchedChangedPost ?? postUndispatchedChangedViaPort(apiPort), logger, {
97
+ const postUndispatchedChanged = opts.undispatchedChangedPost ?? postUndispatchedChangedViaPort(apiPort);
98
+ const undispatchedEmitter = createUndispatchedChangedEmitter(postUndispatchedChanged, logger, {
90
99
  capacity: opts.undispatchedChangedCapacity,
91
100
  backoffInitialMs: opts.undispatchedChangedBackoffInitialMs,
92
101
  backoffMaxMs: opts.undispatchedChangedBackoffMaxMs,
@@ -105,6 +114,79 @@ export async function startBrokerDaemon(opts) {
105
114
  const emitNetworkPresence = (event) => {
106
115
  networkPresenceEmitter.enqueue(event);
107
116
  };
117
+ const postRuntimeInboundRouted = opts.runtimeInboundRoutedPost ?? postRuntimeInboundRoutedViaPort(apiPort);
118
+ const runtimeInboundRoutedEmitter = createRuntimeInboundRoutedEmitter(postRuntimeInboundRouted, logger, {
119
+ capacity: opts.runtimeInboundRoutedCapacity,
120
+ backoffInitialMs: opts.runtimeInboundRoutedBackoffInitialMs,
121
+ backoffMaxMs: opts.runtimeInboundRoutedBackoffMaxMs,
122
+ maxRetries: opts.runtimeInboundRoutedMaxRetries,
123
+ });
124
+ const directPostUndispatched = async (event, opts = {}) => {
125
+ let outcome;
126
+ try {
127
+ outcome = await postUndispatchedChanged(event);
128
+ }
129
+ catch (err) {
130
+ outcome = {
131
+ ok: false,
132
+ terminal: false,
133
+ detail: err instanceof Error ? err.message : String(err),
134
+ };
135
+ }
136
+ if (outcome.ok)
137
+ return true;
138
+ logger.warn("undispatched_changed_direct_post_failed", {
139
+ action: event.action,
140
+ undispatched_id: event.undispatched_id,
141
+ terminal: outcome.terminal,
142
+ status: outcome.status,
143
+ detail: outcome.detail,
144
+ });
145
+ if (!outcome.terminal && opts.queueOnTransientFailure !== false) {
146
+ undispatchedEmitter.enqueue(event);
147
+ }
148
+ return false;
149
+ };
150
+ const directPostRuntimeInboundRouted = async (event, opts = {}) => {
151
+ let outcome;
152
+ try {
153
+ outcome = await postRuntimeInboundRouted(event);
154
+ }
155
+ catch (err) {
156
+ outcome = {
157
+ ok: false,
158
+ terminal: false,
159
+ detail: err instanceof Error ? err.message : String(err),
160
+ };
161
+ }
162
+ if (outcome.ok)
163
+ return true;
164
+ logger.warn("runtime_inbound_routed_direct_post_failed", {
165
+ source_message_id: event.source_message_id,
166
+ routed_to_endpoint_id: event.routed_to_endpoint_id,
167
+ terminal: outcome.terminal,
168
+ status: outcome.status,
169
+ detail: outcome.detail,
170
+ });
171
+ if (!outcome.terminal && opts.queueOnTransientFailure !== false) {
172
+ runtimeInboundRoutedEmitter.enqueue(event);
173
+ }
174
+ return false;
175
+ };
176
+ const markDeliverySeqAccepted = (seq) => {
177
+ if (typeof seq !== "number")
178
+ return true;
179
+ const before = connector.getDeliveryCursor();
180
+ const prepared = connector.prepareDeliverySeqAccepted(seq);
181
+ if (typeof prepared === "number" && prepared !== before) {
182
+ writeDeliveryCursorFile(paths.deliveryCursorFile, prepared);
183
+ }
184
+ const after = connector.markDeliverySeqAccepted(seq);
185
+ if (after !== prepared) {
186
+ throw new Error("delivery cursor changed during durable commit");
187
+ }
188
+ return true;
189
+ };
108
190
  const recordInboundCorrelation = (endpoint_id, metadata) => {
109
191
  const c = metadata && typeof metadata.correlation_id === "string"
110
192
  ? metadata.correlation_id
@@ -285,6 +367,9 @@ export async function startBrokerDaemon(opts) {
285
367
  content: msg.envelope.content,
286
368
  contentType: msg.envelope.contentType,
287
369
  metadata: msg.envelope.metadata,
370
+ ...(msg.envelope.sourceMessageId !== undefined && {
371
+ sourceMessageId: msg.envelope.sourceMessageId,
372
+ }),
288
373
  });
289
374
  }
290
375
  }
@@ -326,6 +411,9 @@ export async function startBrokerDaemon(opts) {
326
411
  version: 1,
327
412
  action: "remove",
328
413
  undispatched_id: event.undispatched_id,
414
+ ...(taken.source_message_id !== undefined && {
415
+ source_message_id: taken.source_message_id,
416
+ }),
329
417
  remove_reason: "lost_at_capacity_during_redispatch_bounce",
330
418
  });
331
419
  }
@@ -344,6 +432,9 @@ export async function startBrokerDaemon(opts) {
344
432
  dispatched_from: event.undispatched_id,
345
433
  dispatched_by: "passport",
346
434
  },
435
+ ...(taken.source_message_id !== undefined && {
436
+ sourceMessageId: taken.source_message_id,
437
+ }),
347
438
  };
348
439
  recordInboundCorrelation(target.endpoint_id, stamped.metadata);
349
440
  if (target.state === "active") {
@@ -359,6 +450,9 @@ export async function startBrokerDaemon(opts) {
359
450
  content: taken.content,
360
451
  contentType: taken.content_type,
361
452
  metadata: stamped.metadata,
453
+ ...(stamped.sourceMessageId !== undefined && {
454
+ sourceMessageId: stamped.sourceMessageId,
455
+ }),
362
456
  },
363
457
  });
364
458
  }
@@ -372,6 +466,9 @@ export async function startBrokerDaemon(opts) {
372
466
  version: 1,
373
467
  action: "dispatch",
374
468
  undispatched_id: event.undispatched_id,
469
+ ...(taken.source_message_id !== undefined && {
470
+ source_message_id: taken.source_message_id,
471
+ }),
375
472
  dispatched_to_endpoint_id: event.target_endpoint_id,
376
473
  });
377
474
  return { ok: true };
@@ -461,6 +558,13 @@ export async function startBrokerDaemon(opts) {
461
558
  throw new BrokerHttpError(400, "ipc_channel_missing", `no open IPC channel for plugin_pid=${body.plugin_pid}; ` +
462
559
  "open WS /v1/stream with x-plugin-pid header first");
463
560
  }
561
+ const spawnDriver = spawnDriverRegistry?.lookup(body.kind);
562
+ const spawnAvailability = spawnDriver
563
+ ? await spawnDriver.isAvailable().catch(() => ({ available: false }))
564
+ : null;
565
+ const runtimeCapabilities = spawnAvailability?.available
566
+ ? [REMOTE_SPAWN_CAPABILITY]
567
+ : undefined;
464
568
  const apiResp = await apiPort.register({
465
569
  runtime_kind: body.kind,
466
570
  endpoint_nonce: randomUUID(),
@@ -471,6 +575,7 @@ export async function startBrokerDaemon(opts) {
471
575
  tracking_ref: body.tracking_ref,
472
576
  session_name: body.session_name,
473
577
  task_hint: body.task_hint,
578
+ runtime_capabilities: runtimeCapabilities,
474
579
  });
475
580
  registry.register({
476
581
  endpoint_id: apiResp.endpoint_id,
@@ -627,6 +732,9 @@ export async function startBrokerDaemon(opts) {
627
732
  content: msg.envelope.content,
628
733
  contentType: msg.envelope.contentType,
629
734
  metadata: msg.envelope.metadata,
735
+ ...(msg.envelope.sourceMessageId !== undefined && {
736
+ sourceMessageId: msg.envelope.sourceMessageId,
737
+ }),
630
738
  });
631
739
  }
632
740
  emitTransition(endpoint_id, "active", "reattach");
@@ -724,7 +832,10 @@ export async function startBrokerDaemon(opts) {
724
832
  }
725
833
  },
726
834
  });
727
- connector.on("message_received", async ({ payload }) => {
835
+ const inboundProcessing = new Set();
836
+ const blockedInboundSeqs = new Set();
837
+ let unsequencedInboundBlocked = false;
838
+ const handleInboundMessage = async (payload) => {
728
839
  const meta = payload.metadata ?? {};
729
840
  const target_endpoint_id = typeof meta.target_endpoint_id === "string"
730
841
  ? meta.target_endpoint_id
@@ -732,26 +843,48 @@ export async function startBrokerDaemon(opts) {
732
843
  const correlation_id = typeof meta.correlation_id === "string" ? meta.correlation_id : undefined;
733
844
  const decision = router.route({ target_endpoint_id, correlation_id });
734
845
  if (decision.kind === "endpoint") {
846
+ if (payload.messageId !== undefined) {
847
+ const posted = await directPostRuntimeInboundRouted({
848
+ type: "runtime_inbound_routed",
849
+ version: 1,
850
+ source_message_id: payload.messageId,
851
+ routed_to_endpoint_id: decision.entry.endpoint_id,
852
+ route_kind: decision.entry.state === "active"
853
+ ? "active_endpoint"
854
+ : "reconnecting_endpoint",
855
+ routed_at: Date.now(),
856
+ }, { queueOnTransientFailure: typeof payload.seq !== "number" });
857
+ if (!posted && typeof payload.seq === "number")
858
+ return false;
859
+ }
735
860
  recordInboundCorrelation(decision.entry.endpoint_id, meta);
736
861
  if (decision.entry.state === "active") {
737
- pushToPlugin(decision.entry.ipc_ws, {
862
+ const pushed = pushToPlugin(decision.entry.ipc_ws, {
738
863
  event: "message_received",
739
864
  from: payload.from,
740
865
  content: payload.content,
741
866
  contentType: payload.contentType,
742
867
  metadata: meta,
868
+ ...(payload.messageId !== undefined && {
869
+ sourceMessageId: payload.messageId,
870
+ }),
743
871
  });
872
+ if (!pushed)
873
+ return false;
744
874
  }
745
875
  else {
746
876
  const buf = reconnectingBuffers.forEndpoint(decision.entry.endpoint_id);
747
877
  buf.append({
748
- id: randomUUID(),
878
+ id: payload.messageId ?? randomUUID(),
749
879
  arrived_at: new Date().toISOString(),
750
880
  envelope: {
751
881
  from: payload.from,
752
882
  content: payload.content,
753
883
  contentType: payload.contentType,
754
884
  metadata: meta,
885
+ ...(payload.messageId !== undefined && {
886
+ sourceMessageId: payload.messageId,
887
+ }),
755
888
  },
756
889
  });
757
890
  logger.info("buffered_for_reconnecting_endpoint", {
@@ -759,7 +892,7 @@ export async function startBrokerDaemon(opts) {
759
892
  buffer_size: buf.size(),
760
893
  });
761
894
  }
762
- return;
895
+ return markDeliverySeqAccepted(payload.seq);
763
896
  }
764
897
  let reason = "unaddressed";
765
898
  let originalTarget;
@@ -779,7 +912,10 @@ export async function startBrokerDaemon(opts) {
779
912
  }
780
913
  }
781
914
  const undispatched = {
782
- id: randomUUID(),
915
+ id: payload.messageId ?? randomUUID(),
916
+ ...(payload.messageId !== undefined && {
917
+ source_message_id: payload.messageId,
918
+ }),
783
919
  arrived_at: new Date().toISOString(),
784
920
  sender_address: payload.from,
785
921
  content: payload.content,
@@ -796,31 +932,82 @@ export async function startBrokerDaemon(opts) {
796
932
  size: undispatchedInbox.size(),
797
933
  capacity: undispatchedInbox.capacity(),
798
934
  });
935
+ return false;
799
936
  }
800
- else {
801
- logger.info("undispatched_added", { id: undispatched.id, reason });
802
- const wireReason = undispatched.reason === "unaddressed"
803
- ? "no_target_endpoint"
804
- : undispatched.reason;
805
- emitUndispatched({
806
- type: "undispatched_changed",
807
- version: 1,
808
- action: "add",
809
- undispatched_id: undispatched.id,
810
- sender_address: undispatched.sender_address,
811
- content_preview: truncateContentPreview(undispatched.content, CONTENT_PREVIEW_MAX_CODEPOINTS),
812
- reason: wireReason,
813
- ...(undispatched.original_target_endpoint_id !== undefined && {
814
- target_endpoint_id_hint: undispatched.original_target_endpoint_id,
815
- }),
816
- ...(typeof correlation_id === "string" && {
817
- in_reply_to: correlation_id,
818
- }),
819
- arrived_at: Date.parse(undispatched.arrived_at),
937
+ logger.info("undispatched_added", { id: undispatched.id, reason });
938
+ const wireReason = undispatched.reason === "unaddressed"
939
+ ? "no_target_endpoint"
940
+ : undispatched.reason;
941
+ const posted = await directPostUndispatched({
942
+ type: "undispatched_changed",
943
+ version: 1,
944
+ action: "add",
945
+ undispatched_id: undispatched.id,
946
+ ...(undispatched.source_message_id !== undefined && {
947
+ source_message_id: undispatched.source_message_id,
948
+ }),
949
+ sender_address: undispatched.sender_address,
950
+ content_preview: truncateContentPreview(undispatched.content, CONTENT_PREVIEW_MAX_CODEPOINTS),
951
+ reason: wireReason,
952
+ ...(undispatched.original_target_endpoint_id !== undefined && {
953
+ target_endpoint_id_hint: undispatched.original_target_endpoint_id,
954
+ }),
955
+ ...(typeof correlation_id === "string" && {
956
+ in_reply_to: correlation_id,
957
+ }),
958
+ arrived_at: Date.parse(undispatched.arrived_at),
959
+ }, { queueOnTransientFailure: typeof payload.seq !== "number" });
960
+ if (!posted)
961
+ return false;
962
+ return markDeliverySeqAccepted(payload.seq);
963
+ };
964
+ connector.on("message_received", ({ payload }) => {
965
+ let task;
966
+ task = handleInboundMessage(payload)
967
+ .then((accepted) => {
968
+ if (typeof payload.seq === "number") {
969
+ if (accepted)
970
+ blockedInboundSeqs.delete(payload.seq);
971
+ else
972
+ blockedInboundSeqs.add(payload.seq);
973
+ return;
974
+ }
975
+ if (accepted)
976
+ unsequencedInboundBlocked = false;
977
+ else
978
+ unsequencedInboundBlocked = true;
979
+ })
980
+ .catch((err) => {
981
+ if (typeof payload.seq === "number") {
982
+ blockedInboundSeqs.add(payload.seq);
983
+ }
984
+ else {
985
+ unsequencedInboundBlocked = true;
986
+ }
987
+ logger.error("inbound_message_handling_failed", {
988
+ err: err instanceof Error ? err.message : String(err),
989
+ messageId: payload.messageId,
990
+ from: payload.from,
820
991
  });
821
- }
992
+ })
993
+ .finally(() => {
994
+ inboundProcessing.delete(task);
995
+ });
996
+ inboundProcessing.add(task);
822
997
  });
823
- connector.on("delivery_pending", ({ payload }) => {
998
+ connector.on("delivery_pending", async ({ payload }) => {
999
+ if (inboundProcessing.size > 0) {
1000
+ await Promise.allSettled([...inboundProcessing]);
1001
+ }
1002
+ if (unsequencedInboundBlocked || blockedInboundSeqs.size > 0) {
1003
+ logger.warn("delivery_ack_deferred_until_replay", {
1004
+ upTo: payload.upTo,
1005
+ count: payload.count,
1006
+ blockedSeqs: [...blockedInboundSeqs].sort((a, b) => a - b),
1007
+ unsequencedBlocked: unsequencedInboundBlocked,
1008
+ });
1009
+ return;
1010
+ }
824
1011
  connector.ackDelivery(payload.upTo);
825
1012
  });
826
1013
  writeDiscoveryFile(paths.discoveryFile, {
@@ -887,6 +1074,13 @@ export async function startBrokerDaemon(opts) {
887
1074
  });
888
1075
  }
889
1076
  await networkPresenceEmitter.shutdown();
1077
+ if (runtimeInboundRoutedEmitter.size() > 0) {
1078
+ logger.warn("runtime_inbound_routed_queue_dropped_on_shutdown", {
1079
+ size: runtimeInboundRoutedEmitter.size(),
1080
+ reason,
1081
+ });
1082
+ }
1083
+ await runtimeInboundRoutedEmitter.shutdown();
890
1084
  const endpoints = registry.list();
891
1085
  await Promise.all(endpoints.map(async (entry) => {
892
1086
  try {
@@ -923,6 +1117,7 @@ export async function startBrokerDaemon(opts) {
923
1117
  retryQueueSize: () => retryQueue.size(),
924
1118
  undispatchedChangedQueueSize: () => undispatchedEmitter.size(),
925
1119
  networkPresenceChangedQueueSize: () => networkPresenceEmitter.size(),
1120
+ runtimeInboundRoutedQueueSize: () => runtimeInboundRoutedEmitter.size(),
926
1121
  replyCorrelationCacheSize: (endpoint_id) => replyCorrelationCache.sizeForEndpoint(endpoint_id),
927
1122
  };
928
1123
  }
@@ -38,6 +38,10 @@ export declare class ConnectorWS {
38
38
  disconnect(): void;
39
39
  send(to: string, content: string, contentType?: string, metadata?: Record<string, unknown>): Promise<SendAckEvent>;
40
40
  ackDelivery(upTo: string): boolean;
41
+ setDeliveryCursor(seq: number): void;
42
+ getDeliveryCursor(): number | undefined;
43
+ prepareDeliverySeqAccepted(seq: number): number | undefined;
44
+ markDeliverySeqAccepted(seq: number): number | undefined;
41
45
  on<E extends ConnectorWSEvent["event"]>(event: E, listener: ListenerFor<E>): this;
42
46
  off<E extends ConnectorWSEvent["event"]>(event: E, listener: ListenerFor<E>): this;
43
47
  _emitForTesting(e: ConnectorWSEvent): void;
@@ -1 +1 @@
1
- {"version":3,"file":"connector-ws.d.ts","sourceRoot":"","sources":["../../src/broker/connector-ws.ts"],"names":[],"mappings":"AAaA,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,qBAAqB,CAAA;CAAE,GAC7D;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAC5C;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAC5D;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAC5D;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,GACzB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC;AAEvC,KAAK,WAAW,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,IAAI,CACtD,CAAC,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,KACvC,IAAI,CAAC;AAEV,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsB;gBAE9B,IAAI,EAAE,kBAAkB;IAMpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,IAAI;IASlB,IAAI,CACF,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,SAAS,EACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,YAAY,CAAC;IAKxB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIlC,EAAE,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,EACpC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GACvB,IAAI;IAKP,GAAG,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,EACrC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GACvB,IAAI;IAMS,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAI1D,OAAO,CAAC,cAAc;CA0BvB;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"connector-ws.d.ts","sourceRoot":"","sources":["../../src/broker/connector-ws.ts"],"names":[],"mappings":"AAaA,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,qBAAqB,CAAA;CAAE,GAC7D;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAC5C;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAC5D;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAC5D;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,GACzB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC;AAEvC,KAAK,WAAW,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,IAAI,CACtD,CAAC,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,KACvC,IAAI,CAAC;AAEV,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsB;gBAE9B,IAAI,EAAE,kBAAkB;IAMpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,IAAI;IASlB,IAAI,CACF,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,SAAS,EACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,YAAY,CAAC;IAKxB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAKlC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKpC,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAKvC,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK3D,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIxD,EAAE,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,EACpC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GACvB,IAAI;IAKP,GAAG,CAAC,CAAC,SAAS,gBAAgB,CAAC,OAAO,CAAC,EACrC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GACvB,IAAI;IAMS,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAI1D,OAAO,CAAC,cAAc;CA0BvB;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -19,6 +19,18 @@ export class ConnectorWS {
19
19
  ackDelivery(upTo) {
20
20
  return this.client.ackDelivery(upTo);
21
21
  }
22
+ setDeliveryCursor(seq) {
23
+ this.client.setDeliveryCursor(seq);
24
+ }
25
+ getDeliveryCursor() {
26
+ return this.client.getDeliveryCursor();
27
+ }
28
+ prepareDeliverySeqAccepted(seq) {
29
+ return this.client.prepareDeliverySeqAccepted(seq);
30
+ }
31
+ markDeliverySeqAccepted(seq) {
32
+ return this.client.markDeliverySeqAccepted(seq);
33
+ }
22
34
  on(event, listener) {
23
35
  this.bus.on(event, listener);
24
36
  return this;
@@ -0,0 +1,8 @@
1
+ export interface DeliveryCursorRecord {
2
+ version: 1;
3
+ lastKnownSeq: number;
4
+ updatedAt: string;
5
+ }
6
+ export declare function readDeliveryCursorFile(path: string): number | null;
7
+ export declare function writeDeliveryCursorFile(path: string, seq: number): void;
8
+ //# sourceMappingURL=delivery-cursor-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-cursor-file.d.ts","sourceRoot":"","sources":["../../src/broker/delivery-cursor-file.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBlE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAiCvE"}
@@ -0,0 +1,71 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { chmodSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ export function readDeliveryCursorFile(path) {
5
+ let raw;
6
+ try {
7
+ raw = readFileSync(path, "utf8");
8
+ }
9
+ catch (err) {
10
+ if (isNodeErr(err, "ENOENT"))
11
+ return null;
12
+ throw err;
13
+ }
14
+ try {
15
+ const parsed = JSON.parse(raw);
16
+ if (!isDeliveryCursorRecord(parsed))
17
+ return null;
18
+ return parsed.lastKnownSeq;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ export function writeDeliveryCursorFile(path, seq) {
25
+ if (!Number.isInteger(seq) || seq < 0) {
26
+ throw new Error(`delivery cursor must be a non-negative integer: ${seq}`);
27
+ }
28
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
29
+ const tmp = `${path}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
30
+ const record = {
31
+ version: 1,
32
+ lastKnownSeq: seq,
33
+ updatedAt: new Date().toISOString(),
34
+ };
35
+ writeFileSync(tmp, JSON.stringify(record, null, 2), {
36
+ mode: 0o600,
37
+ encoding: "utf8",
38
+ });
39
+ try {
40
+ chmodSync(tmp, 0o600);
41
+ }
42
+ catch {
43
+ }
44
+ try {
45
+ renameSync(tmp, path);
46
+ }
47
+ catch (err) {
48
+ try {
49
+ unlinkSync(tmp);
50
+ }
51
+ catch {
52
+ }
53
+ throw err;
54
+ }
55
+ }
56
+ function isDeliveryCursorRecord(value) {
57
+ if (typeof value !== "object" || value === null)
58
+ return false;
59
+ const v = value;
60
+ return (v.version === 1 &&
61
+ typeof v.lastKnownSeq === "number" &&
62
+ Number.isInteger(v.lastKnownSeq) &&
63
+ v.lastKnownSeq >= 0 &&
64
+ typeof v.updatedAt === "string");
65
+ }
66
+ function isNodeErr(err, code) {
67
+ return (typeof err === "object" &&
68
+ err !== null &&
69
+ "code" in err &&
70
+ err.code === code);
71
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AAgFA,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;AAED,UAAU,gBAAgB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAUD,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA8F9B;AA2DD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,OAAO,UAAU,CAAC,KAAwB,GACpD,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAaD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,GACnB,mBAAmB,CAgHrB;AAYD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgG1C"}
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AAiFA,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;AAED,UAAU,gBAAgB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAUD,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA8F9B;AA2DD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,OAAO,UAAU,CAAC,KAAwB,GACpD,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAaD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,GACnB,mBAAmB,CAuHrB;AAYD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgG1C"}
@@ -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 { emitRuntimeNetworkPresenceChanged, emitRuntimeUndispatchedChanged, heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, updateRuntimeEndpointDisplayMetadata, } from "../runtime-endpoint-client.js";
5
+ import { emitRuntimeNetworkPresenceChanged, emitRuntimeInboundRouted, emitRuntimeUndispatchedChanged, heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, updateRuntimeEndpointDisplayMetadata, } 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";
@@ -171,6 +171,9 @@ export function buildApiPort(apiHost, runtimeKey, logger) {
171
171
  async emitNetworkPresenceChanged(event) {
172
172
  return emitRuntimeNetworkPresenceChanged({ apiHost }, runtimeKey, event);
173
173
  },
174
+ async emitRuntimeInboundRouted(event) {
175
+ return emitRuntimeInboundRouted({ apiHost }, runtimeKey, event);
176
+ },
174
177
  };
175
178
  }
176
179
  function errorStatus(err) {
@@ -68,13 +68,14 @@ export interface RunningIPCServer {
68
68
  close(): Promise<void>;
69
69
  }
70
70
  export declare function startIPCServer(opts: IPCServerOptions): Promise<RunningIPCServer>;
71
- export declare function pushToPlugin(ws: WebSocket, event: PushEvent): void;
71
+ export declare function pushToPlugin(ws: WebSocket, event: PushEvent): boolean;
72
72
  export type PushEvent = {
73
73
  event: "message_received";
74
74
  from: string;
75
75
  content: string;
76
76
  contentType: string;
77
77
  metadata?: Record<string, unknown>;
78
+ sourceMessageId?: string;
78
79
  } | {
79
80
  event: "ping";
80
81
  ts: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"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"}
@@ -274,8 +274,9 @@ async function closeServer(http, wss) {
274
274
  }
275
275
  export function pushToPlugin(ws, event) {
276
276
  if (ws.readyState !== WebSocket.OPEN)
277
- return;
277
+ return false;
278
278
  ws.send(JSON.stringify(event));
279
+ return true;
279
280
  }
280
281
  export function parsePluginFrame(data) {
281
282
  try {