@naylence/runtime 0.3.5-test.934 → 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.934
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.934';
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.
@@ -9291,6 +9291,48 @@ class BaseAsyncConnector extends TaskSpawner {
9291
9291
  connector_id: this._connectorFlowId,
9292
9292
  });
9293
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
+ });
9335
+ }
9294
9336
  /**
9295
9337
  * Close the connector with optional code and reason
9296
9338
  */
@@ -9928,6 +9970,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9928
9970
  visibility: isHidden ? 'hidden' : 'visible',
9929
9971
  timestamp: new Date().toISOString(),
9930
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
+ }
9931
9992
  };
9932
9993
  if (typeof document !== 'undefined') {
9933
9994
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -10817,6 +10878,15 @@ class UpstreamSessionManager extends TaskSpawner {
10817
10878
  if (stopEvt.isSet() || signal?.aborted) {
10818
10879
  break;
10819
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
+ }
10820
10890
  const envelope = await this.makeHeartbeatEnvelope();
10821
10891
  logger$Z.debug('sending_heartbeat', {
10822
10892
  hb_corr_id: envelope.corrId,
@@ -10838,6 +10908,7 @@ class UpstreamSessionManager extends TaskSpawner {
10838
10908
  throw error;
10839
10909
  }
10840
10910
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10911
+ // Don't check heartbeat timeout when paused
10841
10912
  if (this.lastHeartbeatAckTime !== null &&
10842
10913
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10843
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.934
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.934';
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.
@@ -9289,6 +9289,48 @@ class BaseAsyncConnector extends TaskSpawner {
9289
9289
  connector_id: this._connectorFlowId,
9290
9290
  });
9291
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
+ });
9333
+ }
9292
9334
  /**
9293
9335
  * Close the connector with optional code and reason
9294
9336
  */
@@ -9926,6 +9968,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9926
9968
  visibility: isHidden ? 'hidden' : 'visible',
9927
9969
  timestamp: new Date().toISOString(),
9928
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
+ }
9929
9990
  };
9930
9991
  if (typeof document !== 'undefined') {
9931
9992
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -10815,6 +10876,15 @@ class UpstreamSessionManager extends TaskSpawner {
10815
10876
  if (stopEvt.isSet() || signal?.aborted) {
10816
10877
  break;
10817
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
+ }
10818
10888
  const envelope = await this.makeHeartbeatEnvelope();
10819
10889
  logger$Z.debug('sending_heartbeat', {
10820
10890
  hb_corr_id: envelope.corrId,
@@ -10836,6 +10906,7 @@ class UpstreamSessionManager extends TaskSpawner {
10836
10906
  throw error;
10837
10907
  }
10838
10908
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10909
+ // Don't check heartbeat timeout when paused
10839
10910
  if (this.lastHeartbeatAckTime !== null &&
10840
10911
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10841
10912
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -169,6 +169,48 @@ class BaseAsyncConnector extends task_spawner_js_1.TaskSpawner {
169
169
  connector_id: this._connectorFlowId,
170
170
  });
171
171
  }
172
+ /**
173
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
174
+ */
175
+ async pause() {
176
+ logger.debug('pausing_connector', {
177
+ current_state: this._state,
178
+ connector_id: this._connectorFlowId,
179
+ });
180
+ if (this._state !== core_1.ConnectorState.STARTED) {
181
+ logger.debug('connector_pause_invalid_state', {
182
+ current_state: this._state,
183
+ connector_id: this._connectorFlowId,
184
+ });
185
+ return;
186
+ }
187
+ this._setState(core_1.ConnectorState.PAUSED);
188
+ logger.debug('connector_paused', {
189
+ current_state: this._state,
190
+ connector_id: this._connectorFlowId,
191
+ });
192
+ }
193
+ /**
194
+ * Resume the connector from paused state
195
+ */
196
+ async resume() {
197
+ logger.debug('resuming_connector', {
198
+ current_state: this._state,
199
+ connector_id: this._connectorFlowId,
200
+ });
201
+ if (this._state !== core_1.ConnectorState.PAUSED) {
202
+ logger.debug('connector_resume_invalid_state', {
203
+ current_state: this._state,
204
+ connector_id: this._connectorFlowId,
205
+ });
206
+ return;
207
+ }
208
+ this._setState(core_1.ConnectorState.STARTED);
209
+ logger.debug('connector_resumed', {
210
+ current_state: this._state,
211
+ connector_id: this._connectorFlowId,
212
+ });
213
+ }
172
214
  /**
173
215
  * Close the connector with optional code and reason
174
216
  */
@@ -5,6 +5,7 @@ const base_async_connector_js_1 = require("./base-async-connector.js");
5
5
  const errors_js_1 = require("../errors/errors.js");
6
6
  const logging_js_1 = require("../util/logging.js");
7
7
  const bounded_async_queue_js_1 = require("../util/bounded-async-queue.js");
8
+ const core_1 = require("@naylence/core");
8
9
  const logger = (0, logging_js_1.getLogger)('naylence.fame.connector.broadcast_channel_connector');
9
10
  exports.BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
10
11
  const DEFAULT_CHANNEL = 'naylence-fabric';
@@ -157,6 +158,25 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
157
158
  visibility: isHidden ? 'hidden' : 'visible',
158
159
  timestamp: new Date().toISOString(),
159
160
  });
161
+ // Pause/resume connector based on visibility
162
+ if (isHidden && this.state === core_1.ConnectorState.STARTED) {
163
+ this.pause().catch((err) => {
164
+ logger.warning('broadcast_channel_pause_failed', {
165
+ channel: this.channelName,
166
+ connector_id: this.connectorId,
167
+ error: err instanceof Error ? err.message : String(err),
168
+ });
169
+ });
170
+ }
171
+ else if (!isHidden && this.state === core_1.ConnectorState.PAUSED) {
172
+ this.resume().catch((err) => {
173
+ logger.warning('broadcast_channel_resume_failed', {
174
+ channel: this.channelName,
175
+ connector_id: this.connectorId,
176
+ error: err instanceof Error ? err.message : String(err),
177
+ });
178
+ });
179
+ }
160
180
  };
161
181
  if (typeof document !== 'undefined') {
162
182
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -536,6 +536,15 @@ class UpstreamSessionManager extends task_spawner_js_1.TaskSpawner {
536
536
  if (stopEvt.isSet() || signal?.aborted) {
537
537
  break;
538
538
  }
539
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
540
+ // Keep ack time current so we don't timeout immediately after resuming
541
+ if (connector.state === core_1.ConnectorState.PAUSED) {
542
+ logger.debug('skipping_heartbeat_connector_paused', {
543
+ connector_state: connector.state,
544
+ });
545
+ this.lastHeartbeatAckTime = Date.now();
546
+ continue;
547
+ }
539
548
  const envelope = await this.makeHeartbeatEnvelope();
540
549
  logger.debug('sending_heartbeat', {
541
550
  hb_corr_id: envelope.corrId,
@@ -557,6 +566,7 @@ class UpstreamSessionManager extends task_spawner_js_1.TaskSpawner {
557
566
  throw error;
558
567
  }
559
568
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
569
+ // Don't check heartbeat timeout when paused
560
570
  if (this.lastHeartbeatAckTime !== null &&
561
571
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
562
572
  throw new errors_js_1.FameConnectError('missed heartbeat acknowledgement');
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  // This file is auto-generated during build - do not edit manually
3
- // Generated from package.json version: 0.3.5-test.934
3
+ // Generated from package.json version: 0.3.5-test.936
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.VERSION = void 0;
6
6
  /**
7
7
  * The package version, injected at build time.
8
8
  * @internal
9
9
  */
10
- exports.VERSION = '0.3.5-test.934';
10
+ exports.VERSION = '0.3.5-test.936';
@@ -165,6 +165,48 @@ export class BaseAsyncConnector extends TaskSpawner {
165
165
  connector_id: this._connectorFlowId,
166
166
  });
167
167
  }
168
+ /**
169
+ * Pause the connector (suspends heartbeat and housekeeping, but keeps connection alive)
170
+ */
171
+ async pause() {
172
+ logger.debug('pausing_connector', {
173
+ current_state: this._state,
174
+ connector_id: this._connectorFlowId,
175
+ });
176
+ if (this._state !== ConnectorState.STARTED) {
177
+ logger.debug('connector_pause_invalid_state', {
178
+ current_state: this._state,
179
+ connector_id: this._connectorFlowId,
180
+ });
181
+ return;
182
+ }
183
+ this._setState(ConnectorState.PAUSED);
184
+ logger.debug('connector_paused', {
185
+ current_state: this._state,
186
+ connector_id: this._connectorFlowId,
187
+ });
188
+ }
189
+ /**
190
+ * Resume the connector from paused state
191
+ */
192
+ async resume() {
193
+ logger.debug('resuming_connector', {
194
+ current_state: this._state,
195
+ connector_id: this._connectorFlowId,
196
+ });
197
+ if (this._state !== ConnectorState.PAUSED) {
198
+ logger.debug('connector_resume_invalid_state', {
199
+ current_state: this._state,
200
+ connector_id: this._connectorFlowId,
201
+ });
202
+ return;
203
+ }
204
+ this._setState(ConnectorState.STARTED);
205
+ logger.debug('connector_resumed', {
206
+ current_state: this._state,
207
+ connector_id: this._connectorFlowId,
208
+ });
209
+ }
168
210
  /**
169
211
  * Close the connector with optional code and reason
170
212
  */
@@ -2,6 +2,7 @@ import { BaseAsyncConnector, } from './base-async-connector.js';
2
2
  import { FameTransportClose } from '../errors/errors.js';
3
3
  import { getLogger } from '../util/logging.js';
4
4
  import { BoundedAsyncQueue, QueueFullError, } from '../util/bounded-async-queue.js';
5
+ import { ConnectorState } from '@naylence/core';
5
6
  const logger = getLogger('naylence.fame.connector.broadcast_channel_connector');
6
7
  export const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
7
8
  const DEFAULT_CHANNEL = 'naylence-fabric';
@@ -154,6 +155,25 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
154
155
  visibility: isHidden ? 'hidden' : 'visible',
155
156
  timestamp: new Date().toISOString(),
156
157
  });
158
+ // Pause/resume connector based on visibility
159
+ if (isHidden && this.state === ConnectorState.STARTED) {
160
+ this.pause().catch((err) => {
161
+ logger.warning('broadcast_channel_pause_failed', {
162
+ channel: this.channelName,
163
+ connector_id: this.connectorId,
164
+ error: err instanceof Error ? err.message : String(err),
165
+ });
166
+ });
167
+ }
168
+ else if (!isHidden && this.state === ConnectorState.PAUSED) {
169
+ this.resume().catch((err) => {
170
+ logger.warning('broadcast_channel_resume_failed', {
171
+ channel: this.channelName,
172
+ connector_id: this.connectorId,
173
+ error: err instanceof Error ? err.message : String(err),
174
+ });
175
+ });
176
+ }
157
177
  };
158
178
  if (typeof document !== 'undefined') {
159
179
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -2,7 +2,7 @@ import { ConnectorFactory } from '../connector/connector-factory.js';
2
2
  import { TaskSpawner } from '../util/task-spawner.js';
3
3
  import { AsyncEvent } from '../util/async-event.js';
4
4
  import { getLogger } from '../util/logging.js';
5
- import { DeliveryOriginType, FameFabric, generateId, } from '@naylence/core';
5
+ import { ConnectorState, DeliveryOriginType, FameFabric, generateId, } from '@naylence/core';
6
6
  import { FameConnectError, FameMessageTooLarge, FameTransportClose, } from '../errors/errors.js';
7
7
  import { TaskCancelledError } from '../util/task-types.js';
8
8
  import { FameResponseType } from '@naylence/core';
@@ -533,6 +533,15 @@ export class UpstreamSessionManager extends TaskSpawner {
533
533
  if (stopEvt.isSet() || signal?.aborted) {
534
534
  break;
535
535
  }
536
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
537
+ // Keep ack time current so we don't timeout immediately after resuming
538
+ if (connector.state === ConnectorState.PAUSED) {
539
+ logger.debug('skipping_heartbeat_connector_paused', {
540
+ connector_state: connector.state,
541
+ });
542
+ this.lastHeartbeatAckTime = Date.now();
543
+ continue;
544
+ }
536
545
  const envelope = await this.makeHeartbeatEnvelope();
537
546
  logger.debug('sending_heartbeat', {
538
547
  hb_corr_id: envelope.corrId,
@@ -554,6 +563,7 @@ export class UpstreamSessionManager extends TaskSpawner {
554
563
  throw error;
555
564
  }
556
565
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
566
+ // Don't check heartbeat timeout when paused
557
567
  if (this.lastHeartbeatAckTime !== null &&
558
568
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
559
569
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -1,7 +1,7 @@
1
1
  // This file is auto-generated during build - do not edit manually
2
- // Generated from package.json version: 0.3.5-test.934
2
+ // Generated from package.json version: 0.3.5-test.936
3
3
  /**
4
4
  * The package version, injected at build time.
5
5
  * @internal
6
6
  */
7
- export const VERSION = '0.3.5-test.934';
7
+ export const VERSION = '0.3.5-test.936';
@@ -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.934
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.934';
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.
@@ -9207,6 +9207,48 @@ class BaseAsyncConnector extends TaskSpawner {
9207
9207
  connector_id: this._connectorFlowId,
9208
9208
  });
9209
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
+ });
9251
+ }
9210
9252
  /**
9211
9253
  * Close the connector with optional code and reason
9212
9254
  */
@@ -9844,6 +9886,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9844
9886
  visibility: isHidden ? 'hidden' : 'visible',
9845
9887
  timestamp: new Date().toISOString(),
9846
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
+ }
9847
9908
  };
9848
9909
  if (typeof document !== 'undefined') {
9849
9910
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -10733,6 +10794,15 @@ class UpstreamSessionManager extends TaskSpawner {
10733
10794
  if (stopEvt.isSet() || signal?.aborted) {
10734
10795
  break;
10735
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
+ }
10736
10806
  const envelope = await this.makeHeartbeatEnvelope();
10737
10807
  logger$Z.debug('sending_heartbeat', {
10738
10808
  hb_corr_id: envelope.corrId,
@@ -10754,6 +10824,7 @@ class UpstreamSessionManager extends TaskSpawner {
10754
10824
  throw error;
10755
10825
  }
10756
10826
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10827
+ // Don't check heartbeat timeout when paused
10757
10828
  if (this.lastHeartbeatAckTime !== null &&
10758
10829
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10759
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.934
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.934';
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.
@@ -9206,6 +9206,48 @@ class BaseAsyncConnector extends TaskSpawner {
9206
9206
  connector_id: this._connectorFlowId,
9207
9207
  });
9208
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
+ });
9250
+ }
9209
9251
  /**
9210
9252
  * Close the connector with optional code and reason
9211
9253
  */
@@ -9843,6 +9885,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9843
9885
  visibility: isHidden ? 'hidden' : 'visible',
9844
9886
  timestamp: new Date().toISOString(),
9845
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
+ }
9846
9907
  };
9847
9908
  if (typeof document !== 'undefined') {
9848
9909
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -10732,6 +10793,15 @@ class UpstreamSessionManager extends TaskSpawner {
10732
10793
  if (stopEvt.isSet() || signal?.aborted) {
10733
10794
  break;
10734
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
+ }
10735
10805
  const envelope = await this.makeHeartbeatEnvelope();
10736
10806
  logger$Z.debug('sending_heartbeat', {
10737
10807
  hb_corr_id: envelope.corrId,
@@ -10753,6 +10823,7 @@ class UpstreamSessionManager extends TaskSpawner {
10753
10823
  throw error;
10754
10824
  }
10755
10825
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
10826
+ // Don't check heartbeat timeout when paused
10756
10827
  if (this.lastHeartbeatAckTime !== null &&
10757
10828
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
10758
10829
  throw new FameConnectError('missed heartbeat acknowledgement');
@@ -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
  */
@@ -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.936
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.936';
5445
5487
 
5446
5488
  /**
5447
5489
  * Fame errors module - Fame protocol specific error classes
@@ -11581,6 +11623,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
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);
@@ -12425,6 +12486,15 @@ class UpstreamSessionManager extends TaskSpawner {
12425
12486
  if (stopEvt.isSet() || signal?.aborted) {
12426
12487
  break;
12427
12488
  }
12489
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
12490
+ // Keep ack time current so we don't timeout immediately after resuming
12491
+ if (connector.state === core.ConnectorState.PAUSED) {
12492
+ logger$$.debug('skipping_heartbeat_connector_paused', {
12493
+ connector_state: connector.state,
12494
+ });
12495
+ this.lastHeartbeatAckTime = Date.now();
12496
+ continue;
12497
+ }
12428
12498
  const envelope = await this.makeHeartbeatEnvelope();
12429
12499
  logger$$.debug('sending_heartbeat', {
12430
12500
  hb_corr_id: envelope.corrId,
@@ -12446,6 +12516,7 @@ class UpstreamSessionManager extends TaskSpawner {
12446
12516
  throw error;
12447
12517
  }
12448
12518
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
12519
+ // Don't check heartbeat timeout when paused
12449
12520
  if (this.lastHeartbeatAckTime !== null &&
12450
12521
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
12451
12522
  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
  */
@@ -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.936
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.936';
5444
5486
 
5445
5487
  /**
5446
5488
  * Fame errors module - Fame protocol specific error classes
@@ -11580,6 +11622,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
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);
@@ -12424,6 +12485,15 @@ class UpstreamSessionManager extends TaskSpawner {
12424
12485
  if (stopEvt.isSet() || signal?.aborted) {
12425
12486
  break;
12426
12487
  }
12488
+ // Skip heartbeat if connector is paused (e.g., tab is hidden)
12489
+ // Keep ack time current so we don't timeout immediately after resuming
12490
+ if (connector.state === ConnectorState.PAUSED) {
12491
+ logger$$.debug('skipping_heartbeat_connector_paused', {
12492
+ connector_state: connector.state,
12493
+ });
12494
+ this.lastHeartbeatAckTime = Date.now();
12495
+ continue;
12496
+ }
12427
12497
  const envelope = await this.makeHeartbeatEnvelope();
12428
12498
  logger$$.debug('sending_heartbeat', {
12429
12499
  hb_corr_id: envelope.corrId,
@@ -12445,6 +12515,7 @@ class UpstreamSessionManager extends TaskSpawner {
12445
12515
  throw error;
12446
12516
  }
12447
12517
  await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
12518
+ // Don't check heartbeat timeout when paused
12448
12519
  if (this.lastHeartbeatAckTime !== null &&
12449
12520
  Date.now() - this.lastHeartbeatAckTime > graceMs) {
12450
12521
  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
  */
@@ -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.936";
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.936",
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",