@naylence/runtime 0.3.5-test.941 → 0.3.5-test.943

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 (33) hide show
  1. package/dist/browser/index.cjs +390 -8
  2. package/dist/browser/index.mjs +390 -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/inpage-connector-factory.js +12 -0
  6. package/dist/cjs/naylence/fame/connector/inpage-connector.js +159 -1
  7. package/dist/cjs/naylence/fame/connector/transport-frame.js +101 -0
  8. package/dist/cjs/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  9. package/dist/cjs/naylence/fame/grants/inpage-connection-grant.js +28 -0
  10. package/dist/cjs/naylence/fame/node/upstream-session-manager.js +2 -2
  11. package/dist/cjs/version.js +2 -2
  12. package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
  13. package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
  14. package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +12 -0
  15. package/dist/esm/naylence/fame/connector/inpage-connector.js +159 -1
  16. package/dist/esm/naylence/fame/connector/transport-frame.js +94 -0
  17. package/dist/esm/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
  18. package/dist/esm/naylence/fame/grants/inpage-connection-grant.js +28 -0
  19. package/dist/esm/naylence/fame/node/upstream-session-manager.js +2 -2
  20. package/dist/esm/version.js +2 -2
  21. package/dist/node/index.cjs +390 -8
  22. package/dist/node/index.mjs +390 -8
  23. package/dist/node/node.cjs +406 -8
  24. package/dist/node/node.mjs +406 -8
  25. package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +2 -0
  26. package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +4 -0
  27. package/dist/types/naylence/fame/connector/inpage-connector-factory.d.ts +2 -0
  28. package/dist/types/naylence/fame/connector/inpage-connector.d.ts +11 -1
  29. package/dist/types/naylence/fame/connector/transport-frame.d.ts +58 -0
  30. package/dist/types/naylence/fame/grants/broadcast-channel-connection-grant.d.ts +6 -0
  31. package/dist/types/naylence/fame/grants/inpage-connection-grant.d.ts +8 -0
  32. package/dist/types/version.d.ts +1 -1
  33. package/package.json +1 -1
@@ -98,12 +98,12 @@ installProcessEnvShim();
98
98
  // --- END ENV SHIM ---
99
99
 
100
100
  // This file is auto-generated during build - do not edit manually
101
- // Generated from package.json version: 0.3.5-test.941
101
+ // Generated from package.json version: 0.3.5-test.943
102
102
  /**
103
103
  * The package version, injected at build time.
104
104
  * @internal
105
105
  */
106
- const VERSION = '0.3.5-test.941';
106
+ const VERSION = '0.3.5-test.943';
107
107
 
108
108
  /**
109
109
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9818,6 +9818,85 @@ class BoundedAsyncQueue {
9818
9818
  }
9819
9819
  }
9820
9820
 
9821
+ /**
9822
+ * Transport frame layer for multiplexing logical links on physical channels.
9823
+ *
9824
+ * This lightweight framing layer wraps raw FAME payloads to enable multiple
9825
+ * logical connections over a single physical channel (BroadcastChannel or InPage bus).
9826
+ *
9827
+ * The transport frame does NOT modify FAME envelopes - it only wraps the raw
9828
+ * Uint8Array payload at the connector level.
9829
+ */
9830
+ /**
9831
+ * Transport frame version for future compatibility
9832
+ */
9833
+ const TRANSPORT_FRAME_VERSION = 1;
9834
+ /**
9835
+ * Wrap a raw payload in a transport frame
9836
+ *
9837
+ * @param payload - Raw FAME envelope bytes
9838
+ * @param srcNodeId - Local node ID (this connector)
9839
+ * @param dstNodeId - Remote node ID (target connector)
9840
+ * @returns Transport frame ready for transmission
9841
+ */
9842
+ function wrapTransportFrame(payload, srcNodeId, dstNodeId) {
9843
+ return {
9844
+ v: TRANSPORT_FRAME_VERSION,
9845
+ src: srcNodeId,
9846
+ dst: dstNodeId,
9847
+ payload,
9848
+ };
9849
+ }
9850
+ /**
9851
+ * Serialize a transport frame for transmission over the bus
9852
+ *
9853
+ * @param frame - Transport frame to serialize
9854
+ * @returns Serialized frame data ready for postMessage/dispatchEvent
9855
+ */
9856
+ function serializeTransportFrame(frame) {
9857
+ // Convert Uint8Array to regular array for JSON serialization
9858
+ const serializable = {
9859
+ v: frame.v,
9860
+ src: frame.src,
9861
+ dst: frame.dst,
9862
+ payload: Array.from(frame.payload),
9863
+ };
9864
+ return serializable;
9865
+ }
9866
+ /**
9867
+ * Unwrap a transport frame, validating source and destination
9868
+ *
9869
+ * @param raw - Raw data from the bus
9870
+ * @param localNodeId - This connector's node ID
9871
+ * @param remoteNodeId - Expected remote node ID
9872
+ * @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
9873
+ */
9874
+ function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
9875
+ // Validate basic structure
9876
+ if (!raw || typeof raw !== 'object') {
9877
+ return null;
9878
+ }
9879
+ const frame = raw;
9880
+ // Check version
9881
+ if (frame.v !== TRANSPORT_FRAME_VERSION) {
9882
+ return null;
9883
+ }
9884
+ // Check src and dst
9885
+ if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
9886
+ return null;
9887
+ }
9888
+ // Only accept frames addressed to us from the expected remote
9889
+ if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
9890
+ return null;
9891
+ }
9892
+ // Extract payload
9893
+ if (!frame.payload || !Array.isArray(frame.payload)) {
9894
+ return null;
9895
+ }
9896
+ // Convert array back to Uint8Array
9897
+ return Uint8Array.from(frame.payload);
9898
+ }
9899
+
9821
9900
  const logger$_ = getLogger('naylence.fame.connector.broadcast_channel_connector');
9822
9901
  const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
9823
9902
  const DEFAULT_CHANNEL$7 = 'naylence-fabric';
@@ -9883,9 +9962,20 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9883
9962
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9884
9963
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9885
9964
  this.channel = new BroadcastChannel(this.channelName);
9965
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
9966
+ this.localNodeId =
9967
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
9968
+ ? config.localNodeId.trim()
9969
+ : this.connectorId;
9970
+ this.remoteNodeId =
9971
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
9972
+ ? config.remoteNodeId.trim()
9973
+ : '*'; // Accept from any remote if not specified
9886
9974
  logger$_.debug('broadcast_channel_connector_created', {
9887
9975
  channel: this.channelName,
9888
9976
  connector_id: this.connectorId,
9977
+ local_node_id: this.localNodeId,
9978
+ remote_node_id: this.remoteNodeId,
9889
9979
  inbox_capacity: preferredCapacity,
9890
9980
  timestamp: new Date().toISOString(),
9891
9981
  });
@@ -9918,6 +10008,46 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9918
10008
  if (busMessage.senderId === this.connectorId) {
9919
10009
  return;
9920
10010
  }
10011
+ // Try to unwrap as transport frame
10012
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
10013
+ if (unwrapped) {
10014
+ // Successfully unwrapped transport frame
10015
+ logger$_.debug('broadcast_channel_transport_frame_received', {
10016
+ channel: this.channelName,
10017
+ sender_id: busMessage.senderId,
10018
+ connector_id: this.connectorId,
10019
+ local_node_id: this.localNodeId,
10020
+ remote_node_id: this.remoteNodeId,
10021
+ payload_length: unwrapped.byteLength,
10022
+ });
10023
+ if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
10024
+ return;
10025
+ }
10026
+ try {
10027
+ if (typeof this.inbox.tryEnqueue === 'function') {
10028
+ const accepted = this.inbox.tryEnqueue(unwrapped);
10029
+ if (accepted) {
10030
+ return;
10031
+ }
10032
+ }
10033
+ this.inbox.enqueue(unwrapped);
10034
+ }
10035
+ catch (error) {
10036
+ if (error instanceof QueueFullError) {
10037
+ logger$_.warning('broadcast_channel_receive_queue_full', {
10038
+ channel: this.channelName,
10039
+ });
10040
+ }
10041
+ else {
10042
+ logger$_.error('broadcast_channel_receive_error', {
10043
+ channel: this.channelName,
10044
+ error: error instanceof Error ? error.message : String(error),
10045
+ });
10046
+ }
10047
+ }
10048
+ return;
10049
+ }
10050
+ // Fall back to legacy format (no transport frame)
9921
10051
  const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
9922
10052
  if (!payload) {
9923
10053
  logger$_.debug('broadcast_channel_payload_rejected', {
@@ -10056,10 +10186,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10056
10186
  logger$_.debug('broadcast_channel_message_sending', {
10057
10187
  channel: this.channelName,
10058
10188
  sender_id: this.connectorId,
10059
- });
10189
+ local_node_id: this.localNodeId,
10190
+ remote_node_id: this.remoteNodeId,
10191
+ });
10192
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
10193
+ // (not using default values). This ensures backwards compatibility.
10194
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
10195
+ this.remoteNodeId !== '*';
10196
+ let payload;
10197
+ if (useTransportFrame) {
10198
+ // Wrap payload in transport frame
10199
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
10200
+ payload = serializeTransportFrame(frame);
10201
+ }
10202
+ else {
10203
+ // Legacy format: send raw payload
10204
+ payload = data;
10205
+ }
10060
10206
  this.channel.postMessage({
10061
10207
  senderId: this.connectorId,
10062
- payload: data,
10208
+ payload,
10063
10209
  });
10064
10210
  }
10065
10211
  async _transportReceive() {
@@ -10352,6 +10498,14 @@ function isBroadcastChannelConnectionGrant(candidate) {
10352
10498
  record.inboxCapacity <= 0)) {
10353
10499
  return false;
10354
10500
  }
10501
+ if (record.localNodeId !== undefined &&
10502
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
10503
+ return false;
10504
+ }
10505
+ if (record.remoteNodeId !== undefined &&
10506
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
10507
+ return false;
10508
+ }
10355
10509
  return true;
10356
10510
  }
10357
10511
  function normalizeBroadcastChannelConnectionGrant(candidate) {
@@ -10385,6 +10539,20 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
10385
10539
  }
10386
10540
  result.inboxCapacity = Math.floor(inboxValue);
10387
10541
  }
10542
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
10543
+ if (localNodeIdValue !== undefined) {
10544
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
10545
+ throw new TypeError('BroadcastChannelConnectionGrant "localNodeId" must be a non-empty string when provided');
10546
+ }
10547
+ result.localNodeId = localNodeIdValue.trim();
10548
+ }
10549
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
10550
+ if (remoteNodeIdValue !== undefined) {
10551
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
10552
+ throw new TypeError('BroadcastChannelConnectionGrant "remoteNodeId" must be a non-empty string when provided');
10553
+ }
10554
+ result.remoteNodeId = remoteNodeIdValue.trim();
10555
+ }
10388
10556
  return result;
10389
10557
  }
10390
10558
  function broadcastChannelGrantToConnectorConfig(grant) {
@@ -10398,6 +10566,12 @@ function broadcastChannelGrantToConnectorConfig(grant) {
10398
10566
  if (normalized.inboxCapacity !== undefined) {
10399
10567
  config.inboxCapacity = normalized.inboxCapacity;
10400
10568
  }
10569
+ if (normalized.localNodeId) {
10570
+ config.localNodeId = normalized.localNodeId;
10571
+ }
10572
+ if (normalized.remoteNodeId) {
10573
+ config.remoteNodeId = normalized.remoteNodeId;
10574
+ }
10401
10575
  return config;
10402
10576
  }
10403
10577
 
@@ -10777,7 +10951,7 @@ class UpstreamSessionManager extends TaskSpawner {
10777
10951
  this.currentStopSubtasks = null;
10778
10952
  await Promise.allSettled(tasks.map((task) => task.promise));
10779
10953
  if (this.connector) {
10780
- logger$Z.info('upstream_stopping_old_connector', {
10954
+ logger$Z.debug('upstream_stopping_old_connector', {
10781
10955
  connect_epoch: this.connectEpoch,
10782
10956
  target_system_id: this.targetSystemId,
10783
10957
  timestamp: new Date().toISOString(),
@@ -10788,7 +10962,7 @@ class UpstreamSessionManager extends TaskSpawner {
10788
10962
  error: err instanceof Error ? err.message : String(err),
10789
10963
  });
10790
10964
  });
10791
- logger$Z.info('upstream_old_connector_stopped', {
10965
+ logger$Z.debug('upstream_old_connector_stopped', {
10792
10966
  connect_epoch: this.connectEpoch,
10793
10967
  target_system_id: this.targetSystemId,
10794
10968
  timestamp: new Date().toISOString(),
@@ -20332,6 +20506,7 @@ class InPageConnector extends BaseAsyncConnector {
20332
20506
  ensureBrowserEnvironment$2();
20333
20507
  super(baseConfig);
20334
20508
  this.listenerRegistered = false;
20509
+ this.visibilityChangeListenerRegistered = false;
20335
20510
  this.channelName =
20336
20511
  typeof config.channelName === 'string' && config.channelName.trim().length > 0
20337
20512
  ? config.channelName.trim()
@@ -20343,9 +20518,20 @@ class InPageConnector extends BaseAsyncConnector {
20343
20518
  : DEFAULT_INBOX_CAPACITY$6;
20344
20519
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
20345
20520
  this.connectorId = InPageConnector.generateConnectorId();
20521
+ // Set local and remote node IDs (defaults to connector ID for backwards compatibility)
20522
+ this.localNodeId =
20523
+ typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
20524
+ ? config.localNodeId.trim()
20525
+ : this.connectorId;
20526
+ this.remoteNodeId =
20527
+ typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
20528
+ ? config.remoteNodeId.trim()
20529
+ : '*'; // Accept from any remote if not specified
20346
20530
  logger$G.debug('inpage_connector_initialized', {
20347
20531
  channel: this.channelName,
20348
20532
  connector_id: this.connectorId,
20533
+ local_node_id: this.localNodeId,
20534
+ remote_node_id: this.remoteNodeId,
20349
20535
  });
20350
20536
  this.onMsg = (event) => {
20351
20537
  const messageEvent = event;
@@ -20379,6 +20565,43 @@ class InPageConnector extends BaseAsyncConnector {
20379
20565
  if (busMessage.senderId === this.connectorId) {
20380
20566
  return;
20381
20567
  }
20568
+ // Try to unwrap as transport frame
20569
+ const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
20570
+ if (unwrapped) {
20571
+ // Successfully unwrapped transport frame
20572
+ logger$G.debug('inpage_transport_frame_received', {
20573
+ channel: this.channelName,
20574
+ sender_id: busMessage.senderId,
20575
+ connector_id: this.connectorId,
20576
+ local_node_id: this.localNodeId,
20577
+ remote_node_id: this.remoteNodeId,
20578
+ payload_length: unwrapped.byteLength,
20579
+ });
20580
+ try {
20581
+ if (typeof this.inbox.tryEnqueue === 'function') {
20582
+ const accepted = this.inbox.tryEnqueue(unwrapped);
20583
+ if (accepted) {
20584
+ return;
20585
+ }
20586
+ }
20587
+ this.inbox.enqueue(unwrapped);
20588
+ }
20589
+ catch (error) {
20590
+ if (error instanceof QueueFullError) {
20591
+ logger$G.warning('inpage_receive_queue_full', {
20592
+ channel: this.channelName,
20593
+ });
20594
+ }
20595
+ else {
20596
+ logger$G.error('inpage_receive_error', {
20597
+ channel: this.channelName,
20598
+ error: error instanceof Error ? error.message : String(error),
20599
+ });
20600
+ }
20601
+ }
20602
+ return;
20603
+ }
20604
+ // Fall back to legacy format (no transport frame)
20382
20605
  const payload = InPageConnector.coercePayload(busMessage.payload);
20383
20606
  if (!payload) {
20384
20607
  logger$G.debug('inpage_payload_rejected', {
@@ -20419,6 +20642,92 @@ class InPageConnector extends BaseAsyncConnector {
20419
20642
  };
20420
20643
  getSharedBus$1().addEventListener(this.channelName, this.onMsg);
20421
20644
  this.listenerRegistered = true;
20645
+ // Setup visibility change monitoring
20646
+ this.visibilityChangeHandler = () => {
20647
+ const isHidden = document.hidden;
20648
+ logger$G.debug('inpage_visibility_changed', {
20649
+ channel: this.channelName,
20650
+ connector_id: this.connectorId,
20651
+ visibility: isHidden ? 'hidden' : 'visible',
20652
+ timestamp: new Date().toISOString(),
20653
+ });
20654
+ // Pause/resume connector based on visibility
20655
+ if (isHidden && this.state === core.ConnectorState.STARTED) {
20656
+ this.pause().catch((err) => {
20657
+ logger$G.warning('inpage_pause_failed', {
20658
+ channel: this.channelName,
20659
+ connector_id: this.connectorId,
20660
+ error: err instanceof Error ? err.message : String(err),
20661
+ });
20662
+ });
20663
+ }
20664
+ else if (!isHidden && this.state === core.ConnectorState.PAUSED) {
20665
+ this.resume().catch((err) => {
20666
+ logger$G.warning('inpage_resume_failed', {
20667
+ channel: this.channelName,
20668
+ connector_id: this.connectorId,
20669
+ error: err instanceof Error ? err.message : String(err),
20670
+ });
20671
+ });
20672
+ }
20673
+ };
20674
+ if (typeof document !== 'undefined') {
20675
+ document.addEventListener('visibilitychange', this.visibilityChangeHandler);
20676
+ this.visibilityChangeListenerRegistered = true;
20677
+ // Track page lifecycle events to detect browser unload/discard
20678
+ if (typeof window !== 'undefined') {
20679
+ const lifecycleLogger = (event) => {
20680
+ logger$G.info('inpage_page_lifecycle', {
20681
+ channel: this.channelName,
20682
+ connector_id: this.connectorId,
20683
+ event_type: event.type,
20684
+ visibility_state: document.visibilityState,
20685
+ timestamp: new Date().toISOString(),
20686
+ });
20687
+ };
20688
+ window.addEventListener('beforeunload', lifecycleLogger);
20689
+ window.addEventListener('unload', lifecycleLogger);
20690
+ window.addEventListener('pagehide', lifecycleLogger);
20691
+ window.addEventListener('pageshow', lifecycleLogger);
20692
+ document.addEventListener('freeze', lifecycleLogger);
20693
+ document.addEventListener('resume', lifecycleLogger);
20694
+ }
20695
+ // Log initial state with detailed visibility info
20696
+ logger$G.debug('inpage_initial_visibility', {
20697
+ channel: this.channelName,
20698
+ connector_id: this.connectorId,
20699
+ visibility: document.hidden ? 'hidden' : 'visible',
20700
+ document_hidden: document.hidden,
20701
+ visibility_state: document.visibilityState,
20702
+ has_focus: document.hasFocus(),
20703
+ timestamp: new Date().toISOString(),
20704
+ });
20705
+ }
20706
+ }
20707
+ /**
20708
+ * Override start() to check initial visibility state
20709
+ */
20710
+ async start(inboundHandler) {
20711
+ await super.start(inboundHandler);
20712
+ // After transitioning to STARTED, check if tab is already hidden
20713
+ if (typeof document !== 'undefined' && document.hidden) {
20714
+ logger$G.debug('inpage_start_in_hidden_tab', {
20715
+ channel: this.channelName,
20716
+ connector_id: this.connectorId,
20717
+ document_hidden: document.hidden,
20718
+ visibility_state: document.visibilityState,
20719
+ has_focus: document.hasFocus(),
20720
+ timestamp: new Date().toISOString(),
20721
+ });
20722
+ // Immediately pause if tab is hidden at start time
20723
+ await this.pause().catch((err) => {
20724
+ logger$G.warning('inpage_initial_pause_failed', {
20725
+ channel: this.channelName,
20726
+ connector_id: this.connectorId,
20727
+ error: err instanceof Error ? err.message : String(err),
20728
+ });
20729
+ });
20730
+ }
20422
20731
  }
20423
20732
  // Allow listeners to feed envelopes directly into the in-page receive queue.
20424
20733
  async pushToReceive(rawOrEnvelope) {
@@ -20451,11 +20760,27 @@ class InPageConnector extends BaseAsyncConnector {
20451
20760
  logger$G.debug('inpage_message_sending', {
20452
20761
  channel: this.channelName,
20453
20762
  sender_id: this.connectorId,
20454
- });
20763
+ local_node_id: this.localNodeId,
20764
+ remote_node_id: this.remoteNodeId,
20765
+ });
20766
+ // Only use transport framing if both localNodeId and remoteNodeId are explicitly set
20767
+ // (not using default values). This ensures backwards compatibility.
20768
+ const useTransportFrame = this.localNodeId !== this.connectorId ||
20769
+ this.remoteNodeId !== '*';
20770
+ let payload;
20771
+ if (useTransportFrame) {
20772
+ // Wrap payload in transport frame
20773
+ const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
20774
+ payload = serializeTransportFrame(frame);
20775
+ }
20776
+ else {
20777
+ // Legacy format: send raw payload
20778
+ payload = data;
20779
+ }
20455
20780
  const event = new MessageEvent(this.channelName, {
20456
20781
  data: {
20457
20782
  senderId: this.connectorId,
20458
- payload: data,
20783
+ payload,
20459
20784
  },
20460
20785
  });
20461
20786
  getSharedBus$1().dispatchEvent(event);
@@ -20468,6 +20793,11 @@ class InPageConnector extends BaseAsyncConnector {
20468
20793
  getSharedBus$1().removeEventListener(this.channelName, this.onMsg);
20469
20794
  this.listenerRegistered = false;
20470
20795
  }
20796
+ if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
20797
+ document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
20798
+ this.visibilityChangeListenerRegistered = false;
20799
+ this.visibilityChangeHandler = undefined;
20800
+ }
20471
20801
  const closeCode = typeof code === 'number' ? code : 1000;
20472
20802
  const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
20473
20803
  const shutdownError = new FameTransportClose(closeReason, closeCode);
@@ -27815,6 +28145,14 @@ function isInPageConnectionGrant(candidate) {
27815
28145
  record.inboxCapacity <= 0)) {
27816
28146
  return false;
27817
28147
  }
28148
+ if (record.localNodeId !== undefined &&
28149
+ (typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
28150
+ return false;
28151
+ }
28152
+ if (record.remoteNodeId !== undefined &&
28153
+ (typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
28154
+ return false;
28155
+ }
27818
28156
  return true;
27819
28157
  }
27820
28158
  function normalizeInPageConnectionGrant(candidate) {
@@ -27848,6 +28186,20 @@ function normalizeInPageConnectionGrant(candidate) {
27848
28186
  }
27849
28187
  result.inboxCapacity = Math.floor(inboxValue);
27850
28188
  }
28189
+ const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
28190
+ if (localNodeIdValue !== undefined) {
28191
+ if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
28192
+ throw new TypeError('InPageConnectionGrant "localNodeId" must be a non-empty string when provided');
28193
+ }
28194
+ result.localNodeId = localNodeIdValue.trim();
28195
+ }
28196
+ const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
28197
+ if (remoteNodeIdValue !== undefined) {
28198
+ if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
28199
+ throw new TypeError('InPageConnectionGrant "remoteNodeId" must be a non-empty string when provided');
28200
+ }
28201
+ result.remoteNodeId = remoteNodeIdValue.trim();
28202
+ }
27851
28203
  return result;
27852
28204
  }
27853
28205
  function inPageGrantToConnectorConfig(grant) {
@@ -27861,6 +28213,12 @@ function inPageGrantToConnectorConfig(grant) {
27861
28213
  if (normalized.inboxCapacity !== undefined) {
27862
28214
  config.inboxCapacity = normalized.inboxCapacity;
27863
28215
  }
28216
+ if (normalized.localNodeId) {
28217
+ config.localNodeId = normalized.localNodeId;
28218
+ }
28219
+ if (normalized.remoteNodeId) {
28220
+ config.remoteNodeId = normalized.remoteNodeId;
28221
+ }
27864
28222
  return config;
27865
28223
  }
27866
28224
 
@@ -28482,6 +28840,8 @@ class InPageConnectorFactory extends ConnectorFactory {
28482
28840
  type: INPAGE_CONNECTOR_TYPE,
28483
28841
  channelName,
28484
28842
  inboxCapacity,
28843
+ localNodeId: normalized.localNodeId,
28844
+ remoteNodeId: normalized.remoteNodeId,
28485
28845
  };
28486
28846
  const connector = new InPageConnector(connectorConfig, baseConfig);
28487
28847
  if (options.authorization) {
@@ -28550,6 +28910,16 @@ class InPageConnectorFactory extends ConnectorFactory {
28550
28910
  if (candidate.authorizationContext !== undefined) {
28551
28911
  normalized.authorizationContext = candidate.authorizationContext;
28552
28912
  }
28913
+ // Handle localNodeId
28914
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
28915
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
28916
+ normalized.localNodeId = localNodeId.trim();
28917
+ }
28918
+ // Handle remoteNodeId
28919
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
28920
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
28921
+ normalized.remoteNodeId = remoteNodeId.trim();
28922
+ }
28553
28923
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
28554
28924
  normalized.inboxCapacity =
28555
28925
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
@@ -28649,6 +29019,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28649
29019
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
28650
29020
  channelName,
28651
29021
  inboxCapacity,
29022
+ localNodeId: normalized.localNodeId,
29023
+ remoteNodeId: normalized.remoteNodeId,
28652
29024
  };
28653
29025
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
28654
29026
  if (options.authorization) {
@@ -28710,6 +29082,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28710
29082
  if (candidate.authorizationContext !== undefined) {
28711
29083
  normalized.authorizationContext = candidate.authorizationContext;
28712
29084
  }
29085
+ // Handle localNodeId
29086
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
29087
+ if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
29088
+ normalized.localNodeId = localNodeId.trim();
29089
+ }
29090
+ // Handle remoteNodeId
29091
+ const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
29092
+ if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
29093
+ normalized.remoteNodeId = remoteNodeId.trim();
29094
+ }
28713
29095
  normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$4;
28714
29096
  normalized.inboxCapacity =
28715
29097
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$4;