@naylence/runtime 0.3.5-test.933 → 0.3.5-test.936

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.
@@ -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.933
17
+ // Generated from package.json version: 0.3.5-test.936
18
18
  /**
19
19
  * The package version, injected at build time.
20
20
  * @internal
21
21
  */
22
- const VERSION = '0.3.5-test.933';
22
+ const VERSION = '0.3.5-test.936';
23
23
 
24
24
  /**
25
25
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9186,6 +9186,10 @@ class BaseAsyncConnector extends TaskSpawner {
9186
9186
  * Stop the connector gracefully
9187
9187
  */
9188
9188
  async stop() {
9189
+ logger$$.debug('stopping_connector', {
9190
+ current_state: this._state,
9191
+ connector_id: this._connectorFlowId,
9192
+ });
9189
9193
  if (!core.ConnectorStateUtils.canStop(this._state)) {
9190
9194
  logger$$.debug('connector_stop_already_stopped', {
9191
9195
  current_state: this._state,
@@ -9198,6 +9202,52 @@ class BaseAsyncConnector extends TaskSpawner {
9198
9202
  if (this._lastError) {
9199
9203
  throw this._lastError;
9200
9204
  }
9205
+ logger$$.debug('connector_stopped', {
9206
+ current_state: this._state,
9207
+ connector_id: this._connectorFlowId,
9208
+ });
9209
+ }
9210
+ /**
9211
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
9212
+ */
9213
+ async pause() {
9214
+ logger$$.debug('pausing_connector', {
9215
+ current_state: this._state,
9216
+ connector_id: this._connectorFlowId,
9217
+ });
9218
+ if (this._state !== core.ConnectorState.STARTED) {
9219
+ logger$$.debug('connector_pause_invalid_state', {
9220
+ current_state: this._state,
9221
+ connector_id: this._connectorFlowId,
9222
+ });
9223
+ return;
9224
+ }
9225
+ this._setState(core.ConnectorState.PAUSED);
9226
+ logger$$.debug('connector_paused', {
9227
+ current_state: this._state,
9228
+ connector_id: this._connectorFlowId,
9229
+ });
9230
+ }
9231
+ /**
9232
+ * Resume the connector from paused state
9233
+ */
9234
+ async resume() {
9235
+ logger$$.debug('resuming_connector', {
9236
+ current_state: this._state,
9237
+ connector_id: this._connectorFlowId,
9238
+ });
9239
+ if (this._state !== core.ConnectorState.PAUSED) {
9240
+ logger$$.debug('connector_resume_invalid_state', {
9241
+ current_state: this._state,
9242
+ connector_id: this._connectorFlowId,
9243
+ });
9244
+ return;
9245
+ }
9246
+ this._setState(core.ConnectorState.STARTED);
9247
+ logger$$.debug('connector_resumed', {
9248
+ current_state: this._state,
9249
+ connector_id: this._connectorFlowId,
9250
+ });
9201
9251
  }
9202
9252
  /**
9203
9253
  * Close the connector with optional code and reason
@@ -9528,8 +9578,21 @@ class BaseAsyncConnector extends TaskSpawner {
9528
9578
  */
9529
9579
  async _shutdown(code, reason, gracePeriod, exc) {
9530
9580
  if (this._closed) {
9581
+ logger$$.debug('shutdown_already_closed', {
9582
+ connector_id: this._connectorFlowId,
9583
+ current_state: this._state,
9584
+ });
9531
9585
  return;
9532
9586
  }
9587
+ logger$$.info('connector_shutdown_starting', {
9588
+ connector_id: this._connectorFlowId,
9589
+ connector_type: this.constructor.name,
9590
+ code,
9591
+ reason,
9592
+ current_state: this._state,
9593
+ has_error: !!exc,
9594
+ timestamp: new Date().toISOString(),
9595
+ });
9533
9596
  this._closed = true;
9534
9597
  this._closeCode = code;
9535
9598
  this._closeReason = reason;
@@ -9551,16 +9614,39 @@ class BaseAsyncConnector extends TaskSpawner {
9551
9614
  this._sendPromiseResolve = undefined;
9552
9615
  }
9553
9616
  // Close transport
9617
+ logger$$.info('connector_closing_transport', {
9618
+ connector_id: this._connectorFlowId,
9619
+ connector_type: this.constructor.name,
9620
+ timestamp: new Date().toISOString(),
9621
+ });
9554
9622
  await this._transportClose(code, reason);
9623
+ logger$$.info('connector_transport_closed', {
9624
+ connector_id: this._connectorFlowId,
9625
+ connector_type: this.constructor.name,
9626
+ timestamp: new Date().toISOString(),
9627
+ });
9555
9628
  // Shutdown spawned tasks
9629
+ logger$$.info('connector_shutting_down_tasks', {
9630
+ connector_id: this._connectorFlowId,
9631
+ connector_type: this.constructor.name,
9632
+ grace_period_ms: effectiveGracePeriod * 1000,
9633
+ join_timeout_ms: this._shutdownJoinTimeout,
9634
+ timestamp: new Date().toISOString(),
9635
+ });
9556
9636
  try {
9557
9637
  await this.shutdownTasks({
9558
9638
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
9559
9639
  joinTimeout: this._shutdownJoinTimeout,
9560
9640
  });
9641
+ logger$$.info('connector_tasks_shutdown_complete', {
9642
+ connector_id: this._connectorFlowId,
9643
+ connector_type: this.constructor.name,
9644
+ timestamp: new Date().toISOString(),
9645
+ });
9561
9646
  }
9562
9647
  catch (error) {
9563
9648
  logger$$.warning('task_shutdown_error', {
9649
+ connector_id: this._connectorFlowId,
9564
9650
  error: error instanceof Error ? error.message : String(error),
9565
9651
  });
9566
9652
  }
@@ -9572,6 +9658,12 @@ class BaseAsyncConnector extends TaskSpawner {
9572
9658
  if (this._closeResolver) {
9573
9659
  this._closeResolver();
9574
9660
  }
9661
+ logger$$.info('connector_shutdown_complete', {
9662
+ connector_id: this._connectorFlowId,
9663
+ connector_type: this.constructor.name,
9664
+ final_state: this._state,
9665
+ timestamp: new Date().toISOString(),
9666
+ });
9575
9667
  }
9576
9668
  /**
9577
9669
  * Close the underlying transport
@@ -9707,12 +9799,22 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9707
9799
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9708
9800
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9709
9801
  this.channel = new BroadcastChannel(this.channelName);
9710
- logger$_.debug('broadcast_channel_connector_initialized', {
9802
+ logger$_.info('broadcast_channel_connector_created', {
9711
9803
  channel: this.channelName,
9712
9804
  connector_id: this.connectorId,
9713
9805
  inbox_capacity: preferredCapacity,
9806
+ timestamp: new Date().toISOString(),
9714
9807
  });
9715
9808
  this.onMsg = (event) => {
9809
+ // Guard: Don't process if listener was unregistered
9810
+ if (!this.listenerRegistered) {
9811
+ logger$_.warning('broadcast_channel_message_after_unregister', {
9812
+ channel: this.channelName,
9813
+ connector_id: this.connectorId,
9814
+ timestamp: new Date().toISOString(),
9815
+ });
9816
+ return;
9817
+ }
9716
9818
  const message = event.data;
9717
9819
  logger$_.debug('broadcast_channel_raw_event', {
9718
9820
  channel: this.channelName,
@@ -9784,6 +9886,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9784
9886
  visibility: isHidden ? 'hidden' : 'visible',
9785
9887
  timestamp: new Date().toISOString(),
9786
9888
  });
9889
+ // Pause/resume connector based on visibility
9890
+ if (isHidden && this.state === core.ConnectorState.STARTED) {
9891
+ this.pause().catch((err) => {
9892
+ logger$_.warning('broadcast_channel_pause_failed', {
9893
+ channel: this.channelName,
9894
+ connector_id: this.connectorId,
9895
+ error: err instanceof Error ? err.message : String(err),
9896
+ });
9897
+ });
9898
+ }
9899
+ else if (!isHidden && this.state === core.ConnectorState.PAUSED) {
9900
+ this.resume().catch((err) => {
9901
+ logger$_.warning('broadcast_channel_resume_failed', {
9902
+ channel: this.channelName,
9903
+ connector_id: this.connectorId,
9904
+ error: err instanceof Error ? err.message : String(err),
9905
+ });
9906
+ });
9907
+ }
9787
9908
  };
9788
9909
  if (typeof document !== 'undefined') {
9789
9910
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -9839,16 +9960,44 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9839
9960
  return await this.inbox.dequeue();
9840
9961
  }
9841
9962
  async _transportClose(code, reason) {
9963
+ logger$_.info('broadcast_channel_transport_closing', {
9964
+ channel: this.channelName,
9965
+ connector_id: this.connectorId,
9966
+ code,
9967
+ reason,
9968
+ listener_registered: this.listenerRegistered,
9969
+ timestamp: new Date().toISOString(),
9970
+ });
9842
9971
  if (this.listenerRegistered) {
9972
+ logger$_.info('broadcast_channel_removing_listener', {
9973
+ channel: this.channelName,
9974
+ connector_id: this.connectorId,
9975
+ timestamp: new Date().toISOString(),
9976
+ });
9843
9977
  this.channel.removeEventListener('message', this.onMsg);
9844
9978
  this.listenerRegistered = false;
9979
+ logger$_.info('broadcast_channel_listener_removed', {
9980
+ channel: this.channelName,
9981
+ connector_id: this.connectorId,
9982
+ timestamp: new Date().toISOString(),
9983
+ });
9845
9984
  }
9846
9985
  if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
9847
9986
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
9848
9987
  this.visibilityChangeListenerRegistered = false;
9849
9988
  this.visibilityChangeHandler = undefined;
9850
9989
  }
9990
+ logger$_.info('broadcast_channel_closing', {
9991
+ channel: this.channelName,
9992
+ connector_id: this.connectorId,
9993
+ timestamp: new Date().toISOString(),
9994
+ });
9851
9995
  this.channel.close();
9996
+ logger$_.info('broadcast_channel_closed', {
9997
+ channel: this.channelName,
9998
+ connector_id: this.connectorId,
9999
+ timestamp: new Date().toISOString(),
10000
+ });
9852
10001
  const closeCode = typeof code === 'number' ? code : 1000;
9853
10002
  const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
9854
10003
  const shutdownError = new FameTransportClose(closeReason, closeCode);
@@ -10496,7 +10645,22 @@ class UpstreamSessionManager extends TaskSpawner {
10496
10645
  this.currentStopSubtasks = null;
10497
10646
  await Promise.allSettled(tasks.map((task) => task.promise));
10498
10647
  if (this.connector) {
10499
- await this.connector.stop().catch(() => undefined);
10648
+ logger$Z.info('upstream_stopping_old_connector', {
10649
+ connect_epoch: this.connectEpoch,
10650
+ target_system_id: this.targetSystemId,
10651
+ timestamp: new Date().toISOString(),
10652
+ });
10653
+ await this.connector.stop().catch((err) => {
10654
+ logger$Z.warning('upstream_connector_stop_error', {
10655
+ connect_epoch: this.connectEpoch,
10656
+ error: err instanceof Error ? err.message : String(err),
10657
+ });
10658
+ });
10659
+ logger$Z.info('upstream_old_connector_stopped', {
10660
+ connect_epoch: this.connectEpoch,
10661
+ target_system_id: this.targetSystemId,
10662
+ timestamp: new Date().toISOString(),
10663
+ });
10500
10664
  this.connector = null;
10501
10665
  }
10502
10666
  }
@@ -10630,6 +10794,15 @@ class UpstreamSessionManager extends TaskSpawner {
10630
10794
  if (stopEvt.isSet() || signal?.aborted) {
10631
10795
  break;
10632
10796
  }
10797
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
10798
+ // Keep ack time current so we don't timeout immediately after resuming
10799
+ if (connector.state === core.ConnectorState.PAUSED) {
10800
+ logger$Z.debug('skipping_heartbeat_connector_paused', {
10801
+ connector_state: connector.state,
10802
+ });
10803
+ this.lastHeartbeatAckTime = Date.now();
10804
+ continue;
10805
+ }
10633
10806
  const envelope = await this.makeHeartbeatEnvelope();
10634
10807
  logger$Z.debug('sending_heartbeat', {
10635
10808
  hb_corr_id: envelope.corrId,
@@ -10651,6 +10824,7 @@ class UpstreamSessionManager extends TaskSpawner {
10651
10824
  throw error;
10652
10825
  }
10653
10826
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10827
+ // Don't check heartbeat timeout when paused
10654
10828
  if (this.lastHeartbeatAckTime !== null &&
10655
10829
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10656
10830
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -13,12 +13,12 @@ import fastify from 'fastify';
13
13
  import websocketPlugin from '@fastify/websocket';
14
14
 
15
15
  // This file is auto-generated during build - do not edit manually
16
- // Generated from package.json version: 0.3.5-test.933
16
+ // Generated from package.json version: 0.3.5-test.936
17
17
  /**
18
18
  * The package version, injected at build time.
19
19
  * @internal
20
20
  */
21
- const VERSION = '0.3.5-test.933';
21
+ const VERSION = '0.3.5-test.936';
22
22
 
23
23
  /**
24
24
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9185,6 +9185,10 @@ class BaseAsyncConnector extends TaskSpawner {
9185
9185
  * Stop the connector gracefully
9186
9186
  */
9187
9187
  async stop() {
9188
+ logger$$.debug('stopping_connector', {
9189
+ current_state: this._state,
9190
+ connector_id: this._connectorFlowId,
9191
+ });
9188
9192
  if (!ConnectorStateUtils.canStop(this._state)) {
9189
9193
  logger$$.debug('connector_stop_already_stopped', {
9190
9194
  current_state: this._state,
@@ -9197,6 +9201,52 @@ class BaseAsyncConnector extends TaskSpawner {
9197
9201
  if (this._lastError) {
9198
9202
  throw this._lastError;
9199
9203
  }
9204
+ logger$$.debug('connector_stopped', {
9205
+ current_state: this._state,
9206
+ connector_id: this._connectorFlowId,
9207
+ });
9208
+ }
9209
+ /**
9210
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
9211
+ */
9212
+ async pause() {
9213
+ logger$$.debug('pausing_connector', {
9214
+ current_state: this._state,
9215
+ connector_id: this._connectorFlowId,
9216
+ });
9217
+ if (this._state !== ConnectorState.STARTED) {
9218
+ logger$$.debug('connector_pause_invalid_state', {
9219
+ current_state: this._state,
9220
+ connector_id: this._connectorFlowId,
9221
+ });
9222
+ return;
9223
+ }
9224
+ this._setState(ConnectorState.PAUSED);
9225
+ logger$$.debug('connector_paused', {
9226
+ current_state: this._state,
9227
+ connector_id: this._connectorFlowId,
9228
+ });
9229
+ }
9230
+ /**
9231
+ * Resume the connector from paused state
9232
+ */
9233
+ async resume() {
9234
+ logger$$.debug('resuming_connector', {
9235
+ current_state: this._state,
9236
+ connector_id: this._connectorFlowId,
9237
+ });
9238
+ if (this._state !== ConnectorState.PAUSED) {
9239
+ logger$$.debug('connector_resume_invalid_state', {
9240
+ current_state: this._state,
9241
+ connector_id: this._connectorFlowId,
9242
+ });
9243
+ return;
9244
+ }
9245
+ this._setState(ConnectorState.STARTED);
9246
+ logger$$.debug('connector_resumed', {
9247
+ current_state: this._state,
9248
+ connector_id: this._connectorFlowId,
9249
+ });
9200
9250
  }
9201
9251
  /**
9202
9252
  * Close the connector with optional code and reason
@@ -9527,8 +9577,21 @@ class BaseAsyncConnector extends TaskSpawner {
9527
9577
  */
9528
9578
  async _shutdown(code, reason, gracePeriod, exc) {
9529
9579
  if (this._closed) {
9580
+ logger$$.debug('shutdown_already_closed', {
9581
+ connector_id: this._connectorFlowId,
9582
+ current_state: this._state,
9583
+ });
9530
9584
  return;
9531
9585
  }
9586
+ logger$$.info('connector_shutdown_starting', {
9587
+ connector_id: this._connectorFlowId,
9588
+ connector_type: this.constructor.name,
9589
+ code,
9590
+ reason,
9591
+ current_state: this._state,
9592
+ has_error: !!exc,
9593
+ timestamp: new Date().toISOString(),
9594
+ });
9532
9595
  this._closed = true;
9533
9596
  this._closeCode = code;
9534
9597
  this._closeReason = reason;
@@ -9550,16 +9613,39 @@ class BaseAsyncConnector extends TaskSpawner {
9550
9613
  this._sendPromiseResolve = undefined;
9551
9614
  }
9552
9615
  // Close transport
9616
+ logger$$.info('connector_closing_transport', {
9617
+ connector_id: this._connectorFlowId,
9618
+ connector_type: this.constructor.name,
9619
+ timestamp: new Date().toISOString(),
9620
+ });
9553
9621
  await this._transportClose(code, reason);
9622
+ logger$$.info('connector_transport_closed', {
9623
+ connector_id: this._connectorFlowId,
9624
+ connector_type: this.constructor.name,
9625
+ timestamp: new Date().toISOString(),
9626
+ });
9554
9627
  // Shutdown spawned tasks
9628
+ logger$$.info('connector_shutting_down_tasks', {
9629
+ connector_id: this._connectorFlowId,
9630
+ connector_type: this.constructor.name,
9631
+ grace_period_ms: effectiveGracePeriod * 1000,
9632
+ join_timeout_ms: this._shutdownJoinTimeout,
9633
+ timestamp: new Date().toISOString(),
9634
+ });
9555
9635
  try {
9556
9636
  await this.shutdownTasks({
9557
9637
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
9558
9638
  joinTimeout: this._shutdownJoinTimeout,
9559
9639
  });
9640
+ logger$$.info('connector_tasks_shutdown_complete', {
9641
+ connector_id: this._connectorFlowId,
9642
+ connector_type: this.constructor.name,
9643
+ timestamp: new Date().toISOString(),
9644
+ });
9560
9645
  }
9561
9646
  catch (error) {
9562
9647
  logger$$.warning('task_shutdown_error', {
9648
+ connector_id: this._connectorFlowId,
9563
9649
  error: error instanceof Error ? error.message : String(error),
9564
9650
  });
9565
9651
  }
@@ -9571,6 +9657,12 @@ class BaseAsyncConnector extends TaskSpawner {
9571
9657
  if (this._closeResolver) {
9572
9658
  this._closeResolver();
9573
9659
  }
9660
+ logger$$.info('connector_shutdown_complete', {
9661
+ connector_id: this._connectorFlowId,
9662
+ connector_type: this.constructor.name,
9663
+ final_state: this._state,
9664
+ timestamp: new Date().toISOString(),
9665
+ });
9574
9666
  }
9575
9667
  /**
9576
9668
  * Close the underlying transport
@@ -9706,12 +9798,22 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9706
9798
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9707
9799
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9708
9800
  this.channel = new BroadcastChannel(this.channelName);
9709
- logger$_.debug('broadcast_channel_connector_initialized', {
9801
+ logger$_.info('broadcast_channel_connector_created', {
9710
9802
  channel: this.channelName,
9711
9803
  connector_id: this.connectorId,
9712
9804
  inbox_capacity: preferredCapacity,
9805
+ timestamp: new Date().toISOString(),
9713
9806
  });
9714
9807
  this.onMsg = (event) => {
9808
+ // Guard: Don't process if listener was unregistered
9809
+ if (!this.listenerRegistered) {
9810
+ logger$_.warning('broadcast_channel_message_after_unregister', {
9811
+ channel: this.channelName,
9812
+ connector_id: this.connectorId,
9813
+ timestamp: new Date().toISOString(),
9814
+ });
9815
+ return;
9816
+ }
9715
9817
  const message = event.data;
9716
9818
  logger$_.debug('broadcast_channel_raw_event', {
9717
9819
  channel: this.channelName,
@@ -9783,6 +9885,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9783
9885
  visibility: isHidden ? 'hidden' : 'visible',
9784
9886
  timestamp: new Date().toISOString(),
9785
9887
  });
9888
+ // Pause/resume connector based on visibility
9889
+ if (isHidden && this.state === ConnectorState.STARTED) {
9890
+ this.pause().catch((err) => {
9891
+ logger$_.warning('broadcast_channel_pause_failed', {
9892
+ channel: this.channelName,
9893
+ connector_id: this.connectorId,
9894
+ error: err instanceof Error ? err.message : String(err),
9895
+ });
9896
+ });
9897
+ }
9898
+ else if (!isHidden && this.state === ConnectorState.PAUSED) {
9899
+ this.resume().catch((err) => {
9900
+ logger$_.warning('broadcast_channel_resume_failed', {
9901
+ channel: this.channelName,
9902
+ connector_id: this.connectorId,
9903
+ error: err instanceof Error ? err.message : String(err),
9904
+ });
9905
+ });
9906
+ }
9786
9907
  };
9787
9908
  if (typeof document !== 'undefined') {
9788
9909
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -9838,16 +9959,44 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9838
9959
  return await this.inbox.dequeue();
9839
9960
  }
9840
9961
  async _transportClose(code, reason) {
9962
+ logger$_.info('broadcast_channel_transport_closing', {
9963
+ channel: this.channelName,
9964
+ connector_id: this.connectorId,
9965
+ code,
9966
+ reason,
9967
+ listener_registered: this.listenerRegistered,
9968
+ timestamp: new Date().toISOString(),
9969
+ });
9841
9970
  if (this.listenerRegistered) {
9971
+ logger$_.info('broadcast_channel_removing_listener', {
9972
+ channel: this.channelName,
9973
+ connector_id: this.connectorId,
9974
+ timestamp: new Date().toISOString(),
9975
+ });
9842
9976
  this.channel.removeEventListener('message', this.onMsg);
9843
9977
  this.listenerRegistered = false;
9978
+ logger$_.info('broadcast_channel_listener_removed', {
9979
+ channel: this.channelName,
9980
+ connector_id: this.connectorId,
9981
+ timestamp: new Date().toISOString(),
9982
+ });
9844
9983
  }
9845
9984
  if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
9846
9985
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
9847
9986
  this.visibilityChangeListenerRegistered = false;
9848
9987
  this.visibilityChangeHandler = undefined;
9849
9988
  }
9989
+ logger$_.info('broadcast_channel_closing', {
9990
+ channel: this.channelName,
9991
+ connector_id: this.connectorId,
9992
+ timestamp: new Date().toISOString(),
9993
+ });
9850
9994
  this.channel.close();
9995
+ logger$_.info('broadcast_channel_closed', {
9996
+ channel: this.channelName,
9997
+ connector_id: this.connectorId,
9998
+ timestamp: new Date().toISOString(),
9999
+ });
9851
10000
  const closeCode = typeof code === 'number' ? code : 1000;
9852
10001
  const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
9853
10002
  const shutdownError = new FameTransportClose(closeReason, closeCode);
@@ -10495,7 +10644,22 @@ class UpstreamSessionManager extends TaskSpawner {
10495
10644
  this.currentStopSubtasks = null;
10496
10645
  await Promise.allSettled(tasks.map((task) => task.promise));
10497
10646
  if (this.connector) {
10498
- await this.connector.stop().catch(() => undefined);
10647
+ logger$Z.info('upstream_stopping_old_connector', {
10648
+ connect_epoch: this.connectEpoch,
10649
+ target_system_id: this.targetSystemId,
10650
+ timestamp: new Date().toISOString(),
10651
+ });
10652
+ await this.connector.stop().catch((err) => {
10653
+ logger$Z.warning('upstream_connector_stop_error', {
10654
+ connect_epoch: this.connectEpoch,
10655
+ error: err instanceof Error ? err.message : String(err),
10656
+ });
10657
+ });
10658
+ logger$Z.info('upstream_old_connector_stopped', {
10659
+ connect_epoch: this.connectEpoch,
10660
+ target_system_id: this.targetSystemId,
10661
+ timestamp: new Date().toISOString(),
10662
+ });
10499
10663
  this.connector = null;
10500
10664
  }
10501
10665
  }
@@ -10629,6 +10793,15 @@ class UpstreamSessionManager extends TaskSpawner {
10629
10793
  if (stopEvt.isSet() || signal?.aborted) {
10630
10794
  break;
10631
10795
  }
10796
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
10797
+ // Keep ack time current so we don't timeout immediately after resuming
10798
+ if (connector.state === ConnectorState.PAUSED) {
10799
+ logger$Z.debug('skipping_heartbeat_connector_paused', {
10800
+ connector_state: connector.state,
10801
+ });
10802
+ this.lastHeartbeatAckTime = Date.now();
10803
+ continue;
10804
+ }
10632
10805
  const envelope = await this.makeHeartbeatEnvelope();
10633
10806
  logger$Z.debug('sending_heartbeat', {
10634
10807
  hb_corr_id: envelope.corrId,
@@ -10650,6 +10823,7 @@ class UpstreamSessionManager extends TaskSpawner {
10650
10823
  throw error;
10651
10824
  }
10652
10825
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10826
+ // Don't check heartbeat timeout when paused
10653
10827
  if (this.lastHeartbeatAckTime !== null &&
10654
10828
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10655
10829
  throw new FameConnectError('missed heartbeat acknowledgement');