@naylence/runtime 0.3.6-test.101 → 0.3.6-test.103
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 +42 -11
- package/dist/browser/index.mjs +42 -11
- package/dist/cjs/naylence/fame/node/admission/default-node-attach-client.js +30 -4
- package/dist/cjs/naylence/fame/node/upstream-session-manager.js +10 -5
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/node/admission/default-node-attach-client.js +30 -4
- package/dist/esm/naylence/fame/node/upstream-session-manager.js +10 -5
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +42 -11
- package/dist/node/index.mjs +42 -11
- package/dist/node/node.cjs +42 -11
- package/dist/node/node.mjs +42 -11
- package/dist/types/naylence/fame/node/admission/default-node-attach-client.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
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.6-test.
|
|
101
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
102
102
|
/**
|
|
103
103
|
* The package version, injected at build time.
|
|
104
104
|
* @internal
|
|
105
105
|
*/
|
|
106
|
-
const VERSION = '0.3.6-test.
|
|
106
|
+
const VERSION = '0.3.6-test.103';
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -10863,6 +10863,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10863
10863
|
await connector.start(this.wrappedHandler);
|
|
10864
10864
|
this.connector = connector;
|
|
10865
10865
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
10866
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
10867
|
+
// This prevents adding duplicate broadcast grants
|
|
10868
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
10869
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
10870
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
10871
|
+
: null;
|
|
10866
10872
|
// Include admission client's connection grants as callback grants
|
|
10867
10873
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
10868
10874
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -10876,11 +10882,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10876
10882
|
}
|
|
10877
10883
|
}
|
|
10878
10884
|
}
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
}
|
|
10885
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
10886
|
+
// any broadcast grants that may have been in connectionGrants
|
|
10887
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
10888
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
10884
10889
|
}
|
|
10885
10890
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
10886
10891
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -12679,15 +12684,29 @@ class DefaultNodeAttachClient {
|
|
|
12679
12684
|
constructor(options = {}) {
|
|
12680
12685
|
this.buffer = [];
|
|
12681
12686
|
this.inHandshake = false;
|
|
12687
|
+
this.expectedSystemId = null;
|
|
12682
12688
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
12683
12689
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
12684
12690
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
12685
12691
|
}
|
|
12686
12692
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
12687
12693
|
this.inHandshake = true;
|
|
12694
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
12688
12695
|
const interimHandler = async (envelope, context) => {
|
|
12689
12696
|
if (this.inHandshake) {
|
|
12690
|
-
|
|
12697
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
12698
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
12699
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
12700
|
+
this.buffer.push(envelope);
|
|
12701
|
+
}
|
|
12702
|
+
else {
|
|
12703
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
12704
|
+
logger$W.debug('handshake_ignoring_frame_from_different_system', {
|
|
12705
|
+
frame_type: envelope.frame.type,
|
|
12706
|
+
frame_system_id: frameSystemId,
|
|
12707
|
+
expected_system_id: this.expectedSystemId,
|
|
12708
|
+
});
|
|
12709
|
+
}
|
|
12691
12710
|
return null;
|
|
12692
12711
|
}
|
|
12693
12712
|
return finalHandler(envelope, context);
|
|
@@ -12814,6 +12833,7 @@ class DefaultNodeAttachClient {
|
|
|
12814
12833
|
parent_id: ackFrame.targetSystemId,
|
|
12815
12834
|
});
|
|
12816
12835
|
this.inHandshake = false;
|
|
12836
|
+
this.expectedSystemId = null;
|
|
12817
12837
|
await connector.replaceHandler(finalHandler);
|
|
12818
12838
|
while (this.buffer.length > 0) {
|
|
12819
12839
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -12890,9 +12910,20 @@ class DefaultNodeAttachClient {
|
|
|
12890
12910
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
12891
12911
|
return envelope;
|
|
12892
12912
|
}
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12913
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
12914
|
+
// where multiple agents attach concurrently to the same channel
|
|
12915
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
12916
|
+
logger$W.debug('handshake_ignoring_concurrent_attach', {
|
|
12917
|
+
frame_type: envelope.frame.type,
|
|
12918
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
12919
|
+
});
|
|
12920
|
+
}
|
|
12921
|
+
else {
|
|
12922
|
+
// Other unexpected frames are still logged as errors
|
|
12923
|
+
logger$W.error('unexpected_frame_during_handshake', {
|
|
12924
|
+
frame_type: envelope.frame.type,
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12896
12927
|
}
|
|
12897
12928
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
12898
12929
|
}
|
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.6-test.
|
|
99
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
100
100
|
/**
|
|
101
101
|
* The package version, injected at build time.
|
|
102
102
|
* @internal
|
|
103
103
|
*/
|
|
104
|
-
const VERSION = '0.3.6-test.
|
|
104
|
+
const VERSION = '0.3.6-test.103';
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -10861,6 +10861,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10861
10861
|
await connector.start(this.wrappedHandler);
|
|
10862
10862
|
this.connector = connector;
|
|
10863
10863
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
10864
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
10865
|
+
// This prevents adding duplicate broadcast grants
|
|
10866
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
10867
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
10868
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
10869
|
+
: null;
|
|
10864
10870
|
// Include admission client's connection grants as callback grants
|
|
10865
10871
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
10866
10872
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -10874,11 +10880,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10874
10880
|
}
|
|
10875
10881
|
}
|
|
10876
10882
|
}
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
}
|
|
10883
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
10884
|
+
// any broadcast grants that may have been in connectionGrants
|
|
10885
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
10886
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
10882
10887
|
}
|
|
10883
10888
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
10884
10889
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -12677,15 +12682,29 @@ class DefaultNodeAttachClient {
|
|
|
12677
12682
|
constructor(options = {}) {
|
|
12678
12683
|
this.buffer = [];
|
|
12679
12684
|
this.inHandshake = false;
|
|
12685
|
+
this.expectedSystemId = null;
|
|
12680
12686
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
12681
12687
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
12682
12688
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
12683
12689
|
}
|
|
12684
12690
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
12685
12691
|
this.inHandshake = true;
|
|
12692
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
12686
12693
|
const interimHandler = async (envelope, context) => {
|
|
12687
12694
|
if (this.inHandshake) {
|
|
12688
|
-
|
|
12695
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
12696
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
12697
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
12698
|
+
this.buffer.push(envelope);
|
|
12699
|
+
}
|
|
12700
|
+
else {
|
|
12701
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
12702
|
+
logger$W.debug('handshake_ignoring_frame_from_different_system', {
|
|
12703
|
+
frame_type: envelope.frame.type,
|
|
12704
|
+
frame_system_id: frameSystemId,
|
|
12705
|
+
expected_system_id: this.expectedSystemId,
|
|
12706
|
+
});
|
|
12707
|
+
}
|
|
12689
12708
|
return null;
|
|
12690
12709
|
}
|
|
12691
12710
|
return finalHandler(envelope, context);
|
|
@@ -12812,6 +12831,7 @@ class DefaultNodeAttachClient {
|
|
|
12812
12831
|
parent_id: ackFrame.targetSystemId,
|
|
12813
12832
|
});
|
|
12814
12833
|
this.inHandshake = false;
|
|
12834
|
+
this.expectedSystemId = null;
|
|
12815
12835
|
await connector.replaceHandler(finalHandler);
|
|
12816
12836
|
while (this.buffer.length > 0) {
|
|
12817
12837
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -12888,9 +12908,20 @@ class DefaultNodeAttachClient {
|
|
|
12888
12908
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
12889
12909
|
return envelope;
|
|
12890
12910
|
}
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12911
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
12912
|
+
// where multiple agents attach concurrently to the same channel
|
|
12913
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
12914
|
+
logger$W.debug('handshake_ignoring_concurrent_attach', {
|
|
12915
|
+
frame_type: envelope.frame.type,
|
|
12916
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
12917
|
+
});
|
|
12918
|
+
}
|
|
12919
|
+
else {
|
|
12920
|
+
// Other unexpected frames are still logged as errors
|
|
12921
|
+
logger$W.error('unexpected_frame_during_handshake', {
|
|
12922
|
+
frame_type: envelope.frame.type,
|
|
12923
|
+
});
|
|
12924
|
+
}
|
|
12894
12925
|
}
|
|
12895
12926
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
12896
12927
|
}
|
|
@@ -11,15 +11,29 @@ class DefaultNodeAttachClient {
|
|
|
11
11
|
constructor(options = {}) {
|
|
12
12
|
this.buffer = [];
|
|
13
13
|
this.inHandshake = false;
|
|
14
|
+
this.expectedSystemId = null;
|
|
14
15
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
15
16
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
16
17
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
17
18
|
}
|
|
18
19
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
19
20
|
this.inHandshake = true;
|
|
21
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
20
22
|
const interimHandler = async (envelope, context) => {
|
|
21
23
|
if (this.inHandshake) {
|
|
22
|
-
|
|
24
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
25
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
26
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
27
|
+
this.buffer.push(envelope);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
31
|
+
logger.debug('handshake_ignoring_frame_from_different_system', {
|
|
32
|
+
frame_type: envelope.frame.type,
|
|
33
|
+
frame_system_id: frameSystemId,
|
|
34
|
+
expected_system_id: this.expectedSystemId,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
23
37
|
return null;
|
|
24
38
|
}
|
|
25
39
|
return finalHandler(envelope, context);
|
|
@@ -146,6 +160,7 @@ class DefaultNodeAttachClient {
|
|
|
146
160
|
parent_id: ackFrame.targetSystemId,
|
|
147
161
|
});
|
|
148
162
|
this.inHandshake = false;
|
|
163
|
+
this.expectedSystemId = null;
|
|
149
164
|
await connector.replaceHandler(finalHandler);
|
|
150
165
|
while (this.buffer.length > 0) {
|
|
151
166
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -222,9 +237,20 @@ class DefaultNodeAttachClient {
|
|
|
222
237
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
223
238
|
return envelope;
|
|
224
239
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
240
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
241
|
+
// where multiple agents attach concurrently to the same channel
|
|
242
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
243
|
+
logger.debug('handshake_ignoring_concurrent_attach', {
|
|
244
|
+
frame_type: envelope.frame.type,
|
|
245
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// Other unexpected frames are still logged as errors
|
|
250
|
+
logger.error('unexpected_frame_during_handshake', {
|
|
251
|
+
frame_type: envelope.frame.type,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
228
254
|
}
|
|
229
255
|
await (0, task_utils_js_1.delay)(HANDSHAKE_POLL_INTERVAL_MS);
|
|
230
256
|
}
|
|
@@ -321,6 +321,12 @@ class UpstreamSessionManager extends task_spawner_js_1.TaskSpawner {
|
|
|
321
321
|
await connector.start(this.wrappedHandler);
|
|
322
322
|
this.connector = connector;
|
|
323
323
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
324
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
325
|
+
// This prevents adding duplicate broadcast grants
|
|
326
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
327
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
328
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
329
|
+
: null;
|
|
324
330
|
// Include admission client's connection grants as callback grants
|
|
325
331
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
326
332
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -334,11 +340,10 @@ class UpstreamSessionManager extends task_spawner_js_1.TaskSpawner {
|
|
|
334
340
|
}
|
|
335
341
|
}
|
|
336
342
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
343
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
344
|
+
// any broadcast grants that may have been in connectionGrants
|
|
345
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
346
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
342
347
|
}
|
|
343
348
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
344
349
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
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.6-test.
|
|
3
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
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.6-test.
|
|
10
|
+
exports.VERSION = '0.3.6-test.103';
|
|
@@ -8,15 +8,29 @@ export class DefaultNodeAttachClient {
|
|
|
8
8
|
constructor(options = {}) {
|
|
9
9
|
this.buffer = [];
|
|
10
10
|
this.inHandshake = false;
|
|
11
|
+
this.expectedSystemId = null;
|
|
11
12
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
12
13
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
13
14
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
14
15
|
}
|
|
15
16
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
16
17
|
this.inHandshake = true;
|
|
18
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
17
19
|
const interimHandler = async (envelope, context) => {
|
|
18
20
|
if (this.inHandshake) {
|
|
19
|
-
|
|
21
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
22
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
23
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
24
|
+
this.buffer.push(envelope);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
28
|
+
logger.debug('handshake_ignoring_frame_from_different_system', {
|
|
29
|
+
frame_type: envelope.frame.type,
|
|
30
|
+
frame_system_id: frameSystemId,
|
|
31
|
+
expected_system_id: this.expectedSystemId,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
20
34
|
return null;
|
|
21
35
|
}
|
|
22
36
|
return finalHandler(envelope, context);
|
|
@@ -143,6 +157,7 @@ export class DefaultNodeAttachClient {
|
|
|
143
157
|
parent_id: ackFrame.targetSystemId,
|
|
144
158
|
});
|
|
145
159
|
this.inHandshake = false;
|
|
160
|
+
this.expectedSystemId = null;
|
|
146
161
|
await connector.replaceHandler(finalHandler);
|
|
147
162
|
while (this.buffer.length > 0) {
|
|
148
163
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -219,9 +234,20 @@ export class DefaultNodeAttachClient {
|
|
|
219
234
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
220
235
|
return envelope;
|
|
221
236
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
237
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
238
|
+
// where multiple agents attach concurrently to the same channel
|
|
239
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
240
|
+
logger.debug('handshake_ignoring_concurrent_attach', {
|
|
241
|
+
frame_type: envelope.frame.type,
|
|
242
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// Other unexpected frames are still logged as errors
|
|
247
|
+
logger.error('unexpected_frame_during_handshake', {
|
|
248
|
+
frame_type: envelope.frame.type,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
225
251
|
}
|
|
226
252
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
227
253
|
}
|
|
@@ -318,6 +318,12 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
318
318
|
await connector.start(this.wrappedHandler);
|
|
319
319
|
this.connector = connector;
|
|
320
320
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
321
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
322
|
+
// This prevents adding duplicate broadcast grants
|
|
323
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
324
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
325
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
326
|
+
: null;
|
|
321
327
|
// Include admission client's connection grants as callback grants
|
|
322
328
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
323
329
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -331,11 +337,10 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
331
337
|
}
|
|
332
338
|
}
|
|
333
339
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
340
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
341
|
+
// any broadcast grants that may have been in connectionGrants
|
|
342
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
343
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
339
344
|
}
|
|
340
345
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
341
346
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
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.6-test.
|
|
2
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
3
3
|
/**
|
|
4
4
|
* The package version, injected at build time.
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.3.6-test.
|
|
7
|
+
export const VERSION = '0.3.6-test.103';
|
package/dist/node/index.cjs
CHANGED
|
@@ -14,12 +14,12 @@ var fastify = require('fastify');
|
|
|
14
14
|
var websocketPlugin = require('@fastify/websocket');
|
|
15
15
|
|
|
16
16
|
// This file is auto-generated during build - do not edit manually
|
|
17
|
-
// Generated from package.json version: 0.3.6-test.
|
|
17
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
18
18
|
/**
|
|
19
19
|
* The package version, injected at build time.
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
|
-
const VERSION = '0.3.6-test.
|
|
22
|
+
const VERSION = '0.3.6-test.103';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -10779,6 +10779,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10779
10779
|
await connector.start(this.wrappedHandler);
|
|
10780
10780
|
this.connector = connector;
|
|
10781
10781
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
10782
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
10783
|
+
// This prevents adding duplicate broadcast grants
|
|
10784
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
10785
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
10786
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
10787
|
+
: null;
|
|
10782
10788
|
// Include admission client's connection grants as callback grants
|
|
10783
10789
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
10784
10790
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -10792,11 +10798,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10792
10798
|
}
|
|
10793
10799
|
}
|
|
10794
10800
|
}
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
}
|
|
10801
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
10802
|
+
// any broadcast grants that may have been in connectionGrants
|
|
10803
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
10804
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
10800
10805
|
}
|
|
10801
10806
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
10802
10807
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -12595,15 +12600,29 @@ class DefaultNodeAttachClient {
|
|
|
12595
12600
|
constructor(options = {}) {
|
|
12596
12601
|
this.buffer = [];
|
|
12597
12602
|
this.inHandshake = false;
|
|
12603
|
+
this.expectedSystemId = null;
|
|
12598
12604
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
12599
12605
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
12600
12606
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
12601
12607
|
}
|
|
12602
12608
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
12603
12609
|
this.inHandshake = true;
|
|
12610
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
12604
12611
|
const interimHandler = async (envelope, context) => {
|
|
12605
12612
|
if (this.inHandshake) {
|
|
12606
|
-
|
|
12613
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
12614
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
12615
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
12616
|
+
this.buffer.push(envelope);
|
|
12617
|
+
}
|
|
12618
|
+
else {
|
|
12619
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
12620
|
+
logger$W.debug('handshake_ignoring_frame_from_different_system', {
|
|
12621
|
+
frame_type: envelope.frame.type,
|
|
12622
|
+
frame_system_id: frameSystemId,
|
|
12623
|
+
expected_system_id: this.expectedSystemId,
|
|
12624
|
+
});
|
|
12625
|
+
}
|
|
12607
12626
|
return null;
|
|
12608
12627
|
}
|
|
12609
12628
|
return finalHandler(envelope, context);
|
|
@@ -12730,6 +12749,7 @@ class DefaultNodeAttachClient {
|
|
|
12730
12749
|
parent_id: ackFrame.targetSystemId,
|
|
12731
12750
|
});
|
|
12732
12751
|
this.inHandshake = false;
|
|
12752
|
+
this.expectedSystemId = null;
|
|
12733
12753
|
await connector.replaceHandler(finalHandler);
|
|
12734
12754
|
while (this.buffer.length > 0) {
|
|
12735
12755
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -12806,9 +12826,20 @@ class DefaultNodeAttachClient {
|
|
|
12806
12826
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
12807
12827
|
return envelope;
|
|
12808
12828
|
}
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12829
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
12830
|
+
// where multiple agents attach concurrently to the same channel
|
|
12831
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
12832
|
+
logger$W.debug('handshake_ignoring_concurrent_attach', {
|
|
12833
|
+
frame_type: envelope.frame.type,
|
|
12834
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
12835
|
+
});
|
|
12836
|
+
}
|
|
12837
|
+
else {
|
|
12838
|
+
// Other unexpected frames are still logged as errors
|
|
12839
|
+
logger$W.error('unexpected_frame_during_handshake', {
|
|
12840
|
+
frame_type: envelope.frame.type,
|
|
12841
|
+
});
|
|
12842
|
+
}
|
|
12812
12843
|
}
|
|
12813
12844
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
12814
12845
|
}
|
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.6-test.
|
|
16
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
17
17
|
/**
|
|
18
18
|
* The package version, injected at build time.
|
|
19
19
|
* @internal
|
|
20
20
|
*/
|
|
21
|
-
const VERSION = '0.3.6-test.
|
|
21
|
+
const VERSION = '0.3.6-test.103';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Fame protocol specific error classes with WebSocket close codes and proper inheritance.
|
|
@@ -10778,6 +10778,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10778
10778
|
await connector.start(this.wrappedHandler);
|
|
10779
10779
|
this.connector = connector;
|
|
10780
10780
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
10781
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
10782
|
+
// This prevents adding duplicate broadcast grants
|
|
10783
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
10784
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
10785
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
10786
|
+
: null;
|
|
10781
10787
|
// Include admission client's connection grants as callback grants
|
|
10782
10788
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
10783
10789
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -10791,11 +10797,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
10791
10797
|
}
|
|
10792
10798
|
}
|
|
10793
10799
|
}
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
}
|
|
10800
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
10801
|
+
// any broadcast grants that may have been in connectionGrants
|
|
10802
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
10803
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
10799
10804
|
}
|
|
10800
10805
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
10801
10806
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -12594,15 +12599,29 @@ class DefaultNodeAttachClient {
|
|
|
12594
12599
|
constructor(options = {}) {
|
|
12595
12600
|
this.buffer = [];
|
|
12596
12601
|
this.inHandshake = false;
|
|
12602
|
+
this.expectedSystemId = null;
|
|
12597
12603
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
12598
12604
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
12599
12605
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
12600
12606
|
}
|
|
12601
12607
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
12602
12608
|
this.inHandshake = true;
|
|
12609
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
12603
12610
|
const interimHandler = async (envelope, context) => {
|
|
12604
12611
|
if (this.inHandshake) {
|
|
12605
|
-
|
|
12612
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
12613
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
12614
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
12615
|
+
this.buffer.push(envelope);
|
|
12616
|
+
}
|
|
12617
|
+
else {
|
|
12618
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
12619
|
+
logger$W.debug('handshake_ignoring_frame_from_different_system', {
|
|
12620
|
+
frame_type: envelope.frame.type,
|
|
12621
|
+
frame_system_id: frameSystemId,
|
|
12622
|
+
expected_system_id: this.expectedSystemId,
|
|
12623
|
+
});
|
|
12624
|
+
}
|
|
12606
12625
|
return null;
|
|
12607
12626
|
}
|
|
12608
12627
|
return finalHandler(envelope, context);
|
|
@@ -12729,6 +12748,7 @@ class DefaultNodeAttachClient {
|
|
|
12729
12748
|
parent_id: ackFrame.targetSystemId,
|
|
12730
12749
|
});
|
|
12731
12750
|
this.inHandshake = false;
|
|
12751
|
+
this.expectedSystemId = null;
|
|
12732
12752
|
await connector.replaceHandler(finalHandler);
|
|
12733
12753
|
while (this.buffer.length > 0) {
|
|
12734
12754
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -12805,9 +12825,20 @@ class DefaultNodeAttachClient {
|
|
|
12805
12825
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
12806
12826
|
return envelope;
|
|
12807
12827
|
}
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12828
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
12829
|
+
// where multiple agents attach concurrently to the same channel
|
|
12830
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
12831
|
+
logger$W.debug('handshake_ignoring_concurrent_attach', {
|
|
12832
|
+
frame_type: envelope.frame.type,
|
|
12833
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
12834
|
+
});
|
|
12835
|
+
}
|
|
12836
|
+
else {
|
|
12837
|
+
// Other unexpected frames are still logged as errors
|
|
12838
|
+
logger$W.error('unexpected_frame_during_handshake', {
|
|
12839
|
+
frame_type: envelope.frame.type,
|
|
12840
|
+
});
|
|
12841
|
+
}
|
|
12811
12842
|
}
|
|
12812
12843
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
12813
12844
|
}
|
package/dist/node/node.cjs
CHANGED
|
@@ -5563,12 +5563,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
|
|
|
5563
5563
|
}
|
|
5564
5564
|
|
|
5565
5565
|
// This file is auto-generated during build - do not edit manually
|
|
5566
|
-
// Generated from package.json version: 0.3.6-test.
|
|
5566
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
5567
5567
|
/**
|
|
5568
5568
|
* The package version, injected at build time.
|
|
5569
5569
|
* @internal
|
|
5570
5570
|
*/
|
|
5571
|
-
const VERSION = '0.3.6-test.
|
|
5571
|
+
const VERSION = '0.3.6-test.103';
|
|
5572
5572
|
|
|
5573
5573
|
/**
|
|
5574
5574
|
* Fame errors module - Fame protocol specific error classes
|
|
@@ -12471,6 +12471,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
12471
12471
|
await connector.start(this.wrappedHandler);
|
|
12472
12472
|
this.connector = connector;
|
|
12473
12473
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
12474
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
12475
|
+
// This prevents adding duplicate broadcast grants
|
|
12476
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
12477
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
12478
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
12479
|
+
: null;
|
|
12474
12480
|
// Include admission client's connection grants as callback grants
|
|
12475
12481
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
12476
12482
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -12484,11 +12490,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
12484
12490
|
}
|
|
12485
12491
|
}
|
|
12486
12492
|
}
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
}
|
|
12493
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
12494
|
+
// any broadcast grants that may have been in connectionGrants
|
|
12495
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
12496
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
12492
12497
|
}
|
|
12493
12498
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
12494
12499
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -14287,15 +14292,29 @@ class DefaultNodeAttachClient {
|
|
|
14287
14292
|
constructor(options = {}) {
|
|
14288
14293
|
this.buffer = [];
|
|
14289
14294
|
this.inHandshake = false;
|
|
14295
|
+
this.expectedSystemId = null;
|
|
14290
14296
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
14291
14297
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
14292
14298
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
14293
14299
|
}
|
|
14294
14300
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
14295
14301
|
this.inHandshake = true;
|
|
14302
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
14296
14303
|
const interimHandler = async (envelope, context) => {
|
|
14297
14304
|
if (this.inHandshake) {
|
|
14298
|
-
|
|
14305
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
14306
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
14307
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
14308
|
+
this.buffer.push(envelope);
|
|
14309
|
+
}
|
|
14310
|
+
else {
|
|
14311
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
14312
|
+
logger$Y.debug('handshake_ignoring_frame_from_different_system', {
|
|
14313
|
+
frame_type: envelope.frame.type,
|
|
14314
|
+
frame_system_id: frameSystemId,
|
|
14315
|
+
expected_system_id: this.expectedSystemId,
|
|
14316
|
+
});
|
|
14317
|
+
}
|
|
14299
14318
|
return null;
|
|
14300
14319
|
}
|
|
14301
14320
|
return finalHandler(envelope, context);
|
|
@@ -14422,6 +14441,7 @@ class DefaultNodeAttachClient {
|
|
|
14422
14441
|
parent_id: ackFrame.targetSystemId,
|
|
14423
14442
|
});
|
|
14424
14443
|
this.inHandshake = false;
|
|
14444
|
+
this.expectedSystemId = null;
|
|
14425
14445
|
await connector.replaceHandler(finalHandler);
|
|
14426
14446
|
while (this.buffer.length > 0) {
|
|
14427
14447
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -14498,9 +14518,20 @@ class DefaultNodeAttachClient {
|
|
|
14498
14518
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
14499
14519
|
return envelope;
|
|
14500
14520
|
}
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
-
|
|
14521
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
14522
|
+
// where multiple agents attach concurrently to the same channel
|
|
14523
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
14524
|
+
logger$Y.debug('handshake_ignoring_concurrent_attach', {
|
|
14525
|
+
frame_type: envelope.frame.type,
|
|
14526
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
14527
|
+
});
|
|
14528
|
+
}
|
|
14529
|
+
else {
|
|
14530
|
+
// Other unexpected frames are still logged as errors
|
|
14531
|
+
logger$Y.error('unexpected_frame_during_handshake', {
|
|
14532
|
+
frame_type: envelope.frame.type,
|
|
14533
|
+
});
|
|
14534
|
+
}
|
|
14504
14535
|
}
|
|
14505
14536
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
14506
14537
|
}
|
package/dist/node/node.mjs
CHANGED
|
@@ -5562,12 +5562,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
|
|
|
5562
5562
|
}
|
|
5563
5563
|
|
|
5564
5564
|
// This file is auto-generated during build - do not edit manually
|
|
5565
|
-
// Generated from package.json version: 0.3.6-test.
|
|
5565
|
+
// Generated from package.json version: 0.3.6-test.103
|
|
5566
5566
|
/**
|
|
5567
5567
|
* The package version, injected at build time.
|
|
5568
5568
|
* @internal
|
|
5569
5569
|
*/
|
|
5570
|
-
const VERSION = '0.3.6-test.
|
|
5570
|
+
const VERSION = '0.3.6-test.103';
|
|
5571
5571
|
|
|
5572
5572
|
/**
|
|
5573
5573
|
* Fame errors module - Fame protocol specific error classes
|
|
@@ -12470,6 +12470,12 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
12470
12470
|
await connector.start(this.wrappedHandler);
|
|
12471
12471
|
this.connector = connector;
|
|
12472
12472
|
const callbackGrants = this.node.gatherSupportedCallbackGrants();
|
|
12473
|
+
// Check if we should create a broadcast callback grant before processing connection grants
|
|
12474
|
+
// This prevents adding duplicate broadcast grants
|
|
12475
|
+
const shouldAddBroadcastGrant = this.shouldAdvertiseBroadcastGrant(grant, callbackGrants);
|
|
12476
|
+
const broadcastCallbackGrant = shouldAddBroadcastGrant
|
|
12477
|
+
? this.createBroadcastCallbackGrant(grant)
|
|
12478
|
+
: null;
|
|
12473
12479
|
// Include admission client's connection grants as callback grants
|
|
12474
12480
|
// This ensures DirectAdmissionClient grants are available for grant selection
|
|
12475
12481
|
if (welcome.frame.connectionGrants && Array.isArray(welcome.frame.connectionGrants)) {
|
|
@@ -12483,11 +12489,10 @@ class UpstreamSessionManager extends TaskSpawner {
|
|
|
12483
12489
|
}
|
|
12484
12490
|
}
|
|
12485
12491
|
}
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
}
|
|
12492
|
+
// Add broadcast grant after connection grants to ensure we don't duplicate
|
|
12493
|
+
// any broadcast grants that may have been in connectionGrants
|
|
12494
|
+
if (broadcastCallbackGrant && this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
|
|
12495
|
+
callbackGrants.push(broadcastCallbackGrant);
|
|
12491
12496
|
}
|
|
12492
12497
|
const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
|
|
12493
12498
|
this.targetSystemId = attachInfo.targetSystemId ?? null;
|
|
@@ -14286,15 +14291,29 @@ class DefaultNodeAttachClient {
|
|
|
14286
14291
|
constructor(options = {}) {
|
|
14287
14292
|
this.buffer = [];
|
|
14288
14293
|
this.inHandshake = false;
|
|
14294
|
+
this.expectedSystemId = null;
|
|
14289
14295
|
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
14290
14296
|
this.attachmentKeyValidator = options.attachmentKeyValidator;
|
|
14291
14297
|
this.replicaStickinessManager = options.replicaStickinessManager ?? null;
|
|
14292
14298
|
}
|
|
14293
14299
|
async attach(node, originType, connector, welcomeFrame, finalHandler, keys, callbackGrants) {
|
|
14294
14300
|
this.inHandshake = true;
|
|
14301
|
+
this.expectedSystemId = welcomeFrame.systemId;
|
|
14295
14302
|
const interimHandler = async (envelope, context) => {
|
|
14296
14303
|
if (this.inHandshake) {
|
|
14297
|
-
|
|
14304
|
+
// Filter: only buffer frames related to our systemId or frames without systemId info
|
|
14305
|
+
const frameSystemId = envelope.frame?.systemId;
|
|
14306
|
+
if (!frameSystemId || frameSystemId === this.expectedSystemId) {
|
|
14307
|
+
this.buffer.push(envelope);
|
|
14308
|
+
}
|
|
14309
|
+
else {
|
|
14310
|
+
// Silently ignore frames from other agents during concurrent handshakes
|
|
14311
|
+
logger$Y.debug('handshake_ignoring_frame_from_different_system', {
|
|
14312
|
+
frame_type: envelope.frame.type,
|
|
14313
|
+
frame_system_id: frameSystemId,
|
|
14314
|
+
expected_system_id: this.expectedSystemId,
|
|
14315
|
+
});
|
|
14316
|
+
}
|
|
14298
14317
|
return null;
|
|
14299
14318
|
}
|
|
14300
14319
|
return finalHandler(envelope, context);
|
|
@@ -14421,6 +14440,7 @@ class DefaultNodeAttachClient {
|
|
|
14421
14440
|
parent_id: ackFrame.targetSystemId,
|
|
14422
14441
|
});
|
|
14423
14442
|
this.inHandshake = false;
|
|
14443
|
+
this.expectedSystemId = null;
|
|
14424
14444
|
await connector.replaceHandler(finalHandler);
|
|
14425
14445
|
while (this.buffer.length > 0) {
|
|
14426
14446
|
const bufferedEnvelope = this.buffer.shift();
|
|
@@ -14497,9 +14517,20 @@ class DefaultNodeAttachClient {
|
|
|
14497
14517
|
if (envelope.frame.type === 'NodeAttachAck') {
|
|
14498
14518
|
return envelope;
|
|
14499
14519
|
}
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14520
|
+
// NodeAttach frames during handshake are expected in multi-agent scenarios
|
|
14521
|
+
// where multiple agents attach concurrently to the same channel
|
|
14522
|
+
if (envelope.frame.type === 'NodeAttach') {
|
|
14523
|
+
logger$Y.debug('handshake_ignoring_concurrent_attach', {
|
|
14524
|
+
frame_type: envelope.frame.type,
|
|
14525
|
+
frame_system_id: envelope.frame?.systemId ?? 'unknown',
|
|
14526
|
+
});
|
|
14527
|
+
}
|
|
14528
|
+
else {
|
|
14529
|
+
// Other unexpected frames are still logged as errors
|
|
14530
|
+
logger$Y.error('unexpected_frame_during_handshake', {
|
|
14531
|
+
frame_type: envelope.frame.type,
|
|
14532
|
+
});
|
|
14533
|
+
}
|
|
14503
14534
|
}
|
|
14504
14535
|
await delay(HANDSHAKE_POLL_INTERVAL_MS);
|
|
14505
14536
|
}
|
|
@@ -14,6 +14,7 @@ export declare class DefaultNodeAttachClient implements NodeAttachClient {
|
|
|
14
14
|
private readonly replicaStickinessManager;
|
|
15
15
|
private readonly buffer;
|
|
16
16
|
private inHandshake;
|
|
17
|
+
private expectedSystemId;
|
|
17
18
|
constructor(options?: DefaultNodeAttachClientOptions);
|
|
18
19
|
attach(node: NodeLike, originType: DeliveryOriginType, connector: FameConnector, welcomeFrame: NodeWelcomeFrame, finalHandler: FameEnvelopeHandler, keys?: Array<Record<string, unknown>>, callbackGrants?: Array<Record<string, unknown>>): Promise<AttachInfo>;
|
|
19
20
|
private awaitAck;
|
package/dist/types/version.d.ts
CHANGED