@naylence/runtime 0.3.5-test.942 → 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 +296 -6
- package/dist/browser/index.mjs +296 -6
- 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 +66 -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/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 +66 -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/version.js +2 -2
- package/dist/node/index.cjs +296 -6
- package/dist/node/index.mjs +296 -6
- package/dist/node/node.cjs +312 -6
- package/dist/node/node.mjs +312 -6
- 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 +4 -0
- 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/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.943
|
|
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.943';
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -9816,6 +9816,85 @@ class BoundedAsyncQueue {
|
|
|
9816
9816
|
}
|
|
9817
9817
|
}
|
|
9818
9818
|
|
|
9819
|
+
/**
|
|
9820
|
+
* Transport frame layer for multiplexing logical links on physical channels.
|
|
9821
|
+
*
|
|
9822
|
+
* This lightweight framing layer wraps raw FAME payloads to enable multiple
|
|
9823
|
+
* logical connections over a single physical channel (BroadcastChannel or InPage bus).
|
|
9824
|
+
*
|
|
9825
|
+
* The transport frame does NOT modify FAME envelopes - it only wraps the raw
|
|
9826
|
+
* Uint8Array payload at the connector level.
|
|
9827
|
+
*/
|
|
9828
|
+
/**
|
|
9829
|
+
* Transport frame version for future compatibility
|
|
9830
|
+
*/
|
|
9831
|
+
const TRANSPORT_FRAME_VERSION = 1;
|
|
9832
|
+
/**
|
|
9833
|
+
* Wrap a raw payload in a transport frame
|
|
9834
|
+
*
|
|
9835
|
+
* @param payload - Raw FAME envelope bytes
|
|
9836
|
+
* @param srcNodeId - Local node ID (this connector)
|
|
9837
|
+
* @param dstNodeId - Remote node ID (target connector)
|
|
9838
|
+
* @returns Transport frame ready for transmission
|
|
9839
|
+
*/
|
|
9840
|
+
function wrapTransportFrame(payload, srcNodeId, dstNodeId) {
|
|
9841
|
+
return {
|
|
9842
|
+
v: TRANSPORT_FRAME_VERSION,
|
|
9843
|
+
src: srcNodeId,
|
|
9844
|
+
dst: dstNodeId,
|
|
9845
|
+
payload,
|
|
9846
|
+
};
|
|
9847
|
+
}
|
|
9848
|
+
/**
|
|
9849
|
+
* Serialize a transport frame for transmission over the bus
|
|
9850
|
+
*
|
|
9851
|
+
* @param frame - Transport frame to serialize
|
|
9852
|
+
* @returns Serialized frame data ready for postMessage/dispatchEvent
|
|
9853
|
+
*/
|
|
9854
|
+
function serializeTransportFrame(frame) {
|
|
9855
|
+
// Convert Uint8Array to regular array for JSON serialization
|
|
9856
|
+
const serializable = {
|
|
9857
|
+
v: frame.v,
|
|
9858
|
+
src: frame.src,
|
|
9859
|
+
dst: frame.dst,
|
|
9860
|
+
payload: Array.from(frame.payload),
|
|
9861
|
+
};
|
|
9862
|
+
return serializable;
|
|
9863
|
+
}
|
|
9864
|
+
/**
|
|
9865
|
+
* Unwrap a transport frame, validating source and destination
|
|
9866
|
+
*
|
|
9867
|
+
* @param raw - Raw data from the bus
|
|
9868
|
+
* @param localNodeId - This connector's node ID
|
|
9869
|
+
* @param remoteNodeId - Expected remote node ID
|
|
9870
|
+
* @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
|
|
9871
|
+
*/
|
|
9872
|
+
function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
|
|
9873
|
+
// Validate basic structure
|
|
9874
|
+
if (!raw || typeof raw !== 'object') {
|
|
9875
|
+
return null;
|
|
9876
|
+
}
|
|
9877
|
+
const frame = raw;
|
|
9878
|
+
// Check version
|
|
9879
|
+
if (frame.v !== TRANSPORT_FRAME_VERSION) {
|
|
9880
|
+
return null;
|
|
9881
|
+
}
|
|
9882
|
+
// Check src and dst
|
|
9883
|
+
if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
|
|
9884
|
+
return null;
|
|
9885
|
+
}
|
|
9886
|
+
// Only accept frames addressed to us from the expected remote
|
|
9887
|
+
if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
|
|
9888
|
+
return null;
|
|
9889
|
+
}
|
|
9890
|
+
// Extract payload
|
|
9891
|
+
if (!frame.payload || !Array.isArray(frame.payload)) {
|
|
9892
|
+
return null;
|
|
9893
|
+
}
|
|
9894
|
+
// Convert array back to Uint8Array
|
|
9895
|
+
return Uint8Array.from(frame.payload);
|
|
9896
|
+
}
|
|
9897
|
+
|
|
9819
9898
|
const logger$_ = getLogger('naylence.fame.connector.broadcast_channel_connector');
|
|
9820
9899
|
const BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
|
|
9821
9900
|
const DEFAULT_CHANNEL$7 = 'naylence-fabric';
|
|
@@ -9881,9 +9960,20 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9881
9960
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
9882
9961
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
9883
9962
|
this.channel = new BroadcastChannel(this.channelName);
|
|
9963
|
+
// Set local and remote node IDs (defaults to connector ID for backwards compatibility)
|
|
9964
|
+
this.localNodeId =
|
|
9965
|
+
typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
|
|
9966
|
+
? config.localNodeId.trim()
|
|
9967
|
+
: this.connectorId;
|
|
9968
|
+
this.remoteNodeId =
|
|
9969
|
+
typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
|
|
9970
|
+
? config.remoteNodeId.trim()
|
|
9971
|
+
: '*'; // Accept from any remote if not specified
|
|
9884
9972
|
logger$_.debug('broadcast_channel_connector_created', {
|
|
9885
9973
|
channel: this.channelName,
|
|
9886
9974
|
connector_id: this.connectorId,
|
|
9975
|
+
local_node_id: this.localNodeId,
|
|
9976
|
+
remote_node_id: this.remoteNodeId,
|
|
9887
9977
|
inbox_capacity: preferredCapacity,
|
|
9888
9978
|
timestamp: new Date().toISOString(),
|
|
9889
9979
|
});
|
|
@@ -9916,6 +10006,46 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
9916
10006
|
if (busMessage.senderId === this.connectorId) {
|
|
9917
10007
|
return;
|
|
9918
10008
|
}
|
|
10009
|
+
// Try to unwrap as transport frame
|
|
10010
|
+
const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
|
|
10011
|
+
if (unwrapped) {
|
|
10012
|
+
// Successfully unwrapped transport frame
|
|
10013
|
+
logger$_.debug('broadcast_channel_transport_frame_received', {
|
|
10014
|
+
channel: this.channelName,
|
|
10015
|
+
sender_id: busMessage.senderId,
|
|
10016
|
+
connector_id: this.connectorId,
|
|
10017
|
+
local_node_id: this.localNodeId,
|
|
10018
|
+
remote_node_id: this.remoteNodeId,
|
|
10019
|
+
payload_length: unwrapped.byteLength,
|
|
10020
|
+
});
|
|
10021
|
+
if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
|
|
10022
|
+
return;
|
|
10023
|
+
}
|
|
10024
|
+
try {
|
|
10025
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
10026
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
10027
|
+
if (accepted) {
|
|
10028
|
+
return;
|
|
10029
|
+
}
|
|
10030
|
+
}
|
|
10031
|
+
this.inbox.enqueue(unwrapped);
|
|
10032
|
+
}
|
|
10033
|
+
catch (error) {
|
|
10034
|
+
if (error instanceof QueueFullError) {
|
|
10035
|
+
logger$_.warning('broadcast_channel_receive_queue_full', {
|
|
10036
|
+
channel: this.channelName,
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
else {
|
|
10040
|
+
logger$_.error('broadcast_channel_receive_error', {
|
|
10041
|
+
channel: this.channelName,
|
|
10042
|
+
error: error instanceof Error ? error.message : String(error),
|
|
10043
|
+
});
|
|
10044
|
+
}
|
|
10045
|
+
}
|
|
10046
|
+
return;
|
|
10047
|
+
}
|
|
10048
|
+
// Fall back to legacy format (no transport frame)
|
|
9919
10049
|
const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
|
|
9920
10050
|
if (!payload) {
|
|
9921
10051
|
logger$_.debug('broadcast_channel_payload_rejected', {
|
|
@@ -10054,10 +10184,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
10054
10184
|
logger$_.debug('broadcast_channel_message_sending', {
|
|
10055
10185
|
channel: this.channelName,
|
|
10056
10186
|
sender_id: this.connectorId,
|
|
10057
|
-
|
|
10187
|
+
local_node_id: this.localNodeId,
|
|
10188
|
+
remote_node_id: this.remoteNodeId,
|
|
10189
|
+
});
|
|
10190
|
+
// Only use transport framing if both localNodeId and remoteNodeId are explicitly set
|
|
10191
|
+
// (not using default values). This ensures backwards compatibility.
|
|
10192
|
+
const useTransportFrame = this.localNodeId !== this.connectorId ||
|
|
10193
|
+
this.remoteNodeId !== '*';
|
|
10194
|
+
let payload;
|
|
10195
|
+
if (useTransportFrame) {
|
|
10196
|
+
// Wrap payload in transport frame
|
|
10197
|
+
const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
|
|
10198
|
+
payload = serializeTransportFrame(frame);
|
|
10199
|
+
}
|
|
10200
|
+
else {
|
|
10201
|
+
// Legacy format: send raw payload
|
|
10202
|
+
payload = data;
|
|
10203
|
+
}
|
|
10058
10204
|
this.channel.postMessage({
|
|
10059
10205
|
senderId: this.connectorId,
|
|
10060
|
-
payload
|
|
10206
|
+
payload,
|
|
10061
10207
|
});
|
|
10062
10208
|
}
|
|
10063
10209
|
async _transportReceive() {
|
|
@@ -10350,6 +10496,14 @@ function isBroadcastChannelConnectionGrant(candidate) {
|
|
|
10350
10496
|
record.inboxCapacity <= 0)) {
|
|
10351
10497
|
return false;
|
|
10352
10498
|
}
|
|
10499
|
+
if (record.localNodeId !== undefined &&
|
|
10500
|
+
(typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
|
|
10501
|
+
return false;
|
|
10502
|
+
}
|
|
10503
|
+
if (record.remoteNodeId !== undefined &&
|
|
10504
|
+
(typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
|
|
10505
|
+
return false;
|
|
10506
|
+
}
|
|
10353
10507
|
return true;
|
|
10354
10508
|
}
|
|
10355
10509
|
function normalizeBroadcastChannelConnectionGrant(candidate) {
|
|
@@ -10383,6 +10537,20 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
|
|
|
10383
10537
|
}
|
|
10384
10538
|
result.inboxCapacity = Math.floor(inboxValue);
|
|
10385
10539
|
}
|
|
10540
|
+
const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
|
|
10541
|
+
if (localNodeIdValue !== undefined) {
|
|
10542
|
+
if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
|
|
10543
|
+
throw new TypeError('BroadcastChannelConnectionGrant "localNodeId" must be a non-empty string when provided');
|
|
10544
|
+
}
|
|
10545
|
+
result.localNodeId = localNodeIdValue.trim();
|
|
10546
|
+
}
|
|
10547
|
+
const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
10548
|
+
if (remoteNodeIdValue !== undefined) {
|
|
10549
|
+
if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
|
|
10550
|
+
throw new TypeError('BroadcastChannelConnectionGrant "remoteNodeId" must be a non-empty string when provided');
|
|
10551
|
+
}
|
|
10552
|
+
result.remoteNodeId = remoteNodeIdValue.trim();
|
|
10553
|
+
}
|
|
10386
10554
|
return result;
|
|
10387
10555
|
}
|
|
10388
10556
|
function broadcastChannelGrantToConnectorConfig(grant) {
|
|
@@ -10396,6 +10564,12 @@ function broadcastChannelGrantToConnectorConfig(grant) {
|
|
|
10396
10564
|
if (normalized.inboxCapacity !== undefined) {
|
|
10397
10565
|
config.inboxCapacity = normalized.inboxCapacity;
|
|
10398
10566
|
}
|
|
10567
|
+
if (normalized.localNodeId) {
|
|
10568
|
+
config.localNodeId = normalized.localNodeId;
|
|
10569
|
+
}
|
|
10570
|
+
if (normalized.remoteNodeId) {
|
|
10571
|
+
config.remoteNodeId = normalized.remoteNodeId;
|
|
10572
|
+
}
|
|
10399
10573
|
return config;
|
|
10400
10574
|
}
|
|
10401
10575
|
|
|
@@ -20342,9 +20516,20 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20342
20516
|
: DEFAULT_INBOX_CAPACITY$6;
|
|
20343
20517
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
20344
20518
|
this.connectorId = InPageConnector.generateConnectorId();
|
|
20519
|
+
// Set local and remote node IDs (defaults to connector ID for backwards compatibility)
|
|
20520
|
+
this.localNodeId =
|
|
20521
|
+
typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
|
|
20522
|
+
? config.localNodeId.trim()
|
|
20523
|
+
: this.connectorId;
|
|
20524
|
+
this.remoteNodeId =
|
|
20525
|
+
typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
|
|
20526
|
+
? config.remoteNodeId.trim()
|
|
20527
|
+
: '*'; // Accept from any remote if not specified
|
|
20345
20528
|
logger$G.debug('inpage_connector_initialized', {
|
|
20346
20529
|
channel: this.channelName,
|
|
20347
20530
|
connector_id: this.connectorId,
|
|
20531
|
+
local_node_id: this.localNodeId,
|
|
20532
|
+
remote_node_id: this.remoteNodeId,
|
|
20348
20533
|
});
|
|
20349
20534
|
this.onMsg = (event) => {
|
|
20350
20535
|
const messageEvent = event;
|
|
@@ -20378,6 +20563,43 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20378
20563
|
if (busMessage.senderId === this.connectorId) {
|
|
20379
20564
|
return;
|
|
20380
20565
|
}
|
|
20566
|
+
// Try to unwrap as transport frame
|
|
20567
|
+
const unwrapped = unwrapTransportFrame(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
|
|
20568
|
+
if (unwrapped) {
|
|
20569
|
+
// Successfully unwrapped transport frame
|
|
20570
|
+
logger$G.debug('inpage_transport_frame_received', {
|
|
20571
|
+
channel: this.channelName,
|
|
20572
|
+
sender_id: busMessage.senderId,
|
|
20573
|
+
connector_id: this.connectorId,
|
|
20574
|
+
local_node_id: this.localNodeId,
|
|
20575
|
+
remote_node_id: this.remoteNodeId,
|
|
20576
|
+
payload_length: unwrapped.byteLength,
|
|
20577
|
+
});
|
|
20578
|
+
try {
|
|
20579
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
20580
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
20581
|
+
if (accepted) {
|
|
20582
|
+
return;
|
|
20583
|
+
}
|
|
20584
|
+
}
|
|
20585
|
+
this.inbox.enqueue(unwrapped);
|
|
20586
|
+
}
|
|
20587
|
+
catch (error) {
|
|
20588
|
+
if (error instanceof QueueFullError) {
|
|
20589
|
+
logger$G.warning('inpage_receive_queue_full', {
|
|
20590
|
+
channel: this.channelName,
|
|
20591
|
+
});
|
|
20592
|
+
}
|
|
20593
|
+
else {
|
|
20594
|
+
logger$G.error('inpage_receive_error', {
|
|
20595
|
+
channel: this.channelName,
|
|
20596
|
+
error: error instanceof Error ? error.message : String(error),
|
|
20597
|
+
});
|
|
20598
|
+
}
|
|
20599
|
+
}
|
|
20600
|
+
return;
|
|
20601
|
+
}
|
|
20602
|
+
// Fall back to legacy format (no transport frame)
|
|
20381
20603
|
const payload = InPageConnector.coercePayload(busMessage.payload);
|
|
20382
20604
|
if (!payload) {
|
|
20383
20605
|
logger$G.debug('inpage_payload_rejected', {
|
|
@@ -20536,11 +20758,27 @@ class InPageConnector extends BaseAsyncConnector {
|
|
|
20536
20758
|
logger$G.debug('inpage_message_sending', {
|
|
20537
20759
|
channel: this.channelName,
|
|
20538
20760
|
sender_id: this.connectorId,
|
|
20539
|
-
|
|
20761
|
+
local_node_id: this.localNodeId,
|
|
20762
|
+
remote_node_id: this.remoteNodeId,
|
|
20763
|
+
});
|
|
20764
|
+
// Only use transport framing if both localNodeId and remoteNodeId are explicitly set
|
|
20765
|
+
// (not using default values). This ensures backwards compatibility.
|
|
20766
|
+
const useTransportFrame = this.localNodeId !== this.connectorId ||
|
|
20767
|
+
this.remoteNodeId !== '*';
|
|
20768
|
+
let payload;
|
|
20769
|
+
if (useTransportFrame) {
|
|
20770
|
+
// Wrap payload in transport frame
|
|
20771
|
+
const frame = wrapTransportFrame(data, this.localNodeId, this.remoteNodeId);
|
|
20772
|
+
payload = serializeTransportFrame(frame);
|
|
20773
|
+
}
|
|
20774
|
+
else {
|
|
20775
|
+
// Legacy format: send raw payload
|
|
20776
|
+
payload = data;
|
|
20777
|
+
}
|
|
20540
20778
|
const event = new MessageEvent(this.channelName, {
|
|
20541
20779
|
data: {
|
|
20542
20780
|
senderId: this.connectorId,
|
|
20543
|
-
payload
|
|
20781
|
+
payload,
|
|
20544
20782
|
},
|
|
20545
20783
|
});
|
|
20546
20784
|
getSharedBus$1().dispatchEvent(event);
|
|
@@ -27905,6 +28143,14 @@ function isInPageConnectionGrant(candidate) {
|
|
|
27905
28143
|
record.inboxCapacity <= 0)) {
|
|
27906
28144
|
return false;
|
|
27907
28145
|
}
|
|
28146
|
+
if (record.localNodeId !== undefined &&
|
|
28147
|
+
(typeof record.localNodeId !== 'string' || record.localNodeId.length === 0)) {
|
|
28148
|
+
return false;
|
|
28149
|
+
}
|
|
28150
|
+
if (record.remoteNodeId !== undefined &&
|
|
28151
|
+
(typeof record.remoteNodeId !== 'string' || record.remoteNodeId.length === 0)) {
|
|
28152
|
+
return false;
|
|
28153
|
+
}
|
|
27908
28154
|
return true;
|
|
27909
28155
|
}
|
|
27910
28156
|
function normalizeInPageConnectionGrant(candidate) {
|
|
@@ -27938,6 +28184,20 @@ function normalizeInPageConnectionGrant(candidate) {
|
|
|
27938
28184
|
}
|
|
27939
28185
|
result.inboxCapacity = Math.floor(inboxValue);
|
|
27940
28186
|
}
|
|
28187
|
+
const localNodeIdValue = candidate.localNodeId ?? candidate['local_node_id'];
|
|
28188
|
+
if (localNodeIdValue !== undefined) {
|
|
28189
|
+
if (typeof localNodeIdValue !== 'string' || localNodeIdValue.trim().length === 0) {
|
|
28190
|
+
throw new TypeError('InPageConnectionGrant "localNodeId" must be a non-empty string when provided');
|
|
28191
|
+
}
|
|
28192
|
+
result.localNodeId = localNodeIdValue.trim();
|
|
28193
|
+
}
|
|
28194
|
+
const remoteNodeIdValue = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
28195
|
+
if (remoteNodeIdValue !== undefined) {
|
|
28196
|
+
if (typeof remoteNodeIdValue !== 'string' || remoteNodeIdValue.trim().length === 0) {
|
|
28197
|
+
throw new TypeError('InPageConnectionGrant "remoteNodeId" must be a non-empty string when provided');
|
|
28198
|
+
}
|
|
28199
|
+
result.remoteNodeId = remoteNodeIdValue.trim();
|
|
28200
|
+
}
|
|
27941
28201
|
return result;
|
|
27942
28202
|
}
|
|
27943
28203
|
function inPageGrantToConnectorConfig(grant) {
|
|
@@ -27951,6 +28211,12 @@ function inPageGrantToConnectorConfig(grant) {
|
|
|
27951
28211
|
if (normalized.inboxCapacity !== undefined) {
|
|
27952
28212
|
config.inboxCapacity = normalized.inboxCapacity;
|
|
27953
28213
|
}
|
|
28214
|
+
if (normalized.localNodeId) {
|
|
28215
|
+
config.localNodeId = normalized.localNodeId;
|
|
28216
|
+
}
|
|
28217
|
+
if (normalized.remoteNodeId) {
|
|
28218
|
+
config.remoteNodeId = normalized.remoteNodeId;
|
|
28219
|
+
}
|
|
27954
28220
|
return config;
|
|
27955
28221
|
}
|
|
27956
28222
|
|
|
@@ -28572,6 +28838,8 @@ class InPageConnectorFactory extends ConnectorFactory {
|
|
|
28572
28838
|
type: INPAGE_CONNECTOR_TYPE,
|
|
28573
28839
|
channelName,
|
|
28574
28840
|
inboxCapacity,
|
|
28841
|
+
localNodeId: normalized.localNodeId,
|
|
28842
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
28575
28843
|
};
|
|
28576
28844
|
const connector = new InPageConnector(connectorConfig, baseConfig);
|
|
28577
28845
|
if (options.authorization) {
|
|
@@ -28640,6 +28908,16 @@ class InPageConnectorFactory extends ConnectorFactory {
|
|
|
28640
28908
|
if (candidate.authorizationContext !== undefined) {
|
|
28641
28909
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
28642
28910
|
}
|
|
28911
|
+
// Handle localNodeId
|
|
28912
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
28913
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
28914
|
+
normalized.localNodeId = localNodeId.trim();
|
|
28915
|
+
}
|
|
28916
|
+
// Handle remoteNodeId
|
|
28917
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
28918
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
28919
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
28920
|
+
}
|
|
28643
28921
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
|
|
28644
28922
|
normalized.inboxCapacity =
|
|
28645
28923
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
|
|
@@ -28739,6 +29017,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
|
|
|
28739
29017
|
type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
28740
29018
|
channelName,
|
|
28741
29019
|
inboxCapacity,
|
|
29020
|
+
localNodeId: normalized.localNodeId,
|
|
29021
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
28742
29022
|
};
|
|
28743
29023
|
const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
|
|
28744
29024
|
if (options.authorization) {
|
|
@@ -28800,6 +29080,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
|
|
|
28800
29080
|
if (candidate.authorizationContext !== undefined) {
|
|
28801
29081
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
28802
29082
|
}
|
|
29083
|
+
// Handle localNodeId
|
|
29084
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
29085
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
29086
|
+
normalized.localNodeId = localNodeId.trim();
|
|
29087
|
+
}
|
|
29088
|
+
// Handle remoteNodeId
|
|
29089
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
29090
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
29091
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
29092
|
+
}
|
|
28803
29093
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL$4;
|
|
28804
29094
|
normalized.inboxCapacity =
|
|
28805
29095
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$4;
|
|
@@ -89,6 +89,8 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
|
|
|
89
89
|
type: broadcast_channel_connector_js_1.BROADCAST_CHANNEL_CONNECTOR_TYPE,
|
|
90
90
|
channelName,
|
|
91
91
|
inboxCapacity,
|
|
92
|
+
localNodeId: normalized.localNodeId,
|
|
93
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
92
94
|
};
|
|
93
95
|
const connector = new broadcast_channel_connector_js_1.BroadcastChannelConnector(connectorConfig, baseConfig);
|
|
94
96
|
if (options.authorization) {
|
|
@@ -150,6 +152,16 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
|
|
|
150
152
|
if (candidate.authorizationContext !== undefined) {
|
|
151
153
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
152
154
|
}
|
|
155
|
+
// Handle localNodeId
|
|
156
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
157
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
158
|
+
normalized.localNodeId = localNodeId.trim();
|
|
159
|
+
}
|
|
160
|
+
// Handle remoteNodeId
|
|
161
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
162
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
163
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
164
|
+
}
|
|
153
165
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL;
|
|
154
166
|
normalized.inboxCapacity =
|
|
155
167
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY;
|
|
@@ -6,6 +6,7 @@ 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
8
|
const core_1 = require("@naylence/core");
|
|
9
|
+
const transport_frame_js_1 = require("./transport-frame.js");
|
|
9
10
|
const logger = (0, logging_js_1.getLogger)('naylence.fame.connector.broadcast_channel_connector');
|
|
10
11
|
exports.BROADCAST_CHANNEL_CONNECTOR_TYPE = 'broadcast-channel-connector';
|
|
11
12
|
const DEFAULT_CHANNEL = 'naylence-fabric';
|
|
@@ -71,9 +72,20 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
|
|
|
71
72
|
this.inbox = new bounded_async_queue_js_1.BoundedAsyncQueue(preferredCapacity);
|
|
72
73
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
73
74
|
this.channel = new BroadcastChannel(this.channelName);
|
|
75
|
+
// Set local and remote node IDs (defaults to connector ID for backwards compatibility)
|
|
76
|
+
this.localNodeId =
|
|
77
|
+
typeof config.localNodeId === 'string' && config.localNodeId.trim().length > 0
|
|
78
|
+
? config.localNodeId.trim()
|
|
79
|
+
: this.connectorId;
|
|
80
|
+
this.remoteNodeId =
|
|
81
|
+
typeof config.remoteNodeId === 'string' && config.remoteNodeId.trim().length > 0
|
|
82
|
+
? config.remoteNodeId.trim()
|
|
83
|
+
: '*'; // Accept from any remote if not specified
|
|
74
84
|
logger.debug('broadcast_channel_connector_created', {
|
|
75
85
|
channel: this.channelName,
|
|
76
86
|
connector_id: this.connectorId,
|
|
87
|
+
local_node_id: this.localNodeId,
|
|
88
|
+
remote_node_id: this.remoteNodeId,
|
|
77
89
|
inbox_capacity: preferredCapacity,
|
|
78
90
|
timestamp: new Date().toISOString(),
|
|
79
91
|
});
|
|
@@ -106,6 +118,46 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
|
|
|
106
118
|
if (busMessage.senderId === this.connectorId) {
|
|
107
119
|
return;
|
|
108
120
|
}
|
|
121
|
+
// Try to unwrap as transport frame
|
|
122
|
+
const unwrapped = (0, transport_frame_js_1.unwrapTransportFrame)(busMessage.payload, this.localNodeId, this.remoteNodeId === '*' ? busMessage.senderId : this.remoteNodeId);
|
|
123
|
+
if (unwrapped) {
|
|
124
|
+
// Successfully unwrapped transport frame
|
|
125
|
+
logger.debug('broadcast_channel_transport_frame_received', {
|
|
126
|
+
channel: this.channelName,
|
|
127
|
+
sender_id: busMessage.senderId,
|
|
128
|
+
connector_id: this.connectorId,
|
|
129
|
+
local_node_id: this.localNodeId,
|
|
130
|
+
remote_node_id: this.remoteNodeId,
|
|
131
|
+
payload_length: unwrapped.byteLength,
|
|
132
|
+
});
|
|
133
|
+
if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
138
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
139
|
+
if (accepted) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
this.inbox.enqueue(unwrapped);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error instanceof bounded_async_queue_js_1.QueueFullError) {
|
|
147
|
+
logger.warning('broadcast_channel_receive_queue_full', {
|
|
148
|
+
channel: this.channelName,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
logger.error('broadcast_channel_receive_error', {
|
|
153
|
+
channel: this.channelName,
|
|
154
|
+
error: error instanceof Error ? error.message : String(error),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Fall back to legacy format (no transport frame)
|
|
109
161
|
const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
|
|
110
162
|
if (!payload) {
|
|
111
163
|
logger.debug('broadcast_channel_payload_rejected', {
|
|
@@ -244,10 +296,26 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
|
|
|
244
296
|
logger.debug('broadcast_channel_message_sending', {
|
|
245
297
|
channel: this.channelName,
|
|
246
298
|
sender_id: this.connectorId,
|
|
299
|
+
local_node_id: this.localNodeId,
|
|
300
|
+
remote_node_id: this.remoteNodeId,
|
|
247
301
|
});
|
|
302
|
+
// Only use transport framing if both localNodeId and remoteNodeId are explicitly set
|
|
303
|
+
// (not using default values). This ensures backwards compatibility.
|
|
304
|
+
const useTransportFrame = this.localNodeId !== this.connectorId ||
|
|
305
|
+
this.remoteNodeId !== '*';
|
|
306
|
+
let payload;
|
|
307
|
+
if (useTransportFrame) {
|
|
308
|
+
// Wrap payload in transport frame
|
|
309
|
+
const frame = (0, transport_frame_js_1.wrapTransportFrame)(data, this.localNodeId, this.remoteNodeId);
|
|
310
|
+
payload = (0, transport_frame_js_1.serializeTransportFrame)(frame);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// Legacy format: send raw payload
|
|
314
|
+
payload = data;
|
|
315
|
+
}
|
|
248
316
|
this.channel.postMessage({
|
|
249
317
|
senderId: this.connectorId,
|
|
250
|
-
payload
|
|
318
|
+
payload,
|
|
251
319
|
});
|
|
252
320
|
}
|
|
253
321
|
async _transportReceive() {
|
|
@@ -84,6 +84,8 @@ class InPageConnectorFactory extends connector_factory_js_1.ConnectorFactory {
|
|
|
84
84
|
type: inpage_connector_js_1.INPAGE_CONNECTOR_TYPE,
|
|
85
85
|
channelName,
|
|
86
86
|
inboxCapacity,
|
|
87
|
+
localNodeId: normalized.localNodeId,
|
|
88
|
+
remoteNodeId: normalized.remoteNodeId,
|
|
87
89
|
};
|
|
88
90
|
const connector = new inpage_connector_js_1.InPageConnector(connectorConfig, baseConfig);
|
|
89
91
|
if (options.authorization) {
|
|
@@ -152,6 +154,16 @@ class InPageConnectorFactory extends connector_factory_js_1.ConnectorFactory {
|
|
|
152
154
|
if (candidate.authorizationContext !== undefined) {
|
|
153
155
|
normalized.authorizationContext = candidate.authorizationContext;
|
|
154
156
|
}
|
|
157
|
+
// Handle localNodeId
|
|
158
|
+
const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
|
|
159
|
+
if (typeof localNodeId === 'string' && localNodeId.trim().length > 0) {
|
|
160
|
+
normalized.localNodeId = localNodeId.trim();
|
|
161
|
+
}
|
|
162
|
+
// Handle remoteNodeId
|
|
163
|
+
const remoteNodeId = candidate.remoteNodeId ?? candidate['remote_node_id'];
|
|
164
|
+
if (typeof remoteNodeId === 'string' && remoteNodeId.trim().length > 0) {
|
|
165
|
+
normalized.remoteNodeId = remoteNodeId.trim();
|
|
166
|
+
}
|
|
155
167
|
normalized.channelName = normalized.channelName ?? DEFAULT_CHANNEL;
|
|
156
168
|
normalized.inboxCapacity =
|
|
157
169
|
normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY;
|