@naylence/runtime 0.3.5-test.941 → 0.3.5-test.943
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 +390 -8
- package/dist/browser/index.mjs +390 -8
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
- package/dist/cjs/naylence/fame/connector/inpage-connector-factory.js +12 -0
- package/dist/cjs/naylence/fame/connector/inpage-connector.js +159 -1
- package/dist/cjs/naylence/fame/connector/transport-frame.js +101 -0
- package/dist/cjs/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
- package/dist/cjs/naylence/fame/grants/inpage-connection-grant.js +28 -0
- package/dist/cjs/naylence/fame/node/upstream-session-manager.js +2 -2
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -0
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +69 -1
- package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +12 -0
- package/dist/esm/naylence/fame/connector/inpage-connector.js +159 -1
- package/dist/esm/naylence/fame/connector/transport-frame.js +94 -0
- package/dist/esm/naylence/fame/grants/broadcast-channel-connection-grant.js +28 -0
- package/dist/esm/naylence/fame/grants/inpage-connection-grant.js +28 -0
- package/dist/esm/naylence/fame/node/upstream-session-manager.js +2 -2
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +390 -8
- package/dist/node/index.mjs +390 -8
- package/dist/node/node.cjs +406 -8
- package/dist/node/node.mjs +406 -8
- package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +2 -0
- package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +4 -0
- package/dist/types/naylence/fame/connector/inpage-connector-factory.d.ts +2 -0
- package/dist/types/naylence/fame/connector/inpage-connector.d.ts +11 -1
- package/dist/types/naylence/fame/connector/transport-frame.d.ts +58 -0
- package/dist/types/naylence/fame/grants/broadcast-channel-connection-grant.d.ts +6 -0
- package/dist/types/naylence/fame/grants/inpage-connection-grant.d.ts +8 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/node/index.mjs
CHANGED
|
@@ -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.
|
|
16
|
+
// Generated from package.json version: 0.3.5-test.943
|
|
17
17
|
/**
|
|
18
18
|
* The package version, injected at build time.
|
|
19
19
|
* @internal
|
|
20
20
|
*/
|
|
21
|
-
const VERSION = '0.3.5-test.
|
|
21
|
+
const VERSION = '0.3.5-test.943';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -9733,6 +9733,85 @@ class BoundedAsyncQueue {
|
|
|
9733
9733
|
}
|
|
9734
9734
|
}
|
|
9735
9735
|
|
|
9736
|
+
/**
|
|
9737
|
+
* Transport frame layer for multiplexing logical links on physical channels.
|
|
9738
|
+
*
|
|
9739
|
+
* This lightweight framing layer wraps raw FAME payloads to enable multiple
|
|
9740
|
+
* logical connections over a single physical channel (BroadcastChannel or InPage bus).
|
|
9741
|
+
*
|
|
9742
|
+
* The transport frame does NOT modify FAME envelopes - it only wraps the raw
|
|
9743
|
+
* Uint8Array payload at the connector level.
|
|
9744
|
+
*/
|
|
9745
|
+
/**
|
|
9746
|
+
* Transport frame version for future compatibility
|
|
9747
|
+
*/
|
|
9748
|
+
const TRANSPORT_FRAME_VERSION = 1;
|
|
9749
|
+
/**
|
|
9750
|
+
* Wrap a raw payload in a transport frame
|
|
9751
|
+
*
|
|
9752
|
+
* @param payload - Raw FAME envelope bytes
|
|
9753
|
+
* @param srcNodeId - Local node ID (this connector)
|
|
9754
|
+
* @param dstNodeId - Remote node ID (target connector)
|
|
9755
|
+
* @returns Transport frame ready for transmission
|
|
9756
|
+
*/
|
|
9757
|
+
function wrapTransportFrame(payload, srcNodeId, dstNodeId) {
|
|
9758
|
+
return {
|
|
9759
|
+
v: TRANSPORT_FRAME_VERSION,
|
|
9760
|
+
src: srcNodeId,
|
|
9761
|
+
dst: dstNodeId,
|
|
9762
|
+
payload,
|
|
9763
|
+
};
|
|
9764
|
+
}
|
|
9765
|
+
/**
|
|
9766
|
+
* Serialize a transport frame for transmission over the bus
|
|
9767
|
+
*
|
|
9768
|
+
* @param frame - Transport frame to serialize
|
|
9769
|
+
* @returns Serialized frame data ready for postMessage/dispatchEvent
|
|
9770
|
+
*/
|
|
9771
|
+
function serializeTransportFrame(frame) {
|
|
9772
|
+
// Convert Uint8Array to regular array for JSON serialization
|
|
9773
|
+
const serializable = {
|
|
9774
|
+
v: frame.v,
|
|
9775
|
+
src: frame.src,
|
|
9776
|
+
dst: frame.dst,
|
|
9777
|
+
payload: Array.from(frame.payload),
|
|
9778
|
+
};
|
|
9779
|
+
return serializable;
|
|
9780
|
+
}
|
|
9781
|
+
/**
|
|
9782
|
+
* Unwrap a transport frame, validating source and destination
|
|
9783
|
+
*
|
|
9784
|
+
* @param raw - Raw data from the bus
|
|
9785
|
+
* @param localNodeId - This connector's node ID
|
|
9786
|
+
* @param remoteNodeId - Expected remote node ID
|
|
9787
|
+
* @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
|
|
9788
|
+
*/
|
|
9789
|
+
function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
|
|
9790
|
+
// Validate basic structure
|
|
9791
|
+
if (!raw || typeof raw !== 'object') {
|
|
9792
|
+
return null;
|
|
9793
|
+
}
|
|
9794
|
+
const frame = raw;
|
|
9795
|
+
// Check version
|
|
9796
|
+
if (frame.v !== TRANSPORT_FRAME_VERSION) {
|
|
9797
|
+
return null;
|
|
9798
|
+
}
|
|
9799
|
+
// Check src and dst
|
|
9800
|
+
if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
|
|
9801
|
+
return null;
|
|
9802
|
+
}
|
|
9803
|
+
// Only accept frames addressed to us from the expected remote
|
|
9804
|
+
if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
|
|
9805
|
+
return null;
|
|
9806
|
+
}
|
|
9807
|
+
// Extract payload
|
|
9808
|
+
if (!frame.payload || !Array.isArray(frame.payload)) {
|
|
9809
|
+
return null;
|
|
9810
|
+
}
|
|
9811
|
+
// Convert array back to Uint8Array
|
|
9812
|
+
return Uint8Array.from(frame.payload);
|
|
9813
|
+
}
|
|
9814
|
+
|
|
9736
9815
|
const logger$_ = getLogger('naylence.fame.connector.broadcast_channel_connector');
|
|
9737
9816
|
const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
|
|
9738
9817
|
const DEFAULT_CHANNEL$7 = 'naylence-fabric';
|
|
@@ -9798,9 +9877,20 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9798
9877
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
9799
9878
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
9800
9879
|
this.channel = new BroadcastChannel(this.channelName);
|
|
9880
|
+
// Set local and remote node IDs (defaults to connector ID for backwards compatibility)
|
|
9881
|
+
this.localNodeId =
|
|
9882
|
+
typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
|
|
9883
|
+
? config.localNodeId.trim()
|
|
9884
|
+
: this.connectorId;
|
|
9885
|
+
this.remoteNodeId =
|
|
9886
|
+
typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
|
|
9887
|
+
? config.remoteNodeId.trim()
|
|
9888
|
+
: '*'; // Accept from any remote if not specified
|
|
9801
9889
|
logger$_.debug('broadcast_channel_connector_created', {
|
|
9802
9890
|
channel: this.channelName,
|
|
9803
9891
|
connector_id: this.connectorId,
|
|
9892
|
+
local_node_id: this.localNodeId,
|
|
9893
|
+
remote_node_id: this.remoteNodeId,
|
|
9804
9894
|
inbox_capacity: preferredCapacity,
|
|
9805
9895
|
timestamp: new Date().toISOString(),
|
|
9806
9896
|
});
|
|
@@ -9833,6 +9923,46 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9833
9923
|
if (busMessage.senderId === this.connectorId) {
|
|
9834
9924
|
return;
|
|
9835
9925
|
}
|
|
9926
|
+
// Try to unwrap as transport frame
|
|
9927
|
+
const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
|
|
9928
|
+
if (unwrapped) {
|
|
9929
|
+
// Successfully unwrapped transport frame
|
|
9930
|
+
logger$_.debug('broadcast_channel_transport_frame_received', {
|
|
9931
|
+
channel: this.channelName,
|
|
9932
|
+
sender_id: busMessage.senderId,
|
|
9933
|
+
connector_id: this.connectorId,
|
|
9934
|
+
local_node_id: this.localNodeId,
|
|
9935
|
+
remote_node_id: this.remoteNodeId,
|
|
9936
|
+
payload_length: unwrapped.byteLength,
|
|
9937
|
+
});
|
|
9938
|
+
if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
|
|
9939
|
+
return;
|
|
9940
|
+
}
|
|
9941
|
+
try {
|
|
9942
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
9943
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
9944
|
+
if (accepted) {
|
|
9945
|
+
return;
|
|
9946
|
+
}
|
|
9947
|
+
}
|
|
9948
|
+
this.inbox.enqueue(unwrapped);
|
|
9949
|
+
}
|
|
9950
|
+
catch (error) {
|
|
9951
|
+
if (error instanceof QueueFullError) {
|
|
9952
|
+
logger$_.warning('broadcast_channel_receive_queue_full', {
|
|
9953
|
+
channel: this.channelName,
|
|
9954
|
+
});
|
|
9955
|
+
}
|
|
9956
|
+
else {
|
|
9957
|
+
logger$_.error('broadcast_channel_receive_error', {
|
|
9958
|
+
channel: this.channelName,
|
|
9959
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9960
|
+
});
|
|
9961
|
+
}
|
|
9962
|
+
}
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
// Fall back to legacy format (no transport frame)
|
|
9836
9966
|
const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
|
|
9837
9967
|
if (!payload) {
|
|
9838
9968
|
logger$_.debug('broadcast_channel_payload_rejected', {
|
|
@@ -9971,10 +10101,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9971
10101
|
logger$_.debug('broadcast_channel_message_sending', {
|
|
9972
10102
|
channel: this.channelName,
|
|
9973
10103
|
sender_id: this.connectorId,
|
|
9974
|
-
|
|
10104
|
+
local_node_id: this.localNodeId,
|
|
10105
|
+
remote_node_id: this.remoteNodeId,
|
|
10106
|
+
});
|
|
10107
|
+
// Only use transport framing if both localNodeId and remoteNodeId are explicitly set
|
|
10108
|
+
// (not using default values). This ensures backwards compatibility.
|
|
10109
|
+
const useTransportFrame = this.localNodeId !== this.connectorId ||
|
|
10110
|
+
this.remoteNodeId !== '*';
|
|
10111
|
+
let payload;
|
|
10112
|
+
if (useTransportFrame) {
|
|
10113
|
+
// Wrap payload in transport frame
|
|
10114
|
+
const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
|
|
10115
|
+
payload = serializeTransportFrame(frame);
|
|
10116
|
+
}
|
|
10117
|
+
else {
|
|
10118
|
+
// Legacy format: send raw payload
|
|
10119
|
+
payload = data;
|
|
10120
|
+
}
|
|
9975
10121
|
this.channel.postMessage({
|
|
9976
10122
|
senderId: this.connectorId,
|
|
9977
|
-
payload
|
|
10123
|
+
payload,
|
|
9978
10124
|
});
|
|
9979
10125
|
}
|
|
9980
10126
|
async _transportReceive() {
|
|
@@ -10267,6 +10413,14 @@ function isBroadcastChannelConnectionGrant(candidate) {
|
|
|
10267
10413
|
record.inboxCapacity <= 0)) {
|
|
10268
10414
|
return false;
|
|
10269
10415
|
}
|
|
10416
|
+
if (record.localNodeId !== undefined &&
|
|
10417
|
+
(typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
|
|
10418
|
+
return false;
|
|
10419
|
+
}
|
|
10420
|
+
if (record.remoteNodeId !== undefined &&
|
|
10421
|
+
(typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
|
|
10422
|
+
return false;
|
|
10423
|
+
}
|
|
10270
10424
|
return true;
|
|
10271
10425
|
}
|
|
10272
10426
|
function normalizeBroadcastChannelConnectionGrant(candidate) {
|
|
@@ -10300,6 +10454,20 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
|
|
|
10300
10454
|
}
|
|
10301
10455
|
result.inboxCapacity = Math.floor(inboxValue);
|
|
10302
10456
|
}
|
|
10457
|
+
const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
|
|
10458
|
+
if (localNodeIdValue !== undefined) {
|
|
10459
|
+
if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
|
|
10460
|
+
throw new TypeError('BroadcastChannelConnectionGrant "localNodeId" must be a non-empty string when provided');
|
|
10461
|
+
}
|
|
10462
|
+
result.localNodeId = localNodeIdValue.trim();
|
|
10463
|
+
}
|
|
10464
|
+
const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
10465
|
+
if (remoteNodeIdValue !== undefined) {
|
|
10466
|
+
if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
|
|
10467
|
+
throw new TypeError('BroadcastChannelConnectionGrant "remoteNodeId" must be a non-empty string when provided');
|
|
10468
|
+
}
|
|
10469
|
+
result.remoteNodeId = remoteNodeIdValue.trim();
|
|
10470
|
+
}
|
|
10303
10471
|
return result;
|
|
10304
10472
|
}
|
|
10305
10473
|
function broadcastChannelGrantToConnectorConfig(grant) {
|
|
@@ -10313,6 +10481,12 @@ function broadcastChannelGrantToConnectorConfig(grant) {
|
|
|
10313
10481
|
if (normalized.inboxCapacity !== undefined) {
|
|
10314
10482
|
config.inboxCapacity = normalized.inboxCapacity;
|
|
10315
10483
|
}
|
|
10484
|
+
if (normalized.localNodeId) {
|
|
10485
|
+
config.localNodeId = normalized.localNodeId;
|
|
10486
|
+
}
|
|
10487
|
+
if (normalized.remoteNodeId) {
|
|
10488
|
+
config.remoteNodeId = normalized.remoteNodeId;
|
|
10489
|
+
}
|
|
10316
10490
|
return config;
|
|
10317
10491
|
}
|
|
10318
10492
|
|
|
@@ -10692,7 +10866,7 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10692
10866
|
this.currentStopSubtasks = null;
|
|
10693
10867
|
await Promise.allSettled(tasks.map((task) => task.promise));
|
|
10694
10868
|
if (this.connector) {
|
|
10695
|
-
logger$Z.
|
|
10869
|
+
logger$Z.debug('upstream_stopping_old_connector', {
|
|
10696
10870
|
connect_epoch: this.connectEpoch,
|
|
10697
10871
|
target_system_id: this.targetSystemId,
|
|
10698
10872
|
timestamp: new Date().toISOString(),
|
|
@@ -10703,7 +10877,7 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10703
10877
|
error: err instanceof Error ? err.message : String(err),
|
|
10704
10878
|
});
|
|
10705
10879
|
});
|
|
10706
|
-
logger$Z.
|
|
10880
|
+
logger$Z.debug('upstream_old_connector_stopped', {
|
|
10707
10881
|
connect_epoch: this.connectEpoch,
|
|
10708
10882
|
target_system_id: this.targetSystemId,
|
|
10709
10883
|
timestamp: new Date().toISOString(),
|
|
@@ -20247,6 +20421,7 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20247
20421
|
ensureBrowserEnvironment$2();
|
|
20248
20422
|
super(baseConfig);
|
|
20249
20423
|
this.listenerRegistered = false;
|
|
20424
|
+
this.visibilityChangeListenerRegistered = false;
|
|
20250
20425
|
this.channelName =
|
|
20251
20426
|
typeof config.channelName === 'string' && config.channelName.trim().length > 0
|
|
20252
20427
|
? config.channelName.trim()
|
|
@@ -20258,9 +20433,20 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20258
20433
|
: DEFAULT_INBOX_CAPACITY$6;
|
|
20259
20434
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
20260
20435
|
this.connectorId = InPageConnector.generateConnectorId();
|
|
20436
|
+
// Set local and remote node IDs (defaults to connector ID for backwards compatibility)
|
|
20437
|
+
this.localNodeId =
|
|
20438
|
+
typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
|
|
20439
|
+
? config.localNodeId.trim()
|
|
20440
|
+
: this.connectorId;
|
|
20441
|
+
this.remoteNodeId =
|
|
20442
|
+
typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
|
|
20443
|
+
? config.remoteNodeId.trim()
|
|
20444
|
+
: '*'; // Accept from any remote if not specified
|
|
20261
20445
|
logger$G.debug('inpage_connector_initialized', {
|
|
20262
20446
|
channel: this.channelName,
|
|
20263
20447
|
connector_id: this.connectorId,
|
|
20448
|
+
local_node_id: this.localNodeId,
|
|
20449
|
+
remote_node_id: this.remoteNodeId,
|
|
20264
20450
|
});
|
|
20265
20451
|
this.onMsg = (event) => {
|
|
20266
20452
|
const messageEvent = event;
|
|
@@ -20294,6 +20480,43 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20294
20480
|
if (busMessage.senderId === this.connectorId) {
|
|
20295
20481
|
return;
|
|
20296
20482
|
}
|
|
20483
|
+
// Try to unwrap as transport frame
|
|
20484
|
+
const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
|
|
20485
|
+
if (unwrapped) {
|
|
20486
|
+
// Successfully unwrapped transport frame
|
|
20487
|
+
logger$G.debug('inpage_transport_frame_received', {
|
|
20488
|
+
channel: this.channelName,
|
|
20489
|
+
sender_id: busMessage.senderId,
|
|
20490
|
+
connector_id: this.connectorId,
|
|
20491
|
+
local_node_id: this.localNodeId,
|
|
20492
|
+
remote_node_id: this.remoteNodeId,
|
|
20493
|
+
payload_length: unwrapped.byteLength,
|
|
20494
|
+
});
|
|
20495
|
+
try {
|
|
20496
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
20497
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
20498
|
+
if (accepted) {
|
|
20499
|
+
return;
|
|
20500
|
+
}
|
|
20501
|
+
}
|
|
20502
|
+
this.inbox.enqueue(unwrapped);
|
|
20503
|
+
}
|
|
20504
|
+
catch (error) {
|
|
20505
|
+
if (error instanceof QueueFullError) {
|
|
20506
|
+
logger$G.warning('inpage_receive_queue_full', {
|
|
20507
|
+
channel: this.channelName,
|
|
20508
|
+
});
|
|
20509
|
+
}
|
|
20510
|
+
else {
|
|
20511
|
+
logger$G.error('inpage_receive_error', {
|
|
20512
|
+
channel: this.channelName,
|
|
20513
|
+
error: error instanceof Error ? error.message : String(error),
|
|
20514
|
+
});
|
|
20515
|
+
}
|
|
20516
|
+
}
|
|
20517
|
+
return;
|
|
20518
|
+
}
|
|
20519
|
+
// Fall back to legacy format (no transport frame)
|
|
20297
20520
|
const payload = InPageConnector.coercePayload(busMessage.payload);
|
|
20298
20521
|
if (!payload) {
|
|
20299
20522
|
logger$G.debug('inpage_payload_rejected', {
|
|
@@ -20334,6 +20557,92 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20334
20557
|
};
|
|
20335
20558
|
getSharedBus$1().addEventListener(this.channelName, this.onMsg);
|
|
20336
20559
|
this.listenerRegistered = true;
|
|
20560
|
+
// Setup visibility change monitoring
|
|
20561
|
+
this.visibilityChangeHandler = () => {
|
|
20562
|
+
const isHidden = document.hidden;
|
|
20563
|
+
logger$G.debug('inpage_visibility_changed', {
|
|
20564
|
+
channel: this.channelName,
|
|
20565
|
+
connector_id: this.connectorId,
|
|
20566
|
+
visibility: isHidden ? 'hidden' : 'visible',
|
|
20567
|
+
timestamp: new Date().toISOString(),
|
|
20568
|
+
});
|
|
20569
|
+
// Pause/resume connector based on visibility
|
|
20570
|
+
if (isHidden && this.state === ConnectorState.STARTED) {
|
|
20571
|
+
this.pause().catch((err) => {
|
|
20572
|
+
logger$G.warning('inpage_pause_failed', {
|
|
20573
|
+
channel: this.channelName,
|
|
20574
|
+
connector_id: this.connectorId,
|
|
20575
|
+
error: err instanceof Error ? err.message : String(err),
|
|
20576
|
+
});
|
|
20577
|
+
});
|
|
20578
|
+
}
|
|
20579
|
+
else if (!isHidden && this.state === ConnectorState.PAUSED) {
|
|
20580
|
+
this.resume().catch((err) => {
|
|
20581
|
+
logger$G.warning('inpage_resume_failed', {
|
|
20582
|
+
channel: this.channelName,
|
|
20583
|
+
connector_id: this.connectorId,
|
|
20584
|
+
error: err instanceof Error ? err.message : String(err),
|
|
20585
|
+
});
|
|
20586
|
+
});
|
|
20587
|
+
}
|
|
20588
|
+
};
|
|
20589
|
+
if (typeof document !== 'undefined') {
|
|
20590
|
+
document.addEventListener('visibilitychange', this.visibilityChangeHandler);
|
|
20591
|
+
this.visibilityChangeListenerRegistered = true;
|
|
20592
|
+
// Track page lifecycle events to detect browser unload/discard
|
|
20593
|
+
if (typeof window !== 'undefined') {
|
|
20594
|
+
const lifecycleLogger = (event) => {
|
|
20595
|
+
logger$G.info('inpage_page_lifecycle', {
|
|
20596
|
+
channel: this.channelName,
|
|
20597
|
+
connector_id: this.connectorId,
|
|
20598
|
+
event_type: event.type,
|
|
20599
|
+
visibility_state: document.visibilityState,
|
|
20600
|
+
timestamp: new Date().toISOString(),
|
|
20601
|
+
});
|
|
20602
|
+
};
|
|
20603
|
+
window.addEventListener('beforeunload', lifecycleLogger);
|
|
20604
|
+
window.addEventListener('unload', lifecycleLogger);
|
|
20605
|
+
window.addEventListener('pagehide', lifecycleLogger);
|
|
20606
|
+
window.addEventListener('pageshow', lifecycleLogger);
|
|
20607
|
+
document.addEventListener('freeze', lifecycleLogger);
|
|
20608
|
+
document.addEventListener('resume', lifecycleLogger);
|
|
20609
|
+
}
|
|
20610
|
+
// Log initial state with detailed visibility info
|
|
20611
|
+
logger$G.debug('inpage_initial_visibility', {
|
|
20612
|
+
channel: this.channelName,
|
|
20613
|
+
connector_id: this.connectorId,
|
|
20614
|
+
visibility: document.hidden ? 'hidden' : 'visible',
|
|
20615
|
+
document_hidden: document.hidden,
|
|
20616
|
+
visibility_state: document.visibilityState,
|
|
20617
|
+
has_focus: document.hasFocus(),
|
|
20618
|
+
timestamp: new Date().toISOString(),
|
|
20619
|
+
});
|
|
20620
|
+
}
|
|
20621
|
+
}
|
|
20622
|
+
/**
|
|
20623
|
+
* Override start() to check initial visibility state
|
|
20624
|
+
*/
|
|
20625
|
+
async start(inboundHandler) {
|
|
20626
|
+
await super.start(inboundHandler);
|
|
20627
|
+
// After transitioning to STARTED, check if tab is already hidden
|
|
20628
|
+
if (typeof document !== 'undefined' && document.hidden) {
|
|
20629
|
+
logger$G.debug('inpage_start_in_hidden_tab', {
|
|
20630
|
+
channel: this.channelName,
|
|
20631
|
+
connector_id: this.connectorId,
|
|
20632
|
+
document_hidden: document.hidden,
|
|
20633
|
+
visibility_state: document.visibilityState,
|
|
20634
|
+
has_focus: document.hasFocus(),
|
|
20635
|
+
timestamp: new Date().toISOString(),
|
|
20636
|
+
});
|
|
20637
|
+
// Immediately pause if tab is hidden at start time
|
|
20638
|
+
await this.pause().catch((err) => {
|
|
20639
|
+
logger$G.warning('inpage_initial_pause_failed', {
|
|
20640
|
+
channel: this.channelName,
|
|
20641
|
+
connector_id: this.connectorId,
|
|
20642
|
+
error: err instanceof Error ? err.message : String(err),
|
|
20643
|
+
});
|
|
20644
|
+
});
|
|
20645
|
+
}
|
|
20337
20646
|
}
|
|
20338
20647
|
// Allow listeners to feed envelopes directly into the in-page receive queue.
|
|
20339
20648
|
async pushToReceive(rawOrEnvelope) {
|
|
@@ -20366,11 +20675,27 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20366
20675
|
logger$G.debug('inpage_message_sending', {
|
|
20367
20676
|
channel: this.channelName,
|
|
20368
20677
|
sender_id: this.connectorId,
|
|
20369
|
-
|
|
20678
|
+
local_node_id: this.localNodeId,
|
|
20679
|
+
remote_node_id: this.remoteNodeId,
|
|
20680
|
+
});
|
|
20681
|
+
// Only use transport framing if both localNodeId and remoteNodeId are explicitly set
|
|
20682
|
+
// (not using default values). This ensures backwards compatibility.
|
|
20683
|
+
const useTransportFrame = this.localNodeId !== this.connectorId ||
|
|
20684
|
+
this.remoteNodeId !== '*';
|
|
20685
|
+
let payload;
|
|
20686
|
+
if (useTransportFrame) {
|
|
20687
|
+
// Wrap payload in transport frame
|
|
20688
|
+
const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
|
|
20689
|
+
payload = serializeTransportFrame(frame);
|
|
20690
|
+
}
|
|
20691
|
+
else {
|
|
20692
|
+
// Legacy format: send raw payload
|
|
20693
|
+
payload = data;
|
|
20694
|
+
}
|
|
20370
20695
|
const event = new MessageEvent(this.channelName, {
|
|
20371
20696
|
data: {
|
|
20372
20697
|
senderId: this.connectorId,
|
|
20373
|
-
payload
|
|
20698
|
+
payload,
|
|
20374
20699
|
},
|
|
20375
20700
|
});
|
|
20376
20701
|
getSharedBus$1().dispatchEvent(event);
|
|
@@ -20383,6 +20708,11 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20383
20708
|
getSharedBus$1().removeEventListener(this.channelName, this.onMsg);
|
|
20384
20709
|
this.listenerRegistered = false;
|
|
20385
20710
|
}
|
|
20711
|
+
if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
|
|
20712
|
+
document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
|
|
20713
|
+
this.visibilityChangeListenerRegistered = false;
|
|
20714
|
+
this.visibilityChangeHandler = undefined;
|
|
20715
|
+
}
|
|
20386
20716
|
const closeCode = typeof code === 'number' ? code : 1000;
|
|
20387
20717
|
const closeReason = typeof reason === 'string' && reason.length > 0 ? reason : 'closed';
|
|
20388
20718
|
const shutdownError = new FameTransportClose(closeReason, closeCode);
|
|
@@ -27730,6 +28060,14 @@ function isInPageConnectionGrant(candidate) {
|
|
|
27730
28060
|
record.inboxCapacity <= 0)) {
|
|
27731
28061
|
return false;
|
|
27732
28062
|
}
|
|
28063
|
+
if (record.localNodeId !== undefined &&
|
|
28064
|
+
(typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
|
|
28065
|
+
return false;
|
|
28066
|
+
}
|
|
28067
|
+
if (record.remoteNodeId !== undefined &&
|
|
28068
|
+
(typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
|
|
28069
|
+
return false;
|
|
28070
|
+
}
|
|
27733
28071
|
return true;
|
|
27734
28072
|
}
|
|
27735
28073
|
function normalizeInPageConnectionGrant(candidate) {
|
|
@@ -27763,6 +28101,20 @@ function normalizeInPageConnectionGrant(candidate) {
|
|
|
27763
28101
|
}
|
|
27764
28102
|
result.inboxCapacity = Math.floor(inboxValue);
|
|
27765
28103
|
}
|
|
28104
|
+
const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
|
|
28105
|
+
if (localNodeIdValue !== undefined) {
|
|
28106
|
+
if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
|
|
28107
|
+
throw new TypeError('InPageConnectionGrant "localNodeId" must be a non-empty string when provided');
|
|
28108
|
+
}
|
|
28109
|
+
result.localNodeId = localNodeIdValue.trim();
|
|
28110
|
+
}
|
|
28111
|
+
const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
28112
|
+
if (remoteNodeIdValue !== undefined) {
|
|
28113
|
+
if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
|
|
28114
|
+
throw new TypeError('InPageConnectionGrant "remoteNodeId" must be a non-empty string when provided');
|
|
28115
|
+
}
|
|
28116
|
+
result.remoteNodeId = remoteNodeIdValue.trim();
|
|
28117
|
+
}
|
|
27766
28118
|
return result;
|
|
27767
28119
|
}
|
|
27768
28120
|
function inPageGrantToConnectorConfig(grant) {
|
|
@@ -27776,6 +28128,12 @@ function inPageGrantToConnectorConfig(grant) {
|
|
|
27776
28128
|
if (normalized.inboxCapacity !== undefined) {
|
|
27777
28129
|
config.inboxCapacity = normalized.inboxCapacity;
|
|
27778
28130
|
}
|
|
28131
|
+
if (normalized.localNodeId) {
|
|
28132
|
+
config.localNodeId = normalized.localNodeId;
|
|
28133
|
+
}
|
|
28134
|
+
if (normalized.remoteNodeId) {
|
|
28135
|
+
config.remoteNodeId = normalized.remoteNodeId;
|
|
28136
|
+
}
|
|
27779
28137
|
return config;
|
|
27780
28138
|
}
|
|
27781
28139
|
|
|
@@ -28402,6 +28760,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
|
|
|
28402
28760
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
28403
28761
|
channelName,
|
|
28404
28762
|
inboxCapacity,
|
|
28763
|
+
localNodeId: normalized.localNodeId,
|
|
28764
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
28405
28765
|
};
|
|
28406
28766
|
const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
|
|
28407
28767
|
if (options.authorization) {
|
|
@@ -28463,6 +28823,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
|
|
|
28463
28823
|
if (candidate.authorizationContext !== undefined) {
|
|
28464
28824
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
28465
28825
|
}
|
|
28826
|
+
// Handle localNodeId
|
|
28827
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
28828
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
28829
|
+
normalized.localNodeId = localNodeId.trim();
|
|
28830
|
+
}
|
|
28831
|
+
// Handle remoteNodeId
|
|
28832
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
28833
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
28834
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
28835
|
+
}
|
|
28466
28836
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
|
|
28467
28837
|
normalized.inboxCapacity =
|
|
28468
28838
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
|
|
@@ -29026,6 +29396,8 @@ class InPageConnectorFactory extends ConnectorFactory {
|
|
|
29026
29396
|
type: INPAGE_CONNECTOR_TYPE,
|
|
29027
29397
|
channelName,
|
|
29028
29398
|
inboxCapacity,
|
|
29399
|
+
localNodeId: normalized.localNodeId,
|
|
29400
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
29029
29401
|
};
|
|
29030
29402
|
const connector = new InPageConnector(connectorConfig, baseConfig);
|
|
29031
29403
|
if (options.authorization) {
|
|
@@ -29094,6 +29466,16 @@ class InPageConnectorFactory extends ConnectorFactory {
|
|
|
29094
29466
|
if (candidate.authorizationContext !== undefined) {
|
|
29095
29467
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
29096
29468
|
}
|
|
29469
|
+
// Handle localNodeId
|
|
29470
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
29471
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
29472
|
+
normalized.localNodeId = localNodeId.trim();
|
|
29473
|
+
}
|
|
29474
|
+
// Handle remoteNodeId
|
|
29475
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
29476
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
29477
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
29478
|
+
}
|
|
29097
29479
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$3;
|
|
29098
29480
|
normalized.inboxCapacity =
|
|
29099
29481
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$3;
|