@masons/runtime-broker 0.1.1 → 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 (49) 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 +247 -30
  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 +11 -2
  13. package/dist/broker/ipc-server.d.ts.map +1 -1
  14. package/dist/broker/ipc-server.js +32 -7
  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.d.ts +5 -1
  33. package/dist/broker/version-handshake.d.ts.map +1 -1
  34. package/dist/broker/version-handshake.js +3 -2
  35. package/dist/broker-client/broker-client.d.ts +14 -0
  36. package/dist/broker-client/broker-client.d.ts.map +1 -1
  37. package/dist/broker-client/broker-client.js +57 -0
  38. package/dist/connector-client.d.ts +5 -0
  39. package/dist/connector-client.d.ts.map +1 -1
  40. package/dist/connector-client.js +47 -5
  41. package/dist/runtime-endpoint-client.d.ts +4 -0
  42. package/dist/runtime-endpoint-client.d.ts.map +1 -1
  43. package/dist/runtime-endpoint-client.js +33 -0
  44. package/dist/types.d.ts +2 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/types.js +1 -0
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/package.json +1 -1
@@ -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":"AA2BA,OAAO,EAAqB,KAAK,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGjD,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,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,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,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;AAEjC,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;CAC3C;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;CAC3C;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,CAwvCxB;AAGD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED,YAAY,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"broker-daemon.d.ts","sourceRoot":"","sources":["../../src/broker/broker-daemon.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -113,6 +195,7 @@ export async function startBrokerDaemon(opts) {
113
195
  return;
114
196
  replyCorrelationCache.record(endpoint_id, c);
115
197
  };
198
+ const channels = new Map();
116
199
  let networkPresence = "offline";
117
200
  let presenceGraceTimer;
118
201
  const applyPresenceTransition = (event) => {
@@ -150,6 +233,15 @@ export async function startBrokerDaemon(opts) {
150
233
  ts: Date.now(),
151
234
  reason: effect.reason,
152
235
  });
236
+ if (channels.size > 0) {
237
+ for (const ws of channels.values()) {
238
+ pushToPlugin(ws, {
239
+ event: "presence_changed",
240
+ presence: effect.presence,
241
+ ...(effect.reason ? { reason: effect.reason } : {}),
242
+ });
243
+ }
244
+ }
153
245
  if (effect.presence === "online") {
154
246
  void retryQueue.flush(async (entry) => {
155
247
  await apiPort.transitionState(entry.endpoint_id, entry.params);
@@ -166,7 +258,6 @@ export async function startBrokerDaemon(opts) {
166
258
  connector.on("disconnected", () => {
167
259
  applyPresenceTransition({ type: "connector_disconnected" });
168
260
  });
169
- const channels = new Map();
170
261
  const wsEndpoints = new WeakMap();
171
262
  const heartbeatTimers = new Map();
172
263
  const displacedWs = new WeakSet();
@@ -276,6 +367,9 @@ export async function startBrokerDaemon(opts) {
276
367
  content: msg.envelope.content,
277
368
  contentType: msg.envelope.contentType,
278
369
  metadata: msg.envelope.metadata,
370
+ ...(msg.envelope.sourceMessageId !== undefined && {
371
+ sourceMessageId: msg.envelope.sourceMessageId,
372
+ }),
279
373
  });
280
374
  }
281
375
  }
@@ -317,6 +411,9 @@ export async function startBrokerDaemon(opts) {
317
411
  version: 1,
318
412
  action: "remove",
319
413
  undispatched_id: event.undispatched_id,
414
+ ...(taken.source_message_id !== undefined && {
415
+ source_message_id: taken.source_message_id,
416
+ }),
320
417
  remove_reason: "lost_at_capacity_during_redispatch_bounce",
321
418
  });
322
419
  }
@@ -335,6 +432,9 @@ export async function startBrokerDaemon(opts) {
335
432
  dispatched_from: event.undispatched_id,
336
433
  dispatched_by: "passport",
337
434
  },
435
+ ...(taken.source_message_id !== undefined && {
436
+ sourceMessageId: taken.source_message_id,
437
+ }),
338
438
  };
339
439
  recordInboundCorrelation(target.endpoint_id, stamped.metadata);
340
440
  if (target.state === "active") {
@@ -350,6 +450,9 @@ export async function startBrokerDaemon(opts) {
350
450
  content: taken.content,
351
451
  contentType: taken.content_type,
352
452
  metadata: stamped.metadata,
453
+ ...(stamped.sourceMessageId !== undefined && {
454
+ sourceMessageId: stamped.sourceMessageId,
455
+ }),
353
456
  },
354
457
  });
355
458
  }
@@ -363,6 +466,9 @@ export async function startBrokerDaemon(opts) {
363
466
  version: 1,
364
467
  action: "dispatch",
365
468
  undispatched_id: event.undispatched_id,
469
+ ...(taken.source_message_id !== undefined && {
470
+ source_message_id: taken.source_message_id,
471
+ }),
366
472
  dispatched_to_endpoint_id: event.target_endpoint_id,
367
473
  });
368
474
  return { ok: true };
@@ -452,6 +558,13 @@ export async function startBrokerDaemon(opts) {
452
558
  throw new BrokerHttpError(400, "ipc_channel_missing", `no open IPC channel for plugin_pid=${body.plugin_pid}; ` +
453
559
  "open WS /v1/stream with x-plugin-pid header first");
454
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;
455
568
  const apiResp = await apiPort.register({
456
569
  runtime_kind: body.kind,
457
570
  endpoint_nonce: randomUUID(),
@@ -462,6 +575,7 @@ export async function startBrokerDaemon(opts) {
462
575
  tracking_ref: body.tracking_ref,
463
576
  session_name: body.session_name,
464
577
  task_hint: body.task_hint,
578
+ runtime_capabilities: runtimeCapabilities,
465
579
  });
466
580
  registry.register({
467
581
  endpoint_id: apiResp.endpoint_id,
@@ -571,7 +685,19 @@ export async function startBrokerDaemon(opts) {
571
685
  source_endpoint_id: body.endpoint_id,
572
686
  require_live: body.require_live ?? false,
573
687
  };
574
- const ack = await connector.send(body.to, body.content, body.contentType ?? "text", metadata);
688
+ let ack;
689
+ try {
690
+ ack = await connector.send(body.to, body.content, body.contentType ?? "text", metadata);
691
+ }
692
+ catch (err) {
693
+ const msg = err instanceof Error ? err.message : String(err);
694
+ if (msg === "WebSocket not connected" || msg === "SEND_ACK timeout") {
695
+ throw new BrokerHttpError(503, "connector_unavailable", msg, {
696
+ retryable: true,
697
+ });
698
+ }
699
+ throw err;
700
+ }
575
701
  return { messageId: ack.messageId, status: ack.status };
576
702
  },
577
703
  async reattachEndpoint(endpoint_id, plugin_pid, _ipcWsHint) {
@@ -606,6 +732,9 @@ export async function startBrokerDaemon(opts) {
606
732
  content: msg.envelope.content,
607
733
  contentType: msg.envelope.contentType,
608
734
  metadata: msg.envelope.metadata,
735
+ ...(msg.envelope.sourceMessageId !== undefined && {
736
+ sourceMessageId: msg.envelope.sourceMessageId,
737
+ }),
609
738
  });
610
739
  }
611
740
  emitTransition(endpoint_id, "active", "reattach");
@@ -672,6 +801,7 @@ export async function startBrokerDaemon(opts) {
672
801
  bearerToken,
673
802
  handlers,
674
803
  logger,
804
+ getNetworkPresence: () => networkPresence,
675
805
  onChannelOpened: (plugin_pid, ws) => {
676
806
  const prior = channels.get(plugin_pid);
677
807
  if (prior && prior !== ws) {
@@ -702,7 +832,10 @@ export async function startBrokerDaemon(opts) {
702
832
  }
703
833
  },
704
834
  });
705
- 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) => {
706
839
  const meta = payload.metadata ?? {};
707
840
  const target_endpoint_id = typeof meta.target_endpoint_id === "string"
708
841
  ? meta.target_endpoint_id
@@ -710,26 +843,48 @@ export async function startBrokerDaemon(opts) {
710
843
  const correlation_id = typeof meta.correlation_id === "string" ? meta.correlation_id : undefined;
711
844
  const decision = router.route({ target_endpoint_id, correlation_id });
712
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
+ }
713
860
  recordInboundCorrelation(decision.entry.endpoint_id, meta);
714
861
  if (decision.entry.state === "active") {
715
- pushToPlugin(decision.entry.ipc_ws, {
862
+ const pushed = pushToPlugin(decision.entry.ipc_ws, {
716
863
  event: "message_received",
717
864
  from: payload.from,
718
865
  content: payload.content,
719
866
  contentType: payload.contentType,
720
867
  metadata: meta,
868
+ ...(payload.messageId !== undefined && {
869
+ sourceMessageId: payload.messageId,
870
+ }),
721
871
  });
872
+ if (!pushed)
873
+ return false;
722
874
  }
723
875
  else {
724
876
  const buf = reconnectingBuffers.forEndpoint(decision.entry.endpoint_id);
725
877
  buf.append({
726
- id: randomUUID(),
878
+ id: payload.messageId ?? randomUUID(),
727
879
  arrived_at: new Date().toISOString(),
728
880
  envelope: {
729
881
  from: payload.from,
730
882
  content: payload.content,
731
883
  contentType: payload.contentType,
732
884
  metadata: meta,
885
+ ...(payload.messageId !== undefined && {
886
+ sourceMessageId: payload.messageId,
887
+ }),
733
888
  },
734
889
  });
735
890
  logger.info("buffered_for_reconnecting_endpoint", {
@@ -737,7 +892,7 @@ export async function startBrokerDaemon(opts) {
737
892
  buffer_size: buf.size(),
738
893
  });
739
894
  }
740
- return;
895
+ return markDeliverySeqAccepted(payload.seq);
741
896
  }
742
897
  let reason = "unaddressed";
743
898
  let originalTarget;
@@ -757,7 +912,10 @@ export async function startBrokerDaemon(opts) {
757
912
  }
758
913
  }
759
914
  const undispatched = {
760
- id: randomUUID(),
915
+ id: payload.messageId ?? randomUUID(),
916
+ ...(payload.messageId !== undefined && {
917
+ source_message_id: payload.messageId,
918
+ }),
761
919
  arrived_at: new Date().toISOString(),
762
920
  sender_address: payload.from,
763
921
  content: payload.content,
@@ -774,31 +932,82 @@ export async function startBrokerDaemon(opts) {
774
932
  size: undispatchedInbox.size(),
775
933
  capacity: undispatchedInbox.capacity(),
776
934
  });
935
+ return false;
777
936
  }
778
- else {
779
- logger.info("undispatched_added", { id: undispatched.id, reason });
780
- const wireReason = undispatched.reason === "unaddressed"
781
- ? "no_target_endpoint"
782
- : undispatched.reason;
783
- emitUndispatched({
784
- type: "undispatched_changed",
785
- version: 1,
786
- action: "add",
787
- undispatched_id: undispatched.id,
788
- sender_address: undispatched.sender_address,
789
- content_preview: truncateContentPreview(undispatched.content, CONTENT_PREVIEW_MAX_CODEPOINTS),
790
- reason: wireReason,
791
- ...(undispatched.original_target_endpoint_id !== undefined && {
792
- target_endpoint_id_hint: undispatched.original_target_endpoint_id,
793
- }),
794
- ...(typeof correlation_id === "string" && {
795
- in_reply_to: correlation_id,
796
- }),
797
- 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,
798
991
  });
799
- }
992
+ })
993
+ .finally(() => {
994
+ inboundProcessing.delete(task);
995
+ });
996
+ inboundProcessing.add(task);
800
997
  });
801
- 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
+ }
802
1011
  connector.ackDelivery(payload.upTo);
803
1012
  });
804
1013
  writeDiscoveryFile(paths.discoveryFile, {
@@ -865,6 +1074,13 @@ export async function startBrokerDaemon(opts) {
865
1074
  });
866
1075
  }
867
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();
868
1084
  const endpoints = registry.list();
869
1085
  await Promise.all(endpoints.map(async (entry) => {
870
1086
  try {
@@ -901,6 +1117,7 @@ export async function startBrokerDaemon(opts) {
901
1117
  retryQueueSize: () => retryQueue.size(),
902
1118
  undispatchedChangedQueueSize: () => undispatchedEmitter.size(),
903
1119
  networkPresenceChangedQueueSize: () => networkPresenceEmitter.size(),
1120
+ runtimeInboundRoutedQueueSize: () => runtimeInboundRoutedEmitter.size(),
904
1121
  replyCorrelationCacheSize: (endpoint_id) => replyCorrelationCache.sizeForEndpoint(endpoint_id),
905
1122
  };
906
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"}