@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.
@@ -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.933
101
+ // Generated from package.json version: 0.3.5-test.936
102
102
  /**
103
103
  * The package version, injected at build time.
104
104
  * @internal
105
105
  */
106
- const VERSION = '0.3.5-test.933';
106
+ const VERSION = '0.3.5-test.936';
107
107
 
108
108
  /**
109
109
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9270,6 +9270,10 @@ class BaseAsyncConnector extends TaskSpawner {
9270
9270
  * Stop the connector gracefully
9271
9271
  */
9272
9272
  async stop() {
9273
+ logger$$.debug('stopping_connector', {
9274
+ current_state: this._state,
9275
+ connector_id: this._connectorFlowId,
9276
+ });
9273
9277
  if (!core.ConnectorStateUtils.canStop(this._state)) {
9274
9278
  logger$$.debug('connector_stop_already_stopped', {
9275
9279
  current_state: this._state,
@@ -9282,6 +9286,52 @@ class BaseAsyncConnector extends TaskSpawner {
9282
9286
  if (this._lastError) {
9283
9287
  throw this._lastError;
9284
9288
  }
9289
+ logger$$.debug('connector_stopped', {
9290
+ current_state: this._state,
9291
+ connector_id: this._connectorFlowId,
9292
+ });
9293
+ }
9294
+ /**
9295
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
9296
+ */
9297
+ async pause() {
9298
+ logger$$.debug('pausing_connector', {
9299
+ current_state: this._state,
9300
+ connector_id: this._connectorFlowId,
9301
+ });
9302
+ if (this._state !== core.ConnectorState.STARTED) {
9303
+ logger$$.debug('connector_pause_invalid_state', {
9304
+ current_state: this._state,
9305
+ connector_id: this._connectorFlowId,
9306
+ });
9307
+ return;
9308
+ }
9309
+ this._setState(core.ConnectorState.PAUSED);
9310
+ logger$$.debug('connector_paused', {
9311
+ current_state: this._state,
9312
+ connector_id: this._connectorFlowId,
9313
+ });
9314
+ }
9315
+ /**
9316
+ * Resume the connector from paused state
9317
+ */
9318
+ async resume() {
9319
+ logger$$.debug('resuming_connector', {
9320
+ current_state: this._state,
9321
+ connector_id: this._connectorFlowId,
9322
+ });
9323
+ if (this._state !== core.ConnectorState.PAUSED) {
9324
+ logger$$.debug('connector_resume_invalid_state', {
9325
+ current_state: this._state,
9326
+ connector_id: this._connectorFlowId,
9327
+ });
9328
+ return;
9329
+ }
9330
+ this._setState(core.ConnectorState.STARTED);
9331
+ logger$$.debug('connector_resumed', {
9332
+ current_state: this._state,
9333
+ connector_id: this._connectorFlowId,
9334
+ });
9285
9335
  }
9286
9336
  /**
9287
9337
  * Close the connector with optional code and reason
@@ -9612,8 +9662,21 @@ class BaseAsyncConnector extends TaskSpawner {
9612
9662
  */
9613
9663
  async _shutdown(code, reason, gracePeriod, exc) {
9614
9664
  if (this._closed) {
9665
+ logger$$.debug('shutdown_already_closed', {
9666
+ connector_id: this._connectorFlowId,
9667
+ current_state: this._state,
9668
+ });
9615
9669
  return;
9616
9670
  }
9671
+ logger$$.info('connector_shutdown_starting', {
9672
+ connector_id: this._connectorFlowId,
9673
+ connector_type: this.constructor.name,
9674
+ code,
9675
+ reason,
9676
+ current_state: this._state,
9677
+ has_error: !!exc,
9678
+ timestamp: new Date().toISOString(),
9679
+ });
9617
9680
  this._closed = true;
9618
9681
  this._closeCode = code;
9619
9682
  this._closeReason = reason;
@@ -9635,16 +9698,39 @@ class BaseAsyncConnector extends TaskSpawner {
9635
9698
  this._sendPromiseResolve = undefined;
9636
9699
  }
9637
9700
  // Close transport
9701
+ logger$$.info('connector_closing_transport', {
9702
+ connector_id: this._connectorFlowId,
9703
+ connector_type: this.constructor.name,
9704
+ timestamp: new Date().toISOString(),
9705
+ });
9638
9706
  await this._transportClose(code, reason);
9707
+ logger$$.info('connector_transport_closed', {
9708
+ connector_id: this._connectorFlowId,
9709
+ connector_type: this.constructor.name,
9710
+ timestamp: new Date().toISOString(),
9711
+ });
9639
9712
  // Shutdown spawned tasks
9713
+ logger$$.info('connector_shutting_down_tasks', {
9714
+ connector_id: this._connectorFlowId,
9715
+ connector_type: this.constructor.name,
9716
+ grace_period_ms: effectiveGracePeriod * 1000,
9717
+ join_timeout_ms: this._shutdownJoinTimeout,
9718
+ timestamp: new Date().toISOString(),
9719
+ });
9640
9720
  try {
9641
9721
  await this.shutdownTasks({
9642
9722
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
9643
9723
  joinTimeout: this._shutdownJoinTimeout,
9644
9724
  });
9725
+ logger$$.info('connector_tasks_shutdown_complete', {
9726
+ connector_id: this._connectorFlowId,
9727
+ connector_type: this.constructor.name,
9728
+ timestamp: new Date().toISOString(),
9729
+ });
9645
9730
  }
9646
9731
  catch (error) {
9647
9732
  logger$$.warning('task_shutdown_error', {
9733
+ connector_id: this._connectorFlowId,
9648
9734
  error: error instanceof Error ? error.message : String(error),
9649
9735
  });
9650
9736
  }
@@ -9656,6 +9742,12 @@ class BaseAsyncConnector extends TaskSpawner {
9656
9742
  if (this._closeResolver) {
9657
9743
  this._closeResolver();
9658
9744
  }
9745
+ logger$$.info('connector_shutdown_complete', {
9746
+ connector_id: this._connectorFlowId,
9747
+ connector_type: this.constructor.name,
9748
+ final_state: this._state,
9749
+ timestamp: new Date().toISOString(),
9750
+ });
9659
9751
  }
9660
9752
  /**
9661
9753
  * Close the underlying transport
@@ -9791,12 +9883,22 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9791
9883
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9792
9884
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9793
9885
  this.channel = new BroadcastChannel(this.channelName);
9794
- logger$_.debug('broadcast_channel_connector_initialized', {
9886
+ logger$_.info('broadcast_channel_connector_created', {
9795
9887
  channel: this.channelName,
9796
9888
  connector_id: this.connectorId,
9797
9889
  inbox_capacity: preferredCapacity,
9890
+ timestamp: new Date().toISOString(),
9798
9891
  });
9799
9892
  this.onMsg = (event) => {
9893
+ // Guard: Don't process if listener was unregistered
9894
+ if (!this.listenerRegistered) {
9895
+ logger$_.warning('broadcast_channel_message_after_unregister', {
9896
+ channel: this.channelName,
9897
+ connector_id: this.connectorId,
9898
+ timestamp: new Date().toISOString(),
9899
+ });
9900
+ return;
9901
+ }
9800
9902
  const message = event.data;
9801
9903
  logger$_.debug('broadcast_channel_raw_event', {
9802
9904
  channel: this.channelName,
@@ -9868,6 +9970,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9868
9970
  visibility: isHidden ? 'hidden' : 'visible',
9869
9971
  timestamp: new Date().toISOString(),
9870
9972
  });
9973
+ // Pause/resume connector based on visibility
9974
+ if (isHidden && this.state === core.ConnectorState.STARTED) {
9975
+ this.pause().catch((err) => {
9976
+ logger$_.warning('broadcast_channel_pause_failed', {
9977
+ channel: this.channelName,
9978
+ connector_id: this.connectorId,
9979
+ error: err instanceof Error ? err.message : String(err),
9980
+ });
9981
+ });
9982
+ }
9983
+ else if (!isHidden && this.state === core.ConnectorState.PAUSED) {
9984
+ this.resume().catch((err) => {
9985
+ logger$_.warning('broadcast_channel_resume_failed', {
9986
+ channel: this.channelName,
9987
+ connector_id: this.connectorId,
9988
+ error: err instanceof Error ? err.message : String(err),
9989
+ });
9990
+ });
9991
+ }
9871
9992
  };
9872
9993
  if (typeof document !== 'undefined') {
9873
9994
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -9923,16 +10044,44 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9923
10044
  return await this.inbox.dequeue();
9924
10045
  }
9925
10046
  async _transportClose(code, reason) {
10047
+ logger$_.info('broadcast_channel_transport_closing', {
10048
+ channel: this.channelName,
10049
+ connector_id: this.connectorId,
10050
+ code,
10051
+ reason,
10052
+ listener_registered: this.listenerRegistered,
10053
+ timestamp: new Date().toISOString(),
10054
+ });
9926
10055
  if (this.listenerRegistered) {
10056
+ logger$_.info('broadcast_channel_removing_listener', {
10057
+ channel: this.channelName,
10058
+ connector_id: this.connectorId,
10059
+ timestamp: new Date().toISOString(),
10060
+ });
9927
10061
  this.channel.removeEventListener('message', this.onMsg);
9928
10062
  this.listenerRegistered = false;
10063
+ logger$_.info('broadcast_channel_listener_removed', {
10064
+ channel: this.channelName,
10065
+ connector_id: this.connectorId,
10066
+ timestamp: new Date().toISOString(),
10067
+ });
9929
10068
  }
9930
10069
  if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
9931
10070
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
9932
10071
  this.visibilityChangeListenerRegistered = false;
9933
10072
  this.visibilityChangeHandler = undefined;
9934
10073
  }
10074
+ logger$_.info('broadcast_channel_closing', {
10075
+ channel: this.channelName,
10076
+ connector_id: this.connectorId,
10077
+ timestamp: new Date().toISOString(),
10078
+ });
9935
10079
  this.channel.close();
10080
+ logger$_.info('broadcast_channel_closed', {
10081
+ channel: this.channelName,
10082
+ connector_id: this.connectorId,
10083
+ timestamp: new Date().toISOString(),
10084
+ });
9936
10085
  const closeCode = typeof code === 'number' ? code : 1000;
9937
10086
  const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
9938
10087
  const shutdownError = new FameTransportClose(closeReason, closeCode);
@@ -10580,7 +10729,22 @@ class UpstreamSessionManager extends TaskSpawner {
10580
10729
  this.currentStopSubtasks = null;
10581
10730
  await Promise.allSettled(tasks.map((task) => task.promise));
10582
10731
  if (this.connector) {
10583
- await this.connector.stop().catch(() => undefined);
10732
+ logger$Z.info('upstream_stopping_old_connector', {
10733
+ connect_epoch: this.connectEpoch,
10734
+ target_system_id: this.targetSystemId,
10735
+ timestamp: new Date().toISOString(),
10736
+ });
10737
+ await this.connector.stop().catch((err) => {
10738
+ logger$Z.warning('upstream_connector_stop_error', {
10739
+ connect_epoch: this.connectEpoch,
10740
+ error: err instanceof Error ? err.message : String(err),
10741
+ });
10742
+ });
10743
+ logger$Z.info('upstream_old_connector_stopped', {
10744
+ connect_epoch: this.connectEpoch,
10745
+ target_system_id: this.targetSystemId,
10746
+ timestamp: new Date().toISOString(),
10747
+ });
10584
10748
  this.connector = null;
10585
10749
  }
10586
10750
  }
@@ -10714,6 +10878,15 @@ class UpstreamSessionManager extends TaskSpawner {
10714
10878
  if (stopEvt.isSet() || signal?.aborted) {
10715
10879
  break;
10716
10880
  }
10881
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
10882
+ // Keep ack time current so we don't timeout immediately after resuming
10883
+ if (connector.state === core.ConnectorState.PAUSED) {
10884
+ logger$Z.debug('skipping_heartbeat_connector_paused', {
10885
+ connector_state: connector.state,
10886
+ });
10887
+ this.lastHeartbeatAckTime = Date.now();
10888
+ continue;
10889
+ }
10717
10890
  const envelope = await this.makeHeartbeatEnvelope();
10718
10891
  logger$Z.debug('sending_heartbeat', {
10719
10892
  hb_corr_id: envelope.corrId,
@@ -10735,6 +10908,7 @@ class UpstreamSessionManager extends TaskSpawner {
10735
10908
  throw error;
10736
10909
  }
10737
10910
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10911
+ // Don't check heartbeat timeout when paused
10738
10912
  if (this.lastHeartbeatAckTime !== null &&
10739
10913
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10740
10914
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -96,12 +96,12 @@ installProcessEnvShim();
96
96
  // --- END ENV SHIM ---
97
97
 
98
98
  // This file is auto-generated during build - do not edit manually
99
- // Generated from package.json version: 0.3.5-test.933
99
+ // Generated from package.json version: 0.3.5-test.936
100
100
  /**
101
101
  * The package version, injected at build time.
102
102
  * @internal
103
103
  */
104
- const VERSION = '0.3.5-test.933';
104
+ const VERSION = '0.3.5-test.936';
105
105
 
106
106
  /**
107
107
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9268,6 +9268,10 @@ class BaseAsyncConnector extends TaskSpawner {
9268
9268
  * Stop the connector gracefully
9269
9269
  */
9270
9270
  async stop() {
9271
+ logger$$.debug('stopping_connector', {
9272
+ current_state: this._state,
9273
+ connector_id: this._connectorFlowId,
9274
+ });
9271
9275
  if (!ConnectorStateUtils.canStop(this._state)) {
9272
9276
  logger$$.debug('connector_stop_already_stopped', {
9273
9277
  current_state: this._state,
@@ -9280,6 +9284,52 @@ class BaseAsyncConnector extends TaskSpawner {
9280
9284
  if (this._lastError) {
9281
9285
  throw this._lastError;
9282
9286
  }
9287
+ logger$$.debug('connector_stopped', {
9288
+ current_state: this._state,
9289
+ connector_id: this._connectorFlowId,
9290
+ });
9291
+ }
9292
+ /**
9293
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
9294
+ */
9295
+ async pause() {
9296
+ logger$$.debug('pausing_connector', {
9297
+ current_state: this._state,
9298
+ connector_id: this._connectorFlowId,
9299
+ });
9300
+ if (this._state !== ConnectorState.STARTED) {
9301
+ logger$$.debug('connector_pause_invalid_state', {
9302
+ current_state: this._state,
9303
+ connector_id: this._connectorFlowId,
9304
+ });
9305
+ return;
9306
+ }
9307
+ this._setState(ConnectorState.PAUSED);
9308
+ logger$$.debug('connector_paused', {
9309
+ current_state: this._state,
9310
+ connector_id: this._connectorFlowId,
9311
+ });
9312
+ }
9313
+ /**
9314
+ * Resume the connector from paused state
9315
+ */
9316
+ async resume() {
9317
+ logger$$.debug('resuming_connector', {
9318
+ current_state: this._state,
9319
+ connector_id: this._connectorFlowId,
9320
+ });
9321
+ if (this._state !== ConnectorState.PAUSED) {
9322
+ logger$$.debug('connector_resume_invalid_state', {
9323
+ current_state: this._state,
9324
+ connector_id: this._connectorFlowId,
9325
+ });
9326
+ return;
9327
+ }
9328
+ this._setState(ConnectorState.STARTED);
9329
+ logger$$.debug('connector_resumed', {
9330
+ current_state: this._state,
9331
+ connector_id: this._connectorFlowId,
9332
+ });
9283
9333
  }
9284
9334
  /**
9285
9335
  * Close the connector with optional code and reason
@@ -9610,8 +9660,21 @@ class BaseAsyncConnector extends TaskSpawner {
9610
9660
  */
9611
9661
  async _shutdown(code, reason, gracePeriod, exc) {
9612
9662
  if (this._closed) {
9663
+ logger$$.debug('shutdown_already_closed', {
9664
+ connector_id: this._connectorFlowId,
9665
+ current_state: this._state,
9666
+ });
9613
9667
  return;
9614
9668
  }
9669
+ logger$$.info('connector_shutdown_starting', {
9670
+ connector_id: this._connectorFlowId,
9671
+ connector_type: this.constructor.name,
9672
+ code,
9673
+ reason,
9674
+ current_state: this._state,
9675
+ has_error: !!exc,
9676
+ timestamp: new Date().toISOString(),
9677
+ });
9615
9678
  this._closed = true;
9616
9679
  this._closeCode = code;
9617
9680
  this._closeReason = reason;
@@ -9633,16 +9696,39 @@ class BaseAsyncConnector extends TaskSpawner {
9633
9696
  this._sendPromiseResolve = undefined;
9634
9697
  }
9635
9698
  // Close transport
9699
+ logger$$.info('connector_closing_transport', {
9700
+ connector_id: this._connectorFlowId,
9701
+ connector_type: this.constructor.name,
9702
+ timestamp: new Date().toISOString(),
9703
+ });
9636
9704
  await this._transportClose(code, reason);
9705
+ logger$$.info('connector_transport_closed', {
9706
+ connector_id: this._connectorFlowId,
9707
+ connector_type: this.constructor.name,
9708
+ timestamp: new Date().toISOString(),
9709
+ });
9637
9710
  // Shutdown spawned tasks
9711
+ logger$$.info('connector_shutting_down_tasks', {
9712
+ connector_id: this._connectorFlowId,
9713
+ connector_type: this.constructor.name,
9714
+ grace_period_ms: effectiveGracePeriod * 1000,
9715
+ join_timeout_ms: this._shutdownJoinTimeout,
9716
+ timestamp: new Date().toISOString(),
9717
+ });
9638
9718
  try {
9639
9719
  await this.shutdownTasks({
9640
9720
  gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
9641
9721
  joinTimeout: this._shutdownJoinTimeout,
9642
9722
  });
9723
+ logger$$.info('connector_tasks_shutdown_complete', {
9724
+ connector_id: this._connectorFlowId,
9725
+ connector_type: this.constructor.name,
9726
+ timestamp: new Date().toISOString(),
9727
+ });
9643
9728
  }
9644
9729
  catch (error) {
9645
9730
  logger$$.warning('task_shutdown_error', {
9731
+ connector_id: this._connectorFlowId,
9646
9732
  error: error instanceof Error ? error.message : String(error),
9647
9733
  });
9648
9734
  }
@@ -9654,6 +9740,12 @@ class BaseAsyncConnector extends TaskSpawner {
9654
9740
  if (this._closeResolver) {
9655
9741
  this._closeResolver();
9656
9742
  }
9743
+ logger$$.info('connector_shutdown_complete', {
9744
+ connector_id: this._connectorFlowId,
9745
+ connector_type: this.constructor.name,
9746
+ final_state: this._state,
9747
+ timestamp: new Date().toISOString(),
9748
+ });
9657
9749
  }
9658
9750
  /**
9659
9751
  * Close the underlying transport
@@ -9789,12 +9881,22 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9789
9881
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9790
9882
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9791
9883
  this.channel = new BroadcastChannel(this.channelName);
9792
- logger$_.debug('broadcast_channel_connector_initialized', {
9884
+ logger$_.info('broadcast_channel_connector_created', {
9793
9885
  channel: this.channelName,
9794
9886
  connector_id: this.connectorId,
9795
9887
  inbox_capacity: preferredCapacity,
9888
+ timestamp: new Date().toISOString(),
9796
9889
  });
9797
9890
  this.onMsg = (event) => {
9891
+ // Guard: Don't process if listener was unregistered
9892
+ if (!this.listenerRegistered) {
9893
+ logger$_.warning('broadcast_channel_message_after_unregister', {
9894
+ channel: this.channelName,
9895
+ connector_id: this.connectorId,
9896
+ timestamp: new Date().toISOString(),
9897
+ });
9898
+ return;
9899
+ }
9798
9900
  const message = event.data;
9799
9901
  logger$_.debug('broadcast_channel_raw_event', {
9800
9902
  channel: this.channelName,
@@ -9866,6 +9968,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9866
9968
  visibility: isHidden ? 'hidden' : 'visible',
9867
9969
  timestamp: new Date().toISOString(),
9868
9970
  });
9971
+ // Pause/resume connector based on visibility
9972
+ if (isHidden && this.state === ConnectorState.STARTED) {
9973
+ this.pause().catch((err) => {
9974
+ logger$_.warning('broadcast_channel_pause_failed', {
9975
+ channel: this.channelName,
9976
+ connector_id: this.connectorId,
9977
+ error: err instanceof Error ? err.message : String(err),
9978
+ });
9979
+ });
9980
+ }
9981
+ else if (!isHidden && this.state === ConnectorState.PAUSED) {
9982
+ this.resume().catch((err) => {
9983
+ logger$_.warning('broadcast_channel_resume_failed', {
9984
+ channel: this.channelName,
9985
+ connector_id: this.connectorId,
9986
+ error: err instanceof Error ? err.message : String(err),
9987
+ });
9988
+ });
9989
+ }
9869
9990
  };
9870
9991
  if (typeof document !== 'undefined') {
9871
9992
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -9921,16 +10042,44 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9921
10042
  return await this.inbox.dequeue();
9922
10043
  }
9923
10044
  async _transportClose(code, reason) {
10045
+ logger$_.info('broadcast_channel_transport_closing', {
10046
+ channel: this.channelName,
10047
+ connector_id: this.connectorId,
10048
+ code,
10049
+ reason,
10050
+ listener_registered: this.listenerRegistered,
10051
+ timestamp: new Date().toISOString(),
10052
+ });
9924
10053
  if (this.listenerRegistered) {
10054
+ logger$_.info('broadcast_channel_removing_listener', {
10055
+ channel: this.channelName,
10056
+ connector_id: this.connectorId,
10057
+ timestamp: new Date().toISOString(),
10058
+ });
9925
10059
  this.channel.removeEventListener('message', this.onMsg);
9926
10060
  this.listenerRegistered = false;
10061
+ logger$_.info('broadcast_channel_listener_removed', {
10062
+ channel: this.channelName,
10063
+ connector_id: this.connectorId,
10064
+ timestamp: new Date().toISOString(),
10065
+ });
9927
10066
  }
9928
10067
  if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
9929
10068
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
9930
10069
  this.visibilityChangeListenerRegistered = false;
9931
10070
  this.visibilityChangeHandler = undefined;
9932
10071
  }
10072
+ logger$_.info('broadcast_channel_closing', {
10073
+ channel: this.channelName,
10074
+ connector_id: this.connectorId,
10075
+ timestamp: new Date().toISOString(),
10076
+ });
9933
10077
  this.channel.close();
10078
+ logger$_.info('broadcast_channel_closed', {
10079
+ channel: this.channelName,
10080
+ connector_id: this.connectorId,
10081
+ timestamp: new Date().toISOString(),
10082
+ });
9934
10083
  const closeCode = typeof code === 'number' ? code : 1000;
9935
10084
  const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
9936
10085
  const shutdownError = new FameTransportClose(closeReason, closeCode);
@@ -10578,7 +10727,22 @@ class UpstreamSessionManager extends TaskSpawner {
10578
10727
  this.currentStopSubtasks = null;
10579
10728
  await Promise.allSettled(tasks.map((task) => task.promise));
10580
10729
  if (this.connector) {
10581
- await this.connector.stop().catch(() => undefined);
10730
+ logger$Z.info('upstream_stopping_old_connector', {
10731
+ connect_epoch: this.connectEpoch,
10732
+ target_system_id: this.targetSystemId,
10733
+ timestamp: new Date().toISOString(),
10734
+ });
10735
+ await this.connector.stop().catch((err) => {
10736
+ logger$Z.warning('upstream_connector_stop_error', {
10737
+ connect_epoch: this.connectEpoch,
10738
+ error: err instanceof Error ? err.message : String(err),
10739
+ });
10740
+ });
10741
+ logger$Z.info('upstream_old_connector_stopped', {
10742
+ connect_epoch: this.connectEpoch,
10743
+ target_system_id: this.targetSystemId,
10744
+ timestamp: new Date().toISOString(),
10745
+ });
10582
10746
  this.connector = null;
10583
10747
  }
10584
10748
  }
@@ -10712,6 +10876,15 @@ class UpstreamSessionManager extends TaskSpawner {
10712
10876
  if (stopEvt.isSet() || signal?.aborted) {
10713
10877
  break;
10714
10878
  }
10879
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
10880
+ // Keep ack time current so we don't timeout immediately after resuming
10881
+ if (connector.state === ConnectorState.PAUSED) {
10882
+ logger$Z.debug('skipping_heartbeat_connector_paused', {
10883
+ connector_state: connector.state,
10884
+ });
10885
+ this.lastHeartbeatAckTime = Date.now();
10886
+ continue;
10887
+ }
10715
10888
  const envelope = await this.makeHeartbeatEnvelope();
10716
10889
  logger$Z.debug('sending_heartbeat', {
10717
10890
  hb_corr_id: envelope.corrId,
@@ -10733,6 +10906,7 @@ class UpstreamSessionManager extends TaskSpawner {
10733
10906
  throw error;
10734
10907
  }
10735
10908
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10909
+ // Don't check heartbeat timeout when paused
10736
10910
  if (this.lastHeartbeatAckTime !== null &&
10737
10911
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10738
10912
  throw new FameConnectError('missed heartbeat acknowledgement');