@naylence/runtime 0.3.5-test.942 → 0.3.5-test.944

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 (36) hide show
  1. package/dist/browser/index.cjs +380 -8
  2. package/dist/browser/index.mjs +380 -8
  3. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
  4. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
  5. package/dist/cjs/naylence/fame/connector/broadcast-channel-listener.js +35 -0
  6. package/dist/cjs/naylence/fame/connector/inpage-connector-factory.js +12 -0
  7. package/dist/cjs/naylence/fame/connector/inpage-connector.js +66 -1
  8. package/dist/cjs/naylence/fame/connector/inpage-listener.js +49 -2
  9. package/dist/cjs/naylence/fame/connector/transport-frame.js +101 -0
  10. package/dist/cjs/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  11. package/dist/cjs/naylence/fame/grants/inpage-connection-grant.js +28 -0
  12. package/dist/cjs/version.js +2 -2
  13. package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
  14. package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
  15. package/dist/esm/naylence/fame/connector/broadcast-channel-listener.js +35 -0
  16. package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +12 -0
  17. package/dist/esm/naylence/fame/connector/inpage-connector.js +66 -1
  18. package/dist/esm/naylence/fame/connector/inpage-listener.js +49 -2
  19. package/dist/esm/naylence/fame/connector/transport-frame.js +94 -0
  20. package/dist/esm/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  21. package/dist/esm/naylence/fame/grants/inpage-connection-grant.js +28 -0
  22. package/dist/esm/version.js +2 -2
  23. package/dist/node/index.cjs +380 -8
  24. package/dist/node/index.mjs +380 -8
  25. package/dist/node/node.cjs +396 -8
  26. package/dist/node/node.mjs +396 -8
  27. package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +2 -0
  28. package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +4 -0
  29. package/dist/types/naylence/fame/connector/inpage-connector-factory.d.ts +2 -0
  30. package/dist/types/naylence/fame/connector/inpage-connector.d.ts +4 -0
  31. package/dist/types/naylence/fame/connector/inpage-listener.d.ts +1 -0
  32. package/dist/types/naylence/fame/connector/transport-frame.d.ts +58 -0
  33. package/dist/types/naylence/fame/grants/broadcast-channel-connection-grant.d.ts +6 -0
  34. package/dist/types/naylence/fame/grants/inpage-connection-grant.d.ts +8 -0
  35. package/dist/types/version.d.ts +1 -1
  36. package/package.json +1 -1
@@ -14,12 +14,12 @@ var fastify = require('fastify');
14
14
  var websocketPlugin = require('@fastify/websocket');
15
15
 
16
16
  // This file is auto-generated during build - do not edit manually
17
- // Generated from package.json version: 0.3.5-test.942
17
+ // Generated from package.json version: 0.3.5-test.944
18
18
  /**
19
19
  * The package version, injected at build time.
20
20
  * @internal
21
21
  */
22
- const VERSION = '0.3.5-test.942';
22
+ const VERSION = '0.3.5-test.944';
23
23
 
24
24
  /**
25
25
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9734,6 +9734,85 @@ class BoundedAsyncQueue {
9734
9734
  }
9735
9735
  }
9736
9736
 
9737
+ /**
9738
+ * Transport frame layer for multiplexing logical links on physical channels.
9739
+ *
9740
+ * This lightweight framing layer wraps raw FAME payloads to enable multiple
9741
+ * logical connections over a single physical channel (BroadcastChannel or InPage bus).
9742
+ *
9743
+ * The transport frame does NOT modify FAME envelopes - it only wraps the raw
9744
+ * Uint8Array payload at the connector level.
9745
+ */
9746
+ /**
9747
+ * Transport frame version for future compatibility
9748
+ */
9749
+ const TRANSPORT_FRAME_VERSION = 1;
9750
+ /**
9751
+ * Wrap a raw payload in a transport frame
9752
+ *
9753
+ * @param payload - Raw FAME envelope bytes
9754
+ * @param srcNodeId - Local node ID (this connector)
9755
+ * @param dstNodeId - Remote node ID (target connector)
9756
+ * @returns Transport frame ready for transmission
9757
+ */
9758
+ function wrapTransportFrame(payload, srcNodeId, dstNodeId) {
9759
+ return {
9760
+ v: TRANSPORT_FRAME_VERSION,
9761
+ src: srcNodeId,
9762
+ dst: dstNodeId,
9763
+ payload,
9764
+ };
9765
+ }
9766
+ /**
9767
+ * Serialize a transport frame for transmission over the bus
9768
+ *
9769
+ * @param frame - Transport frame to serialize
9770
+ * @returns Serialized frame data ready for postMessage/dispatchEvent
9771
+ */
9772
+ function serializeTransportFrame(frame) {
9773
+ // Convert Uint8Array to regular array for JSON serialization
9774
+ const serializable = {
9775
+ v: frame.v,
9776
+ src: frame.src,
9777
+ dst: frame.dst,
9778
+ payload: Array.from(frame.payload),
9779
+ };
9780
+ return serializable;
9781
+ }
9782
+ /**
9783
+ * Unwrap a transport frame, validating source and destination
9784
+ *
9785
+ * @param raw - Raw data from the bus
9786
+ * @param localNodeId - This connector's node ID
9787
+ * @param remoteNodeId - Expected remote node ID
9788
+ * @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
9789
+ */
9790
+ function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
9791
+ // Validate basic structure
9792
+ if (!raw || typeof raw !== 'object') {
9793
+ return null;
9794
+ }
9795
+ const frame = raw;
9796
+ // Check version
9797
+ if (frame.v !== TRANSPORT_FRAME_VERSION) {
9798
+ return null;
9799
+ }
9800
+ // Check src and dst
9801
+ if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
9802
+ return null;
9803
+ }
9804
+ // Only accept frames addressed to us from the expected remote
9805
+ if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
9806
+ return null;
9807
+ }
9808
+ // Extract payload
9809
+ if (!frame.payload || !Array.isArray(frame.payload)) {
9810
+ return null;
9811
+ }
9812
+ // Convert array back to Uint8Array
9813
+ return Uint8Array.from(frame.payload);
9814
+ }
9815
+
9737
9816
  const logger$_ = getLogger('naylence.fame.connector.broadcast_channel_connector');
9738
9817
  const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
9739
9818
  const DEFAULT_CHANNEL$7 = 'naylence-fabric';
@@ -9799,9 +9878,20 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9799
9878
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9800
9879
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9801
9880
  this.channel = new BroadcastChannel(this.channelName);
9881
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
9882
+ this.localNodeId =
9883
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
9884
+ ? config.localNodeId.trim()
9885
+ : this.connectorId;
9886
+ this.remoteNodeId =
9887
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
9888
+ ? config.remoteNodeId.trim()
9889
+ : '*'; // Accept from any remote if not specified
9802
9890
  logger$_.debug('broadcast_channel_connector_created', {
9803
9891
  channel: this.channelName,
9804
9892
  connector_id: this.connectorId,
9893
+ local_node_id: this.localNodeId,
9894
+ remote_node_id: this.remoteNodeId,
9805
9895
  inbox_capacity: preferredCapacity,
9806
9896
  timestamp: new Date().toISOString(),
9807
9897
  });
@@ -9834,6 +9924,46 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9834
9924
  if (busMessage.senderId === this.connectorId) {
9835
9925
  return;
9836
9926
  }
9927
+ // Try to unwrap as transport frame
9928
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
9929
+ if (unwrapped) {
9930
+ // Successfully unwrapped transport frame
9931
+ logger$_.debug('broadcast_channel_transport_frame_received', {
9932
+ channel: this.channelName,
9933
+ sender_id: busMessage.senderId,
9934
+ connector_id: this.connectorId,
9935
+ local_node_id: this.localNodeId,
9936
+ remote_node_id: this.remoteNodeId,
9937
+ payload_length: unwrapped.byteLength,
9938
+ });
9939
+ if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
9940
+ return;
9941
+ }
9942
+ try {
9943
+ if (typeof this.inbox.tryEnqueue === 'function') {
9944
+ const accepted = this.inbox.tryEnqueue(unwrapped);
9945
+ if (accepted) {
9946
+ return;
9947
+ }
9948
+ }
9949
+ this.inbox.enqueue(unwrapped);
9950
+ }
9951
+ catch (error) {
9952
+ if (error instanceof QueueFullError) {
9953
+ logger$_.warning('broadcast_channel_receive_queue_full', {
9954
+ channel: this.channelName,
9955
+ });
9956
+ }
9957
+ else {
9958
+ logger$_.error('broadcast_channel_receive_error', {
9959
+ channel: this.channelName,
9960
+ error: error instanceof Error ? error.message : String(error),
9961
+ });
9962
+ }
9963
+ }
9964
+ return;
9965
+ }
9966
+ // Fall back to legacy format (no transport frame)
9837
9967
  const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
9838
9968
  if (!payload) {
9839
9969
  logger$_.debug('broadcast_channel_payload_rejected', {
@@ -9972,10 +10102,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9972
10102
  logger$_.debug('broadcast_channel_message_sending', {
9973
10103
  channel: this.channelName,
9974
10104
  sender_id: this.connectorId,
9975
- });
10105
+ local_node_id: this.localNodeId,
10106
+ remote_node_id: this.remoteNodeId,
10107
+ });
10108
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
10109
+ // (not using default values). This ensures backwards compatibility.
10110
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
10111
+ this.remoteNodeId !== '*';
10112
+ let payload;
10113
+ if (useTransportFrame) {
10114
+ // Wrap payload in transport frame
10115
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
10116
+ payload = serializeTransportFrame(frame);
10117
+ }
10118
+ else {
10119
+ // Legacy format: send raw payload
10120
+ payload = data;
10121
+ }
9976
10122
  this.channel.postMessage({
9977
10123
  senderId: this.connectorId,
9978
- payload: data,
10124
+ payload,
9979
10125
  });
9980
10126
  }
9981
10127
  async _transportReceive() {
@@ -10268,6 +10414,14 @@ function isBroadcastChannelConnectionGrant(candidate) {
10268
10414
  record.inboxCapacity <= 0)) {
10269
10415
  return false;
10270
10416
  }
10417
+ if (record.localNodeId !== undefined &&
10418
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
10419
+ return false;
10420
+ }
10421
+ if (record.remoteNodeId !== undefined &&
10422
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
10423
+ return false;
10424
+ }
10271
10425
  return true;
10272
10426
  }
10273
10427
  function normalizeBroadcastChannelConnectionGrant(candidate) {
@@ -10301,6 +10455,20 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
10301
10455
  }
10302
10456
  result.inboxCapacity = Math.floor(inboxValue);
10303
10457
  }
10458
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
10459
+ if (localNodeIdValue !== undefined) {
10460
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
10461
+ throw new TypeError('BroadcastChannelConnectionGrant "localNodeId" must be a non-empty string when provided');
10462
+ }
10463
+ result.localNodeId = localNodeIdValue.trim();
10464
+ }
10465
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
10466
+ if (remoteNodeIdValue !== undefined) {
10467
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
10468
+ throw new TypeError('BroadcastChannelConnectionGrant "remoteNodeId" must be a non-empty string when provided');
10469
+ }
10470
+ result.remoteNodeId = remoteNodeIdValue.trim();
10471
+ }
10304
10472
  return result;
10305
10473
  }
10306
10474
  function broadcastChannelGrantToConnectorConfig(grant) {
@@ -10314,6 +10482,12 @@ function broadcastChannelGrantToConnectorConfig(grant) {
10314
10482
  if (normalized.inboxCapacity !== undefined) {
10315
10483
  config.inboxCapacity = normalized.inboxCapacity;
10316
10484
  }
10485
+ if (normalized.localNodeId) {
10486
+ config.localNodeId = normalized.localNodeId;
10487
+ }
10488
+ if (normalized.remoteNodeId) {
10489
+ config.remoteNodeId = normalized.remoteNodeId;
10490
+ }
10317
10491
  return config;
10318
10492
  }
10319
10493
 
@@ -20260,9 +20434,20 @@ class InPageConnector extends BaseAsyncConnector {
20260
20434
  : DEFAULT_INBOX_CAPACITY$6;
20261
20435
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
20262
20436
  this.connectorId = InPageConnector.generateConnectorId();
20437
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
20438
+ this.localNodeId =
20439
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
20440
+ ? config.localNodeId.trim()
20441
+ : this.connectorId;
20442
+ this.remoteNodeId =
20443
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
20444
+ ? config.remoteNodeId.trim()
20445
+ : '*'; // Accept from any remote if not specified
20263
20446
  logger$G.debug('inpage_connector_initialized', {
20264
20447
  channel: this.channelName,
20265
20448
  connector_id: this.connectorId,
20449
+ local_node_id: this.localNodeId,
20450
+ remote_node_id: this.remoteNodeId,
20266
20451
  });
20267
20452
  this.onMsg = (event) => {
20268
20453
  const messageEvent = event;
@@ -20296,6 +20481,43 @@ class InPageConnector extends BaseAsyncConnector {
20296
20481
  if (busMessage.senderId === this.connectorId) {
20297
20482
  return;
20298
20483
  }
20484
+ // Try to unwrap as transport frame
20485
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
20486
+ if (unwrapped) {
20487
+ // Successfully unwrapped transport frame
20488
+ logger$G.debug('inpage_transport_frame_received', {
20489
+ channel: this.channelName,
20490
+ sender_id: busMessage.senderId,
20491
+ connector_id: this.connectorId,
20492
+ local_node_id: this.localNodeId,
20493
+ remote_node_id: this.remoteNodeId,
20494
+ payload_length: unwrapped.byteLength,
20495
+ });
20496
+ try {
20497
+ if (typeof this.inbox.tryEnqueue === 'function') {
20498
+ const accepted = this.inbox.tryEnqueue(unwrapped);
20499
+ if (accepted) {
20500
+ return;
20501
+ }
20502
+ }
20503
+ this.inbox.enqueue(unwrapped);
20504
+ }
20505
+ catch (error) {
20506
+ if (error instanceof QueueFullError) {
20507
+ logger$G.warning('inpage_receive_queue_full', {
20508
+ channel: this.channelName,
20509
+ });
20510
+ }
20511
+ else {
20512
+ logger$G.error('inpage_receive_error', {
20513
+ channel: this.channelName,
20514
+ error: error instanceof Error ? error.message : String(error),
20515
+ });
20516
+ }
20517
+ }
20518
+ return;
20519
+ }
20520
+ // Fall back to legacy format (no transport frame)
20299
20521
  const payload = InPageConnector.coercePayload(busMessage.payload);
20300
20522
  if (!payload) {
20301
20523
  logger$G.debug('inpage_payload_rejected', {
@@ -20454,11 +20676,27 @@ class InPageConnector extends BaseAsyncConnector {
20454
20676
  logger$G.debug('inpage_message_sending', {
20455
20677
  channel: this.channelName,
20456
20678
  sender_id: this.connectorId,
20457
- });
20679
+ local_node_id: this.localNodeId,
20680
+ remote_node_id: this.remoteNodeId,
20681
+ });
20682
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
20683
+ // (not using default values). This ensures backwards compatibility.
20684
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
20685
+ this.remoteNodeId !== '*';
20686
+ let payload;
20687
+ if (useTransportFrame) {
20688
+ // Wrap payload in transport frame
20689
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
20690
+ payload = serializeTransportFrame(frame);
20691
+ }
20692
+ else {
20693
+ // Legacy format: send raw payload
20694
+ payload = data;
20695
+ }
20458
20696
  const event = new MessageEvent(this.channelName, {
20459
20697
  data: {
20460
20698
  senderId: this.connectorId,
20461
- payload: data,
20699
+ payload,
20462
20700
  },
20463
20701
  });
20464
20702
  getSharedBus$1().dispatchEvent(event);
@@ -27823,6 +28061,14 @@ function isInPageConnectionGrant(candidate) {
27823
28061
  record.inboxCapacity <= 0)) {
27824
28062
  return false;
27825
28063
  }
28064
+ if (record.localNodeId !== undefined &&
28065
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
28066
+ return false;
28067
+ }
28068
+ if (record.remoteNodeId !== undefined &&
28069
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
28070
+ return false;
28071
+ }
27826
28072
  return true;
27827
28073
  }
27828
28074
  function normalizeInPageConnectionGrant(candidate) {
@@ -27856,6 +28102,20 @@ function normalizeInPageConnectionGrant(candidate) {
27856
28102
  }
27857
28103
  result.inboxCapacity = Math.floor(inboxValue);
27858
28104
  }
28105
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
28106
+ if (localNodeIdValue !== undefined) {
28107
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
28108
+ throw new TypeError('InPageConnectionGrant "localNodeId" must be a non-empty string when provided');
28109
+ }
28110
+ result.localNodeId = localNodeIdValue.trim();
28111
+ }
28112
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
28113
+ if (remoteNodeIdValue !== undefined) {
28114
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
28115
+ throw new TypeError('InPageConnectionGrant "remoteNodeId" must be a non-empty string when provided');
28116
+ }
28117
+ result.remoteNodeId = remoteNodeIdValue.trim();
28118
+ }
27859
28119
  return result;
27860
28120
  }
27861
28121
  function inPageGrantToConnectorConfig(grant) {
@@ -27869,6 +28129,12 @@ function inPageGrantToConnectorConfig(grant) {
27869
28129
  if (normalized.inboxCapacity !== undefined) {
27870
28130
  config.inboxCapacity = normalized.inboxCapacity;
27871
28131
  }
28132
+ if (normalized.localNodeId) {
28133
+ config.localNodeId = normalized.localNodeId;
28134
+ }
28135
+ if (normalized.remoteNodeId) {
28136
+ config.remoteNodeId = normalized.remoteNodeId;
28137
+ }
27872
28138
  return config;
27873
28139
  }
27874
28140
 
@@ -28495,6 +28761,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28495
28761
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
28496
28762
  channelName,
28497
28763
  inboxCapacity,
28764
+ localNodeId: normalized.localNodeId,
28765
+ remoteNodeId: normalized.remoteNodeId,
28498
28766
  };
28499
28767
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
28500
28768
  if (options.authorization) {
@@ -28556,6 +28824,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28556
28824
  if (candidate.authorizationContext !== undefined) {
28557
28825
  normalized.authorizationContext = candidate.authorizationContext;
28558
28826
  }
28827
+ // Handle localNodeId
28828
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
28829
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
28830
+ normalized.localNodeId = localNodeId.trim();
28831
+ }
28832
+ // Handle remoteNodeId
28833
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
28834
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
28835
+ normalized.remoteNodeId = remoteNodeId.trim();
28836
+ }
28559
28837
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
28560
28838
  normalized.inboxCapacity =
28561
28839
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
@@ -29119,6 +29397,8 @@ class InPageConnectorFactory extends ConnectorFactory {
29119
29397
  type: INPAGE_CONNECTOR_TYPE,
29120
29398
  channelName,
29121
29399
  inboxCapacity,
29400
+ localNodeId: normalized.localNodeId,
29401
+ remoteNodeId: normalized.remoteNodeId,
29122
29402
  };
29123
29403
  const connector = new InPageConnector(connectorConfig, baseConfig);
29124
29404
  if (options.authorization) {
@@ -29187,6 +29467,16 @@ class InPageConnectorFactory extends ConnectorFactory {
29187
29467
  if (candidate.authorizationContext !== undefined) {
29188
29468
  normalized.authorizationContext = candidate.authorizationContext;
29189
29469
  }
29470
+ // Handle localNodeId
29471
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
29472
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
29473
+ normalized.localNodeId = localNodeId.trim();
29474
+ }
29475
+ // Handle remoteNodeId
29476
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
29477
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
29478
+ normalized.remoteNodeId = remoteNodeId.trim();
29479
+ }
29190
29480
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$3;
29191
29481
  normalized.inboxCapacity =
29192
29482
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$3;
@@ -36154,6 +36444,26 @@ class BroadcastChannelListener extends TransportListener {
36154
36444
  inboxCapacity: this._inboxCapacity,
36155
36445
  };
36156
36446
  }
36447
+ // Automatically configure transport frame multiplexing:
36448
+ // Set remoteNodeId to the incoming senderId to target responses back to the specific client/agent
36449
+ const broadcastConfig = connectorConfig;
36450
+ if (!broadcastConfig.remoteNodeId) {
36451
+ broadcastConfig.remoteNodeId = params.senderId;
36452
+ logger$a.debug('broadcast_channel_listener_auto_configured_remote_node_id', {
36453
+ sender_id: params.senderId,
36454
+ system_id: systemId,
36455
+ remote_node_id: params.senderId,
36456
+ local_node_id: broadcastConfig.localNodeId ?? '<not set>',
36457
+ });
36458
+ }
36459
+ else {
36460
+ logger$a.debug('broadcast_channel_listener_using_provided_remote_node_id', {
36461
+ sender_id: params.senderId,
36462
+ system_id: systemId,
36463
+ remote_node_id: broadcastConfig.remoteNodeId,
36464
+ local_node_id: broadcastConfig.localNodeId ?? '<not set>',
36465
+ });
36466
+ }
36157
36467
  try {
36158
36468
  const connector = await routingNode.createOriginConnector({
36159
36469
  originType,
@@ -36223,6 +36533,21 @@ class BroadcastChannelListener extends TransportListener {
36223
36533
  inboxCandidate > 0) {
36224
36534
  config.inboxCapacity = Math.floor(inboxCandidate);
36225
36535
  }
36536
+ // Extract transport frame multiplexing node IDs
36537
+ const localNodeIdCandidate = candidate.localNodeId ?? candidate['local_node_id'];
36538
+ if (typeof localNodeIdCandidate === 'string' && localNodeIdCandidate.trim().length > 0) {
36539
+ config.localNodeId = localNodeIdCandidate.trim();
36540
+ logger$a.debug('broadcast_channel_listener_extracted_local_node_id', {
36541
+ local_node_id: config.localNodeId,
36542
+ });
36543
+ }
36544
+ const remoteNodeIdCandidate = candidate.remoteNodeId ?? candidate['remote_node_id'];
36545
+ if (typeof remoteNodeIdCandidate === 'string' && remoteNodeIdCandidate.trim().length > 0) {
36546
+ config.remoteNodeId = remoteNodeIdCandidate.trim();
36547
+ logger$a.debug('broadcast_channel_listener_extracted_remote_node_id', {
36548
+ remote_node_id: config.remoteNodeId,
36549
+ });
36550
+ }
36226
36551
  return config;
36227
36552
  }
36228
36553
  _monitorConnectorLifecycle(senderId, systemId, connector) {
@@ -36945,6 +37270,7 @@ class InPageListener extends TransportListener {
36945
37270
  this._busHandler = null;
36946
37271
  this._senderRegistry = new Map();
36947
37272
  this._systemToSender = new Map();
37273
+ this._flowIdToSender = new Map();
36948
37274
  this._pendingAttachments = new Map();
36949
37275
  ensureBrowserEnvironment();
36950
37276
  const channelCandidate = options?.channelName;
@@ -37011,6 +37337,7 @@ class InPageListener extends TransportListener {
37011
37337
  this._unregisterBusListener();
37012
37338
  this._senderRegistry.clear();
37013
37339
  this._systemToSender.clear();
37340
+ this._flowIdToSender.clear();
37014
37341
  this._pendingAttachments.clear();
37015
37342
  logger$7.debug('inpage_listener_stopped', {
37016
37343
  channel: this._channelName,
@@ -37064,10 +37391,25 @@ class InPageListener extends TransportListener {
37064
37391
  await this._handleAttachFrame(senderId, envelope);
37065
37392
  return;
37066
37393
  }
37067
- const entry = this._senderRegistry.get(senderId);
37394
+ // Try to find connector by sender ID first
37395
+ let entry = this._senderRegistry.get(senderId);
37396
+ // If not found and we have a flowId, try to route based on flow
37397
+ if (!entry && envelope.flowId) {
37398
+ const originalSenderId = this._flowIdToSender.get(envelope.flowId);
37399
+ if (originalSenderId) {
37400
+ entry = this._senderRegistry.get(originalSenderId);
37401
+ logger$7.debug('inpage_listener_routed_by_flow_id', {
37402
+ sender_id: senderId,
37403
+ original_sender_id: originalSenderId,
37404
+ flow_id: envelope.flowId,
37405
+ frame_type: envelope.frame?.type ?? 'unknown',
37406
+ });
37407
+ }
37408
+ }
37068
37409
  if (!entry) {
37069
37410
  logger$7.debug('inpage_listener_no_connector_for_sender', {
37070
37411
  sender_id: senderId,
37412
+ flow_id: envelope.flowId,
37071
37413
  frame_type: envelope.frame?.type ?? 'unknown',
37072
37414
  });
37073
37415
  return;
@@ -37144,6 +37486,15 @@ class InPageListener extends TransportListener {
37144
37486
  }
37145
37487
  this._senderRegistry.set(senderId, entry);
37146
37488
  this._systemToSender.set(entry.systemId, senderId);
37489
+ // Track the flowId if present so we can route responses back
37490
+ if (envelope.flowId) {
37491
+ this._flowIdToSender.set(envelope.flowId, senderId);
37492
+ logger$7.debug('inpage_listener_registered_flow_id', {
37493
+ sender_id: senderId,
37494
+ system_id: entry.systemId,
37495
+ flow_id: envelope.flowId,
37496
+ });
37497
+ }
37147
37498
  await this._deliverEnvelope(entry, envelope);
37148
37499
  }
37149
37500
  async _createConnectorForAttach(params) {
@@ -37191,7 +37542,7 @@ class InPageListener extends TransportListener {
37191
37542
  origin_type: originType,
37192
37543
  connector_type: connector.constructor?.name ?? 'unknown',
37193
37544
  });
37194
- return { connector, systemId, originType };
37545
+ return { connector, systemId, originType, senderId: params.senderId };
37195
37546
  }
37196
37547
  catch (error) {
37197
37548
  logger$7.error('inpage_listener_connector_creation_failed', {
@@ -37245,6 +37596,12 @@ class InPageListener extends TransportListener {
37245
37596
  if (this._systemToSender.get(systemId) === senderId) {
37246
37597
  this._systemToSender.delete(systemId);
37247
37598
  }
37599
+ // Clean up flowId mappings for this sender
37600
+ for (const [flowId, sid] of this._flowIdToSender.entries()) {
37601
+ if (sid === senderId) {
37602
+ this._flowIdToSender.delete(flowId);
37603
+ }
37604
+ }
37248
37605
  })
37249
37606
  .catch((error) => {
37250
37607
  logger$7.debug('inpage_listener_wait_until_closed_failed', {
@@ -37256,9 +37613,24 @@ class InPageListener extends TransportListener {
37256
37613
  if (this._systemToSender.get(systemId) === senderId) {
37257
37614
  this._systemToSender.delete(systemId);
37258
37615
  }
37616
+ // Clean up flowId mappings for this sender
37617
+ for (const [flowId, sid] of this._flowIdToSender.entries()) {
37618
+ if (sid === senderId) {
37619
+ this._flowIdToSender.delete(flowId);
37620
+ }
37621
+ }
37259
37622
  });
37260
37623
  }
37261
37624
  async _deliverEnvelope(entry, envelope) {
37625
+ // Track flowId for routing responses back
37626
+ if (envelope.flowId && !this._flowIdToSender.has(envelope.flowId)) {
37627
+ this._flowIdToSender.set(envelope.flowId, entry.senderId);
37628
+ logger$7.debug('inpage_listener_registered_flow_id_on_delivery', {
37629
+ sender_id: entry.senderId,
37630
+ system_id: entry.systemId,
37631
+ flow_id: envelope.flowId,
37632
+ });
37633
+ }
37262
37634
  const message = this._buildChannelMessage({
37263
37635
  envelope,
37264
37636
  connector: entry.connector,