@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.
- package/dist/browser/index.cjs +109 -16
- package/dist/browser/index.mjs +109 -16
- package/dist/cjs/naylence/fame/connector/base-async-connector.js +48 -6
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +50 -8
- package/dist/cjs/naylence/fame/node/upstream-session-manager.js +10 -0
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/connector/base-async-connector.js +48 -6
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +50 -8
- package/dist/esm/naylence/fame/node/upstream-session-manager.js +11 -1
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +109 -16
- package/dist/node/index.mjs +109 -16
- package/dist/node/node.cjs +109 -16
- package/dist/node/node.mjs +109 -16
- package/dist/types/naylence/fame/connector/base-async-connector.d.ts +8 -0
- package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +5 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +2 -2
package/dist/browser/index.cjs
CHANGED
|
@@ -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.
|
|
101
|
+
// Generated from package.json version: 0.3.5-test.937
|
|
102
102
|
/**
|
|
103
103
|
* The package version, injected at build time.
|
|
104
104
|
* @internal
|
|
105
105
|
*/
|
|
106
|
-
const VERSION = '0.3.5-test.
|
|
106
|
+
const VERSION = '0.3.5-test.937';
|
|
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
|
*/
|
|
@@ -9626,7 +9668,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9626
9668
|
});
|
|
9627
9669
|
return;
|
|
9628
9670
|
}
|
|
9629
|
-
logger$$.
|
|
9671
|
+
logger$$.debug('connector_shutdown_starting', {
|
|
9630
9672
|
connector_id: this._connectorFlowId,
|
|
9631
9673
|
connector_type: this.constructor.name,
|
|
9632
9674
|
code,
|
|
@@ -9656,19 +9698,19 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9656
9698
|
this._sendPromiseResolve = undefined;
|
|
9657
9699
|
}
|
|
9658
9700
|
// Close transport
|
|
9659
|
-
logger$$.
|
|
9701
|
+
logger$$.debug('connector_closing_transport', {
|
|
9660
9702
|
connector_id: this._connectorFlowId,
|
|
9661
9703
|
connector_type: this.constructor.name,
|
|
9662
9704
|
timestamp: new Date().toISOString(),
|
|
9663
9705
|
});
|
|
9664
9706
|
await this._transportClose(code, reason);
|
|
9665
|
-
logger$$.
|
|
9707
|
+
logger$$.debug('connector_transport_closed', {
|
|
9666
9708
|
connector_id: this._connectorFlowId,
|
|
9667
9709
|
connector_type: this.constructor.name,
|
|
9668
9710
|
timestamp: new Date().toISOString(),
|
|
9669
9711
|
});
|
|
9670
9712
|
// Shutdown spawned tasks
|
|
9671
|
-
logger$$.
|
|
9713
|
+
logger$$.debug('connector_shutting_down_tasks', {
|
|
9672
9714
|
connector_id: this._connectorFlowId,
|
|
9673
9715
|
connector_type: this.constructor.name,
|
|
9674
9716
|
grace_period_ms: effectiveGracePeriod * 1000,
|
|
@@ -9680,7 +9722,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9680
9722
|
gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
|
|
9681
9723
|
joinTimeout: this._shutdownJoinTimeout,
|
|
9682
9724
|
});
|
|
9683
|
-
logger$$.
|
|
9725
|
+
logger$$.debug('connector_tasks_shutdown_complete', {
|
|
9684
9726
|
connector_id: this._connectorFlowId,
|
|
9685
9727
|
connector_type: this.constructor.name,
|
|
9686
9728
|
timestamp: new Date().toISOString(),
|
|
@@ -9700,7 +9742,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9700
9742
|
if (this._closeResolver) {
|
|
9701
9743
|
this._closeResolver();
|
|
9702
9744
|
}
|
|
9703
|
-
logger$$.
|
|
9745
|
+
logger$$.debug('connector_shutdown_complete', {
|
|
9704
9746
|
connector_id: this._connectorFlowId,
|
|
9705
9747
|
connector_type: this.constructor.name,
|
|
9706
9748
|
final_state: this._state,
|
|
@@ -9841,7 +9883,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9841
9883
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
9842
9884
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
9843
9885
|
this.channel = new BroadcastChannel(this.channelName);
|
|
9844
|
-
logger$_.
|
|
9886
|
+
logger$_.debug('broadcast_channel_connector_created', {
|
|
9845
9887
|
channel: this.channelName,
|
|
9846
9888
|
connector_id: this.connectorId,
|
|
9847
9889
|
inbox_capacity: preferredCapacity,
|
|
@@ -9922,18 +9964,37 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9922
9964
|
// Setup visibility change monitoring
|
|
9923
9965
|
this.visibilityChangeHandler = () => {
|
|
9924
9966
|
const isHidden = document.hidden;
|
|
9925
|
-
logger$_.
|
|
9967
|
+
logger$_.debug('broadcast_channel_visibility_changed', {
|
|
9926
9968
|
channel: this.channelName,
|
|
9927
9969
|
connector_id: this.connectorId,
|
|
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);
|
|
9934
9995
|
this.visibilityChangeListenerRegistered = true;
|
|
9935
9996
|
// Log initial state
|
|
9936
|
-
logger$_.
|
|
9997
|
+
logger$_.debug('broadcast_channel_initial_visibility', {
|
|
9937
9998
|
channel: this.channelName,
|
|
9938
9999
|
connector_id: this.connectorId,
|
|
9939
10000
|
visibility: document.hidden ? 'hidden' : 'visible',
|
|
@@ -9983,7 +10044,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9983
10044
|
return await this.inbox.dequeue();
|
|
9984
10045
|
}
|
|
9985
10046
|
async _transportClose(code, reason) {
|
|
9986
|
-
logger$_.
|
|
10047
|
+
logger$_.debug('broadcast_channel_transport_closing', {
|
|
9987
10048
|
channel: this.channelName,
|
|
9988
10049
|
connector_id: this.connectorId,
|
|
9989
10050
|
code,
|
|
@@ -9992,14 +10053,14 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9992
10053
|
timestamp: new Date().toISOString(),
|
|
9993
10054
|
});
|
|
9994
10055
|
if (this.listenerRegistered) {
|
|
9995
|
-
logger$_.
|
|
10056
|
+
logger$_.debug('broadcast_channel_removing_listener', {
|
|
9996
10057
|
channel: this.channelName,
|
|
9997
10058
|
connector_id: this.connectorId,
|
|
9998
10059
|
timestamp: new Date().toISOString(),
|
|
9999
10060
|
});
|
|
10000
10061
|
this.channel.removeEventListener('message', this.onMsg);
|
|
10001
10062
|
this.listenerRegistered = false;
|
|
10002
|
-
logger$_.
|
|
10063
|
+
logger$_.debug('broadcast_channel_listener_removed', {
|
|
10003
10064
|
channel: this.channelName,
|
|
10004
10065
|
connector_id: this.connectorId,
|
|
10005
10066
|
timestamp: new Date().toISOString(),
|
|
@@ -10010,13 +10071,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10010
10071
|
this.visibilityChangeListenerRegistered = false;
|
|
10011
10072
|
this.visibilityChangeHandler = undefined;
|
|
10012
10073
|
}
|
|
10013
|
-
logger$_.
|
|
10074
|
+
logger$_.debug('broadcast_channel_closing', {
|
|
10014
10075
|
channel: this.channelName,
|
|
10015
10076
|
connector_id: this.connectorId,
|
|
10016
10077
|
timestamp: new Date().toISOString(),
|
|
10017
10078
|
});
|
|
10018
10079
|
this.channel.close();
|
|
10019
|
-
logger$_.
|
|
10080
|
+
logger$_.debug('broadcast_channel_closed', {
|
|
10020
10081
|
channel: this.channelName,
|
|
10021
10082
|
connector_id: this.connectorId,
|
|
10022
10083
|
timestamp: new Date().toISOString(),
|
|
@@ -10107,6 +10168,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10107
10168
|
}
|
|
10108
10169
|
return undefined;
|
|
10109
10170
|
}
|
|
10171
|
+
/**
|
|
10172
|
+
* Override start() to check initial visibility state
|
|
10173
|
+
*/
|
|
10174
|
+
async start(inboundHandler) {
|
|
10175
|
+
await super.start(inboundHandler);
|
|
10176
|
+
// After transitioning to STARTED, check if tab is already hidden
|
|
10177
|
+
if (typeof document !== 'undefined' && document.hidden) {
|
|
10178
|
+
logger$_.debug('broadcast_channel_start_in_hidden_tab', {
|
|
10179
|
+
channel: this.channelName,
|
|
10180
|
+
connector_id: this.connectorId,
|
|
10181
|
+
timestamp: new Date().toISOString(),
|
|
10182
|
+
});
|
|
10183
|
+
// Immediately pause if tab is hidden at start time
|
|
10184
|
+
await this.pause().catch((err) => {
|
|
10185
|
+
logger$_.warning('broadcast_channel_initial_pause_failed', {
|
|
10186
|
+
channel: this.channelName,
|
|
10187
|
+
connector_id: this.connectorId,
|
|
10188
|
+
error: err instanceof Error ? err.message : String(err),
|
|
10189
|
+
});
|
|
10190
|
+
});
|
|
10191
|
+
}
|
|
10192
|
+
}
|
|
10110
10193
|
_trimSeenAcks(now) {
|
|
10111
10194
|
while (this.seenAckOrder.length > 0) {
|
|
10112
10195
|
const candidate = this.seenAckOrder[0];
|
|
@@ -10817,6 +10900,15 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10817
10900
|
if (stopEvt.isSet() || signal?.aborted) {
|
|
10818
10901
|
break;
|
|
10819
10902
|
}
|
|
10903
|
+
// Skip heartbeat if connector is paused (e.g., tab is hidden)
|
|
10904
|
+
// Keep ack time current so we don't timeout immediately after resuming
|
|
10905
|
+
if (connector.state === core.ConnectorState.PAUSED) {
|
|
10906
|
+
logger$Z.debug('skipping_heartbeat_connector_paused', {
|
|
10907
|
+
connector_state: connector.state,
|
|
10908
|
+
});
|
|
10909
|
+
this.lastHeartbeatAckTime = Date.now();
|
|
10910
|
+
continue;
|
|
10911
|
+
}
|
|
10820
10912
|
const envelope = await this.makeHeartbeatEnvelope();
|
|
10821
10913
|
logger$Z.debug('sending_heartbeat', {
|
|
10822
10914
|
hb_corr_id: envelope.corrId,
|
|
@@ -10838,6 +10930,7 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10838
10930
|
throw error;
|
|
10839
10931
|
}
|
|
10840
10932
|
await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
|
|
10933
|
+
// Don't check heartbeat timeout when paused
|
|
10841
10934
|
if (this.lastHeartbeatAckTime !== null &&
|
|
10842
10935
|
Date.now() - this.lastHeartbeatAckTime > graceMs) {
|
|
10843
10936
|
throw new FameConnectError('missed heartbeat acknowledgement');
|
package/dist/browser/index.mjs
CHANGED
|
@@ -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.
|
|
99
|
+
// Generated from package.json version: 0.3.5-test.937
|
|
100
100
|
/**
|
|
101
101
|
* The package version, injected at build time.
|
|
102
102
|
* @internal
|
|
103
103
|
*/
|
|
104
|
-
const VERSION = '0.3.5-test.
|
|
104
|
+
const VERSION = '0.3.5-test.937';
|
|
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
|
*/
|
|
@@ -9624,7 +9666,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9624
9666
|
});
|
|
9625
9667
|
return;
|
|
9626
9668
|
}
|
|
9627
|
-
logger$$.
|
|
9669
|
+
logger$$.debug('connector_shutdown_starting', {
|
|
9628
9670
|
connector_id: this._connectorFlowId,
|
|
9629
9671
|
connector_type: this.constructor.name,
|
|
9630
9672
|
code,
|
|
@@ -9654,19 +9696,19 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9654
9696
|
this._sendPromiseResolve = undefined;
|
|
9655
9697
|
}
|
|
9656
9698
|
// Close transport
|
|
9657
|
-
logger$$.
|
|
9699
|
+
logger$$.debug('connector_closing_transport', {
|
|
9658
9700
|
connector_id: this._connectorFlowId,
|
|
9659
9701
|
connector_type: this.constructor.name,
|
|
9660
9702
|
timestamp: new Date().toISOString(),
|
|
9661
9703
|
});
|
|
9662
9704
|
await this._transportClose(code, reason);
|
|
9663
|
-
logger$$.
|
|
9705
|
+
logger$$.debug('connector_transport_closed', {
|
|
9664
9706
|
connector_id: this._connectorFlowId,
|
|
9665
9707
|
connector_type: this.constructor.name,
|
|
9666
9708
|
timestamp: new Date().toISOString(),
|
|
9667
9709
|
});
|
|
9668
9710
|
// Shutdown spawned tasks
|
|
9669
|
-
logger$$.
|
|
9711
|
+
logger$$.debug('connector_shutting_down_tasks', {
|
|
9670
9712
|
connector_id: this._connectorFlowId,
|
|
9671
9713
|
connector_type: this.constructor.name,
|
|
9672
9714
|
grace_period_ms: effectiveGracePeriod * 1000,
|
|
@@ -9678,7 +9720,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9678
9720
|
gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
|
|
9679
9721
|
joinTimeout: this._shutdownJoinTimeout,
|
|
9680
9722
|
});
|
|
9681
|
-
logger$$.
|
|
9723
|
+
logger$$.debug('connector_tasks_shutdown_complete', {
|
|
9682
9724
|
connector_id: this._connectorFlowId,
|
|
9683
9725
|
connector_type: this.constructor.name,
|
|
9684
9726
|
timestamp: new Date().toISOString(),
|
|
@@ -9698,7 +9740,7 @@ class BaseAsyncConnector extends TaskSpawner {
|
|
|
9698
9740
|
if (this._closeResolver) {
|
|
9699
9741
|
this._closeResolver();
|
|
9700
9742
|
}
|
|
9701
|
-
logger$$.
|
|
9743
|
+
logger$$.debug('connector_shutdown_complete', {
|
|
9702
9744
|
connector_id: this._connectorFlowId,
|
|
9703
9745
|
connector_type: this.constructor.name,
|
|
9704
9746
|
final_state: this._state,
|
|
@@ -9839,7 +9881,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9839
9881
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
9840
9882
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
9841
9883
|
this.channel = new BroadcastChannel(this.channelName);
|
|
9842
|
-
logger$_.
|
|
9884
|
+
logger$_.debug('broadcast_channel_connector_created', {
|
|
9843
9885
|
channel: this.channelName,
|
|
9844
9886
|
connector_id: this.connectorId,
|
|
9845
9887
|
inbox_capacity: preferredCapacity,
|
|
@@ -9920,18 +9962,37 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9920
9962
|
// Setup visibility change monitoring
|
|
9921
9963
|
this.visibilityChangeHandler = () => {
|
|
9922
9964
|
const isHidden = document.hidden;
|
|
9923
|
-
logger$_.
|
|
9965
|
+
logger$_.debug('broadcast_channel_visibility_changed', {
|
|
9924
9966
|
channel: this.channelName,
|
|
9925
9967
|
connector_id: this.connectorId,
|
|
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);
|
|
9932
9993
|
this.visibilityChangeListenerRegistered = true;
|
|
9933
9994
|
// Log initial state
|
|
9934
|
-
logger$_.
|
|
9995
|
+
logger$_.debug('broadcast_channel_initial_visibility', {
|
|
9935
9996
|
channel: this.channelName,
|
|
9936
9997
|
connector_id: this.connectorId,
|
|
9937
9998
|
visibility: document.hidden ? 'hidden' : 'visible',
|
|
@@ -9981,7 +10042,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9981
10042
|
return await this.inbox.dequeue();
|
|
9982
10043
|
}
|
|
9983
10044
|
async _transportClose(code, reason) {
|
|
9984
|
-
logger$_.
|
|
10045
|
+
logger$_.debug('broadcast_channel_transport_closing', {
|
|
9985
10046
|
channel: this.channelName,
|
|
9986
10047
|
connector_id: this.connectorId,
|
|
9987
10048
|
code,
|
|
@@ -9990,14 +10051,14 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9990
10051
|
timestamp: new Date().toISOString(),
|
|
9991
10052
|
});
|
|
9992
10053
|
if (this.listenerRegistered) {
|
|
9993
|
-
logger$_.
|
|
10054
|
+
logger$_.debug('broadcast_channel_removing_listener', {
|
|
9994
10055
|
channel: this.channelName,
|
|
9995
10056
|
connector_id: this.connectorId,
|
|
9996
10057
|
timestamp: new Date().toISOString(),
|
|
9997
10058
|
});
|
|
9998
10059
|
this.channel.removeEventListener('message', this.onMsg);
|
|
9999
10060
|
this.listenerRegistered = false;
|
|
10000
|
-
logger$_.
|
|
10061
|
+
logger$_.debug('broadcast_channel_listener_removed', {
|
|
10001
10062
|
channel: this.channelName,
|
|
10002
10063
|
connector_id: this.connectorId,
|
|
10003
10064
|
timestamp: new Date().toISOString(),
|
|
@@ -10008,13 +10069,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10008
10069
|
this.visibilityChangeListenerRegistered = false;
|
|
10009
10070
|
this.visibilityChangeHandler = undefined;
|
|
10010
10071
|
}
|
|
10011
|
-
logger$_.
|
|
10072
|
+
logger$_.debug('broadcast_channel_closing', {
|
|
10012
10073
|
channel: this.channelName,
|
|
10013
10074
|
connector_id: this.connectorId,
|
|
10014
10075
|
timestamp: new Date().toISOString(),
|
|
10015
10076
|
});
|
|
10016
10077
|
this.channel.close();
|
|
10017
|
-
logger$_.
|
|
10078
|
+
logger$_.debug('broadcast_channel_closed', {
|
|
10018
10079
|
channel: this.channelName,
|
|
10019
10080
|
connector_id: this.connectorId,
|
|
10020
10081
|
timestamp: new Date().toISOString(),
|
|
@@ -10105,6 +10166,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10105
10166
|
}
|
|
10106
10167
|
return undefined;
|
|
10107
10168
|
}
|
|
10169
|
+
/**
|
|
10170
|
+
* Override start() to check initial visibility state
|
|
10171
|
+
*/
|
|
10172
|
+
async start(inboundHandler) {
|
|
10173
|
+
await super.start(inboundHandler);
|
|
10174
|
+
// After transitioning to STARTED, check if tab is already hidden
|
|
10175
|
+
if (typeof document !== 'undefined' && document.hidden) {
|
|
10176
|
+
logger$_.debug('broadcast_channel_start_in_hidden_tab', {
|
|
10177
|
+
channel: this.channelName,
|
|
10178
|
+
connector_id: this.connectorId,
|
|
10179
|
+
timestamp: new Date().toISOString(),
|
|
10180
|
+
});
|
|
10181
|
+
// Immediately pause if tab is hidden at start time
|
|
10182
|
+
await this.pause().catch((err) => {
|
|
10183
|
+
logger$_.warning('broadcast_channel_initial_pause_failed', {
|
|
10184
|
+
channel: this.channelName,
|
|
10185
|
+
connector_id: this.connectorId,
|
|
10186
|
+
error: err instanceof Error ? err.message : String(err),
|
|
10187
|
+
});
|
|
10188
|
+
});
|
|
10189
|
+
}
|
|
10190
|
+
}
|
|
10108
10191
|
_trimSeenAcks(now) {
|
|
10109
10192
|
while (this.seenAckOrder.length > 0) {
|
|
10110
10193
|
const candidate = this.seenAckOrder[0];
|
|
@@ -10815,6 +10898,15 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10815
10898
|
if (stopEvt.isSet() || signal?.aborted) {
|
|
10816
10899
|
break;
|
|
10817
10900
|
}
|
|
10901
|
+
// Skip heartbeat if connector is paused (e.g., tab is hidden)
|
|
10902
|
+
// Keep ack time current so we don't timeout immediately after resuming
|
|
10903
|
+
if (connector.state === ConnectorState.PAUSED) {
|
|
10904
|
+
logger$Z.debug('skipping_heartbeat_connector_paused', {
|
|
10905
|
+
connector_state: connector.state,
|
|
10906
|
+
});
|
|
10907
|
+
this.lastHeartbeatAckTime = Date.now();
|
|
10908
|
+
continue;
|
|
10909
|
+
}
|
|
10818
10910
|
const envelope = await this.makeHeartbeatEnvelope();
|
|
10819
10911
|
logger$Z.debug('sending_heartbeat', {
|
|
10820
10912
|
hb_corr_id: envelope.corrId,
|
|
@@ -10836,6 +10928,7 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10836
10928
|
throw error;
|
|
10837
10929
|
}
|
|
10838
10930
|
await this.node.dispatchEvent('onHeartbeatSent', this.node, envelope);
|
|
10931
|
+
// Don't check heartbeat timeout when paused
|
|
10839
10932
|
if (this.lastHeartbeatAckTime !== null &&
|
|
10840
10933
|
Date.now() - this.lastHeartbeatAckTime > graceMs) {
|
|
10841
10934
|
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
|
*/
|
|
@@ -504,7 +546,7 @@ class BaseAsyncConnector extends task_spawner_js_1.TaskSpawner {
|
|
|
504
546
|
});
|
|
505
547
|
return;
|
|
506
548
|
}
|
|
507
|
-
logger.
|
|
549
|
+
logger.debug('connector_shutdown_starting', {
|
|
508
550
|
connector_id: this._connectorFlowId,
|
|
509
551
|
connector_type: this.constructor.name,
|
|
510
552
|
code,
|
|
@@ -534,19 +576,19 @@ class BaseAsyncConnector extends task_spawner_js_1.TaskSpawner {
|
|
|
534
576
|
this._sendPromiseResolve = undefined;
|
|
535
577
|
}
|
|
536
578
|
// Close transport
|
|
537
|
-
logger.
|
|
579
|
+
logger.debug('connector_closing_transport', {
|
|
538
580
|
connector_id: this._connectorFlowId,
|
|
539
581
|
connector_type: this.constructor.name,
|
|
540
582
|
timestamp: new Date().toISOString(),
|
|
541
583
|
});
|
|
542
584
|
await this._transportClose(code, reason);
|
|
543
|
-
logger.
|
|
585
|
+
logger.debug('connector_transport_closed', {
|
|
544
586
|
connector_id: this._connectorFlowId,
|
|
545
587
|
connector_type: this.constructor.name,
|
|
546
588
|
timestamp: new Date().toISOString(),
|
|
547
589
|
});
|
|
548
590
|
// Shutdown spawned tasks
|
|
549
|
-
logger.
|
|
591
|
+
logger.debug('connector_shutting_down_tasks', {
|
|
550
592
|
connector_id: this._connectorFlowId,
|
|
551
593
|
connector_type: this.constructor.name,
|
|
552
594
|
grace_period_ms: effectiveGracePeriod * 1000,
|
|
@@ -558,7 +600,7 @@ class BaseAsyncConnector extends task_spawner_js_1.TaskSpawner {
|
|
|
558
600
|
gracePeriod: effectiveGracePeriod * 1000, // Convert to milliseconds
|
|
559
601
|
joinTimeout: this._shutdownJoinTimeout,
|
|
560
602
|
});
|
|
561
|
-
logger.
|
|
603
|
+
logger.debug('connector_tasks_shutdown_complete', {
|
|
562
604
|
connector_id: this._connectorFlowId,
|
|
563
605
|
connector_type: this.constructor.name,
|
|
564
606
|
timestamp: new Date().toISOString(),
|
|
@@ -578,7 +620,7 @@ class BaseAsyncConnector extends task_spawner_js_1.TaskSpawner {
|
|
|
578
620
|
if (this._closeResolver) {
|
|
579
621
|
this._closeResolver();
|
|
580
622
|
}
|
|
581
|
-
logger.
|
|
623
|
+
logger.debug('connector_shutdown_complete', {
|
|
582
624
|
connector_id: this._connectorFlowId,
|
|
583
625
|
connector_type: this.constructor.name,
|
|
584
626
|
final_state: this._state,
|