@naylence/runtime 0.3.5-test.961 → 0.3.5-test.962

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.
@@ -324,7 +324,7 @@ export class BroadcastChannelListener extends TransportListener {
324
324
  node: routingNode,
325
325
  });
326
326
  const selection = defaultGrantSelectionPolicy.selectCallbackGrant(selectionContext);
327
- connectorConfig = this._grantToConnectorConfig(selection.grant);
327
+ connectorConfig = this._grantToConnectorConfig(selection.grant, systemId);
328
328
  }
329
329
  catch (error) {
330
330
  logger.debug('broadcast_channel_listener_grant_selection_failed', {
@@ -333,13 +333,20 @@ export class BroadcastChannelListener extends TransportListener {
333
333
  error: error instanceof Error ? error.message : String(error),
334
334
  });
335
335
  connectorConfig =
336
- this._extractBroadcastConnectorConfig(frame) ??
337
- {
336
+ this._extractBroadcastConnectorConfig(frame, systemId) ??
337
+ this._buildConnectorConfigForSystem(systemId, {
338
338
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
339
339
  channelName: this._channelName,
340
340
  inboxCapacity: this._inboxCapacity,
341
341
  passive: true,
342
- };
342
+ });
343
+ }
344
+ if (!connectorConfig) {
345
+ logger.error('broadcast_channel_listener_missing_connector_config', {
346
+ sender_id: params.senderId,
347
+ system_id: systemId,
348
+ });
349
+ return null;
343
350
  }
344
351
  try {
345
352
  const connector = await routingNode.createOriginConnector({
@@ -365,7 +372,7 @@ export class BroadcastChannelListener extends TransportListener {
365
372
  return null;
366
373
  }
367
374
  }
368
- _extractBroadcastConnectorConfig(frame) {
375
+ _extractBroadcastConnectorConfig(frame, systemId) {
369
376
  const rawGrants = frame.callbackGrants;
370
377
  if (!Array.isArray(rawGrants)) {
371
378
  return null;
@@ -376,7 +383,10 @@ export class BroadcastChannelListener extends TransportListener {
376
383
  (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE ||
377
384
  grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE)) {
378
385
  try {
379
- return this._grantToConnectorConfig(grant);
386
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE) {
387
+ return this._buildConnectorConfigForSystem(systemId, grant);
388
+ }
389
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
380
390
  }
381
391
  catch (error) {
382
392
  logger.debug('broadcast_channel_listener_grant_normalization_failed', {
@@ -387,31 +397,87 @@ export class BroadcastChannelListener extends TransportListener {
387
397
  }
388
398
  return null;
389
399
  }
390
- _grantToConnectorConfig(grant) {
391
- if (grant.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE) {
392
- if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
393
- return broadcastChannelGrantToConnectorConfig(grant);
400
+ _grantToConnectorConfig(grant, systemId) {
401
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE) {
402
+ return this._buildConnectorConfigForSystem(systemId, grant);
403
+ }
404
+ if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
405
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
406
+ }
407
+ if ('toConnectorConfig' in grant &&
408
+ typeof grant.toConnectorConfig ===
409
+ 'function') {
410
+ const normalized = grant.toConnectorConfig();
411
+ if (normalized.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE) {
412
+ throw new Error(`Unsupported grant connector type: ${normalized.type}`);
394
413
  }
395
- throw new Error(`Unsupported grant type: ${grant.type}`);
414
+ return this._buildConnectorConfigForSystem(systemId, normalized);
396
415
  }
397
- const candidate = grant;
398
- const config = {
416
+ throw new Error(`Unsupported grant type: ${grant.type}`);
417
+ }
418
+ _buildConnectorConfigForSystem(systemId, baseConfig) {
419
+ const localNodeId = this._requireLocalNodeId();
420
+ const targetSystemId = this._normalizeNodeId(systemId);
421
+ if (!targetSystemId) {
422
+ throw new Error('BroadcastChannelListener requires a valid system id');
423
+ }
424
+ const candidate = baseConfig ?? null;
425
+ const channelCandidate = candidate && 'channelName' in candidate
426
+ ? candidate.channelName
427
+ : undefined;
428
+ const inboxCandidate = candidate && 'inboxCapacity' in candidate
429
+ ? candidate.inboxCapacity
430
+ : undefined;
431
+ const initialWindowCandidate = candidate && 'initialWindow' in candidate
432
+ ? candidate.initialWindow
433
+ : undefined;
434
+ const passiveCandidate = candidate && 'passive' in candidate
435
+ ? candidate.passive
436
+ : undefined;
437
+ const targetCandidate = candidate && 'initialTargetNodeId' in candidate
438
+ ? candidate.initialTargetNodeId
439
+ : undefined;
440
+ const channelName = typeof channelCandidate === 'string' && channelCandidate.trim().length > 0
441
+ ? channelCandidate.trim()
442
+ : this._channelName;
443
+ const inboxCapacity = typeof inboxCandidate === 'number' &&
444
+ Number.isFinite(inboxCandidate) &&
445
+ inboxCandidate > 0
446
+ ? Math.floor(inboxCandidate)
447
+ : this._inboxCapacity;
448
+ const initialWindow = typeof initialWindowCandidate === 'number' &&
449
+ Number.isFinite(initialWindowCandidate) &&
450
+ initialWindowCandidate > 0
451
+ ? Math.floor(initialWindowCandidate)
452
+ : undefined;
453
+ const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
454
+ return {
399
455
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
400
- channelName: this._channelName,
401
- inboxCapacity: this._inboxCapacity,
402
- passive: true,
456
+ channelName,
457
+ inboxCapacity,
458
+ passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
459
+ initialWindow,
460
+ localNodeId,
461
+ initialTargetNodeId,
403
462
  };
404
- const channelCandidate = candidate.channelName ?? candidate['channel_name'];
405
- if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
406
- config.channelName = channelCandidate.trim();
463
+ }
464
+ _requireLocalNodeId() {
465
+ if (!this._routingNode) {
466
+ throw new Error('BroadcastChannelListener requires routing node context');
407
467
  }
408
- const inboxCandidate = candidate.inboxCapacity ?? candidate['inbox_capacity'];
409
- if (typeof inboxCandidate === 'number' &&
410
- Number.isFinite(inboxCandidate) &&
411
- inboxCandidate > 0) {
412
- config.inboxCapacity = Math.floor(inboxCandidate);
468
+ const normalized = this._normalizeNodeId(this._routingNode.sid) ??
469
+ this._normalizeNodeId(this._routingNode.id);
470
+ if (!normalized) {
471
+ throw new Error('BroadcastChannelListener requires routing node with a stable identifier');
472
+ }
473
+ return normalized;
474
+ }
475
+ _normalizeNodeId(value) {
476
+ if (typeof value !== 'string') {
477
+ return null;
413
478
  }
414
- return config;
479
+ const trimmed = value.trim();
480
+ return trimmed.length > 0 ? trimmed : null;
415
481
  }
416
482
  _monitorConnectorLifecycle(senderId, systemId, connector) {
417
483
  const maybeClosable = connector;
@@ -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.961
2
+ // Generated from package.json version: 0.3.5-test.962
3
3
  /**
4
4
  * The package version, injected at build time.
5
5
  * @internal
6
6
  */
7
- export const VERSION = '0.3.5-test.961';
7
+ export const VERSION = '0.3.5-test.962';
@@ -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.5-test.961
17
+ // Generated from package.json version: 0.3.5-test.962
18
18
  /**
19
19
  * The package version, injected at build time.
20
20
  * @internal
21
21
  */
22
- const VERSION = '0.3.5-test.961';
22
+ const VERSION = '0.3.5-test.962';
23
23
 
24
24
  /**
25
25
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -9862,6 +9862,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9862
9862
  }
9863
9863
  return null;
9864
9864
  }
9865
+ static normalizeNodeId(value) {
9866
+ if (typeof value !== 'string') {
9867
+ return null;
9868
+ }
9869
+ const trimmed = value.trim();
9870
+ return trimmed.length > 0 ? trimmed : null;
9871
+ }
9872
+ static normalizeTargetNodeId(value) {
9873
+ if (typeof value !== 'string') {
9874
+ return undefined;
9875
+ }
9876
+ const trimmed = value.trim();
9877
+ if (trimmed.length === 0) {
9878
+ return undefined;
9879
+ }
9880
+ if (trimmed === '*') {
9881
+ return '*';
9882
+ }
9883
+ return trimmed;
9884
+ }
9865
9885
  constructor(config, baseConfig = {}) {
9866
9886
  ensureBroadcastEnvironment();
9867
9887
  super(baseConfig);
@@ -9884,10 +9904,18 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9884
9904
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
9885
9905
  this.inboxCapacity = preferredCapacity;
9886
9906
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
9907
+ const normalizedLocalNodeId = BroadcastChannelConnector.normalizeNodeId(config.localNodeId);
9908
+ if (!normalizedLocalNodeId) {
9909
+ throw new Error('BroadcastChannelConnector requires a non-empty localNodeId');
9910
+ }
9911
+ this.localNodeId = normalizedLocalNodeId;
9912
+ this.targetNodeId = BroadcastChannelConnector.normalizeTargetNodeId(config.initialTargetNodeId);
9887
9913
  this.channel = new BroadcastChannel(this.channelName);
9888
9914
  logger$_.debug('broadcast_channel_connector_created', {
9889
9915
  channel: this.channelName,
9890
9916
  connector_id: this.connectorId,
9917
+ local_node_id: this.localNodeId,
9918
+ target_node_id: this.targetNodeId ?? null,
9891
9919
  inbox_capacity: preferredCapacity,
9892
9920
  timestamp: new Date().toISOString(),
9893
9921
  });
@@ -9909,15 +9937,32 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9909
9937
  ? message.constructor?.name ?? typeof message
9910
9938
  : typeof message,
9911
9939
  has_sender_id: Boolean(message?.senderId),
9940
+ has_sender_node_id: Boolean(message?.senderNodeId),
9912
9941
  });
9913
9942
  if (!message || typeof message !== 'object') {
9914
9943
  return;
9915
9944
  }
9916
9945
  const busMessage = message;
9917
- if (typeof busMessage.senderId !== 'string' || busMessage.senderId.length === 0) {
9946
+ const senderNodeId = BroadcastChannelConnector.normalizeNodeId(busMessage.senderNodeId);
9947
+ if (!senderNodeId) {
9948
+ logger$_.debug('broadcast_channel_message_rejected', {
9949
+ channel: this.channelName,
9950
+ connector_id: this.connectorId,
9951
+ reason: 'missing_sender_node_id',
9952
+ });
9918
9953
  return;
9919
9954
  }
9920
- if (busMessage.senderId === this.connectorId) {
9955
+ if (senderNodeId === this.localNodeId) {
9956
+ logger$_.debug('broadcast_channel_message_rejected', {
9957
+ channel: this.channelName,
9958
+ connector_id: this.connectorId,
9959
+ reason: 'self_echo',
9960
+ sender_node_id: senderNodeId,
9961
+ });
9962
+ return;
9963
+ }
9964
+ const incomingTargetNodeId = BroadcastChannelConnector.normalizeTargetNodeId(busMessage.targetNodeId);
9965
+ if (!this._shouldAcceptMessageFromBus(senderNodeId, incomingTargetNodeId)) {
9921
9966
  return;
9922
9967
  }
9923
9968
  const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
@@ -9931,11 +9976,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9931
9976
  }
9932
9977
  logger$_.debug('broadcast_channel_message_received', {
9933
9978
  channel: this.channelName,
9934
- sender_id: busMessage.senderId,
9979
+ sender_id: message?.senderId,
9980
+ sender_node_id: senderNodeId,
9981
+ target_node_id: incomingTargetNodeId ?? null,
9935
9982
  connector_id: this.connectorId,
9936
9983
  payload_length: payload.byteLength,
9937
9984
  });
9938
- if (this._shouldSkipDuplicateAck(busMessage.senderId, payload)) {
9985
+ if (this._shouldSkipDuplicateAck(senderNodeId, payload)) {
9939
9986
  return;
9940
9987
  }
9941
9988
  try {
@@ -10079,12 +10126,17 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10079
10126
  }
10080
10127
  async _transportSendBytes(data) {
10081
10128
  ensureBroadcastEnvironment();
10129
+ const targetNodeId = this.targetNodeId ?? '*';
10082
10130
  logger$_.debug('broadcast_channel_message_sending', {
10083
10131
  channel: this.channelName,
10084
10132
  sender_id: this.connectorId,
10133
+ sender_node_id: this.localNodeId,
10134
+ target_node_id: targetNodeId,
10085
10135
  });
10086
10136
  this.channel.postMessage({
10087
10137
  senderId: this.connectorId,
10138
+ senderNodeId: this.localNodeId,
10139
+ targetNodeId,
10088
10140
  payload: data,
10089
10141
  });
10090
10142
  }
@@ -10147,6 +10199,51 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10147
10199
  }
10148
10200
  return rawOrEnvelope;
10149
10201
  }
10202
+ _isWildcardTarget() {
10203
+ return this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined';
10204
+ }
10205
+ _shouldAcceptMessageFromBus(senderNodeId, targetNodeId) {
10206
+ if (this._isWildcardTarget()) {
10207
+ if (targetNodeId && targetNodeId !== '*') {
10208
+ logger$_.debug('broadcast_channel_message_rejected', {
10209
+ channel: this.channelName,
10210
+ connector_id: this.connectorId,
10211
+ reason: 'wildcard_target_mismatch',
10212
+ sender_node_id: senderNodeId,
10213
+ target_node_id: targetNodeId,
10214
+ local_node_id: this.localNodeId,
10215
+ });
10216
+ return false;
10217
+ }
10218
+ return true;
10219
+ }
10220
+ const expectedSender = this.targetNodeId;
10221
+ if (expectedSender && expectedSender !== '*' && senderNodeId !== expectedSender) {
10222
+ logger$_.debug('broadcast_channel_message_rejected', {
10223
+ channel: this.channelName,
10224
+ connector_id: this.connectorId,
10225
+ reason: 'unexpected_sender',
10226
+ expected_sender_node_id: expectedSender,
10227
+ sender_node_id: senderNodeId,
10228
+ local_node_id: this.localNodeId,
10229
+ });
10230
+ return false;
10231
+ }
10232
+ if (targetNodeId &&
10233
+ targetNodeId !== '*' &&
10234
+ targetNodeId !== this.localNodeId) {
10235
+ logger$_.debug('broadcast_channel_message_rejected', {
10236
+ channel: this.channelName,
10237
+ connector_id: this.connectorId,
10238
+ reason: 'unexpected_target',
10239
+ sender_node_id: senderNodeId,
10240
+ target_node_id: targetNodeId,
10241
+ local_node_id: this.localNodeId,
10242
+ });
10243
+ return false;
10244
+ }
10245
+ return true;
10246
+ }
10150
10247
  _describeInboxItem(item) {
10151
10248
  if (item instanceof Uint8Array) {
10152
10249
  return 'bytes';
@@ -10177,7 +10274,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10177
10274
  const normalizedSenderId = typeof senderId === 'string' && senderId.length > 0
10178
10275
  ? senderId
10179
10276
  : undefined;
10180
- if (normalizedSenderId && normalizedSenderId !== this.connectorId) {
10277
+ if (normalizedSenderId && normalizedSenderId !== this.localNodeId) {
10181
10278
  logger$_.debug('broadcast_channel_duplicate_ack_bypass_non_self', {
10182
10279
  channel: this.channelName,
10183
10280
  connector_id: this.connectorId,
@@ -10217,7 +10314,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10217
10314
  return false;
10218
10315
  }
10219
10316
  const senderId = this._extractSenderIdFromInboxItem(item);
10220
- if (senderId && senderId !== this.connectorId) {
10317
+ if (senderId && senderId !== this.localNodeId) {
10221
10318
  logger$_.debug('broadcast_channel_duplicate_ack_bypass_non_self', {
10222
10319
  channel: this.channelName,
10223
10320
  connector_id: this.connectorId,
@@ -10313,6 +10410,34 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
10313
10410
  });
10314
10411
  }
10315
10412
  }
10413
+ setTargetNodeId(nodeId) {
10414
+ const normalized = BroadcastChannelConnector.normalizeNodeId(nodeId);
10415
+ if (!normalized) {
10416
+ throw new Error('BroadcastChannelConnector target node id must be a non-empty string');
10417
+ }
10418
+ if (normalized === '*') {
10419
+ this.setWildcardTarget();
10420
+ return;
10421
+ }
10422
+ this.targetNodeId = normalized;
10423
+ logger$_.debug('broadcast_channel_target_updated', {
10424
+ channel: this.channelName,
10425
+ connector_id: this.connectorId,
10426
+ local_node_id: this.localNodeId,
10427
+ target_node_id: this.targetNodeId,
10428
+ target_mode: 'direct',
10429
+ });
10430
+ }
10431
+ setWildcardTarget() {
10432
+ this.targetNodeId = '*';
10433
+ logger$_.debug('broadcast_channel_target_updated', {
10434
+ channel: this.channelName,
10435
+ connector_id: this.connectorId,
10436
+ local_node_id: this.localNodeId,
10437
+ target_node_id: this.targetNodeId,
10438
+ target_mode: 'wildcard',
10439
+ });
10440
+ }
10316
10441
  _trimSeenAcks(now) {
10317
10442
  while (this.seenAckOrder.length > 0) {
10318
10443
  const candidate = this.seenAckOrder[0];
@@ -28687,8 +28812,13 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28687
28812
  }
28688
28813
  const normalized = this._normalizeConfig(config);
28689
28814
  const options = (factoryArgs[0] ?? {});
28815
+ const localNodeId = this._normalizeNodeId(options.localNodeId);
28816
+ if (!localNodeId) {
28817
+ throw new Error('BroadcastChannelConnectorFactory requires a localNodeId in create() options');
28818
+ }
28690
28819
  const channelName = normalized.channelName ?? DEFAULT_CHANNEL$5;
28691
28820
  const inboxCapacity = normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
28821
+ const resolvedTarget = this._normalizeTargetNodeId(options.initialTargetNodeId ?? normalized.initialTargetNodeId);
28692
28822
  const baseConfig = {
28693
28823
  drainTimeout: normalized.drainTimeout,
28694
28824
  flowControl: normalized.flowControl,
@@ -28703,6 +28833,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28703
28833
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
28704
28834
  channelName,
28705
28835
  inboxCapacity,
28836
+ localNodeId,
28837
+ initialTargetNodeId: resolvedTarget,
28706
28838
  };
28707
28839
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
28708
28840
  if (options.authorization) {
@@ -28726,6 +28858,13 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28726
28858
  normalized.channelName = channel.trim();
28727
28859
  }
28728
28860
  const capacity = candidate.inboxCapacity ?? candidate['inbox_capacity'];
28861
+ const initialTargetNodeId = candidate.initialTargetNodeId ?? candidate['initial_target_node_id'];
28862
+ if (typeof initialTargetNodeId === 'string' && initialTargetNodeId.trim().length > 0) {
28863
+ normalized.initialTargetNodeId = initialTargetNodeId.trim();
28864
+ }
28865
+ else if (initialTargetNodeId === '*') {
28866
+ normalized.initialTargetNodeId = '*';
28867
+ }
28729
28868
  if (typeof capacity === 'number' &&
28730
28869
  Number.isFinite(capacity) &&
28731
28870
  capacity > 0) {
@@ -28769,6 +28908,19 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
28769
28908
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$5;
28770
28909
  return normalized;
28771
28910
  }
28911
+ _normalizeNodeId(value) {
28912
+ if (typeof value !== 'string') {
28913
+ return null;
28914
+ }
28915
+ const trimmed = value.trim();
28916
+ return trimmed.length > 0 ? trimmed : null;
28917
+ }
28918
+ _normalizeTargetNodeId(value) {
28919
+ if (value === '*') {
28920
+ return '*';
28921
+ }
28922
+ return this._normalizeNodeId(value) ?? '*';
28923
+ }
28772
28924
  }
28773
28925
 
28774
28926
  var broadcastChannelConnectorFactory = /*#__PURE__*/Object.freeze({
@@ -36346,7 +36498,7 @@ class BroadcastChannelListener extends TransportListener {
36346
36498
  node: routingNode,
36347
36499
  });
36348
36500
  const selection = defaultGrantSelectionPolicy.selectCallbackGrant(selectionContext);
36349
- connectorConfig = this._grantToConnectorConfig(selection.grant);
36501
+ connectorConfig = this._grantToConnectorConfig(selection.grant, systemId);
36350
36502
  }
36351
36503
  catch (error) {
36352
36504
  logger$a.debug('broadcast_channel_listener_grant_selection_failed', {
@@ -36355,13 +36507,20 @@ class BroadcastChannelListener extends TransportListener {
36355
36507
  error: error instanceof Error ? error.message : String(error),
36356
36508
  });
36357
36509
  connectorConfig =
36358
- this._extractBroadcastConnectorConfig(frame) ??
36359
- {
36510
+ this._extractBroadcastConnectorConfig(frame, systemId) ??
36511
+ this._buildConnectorConfigForSystem(systemId, {
36360
36512
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
36361
36513
  channelName: this._channelName,
36362
36514
  inboxCapacity: this._inboxCapacity,
36363
36515
  passive: true,
36364
- };
36516
+ });
36517
+ }
36518
+ if (!connectorConfig) {
36519
+ logger$a.error('broadcast_channel_listener_missing_connector_config', {
36520
+ sender_id: params.senderId,
36521
+ system_id: systemId,
36522
+ });
36523
+ return null;
36365
36524
  }
36366
36525
  try {
36367
36526
  const connector = await routingNode.createOriginConnector({
@@ -36387,7 +36546,7 @@ class BroadcastChannelListener extends TransportListener {
36387
36546
  return null;
36388
36547
  }
36389
36548
  }
36390
- _extractBroadcastConnectorConfig(frame) {
36549
+ _extractBroadcastConnectorConfig(frame, systemId) {
36391
36550
  const rawGrants = frame.callbackGrants;
36392
36551
  if (!Array.isArray(rawGrants)) {
36393
36552
  return null;
@@ -36398,7 +36557,10 @@ class BroadcastChannelListener extends TransportListener {
36398
36557
  (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE ||
36399
36558
  grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE)) {
36400
36559
  try {
36401
- return this._grantToConnectorConfig(grant);
36560
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE) {
36561
+ return this._buildConnectorConfigForSystem(systemId, grant);
36562
+ }
36563
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
36402
36564
  }
36403
36565
  catch (error) {
36404
36566
  logger$a.debug('broadcast_channel_listener_grant_normalization_failed', {
@@ -36409,31 +36571,87 @@ class BroadcastChannelListener extends TransportListener {
36409
36571
  }
36410
36572
  return null;
36411
36573
  }
36412
- _grantToConnectorConfig(grant) {
36413
- if (grant.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE) {
36414
- if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
36415
- return broadcastChannelGrantToConnectorConfig(grant);
36574
+ _grantToConnectorConfig(grant, systemId) {
36575
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE) {
36576
+ return this._buildConnectorConfigForSystem(systemId, grant);
36577
+ }
36578
+ if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
36579
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
36580
+ }
36581
+ if ('toConnectorConfig' in grant &&
36582
+ typeof grant.toConnectorConfig ===
36583
+ 'function') {
36584
+ const normalized = grant.toConnectorConfig();
36585
+ if (normalized.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE) {
36586
+ throw new Error(`Unsupported grant connector type: ${normalized.type}`);
36416
36587
  }
36417
- throw new Error(`Unsupported grant type: ${grant.type}`);
36588
+ return this._buildConnectorConfigForSystem(systemId, normalized);
36418
36589
  }
36419
- const candidate = grant;
36420
- const config = {
36590
+ throw new Error(`Unsupported grant type: ${grant.type}`);
36591
+ }
36592
+ _buildConnectorConfigForSystem(systemId, baseConfig) {
36593
+ const localNodeId = this._requireLocalNodeId();
36594
+ const targetSystemId = this._normalizeNodeId(systemId);
36595
+ if (!targetSystemId) {
36596
+ throw new Error('BroadcastChannelListener requires a valid system id');
36597
+ }
36598
+ const candidate = baseConfig ?? null;
36599
+ const channelCandidate = candidate && 'channelName' in candidate
36600
+ ? candidate.channelName
36601
+ : undefined;
36602
+ const inboxCandidate = candidate && 'inboxCapacity' in candidate
36603
+ ? candidate.inboxCapacity
36604
+ : undefined;
36605
+ const initialWindowCandidate = candidate && 'initialWindow' in candidate
36606
+ ? candidate.initialWindow
36607
+ : undefined;
36608
+ const passiveCandidate = candidate && 'passive' in candidate
36609
+ ? candidate.passive
36610
+ : undefined;
36611
+ const targetCandidate = candidate && 'initialTargetNodeId' in candidate
36612
+ ? candidate.initialTargetNodeId
36613
+ : undefined;
36614
+ const channelName = typeof channelCandidate === 'string' && channelCandidate.trim().length > 0
36615
+ ? channelCandidate.trim()
36616
+ : this._channelName;
36617
+ const inboxCapacity = typeof inboxCandidate === 'number' &&
36618
+ Number.isFinite(inboxCandidate) &&
36619
+ inboxCandidate > 0
36620
+ ? Math.floor(inboxCandidate)
36621
+ : this._inboxCapacity;
36622
+ const initialWindow = typeof initialWindowCandidate === 'number' &&
36623
+ Number.isFinite(initialWindowCandidate) &&
36624
+ initialWindowCandidate > 0
36625
+ ? Math.floor(initialWindowCandidate)
36626
+ : undefined;
36627
+ const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
36628
+ return {
36421
36629
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
36422
- channelName: this._channelName,
36423
- inboxCapacity: this._inboxCapacity,
36424
- passive: true,
36630
+ channelName,
36631
+ inboxCapacity,
36632
+ passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
36633
+ initialWindow,
36634
+ localNodeId,
36635
+ initialTargetNodeId,
36425
36636
  };
36426
- const channelCandidate = candidate.channelName ?? candidate['channel_name'];
36427
- if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
36428
- config.channelName = channelCandidate.trim();
36637
+ }
36638
+ _requireLocalNodeId() {
36639
+ if (!this._routingNode) {
36640
+ throw new Error('BroadcastChannelListener requires routing node context');
36429
36641
  }
36430
- const inboxCandidate = candidate.inboxCapacity ?? candidate['inbox_capacity'];
36431
- if (typeof inboxCandidate === 'number' &&
36432
- Number.isFinite(inboxCandidate) &&
36433
- inboxCandidate > 0) {
36434
- config.inboxCapacity = Math.floor(inboxCandidate);
36642
+ const normalized = this._normalizeNodeId(this._routingNode.sid) ??
36643
+ this._normalizeNodeId(this._routingNode.id);
36644
+ if (!normalized) {
36645
+ throw new Error('BroadcastChannelListener requires routing node with a stable identifier');
36435
36646
  }
36436
- return config;
36647
+ return normalized;
36648
+ }
36649
+ _normalizeNodeId(value) {
36650
+ if (typeof value !== 'string') {
36651
+ return null;
36652
+ }
36653
+ const trimmed = value.trim();
36654
+ return trimmed.length > 0 ? trimmed : null;
36437
36655
  }
36438
36656
  _monitorConnectorLifecycle(senderId, systemId, connector) {
36439
36657
  const maybeClosable = connector;