@naylence/runtime 0.3.5-test.949 → 0.3.5-test.951
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 +154 -84
- package/dist/browser/index.mjs +154 -84
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +54 -33
- package/dist/cjs/naylence/fame/connector/broadcast-channel-listener.js +38 -8
- package/dist/cjs/naylence/fame/connector/inpage-connector.js +51 -30
- package/dist/cjs/naylence/fame/connector/transport-frame.js +10 -11
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +54 -33
- package/dist/esm/naylence/fame/connector/broadcast-channel-listener.js +38 -8
- package/dist/esm/naylence/fame/connector/inpage-connector.js +51 -30
- package/dist/esm/naylence/fame/connector/transport-frame.js +10 -11
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +154 -84
- package/dist/node/index.mjs +154 -84
- package/dist/node/node.cjs +154 -84
- package/dist/node/node.mjs +154 -84
- package/dist/types/naylence/fame/connector/transport-frame.d.ts +3 -5
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -119,43 +119,64 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
|
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
// Try to unwrap as transport frame
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
122
|
+
const frame = (0, transport_frame_js_1.unwrapTransportFrame)(busMessage.payload);
|
|
123
|
+
if (frame) {
|
|
124
|
+
// Apply connector's filtering policy: strict dst check, src accepts wildcard
|
|
125
|
+
const srcMatches = this.remoteNodeId === '*' || frame.src === this.remoteNodeId;
|
|
126
|
+
const dstMatches = frame.dst === this.localNodeId;
|
|
127
|
+
if (dstMatches && srcMatches) {
|
|
128
|
+
// Successfully received and filtered transport frame
|
|
129
|
+
logger.debug('broadcast_channel_transport_frame_received', {
|
|
130
|
+
channel: this.channelName,
|
|
131
|
+
sender_id: busMessage.senderId,
|
|
132
|
+
connector_id: this.connectorId,
|
|
133
|
+
local_node_id: this.localNodeId,
|
|
134
|
+
remote_node_id: this.remoteNodeId,
|
|
135
|
+
frame_src: frame.src,
|
|
136
|
+
frame_dst: frame.dst,
|
|
137
|
+
payload_length: frame.payload.byteLength,
|
|
138
|
+
});
|
|
139
|
+
const unwrapped = frame.payload;
|
|
140
|
+
if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
|
|
141
|
+
return;
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
143
|
+
try {
|
|
144
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
145
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
146
|
+
if (accepted) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
this.inbox.enqueue(unwrapped);
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof bounded_async_queue_js_1.QueueFullError) {
|
|
154
|
+
logger.warning('broadcast_channel_receive_queue_full', {
|
|
155
|
+
channel: this.channelName,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
logger.error('broadcast_channel_receive_error', {
|
|
160
|
+
channel: this.channelName,
|
|
161
|
+
error: error instanceof Error ? error.message : String(error),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
156
164
|
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// Frame filtered out by addressing rules
|
|
169
|
+
logger.debug('broadcast_channel_transport_frame_filtered', {
|
|
170
|
+
channel: this.channelName,
|
|
171
|
+
connector_id: this.connectorId,
|
|
172
|
+
local_node_id: this.localNodeId,
|
|
173
|
+
remote_node_id: this.remoteNodeId,
|
|
174
|
+
frame_src: frame.src,
|
|
175
|
+
frame_dst: frame.dst,
|
|
176
|
+
reason: !dstMatches ? 'wrong_destination' : 'wrong_source',
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
157
179
|
}
|
|
158
|
-
return;
|
|
159
180
|
}
|
|
160
181
|
// Fall back to legacy format (no transport frame)
|
|
161
182
|
const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
|
|
@@ -11,6 +11,7 @@ const broadcast_channel_connector_js_1 = require("./broadcast-channel-connector.
|
|
|
11
11
|
const grant_selection_policy_js_1 = require("./grant-selection-policy.js");
|
|
12
12
|
const bounded_async_queue_js_1 = require("../util/bounded-async-queue.js");
|
|
13
13
|
const broadcast_channel_connection_grant_js_1 = require("../grants/broadcast-channel-connection-grant.js");
|
|
14
|
+
const transport_frame_js_1 = require("./transport-frame.js");
|
|
14
15
|
const logger = (0, logging_js_1.getLogger)('naylence.fame.connector.broadcast_channel_listener');
|
|
15
16
|
const DEFAULT_CHANNEL = 'naylence-fabric';
|
|
16
17
|
const DEFAULT_INBOX_CAPACITY = 2048;
|
|
@@ -213,23 +214,52 @@ class BroadcastChannelListener extends transport_listener_js_1.TransportListener
|
|
|
213
214
|
if (typeof senderId !== 'string' || senderId.length === 0) {
|
|
214
215
|
return null;
|
|
215
216
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
// Check if payload is a transport frame object first
|
|
218
|
+
let envelopePayload = null;
|
|
219
|
+
if (this._routingNode && record.payload && typeof record.payload === 'object') {
|
|
220
|
+
// Try to unwrap as transport frame
|
|
221
|
+
const frame = (0, transport_frame_js_1.unwrapTransportFrame)(record.payload);
|
|
222
|
+
if (frame) {
|
|
223
|
+
// Apply listener's filtering policy: dst must match, src can be anything
|
|
224
|
+
if (frame.dst === this._routingNode.id) {
|
|
225
|
+
envelopePayload = frame.payload;
|
|
226
|
+
logger.debug('broadcast_channel_listener_unwrapped_transport_frame', {
|
|
227
|
+
sender_id: senderId,
|
|
228
|
+
src: frame.src,
|
|
229
|
+
dst: frame.dst,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
// Frame not addressed to us, ignore it
|
|
234
|
+
logger.debug('broadcast_channel_listener_ignored_frame_wrong_destination', {
|
|
235
|
+
sender_id: senderId,
|
|
236
|
+
dst: frame.dst,
|
|
237
|
+
expected: this._routingNode.id,
|
|
238
|
+
});
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// If not a transport frame, try to coerce as legacy format
|
|
244
|
+
if (!envelopePayload) {
|
|
245
|
+
envelopePayload = coercePayload(record.payload);
|
|
246
|
+
if (!envelopePayload) {
|
|
247
|
+
logger.debug('broadcast_channel_listener_ignored_event_without_payload', {
|
|
248
|
+
sender_id: senderId,
|
|
249
|
+
});
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
222
252
|
}
|
|
223
253
|
let envelope;
|
|
224
254
|
try {
|
|
225
|
-
const decoded = new TextDecoder().decode(
|
|
255
|
+
const decoded = new TextDecoder().decode(envelopePayload);
|
|
226
256
|
const parsed = JSON.parse(decoded);
|
|
227
257
|
envelope = (0, core_1.deserializeEnvelope)(parsed);
|
|
228
258
|
}
|
|
229
259
|
catch (error) {
|
|
230
260
|
const decoded = (() => {
|
|
231
261
|
try {
|
|
232
|
-
return new TextDecoder().decode(
|
|
262
|
+
return new TextDecoder().decode(envelopePayload);
|
|
233
263
|
}
|
|
234
264
|
catch {
|
|
235
265
|
return null;
|
|
@@ -129,40 +129,61 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
|
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
// Try to unwrap as transport frame
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
132
|
+
const frame = (0, transport_frame_js_1.unwrapTransportFrame)(busMessage.payload);
|
|
133
|
+
if (frame) {
|
|
134
|
+
// Apply connector's filtering policy: strict dst check, src accepts wildcard
|
|
135
|
+
const srcMatches = this.remoteNodeId === '*' || frame.src === this.remoteNodeId;
|
|
136
|
+
const dstMatches = frame.dst === this.localNodeId;
|
|
137
|
+
if (dstMatches && srcMatches) {
|
|
138
|
+
// Successfully received and filtered transport frame
|
|
139
|
+
logger.debug('inpage_transport_frame_received', {
|
|
140
|
+
channel: this.channelName,
|
|
141
|
+
sender_id: busMessage.senderId,
|
|
142
|
+
connector_id: this.connectorId,
|
|
143
|
+
local_node_id: this.localNodeId,
|
|
144
|
+
remote_node_id: this.remoteNodeId,
|
|
145
|
+
frame_src: frame.src,
|
|
146
|
+
frame_dst: frame.dst,
|
|
147
|
+
payload_length: frame.payload.byteLength,
|
|
148
|
+
});
|
|
149
|
+
const unwrapped = frame.payload;
|
|
150
|
+
try {
|
|
151
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
152
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
153
|
+
if (accepted) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
148
156
|
}
|
|
157
|
+
this.inbox.enqueue(unwrapped);
|
|
149
158
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error instanceof bounded_async_queue_js_1.QueueFullError) {
|
|
161
|
+
logger.warning('inpage_receive_queue_full', {
|
|
162
|
+
channel: this.channelName,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
logger.error('inpage_receive_error', {
|
|
167
|
+
channel: this.channelName,
|
|
168
|
+
error: error instanceof Error ? error.message : String(error),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
163
171
|
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// Frame filtered out by addressing rules
|
|
176
|
+
logger.debug('inpage_transport_frame_filtered', {
|
|
177
|
+
channel: this.channelName,
|
|
178
|
+
connector_id: this.connectorId,
|
|
179
|
+
local_node_id: this.localNodeId,
|
|
180
|
+
remote_node_id: this.remoteNodeId,
|
|
181
|
+
frame_src: frame.src,
|
|
182
|
+
frame_dst: frame.dst,
|
|
183
|
+
reason: !dstMatches ? 'wrong_destination' : 'wrong_source',
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
164
186
|
}
|
|
165
|
-
return;
|
|
166
187
|
}
|
|
167
188
|
// Fall back to legacy format (no transport frame)
|
|
168
189
|
const payload = InPageConnector.coercePayload(busMessage.payload);
|
|
@@ -51,14 +51,12 @@ function serializeTransportFrame(frame) {
|
|
|
51
51
|
return serializable;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Unwrap a transport frame
|
|
54
|
+
* Unwrap a transport frame (pure deserializer - no filtering)
|
|
55
55
|
*
|
|
56
56
|
* @param raw - Raw data from the bus
|
|
57
|
-
* @
|
|
58
|
-
* @param remoteNodeId - Expected remote node ID
|
|
59
|
-
* @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
|
|
57
|
+
* @returns Unwrapped frame with payload as Uint8Array, or null if invalid structure
|
|
60
58
|
*/
|
|
61
|
-
function unwrapTransportFrame(raw
|
|
59
|
+
function unwrapTransportFrame(raw) {
|
|
62
60
|
// Validate basic structure
|
|
63
61
|
if (!raw || typeof raw !== 'object') {
|
|
64
62
|
return null;
|
|
@@ -72,16 +70,17 @@ function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
|
|
|
72
70
|
if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
|
|
73
71
|
return null;
|
|
74
72
|
}
|
|
75
|
-
// Only accept frames addressed to us from the expected remote
|
|
76
|
-
if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
73
|
// Extract payload
|
|
80
74
|
if (!frame.payload || !Array.isArray(frame.payload)) {
|
|
81
75
|
return null;
|
|
82
76
|
}
|
|
83
|
-
// Convert array back to Uint8Array
|
|
84
|
-
return
|
|
77
|
+
// Convert array back to Uint8Array and return full frame
|
|
78
|
+
return {
|
|
79
|
+
v: frame.v,
|
|
80
|
+
src: frame.src,
|
|
81
|
+
dst: frame.dst,
|
|
82
|
+
payload: Uint8Array.from(frame.payload),
|
|
83
|
+
};
|
|
85
84
|
}
|
|
86
85
|
/**
|
|
87
86
|
* Check if raw data looks like a transport frame
|
package/dist/cjs/version.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// This file is auto-generated during build - do not edit manually
|
|
3
|
-
// Generated from package.json version: 0.3.5-test.
|
|
3
|
+
// Generated from package.json version: 0.3.5-test.951
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.VERSION = void 0;
|
|
6
6
|
/**
|
|
7
7
|
* The package version, injected at build time.
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
exports.VERSION = '0.3.5-test.
|
|
10
|
+
exports.VERSION = '0.3.5-test.951';
|
|
@@ -116,43 +116,64 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
// Try to unwrap as transport frame
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
119
|
+
const frame = unwrapTransportFrame(busMessage.payload);
|
|
120
|
+
if (frame) {
|
|
121
|
+
// Apply connector's filtering policy: strict dst check, src accepts wildcard
|
|
122
|
+
const srcMatches = this.remoteNodeId === '*' || frame.src === this.remoteNodeId;
|
|
123
|
+
const dstMatches = frame.dst === this.localNodeId;
|
|
124
|
+
if (dstMatches && srcMatches) {
|
|
125
|
+
// Successfully received and filtered transport frame
|
|
126
|
+
logger.debug('broadcast_channel_transport_frame_received', {
|
|
127
|
+
channel: this.channelName,
|
|
128
|
+
sender_id: busMessage.senderId,
|
|
129
|
+
connector_id: this.connectorId,
|
|
130
|
+
local_node_id: this.localNodeId,
|
|
131
|
+
remote_node_id: this.remoteNodeId,
|
|
132
|
+
frame_src: frame.src,
|
|
133
|
+
frame_dst: frame.dst,
|
|
134
|
+
payload_length: frame.payload.byteLength,
|
|
135
|
+
});
|
|
136
|
+
const unwrapped = frame.payload;
|
|
137
|
+
if (this._shouldSkipDuplicateAck(busMessage.senderId, unwrapped)) {
|
|
138
|
+
return;
|
|
139
139
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
140
|
+
try {
|
|
141
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
142
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
143
|
+
if (accepted) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
this.inbox.enqueue(unwrapped);
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof QueueFullError) {
|
|
151
|
+
logger.warning('broadcast_channel_receive_queue_full', {
|
|
152
|
+
channel: this.channelName,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
logger.error('broadcast_channel_receive_error', {
|
|
157
|
+
channel: this.channelName,
|
|
158
|
+
error: error instanceof Error ? error.message : String(error),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
153
161
|
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// Frame filtered out by addressing rules
|
|
166
|
+
logger.debug('broadcast_channel_transport_frame_filtered', {
|
|
167
|
+
channel: this.channelName,
|
|
168
|
+
connector_id: this.connectorId,
|
|
169
|
+
local_node_id: this.localNodeId,
|
|
170
|
+
remote_node_id: this.remoteNodeId,
|
|
171
|
+
frame_src: frame.src,
|
|
172
|
+
frame_dst: frame.dst,
|
|
173
|
+
reason: !dstMatches ? 'wrong_destination' : 'wrong_source',
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
154
176
|
}
|
|
155
|
-
return;
|
|
156
177
|
}
|
|
157
178
|
// Fall back to legacy format (no transport frame)
|
|
158
179
|
const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
|
|
@@ -7,6 +7,7 @@ import { BROADCAST_CHANNEL_CONNECTOR_TYPE, } from './broadcast-channel-connector
|
|
|
7
7
|
import { GrantSelectionContext, defaultGrantSelectionPolicy, } from './grant-selection-policy.js';
|
|
8
8
|
import { QueueFullError } from '../util/bounded-async-queue.js';
|
|
9
9
|
import { BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE, broadcastChannelGrantToConnectorConfig, } from '../grants/broadcast-channel-connection-grant.js';
|
|
10
|
+
import { unwrapTransportFrame, } from './transport-frame.js';
|
|
10
11
|
const logger = getLogger('naylence.fame.connector.broadcast_channel_listener');
|
|
11
12
|
const DEFAULT_CHANNEL = 'naylence-fabric';
|
|
12
13
|
const DEFAULT_INBOX_CAPACITY = 2048;
|
|
@@ -209,23 +210,52 @@ export class BroadcastChannelListener extends TransportListener {
|
|
|
209
210
|
if (typeof senderId !== 'string' || senderId.length === 0) {
|
|
210
211
|
return null;
|
|
211
212
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
// Check if payload is a transport frame object first
|
|
214
|
+
let envelopePayload = null;
|
|
215
|
+
if (this._routingNode && record.payload && typeof record.payload === 'object') {
|
|
216
|
+
// Try to unwrap as transport frame
|
|
217
|
+
const frame = unwrapTransportFrame(record.payload);
|
|
218
|
+
if (frame) {
|
|
219
|
+
// Apply listener's filtering policy: dst must match, src can be anything
|
|
220
|
+
if (frame.dst === this._routingNode.id) {
|
|
221
|
+
envelopePayload = frame.payload;
|
|
222
|
+
logger.debug('broadcast_channel_listener_unwrapped_transport_frame', {
|
|
223
|
+
sender_id: senderId,
|
|
224
|
+
src: frame.src,
|
|
225
|
+
dst: frame.dst,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Frame not addressed to us, ignore it
|
|
230
|
+
logger.debug('broadcast_channel_listener_ignored_frame_wrong_destination', {
|
|
231
|
+
sender_id: senderId,
|
|
232
|
+
dst: frame.dst,
|
|
233
|
+
expected: this._routingNode.id,
|
|
234
|
+
});
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// If not a transport frame, try to coerce as legacy format
|
|
240
|
+
if (!envelopePayload) {
|
|
241
|
+
envelopePayload = coercePayload(record.payload);
|
|
242
|
+
if (!envelopePayload) {
|
|
243
|
+
logger.debug('broadcast_channel_listener_ignored_event_without_payload', {
|
|
244
|
+
sender_id: senderId,
|
|
245
|
+
});
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
218
248
|
}
|
|
219
249
|
let envelope;
|
|
220
250
|
try {
|
|
221
|
-
const decoded = new TextDecoder().decode(
|
|
251
|
+
const decoded = new TextDecoder().decode(envelopePayload);
|
|
222
252
|
const parsed = JSON.parse(decoded);
|
|
223
253
|
envelope = deserializeEnvelope(parsed);
|
|
224
254
|
}
|
|
225
255
|
catch (error) {
|
|
226
256
|
const decoded = (() => {
|
|
227
257
|
try {
|
|
228
|
-
return new TextDecoder().decode(
|
|
258
|
+
return new TextDecoder().decode(envelopePayload);
|
|
229
259
|
}
|
|
230
260
|
catch {
|
|
231
261
|
return null;
|
|
@@ -126,40 +126,61 @@ export class InPageConnector extends BaseAsyncConnector {
|
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
// Try to unwrap as transport frame
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
129
|
+
const frame = unwrapTransportFrame(busMessage.payload);
|
|
130
|
+
if (frame) {
|
|
131
|
+
// Apply connector's filtering policy: strict dst check, src accepts wildcard
|
|
132
|
+
const srcMatches = this.remoteNodeId === '*' || frame.src === this.remoteNodeId;
|
|
133
|
+
const dstMatches = frame.dst === this.localNodeId;
|
|
134
|
+
if (dstMatches && srcMatches) {
|
|
135
|
+
// Successfully received and filtered transport frame
|
|
136
|
+
logger.debug('inpage_transport_frame_received', {
|
|
137
|
+
channel: this.channelName,
|
|
138
|
+
sender_id: busMessage.senderId,
|
|
139
|
+
connector_id: this.connectorId,
|
|
140
|
+
local_node_id: this.localNodeId,
|
|
141
|
+
remote_node_id: this.remoteNodeId,
|
|
142
|
+
frame_src: frame.src,
|
|
143
|
+
frame_dst: frame.dst,
|
|
144
|
+
payload_length: frame.payload.byteLength,
|
|
145
|
+
});
|
|
146
|
+
const unwrapped = frame.payload;
|
|
147
|
+
try {
|
|
148
|
+
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
149
|
+
const accepted = this.inbox.tryEnqueue(unwrapped);
|
|
150
|
+
if (accepted) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
145
153
|
}
|
|
154
|
+
this.inbox.enqueue(unwrapped);
|
|
146
155
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
});
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (error instanceof QueueFullError) {
|
|
158
|
+
logger.warning('inpage_receive_queue_full', {
|
|
159
|
+
channel: this.channelName,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
logger.error('inpage_receive_error', {
|
|
164
|
+
channel: this.channelName,
|
|
165
|
+
error: error instanceof Error ? error.message : String(error),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
160
168
|
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Frame filtered out by addressing rules
|
|
173
|
+
logger.debug('inpage_transport_frame_filtered', {
|
|
174
|
+
channel: this.channelName,
|
|
175
|
+
connector_id: this.connectorId,
|
|
176
|
+
local_node_id: this.localNodeId,
|
|
177
|
+
remote_node_id: this.remoteNodeId,
|
|
178
|
+
frame_src: frame.src,
|
|
179
|
+
frame_dst: frame.dst,
|
|
180
|
+
reason: !dstMatches ? 'wrong_destination' : 'wrong_source',
|
|
181
|
+
});
|
|
182
|
+
return;
|
|
161
183
|
}
|
|
162
|
-
return;
|
|
163
184
|
}
|
|
164
185
|
// Fall back to legacy format (no transport frame)
|
|
165
186
|
const payload = InPageConnector.coercePayload(busMessage.payload);
|
|
@@ -44,14 +44,12 @@ export function serializeTransportFrame(frame) {
|
|
|
44
44
|
return serializable;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
* Unwrap a transport frame
|
|
47
|
+
* Unwrap a transport frame (pure deserializer - no filtering)
|
|
48
48
|
*
|
|
49
49
|
* @param raw - Raw data from the bus
|
|
50
|
-
* @
|
|
51
|
-
* @param remoteNodeId - Expected remote node ID
|
|
52
|
-
* @returns Unwrapped payload if frame is valid and addressed to us, null otherwise
|
|
50
|
+
* @returns Unwrapped frame with payload as Uint8Array, or null if invalid structure
|
|
53
51
|
*/
|
|
54
|
-
export function unwrapTransportFrame(raw
|
|
52
|
+
export function unwrapTransportFrame(raw) {
|
|
55
53
|
// Validate basic structure
|
|
56
54
|
if (!raw || typeof raw !== 'object') {
|
|
57
55
|
return null;
|
|
@@ -65,16 +63,17 @@ export function unwrapTransportFrame(raw, localNodeId, remoteNodeId) {
|
|
|
65
63
|
if (typeof frame.src !== 'string' || typeof frame.dst !== 'string') {
|
|
66
64
|
return null;
|
|
67
65
|
}
|
|
68
|
-
// Only accept frames addressed to us from the expected remote
|
|
69
|
-
if (frame.dst !== localNodeId || frame.src !== remoteNodeId) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
66
|
// Extract payload
|
|
73
67
|
if (!frame.payload || !Array.isArray(frame.payload)) {
|
|
74
68
|
return null;
|
|
75
69
|
}
|
|
76
|
-
// Convert array back to Uint8Array
|
|
77
|
-
return
|
|
70
|
+
// Convert array back to Uint8Array and return full frame
|
|
71
|
+
return {
|
|
72
|
+
v: frame.v,
|
|
73
|
+
src: frame.src,
|
|
74
|
+
dst: frame.dst,
|
|
75
|
+
payload: Uint8Array.from(frame.payload),
|
|
76
|
+
};
|
|
78
77
|
}
|
|
79
78
|
/**
|
|
80
79
|
* Check if raw data looks like a transport frame
|
package/dist/esm/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated during build - do not edit manually
|
|
2
|
-
// Generated from package.json version: 0.3.5-test.
|
|
2
|
+
// Generated from package.json version: 0.3.5-test.951
|
|
3
3
|
/**
|
|
4
4
|
* The package version, injected at build time.
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.3.5-test.
|
|
7
|
+
export const VERSION = '0.3.5-test.951';
|