@naylence/runtime 0.3.5-test.954 → 0.3.5-test.956

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.
@@ -725,7 +725,7 @@ class TaskCancelledError extends Error {
725
725
  * Provides functionality similar to Python's asyncio TaskSpawner with proper
726
726
  * error handling, cancellation, and graceful shutdown capabilities.
727
727
  */
728
- const logger$1g = getLogger('naylence.fame.util.task_spawner');
728
+ const logger$1h = getLogger('naylence.fame.util.task_spawner');
729
729
  function firstDefined(source, keys) {
730
730
  for (const key of keys) {
731
731
  if (Object.prototype.hasOwnProperty.call(source, key)) {
@@ -886,7 +886,7 @@ class TaskSpawner {
886
886
  const taskId = `task-${++this._taskCounter}`;
887
887
  const taskName = normalizedOptions.name || `unnamed-${taskId}`;
888
888
  const timeout = normalizedOptions.timeout ?? this._config.defaultTimeout;
889
- logger$1g.debug('starting_background_task', {
889
+ logger$1h.debug('starting_background_task', {
890
890
  task_name: taskName,
891
891
  task_id: taskId,
892
892
  });
@@ -903,7 +903,7 @@ class TaskSpawner {
903
903
  task.promise
904
904
  .then(() => {
905
905
  if (!this._suppressCompletionLogging) {
906
- logger$1g.debug('task_completed_successfully', {
906
+ logger$1h.debug('task_completed_successfully', {
907
907
  task_name: taskName,
908
908
  task_id: taskId,
909
909
  duration_ms: Date.now() - task.startTime,
@@ -957,7 +957,7 @@ class TaskSpawner {
957
957
  error.name === 'AbortError' ||
958
958
  error.message === 'Task cancelled' ||
959
959
  error.message === 'Aborted') {
960
- logger$1g.debug('task_cancelled', {
960
+ logger$1h.debug('task_cancelled', {
961
961
  task_name: taskName,
962
962
  note: 'Task cancelled as requested',
963
963
  });
@@ -965,7 +965,7 @@ class TaskSpawner {
965
965
  }
966
966
  // Handle timeout
967
967
  if (error instanceof TaskTimeoutError) {
968
- logger$1g.warning('task_timed_out', {
968
+ logger$1h.warning('task_timed_out', {
969
969
  task_name: taskName,
970
970
  error: error.message,
971
971
  });
@@ -977,7 +977,7 @@ class TaskSpawner {
977
977
  // Handle known WebSocket shutdown race condition (similar to Python version)
978
978
  if (error.message.includes("await wasn't used with future") ||
979
979
  error.message.includes('WebSocket closed during receive')) {
980
- logger$1g.debug('task_shutdown_race_condition_handled', {
980
+ logger$1h.debug('task_shutdown_race_condition_handled', {
981
981
  task_name: taskName,
982
982
  note: 'Normal WebSocket close timing during shutdown - not an error',
983
983
  });
@@ -987,7 +987,7 @@ class TaskSpawner {
987
987
  if (error.name === 'FameTransportClose' ||
988
988
  error.message.includes('normal closure') ||
989
989
  error.message.includes('Connection closed')) {
990
- logger$1g.debug('task_shutdown_completed_normally', {
990
+ logger$1h.debug('task_shutdown_completed_normally', {
991
991
  task_name: taskName,
992
992
  note: 'Task closed normally during shutdown',
993
993
  });
@@ -1000,14 +1000,14 @@ class TaskSpawner {
1000
1000
  // Log retriable errors as warnings (they'll be retried by upstream logic)
1001
1001
  // Log non-retriable errors as errors (fatal failures)
1002
1002
  if (isRetriableError) {
1003
- logger$1g.warning('background_task_failed', {
1003
+ logger$1h.warning('background_task_failed', {
1004
1004
  task_name: taskName,
1005
1005
  error: error.message,
1006
1006
  retriable: true,
1007
1007
  });
1008
1008
  }
1009
1009
  else {
1010
- logger$1g.error('background_task_failed', {
1010
+ logger$1h.error('background_task_failed', {
1011
1011
  task_name: taskName,
1012
1012
  error: error.message,
1013
1013
  stack: error.stack,
@@ -1026,11 +1026,11 @@ class TaskSpawner {
1026
1026
  async shutdownTasks(options = {}) {
1027
1027
  const { gracePeriod, cancelHanging, joinTimeout } = normalizeShutdownOptions(options);
1028
1028
  if (this._tasks.size === 0) {
1029
- logger$1g.debug('shutdown_tasks_no_tasks_to_shutdown');
1029
+ logger$1h.debug('shutdown_tasks_no_tasks_to_shutdown');
1030
1030
  return;
1031
1031
  }
1032
1032
  this._suppressCompletionLogging = true;
1033
- logger$1g.debug('shutting_down_tasks', {
1033
+ logger$1h.debug('shutting_down_tasks', {
1034
1034
  task_count: this._tasks.size,
1035
1035
  task_names: Array.from(this._tasks.values()).map((t) => t.name),
1036
1036
  grace_period_ms: gracePeriod,
@@ -1045,7 +1045,7 @@ class TaskSpawner {
1045
1045
  if (cancelHanging) {
1046
1046
  const stillRunning = tasks.filter((task) => task.getState() === TaskState.RUNNING && !completed.has(task));
1047
1047
  if (stillRunning.length > 0) {
1048
- logger$1g.debug('tasks_did_not_complete_within_grace_period', {
1048
+ logger$1h.debug('tasks_did_not_complete_within_grace_period', {
1049
1049
  hanging_count: stillRunning.length,
1050
1050
  });
1051
1051
  // Wait for them to finish with individual timeouts
@@ -1055,7 +1055,7 @@ class TaskSpawner {
1055
1055
  }
1056
1056
  catch (error) {
1057
1057
  if (error instanceof TaskTimeoutError) {
1058
- logger$1g.warning('task_did_not_shutdown', {
1058
+ logger$1h.warning('task_did_not_shutdown', {
1059
1059
  task_name: task.name || task.id,
1060
1060
  join_timeout_ms: joinTimeout,
1061
1061
  });
@@ -1066,7 +1066,7 @@ class TaskSpawner {
1066
1066
  }
1067
1067
  else if (!(error instanceof TaskCancelledError)) {
1068
1068
  /* istanbul ignore next - unreachable defensive branch */
1069
- logger$1g.error('task_raised_during_cancellation', {
1069
+ logger$1h.error('task_raised_during_cancellation', {
1070
1070
  task_name: task.name || task.id,
1071
1071
  error: error instanceof Error ? error.message : String(error),
1072
1072
  });
@@ -1185,6 +1185,7 @@ class TaskSpawner {
1185
1185
  * condition/promise and ensure at most one notifier coroutine exists for a
1186
1186
  * flow at any time.
1187
1187
  */
1188
+ const logger$1g = getLogger('naylence.fame.flow.flow_controller');
1188
1189
  /**
1189
1190
  * Simple condition variable implementation for TypeScript/Node.js
1190
1191
  * Similar to Python's asyncio.Condition
@@ -1310,8 +1311,17 @@ class FlowController {
1310
1311
  // clamp into [0, initialWindow]
1311
1312
  const newBalance = Math.max(0, Math.min(this.initialWindow, prev + delta));
1312
1313
  this.credits.set(flowId, newBalance);
1314
+ const crossedZero = prev <= 0 && newBalance > 0;
1315
+ logger$1g.debug('flow_controller_add_credits', {
1316
+ flow_id: flowId,
1317
+ delta,
1318
+ prev_balance: prev,
1319
+ new_balance: newBalance,
1320
+ initial_window: this.initialWindow,
1321
+ crossed_zero: crossedZero,
1322
+ });
1313
1323
  // wake waiters only if we crossed the zero boundary
1314
- if (prev <= 0 && newBalance > 0) {
1324
+ if (crossedZero) {
1315
1325
  this.wakeWaiters(flowId);
1316
1326
  }
1317
1327
  return newBalance;
@@ -1322,11 +1332,27 @@ class FlowController {
1322
1332
  async acquire(flowId) {
1323
1333
  this.ensureFlow(flowId);
1324
1334
  const condition = this.conditions.get(flowId);
1335
+ logger$1g.debug('flow_controller_acquire_attempt', {
1336
+ flow_id: flowId,
1337
+ current_balance: this.credits.get(flowId),
1338
+ });
1325
1339
  while (this.credits.get(flowId) <= 0) {
1340
+ logger$1g.debug('flow_controller_waiting_for_credit', {
1341
+ flow_id: flowId,
1342
+ });
1326
1343
  await condition.wait();
1344
+ logger$1g.debug('flow_controller_woke_with_credit', {
1345
+ flow_id: flowId,
1346
+ balance_after_wake: this.credits.get(flowId),
1347
+ });
1327
1348
  }
1328
1349
  const current = this.credits.get(flowId);
1329
1350
  this.credits.set(flowId, current - 1);
1351
+ logger$1g.debug('flow_controller_credit_consumed', {
1352
+ flow_id: flowId,
1353
+ prev_balance: current,
1354
+ remaining_balance: current - 1,
1355
+ });
1330
1356
  }
1331
1357
  /**
1332
1358
  * Consume *credits* immediately (non-blocking).
@@ -1346,6 +1372,12 @@ class FlowController {
1346
1372
  const current = this.credits.get(flowId);
1347
1373
  const remaining = Math.max(current - credits, 0);
1348
1374
  this.credits.set(flowId, remaining);
1375
+ logger$1g.debug('flow_controller_consume', {
1376
+ flow_id: flowId,
1377
+ requested: credits,
1378
+ prev_balance: current,
1379
+ remaining_balance: remaining,
1380
+ });
1349
1381
  return remaining;
1350
1382
  }
1351
1383
  /**
@@ -1366,6 +1398,10 @@ class FlowController {
1366
1398
  this.windowIds.delete(flowId);
1367
1399
  this.credits.set(flowId, this.initialWindow);
1368
1400
  this.wakeWaiters(flowId);
1401
+ logger$1g.debug('flow_controller_flow_reset', {
1402
+ flow_id: flowId,
1403
+ reset_balance: this.initialWindow,
1404
+ });
1369
1405
  }
1370
1406
  /**
1371
1407
  * Return `[windowId, flags]` for the next outbound envelope.
@@ -2229,10 +2265,12 @@ class BaseAsyncConnector extends TaskSpawner {
2229
2265
  throw new FameTransportClose('Connection closed', 1006);
2230
2266
  }
2231
2267
  // Apply flow control if enabled and not a credit update
2232
- if (this._fcEnabled &&
2233
- !(envelope.frame &&
2234
- 'flow_id' in envelope.frame &&
2235
- 'credits' in envelope.frame)) {
2268
+ const isCreditUpdateFrame = Boolean(envelope.frame &&
2269
+ (envelope.frame.type === 'CreditUpdate' ||
2270
+ envelope.frame.type === 'credit_update' ||
2271
+ ('flowId' in envelope.frame && 'credits' in envelope.frame) ||
2272
+ ('flow_id' in envelope.frame && 'credits' in envelope.frame)));
2273
+ if (this._fcEnabled && !isCreditUpdateFrame) {
2236
2274
  const flowId = envelope.flowId || this._connectorFlowId;
2237
2275
  envelope.flowId = flowId;
2238
2276
  const t0 = this._metrics ? performance.now() : 0;
@@ -5478,12 +5516,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
5478
5516
  }
5479
5517
 
5480
5518
  // This file is auto-generated during build - do not edit manually
5481
- // Generated from package.json version: 0.3.5-test.954
5519
+ // Generated from package.json version: 0.3.5-test.956
5482
5520
  /**
5483
5521
  * The package version, injected at build time.
5484
5522
  * @internal
5485
5523
  */
5486
- const VERSION = '0.3.5-test.954';
5524
+ const VERSION = '0.3.5-test.956';
5487
5525
 
5488
5526
  /**
5489
5527
  * Fame errors module - Fame protocol specific error classes
@@ -11534,6 +11572,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11534
11572
  ? Math.floor(config.inboxCapacity)
11535
11573
  : DEFAULT_INBOX_CAPACITY$7;
11536
11574
  this.inbox = new BoundedAsyncQueue(preferredCapacity);
11575
+ this.inboxCapacity = preferredCapacity;
11537
11576
  this.connectorId = BroadcastChannelConnector.generateConnectorId();
11538
11577
  this.channel = new BroadcastChannel(this.channelName);
11539
11578
  logger$10.debug('broadcast_channel_connector_created', {
@@ -11593,15 +11632,27 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11593
11632
  if (typeof this.inbox.tryEnqueue === 'function') {
11594
11633
  const accepted = this.inbox.tryEnqueue(payload);
11595
11634
  if (accepted) {
11635
+ this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
11636
+ source: 'listener',
11637
+ enqueue_strategy: 'try',
11638
+ payload_length: payload.byteLength,
11639
+ });
11596
11640
  return;
11597
11641
  }
11598
11642
  }
11599
11643
  this.inbox.enqueue(payload);
11644
+ this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
11645
+ source: 'listener',
11646
+ enqueue_strategy: 'enqueue',
11647
+ payload_length: payload.byteLength,
11648
+ });
11600
11649
  }
11601
11650
  catch (error) {
11602
11651
  if (error instanceof QueueFullError) {
11603
11652
  logger$10.warning('broadcast_channel_receive_queue_full', {
11604
11653
  channel: this.channelName,
11654
+ inbox_capacity: this.inboxCapacity,
11655
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
11605
11656
  });
11606
11657
  }
11607
11658
  else {
@@ -11612,8 +11663,10 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11612
11663
  }
11613
11664
  }
11614
11665
  };
11615
- this.channel.addEventListener('message', this.onMsg);
11616
- this.listenerRegistered = true;
11666
+ if (!config.passive) {
11667
+ this.channel.addEventListener('message', this.onMsg);
11668
+ this.listenerRegistered = true;
11669
+ }
11617
11670
  // Setup visibility change monitoring
11618
11671
  this.visibilityChangeHandler = () => {
11619
11672
  const isHidden = document.hidden;
@@ -11685,15 +11738,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11685
11738
  if (typeof this.inbox.tryEnqueue === 'function') {
11686
11739
  const accepted = this.inbox.tryEnqueue(item);
11687
11740
  if (accepted) {
11741
+ this.logInboxSnapshot('broadcast_channel_push_enqueued', {
11742
+ enqueue_strategy: 'try',
11743
+ item_type: this._describeInboxItem(item),
11744
+ });
11688
11745
  return;
11689
11746
  }
11690
11747
  }
11691
11748
  this.inbox.enqueue(item);
11749
+ this.logInboxSnapshot('broadcast_channel_push_enqueued', {
11750
+ enqueue_strategy: 'enqueue',
11751
+ item_type: this._describeInboxItem(item),
11752
+ });
11692
11753
  }
11693
11754
  catch (error) {
11694
11755
  if (error instanceof QueueFullError) {
11695
11756
  logger$10.warning('broadcast_channel_push_queue_full', {
11696
11757
  channel: this.channelName,
11758
+ inbox_capacity: this.inboxCapacity,
11759
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
11697
11760
  });
11698
11761
  throw error;
11699
11762
  }
@@ -11716,7 +11779,11 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11716
11779
  });
11717
11780
  }
11718
11781
  async _transportReceive() {
11719
- return await this.inbox.dequeue();
11782
+ const item = await this.inbox.dequeue();
11783
+ this.logInboxSnapshot('broadcast_channel_inbox_dequeued', {
11784
+ item_type: this._describeInboxItem(item),
11785
+ });
11786
+ return item;
11720
11787
  }
11721
11788
  async _transportClose(code, reason) {
11722
11789
  logger$10.debug('broadcast_channel_transport_closing', {
@@ -11770,6 +11837,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
11770
11837
  }
11771
11838
  return rawOrEnvelope;
11772
11839
  }
11840
+ _describeInboxItem(item) {
11841
+ if (item instanceof Uint8Array) {
11842
+ return 'bytes';
11843
+ }
11844
+ if (item.envelope) {
11845
+ return 'channel_message';
11846
+ }
11847
+ if (item.frame) {
11848
+ return 'envelope';
11849
+ }
11850
+ return 'unknown';
11851
+ }
11852
+ logInboxSnapshot(event, extra = {}) {
11853
+ logger$10.debug(event, {
11854
+ channel: this.channelName,
11855
+ connector_id: this.connectorId,
11856
+ connector_state: this.state,
11857
+ inbox_capacity: this.inboxCapacity,
11858
+ inbox_remaining_capacity: this.inbox.remainingCapacity,
11859
+ ...extra,
11860
+ });
11861
+ }
11773
11862
  _shouldSkipDuplicateAck(senderId, payload) {
11774
11863
  const dedupKey = this._extractAckDedupKey(payload);
11775
11864
  if (!dedupKey) {
@@ -32684,6 +32773,7 @@ class BroadcastChannelListener extends TransportListener {
32684
32773
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE$1,
32685
32774
  channelName: this._channelName,
32686
32775
  inboxCapacity: this._inboxCapacity,
32776
+ passive: true,
32687
32777
  };
32688
32778
  }
32689
32779
  try {
@@ -32744,6 +32834,7 @@ class BroadcastChannelListener extends TransportListener {
32744
32834
  type: BROADCAST_CHANNEL_CONNECTOR_TYPE$1,
32745
32835
  channelName: this._channelName,
32746
32836
  inboxCapacity: this._inboxCapacity,
32837
+ passive: true,
32747
32838
  };
32748
32839
  const channelCandidate = candidate.channelName ?? candidate['channel_name'];
32749
32840
  if (typeof channelCandidate === 'string' && channelCandidate.trim().length > 0) {