@naylence/runtime 0.3.5-test.934 → 0.3.5-test.937

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.
@@ -2137,6 +2137,48 @@ class BaseAsyncConnector extends TaskSpawner {
2137
2137
  connector_id: this._connectorFlowId,
2138
2138
  });
2139
2139
  }
2140
+ /**
2141
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
2142
+ */
2143
+ async pause() {
2144
+ logger$1f.debug('pausing_connector', {
2145
+ current_state: this._state,
2146
+ connector_id: this._connectorFlowId,
2147
+ });
2148
+ if (this._state !== core.ConnectorState.STARTED) {
2149
+ logger$1f.debug('connector_pause_invalid_state', {
2150
+ current_state: this._state,
2151
+ connector_id: this._connectorFlowId,
2152
+ });
2153
+ return;
2154
+ }
2155
+ this._setState(core.ConnectorState.PAUSED);
2156
+ logger$1f.debug('connector_paused', {
2157
+ current_state: this._state,
2158
+ connector_id: this._connectorFlowId,
2159
+ });
2160
+ }
2161
+ /**
2162
+ * Resume the connector from paused state
2163
+ */
2164
+ async resume() {
2165
+ logger$1f.debug('resuming_connector', {
2166
+ current_state: this._state,
2167
+ connector_id: this._connectorFlowId,
2168
+ });
2169
+ if (this._state !== core.ConnectorState.PAUSED) {
2170
+ logger$1f.debug('connector_resume_invalid_state', {
2171
+ current_state: this._state,
2172
+ connector_id: this._connectorFlowId,
2173
+ });
2174
+ return;
2175
+ }
2176
+ this._setState(core.ConnectorState.STARTED);
2177
+ logger$1f.debug('connector_resumed', {
2178
+ current_state: this._state,
2179
+ connector_id: this._connectorFlowId,
2180
+ });
2181
+ }
2140
2182
  /**
2141
2183
  * Close the connector with optional code and reason
2142
2184
  */
@@ -2472,7 +2514,7 @@ class BaseAsyncConnector extends TaskSpawner {
2472
2514
  });
2473
2515
  return;
2474
2516
  }
2475
- logger$1f.info('connector_shutdown_starting', {
2517
+ logger$1f.debug('connector_shutdown_starting', {
2476
2518
  connector_id: this._connectorFlowId,
2477
2519
  connector_type: this.constructor.name,
2478
2520
  code,
@@ -2502,19 +2544,19 @@ class BaseAsyncConnector extends TaskSpawner {
2502
2544
  this._sendPromiseResolve = undefined;
2503
2545
  }
2504
2546
  // Close transport
2505
- logger$1f.info('connector_closing_transport', {
2547
+ logger$1f.debug('connector_closing_transport', {
2506
2548
  connector_id: this._connectorFlowId,
2507
2549
  connector_type: this.constructor.name,
2508
2550
  timestamp: new Date().toISOString(),
2509
2551
  });
2510
2552
  await this._transportClose(code, reason);
2511
- logger$1f.info('connector_transport_closed', {
2553
+ logger$1f.debug('connector_transport_closed', {
2512
2554
  connector_id: this._connectorFlowId,
2513
2555
  connector_type: this.constructor.name,
2514
2556
  timestamp: new Date().toISOString(),
2515
2557
  });
2516
2558
  // Shutdown spawned tasks
2517
- logger$1f.info('connector_shutting_down_tasks', {
2559
+ logger$1f.debug('connector_shutting_down_tasks', {
2518
2560
  connector_id: this._connectorFlowId,
2519
2561
  connector_type: this.constructor.name,
2520
2562
  grace_period_ms: effectiveGracePeriod * 1000,
@@ -2526,7 +2568,7 @@ class BaseAsyncConnector extends TaskSpawner {
2526
2568
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
2527
2569
  joinTimeout: this._shutdownJoinTimeout,
2528
2570
  });
2529
- logger$1f.info('connector_tasks_shutdown_complete', {
2571
+ logger$1f.debug('connector_tasks_shutdown_complete', {
2530
2572
  connector_id: this._connectorFlowId,
2531
2573
  connector_type: this.constructor.name,
2532
2574
  timestamp: new Date().toISOString(),
@@ -2546,7 +2588,7 @@ class BaseAsyncConnector extends TaskSpawner {
2546
2588
  if (this._closeResolver) {
2547
2589
  this._closeResolver();
2548
2590
  }
2549
- logger$1f.info('connector_shutdown_complete', {
2591
+ logger$1f.debug('connector_shutdown_complete', {
2550
2592
  connector_id: this._connectorFlowId,
2551
2593
  connector_type: this.constructor.name,
2552
2594
  final_state: this._state,
@@ -5436,12 +5478,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
5436
5478
  }
5437
5479
 
5438
5480
  // This file is auto-generated during build - do not edit manually
5439
- // Generated from package.json version: 0.3.5-test.934
5481
+ // Generated from package.json version: 0.3.5-test.937
5440
5482
  /**
5441
5483
  * The package version, injected at build time.
5442
5484
  * @internal
5443
5485
  */
5444
- const VERSION = '0.3.5-test.934';
5486
+ const VERSION = '0.3.5-test.937';
5445
5487
 
5446
5488
  /**
5447
5489
  * Fame errors module - Fame protocol specific error classes
@@ -11494,7 +11536,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11494
11536
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
11495
11537
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
11496
11538
  this.channel = new BroadcastChannel(this.channelName);
11497
- logger$10.info('broadcast_channel_connector_created', {
11539
+ logger$10.debug('broadcast_channel_connector_created', {
11498
11540
  channel: this.channelName,
11499
11541
  connector_id: this.connectorId,
11500
11542
  inbox_capacity: preferredCapacity,
@@ -11575,18 +11617,37 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11575
11617
  // Setup visibility change monitoring
11576
11618
  this.visibilityChangeHandler = () => {
11577
11619
  const isHidden = document.hidden;
11578
- logger$10.info('broadcast_channel_visibility_changed', {
11620
+ logger$10.debug('broadcast_channel_visibility_changed', {
11579
11621
  channel: this.channelName,
11580
11622
  connector_id: this.connectorId,
11581
11623
  visibility: isHidden ? 'hidden' : 'visible',
11582
11624
  timestamp: new Date().toISOString(),
11583
11625
  });
11626
+ // Pause/resume connector based on visibility
11627
+ if (isHidden && this.state === core.ConnectorState.STARTED) {
11628
+ this.pause().catch((err) => {
11629
+ logger$10.warning('broadcast_channel_pause_failed', {
11630
+ channel: this.channelName,
11631
+ connector_id: this.connectorId,
11632
+ error: err instanceof Error ? err.message : String(err),
11633
+ });
11634
+ });
11635
+ }
11636
+ else if (!isHidden && this.state === core.ConnectorState.PAUSED) {
11637
+ this.resume().catch((err) => {
11638
+ logger$10.warning('broadcast_channel_resume_failed', {
11639
+ channel: this.channelName,
11640
+ connector_id: this.connectorId,
11641
+ error: err instanceof Error ? err.message : String(err),
11642
+ });
11643
+ });
11644
+ }
11584
11645
  };
11585
11646
  if (typeof document !== 'undefined') {
11586
11647
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
11587
11648
  this.visibilityChangeListenerRegistered = true;
11588
11649
  // Log initial state
11589
- logger$10.info('broadcast_channel_initial_visibility', {
11650
+ logger$10.debug('broadcast_channel_initial_visibility', {
11590
11651
  channel: this.channelName,
11591
11652
  connector_id: this.connectorId,
11592
11653
  visibility: document.hidden ? 'hidden' : 'visible',
@@ -11636,7 +11697,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11636
11697
  return await this.inbox.dequeue();
11637
11698
  }
11638
11699
  async _transportClose(code, reason) {
11639
- logger$10.info('broadcast_channel_transport_closing', {
11700
+ logger$10.debug('broadcast_channel_transport_closing', {
11640
11701
  channel: this.channelName,
11641
11702
  connector_id: this.connectorId,
11642
11703
  code,
@@ -11645,14 +11706,14 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11645
11706
  timestamp: new Date().toISOString(),
11646
11707
  });
11647
11708
  if (this.listenerRegistered) {
11648
- logger$10.info('broadcast_channel_removing_listener', {
11709
+ logger$10.debug('broadcast_channel_removing_listener', {
11649
11710
  channel: this.channelName,
11650
11711
  connector_id: this.connectorId,
11651
11712
  timestamp: new Date().toISOString(),
11652
11713
  });
11653
11714
  this.channel.removeEventListener('message', this.onMsg);
11654
11715
  this.listenerRegistered = false;
11655
- logger$10.info('broadcast_channel_listener_removed', {
11716
+ logger$10.debug('broadcast_channel_listener_removed', {
11656
11717
  channel: this.channelName,
11657
11718
  connector_id: this.connectorId,
11658
11719
  timestamp: new Date().toISOString(),
@@ -11663,13 +11724,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11663
11724
  this.visibilityChangeListenerRegistered = false;
11664
11725
  this.visibilityChangeHandler = undefined;
11665
11726
  }
11666
- logger$10.info('broadcast_channel_closing', {
11727
+ logger$10.debug('broadcast_channel_closing', {
11667
11728
  channel: this.channelName,
11668
11729
  connector_id: this.connectorId,
11669
11730
  timestamp: new Date().toISOString(),
11670
11731
  });
11671
11732
  this.channel.close();
11672
- logger$10.info('broadcast_channel_closed', {
11733
+ logger$10.debug('broadcast_channel_closed', {
11673
11734
  channel: this.channelName,
11674
11735
  connector_id: this.connectorId,
11675
11736
  timestamp: new Date().toISOString(),
@@ -11760,6 +11821,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11760
11821
  }
11761
11822
  return undefined;
11762
11823
  }
11824
+ /**
11825
+ * Override start() to check initial visibility state
11826
+ */
11827
+ async start(inboundHandler) {
11828
+ await super.start(inboundHandler);
11829
+ // After transitioning to STARTED, check if tab is already hidden
11830
+ if (typeof document !== 'undefined' && document.hidden) {
11831
+ logger$10.debug('broadcast_channel_start_in_hidden_tab', {
11832
+ channel: this.channelName,
11833
+ connector_id: this.connectorId,
11834
+ timestamp: new Date().toISOString(),
11835
+ });
11836
+ // Immediately pause if tab is hidden at start time
11837
+ await this.pause().catch((err) => {
11838
+ logger$10.warning('broadcast_channel_initial_pause_failed', {
11839
+ channel: this.channelName,
11840
+ connector_id: this.connectorId,
11841
+ error: err instanceof Error ? err.message : String(err),
11842
+ });
11843
+ });
11844
+ }
11845
+ }
11763
11846
  _trimSeenAcks(now) {
11764
11847
  while (this.seenAckOrder.length > 0) {
11765
11848
  const candidate = this.seenAckOrder[0];
@@ -12425,6 +12508,15 @@ class UpstreamSessionManager extends TaskSpawner {
12425
12508
  if (stopEvt.isSet() || signal?.aborted) {
12426
12509
  break;
12427
12510
  }
12511
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
12512
+ // Keep ack time current so we don't timeout immediately after resuming
12513
+ if (connector.state === core.ConnectorState.PAUSED) {
12514
+ logger$$.debug('skipping_heartbeat_connector_paused', {
12515
+ connector_state: connector.state,
12516
+ });
12517
+ this.lastHeartbeatAckTime = Date.now();
12518
+ continue;
12519
+ }
12428
12520
  const envelope = await this.makeHeartbeatEnvelope();
12429
12521
  logger$$.debug('sending_heartbeat', {
12430
12522
  hb_corr_id: envelope.corrId,
@@ -12446,6 +12538,7 @@ class UpstreamSessionManager extends TaskSpawner {
12446
12538
  throw error;
12447
12539
  }
12448
12540
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
12541
+ // Don't check heartbeat timeout when paused
12449
12542
  if (this.lastHeartbeatAckTime !== null &&
12450
12543
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
12451
12544
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -2136,6 +2136,48 @@ class BaseAsyncConnector extends TaskSpawner {
2136
2136
  connector_id: this._connectorFlowId,
2137
2137
  });
2138
2138
  }
2139
+ /**
2140
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
2141
+ */
2142
+ async pause() {
2143
+ logger$1f.debug('pausing_connector', {
2144
+ current_state: this._state,
2145
+ connector_id: this._connectorFlowId,
2146
+ });
2147
+ if (this._state !== ConnectorState.STARTED) {
2148
+ logger$1f.debug('connector_pause_invalid_state', {
2149
+ current_state: this._state,
2150
+ connector_id: this._connectorFlowId,
2151
+ });
2152
+ return;
2153
+ }
2154
+ this._setState(ConnectorState.PAUSED);
2155
+ logger$1f.debug('connector_paused', {
2156
+ current_state: this._state,
2157
+ connector_id: this._connectorFlowId,
2158
+ });
2159
+ }
2160
+ /**
2161
+ * Resume the connector from paused state
2162
+ */
2163
+ async resume() {
2164
+ logger$1f.debug('resuming_connector', {
2165
+ current_state: this._state,
2166
+ connector_id: this._connectorFlowId,
2167
+ });
2168
+ if (this._state !== ConnectorState.PAUSED) {
2169
+ logger$1f.debug('connector_resume_invalid_state', {
2170
+ current_state: this._state,
2171
+ connector_id: this._connectorFlowId,
2172
+ });
2173
+ return;
2174
+ }
2175
+ this._setState(ConnectorState.STARTED);
2176
+ logger$1f.debug('connector_resumed', {
2177
+ current_state: this._state,
2178
+ connector_id: this._connectorFlowId,
2179
+ });
2180
+ }
2139
2181
  /**
2140
2182
  * Close the connector with optional code and reason
2141
2183
  */
@@ -2471,7 +2513,7 @@ class BaseAsyncConnector extends TaskSpawner {
2471
2513
  });
2472
2514
  return;
2473
2515
  }
2474
- logger$1f.info('connector_shutdown_starting', {
2516
+ logger$1f.debug('connector_shutdown_starting', {
2475
2517
  connector_id: this._connectorFlowId,
2476
2518
  connector_type: this.constructor.name,
2477
2519
  code,
@@ -2501,19 +2543,19 @@ class BaseAsyncConnector extends TaskSpawner {
2501
2543
  this._sendPromiseResolve = undefined;
2502
2544
  }
2503
2545
  // Close transport
2504
- logger$1f.info('connector_closing_transport', {
2546
+ logger$1f.debug('connector_closing_transport', {
2505
2547
  connector_id: this._connectorFlowId,
2506
2548
  connector_type: this.constructor.name,
2507
2549
  timestamp: new Date().toISOString(),
2508
2550
  });
2509
2551
  await this._transportClose(code, reason);
2510
- logger$1f.info('connector_transport_closed', {
2552
+ logger$1f.debug('connector_transport_closed', {
2511
2553
  connector_id: this._connectorFlowId,
2512
2554
  connector_type: this.constructor.name,
2513
2555
  timestamp: new Date().toISOString(),
2514
2556
  });
2515
2557
  // Shutdown spawned tasks
2516
- logger$1f.info('connector_shutting_down_tasks', {
2558
+ logger$1f.debug('connector_shutting_down_tasks', {
2517
2559
  connector_id: this._connectorFlowId,
2518
2560
  connector_type: this.constructor.name,
2519
2561
  grace_period_ms: effectiveGracePeriod * 1000,
@@ -2525,7 +2567,7 @@ class BaseAsyncConnector extends TaskSpawner {
2525
2567
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
2526
2568
  joinTimeout: this._shutdownJoinTimeout,
2527
2569
  });
2528
- logger$1f.info('connector_tasks_shutdown_complete', {
2570
+ logger$1f.debug('connector_tasks_shutdown_complete', {
2529
2571
  connector_id: this._connectorFlowId,
2530
2572
  connector_type: this.constructor.name,
2531
2573
  timestamp: new Date().toISOString(),
@@ -2545,7 +2587,7 @@ class BaseAsyncConnector extends TaskSpawner {
2545
2587
  if (this._closeResolver) {
2546
2588
  this._closeResolver();
2547
2589
  }
2548
- logger$1f.info('connector_shutdown_complete', {
2590
+ logger$1f.debug('connector_shutdown_complete', {
2549
2591
  connector_id: this._connectorFlowId,
2550
2592
  connector_type: this.constructor.name,
2551
2593
  final_state: this._state,
@@ -5435,12 +5477,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
5435
5477
  }
5436
5478
 
5437
5479
  // This file is auto-generated during build - do not edit manually
5438
- // Generated from package.json version: 0.3.5-test.934
5480
+ // Generated from package.json version: 0.3.5-test.937
5439
5481
  /**
5440
5482
  * The package version, injected at build time.
5441
5483
  * @internal
5442
5484
  */
5443
- const VERSION = '0.3.5-test.934';
5485
+ const VERSION = '0.3.5-test.937';
5444
5486
 
5445
5487
  /**
5446
5488
  * Fame errors module - Fame protocol specific error classes
@@ -11493,7 +11535,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11493
11535
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
11494
11536
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
11495
11537
  this.channel = new BroadcastChannel(this.channelName);
11496
- logger$10.info('broadcast_channel_connector_created', {
11538
+ logger$10.debug('broadcast_channel_connector_created', {
11497
11539
  channel: this.channelName,
11498
11540
  connector_id: this.connectorId,
11499
11541
  inbox_capacity: preferredCapacity,
@@ -11574,18 +11616,37 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11574
11616
  // Setup visibility change monitoring
11575
11617
  this.visibilityChangeHandler = () => {
11576
11618
  const isHidden = document.hidden;
11577
- logger$10.info('broadcast_channel_visibility_changed', {
11619
+ logger$10.debug('broadcast_channel_visibility_changed', {
11578
11620
  channel: this.channelName,
11579
11621
  connector_id: this.connectorId,
11580
11622
  visibility: isHidden ? 'hidden' : 'visible',
11581
11623
  timestamp: new Date().toISOString(),
11582
11624
  });
11625
+ // Pause/resume connector based on visibility
11626
+ if (isHidden && this.state === ConnectorState.STARTED) {
11627
+ this.pause().catch((err) => {
11628
+ logger$10.warning('broadcast_channel_pause_failed', {
11629
+ channel: this.channelName,
11630
+ connector_id: this.connectorId,
11631
+ error: err instanceof Error ? err.message : String(err),
11632
+ });
11633
+ });
11634
+ }
11635
+ else if (!isHidden && this.state === ConnectorState.PAUSED) {
11636
+ this.resume().catch((err) => {
11637
+ logger$10.warning('broadcast_channel_resume_failed', {
11638
+ channel: this.channelName,
11639
+ connector_id: this.connectorId,
11640
+ error: err instanceof Error ? err.message : String(err),
11641
+ });
11642
+ });
11643
+ }
11583
11644
  };
11584
11645
  if (typeof document !== 'undefined') {
11585
11646
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
11586
11647
  this.visibilityChangeListenerRegistered = true;
11587
11648
  // Log initial state
11588
- logger$10.info('broadcast_channel_initial_visibility', {
11649
+ logger$10.debug('broadcast_channel_initial_visibility', {
11589
11650
  channel: this.channelName,
11590
11651
  connector_id: this.connectorId,
11591
11652
  visibility: document.hidden ? 'hidden' : 'visible',
@@ -11635,7 +11696,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11635
11696
  return await this.inbox.dequeue();
11636
11697
  }
11637
11698
  async _transportClose(code, reason) {
11638
- logger$10.info('broadcast_channel_transport_closing', {
11699
+ logger$10.debug('broadcast_channel_transport_closing', {
11639
11700
  channel: this.channelName,
11640
11701
  connector_id: this.connectorId,
11641
11702
  code,
@@ -11644,14 +11705,14 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11644
11705
  timestamp: new Date().toISOString(),
11645
11706
  });
11646
11707
  if (this.listenerRegistered) {
11647
- logger$10.info('broadcast_channel_removing_listener', {
11708
+ logger$10.debug('broadcast_channel_removing_listener', {
11648
11709
  channel: this.channelName,
11649
11710
  connector_id: this.connectorId,
11650
11711
  timestamp: new Date().toISOString(),
11651
11712
  });
11652
11713
  this.channel.removeEventListener('message', this.onMsg);
11653
11714
  this.listenerRegistered = false;
11654
- logger$10.info('broadcast_channel_listener_removed', {
11715
+ logger$10.debug('broadcast_channel_listener_removed', {
11655
11716
  channel: this.channelName,
11656
11717
  connector_id: this.connectorId,
11657
11718
  timestamp: new Date().toISOString(),
@@ -11662,13 +11723,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11662
11723
  this.visibilityChangeListenerRegistered = false;
11663
11724
  this.visibilityChangeHandler = undefined;
11664
11725
  }
11665
- logger$10.info('broadcast_channel_closing', {
11726
+ logger$10.debug('broadcast_channel_closing', {
11666
11727
  channel: this.channelName,
11667
11728
  connector_id: this.connectorId,
11668
11729
  timestamp: new Date().toISOString(),
11669
11730
  });
11670
11731
  this.channel.close();
11671
- logger$10.info('broadcast_channel_closed', {
11732
+ logger$10.debug('broadcast_channel_closed', {
11672
11733
  channel: this.channelName,
11673
11734
  connector_id: this.connectorId,
11674
11735
  timestamp: new Date().toISOString(),
@@ -11759,6 +11820,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11759
11820
  }
11760
11821
  return undefined;
11761
11822
  }
11823
+ /**
11824
+ * Override start() to check initial visibility state
11825
+ */
11826
+ async start(inboundHandler) {
11827
+ await super.start(inboundHandler);
11828
+ // After transitioning to STARTED, check if tab is already hidden
11829
+ if (typeof document !== 'undefined' && document.hidden) {
11830
+ logger$10.debug('broadcast_channel_start_in_hidden_tab', {
11831
+ channel: this.channelName,
11832
+ connector_id: this.connectorId,
11833
+ timestamp: new Date().toISOString(),
11834
+ });
11835
+ // Immediately pause if tab is hidden at start time
11836
+ await this.pause().catch((err) => {
11837
+ logger$10.warning('broadcast_channel_initial_pause_failed', {
11838
+ channel: this.channelName,
11839
+ connector_id: this.connectorId,
11840
+ error: err instanceof Error ? err.message : String(err),
11841
+ });
11842
+ });
11843
+ }
11844
+ }
11762
11845
  _trimSeenAcks(now) {
11763
11846
  while (this.seenAckOrder.length > 0) {
11764
11847
  const candidate = this.seenAckOrder[0];
@@ -12424,6 +12507,15 @@ class UpstreamSessionManager extends TaskSpawner {
12424
12507
  if (stopEvt.isSet() || signal?.aborted) {
12425
12508
  break;
12426
12509
  }
12510
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
12511
+ // Keep ack time current so we don't timeout immediately after resuming
12512
+ if (connector.state === ConnectorState.PAUSED) {
12513
+ logger$$.debug('skipping_heartbeat_connector_paused', {
12514
+ connector_state: connector.state,
12515
+ });
12516
+ this.lastHeartbeatAckTime = Date.now();
12517
+ continue;
12518
+ }
12427
12519
  const envelope = await this.makeHeartbeatEnvelope();
12428
12520
  logger$$.debug('sending_heartbeat', {
12429
12521
  hb_corr_id: envelope.corrId,
@@ -12445,6 +12537,7 @@ class UpstreamSessionManager extends TaskSpawner {
12445
12537
  throw error;
12446
12538
  }
12447
12539
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
12540
+ // Don't check heartbeat timeout when paused
12448
12541
  if (this.lastHeartbeatAckTime !== null &&
12449
12542
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
12450
12543
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -103,6 +103,14 @@ export declare abstract class BaseAsyncConnector extends TaskSpawner implements
103
103
  * Stop the connector gracefully
104
104
  */
105
105
  stop(): Promise<void>;
106
+ /**
107
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
108
+ */
109
+ pause(): Promise<void>;
110
+ /**
111
+ * Resume the connector from paused state
112
+ */
113
+ resume(): Promise<void>;
106
114
  /**
107
115
  * Close the connector with optional code and reason
108
116
  */
@@ -1,6 +1,6 @@
1
1
  import { BaseAsyncConnector, type BaseAsyncConnectorConfig } from './base-async-connector.js';
2
2
  import type { ConnectorConfig } from './connector-config.js';
3
- import type { FameEnvelope, FameChannelMessage } from '@naylence/core';
3
+ import type { FameEnvelope, FameChannelMessage, FameEnvelopeHandler } from '@naylence/core';
4
4
  export declare const BROADCAST_CHANNEL_CONNECTOR_TYPE: "broadcast-channel-connector";
5
5
  export interface BroadcastChannelConnectorConfig extends ConnectorConfig {
6
6
  type: typeof BROADCAST_CHANNEL_CONNECTOR_TYPE;
@@ -35,6 +35,10 @@ export declare class BroadcastChannelConnector extends BaseAsyncConnector {
35
35
  private _checkDuplicateAck;
36
36
  private _extractEnvelopeFromInboxItem;
37
37
  private _extractSenderIdFromInboxItem;
38
+ /**
39
+ * Override start() to check initial visibility state
40
+ */
41
+ start(inboundHandler: FameEnvelopeHandler): Promise<void>;
38
42
  private _trimSeenAcks;
39
43
  private _extractAckDedupKey;
40
44
  }
@@ -2,4 +2,4 @@
2
2
  * The package version, injected at build time.
3
3
  * @internal
4
4
  */
5
- export declare const VERSION = "0.3.5-test.934";
5
+ export declare const VERSION = "0.3.5-test.937";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naylence/runtime",
3
- "version": "0.3.5-test.934",
3
+ "version": "0.3.5-test.937",
4
4
  "type": "module",
5
5
  "description": "Naylence Runtime - Complete TypeScript runtime",
6
6
  "author": "Naylence Dev <naylencedev@gmail.com>",
@@ -176,7 +176,7 @@
176
176
  "dependencies": {
177
177
  "@fastify/formbody": "^8.0.2",
178
178
  "@fastify/websocket": "^11.2.0",
179
- "@naylence/core": "^0.3.4",
179
+ "@naylence/core": "^0.3.5",
180
180
  "@noble/ciphers": "^2.0.1",
181
181
  "@noble/curves": "^2.0.1",
182
182
  "@noble/ed25519": "^3.0.0",