@naylence/runtime 0.3.6-test.104 → 0.3.6-test.108

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.104
101
+ // Generated from package.json version: 0.3.6-test.108
102
102
  /**
103
103
  * The package version, injected at build time.
104
104
  * @internal
105
105
  */
106
- const VERSION = '0.3.6-test.104';
106
+ const VERSION = '0.3.6-test.108';
107
107
 
108
108
  /**
109
109
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -7175,9 +7175,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7175
7175
  this.ackDoneSince = new Map();
7176
7176
  this.replyDoneSince = new Map();
7177
7177
  this.pendingAckDispatches = new Set();
7178
- this.recentlyHandled = new Map();
7179
- this.recentlyHandledOrder = [];
7180
- this.recentlyHandledTtlMs = 60000;
7181
7178
  this.isPreparingToStop = false;
7182
7179
  this.shutdownRequestedAtMs = null;
7183
7180
  this.shutdownRetryGraceMs = 1000;
@@ -7399,22 +7396,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7399
7396
  }
7400
7397
  }
7401
7398
  else {
7402
- const wasRecentlyHandled = await this.lock.runExclusive(async () => this.wasRecentlyHandled(envelope.id));
7403
- if (wasRecentlyHandled) {
7404
- logger$12.debug('tracker_duplicate_envelope_recently_handled', {
7405
- envp_id: envelope.id,
7406
- });
7407
- return new TrackedEnvelope({
7408
- timeoutAtMs: 0,
7409
- overallTimeoutAtMs: 0,
7410
- expectedResponseType: envelope.rtype ?? core.FameResponseType.NONE,
7411
- createdAtMs: Date.now(),
7412
- status: EnvelopeStatus.HANDLED,
7413
- mailboxType: MailboxType.INBOX,
7414
- originalEnvelope: envelope,
7415
- serviceName: inboxName,
7416
- });
7417
- }
7418
7399
  tracked = new TrackedEnvelope({
7419
7400
  timeoutAtMs: 0,
7420
7401
  overallTimeoutAtMs: 0,
@@ -7436,12 +7417,8 @@ class DefaultDeliveryTracker extends TaskSpawner {
7436
7417
  async onEnvelopeHandled(envelope) {
7437
7418
  const inbox = this.ensureInbox();
7438
7419
  envelope.status = EnvelopeStatus.HANDLED;
7420
+ // Delete the envelope from inbox to prevent growth
7439
7421
  await inbox.delete(envelope.originalEnvelope.id);
7440
- await this.lock.runExclusive(async () => {
7441
- this.markRecentlyHandled(envelope.originalEnvelope.id);
7442
- });
7443
- // Preserve handled envelope to prevent duplicate redelivery during shutdown drains.
7444
- // await inbox.set(envelope.originalEnvelope.id, envelope);
7445
7422
  }
7446
7423
  async onEnvelopeHandleFailed(inboxName, envelope, context, error, isFinalFailure = false) {
7447
7424
  const inbox = this.ensureInbox();
@@ -7656,9 +7633,9 @@ class DefaultDeliveryTracker extends TaskSpawner {
7656
7633
  });
7657
7634
  await this.markDoneSince(this.replyFutures, trackedEnvelope.originalEnvelope.id, this.replyDoneSince);
7658
7635
  await this.markDoneSince(this.ackFutures, trackedEnvelope.originalEnvelope.id, this.ackDoneSince);
7659
- if (envelope.rtype && Boolean(envelope.rtype & core.FameResponseType.ACK)) {
7660
- await this.sendAck(envelope);
7661
- }
7636
+ // Note: ACK is already sent in onCorrelatedMessage (lines 655-657)
7637
+ // when the reply envelope is first delivered. No need to send it again here.
7638
+ // Removing this duplicate sendAck call fixes the duplicate DeliveryAck bug.
7662
7639
  for (const handler of this.eventHandlers) {
7663
7640
  await handler.onEnvelopeReplied?.(trackedEnvelope, envelope);
7664
7641
  }
@@ -7808,8 +7785,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7808
7785
  }
7809
7786
  this.streamDone.clear();
7810
7787
  this.correlationToEnvelope.clear();
7811
- this.recentlyHandled.clear();
7812
- this.recentlyHandledOrder.length = 0;
7813
7788
  return values;
7814
7789
  });
7815
7790
  for (const timer of timers) {
@@ -8391,39 +8366,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
8391
8366
  this.pendingAckDispatches.delete(ackDispatch);
8392
8367
  }
8393
8368
  }
8394
- markRecentlyHandled(envelopeId) {
8395
- const now = Date.now();
8396
- this.recentlyHandled.set(envelopeId, now);
8397
- this.recentlyHandledOrder.push(envelopeId);
8398
- this.trimRecentlyHandled(now);
8399
- }
8400
- wasRecentlyHandled(envelopeId) {
8401
- const now = Date.now();
8402
- const timestamp = this.recentlyHandled.get(envelopeId);
8403
- if (timestamp === undefined) {
8404
- return false;
8405
- }
8406
- if (now - timestamp > this.recentlyHandledTtlMs) {
8407
- this.recentlyHandled.delete(envelopeId);
8408
- return false;
8409
- }
8410
- return true;
8411
- }
8412
- trimRecentlyHandled(now) {
8413
- while (this.recentlyHandledOrder.length > 0) {
8414
- const candidate = this.recentlyHandledOrder[0];
8415
- const timestamp = this.recentlyHandled.get(candidate);
8416
- if (timestamp === undefined) {
8417
- this.recentlyHandledOrder.shift();
8418
- continue;
8419
- }
8420
- if (now - timestamp <= this.recentlyHandledTtlMs) {
8421
- break;
8422
- }
8423
- this.recentlyHandled.delete(candidate);
8424
- this.recentlyHandledOrder.shift();
8425
- }
8426
- }
8427
8369
  getShutdownRetryDeferDelay(nowMs) {
8428
8370
  if (!this.isPreparingToStop || this.shutdownRequestedAtMs === null) {
8429
8371
  return null;
@@ -9996,6 +9938,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9996
9938
  local_node_id: this.localNodeId,
9997
9939
  target_node_id: this.targetNodeId ?? null,
9998
9940
  inbox_capacity: preferredCapacity,
9941
+ passive: config.passive ?? false,
9999
9942
  timestamp: new Date().toISOString(),
10000
9943
  });
10001
9944
  this.onMsg = (event) => {
@@ -29229,6 +29172,7 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
29229
29172
  inboxCapacity,
29230
29173
  localNodeId,
29231
29174
  initialTargetNodeId: resolvedTarget,
29175
+ passive: normalized.passive,
29232
29176
  };
29233
29177
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
29234
29178
  if (options.authorization) {
@@ -29267,6 +29211,9 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
29267
29211
  if (normalizedLocalNodeId) {
29268
29212
  normalized.localNodeId = normalizedLocalNodeId;
29269
29213
  }
29214
+ if (typeof candidate.passive === 'boolean') {
29215
+ normalized.passive = candidate.passive;
29216
+ }
29270
29217
  if (typeof candidate.flowControl === 'boolean') {
29271
29218
  normalized.flowControl = candidate.flowControl;
29272
29219
  }
@@ -30610,11 +30557,19 @@ class BroadcastChannelListener extends TransportListener {
30610
30557
  ? Math.floor(initialWindowCandidate)
30611
30558
  : undefined;
30612
30559
  const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
30560
+ const passive = typeof passiveCandidate === 'boolean' ? passiveCandidate : true;
30561
+ logger$o.debug('broadcast_channel_listener_building_connector_config', {
30562
+ system_id: systemId,
30563
+ channel_name: channelName,
30564
+ passive,
30565
+ has_base_config: !!baseConfig,
30566
+ passive_candidate: passiveCandidate,
30567
+ });
30613
30568
  return {
30614
30569
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
30615
30570
  channelName,
30616
30571
  inboxCapacity,
30617
- passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
30572
+ passive,
30618
30573
  initialWindow,
30619
30574
  localNodeId,
30620
30575
  initialTargetNodeId,
@@ -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.104
99
+ // Generated from package.json version: 0.3.6-test.108
100
100
  /**
101
101
  * The package version, injected at build time.
102
102
  * @internal
103
103
  */
104
- const VERSION = '0.3.6-test.104';
104
+ const VERSION = '0.3.6-test.108';
105
105
 
106
106
  /**
107
107
  * Fame protocol specific error classes with WebSocket close codes and proper inheritance.
@@ -7173,9 +7173,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7173
7173
  this.ackDoneSince = new Map();
7174
7174
  this.replyDoneSince = new Map();
7175
7175
  this.pendingAckDispatches = new Set();
7176
- this.recentlyHandled = new Map();
7177
- this.recentlyHandledOrder = [];
7178
- this.recentlyHandledTtlMs = 60000;
7179
7176
  this.isPreparingToStop = false;
7180
7177
  this.shutdownRequestedAtMs = null;
7181
7178
  this.shutdownRetryGraceMs = 1000;
@@ -7397,22 +7394,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7397
7394
  }
7398
7395
  }
7399
7396
  else {
7400
- const wasRecentlyHandled = await this.lock.runExclusive(async () => this.wasRecentlyHandled(envelope.id));
7401
- if (wasRecentlyHandled) {
7402
- logger$12.debug('tracker_duplicate_envelope_recently_handled', {
7403
- envp_id: envelope.id,
7404
- });
7405
- return new TrackedEnvelope({
7406
- timeoutAtMs: 0,
7407
- overallTimeoutAtMs: 0,
7408
- expectedResponseType: envelope.rtype ?? FameResponseType.NONE,
7409
- createdAtMs: Date.now(),
7410
- status: EnvelopeStatus.HANDLED,
7411
- mailboxType: MailboxType.INBOX,
7412
- originalEnvelope: envelope,
7413
- serviceName: inboxName,
7414
- });
7415
- }
7416
7397
  tracked = new TrackedEnvelope({
7417
7398
  timeoutAtMs: 0,
7418
7399
  overallTimeoutAtMs: 0,
@@ -7434,12 +7415,8 @@ class DefaultDeliveryTracker extends TaskSpawner {
7434
7415
  async onEnvelopeHandled(envelope) {
7435
7416
  const inbox = this.ensureInbox();
7436
7417
  envelope.status = EnvelopeStatus.HANDLED;
7418
+ // Delete the envelope from inbox to prevent growth
7437
7419
  await inbox.delete(envelope.originalEnvelope.id);
7438
- await this.lock.runExclusive(async () => {
7439
- this.markRecentlyHandled(envelope.originalEnvelope.id);
7440
- });
7441
- // Preserve handled envelope to prevent duplicate redelivery during shutdown drains.
7442
- // await inbox.set(envelope.originalEnvelope.id, envelope);
7443
7420
  }
7444
7421
  async onEnvelopeHandleFailed(inboxName, envelope, context, error, isFinalFailure = false) {
7445
7422
  const inbox = this.ensureInbox();
@@ -7654,9 +7631,9 @@ class DefaultDeliveryTracker extends TaskSpawner {
7654
7631
  });
7655
7632
  await this.markDoneSince(this.replyFutures, trackedEnvelope.originalEnvelope.id, this.replyDoneSince);
7656
7633
  await this.markDoneSince(this.ackFutures, trackedEnvelope.originalEnvelope.id, this.ackDoneSince);
7657
- if (envelope.rtype && Boolean(envelope.rtype & FameResponseType.ACK)) {
7658
- await this.sendAck(envelope);
7659
- }
7634
+ // Note: ACK is already sent in onCorrelatedMessage (lines 655-657)
7635
+ // when the reply envelope is first delivered. No need to send it again here.
7636
+ // Removing this duplicate sendAck call fixes the duplicate DeliveryAck bug.
7660
7637
  for (const handler of this.eventHandlers) {
7661
7638
  await handler.onEnvelopeReplied?.(trackedEnvelope, envelope);
7662
7639
  }
@@ -7806,8 +7783,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
7806
7783
  }
7807
7784
  this.streamDone.clear();
7808
7785
  this.correlationToEnvelope.clear();
7809
- this.recentlyHandled.clear();
7810
- this.recentlyHandledOrder.length = 0;
7811
7786
  return values;
7812
7787
  });
7813
7788
  for (const timer of timers) {
@@ -8389,39 +8364,6 @@ class DefaultDeliveryTracker extends TaskSpawner {
8389
8364
  this.pendingAckDispatches.delete(ackDispatch);
8390
8365
  }
8391
8366
  }
8392
- markRecentlyHandled(envelopeId) {
8393
- const now = Date.now();
8394
- this.recentlyHandled.set(envelopeId, now);
8395
- this.recentlyHandledOrder.push(envelopeId);
8396
- this.trimRecentlyHandled(now);
8397
- }
8398
- wasRecentlyHandled(envelopeId) {
8399
- const now = Date.now();
8400
- const timestamp = this.recentlyHandled.get(envelopeId);
8401
- if (timestamp === undefined) {
8402
- return false;
8403
- }
8404
- if (now - timestamp > this.recentlyHandledTtlMs) {
8405
- this.recentlyHandled.delete(envelopeId);
8406
- return false;
8407
- }
8408
- return true;
8409
- }
8410
- trimRecentlyHandled(now) {
8411
- while (this.recentlyHandledOrder.length > 0) {
8412
- const candidate = this.recentlyHandledOrder[0];
8413
- const timestamp = this.recentlyHandled.get(candidate);
8414
- if (timestamp === undefined) {
8415
- this.recentlyHandledOrder.shift();
8416
- continue;
8417
- }
8418
- if (now - timestamp <= this.recentlyHandledTtlMs) {
8419
- break;
8420
- }
8421
- this.recentlyHandled.delete(candidate);
8422
- this.recentlyHandledOrder.shift();
8423
- }
8424
- }
8425
8367
  getShutdownRetryDeferDelay(nowMs) {
8426
8368
  if (!this.isPreparingToStop || this.shutdownRequestedAtMs === null) {
8427
8369
  return null;
@@ -9994,6 +9936,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
9994
9936
  local_node_id: this.localNodeId,
9995
9937
  target_node_id: this.targetNodeId ?? null,
9996
9938
  inbox_capacity: preferredCapacity,
9939
+ passive: config.passive ?? false,
9997
9940
  timestamp: new Date().toISOString(),
9998
9941
  });
9999
9942
  this.onMsg = (event) => {
@@ -29227,6 +29170,7 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
29227
29170
  inboxCapacity,
29228
29171
  localNodeId,
29229
29172
  initialTargetNodeId: resolvedTarget,
29173
+ passive: normalized.passive,
29230
29174
  };
29231
29175
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
29232
29176
  if (options.authorization) {
@@ -29265,6 +29209,9 @@ class BroadcastChannelConnectorFactory extends ConnectorFactory {
29265
29209
  if (normalizedLocalNodeId) {
29266
29210
  normalized.localNodeId = normalizedLocalNodeId;
29267
29211
  }
29212
+ if (typeof candidate.passive === 'boolean') {
29213
+ normalized.passive = candidate.passive;
29214
+ }
29268
29215
  if (typeof candidate.flowControl === 'boolean') {
29269
29216
  normalized.flowControl = candidate.flowControl;
29270
29217
  }
@@ -30608,11 +30555,19 @@ class BroadcastChannelListener extends TransportListener {
30608
30555
  ? Math.floor(initialWindowCandidate)
30609
30556
  : undefined;
30610
30557
  const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
30558
+ const passive = typeof passiveCandidate === 'boolean' ? passiveCandidate : true;
30559
+ logger$o.debug('broadcast_channel_listener_building_connector_config', {
30560
+ system_id: systemId,
30561
+ channel_name: channelName,
30562
+ passive,
30563
+ has_base_config: !!baseConfig,
30564
+ passive_candidate: passiveCandidate,
30565
+ });
30611
30566
  return {
30612
30567
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
30613
30568
  channelName,
30614
30569
  inboxCapacity,
30615
- passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
30570
+ passive,
30616
30571
  initialWindow,
30617
30572
  localNodeId,
30618
30573
  initialTargetNodeId,
@@ -101,6 +101,7 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
101
101
  inboxCapacity,
102
102
  localNodeId,
103
103
  initialTargetNodeId: resolvedTarget,
104
+ passive: normalized.passive,
104
105
  };
105
106
  const connector = new broadcast_channel_connector_js_1.BroadcastChannelConnector(connectorConfig, baseConfig);
106
107
  if (options.authorization) {
@@ -139,6 +140,9 @@ class BroadcastChannelConnectorFactory extends connector_factory_js_1.ConnectorF
139
140
  if (normalizedLocalNodeId) {
140
141
  normalized.localNodeId = normalizedLocalNodeId;
141
142
  }
143
+ if (typeof candidate.passive === 'boolean') {
144
+ normalized.passive = candidate.passive;
145
+ }
142
146
  if (typeof candidate.flowControl === 'boolean') {
143
147
  normalized.flowControl = candidate.flowControl;
144
148
  }
@@ -99,6 +99,7 @@ class BroadcastChannelConnector extends base_async_connector_js_1.BaseAsyncConne
99
99
  local_node_id: this.localNodeId,
100
100
  target_node_id: this.targetNodeId ?? null,
101
101
  inbox_capacity: preferredCapacity,
102
+ passive: config.passive ?? false,
102
103
  timestamp: new Date().toISOString(),
103
104
  });
104
105
  this.onMsg = (event) => {
@@ -455,11 +455,19 @@ class BroadcastChannelListener extends transport_listener_js_1.TransportListener
455
455
  ? Math.floor(initialWindowCandidate)
456
456
  : undefined;
457
457
  const initialTargetNodeId = this._normalizeNodeId(targetCandidate) ?? targetSystemId;
458
+ const passive = typeof passiveCandidate === 'boolean' ? passiveCandidate : true;
459
+ logger.debug('broadcast_channel_listener_building_connector_config', {
460
+ system_id: systemId,
461
+ channel_name: channelName,
462
+ passive,
463
+ has_base_config: !!baseConfig,
464
+ passive_candidate: passiveCandidate,
465
+ });
458
466
  return {
459
467
  type: broadcast_channel_connector_js_1.BROADCAST_CHANNEL_CONNECTOR_TYPE,
460
468
  channelName,
461
469
  inboxCapacity,
462
- passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
470
+ passive,
463
471
  initialWindow,
464
472
  localNodeId,
465
473
  initialTargetNodeId,
@@ -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;
@@ -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.104
3
+ // Generated from package.json version: 0.3.6-test.108
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.104';
10
+ exports.VERSION = '0.3.6-test.108';
@@ -98,6 +98,7 @@ export class BroadcastChannelConnectorFactory extends ConnectorFactory {
98
98
  inboxCapacity,
99
99
  localNodeId,
100
100
  initialTargetNodeId: resolvedTarget,
101
+ passive: normalized.passive,
101
102
  };
102
103
  const connector = new BroadcastChannelConnector(connectorConfig, baseConfig);
103
104
  if (options.authorization) {
@@ -136,6 +137,9 @@ export class BroadcastChannelConnectorFactory extends ConnectorFactory {
136
137
  if (normalizedLocalNodeId) {
137
138
  normalized.localNodeId = normalizedLocalNodeId;
138
139
  }
140
+ if (typeof candidate.passive === 'boolean') {
141
+ normalized.passive = candidate.passive;
142
+ }
139
143
  if (typeof candidate.flowControl === 'boolean') {
140
144
  normalized.flowControl = candidate.flowControl;
141
145
  }
@@ -96,6 +96,7 @@ export class BroadcastChannelConnector extends BaseAsyncConnector {
96
96
  local_node_id: this.localNodeId,
97
97
  target_node_id: this.targetNodeId ?? null,
98
98
  inbox_capacity: preferredCapacity,
99
+ passive: config.passive ?? false,
99
100
  timestamp: new Date().toISOString(),
100
101
  });
101
102
  this.onMsg = (event) => {
@@ -451,11 +451,19 @@ export class BroadcastChannelListener extends TransportListener {
451
451
  ? Math.floor(initialWindowCandidate)
452
452
  : undefined;
453
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
+ });
454
462
  return {
455
463
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE,
456
464
  channelName,
457
465
  inboxCapacity,
458
- passive: typeof passiveCandidate === 'boolean' ? passiveCandidate : true,
466
+ passive,
459
467
  initialWindow,
460
468
  localNodeId,
461
469
  initialTargetNodeId,
@@ -146,9 +146,6 @@ export class DefaultDeliveryTracker extends TaskSpawner {
146
146
  this.ackDoneSince = new Map();
147
147
  this.replyDoneSince = new Map();
148
148
  this.pendingAckDispatches = new Set();
149
- this.recentlyHandled = new Map();
150
- this.recentlyHandledOrder = [];
151
- this.recentlyHandledTtlMs = 60000;
152
149
  this.isPreparingToStop = false;
153
150
  this.shutdownRequestedAtMs = null;
154
151
  this.shutdownRetryGraceMs = 1000;
@@ -384,22 +381,6 @@ export class DefaultDeliveryTracker extends TaskSpawner {
384
381
  }
385
382
  }
386
383
  else {
387
- const wasRecentlyHandled = await this.lock.runExclusive(async () => this.wasRecentlyHandled(envelope.id));
388
- if (wasRecentlyHandled) {
389
- logger.debug('tracker_duplicate_envelope_recently_handled', {
390
- envp_id: envelope.id,
391
- });
392
- return new TrackedEnvelope({
393
- timeoutAtMs: 0,
394
- overallTimeoutAtMs: 0,
395
- expectedResponseType: envelope.rtype ?? FameResponseType.NONE,
396
- createdAtMs: Date.now(),
397
- status: EnvelopeStatus.HANDLED,
398
- mailboxType: MailboxType.INBOX,
399
- originalEnvelope: envelope,
400
- serviceName: inboxName,
401
- });
402
- }
403
384
  tracked = new TrackedEnvelope({
404
385
  timeoutAtMs: 0,
405
386
  overallTimeoutAtMs: 0,
@@ -421,12 +402,8 @@ export class DefaultDeliveryTracker extends TaskSpawner {
421
402
  async onEnvelopeHandled(envelope) {
422
403
  const inbox = this.ensureInbox();
423
404
  envelope.status = EnvelopeStatus.HANDLED;
405
+ // Delete the envelope from inbox to prevent growth
424
406
  await inbox.delete(envelope.originalEnvelope.id);
425
- await this.lock.runExclusive(async () => {
426
- this.markRecentlyHandled(envelope.originalEnvelope.id);
427
- });
428
- // Preserve handled envelope to prevent duplicate redelivery during shutdown drains.
429
- // await inbox.set(envelope.originalEnvelope.id, envelope);
430
407
  }
431
408
  async onEnvelopeHandleFailed(inboxName, envelope, context, error, isFinalFailure = false) {
432
409
  void context;
@@ -645,9 +622,9 @@ export class DefaultDeliveryTracker extends TaskSpawner {
645
622
  });
646
623
  await this.markDoneSince(this.replyFutures, trackedEnvelope.originalEnvelope.id, this.replyDoneSince);
647
624
  await this.markDoneSince(this.ackFutures, trackedEnvelope.originalEnvelope.id, this.ackDoneSince);
648
- if (envelope.rtype && Boolean(envelope.rtype & FameResponseType.ACK)) {
649
- await this.sendAck(envelope);
650
- }
625
+ // Note: ACK is already sent in onCorrelatedMessage (lines 655-657)
626
+ // when the reply envelope is first delivered. No need to send it again here.
627
+ // Removing this duplicate sendAck call fixes the duplicate DeliveryAck bug.
651
628
  for (const handler of this.eventHandlers) {
652
629
  await handler.onEnvelopeReplied?.(trackedEnvelope, envelope);
653
630
  }
@@ -797,8 +774,6 @@ export class DefaultDeliveryTracker extends TaskSpawner {
797
774
  }
798
775
  this.streamDone.clear();
799
776
  this.correlationToEnvelope.clear();
800
- this.recentlyHandled.clear();
801
- this.recentlyHandledOrder.length = 0;
802
777
  return values;
803
778
  });
804
779
  for (const timer of timers) {
@@ -1380,39 +1355,6 @@ export class DefaultDeliveryTracker extends TaskSpawner {
1380
1355
  this.pendingAckDispatches.delete(ackDispatch);
1381
1356
  }
1382
1357
  }
1383
- markRecentlyHandled(envelopeId) {
1384
- const now = Date.now();
1385
- this.recentlyHandled.set(envelopeId, now);
1386
- this.recentlyHandledOrder.push(envelopeId);
1387
- this.trimRecentlyHandled(now);
1388
- }
1389
- wasRecentlyHandled(envelopeId) {
1390
- const now = Date.now();
1391
- const timestamp = this.recentlyHandled.get(envelopeId);
1392
- if (timestamp === undefined) {
1393
- return false;
1394
- }
1395
- if (now - timestamp > this.recentlyHandledTtlMs) {
1396
- this.recentlyHandled.delete(envelopeId);
1397
- return false;
1398
- }
1399
- return true;
1400
- }
1401
- trimRecentlyHandled(now) {
1402
- while (this.recentlyHandledOrder.length > 0) {
1403
- const candidate = this.recentlyHandledOrder[0];
1404
- const timestamp = this.recentlyHandled.get(candidate);
1405
- if (timestamp === undefined) {
1406
- this.recentlyHandledOrder.shift();
1407
- continue;
1408
- }
1409
- if (now - timestamp <= this.recentlyHandledTtlMs) {
1410
- break;
1411
- }
1412
- this.recentlyHandled.delete(candidate);
1413
- this.recentlyHandledOrder.shift();
1414
- }
1415
- }
1416
1358
  getShutdownRetryDeferDelay(nowMs) {
1417
1359
  if (!this.isPreparingToStop || this.shutdownRequestedAtMs === null) {
1418
1360
  return null;