@naylence/runtime 0.3.6 → 0.3.7

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 (71) hide show
  1. package/dist/browser/index.cjs +220 -172
  2. package/dist/browser/index.mjs +220 -173
  3. package/dist/cjs/_env-shim.js +2 -1
  4. package/dist/cjs/naylence/fame/config/extended-fame-config.js +2 -1
  5. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -4
  6. package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +14 -6
  7. package/dist/cjs/naylence/fame/connector/broadcast-channel-listener-factory.js +3 -1
  8. package/dist/cjs/naylence/fame/connector/broadcast-channel-listener.js +11 -7
  9. package/dist/cjs/naylence/fame/connector/index.js +2 -1
  10. package/dist/cjs/naylence/fame/connector/inpage-connector-factory.js +2 -1
  11. package/dist/cjs/naylence/fame/connector/inpage-connector.js +13 -6
  12. package/dist/cjs/naylence/fame/connector/inpage-listener-factory.js +4 -4
  13. package/dist/cjs/naylence/fame/connector/inpage-listener.js +5 -2
  14. package/dist/cjs/naylence/fame/delivery/default-delivery-tracker.js +4 -62
  15. package/dist/cjs/naylence/fame/grants/broadcast-channel-connection-grant.js +6 -3
  16. package/dist/cjs/naylence/fame/grants/inpage-connection-grant.js +4 -2
  17. package/dist/cjs/naylence/fame/http/oauth2-token-router.js +9 -9
  18. package/dist/cjs/naylence/fame/node/admission/default-node-attach-client.js +34 -5
  19. package/dist/cjs/naylence/fame/node/upstream-session-manager.js +40 -8
  20. package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +10 -6
  21. package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider.js +1 -2
  22. package/dist/cjs/naylence/fame/security/default-security-manager.js +2 -1
  23. package/dist/cjs/naylence/fame/security/trust-store/noop-trust-store-provider-factory.js +2 -2
  24. package/dist/cjs/naylence/fame/security/trust-store/trust-store-provider-factory.js +2 -2
  25. package/dist/cjs/naylence/fame/util/index.js +3 -1
  26. package/dist/cjs/node.js +4 -1
  27. package/dist/cjs/version.js +2 -2
  28. package/dist/esm/_env-shim.js +2 -1
  29. package/dist/esm/browser.js +2 -2
  30. package/dist/esm/naylence/fame/config/extended-fame-config.js +2 -1
  31. package/dist/esm/naylence/fame/connector/broadcast-channel-connector-factory.js +12 -4
  32. package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +14 -6
  33. package/dist/esm/naylence/fame/connector/broadcast-channel-listener-factory.js +3 -1
  34. package/dist/esm/naylence/fame/connector/broadcast-channel-listener.js +11 -7
  35. package/dist/esm/naylence/fame/connector/index.js +2 -2
  36. package/dist/esm/naylence/fame/connector/inpage-connector-factory.js +2 -1
  37. package/dist/esm/naylence/fame/connector/inpage-connector.js +13 -6
  38. package/dist/esm/naylence/fame/connector/inpage-listener-factory.js +4 -4
  39. package/dist/esm/naylence/fame/connector/inpage-listener.js +5 -2
  40. package/dist/esm/naylence/fame/delivery/default-delivery-tracker.js +4 -62
  41. package/dist/esm/naylence/fame/grants/broadcast-channel-connection-grant.js +6 -3
  42. package/dist/esm/naylence/fame/grants/inpage-connection-grant.js +4 -2
  43. package/dist/esm/naylence/fame/http/oauth2-token-router.js +9 -9
  44. package/dist/esm/naylence/fame/node/admission/default-node-attach-client.js +34 -5
  45. package/dist/esm/naylence/fame/node/upstream-session-manager.js +40 -8
  46. package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +10 -6
  47. package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider.js +1 -2
  48. package/dist/esm/naylence/fame/security/default-security-manager.js +2 -1
  49. package/dist/esm/naylence/fame/security/index.js +1 -1
  50. package/dist/esm/naylence/fame/security/trust-store/noop-trust-store-provider-factory.js +3 -3
  51. package/dist/esm/naylence/fame/security/trust-store/trust-store-provider-factory.js +3 -3
  52. package/dist/esm/naylence/fame/util/index.js +1 -0
  53. package/dist/esm/node.js +2 -1
  54. package/dist/esm/version.js +2 -2
  55. package/dist/node/index.cjs +218 -171
  56. package/dist/node/index.mjs +218 -172
  57. package/dist/node/node.cjs +184 -136
  58. package/dist/node/node.mjs +183 -137
  59. package/dist/types/browser.d.ts +2 -2
  60. package/dist/types/naylence/fame/connector/broadcast-channel-connector-factory.d.ts +1 -0
  61. package/dist/types/naylence/fame/connector/index.d.ts +3 -3
  62. package/dist/types/naylence/fame/delivery/default-delivery-tracker.d.ts +0 -6
  63. package/dist/types/naylence/fame/node/admission/default-node-attach-client.d.ts +1 -0
  64. package/dist/types/naylence/fame/security/index.d.ts +1 -1
  65. package/dist/types/naylence/fame/security/trust-store/noop-trust-store-provider-factory.d.ts +3 -3
  66. package/dist/types/naylence/fame/security/trust-store/trust-store-provider-factory.d.ts +4 -4
  67. package/dist/types/naylence/fame/security/trust-store/trust-store-provider.d.ts +5 -5
  68. package/dist/types/naylence/fame/util/index.d.ts +1 -0
  69. package/dist/types/node.d.ts +2 -1
  70. package/dist/types/version.d.ts +1 -1
  71. package/package.json +1 -1
@@ -17,7 +17,8 @@ function installProcessEnvShim() {
17
17
  if (g.__ENV__ && typeof g.__ENV__ === 'object')
18
18
  Object.assign(out, g.__ENV__);
19
19
  try {
20
- // @ts-ignore -- import.meta is only available in ESM builds
20
+ // import.meta is only available in ESM builds
21
+ // @ts-ignore
21
22
  const ie = (typeof import.meta !== 'undefined' && import.meta.env) || undefined;
22
23
  if (ie && typeof ie === 'object')
23
24
  Object.assign(out, ie);
@@ -93,7 +93,8 @@ function createFsShim() {
93
93
  else if (options &&
94
94
  typeof options === 'object' &&
95
95
  'encoding' in options &&
96
- typeof options.encoding === 'string') {
96
+ typeof options.encoding ===
97
+ 'string') {
97
98
  encoding = options.encoding;
98
99
  }
99
100
  const data = fsBinding.readFileUtf8(pathOrDescriptor, 0);
@@ -47,10 +47,12 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
47
47
  type: broadcast_channel_connector_js_1.BROADCAST_CHANNEL_CONNECTOR_TYPE,
48
48
  };
49
49
  const channelCandidate = record.channelName ?? record['channel_name'];
50
- if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {
50
+ if (typeof channelCandidate === 'string' &&
51
+ channelCandidate.trim().length > 0) {
51
52
  config.channelName = channelCandidate.trim();
52
53
  }
53
- const inboxCandidate = record.inboxCapacity ?? record['inbox_capacity'];
54
+ const inboxCandidate = record.inboxCapacity ??
55
+ record['inbox_capacity'];
54
56
  if (typeof inboxCandidate === 'number' &&
55
57
  Number.isFinite(inboxCandidate) &&
56
58
  inboxCandidate > 0) {
@@ -74,9 +76,11 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
74
76
  throw new Error('BroadcastChannelConnectorFactory requires a configuration');
75
77
  }
76
78
  const normalized = this._normalizeConfig(config);
77
- const options = (factoryArgs[0] ?? {});
79
+ const options = (factoryArgs[0] ??
80
+ {});
78
81
  const normalizedLocalNodeFromConfig = this._normalizeNodeId(normalized.localNodeId);
79
- const localNodeId = this._normalizeNodeId(options.localNodeId) ?? normalizedLocalNodeFromConfig;
82
+ const localNodeId = this._normalizeNodeId(options.localNodeId) ??
83
+ normalizedLocalNodeFromConfig;
80
84
  if (!localNodeId) {
81
85
  throw new Error('BroadcastChannelConnectorFactory requires a localNodeId from config or create() options');
82
86
  }
@@ -101,6 +105,7 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
101
105
  inboxCapacity,
102
106
  localNodeId,
103
107
  initialTargetNodeId: resolvedTarget,
108
+ passive: normalized.passive,
104
109
  };
105
110
  const connector = new broadcast_channel_connector_js_1.BroadcastChannelConnector(connectorConfig, baseConfig);
106
111
  if (options.authorization) {
@@ -139,6 +144,9 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
139
144
  if (normalizedLocalNodeId) {
140
145
  normalized.localNodeId = normalizedLocalNodeId;
141
146
  }
147
+ if (typeof candidate.passive === 'boolean') {
148
+ normalized.passive = candidate.passive;
149
+ }
142
150
  if (typeof candidate.flowControl === 'boolean') {
143
151
  normalized.flowControl = candidate.flowControl;
144
152
  }
@@ -20,7 +20,8 @@ const ensureBroadcastEnvironment = () => {
20
20
  };
21
21
  class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConnector {
22
22
  static generateConnectorId() {
23
- const globalCrypto = globalThis.crypto;
23
+ const globalCrypto = globalThis
24
+ .crypto;
24
25
  if (globalCrypto?.randomUUID) {
25
26
  return globalCrypto.randomUUID();
26
27
  }
@@ -75,7 +76,8 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
75
76
  this.listenerRegistered = false;
76
77
  this.visibilityChangeListenerRegistered = false;
77
78
  this.channelName =
78
- typeof config.channelName === 'string' && config.channelName.trim().length > 0
79
+ typeof config.channelName === 'string' &&
80
+ config.channelName.trim().length > 0
79
81
  ? config.channelName.trim()
80
82
  : DEFAULT_CHANNEL;
81
83
  const preferredCapacity = typeof config.inboxCapacity === 'number' &&
@@ -99,6 +101,7 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
99
101
  local_node_id: this.localNodeId,
100
102
  target_node_id: this.targetNodeId ?? null,
101
103
  inbox_capacity: preferredCapacity,
104
+ passive: config.passive ?? false,
102
105
  timestamp: new Date().toISOString(),
103
106
  });
104
107
  this.onMsg = (event) => {
@@ -116,7 +119,8 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
116
119
  channel: this.channelName,
117
120
  connector_id: this.connectorId,
118
121
  message_type: message && typeof message === 'object'
119
- ? message.constructor?.name ?? typeof message
122
+ ? (message.constructor
123
+ ?.name ?? typeof message)
120
124
  : typeof message,
121
125
  has_sender_id: Boolean(message?.senderId),
122
126
  has_sender_node_id: Boolean(message?.senderNodeId),
@@ -346,7 +350,9 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
346
350
  timestamp: new Date().toISOString(),
347
351
  });
348
352
  }
349
- if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
353
+ if (this.visibilityChangeListenerRegistered &&
354
+ this.visibilityChangeHandler &&
355
+ typeof document !== 'undefined') {
350
356
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
351
357
  this.visibilityChangeListenerRegistered = false;
352
358
  this.visibilityChangeHandler = undefined;
@@ -374,7 +380,7 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
374
380
  return rawOrEnvelope;
375
381
  }
376
382
  _isWildcardTarget() {
377
- return this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined';
383
+ return (this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined');
378
384
  }
379
385
  _shouldAcceptMessageFromBus(senderNodeId, targetNodeId) {
380
386
  if (this._isWildcardTarget()) {
@@ -394,7 +400,9 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
394
400
  return true;
395
401
  }
396
402
  const expectedSender = this.targetNodeId;
397
- if (expectedSender && expectedSender !== '*' && senderNodeId !== expectedSender) {
403
+ if (expectedSender &&
404
+ expectedSender !== '*' &&
405
+ senderNodeId !== expectedSender) {
398
406
  logger.debug('broadcast_channel_message_rejected', {
399
407
  channel: this.channelName,
400
408
  connector_id: this.connectorId,
@@ -53,7 +53,9 @@ function normalizeConfig(config) {
53
53
  : DEFAULT_CHANNEL;
54
54
  const rawInbox = record.inboxCapacity ?? record['inbox_capacity'];
55
55
  let inboxCapacity = DEFAULT_INBOX_CAPACITY;
56
- if (typeof rawInbox === 'number' && Number.isFinite(rawInbox) && rawInbox > 0) {
56
+ if (typeof rawInbox === 'number' &&
57
+ Number.isFinite(rawInbox) &&
58
+ rawInbox > 0) {
57
59
  inboxCapacity = Math.floor(rawInbox);
58
60
  }
59
61
  else if (typeof rawInbox === 'string') {
@@ -14,9 +14,7 @@ const broadcast_channel_connection_grant_js_1 = require("../grants/broadcast-cha
14
14
  const logger = (0, logging_js_1.getLogger)('naylence.fame.connector.broadcast_channel_listener');
15
15
  const DEFAULT_CHANNEL = 'naylence-fabric';
16
16
  const DEFAULT_INBOX_CAPACITY = 2048;
17
- const RESPONSE_TYPE_MASK = core_1.FameResponseType.ACK |
18
- core_1.FameResponseType.REPLY |
19
- core_1.FameResponseType.STREAM;
17
+ const RESPONSE_TYPE_MASK = core_1.FameResponseType.ACK | core_1.FameResponseType.REPLY | core_1.FameResponseType.STREAM;
20
18
  const isBrowserEnvironment = () => typeof window !== 'undefined' &&
21
19
  typeof BroadcastChannel !== 'undefined' &&
22
20
  typeof MessageEvent !== 'undefined';
@@ -230,9 +228,7 @@ class BroadcastChannelListener extends transport_listener_js_1.TransportListener
230
228
  return null;
231
229
  }
232
230
  })();
233
- if (error instanceof zod_1.ZodError &&
234
- decoded &&
235
- decoded.length > 0) {
231
+ if (error instanceof zod_1.ZodError && decoded && decoded.length > 0) {
236
232
  try {
237
233
  const reparsed = JSON.parse(decoded);
238
234
  const candidate = reparsed.rtype;
@@ -455,11 +451,19 @@ class BroadcastChannelListener extends transport_listener_js_1.TransportListener
455
451
  ? Math.floor(initialWindowCandidate)
456
452
  : undefined;
457
453
  const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
454
+ const passive = typeof passiveCandidate === 'boolean' ? passiveCandidate : true;
455
+ logger.debug('broadcast_channel_listener_building_connector_config', {
456
+ system_id: systemId,
457
+ channel_name: channelName,
458
+ passive,
459
+ has_base_config: !!baseConfig,
460
+ passive_candidate: passiveCandidate,
461
+ });
458
462
  return {
459
463
  type: broadcast_channel_connector_js_1.BROADCAST_CHANNEL_CONNECTOR_TYPE,
460
464
  channelName,
461
465
  inboxCapacity,
462
- passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
466
+ passive,
463
467
  initialWindow,
464
468
  localNodeId,
465
469
  initialTargetNodeId,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBroadcastChannelListenerInstance = exports.BroadcastChannelListener = exports.getInPageListenerInstance = exports.InPageListener = exports.getHttpListenerInstance = exports.HttpListener = exports.getWebsocketListenerInstance = exports.WebSocketListener = exports.DefaultHttpServer = exports.TRANSPORT_LISTENER_FACTORY_BASE_TYPE = exports.TransportListener = exports._NoopFlowController = exports.BROADCAST_CHANNEL_CONNECTOR_TYPE = exports.BroadcastChannelConnector = exports.INPAGE_CONNECTOR_TYPE = exports.InPageConnector = exports.BoundedAsyncQueue = exports.QueueFullError = exports.HttpStatelessConnector = exports.WebSocketState = exports.WebSocketConnector = exports.createResource = exports.ConnectorFactory = exports.createConnectorConfig = exports.isConnectorConfig = exports.ConnectorConfigDefaults = exports.BaseAsyncConnector = void 0;
3
+ exports.getBroadcastChannelListenerInstance = exports.BroadcastChannelListener = exports.getInPageListenerInstance = exports.InPageListener = exports.getHttpListenerInstance = exports.HttpListener = exports.getWebsocketListenerInstance = exports.WebSocketListener = exports.DefaultHttpServer = exports.TRANSPORT_LISTENER_FACTORY_BASE_TYPE = exports.TransportListenerFactory = exports.TransportListener = exports._NoopFlowController = exports.BROADCAST_CHANNEL_CONNECTOR_TYPE = exports.BroadcastChannelConnector = exports.INPAGE_CONNECTOR_TYPE = exports.InPageConnector = exports.BoundedAsyncQueue = exports.QueueFullError = exports.HttpStatelessConnector = exports.WebSocketState = exports.WebSocketConnector = exports.createResource = exports.ConnectorFactory = exports.createConnectorConfig = exports.isConnectorConfig = exports.ConnectorConfigDefaults = exports.BaseAsyncConnector = void 0;
4
4
  require("./http-listener-factory.js");
5
5
  require("./websocket-listener-factory.js");
6
6
  require("./inpage-listener-factory.js");
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "_NoopFlowController", { enumerable: true, get: f
45
45
  var transport_listener_js_1 = require("./transport-listener.js");
46
46
  Object.defineProperty(exports, "TransportListener", { enumerable: true, get: function () { return transport_listener_js_1.TransportListener; } });
47
47
  var transport_listener_factory_js_1 = require("./transport-listener-factory.js");
48
+ Object.defineProperty(exports, "TransportListenerFactory", { enumerable: true, get: function () { return transport_listener_factory_js_1.TransportListenerFactory; } });
48
49
  Object.defineProperty(exports, "TRANSPORT_LISTENER_FACTORY_BASE_TYPE", { enumerable: true, get: function () { return transport_listener_factory_js_1.TRANSPORT_LISTENER_FACTORY_BASE_TYPE; } });
49
50
  var default_http_server_js_1 = require("./default-http-server.js");
50
51
  Object.defineProperty(exports, "DefaultHttpServer", { enumerable: true, get: function () { return default_http_server_js_1.DefaultHttpServer; } });
@@ -69,7 +69,8 @@ class InPageConnectorFactory extends connector_factory_js_1.ConnectorFactory {
69
69
  const normalized = this._normalizeConfig(config);
70
70
  const options = (factoryArgs[0] ?? {});
71
71
  const normalizedLocalNodeFromConfig = this._normalizeNodeId(normalized.localNodeId);
72
- const localNodeId = this._normalizeNodeId(options.localNodeId) ?? normalizedLocalNodeFromConfig;
72
+ const localNodeId = this._normalizeNodeId(options.localNodeId) ??
73
+ normalizedLocalNodeFromConfig;
73
74
  if (!localNodeId) {
74
75
  throw new Error('InPageConnectorFactory requires a localNodeId from config or create() options');
75
76
  }
@@ -90,7 +90,8 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
90
90
  this.listenerRegistered = false;
91
91
  this.visibilityChangeListenerRegistered = false;
92
92
  this.channelName =
93
- typeof config.channelName === 'string' && config.channelName.trim().length > 0
93
+ typeof config.channelName === 'string' &&
94
+ config.channelName.trim().length > 0
94
95
  ? config.channelName.trim()
95
96
  : DEFAULT_CHANNEL;
96
97
  const preferredCapacity = typeof config.inboxCapacity === 'number' &&
@@ -129,7 +130,8 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
129
130
  channel: this.channelName,
130
131
  connector_id: this.connectorId,
131
132
  message_type: message && typeof message === 'object'
132
- ? message.constructor?.name ?? typeof message
133
+ ? (message.constructor
134
+ ?.name ?? typeof message)
133
135
  : typeof message,
134
136
  has_sender_id: Boolean(message?.senderId),
135
137
  has_sender_node_id: Boolean(message?.senderNodeId),
@@ -138,7 +140,8 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
138
140
  return;
139
141
  }
140
142
  const busMessage = message;
141
- const senderId = typeof busMessage.senderId === 'string' && busMessage.senderId.length > 0
143
+ const senderId = typeof busMessage.senderId === 'string' &&
144
+ busMessage.senderId.length > 0
142
145
  ? busMessage.senderId
143
146
  : null;
144
147
  const senderNodeId = InPageConnector.normalizeNodeId(busMessage.senderNodeId);
@@ -389,7 +392,9 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
389
392
  timestamp: new Date().toISOString(),
390
393
  });
391
394
  }
392
- if (this.visibilityChangeListenerRegistered && this.visibilityChangeHandler && typeof document !== 'undefined') {
395
+ if (this.visibilityChangeListenerRegistered &&
396
+ this.visibilityChangeHandler &&
397
+ typeof document !== 'undefined') {
393
398
  document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
394
399
  this.visibilityChangeListenerRegistered = false;
395
400
  this.visibilityChangeHandler = undefined;
@@ -406,7 +411,7 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
406
411
  return rawOrEnvelope;
407
412
  }
408
413
  _isWildcardTarget() {
409
- return this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined';
414
+ return (this.targetNodeId === '*' || typeof this.targetNodeId === 'undefined');
410
415
  }
411
416
  _shouldAcceptMessageFromBus(senderNodeId, targetNodeId) {
412
417
  if (this._isWildcardTarget()) {
@@ -426,7 +431,9 @@ class InPageConnector extends base_async_connector_js_1.BaseAsyncConnector {
426
431
  return true;
427
432
  }
428
433
  const expectedSender = this.targetNodeId;
429
- if (expectedSender && expectedSender !== '*' && senderNodeId !== expectedSender) {
434
+ if (expectedSender &&
435
+ expectedSender !== '*' &&
436
+ senderNodeId !== expectedSender) {
430
437
  logger.debug('inpage_message_rejected', {
431
438
  channel: this.channelName,
432
439
  connector_id: this.connectorId,
@@ -53,7 +53,9 @@ function normalizeConfig(config) {
53
53
  : DEFAULT_CHANNEL;
54
54
  const rawInbox = record.inboxCapacity ?? record['inbox_capacity'];
55
55
  let inboxCapacity = DEFAULT_INBOX_CAPACITY;
56
- if (typeof rawInbox === 'number' && Number.isFinite(rawInbox) && rawInbox > 0) {
56
+ if (typeof rawInbox === 'number' &&
57
+ Number.isFinite(rawInbox) &&
58
+ rawInbox > 0) {
57
59
  inboxCapacity = Math.floor(rawInbox);
58
60
  }
59
61
  else if (typeof rawInbox === 'string') {
@@ -81,9 +83,7 @@ class InPageListenerFactory extends transport_listener_factory_js_1.TransportLis
81
83
  }
82
84
  async create(config, ...factoryArgs) {
83
85
  const normalized = normalizeConfig(config);
84
- const [{ InPageListener }] = await Promise.all([
85
- getInPageListenerModule(),
86
- ]);
86
+ const [{ InPageListener }] = await Promise.all([getInPageListenerModule()]);
87
87
  void factoryArgs;
88
88
  return new InPageListener({
89
89
  channelName: normalized.channelName,
@@ -73,7 +73,9 @@ class InPageListener extends transport_listener_js_1.TransportListener {
73
73
  typeof channelCandidate === 'string' && channelCandidate.trim().length > 0
74
74
  ? channelCandidate.trim()
75
75
  : DEFAULT_CHANNEL;
76
- const normalizedCapacity = typeof inboxCandidate === 'number' && Number.isFinite(inboxCandidate) && inboxCandidate > 0
76
+ const normalizedCapacity = typeof inboxCandidate === 'number' &&
77
+ Number.isFinite(inboxCandidate) &&
78
+ inboxCandidate > 0
77
79
  ? Math.floor(inboxCandidate)
78
80
  : DEFAULT_INBOX_CAPACITY;
79
81
  this._inboxCapacity = normalizedCapacity;
@@ -348,7 +350,8 @@ class InPageListener extends transport_listener_js_1.TransportListener {
348
350
  if (grant.type === inpage_connection_grant_js_1.INPAGE_CONNECTION_GRANT_TYPE) {
349
351
  return (0, inpage_connection_grant_js_1.inPageGrantToConnectorConfig)(grant);
350
352
  }
351
- if (typeof grant?.toConnectorConfig === 'function') {
353
+ if (typeof grant
354
+ ?.toConnectorConfig === 'function') {
352
355
  return grant.toConnectorConfig();
353
356
  }
354
357
  throw new Error(`Unsupported grant type: ${grant.type}`);
@@ -149,9 +149,6 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
149
149
  this.ackDoneSince = new Map();
150
150
  this.replyDoneSince = new Map();
151
151
  this.pendingAckDispatches = new Set();
152
- this.recentlyHandled = new Map();
153
- this.recentlyHandledOrder = [];
154
- this.recentlyHandledTtlMs = 60000;
155
152
  this.isPreparingToStop = false;
156
153
  this.shutdownRequestedAtMs = null;
157
154
  this.shutdownRetryGraceMs = 1000;
@@ -387,22 +384,6 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
387
384
  }
388
385
  }
389
386
  else {
390
- const wasRecentlyHandled = await this.lock.runExclusive(async () => this.wasRecentlyHandled(envelope.id));
391
- if (wasRecentlyHandled) {
392
- logger.debug('tracker_duplicate_envelope_recently_handled', {
393
- envp_id: envelope.id,
394
- });
395
- return new tracked_envelope_js_1.TrackedEnvelope({
396
- timeoutAtMs: 0,
397
- overallTimeoutAtMs: 0,
398
- expectedResponseType: envelope.rtype ?? core_1.FameResponseType.NONE,
399
- createdAtMs: Date.now(),
400
- status: tracked_envelope_js_1.EnvelopeStatus.HANDLED,
401
- mailboxType: tracked_envelope_js_1.MailboxType.INBOX,
402
- originalEnvelope: envelope,
403
- serviceName: inboxName,
404
- });
405
- }
406
387
  tracked = new tracked_envelope_js_1.TrackedEnvelope({
407
388
  timeoutAtMs: 0,
408
389
  overallTimeoutAtMs: 0,
@@ -424,12 +405,8 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
424
405
  async onEnvelopeHandled(envelope) {
425
406
  const inbox = this.ensureInbox();
426
407
  envelope.status = tracked_envelope_js_1.EnvelopeStatus.HANDLED;
408
+ // Delete the envelope from inbox to prevent growth
427
409
  await inbox.delete(envelope.originalEnvelope.id);
428
- await this.lock.runExclusive(async () => {
429
- this.markRecentlyHandled(envelope.originalEnvelope.id);
430
- });
431
- // Preserve handled envelope to prevent duplicate redelivery during shutdown drains.
432
- // await inbox.set(envelope.originalEnvelope.id, envelope);
433
410
  }
434
411
  async onEnvelopeHandleFailed(inboxName, envelope, context, error, isFinalFailure = false) {
435
412
  void context;
@@ -648,9 +625,9 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
648
625
  });
649
626
  await this.markDoneSince(this.replyFutures, trackedEnvelope.originalEnvelope.id, this.replyDoneSince);
650
627
  await this.markDoneSince(this.ackFutures, trackedEnvelope.originalEnvelope.id, this.ackDoneSince);
651
- if (envelope.rtype && Boolean(envelope.rtype & core_1.FameResponseType.ACK)) {
652
- await this.sendAck(envelope);
653
- }
628
+ // Note: ACK is already sent in onCorrelatedMessage (lines 655-657)
629
+ // when the reply envelope is first delivered. No need to send it again here.
630
+ // Removing this duplicate sendAck call fixes the duplicate DeliveryAck bug.
654
631
  for (const handler of this.eventHandlers) {
655
632
  await handler.onEnvelopeReplied?.(trackedEnvelope, envelope);
656
633
  }
@@ -800,8 +777,6 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
800
777
  }
801
778
  this.streamDone.clear();
802
779
  this.correlationToEnvelope.clear();
803
- this.recentlyHandled.clear();
804
- this.recentlyHandledOrder.length = 0;
805
780
  return values;
806
781
  });
807
782
  for (const timer of timers) {
@@ -1383,39 +1358,6 @@ class DefaultDeliveryTracker extends task_spawner_js_1.TaskSpawner {
1383
1358
  this.pendingAckDispatches.delete(ackDispatch);
1384
1359
  }
1385
1360
  }
1386
- markRecentlyHandled(envelopeId) {
1387
- const now = Date.now();
1388
- this.recentlyHandled.set(envelopeId, now);
1389
- this.recentlyHandledOrder.push(envelopeId);
1390
- this.trimRecentlyHandled(now);
1391
- }
1392
- wasRecentlyHandled(envelopeId) {
1393
- const now = Date.now();
1394
- const timestamp = this.recentlyHandled.get(envelopeId);
1395
- if (timestamp === undefined) {
1396
- return false;
1397
- }
1398
- if (now - timestamp > this.recentlyHandledTtlMs) {
1399
- this.recentlyHandled.delete(envelopeId);
1400
- return false;
1401
- }
1402
- return true;
1403
- }
1404
- trimRecentlyHandled(now) {
1405
- while (this.recentlyHandledOrder.length > 0) {
1406
- const candidate = this.recentlyHandledOrder[0];
1407
- const timestamp = this.recentlyHandled.get(candidate);
1408
- if (timestamp === undefined) {
1409
- this.recentlyHandledOrder.shift();
1410
- continue;
1411
- }
1412
- if (now - timestamp <= this.recentlyHandledTtlMs) {
1413
- break;
1414
- }
1415
- this.recentlyHandled.delete(candidate);
1416
- this.recentlyHandledOrder.shift();
1417
- }
1418
- }
1419
1361
  getShutdownRetryDeferDelay(nowMs) {
1420
1362
  if (!this.isPreparingToStop || this.shutdownRequestedAtMs === null) {
1421
1363
  return null;
@@ -47,14 +47,16 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
47
47
  type,
48
48
  purpose,
49
49
  };
50
- const channelValue = candidate.channelName ?? candidate['channel_name'];
50
+ const channelValue = candidate.channelName ??
51
+ candidate['channel_name'];
51
52
  if (channelValue !== undefined) {
52
53
  if (typeof channelValue !== 'string' || channelValue.trim().length === 0) {
53
54
  throw new TypeError('BroadcastChannelConnectionGrant "channelName" must be a non-empty string when provided');
54
55
  }
55
56
  result.channelName = channelValue.trim();
56
57
  }
57
- const inboxValue = candidate.inboxCapacity ?? candidate['inbox_capacity'];
58
+ const inboxValue = candidate.inboxCapacity ??
59
+ candidate['inbox_capacity'];
58
60
  if (inboxValue !== undefined) {
59
61
  if (typeof inboxValue !== 'number' ||
60
62
  !Number.isFinite(inboxValue) ||
@@ -63,7 +65,8 @@ function normalizeBroadcastChannelConnectionGrant(candidate) {
63
65
  }
64
66
  result.inboxCapacity = Math.floor(inboxValue);
65
67
  }
66
- const windowValue = candidate.initialWindow ?? candidate['initial_window'];
68
+ const windowValue = candidate.initialWindow ??
69
+ candidate['initial_window'];
67
70
  if (windowValue !== undefined) {
68
71
  if (typeof windowValue !== 'number' ||
69
72
  !Number.isFinite(windowValue) ||
@@ -42,14 +42,16 @@ function normalizeInPageConnectionGrant(candidate) {
42
42
  type,
43
43
  purpose,
44
44
  };
45
- const channelValue = candidate.channelName ?? candidate['channel_name'];
45
+ const channelValue = candidate.channelName ??
46
+ candidate['channel_name'];
46
47
  if (channelValue !== undefined) {
47
48
  if (typeof channelValue !== 'string' || channelValue.trim().length === 0) {
48
49
  throw new TypeError('InPageConnectionGrant "channelName" must be a non-empty string when provided');
49
50
  }
50
51
  result.channelName = channelValue.trim();
51
52
  }
52
- const inboxValue = candidate.inboxCapacity ?? candidate['inbox_capacity'];
53
+ const inboxValue = candidate.inboxCapacity ??
54
+ candidate['inbox_capacity'];
53
55
  if (inboxValue !== undefined) {
54
56
  if (typeof inboxValue !== 'number' ||
55
57
  !Number.isFinite(inboxValue) ||
@@ -423,7 +423,9 @@ function parseCookies(cookieHeader) {
423
423
  if (!cookieHeader) {
424
424
  return {};
425
425
  }
426
- return cookieHeader.split(';').reduce((acc, entry) => {
426
+ return cookieHeader
427
+ .split(';')
428
+ .reduce((acc, entry) => {
427
429
  const [rawName, ...rawValueParts] = entry.split('=');
428
430
  const name = rawName?.trim();
429
431
  if (!name) {
@@ -571,10 +573,7 @@ function setNoCacheHeaders(res) {
571
573
  res.set('Pragma', 'no-cache');
572
574
  }
573
575
  function respondInvalidClient(res) {
574
- res
575
- .status(401)
576
- .set('WWW-Authenticate', 'Basic')
577
- .json({
576
+ res.status(401).set('WWW-Authenticate', 'Basic').json({
578
577
  error: 'invalid_client',
579
578
  error_description: 'Invalid client credentials',
580
579
  });
@@ -611,10 +610,10 @@ function createOAuth2TokenRouter(options) {
611
610
  DEFAULT_JWT_ALGORITHM;
612
611
  const allowedScopes = getAllowedScopes(configAllowedScopes);
613
612
  const resolvedTokenTtlSec = tokenTtlSec ?? 3600;
614
- const enablePkce = coerceBoolean(process.env[ENV_VAR_ENABLE_PKCE]) ??
615
- (configEnablePkce ?? true);
613
+ const enablePkce = coerceBoolean(process.env[ENV_VAR_ENABLE_PKCE]) ?? configEnablePkce ?? true;
616
614
  const allowPublicClients = coerceBoolean(process.env[ENV_VAR_ALLOW_PUBLIC_CLIENTS]) ??
617
- (configAllowPublicClients ?? true);
615
+ configAllowPublicClients ??
616
+ true;
618
617
  const authorizationCodeTtlSec = ensurePositiveInteger(coerceNumber(process.env[ENV_VAR_AUTHORIZATION_CODE_TTL]) ??
619
618
  configAuthorizationCodeTtlSec) ?? DEFAULT_AUTHORIZATION_CODE_TTL_SEC;
620
619
  const devLoginExplicitlyEnabled = coerceBoolean(process.env[ENV_VAR_ENABLE_DEV_LOGIN]) ??
@@ -629,7 +628,8 @@ function createOAuth2TokenRouter(options) {
629
628
  configDevLoginCookieName ??
630
629
  DEFAULT_SESSION_COOKIE_NAME;
631
630
  const devLoginSecureCookie = coerceBoolean(process.env[ENV_VAR_SESSION_SECURE_COOKIE]) ??
632
- (configDevLoginSecureCookie ?? false);
631
+ configDevLoginSecureCookie ??
632
+ false;
633
633
  const devLoginTitle = coerceString(process.env[ENV_VAR_LOGIN_TITLE]) ??
634
634
  configDevLoginTitle ??
635
635
  DEFAULT_LOGIN_TITLE;
@@ -11,15 +11,30 @@ 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
26
+ ?.systemId;
27
+ if (!frameSystemId || frameSystemId === this.expectedSystemId) {
28
+ this.buffer.push(envelope);
29
+ }
30
+ else {
31
+ // Silently ignore frames from other agents during concurrent handshakes
32
+ logger.debug('handshake_ignoring_frame_from_different_system', {
33
+ frame_type: envelope.frame.type,
34
+ frame_system_id: frameSystemId,
35
+ expected_system_id: this.expectedSystemId,
36
+ });
37
+ }
23
38
  return null;
24
39
  }
25
40
  return finalHandler(envelope, context);
@@ -146,6 +161,7 @@ class DefaultNodeAttachClient {
146
161
  parent_id: ackFrame.targetSystemId,
147
162
  });
148
163
  this.inHandshake = false;
164
+ this.expectedSystemId = null;
149
165
  await connector.replaceHandler(finalHandler);
150
166
  while (this.buffer.length > 0) {
151
167
  const bufferedEnvelope = this.buffer.shift();
@@ -203,7 +219,8 @@ class DefaultNodeAttachClient {
203
219
  const deadline = Date.now() + this.timeoutMs;
204
220
  while (Date.now() < deadline) {
205
221
  // Allow both STARTED and PAUSED states (PAUSED = tab hidden but connection alive)
206
- if (connector.state !== core_1.ConnectorState.STARTED && connector.state !== core_1.ConnectorState.PAUSED) {
222
+ if (connector.state !== core_1.ConnectorState.STARTED &&
223
+ connector.state !== core_1.ConnectorState.PAUSED) {
207
224
  let errorMessage = 'Connector closed while waiting for NodeAttachAck';
208
225
  if (connector.closeCode !== undefined) {
209
226
  errorMessage += ` (code=${connector.closeCode}`;
@@ -222,9 +239,21 @@ class DefaultNodeAttachClient {
222
239
  if (envelope.frame.type === 'NodeAttachAck') {
223
240
  return envelope;
224
241
  }
225
- logger.error('unexpected_frame_during_handshake', {
226
- frame_type: envelope.frame.type,
227
- });
242
+ // NodeAttach frames during handshake are expected in multi-agent scenarios
243
+ // where multiple agents attach concurrently to the same channel
244
+ if (envelope.frame.type === 'NodeAttach') {
245
+ logger.debug('handshake_ignoring_concurrent_attach', {
246
+ frame_type: envelope.frame.type,
247
+ frame_system_id: envelope.frame?.systemId ??
248
+ 'unknown',
249
+ });
250
+ }
251
+ else {
252
+ // Other unexpected frames are still logged as errors
253
+ logger.error('unexpected_frame_during_handshake', {
254
+ frame_type: envelope.frame.type,
255
+ });
256
+ }
228
257
  }
229
258
  await (0, task_utils_js_1.delay)(HANDSHAKE_POLL_INTERVAL_MS);
230
259
  }