@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.
@@ -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
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
10880
- const augmented = this.createBroadcastCallbackGrant(grant);
10881
- if (augmented) {
10882
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$W.error('unexpected_frame_during_handshake', {
12894
- frame_type: envelope.frame.type,
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
  }
@@ -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.101
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
10878
- const augmented = this.createBroadcastCallbackGrant(grant);
10879
- if (augmented) {
10880
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$W.error('unexpected_frame_during_handshake', {
12892
- frame_type: envelope.frame.type,
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
- this.buffer.push(envelope);
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
- logger.error('unexpected_frame_during_handshake', {
226
- frame_type: envelope.frame.type,
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
338
- const augmented = this.createBroadcastCallbackGrant(grant);
339
- if (augmented) {
340
- callbackGrants.push(augmented);
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;
@@ -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.101
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.101';
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
- this.buffer.push(envelope);
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
- logger.error('unexpected_frame_during_handshake', {
223
- frame_type: envelope.frame.type,
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
335
- const augmented = this.createBroadcastCallbackGrant(grant);
336
- if (augmented) {
337
- callbackGrants.push(augmented);
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;
@@ -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.101
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.101';
7
+ export const VERSION = '0.3.6-test.103';
@@ -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.101
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
10796
- const augmented = this.createBroadcastCallbackGrant(grant);
10797
- if (augmented) {
10798
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$W.error('unexpected_frame_during_handshake', {
12810
- frame_type: envelope.frame.type,
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
  }
@@ -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.101
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
10795
- const augmented = this.createBroadcastCallbackGrant(grant);
10796
- if (augmented) {
10797
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$W.error('unexpected_frame_during_handshake', {
12809
- frame_type: envelope.frame.type,
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
  }
@@ -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.101
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
12488
- const augmented = this.createBroadcastCallbackGrant(grant);
12489
- if (augmented) {
12490
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$Y.error('unexpected_frame_during_handshake', {
14502
- frame_type: envelope.frame.type,
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
  }
@@ -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.101
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.101';
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
- if (this.shouldAdvertiseBroadcastGrant(grant, callbackGrants)) {
12487
- const augmented = this.createBroadcastCallbackGrant(grant);
12488
- if (augmented) {
12489
- callbackGrants.push(augmented);
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
- this.buffer.push(envelope);
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
- logger$Y.error('unexpected_frame_during_handshake', {
14501
- frame_type: envelope.frame.type,
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;
@@ -2,4 +2,4 @@
2
2
  * The package version, injected at build time.
3
3
  * @internal
4
4
  */
5
- export declare const VERSION = "0.3.6-test.101";
5
+ export declare const VERSION = "0.3.6-test.103";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naylence/runtime",
3
- "version": "0.3.6-test.101",
3
+ "version": "0.3.6-test.103",
4
4
  "type": "module",
5
5
  "description": "Naylence Runtime - Complete TypeScript runtime",
6
6
  "author": "Naylence Dev <naylencedev@gmail.com>",