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

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.
Files changed (24) hide show
  1. package/dist/browser/index.cjs +290 -33
  2. package/dist/browser/index.mjs +290 -33
  3. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector-factory.js +36 -0
  4. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +131 -6
  5. package/dist/cjs/naylence/fame/connector/broadcast-channel-listener.js +91 -25
  6. package/dist/cjs/naylence/fame/node/upstream-session-manager.js +30 -0
  7. package/dist/cjs/version.js +2 -2
  8. package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +36 -0
  9. package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +131 -6
  10. package/dist/esm/naylence/fame/connector/broadcast-channel-listener.js +91 -25
  11. package/dist/esm/naylence/fame/node/upstream-session-manager.js +30 -0
  12. package/dist/esm/version.js +2 -2
  13. package/dist/node/index.cjs +290 -33
  14. package/dist/node/index.mjs +290 -33
  15. package/dist/node/node.cjs +290 -33
  16. package/dist/node/node.mjs +290 -33
  17. package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +6 -0
  18. package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +10 -0
  19. package/dist/types/naylence/fame/connector/broadcast-channel-connector.node.d.ts +1 -6
  20. package/dist/types/naylence/fame/connector/broadcast-channel-listener.d.ts +3 -0
  21. package/dist/types/naylence/fame/grants/broadcast-channel-connection-grant.d.ts +1 -1
  22. package/dist/types/naylence/fame/node/upstream-session-manager.d.ts +2 -0
  23. package/dist/types/version.d.ts +1 -1
  24. package/package.json +1 -1
@@ -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.5-test.961
5566
+ // Generated from package.json version: 0.3.5-test.963
5567
5567
  /**
5568
5568
  * The package version, injected at build time.
5569
5569
  * @internal
5570
5570
  */
5571
- const VERSION = '0.3.5-test.961';
5571
+ const VERSION = '0.3.5-test.963';
5572
5572
 
5573
5573
  /**
5574
5574
  * Fame errors module - Fame protocol specific error classes
@@ -11599,6 +11599,26 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11599
11599
  }
11600
11600
  return null;
11601
11601
  }
11602
+ static normalizeNodeId(value) {
11603
+ if (typeof value !== 'string') {
11604
+ return null;
11605
+ }
11606
+ const trimmed = value.trim();
11607
+ return trimmed.length > 0 ? trimmed : null;
11608
+ }
11609
+ static normalizeTargetNodeId(value) {
11610
+ if (typeof value !== 'string') {
11611
+ return undefined;
11612
+ }
11613
+ const trimmed = value.trim();
11614
+ if (trimmed.length === 0) {
11615
+ return undefined;
11616
+ }
11617
+ if (trimmed === '*') {
11618
+ return '*';
11619
+ }
11620
+ return trimmed;
11621
+ }
11602
11622
  constructor(config, baseConfig = {}) {
11603
11623
  ensureBroadcastEnvironment();
11604
11624
  super(baseConfig);
@@ -11621,10 +11641,18 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11621
11641
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
11622
11642
  this.inboxCapacity = preferredCapacity;
11623
11643
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
11644
+ const normalizedLocalNodeId = BroadcastChannelConnector.normalizeNodeId(config.localNodeId);
11645
+ if (!normalizedLocalNodeId) {
11646
+ throw new Error('BroadcastChannelConnector requires a non-empty localNodeId');
11647
+ }
11648
+ this.localNodeId = normalizedLocalNodeId;
11649
+ this.targetNodeId = BroadcastChannelConnector.normalizeTargetNodeId(config.initialTargetNodeId);
11624
11650
  this.channel = new BroadcastChannel(this.channelName);
11625
11651
  logger$10.debug('broadcast_channel_connector_created', {
11626
11652
  channel: this.channelName,
11627
11653
  connector_id: this.connectorId,
11654
+ local_node_id: this.localNodeId,
11655
+ target_node_id: this.targetNodeId ?? null,
11628
11656
  inbox_capacity: preferredCapacity,
11629
11657
  timestamp: new Date().toISOString(),
11630
11658
  });
@@ -11646,15 +11674,32 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11646
11674
  ? message.constructor?.name ?? typeof message
11647
11675
  : typeof message,
11648
11676
  has_sender_id: Boolean(message?.senderId),
11677
+ has_sender_node_id: Boolean(message?.senderNodeId),
11649
11678
  });
11650
11679
  if (!message || typeof message !== 'object') {
11651
11680
  return;
11652
11681
  }
11653
11682
  const busMessage = message;
11654
- if (typeof busMessage.senderId !== 'string' || busMessage.senderId.length === 0) {
11683
+ const senderNodeId = BroadcastChannelConnector.normalizeNodeId(busMessage.senderNodeId);
11684
+ if (!senderNodeId) {
11685
+ logger$10.debug('broadcast_channel_message_rejected', {
11686
+ channel: this.channelName,
11687
+ connector_id: this.connectorId,
11688
+ reason: 'missing_sender_node_id',
11689
+ });
11655
11690
  return;
11656
11691
  }
11657
- if (busMessage.senderId === this.connectorId) {
11692
+ if (senderNodeId === this.localNodeId) {
11693
+ logger$10.debug('broadcast_channel_message_rejected', {
11694
+ channel: this.channelName,
11695
+ connector_id: this.connectorId,
11696
+ reason: 'self_echo',
11697
+ sender_node_id: senderNodeId,
11698
+ });
11699
+ return;
11700
+ }
11701
+ const incomingTargetNodeId = BroadcastChannelConnector.normalizeTargetNodeId(busMessage.targetNodeId);
11702
+ if (!this._shouldAcceptMessageFromBus(senderNodeId, incomingTargetNodeId)) {
11658
11703
  return;
11659
11704
  }
11660
11705
  const payload = BroadcastChannelConnector.coercePayload(busMessage.payload);
@@ -11668,11 +11713,13 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11668
11713
  }
11669
11714
  logger$10.debug('broadcast_channel_message_received', {
11670
11715
  channel: this.channelName,
11671
- sender_id: busMessage.senderId,
11716
+ sender_id: message?.senderId,
11717
+ sender_node_id: senderNodeId,
11718
+ target_node_id: incomingTargetNodeId ?? null,
11672
11719
  connector_id: this.connectorId,
11673
11720
  payload_length: payload.byteLength,
11674
11721
  });
11675
- if (this._shouldSkipDuplicateAck(busMessage.senderId, payload)) {
11722
+ if (this._shouldSkipDuplicateAck(senderNodeId, payload)) {
11676
11723
  return;
11677
11724
  }
11678
11725
  try {
@@ -11816,12 +11863,17 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11816
11863
  }
11817
11864
  async _transportSendBytes(data) {
11818
11865
  ensureBroadcastEnvironment();
11866
+ const targetNodeId = this.targetNodeId ?? '*';
11819
11867
  logger$10.debug('broadcast_channel_message_sending', {
11820
11868
  channel: this.channelName,
11821
11869
  sender_id: this.connectorId,
11870
+ sender_node_id: this.localNodeId,
11871
+ target_node_id: targetNodeId,
11822
11872
  });
11823
11873
  this.channel.postMessage({
11824
11874
  senderId: this.connectorId,
11875
+ senderNodeId: this.localNodeId,
11876
+ targetNodeId,
11825
11877
  payload: data,
11826
11878
  });
11827
11879
  }
@@ -11884,6 +11936,51 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11884
11936
  }
11885
11937
  return rawOrEnvelope;
11886
11938
  }
11939
+ _isWildcardTarget() {
11940
+ return this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined';
11941
+ }
11942
+ _shouldAcceptMessageFromBus(senderNodeId, targetNodeId) {
11943
+ if (this._isWildcardTarget()) {
11944
+ if (targetNodeId && targetNodeId !== '*') {
11945
+ logger$10.debug('broadcast_channel_message_rejected', {
11946
+ channel: this.channelName,
11947
+ connector_id: this.connectorId,
11948
+ reason: 'wildcard_target_mismatch',
11949
+ sender_node_id: senderNodeId,
11950
+ target_node_id: targetNodeId,
11951
+ local_node_id: this.localNodeId,
11952
+ });
11953
+ return false;
11954
+ }
11955
+ return true;
11956
+ }
11957
+ const expectedSender = this.targetNodeId;
11958
+ if (expectedSender && expectedSender !== '*' && senderNodeId !== expectedSender) {
11959
+ logger$10.debug('broadcast_channel_message_rejected', {
11960
+ channel: this.channelName,
11961
+ connector_id: this.connectorId,
11962
+ reason: 'unexpected_sender',
11963
+ expected_sender_node_id: expectedSender,
11964
+ sender_node_id: senderNodeId,
11965
+ local_node_id: this.localNodeId,
11966
+ });
11967
+ return false;
11968
+ }
11969
+ if (targetNodeId &&
11970
+ targetNodeId !== '*' &&
11971
+ targetNodeId !== this.localNodeId) {
11972
+ logger$10.debug('broadcast_channel_message_rejected', {
11973
+ channel: this.channelName,
11974
+ connector_id: this.connectorId,
11975
+ reason: 'unexpected_target',
11976
+ sender_node_id: senderNodeId,
11977
+ target_node_id: targetNodeId,
11978
+ local_node_id: this.localNodeId,
11979
+ });
11980
+ return false;
11981
+ }
11982
+ return true;
11983
+ }
11887
11984
  _describeInboxItem(item) {
11888
11985
  if (item instanceof Uint8Array) {
11889
11986
  return 'bytes';
@@ -11914,7 +12011,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11914
12011
  const normalizedSenderId = typeof senderId === 'string' && senderId.length > 0
11915
12012
  ? senderId
11916
12013
  : undefined;
11917
- if (normalizedSenderId && normalizedSenderId !== this.connectorId) {
12014
+ if (normalizedSenderId && normalizedSenderId !== this.localNodeId) {
11918
12015
  logger$10.debug('broadcast_channel_duplicate_ack_bypass_non_self', {
11919
12016
  channel: this.channelName,
11920
12017
  connector_id: this.connectorId,
@@ -11954,7 +12051,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11954
12051
  return false;
11955
12052
  }
11956
12053
  const senderId = this._extractSenderIdFromInboxItem(item);
11957
- if (senderId && senderId !== this.connectorId) {
12054
+ if (senderId && senderId !== this.localNodeId) {
11958
12055
  logger$10.debug('broadcast_channel_duplicate_ack_bypass_non_self', {
11959
12056
  channel: this.channelName,
11960
12057
  connector_id: this.connectorId,
@@ -12050,6 +12147,34 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
12050
12147
  });
12051
12148
  }
12052
12149
  }
12150
+ setTargetNodeId(nodeId) {
12151
+ const normalized = BroadcastChannelConnector.normalizeNodeId(nodeId);
12152
+ if (!normalized) {
12153
+ throw new Error('BroadcastChannelConnector target node id must be a non-empty string');
12154
+ }
12155
+ if (normalized === '*') {
12156
+ this.setWildcardTarget();
12157
+ return;
12158
+ }
12159
+ this.targetNodeId = normalized;
12160
+ logger$10.debug('broadcast_channel_target_updated', {
12161
+ channel: this.channelName,
12162
+ connector_id: this.connectorId,
12163
+ local_node_id: this.localNodeId,
12164
+ target_node_id: this.targetNodeId,
12165
+ target_mode: 'direct',
12166
+ });
12167
+ }
12168
+ setWildcardTarget() {
12169
+ this.targetNodeId = '*';
12170
+ logger$10.debug('broadcast_channel_target_updated', {
12171
+ channel: this.channelName,
12172
+ connector_id: this.connectorId,
12173
+ local_node_id: this.localNodeId,
12174
+ target_node_id: this.targetNodeId,
12175
+ target_mode: 'wildcard',
12176
+ });
12177
+ }
12053
12178
  _trimSeenAcks(now) {
12054
12179
  while (this.seenAckOrder.length > 0) {
12055
12180
  const candidate = this.seenAckOrder[0];
@@ -12476,6 +12601,20 @@ class UpstreamSessionManager extends TaskSpawner {
12476
12601
  waitEvent(event, signal) {
12477
12602
  return signal ? event.wait({ signal }) : event.wait();
12478
12603
  }
12604
+ _getLocalNodeId() {
12605
+ const normalized = this._normalizeNodeId(this.node.id);
12606
+ if (!normalized) {
12607
+ throw new Error('UpstreamSessionManager requires node with a stable identifier');
12608
+ }
12609
+ return normalized;
12610
+ }
12611
+ _normalizeNodeId(value) {
12612
+ if (typeof value !== 'string') {
12613
+ return null;
12614
+ }
12615
+ const trimmed = value.trim();
12616
+ return trimmed.length > 0 ? trimmed : null;
12617
+ }
12479
12618
  async connectCycle() {
12480
12619
  if (!this.admissionClient) {
12481
12620
  throw new FameConnectError('Admission client is required to attach upstream');
@@ -12497,6 +12636,8 @@ class UpstreamSessionManager extends TaskSpawner {
12497
12636
  await this.onWelcome(welcome.frame);
12498
12637
  const connector = await ConnectorFactory.createConnector(grant, {
12499
12638
  systemId: welcome.frame.systemId,
12639
+ localNodeId: this._getLocalNodeId(),
12640
+ initialTargetNodeId: '*',
12500
12641
  });
12501
12642
  await connector.start(this.wrappedHandler);
12502
12643
  this.connector = connector;
@@ -12522,6 +12663,20 @@ class UpstreamSessionManager extends TaskSpawner {
12522
12663
  }
12523
12664
  const attachInfo = await this.attachClient.attach(this.node, this.outboundOriginType, connector, welcome.frame, this.wrappedHandler, this.getKeys() ?? undefined, callbackGrants);
12524
12665
  this.targetSystemId = attachInfo.targetSystemId ?? null;
12666
+ if (this.targetSystemId) {
12667
+ const targetAware = connector;
12668
+ if (typeof targetAware.setTargetNodeId === 'function') {
12669
+ try {
12670
+ targetAware.setTargetNodeId(this.targetSystemId);
12671
+ }
12672
+ catch (error) {
12673
+ logger$$.warning('broadcast_channel_target_apply_failed', {
12674
+ error: error instanceof Error ? error.message : String(error),
12675
+ target_node_id: this.targetSystemId,
12676
+ });
12677
+ }
12678
+ }
12679
+ }
12525
12680
  await this.onAttach(attachInfo, connector);
12526
12681
  // Close the admission client immediately after attach completes
12527
12682
  // This releases HTTP keep-alive connections (Node.js fetch/undici requires explicit cleanup)
@@ -30620,8 +30775,16 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
30620
30775
  }
30621
30776
  const normalized = this._normalizeConfig(config);
30622
30777
  const options = (factoryArgs[0] ?? {});
30778
+ const normalizedLocalNodeFromConfig = this._normalizeNodeId(normalized.localNodeId);
30779
+ const localNodeId = this._normalizeNodeId(options.localNodeId) ?? normalizedLocalNodeFromConfig;
30780
+ if (!localNodeId) {
30781
+ throw new Error('BroadcastChannelConnectorFactory requires a localNodeId from config or create() options');
30782
+ }
30623
30783
  const channelName = normalized.channelName ?? DEFAULT_CHANNEL$2;
30624
30784
  const inboxCapacity = normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$2;
30785
+ const targetFromOptions = this._normalizeTargetNodeId(options.initialTargetNodeId);
30786
+ const targetFromConfig = this._normalizeTargetNodeId(normalized.initialTargetNodeId);
30787
+ const resolvedTarget = targetFromOptions ?? targetFromConfig ?? '*';
30625
30788
  const baseConfig = {
30626
30789
  drainTimeout: normalized.drainTimeout,
30627
30790
  flowControl: normalized.flowControl,
@@ -30636,6 +30799,8 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
30636
30799
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE$1,
30637
30800
  channelName,
30638
30801
  inboxCapacity,
30802
+ localNodeId,
30803
+ initialTargetNodeId: resolvedTarget,
30639
30804
  };
30640
30805
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
30641
30806
  if (options.authorization) {
@@ -30659,11 +30824,21 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
30659
30824
  normalized.channelName = channel.trim();
30660
30825
  }
30661
30826
  const capacity = candidate.inboxCapacity ?? candidate['inbox_capacity'];
30827
+ const initialTargetNodeId = candidate.initialTargetNodeId ?? candidate['initial_target_node_id'];
30828
+ const normalizedTarget = this._normalizeTargetNodeId(initialTargetNodeId);
30829
+ if (normalizedTarget) {
30830
+ normalized.initialTargetNodeId = normalizedTarget;
30831
+ }
30662
30832
  if (typeof capacity === 'number' &&
30663
30833
  Number.isFinite(capacity) &&
30664
30834
  capacity > 0) {
30665
30835
  normalized.inboxCapacity = Math.floor(capacity);
30666
30836
  }
30837
+ const localNodeId = candidate.localNodeId ?? candidate['local_node_id'];
30838
+ const normalizedLocalNodeId = this._normalizeNodeId(localNodeId);
30839
+ if (normalizedLocalNodeId) {
30840
+ normalized.localNodeId = normalizedLocalNodeId;
30841
+ }
30667
30842
  if (typeof candidate.flowControl === 'boolean') {
30668
30843
  normalized.flowControl = candidate.flowControl;
30669
30844
  }
@@ -30702,6 +30877,22 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
30702
30877
  normalized.inboxCapacity ?? DEFAULT_INBOX_CAPACITY$2;
30703
30878
  return normalized;
30704
30879
  }
30880
+ _normalizeNodeId(value) {
30881
+ if (typeof value !== 'string') {
30882
+ return null;
30883
+ }
30884
+ const trimmed = value.trim();
30885
+ return trimmed.length > 0 ? trimmed : null;
30886
+ }
30887
+ _normalizeTargetNodeId(value) {
30888
+ if (value === undefined || value === null) {
30889
+ return undefined;
30890
+ }
30891
+ if (value === '*') {
30892
+ return '*';
30893
+ }
30894
+ return this._normalizeNodeId(value) ?? undefined;
30895
+ }
30705
30896
  }
30706
30897
 
30707
30898
  var broadcastChannelConnectorFactory = /*#__PURE__*/Object.freeze({
@@ -32859,7 +33050,7 @@ class BroadcastChannelListener extends TransportListener {
32859
33050
  node: routingNode,
32860
33051
  });
32861
33052
  const selection = defaultGrantSelectionPolicy.selectCallbackGrant(selectionContext);
32862
- connectorConfig = this._grantToConnectorConfig(selection.grant);
33053
+ connectorConfig = this._grantToConnectorConfig(selection.grant, systemId);
32863
33054
  }
32864
33055
  catch (error) {
32865
33056
  logger$n.debug('broadcast_channel_listener_grant_selection_failed', {
@@ -32868,13 +33059,20 @@ class BroadcastChannelListener extends TransportListener {
32868
33059
  error: error instanceof Error ? error.message : String(error),
32869
33060
  });
32870
33061
  connectorConfig =
32871
- this._extractBroadcastConnectorConfig(frame) ??
32872
- {
33062
+ this._extractBroadcastConnectorConfig(frame, systemId) ??
33063
+ this._buildConnectorConfigForSystem(systemId, {
32873
33064
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE$1,
32874
33065
  channelName: this._channelName,
32875
33066
  inboxCapacity: this._inboxCapacity,
32876
33067
  passive: true,
32877
- };
33068
+ });
33069
+ }
33070
+ if (!connectorConfig) {
33071
+ logger$n.error('broadcast_channel_listener_missing_connector_config', {
33072
+ sender_id: params.senderId,
33073
+ system_id: systemId,
33074
+ });
33075
+ return null;
32878
33076
  }
32879
33077
  try {
32880
33078
  const connector = await routingNode.createOriginConnector({
@@ -32900,7 +33098,7 @@ class BroadcastChannelListener extends TransportListener {
32900
33098
  return null;
32901
33099
  }
32902
33100
  }
32903
- _extractBroadcastConnectorConfig(frame) {
33101
+ _extractBroadcastConnectorConfig(frame, systemId) {
32904
33102
  const rawGrants = frame.callbackGrants;
32905
33103
  if (!Array.isArray(rawGrants)) {
32906
33104
  return null;
@@ -32911,7 +33109,10 @@ class BroadcastChannelListener extends TransportListener {
32911
33109
  (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE ||
32912
33110
  grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE$1)) {
32913
33111
  try {
32914
- return this._grantToConnectorConfig(grant);
33112
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE$1) {
33113
+ return this._buildConnectorConfigForSystem(systemId, grant);
33114
+ }
33115
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
32915
33116
  }
32916
33117
  catch (error) {
32917
33118
  logger$n.debug('broadcast_channel_listener_grant_normalization_failed', {
@@ -32922,31 +33123,87 @@ class BroadcastChannelListener extends TransportListener {
32922
33123
  }
32923
33124
  return null;
32924
33125
  }
32925
- _grantToConnectorConfig(grant) {
32926
- if (grant.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE$1) {
32927
- if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
32928
- return broadcastChannelGrantToConnectorConfig(grant);
33126
+ _grantToConnectorConfig(grant, systemId) {
33127
+ if (grant.type === BROADCAST_CHANNEL_CONNECTOR_TYPE$1) {
33128
+ return this._buildConnectorConfigForSystem(systemId, grant);
33129
+ }
33130
+ if (grant.type === BROADCAST_CHANNEL_CONNECTION_GRANT_TYPE) {
33131
+ return this._buildConnectorConfigForSystem(systemId, broadcastChannelGrantToConnectorConfig(grant));
33132
+ }
33133
+ if ('toConnectorConfig' in grant &&
33134
+ typeof grant.toConnectorConfig ===
33135
+ 'function') {
33136
+ const normalized = grant.toConnectorConfig();
33137
+ if (normalized.type !== BROADCAST_CHANNEL_CONNECTOR_TYPE$1) {
33138
+ throw new Error(`Unsupported grant connector type: ${normalized.type}`);
32929
33139
  }
32930
- throw new Error(`Unsupported grant type: ${grant.type}`);
33140
+ return this._buildConnectorConfigForSystem(systemId, normalized);
32931
33141
  }
32932
- const candidate = grant;
32933
- const config = {
33142
+ throw new Error(`Unsupported grant type: ${grant.type}`);
33143
+ }
33144
+ _buildConnectorConfigForSystem(systemId, baseConfig) {
33145
+ const localNodeId = this._requireLocalNodeId();
33146
+ const targetSystemId = this._normalizeNodeId(systemId);
33147
+ if (!targetSystemId) {
33148
+ throw new Error('BroadcastChannelListener requires a valid system id');
33149
+ }
33150
+ const candidate = baseConfig ?? null;
33151
+ const channelCandidate = candidate && 'channelName' in candidate
33152
+ ? candidate.channelName
33153
+ : undefined;
33154
+ const inboxCandidate = candidate && 'inboxCapacity' in candidate
33155
+ ? candidate.inboxCapacity
33156
+ : undefined;
33157
+ const initialWindowCandidate = candidate && 'initialWindow' in candidate
33158
+ ? candidate.initialWindow
33159
+ : undefined;
33160
+ const passiveCandidate = candidate && 'passive' in candidate
33161
+ ? candidate.passive
33162
+ : undefined;
33163
+ const targetCandidate = candidate && 'initialTargetNodeId' in candidate
33164
+ ? candidate.initialTargetNodeId
33165
+ : undefined;
33166
+ const channelName = typeof channelCandidate === 'string' && channelCandidate.trim().length > 0
33167
+ ? channelCandidate.trim()
33168
+ : this._channelName;
33169
+ const inboxCapacity = typeof inboxCandidate === 'number' &&
33170
+ Number.isFinite(inboxCandidate) &&
33171
+ inboxCandidate > 0
33172
+ ? Math.floor(inboxCandidate)
33173
+ : this._inboxCapacity;
33174
+ const initialWindow = typeof initialWindowCandidate === 'number' &&
33175
+ Number.isFinite(initialWindowCandidate) &&
33176
+ initialWindowCandidate > 0
33177
+ ? Math.floor(initialWindowCandidate)
33178
+ : undefined;
33179
+ const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
33180
+ return {
32934
33181
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE$1,
32935
- channelName: this._channelName,
32936
- inboxCapacity: this._inboxCapacity,
32937
- passive: true,
33182
+ channelName,
33183
+ inboxCapacity,
33184
+ passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
33185
+ initialWindow,
33186
+ localNodeId,
33187
+ initialTargetNodeId,
32938
33188
  };
32939
- const channelCandidate = candidate.channelName ?? candidate['channel_name'];
32940
- if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
32941
- config.channelName = channelCandidate.trim();
33189
+ }
33190
+ _requireLocalNodeId() {
33191
+ if (!this._routingNode) {
33192
+ throw new Error('BroadcastChannelListener requires routing node context');
32942
33193
  }
32943
- const inboxCandidate = candidate.inboxCapacity ?? candidate['inbox_capacity'];
32944
- if (typeof inboxCandidate === 'number' &&
32945
- Number.isFinite(inboxCandidate) &&
32946
- inboxCandidate > 0) {
32947
- config.inboxCapacity = Math.floor(inboxCandidate);
33194
+ const normalized = this._normalizeNodeId(this._routingNode.sid) ??
33195
+ this._normalizeNodeId(this._routingNode.id);
33196
+ if (!normalized) {
33197
+ throw new Error('BroadcastChannelListener requires routing node with a stable identifier');
32948
33198
  }
32949
- return config;
33199
+ return normalized;
33200
+ }
33201
+ _normalizeNodeId(value) {
33202
+ if (typeof value !== 'string') {
33203
+ return null;
33204
+ }
33205
+ const trimmed = value.trim();
33206
+ return trimmed.length > 0 ? trimmed : null;
32950
33207
  }
32951
33208
  _monitorConnectorLifecycle(senderId, systemId, connector) {
32952
33209
  const maybeClosable = connector;