@rasputin-ai/node 0.5.0-alpha.4 → 0.5.0-alpha.6

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.
package/dist/index.js CHANGED
@@ -386,83 +386,385 @@ var scheduleInstrumentationManifestUpload = (options) => {
386
386
  import { AsyncLocalStorage } from "node:async_hooks";
387
387
  import { runtimeFunctionId as runtimeFunctionId2 } from "@rasputin-ai/core";
388
388
 
389
- // src/execution-recorder/call-aware-event-buffer.ts
390
- var isSuppressionPlaceholder = (item) => "kind" in item && item.kind === "suppressed";
391
- var CallAwareEventBuffer = class {
389
+ // src/execution-recorder/execution-journal.ts
390
+ var KIND_ENTER = 1;
391
+ var KIND_EXIT = 2;
392
+ var KIND_THROW = 3;
393
+ var KIND_SUPPRESSED = 4;
394
+ var NO_PARENT = 4294967295;
395
+ var NO_SUPPRESSION = 4294967295;
396
+ var MAX_POOLED_JOURNALS = 8;
397
+ var MAX_POOLED_JOURNAL_CAPACITY = 4096;
398
+ var INITIAL_JOURNAL_STORAGE = 32;
399
+ var BYTES_PER_EVENT = Uint8Array.BYTES_PER_ELEMENT + Uint32Array.BYTES_PER_ELEMENT * 4 + BigInt64Array.BYTES_PER_ELEMENT * 2;
400
+ var DEFAULT_MAX_EVENTS_PER_EXECUTION = 500;
401
+ var MAX_JOURNAL_EVENTS = 16384;
402
+ var elapsedMs = (startedAtNs, endedAtNs) => Number(endedAtNs - startedAtNs) / 1e6;
403
+ var roundedMilliseconds = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
404
+ var relativeMs = (relativeNs) => Number(relativeNs) / 1e6;
405
+ var sanitizeJournalCapacity = (value) => {
406
+ const requested = value ?? DEFAULT_MAX_EVENTS_PER_EXECUTION;
407
+ if (!Number.isFinite(requested)) return DEFAULT_MAX_EVENTS_PER_EXECUTION;
408
+ return Math.min(MAX_JOURNAL_EVENTS, Math.max(2, Math.floor(requested)));
409
+ };
410
+ var ExecutionJournal = class {
411
+ dropped = 0;
412
+ allocatedBytes = 0;
413
+ onGrow;
414
+ length = 0;
415
+ kind = new Uint8Array(0);
416
+ planId = new Uint32Array(0);
417
+ callId = new Uint32Array(0);
418
+ parentCallId = new Uint32Array(0);
419
+ timestampNs = new BigInt64Array(0);
420
+ durationNs = new BigInt64Array(0);
421
+ suppressionIndex = new Uint32Array(0);
422
+ payloads = [];
423
+ suppressions = [];
424
+ openCallIds = /* @__PURE__ */ new Set();
425
+ notedPlanIds = [];
426
+ notedPlanSet = /* @__PURE__ */ new Set();
427
+ maxCapacity;
392
428
  constructor(capacity) {
393
- this.capacity = capacity;
429
+ this.maxCapacity = sanitizeJournalCapacity(capacity);
430
+ this.reallocate(Math.min(this.maxCapacity, INITIAL_JOURNAL_STORAGE));
431
+ }
432
+ get capacity() {
433
+ return this.maxCapacity;
434
+ }
435
+ get hasOpenCalls() {
436
+ return this.openCallIds.size > 0;
437
+ }
438
+ get eventCount() {
439
+ return this.length;
440
+ }
441
+ get payloadSlotCount() {
442
+ return this.payloads.length;
394
443
  }
395
- items = [];
396
- openCallIds = /* @__PURE__ */ new Set();
397
- dropped = 0;
398
444
  canStartCall() {
399
- return this.items.length + this.openCallIds.size + 2 <= this.capacity;
445
+ if (this.length + this.openCallIds.size + 2 > this.maxCapacity) return false;
446
+ return this.ensureCapacity(this.length + 2);
400
447
  }
401
- startCall(event) {
402
- this.items.push(event);
403
- this.openCallIds.add(event.callId);
448
+ notePlan(runtimePlanId) {
449
+ if (this.notedPlanSet.has(runtimePlanId)) return;
450
+ this.notedPlanSet.add(runtimePlanId);
451
+ this.notedPlanIds.push(runtimePlanId);
404
452
  }
405
- finishCall(event) {
406
- if (event.type !== "function_exit" && event.type !== "function_throw") return;
407
- if (!this.openCallIds.delete(event.callId)) return;
408
- this.items.push(event);
453
+ registerSuppression(group) {
454
+ if (group.storageIndex >= 0) return group;
455
+ group.storageIndex = this.suppressions.length;
456
+ this.suppressions.push(group);
457
+ return group;
458
+ }
459
+ startCall(runtimePlanId, callId, parentCallId, timestampNs, args) {
460
+ if (!this.write(
461
+ KIND_ENTER,
462
+ runtimePlanId,
463
+ callId,
464
+ parentCallId,
465
+ timestampNs,
466
+ 0n,
467
+ args,
468
+ NO_SUPPRESSION
469
+ )) {
470
+ return;
471
+ }
472
+ this.openCallIds.add(callId);
473
+ }
474
+ finishCall(kind, callId, timestampNs, durationNs, payload) {
475
+ if (!this.openCallIds.delete(callId)) return;
476
+ this.write(kind, 0, callId, void 0, timestampNs, durationNs, payload, NO_SUPPRESSION);
409
477
  }
410
478
  dropCall() {
411
479
  this.dropped += 2;
412
480
  }
413
481
  appendSuppressed(group) {
414
- if (this.items.length + this.openCallIds.size + 1 > this.capacity) {
482
+ if (this.length + this.openCallIds.size + 1 > this.maxCapacity) {
483
+ this.dropped++;
484
+ return false;
485
+ }
486
+ this.registerSuppression(group);
487
+ group.retainedIndex = this.length;
488
+ if (!this.write(
489
+ KIND_SUPPRESSED,
490
+ group.runtimePlanId,
491
+ 0,
492
+ group.parentCallId,
493
+ 0n,
494
+ 0n,
495
+ void 0,
496
+ group.storageIndex
497
+ )) {
498
+ group.retainedIndex = -1;
415
499
  this.dropped++;
416
500
  return false;
417
501
  }
418
- const placeholder = { kind: "suppressed", group };
419
- this.items.push(placeholder);
420
- group.retainedSlot = placeholder;
421
502
  return true;
422
503
  }
423
- forceCompletedCall(enter, terminal) {
424
- while (this.items.length + this.openCallIds.size + 2 > this.capacity) {
504
+ forceCompletedCall(runtimePlanId, callId, parentCallId, enterTimestampNs, args, terminalKind, terminalTimestampNs, durationNs, payload) {
505
+ while (this.length + this.openCallIds.size + 2 > this.maxCapacity) {
425
506
  if (!this.evictCompletedLeafOrSummary()) {
426
507
  this.dropCall();
427
508
  return false;
428
509
  }
429
510
  }
430
- this.items.push(enter, terminal);
511
+ if (!this.ensureCapacity(this.length + 2)) {
512
+ this.dropCall();
513
+ return false;
514
+ }
515
+ this.write(
516
+ KIND_ENTER,
517
+ runtimePlanId,
518
+ callId,
519
+ parentCallId,
520
+ enterTimestampNs,
521
+ 0n,
522
+ args,
523
+ NO_SUPPRESSION
524
+ );
525
+ this.write(
526
+ terminalKind,
527
+ 0,
528
+ callId,
529
+ void 0,
530
+ terminalTimestampNs,
531
+ durationNs,
532
+ payload,
533
+ NO_SUPPRESSION
534
+ );
431
535
  return true;
432
536
  }
433
- values() {
434
- return [...this.items];
537
+ materialize(plansByRuntimeId, executionStartedAtNs) {
538
+ const events = [];
539
+ const referencedFunctionIds = /* @__PURE__ */ new Set();
540
+ for (let index = 0; index < this.length; index++) {
541
+ const event = this.eventAt(index, plansByRuntimeId, executionStartedAtNs);
542
+ if (!event) continue;
543
+ events.push(event);
544
+ if (event.type === "function_enter" || event.type === "function_calls_suppressed") {
545
+ referencedFunctionIds.add(event.functionId);
546
+ }
547
+ }
548
+ const functions = [];
549
+ const seenFunctionIds = /* @__PURE__ */ new Set();
550
+ for (const runtimePlanId of this.notedPlanIds) {
551
+ const definition = plansByRuntimeId[runtimePlanId]?.definition;
552
+ if (!definition || !referencedFunctionIds.has(definition.functionId)) continue;
553
+ if (seenFunctionIds.has(definition.functionId)) continue;
554
+ seenFunctionIds.add(definition.functionId);
555
+ functions.push(definition);
556
+ }
557
+ return { events, functions };
558
+ }
559
+ clear() {
560
+ this.length = 0;
561
+ this.dropped = 0;
562
+ this.onGrow = void 0;
563
+ this.openCallIds.clear();
564
+ this.notedPlanIds.length = 0;
565
+ this.notedPlanSet.clear();
566
+ for (let index = 0; index < this.payloads.length; index++) this.payloads[index] = void 0;
567
+ this.payloads.length = 0;
568
+ for (const group of this.suppressions) {
569
+ group.retainedIndex = -1;
570
+ group.storageIndex = -1;
571
+ }
572
+ this.suppressions.length = 0;
573
+ }
574
+ eventAt(index, plansByRuntimeId, executionStartedAtNs) {
575
+ const kind = this.kind[index];
576
+ if (kind === KIND_ENTER) {
577
+ const functionId = plansByRuntimeId[this.planId[index] ?? 0]?.functionId;
578
+ if (!functionId) return void 0;
579
+ const parentCallId = this.parentCallId[index] ?? NO_PARENT;
580
+ const payload = this.payloads[index];
581
+ return {
582
+ type: "function_enter",
583
+ callId: this.callId[index] ?? 0,
584
+ functionId,
585
+ timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
586
+ args: Array.isArray(payload) ? payload : [],
587
+ ...parentCallId === NO_PARENT ? {} : { parentCallId }
588
+ };
589
+ }
590
+ if (kind === KIND_EXIT) {
591
+ return {
592
+ type: "function_exit",
593
+ callId: this.callId[index] ?? 0,
594
+ timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
595
+ durationMs: relativeMs(this.durationNs[index] ?? 0n),
596
+ returnValue: this.payloads[index]
597
+ };
598
+ }
599
+ if (kind === KIND_THROW) {
600
+ return {
601
+ type: "function_throw",
602
+ callId: this.callId[index] ?? 0,
603
+ timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
604
+ durationMs: relativeMs(this.durationNs[index] ?? 0n),
605
+ error: this.payloads[index]
606
+ };
607
+ }
608
+ if (kind === KIND_SUPPRESSED) {
609
+ const group = this.suppressions[this.suppressionIndex[index] ?? 0];
610
+ if (!group) return void 0;
611
+ return {
612
+ type: "function_calls_suppressed",
613
+ functionId: group.functionId,
614
+ timestampMs: elapsedMs(executionStartedAtNs, group.firstTimestampNs),
615
+ lastTimestampMs: elapsedMs(executionStartedAtNs, group.lastTimestampNs),
616
+ suppressedCallCount: group.count,
617
+ totalDurationMs: roundedMilliseconds(group.totalDurationNs),
618
+ ...group.parentCallId === void 0 ? {} : { parentCallId: group.parentCallId }
619
+ };
620
+ }
621
+ return void 0;
622
+ }
623
+ write(kind, runtimePlanId, callId, parentCallId, timestampNs, durationNs, payload, suppressionIndex) {
624
+ if (!this.ensureCapacity(this.length + 1)) return false;
625
+ const index = this.length;
626
+ this.kind[index] = kind;
627
+ this.planId[index] = runtimePlanId;
628
+ this.callId[index] = callId;
629
+ this.parentCallId[index] = parentCallId === void 0 ? NO_PARENT : parentCallId;
630
+ this.timestampNs[index] = timestampNs;
631
+ this.durationNs[index] = durationNs;
632
+ this.payloads[index] = payload;
633
+ this.suppressionIndex[index] = suppressionIndex;
634
+ this.length++;
635
+ return true;
636
+ }
637
+ ensureCapacity(needed) {
638
+ if (needed <= this.kind.length) return true;
639
+ if (needed > this.maxCapacity) return false;
640
+ let next = this.kind.length === 0 ? Math.min(INITIAL_JOURNAL_STORAGE, this.maxCapacity) : this.kind.length;
641
+ while (next < needed) {
642
+ const grown = Math.min(this.maxCapacity, next * 2);
643
+ if (grown <= next) return false;
644
+ next = grown;
645
+ }
646
+ const extraBytes = (next - this.kind.length) * BYTES_PER_EVENT;
647
+ if (this.onGrow && extraBytes > 0 && !this.onGrow(extraBytes)) return false;
648
+ this.reallocate(next);
649
+ return true;
650
+ }
651
+ reallocate(size) {
652
+ const nextKind = new Uint8Array(size);
653
+ const nextPlanId = new Uint32Array(size);
654
+ const nextCallId = new Uint32Array(size);
655
+ const nextParentCallId = new Uint32Array(size);
656
+ const nextTimestampNs = new BigInt64Array(size);
657
+ const nextDurationNs = new BigInt64Array(size);
658
+ const nextSuppressionIndex = new Uint32Array(size);
659
+ if (this.length > 0) {
660
+ nextKind.set(this.kind.subarray(0, this.length));
661
+ nextPlanId.set(this.planId.subarray(0, this.length));
662
+ nextCallId.set(this.callId.subarray(0, this.length));
663
+ nextParentCallId.set(this.parentCallId.subarray(0, this.length));
664
+ nextTimestampNs.set(this.timestampNs.subarray(0, this.length));
665
+ nextDurationNs.set(this.durationNs.subarray(0, this.length));
666
+ nextSuppressionIndex.set(this.suppressionIndex.subarray(0, this.length));
667
+ }
668
+ this.kind = nextKind;
669
+ this.planId = nextPlanId;
670
+ this.callId = nextCallId;
671
+ this.parentCallId = nextParentCallId;
672
+ this.timestampNs = nextTimestampNs;
673
+ this.durationNs = nextDurationNs;
674
+ this.suppressionIndex = nextSuppressionIndex;
675
+ this.allocatedBytes = size * BYTES_PER_EVENT;
435
676
  }
436
677
  evictCompletedLeafOrSummary() {
437
- const summaryIndex = this.items.findIndex((item) => isSuppressionPlaceholder(item));
438
- if (summaryIndex >= 0) {
439
- const summary = this.items[summaryIndex];
440
- if (summary && isSuppressionPlaceholder(summary)) summary.group.retainedSlot = void 0;
441
- this.items.splice(summaryIndex, 1);
678
+ for (let index = 0; index < this.length; index++) {
679
+ if (this.kind[index] !== KIND_SUPPRESSED) continue;
680
+ const group = this.suppressions[this.suppressionIndex[index] ?? 0];
681
+ if (group) group.retainedIndex = -1;
682
+ this.removeAt(index);
442
683
  this.dropped++;
443
684
  return true;
444
685
  }
445
686
  const parentCallIds = /* @__PURE__ */ new Set();
446
- for (const item of this.items) {
447
- const parentCallId = isSuppressionPlaceholder(item) ? item.group.parentCallId : item.type === "function_enter" ? item.parentCallId : void 0;
448
- if (parentCallId !== void 0) parentCallIds.add(parentCallId);
687
+ for (let index = 0; index < this.length; index++) {
688
+ const kind = this.kind[index];
689
+ if (kind !== KIND_ENTER && kind !== KIND_SUPPRESSED) continue;
690
+ const parentCallId = this.parentCallId[index] ?? NO_PARENT;
691
+ if (parentCallId !== NO_PARENT) parentCallIds.add(parentCallId);
449
692
  }
450
- for (let index = 0; index < this.items.length; index++) {
451
- const event = this.items[index];
452
- if (!event || isSuppressionPlaceholder(event) || event.type !== "function_enter" || this.openCallIds.has(event.callId) || parentCallIds.has(event.callId)) {
453
- continue;
693
+ for (let index = 0; index < this.length; index++) {
694
+ if (this.kind[index] !== KIND_ENTER) continue;
695
+ const eventCallId = this.callId[index] ?? 0;
696
+ if (this.openCallIds.has(eventCallId) || parentCallIds.has(eventCallId)) continue;
697
+ let terminalIndex = -1;
698
+ for (let candidate = 0; candidate < this.length; candidate++) {
699
+ const kind = this.kind[candidate];
700
+ if ((kind === KIND_EXIT || kind === KIND_THROW) && this.callId[candidate] === eventCallId) {
701
+ terminalIndex = candidate;
702
+ break;
703
+ }
454
704
  }
455
- const terminalIndex = this.items.findIndex(
456
- (candidate) => !isSuppressionPlaceholder(candidate) && (candidate.type === "function_exit" || candidate.type === "function_throw") && candidate.callId === event.callId
457
- );
458
705
  if (terminalIndex < 0) continue;
459
- this.items.splice(Math.max(index, terminalIndex), 1);
460
- this.items.splice(Math.min(index, terminalIndex), 1);
706
+ const later = Math.max(index, terminalIndex);
707
+ const earlier = Math.min(index, terminalIndex);
708
+ this.removeAt(later);
709
+ this.removeAt(earlier);
461
710
  this.dropped += 2;
462
711
  return true;
463
712
  }
464
713
  return false;
465
714
  }
715
+ removeAt(index) {
716
+ this.payloads[index] = void 0;
717
+ const next = index + 1;
718
+ if (next < this.length) {
719
+ this.kind.copyWithin(index, next, this.length);
720
+ this.planId.copyWithin(index, next, this.length);
721
+ this.callId.copyWithin(index, next, this.length);
722
+ this.parentCallId.copyWithin(index, next, this.length);
723
+ this.timestampNs.copyWithin(index, next, this.length);
724
+ this.durationNs.copyWithin(index, next, this.length);
725
+ this.suppressionIndex.copyWithin(index, next, this.length);
726
+ this.payloads.copyWithin(index, next, this.length);
727
+ }
728
+ this.payloads[this.length - 1] = void 0;
729
+ this.length--;
730
+ this.payloads.length = this.length;
731
+ for (const group of this.suppressions) {
732
+ if (group.retainedIndex > index) group.retainedIndex--;
733
+ }
734
+ }
735
+ };
736
+ var ExecutionJournalPool = class {
737
+ constructor(capacity, maxPooled = MAX_POOLED_JOURNALS) {
738
+ this.capacity = capacity;
739
+ this.maxPooled = maxPooled;
740
+ }
741
+ hits = 0;
742
+ misses = 0;
743
+ available = [];
744
+ acquire() {
745
+ const pooled = this.available.pop();
746
+ if (pooled) {
747
+ this.hits++;
748
+ return pooled;
749
+ }
750
+ this.misses++;
751
+ return new ExecutionJournal(this.capacity);
752
+ }
753
+ release(journal) {
754
+ journal.clear();
755
+ if (this.available.length >= this.maxPooled || journal.capacity > MAX_POOLED_JOURNAL_CAPACITY || journal.capacity !== this.capacity) {
756
+ return;
757
+ }
758
+ this.available.push(journal);
759
+ }
760
+ stats() {
761
+ return {
762
+ journalPoolHits: this.hits,
763
+ journalPoolMisses: this.misses,
764
+ journalPoolSize: this.available.length,
765
+ journalAllocatedCapacity: this.capacity
766
+ };
767
+ }
466
768
  };
467
769
 
468
770
  // src/execution-recorder/recorder-memory-budget.ts
@@ -540,6 +842,12 @@ var RecorderMemoryBudget = class {
540
842
  this.dropEvents(allocation, 1);
541
843
  return false;
542
844
  }
845
+ reserveStorage(allocation, bytes) {
846
+ if (allocation.released || allocation.mode === "metadata-only") return false;
847
+ if (this.reserve(allocation, bytes)) return true;
848
+ this.markPressure(allocation, "metadata-only");
849
+ return false;
850
+ }
543
851
  release(allocation) {
544
852
  if (allocation.released) return;
545
853
  allocation.released = true;
@@ -600,10 +908,7 @@ var defaults = {
600
908
  maxStringLength: 500,
601
909
  maxSerializedValueBytes: 8 * 1024
602
910
  };
603
- var TYPE_MARKER_OPEN = '{"__rasputin_type":"';
604
- var TYPE_MARKER_VALUE_MID = '","value":"';
605
- var TYPE_MARKER_CLOSE = '"}';
606
- var UNDEFINED_MARKER_BYTES = TYPE_MARKER_OPEN.length + "undefined".length + TYPE_MARKER_CLOSE.length;
911
+ var REDACTED = "[RASPUTIN_REDACTED]";
607
912
  var truncation = (reason, extra = {}) => ({
608
913
  __rasputin_truncated: true,
609
914
  __reason: reason,
@@ -613,7 +918,83 @@ var typeMarker = (type, value) => ({
613
918
  __rasputin_type: type,
614
919
  ...value === void 0 ? {} : { value }
615
920
  });
616
- var REDACTED = "[RASPUTIN_REDACTED]";
921
+ var jsonStringUtf8Bytes = (value) => {
922
+ let bytes = 2;
923
+ for (let index = 0; index < value.length; index++) {
924
+ const code = value.charCodeAt(index);
925
+ if (code === 34 || code === 92) {
926
+ bytes += 2;
927
+ continue;
928
+ }
929
+ if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
930
+ bytes += 2;
931
+ continue;
932
+ }
933
+ if (code < 32) {
934
+ bytes += 6;
935
+ continue;
936
+ }
937
+ if (code < 128) {
938
+ bytes += 1;
939
+ continue;
940
+ }
941
+ if (code < 2048) {
942
+ bytes += 2;
943
+ continue;
944
+ }
945
+ if (code >= 55296 && code <= 56319) {
946
+ const next = value.charCodeAt(index + 1);
947
+ if (index + 1 < value.length && next >= 56320 && next <= 57343) {
948
+ bytes += 4;
949
+ index++;
950
+ continue;
951
+ }
952
+ bytes += 6;
953
+ continue;
954
+ }
955
+ if (code >= 56320 && code <= 57343) {
956
+ bytes += 6;
957
+ continue;
958
+ }
959
+ bytes += 3;
960
+ }
961
+ return bytes;
962
+ };
963
+ var jsonLiteralUtf8Bytes = (value) => {
964
+ if (value === null) return 4;
965
+ switch (typeof value) {
966
+ case "boolean":
967
+ return value ? 4 : 5;
968
+ case "number":
969
+ if (!Number.isFinite(value)) return 4;
970
+ if (Object.is(value, -0)) return 1;
971
+ return String(value).length;
972
+ case "string":
973
+ return jsonStringUtf8Bytes(value);
974
+ case "object": {
975
+ if (Array.isArray(value)) {
976
+ let bytes2 = 2;
977
+ for (let index = 0; index < value.length; index++) {
978
+ if (index > 0) bytes2 += 1;
979
+ bytes2 += jsonLiteralUtf8Bytes(value[index]);
980
+ }
981
+ return bytes2;
982
+ }
983
+ const record = value;
984
+ let bytes = 2;
985
+ let first = true;
986
+ for (const key of Object.keys(record)) {
987
+ if (!first) bytes += 1;
988
+ first = false;
989
+ bytes += jsonStringUtf8Bytes(key) + 1;
990
+ bytes += jsonLiteralUtf8Bytes(record[key]);
991
+ }
992
+ return bytes;
993
+ }
994
+ default:
995
+ return Buffer2.byteLength(JSON.stringify(value) ?? "null", "utf8");
996
+ }
997
+ };
617
998
  var compileLimits = (options) => ({
618
999
  maxDepth: options.maxDepth ?? defaults.maxDepth,
619
1000
  maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
@@ -625,6 +1006,13 @@ var compileRedactKeys = (options) => {
625
1006
  if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
626
1007
  return /* @__PURE__ */ new Set([...DEFAULT_REDACT_KEYS, ...options.redactKeys.map((key) => key.toLowerCase())]);
627
1008
  };
1009
+ var keyNeedsCaseFold = (key) => {
1010
+ for (let index = 0; index < key.length; index++) {
1011
+ const code = key.charCodeAt(index);
1012
+ if (code > 127 || code >= 65 && code <= 90) return true;
1013
+ }
1014
+ return false;
1015
+ };
628
1016
  var isJsonSafeString = (value) => {
629
1017
  for (let index = 0; index < value.length; index++) {
630
1018
  const code = value.charCodeAt(index);
@@ -639,7 +1027,6 @@ var isJsonSafeString = (value) => {
639
1027
  }
640
1028
  return true;
641
1029
  };
642
- var typeMarkerWithValueBytes = (type, jsonSafeValue) => TYPE_MARKER_OPEN.length + type.length + TYPE_MARKER_VALUE_MID.length + Buffer2.byteLength(jsonSafeValue, "utf8") + TYPE_MARKER_CLOSE.length;
643
1030
  var primitiveFastPath = (value, maxStringLength) => {
644
1031
  if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
645
1032
  if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
@@ -653,176 +1040,306 @@ var primitiveFastPath = (value, maxStringLength) => {
653
1040
  return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
654
1041
  }
655
1042
  if (typeof value === "undefined") {
656
- return {
657
- value: { __rasputin_type: "undefined" },
658
- bytes: UNDEFINED_MARKER_BYTES,
659
- visitedNodes: 1
660
- };
1043
+ const serialized = typeMarker("undefined");
1044
+ return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
661
1045
  }
662
1046
  if (typeof value === "bigint") {
663
- const digits = value.toString();
664
- return {
665
- value: { __rasputin_type: "bigint", value: digits },
666
- bytes: typeMarkerWithValueBytes("bigint", digits),
667
- visitedNodes: 1
668
- };
1047
+ const serialized = typeMarker("bigint", value.toString());
1048
+ return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
669
1049
  }
670
1050
  if (typeof value === "symbol") {
671
1051
  const text = String(value);
672
1052
  if (!isJsonSafeString(text)) return void 0;
673
- return {
674
- value: { __rasputin_type: "symbol", value: text },
675
- bytes: typeMarkerWithValueBytes("symbol", text),
676
- visitedNodes: 1
677
- };
1053
+ const serialized = typeMarker("symbol", text);
1054
+ return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
678
1055
  }
679
1056
  if (typeof value === "function") {
680
1057
  const name = value.name || "anonymous";
681
1058
  if (!isJsonSafeString(name)) return void 0;
682
- return {
683
- value: { __rasputin_type: "function", value: name },
684
- bytes: typeMarkerWithValueBytes("function", name),
685
- visitedNodes: 1
686
- };
1059
+ const serialized = typeMarker("function", name);
1060
+ return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
687
1061
  }
688
1062
  return void 0;
689
1063
  };
690
1064
  var createSafeSerializer = (options = {}) => {
691
1065
  const limits = compileLimits(options);
692
1066
  const redactKeys = compileRedactKeys(options);
693
- const serializeInner = (value, depth, seen, metrics) => {
1067
+ const sharedPath = /* @__PURE__ */ new Set();
1068
+ let serializing = false;
1069
+ const isRedactedKey = (key) => {
1070
+ if (redactKeys.has(key)) return true;
1071
+ if (!keyNeedsCaseFold(key)) return false;
1072
+ return redactKeys.has(key.toLowerCase());
1073
+ };
1074
+ const addBytes = (metrics, count) => {
1075
+ metrics.bytes += count;
1076
+ if (metrics.bytes > limits.maxSerializedValueBytes) metrics.oversize = true;
1077
+ };
1078
+ const boundedOversize = (bytes, visitedNodes) => {
1079
+ const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
1080
+ return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
1081
+ };
1082
+ const openObject = (metrics, allocate) => {
1083
+ addBytes(metrics, 2);
1084
+ return {
1085
+ target: allocate && !metrics.oversize ? {} : void 0,
1086
+ first: true
1087
+ };
1088
+ };
1089
+ const openArray = (metrics, allocate) => {
1090
+ addBytes(metrics, 2);
1091
+ return {
1092
+ items: allocate && !metrics.oversize ? [] : void 0,
1093
+ first: true
1094
+ };
1095
+ };
1096
+ const beginField = (metrics, object, key) => {
1097
+ if (!object.first) addBytes(metrics, 1);
1098
+ object.first = false;
1099
+ addBytes(metrics, jsonStringUtf8Bytes(key) + 1);
1100
+ };
1101
+ const assignField = (object, key, fieldValue) => {
1102
+ if (object.target) object.target[key] = fieldValue;
1103
+ };
1104
+ const writeLiteralField = (metrics, object, key, jsonValue) => {
1105
+ beginField(metrics, object, key);
1106
+ addBytes(metrics, jsonLiteralUtf8Bytes(jsonValue));
1107
+ assignField(object, key, jsonValue);
1108
+ };
1109
+ const writeTypeMarker = (metrics, allocate, type, nestedValue) => {
1110
+ const object = openObject(metrics, allocate);
1111
+ writeLiteralField(metrics, object, "__rasputin_type", type);
1112
+ if (nestedValue !== void 0) writeLiteralField(metrics, object, "value", nestedValue);
1113
+ return object.target;
1114
+ };
1115
+ const writeTruncation = (metrics, allocate, reason, extra = {}) => {
1116
+ const object = openObject(metrics, allocate);
1117
+ writeLiteralField(metrics, object, "__rasputin_truncated", true);
1118
+ writeLiteralField(metrics, object, "__reason", reason);
1119
+ for (const key of Object.keys(extra)) writeLiteralField(metrics, object, key, extra[key]);
1120
+ return object.target;
1121
+ };
1122
+ const serializeInner = (value, depth, path, allocate, metrics) => {
694
1123
  metrics.visitedNodes++;
695
- if (value === null || typeof value === "boolean" || typeof value === "number") return value;
1124
+ const store = allocate && !metrics.oversize;
1125
+ if (value === null) {
1126
+ addBytes(metrics, 4);
1127
+ return store ? null : void 0;
1128
+ }
1129
+ if (typeof value === "boolean") {
1130
+ addBytes(metrics, value ? 4 : 5);
1131
+ return store ? value : void 0;
1132
+ }
1133
+ if (typeof value === "number") {
1134
+ if (!Number.isFinite(value)) addBytes(metrics, 4);
1135
+ else if (Object.is(value, -0)) addBytes(metrics, 1);
1136
+ else addBytes(metrics, String(value).length);
1137
+ return store ? value : void 0;
1138
+ }
696
1139
  if (typeof value === "string") {
697
- if (value.length <= limits.maxStringLength) return value;
698
- return truncation("max_string_length", {
1140
+ if (value.length <= limits.maxStringLength) {
1141
+ addBytes(metrics, jsonStringUtf8Bytes(value));
1142
+ return store ? value : void 0;
1143
+ }
1144
+ return writeTruncation(metrics, store, "max_string_length", {
699
1145
  __original_length: value.length,
700
1146
  value: value.slice(0, limits.maxStringLength)
701
1147
  });
702
1148
  }
703
- if (typeof value === "undefined") return typeMarker("undefined");
704
- if (typeof value === "bigint") return typeMarker("bigint", value.toString());
705
- if (typeof value === "symbol") return typeMarker("symbol", String(value));
706
- if (typeof value === "function") return typeMarker("function", value.name || "anonymous");
707
- if (depth >= limits.maxDepth) return truncation("max_depth");
708
- if (typeof value !== "object") return typeMarker(typeof value);
709
- const tracking = seen ?? /* @__PURE__ */ new WeakSet();
710
- if (tracking.has(value)) return typeMarker("circular");
711
- tracking.add(value);
1149
+ if (typeof value === "undefined") return writeTypeMarker(metrics, store, "undefined");
1150
+ if (typeof value === "bigint") {
1151
+ return writeTypeMarker(metrics, store, "bigint", value.toString());
1152
+ }
1153
+ if (typeof value === "symbol") {
1154
+ return writeTypeMarker(metrics, store, "symbol", String(value));
1155
+ }
1156
+ if (typeof value === "function") {
1157
+ return writeTypeMarker(metrics, store, "function", value.name || "anonymous");
1158
+ }
1159
+ if (depth >= limits.maxDepth) return writeTruncation(metrics, store, "max_depth");
1160
+ if (typeof value !== "object") return writeTypeMarker(metrics, store, typeof value);
1161
+ if (path.has(value)) return writeTypeMarker(metrics, store, "circular");
1162
+ path.add(value);
1163
+ const bytesBefore = metrics.bytes;
1164
+ const oversizeBefore = metrics.oversize;
712
1165
  try {
1166
+ const childAllocate = allocate && !metrics.oversize;
713
1167
  if (value instanceof Error) {
714
- return {
715
- __rasputin_type: "Error",
716
- name: value.name,
717
- message: serializeInner(value.message, depth + 1, tracking, metrics),
718
- ...value.stack ? { stack: serializeInner(value.stack, depth + 1, tracking, metrics) } : {}
719
- };
1168
+ const object2 = openObject(metrics, childAllocate);
1169
+ writeLiteralField(metrics, object2, "__rasputin_type", "Error");
1170
+ writeLiteralField(metrics, object2, "name", value.name);
1171
+ beginField(metrics, object2, "message");
1172
+ assignField(
1173
+ object2,
1174
+ "message",
1175
+ serializeInner(value.message, depth + 1, path, childAllocate, metrics)
1176
+ );
1177
+ if (value.stack) {
1178
+ beginField(metrics, object2, "stack");
1179
+ assignField(
1180
+ object2,
1181
+ "stack",
1182
+ serializeInner(value.stack, depth + 1, path, childAllocate, metrics)
1183
+ );
1184
+ }
1185
+ return object2.target;
1186
+ }
1187
+ if (value instanceof Date) {
1188
+ return writeTypeMarker(metrics, childAllocate, "Date", value.toISOString());
720
1189
  }
721
- if (value instanceof Date) return typeMarker("Date", value.toISOString());
722
1190
  if (Buffer2.isBuffer(value)) {
723
- return typeMarker("Buffer", {
1191
+ return writeTypeMarker(metrics, childAllocate, "Buffer", {
724
1192
  byteLength: value.byteLength,
725
1193
  base64: value.subarray(0, limits.maxStringLength).toString("base64"),
726
1194
  ...value.byteLength > limits.maxStringLength ? { __rasputin_truncated: true } : {}
727
1195
  });
728
1196
  }
729
- if (value instanceof Promise) return typeMarker("Promise");
1197
+ if (value instanceof Promise) return writeTypeMarker(metrics, childAllocate, "Promise");
730
1198
  if (value instanceof Map) {
731
- const entries = [];
1199
+ const object2 = openObject(metrics, childAllocate);
1200
+ writeLiteralField(metrics, object2, "__rasputin_type", "Map");
1201
+ beginField(metrics, object2, "entries");
1202
+ const entries = openArray(metrics, childAllocate);
1203
+ let counted2 = 0;
732
1204
  for (const entry of value.entries()) {
733
- if (entries.length >= limits.maxArrayElements) break;
734
- entries.push([
735
- serializeInner(entry[0], depth + 1, tracking, metrics),
736
- serializeInner(entry[1], depth + 1, tracking, metrics)
737
- ]);
1205
+ if (counted2 >= limits.maxArrayElements) break;
1206
+ if (!entries.first) addBytes(metrics, 1);
1207
+ entries.first = false;
1208
+ addBytes(metrics, 2);
1209
+ const key = serializeInner(entry[0], depth + 1, path, childAllocate, metrics);
1210
+ addBytes(metrics, 1);
1211
+ const mapped = serializeInner(entry[1], depth + 1, path, childAllocate, metrics);
1212
+ entries.items?.push([key, mapped]);
1213
+ counted2++;
1214
+ }
1215
+ assignField(object2, "entries", entries.items ?? []);
1216
+ if (value.size > limits.maxArrayElements) {
1217
+ writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1218
+ writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1219
+ writeLiteralField(metrics, object2, "__original_length", value.size);
738
1220
  }
739
- return {
740
- __rasputin_type: "Map",
741
- entries,
742
- ...value.size > limits.maxArrayElements ? truncation("max_array_elements", { __original_length: value.size }) : {}
743
- };
1221
+ return object2.target;
744
1222
  }
745
1223
  if (value instanceof Set) {
746
- const items = [];
1224
+ const object2 = openObject(metrics, childAllocate);
1225
+ writeLiteralField(metrics, object2, "__rasputin_type", "Set");
1226
+ beginField(metrics, object2, "values");
1227
+ const items = openArray(metrics, childAllocate);
1228
+ let counted2 = 0;
747
1229
  for (const item of value.values()) {
748
- if (items.length >= limits.maxArrayElements) break;
749
- items.push(serializeInner(item, depth + 1, tracking, metrics));
1230
+ if (counted2 >= limits.maxArrayElements) break;
1231
+ if (!items.first) addBytes(metrics, 1);
1232
+ items.first = false;
1233
+ const serializedItem = serializeInner(item, depth + 1, path, childAllocate, metrics);
1234
+ items.items?.push(serializedItem);
1235
+ counted2++;
750
1236
  }
751
- return {
752
- __rasputin_type: "Set",
753
- values: items,
754
- ...value.size > limits.maxArrayElements ? truncation("max_array_elements", { __original_length: value.size }) : {}
755
- };
1237
+ assignField(object2, "values", items.items ?? []);
1238
+ if (value.size > limits.maxArrayElements) {
1239
+ writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1240
+ writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1241
+ writeLiteralField(metrics, object2, "__original_length", value.size);
1242
+ }
1243
+ return object2.target;
756
1244
  }
757
1245
  if (Array.isArray(value)) {
1246
+ const items = openArray(metrics, childAllocate);
758
1247
  const maxItems = value.length > limits.maxArrayElements ? limits.maxArrayElements - 1 : value.length;
759
- const items = [];
760
1248
  for (let index = 0; index < maxItems; index++) {
761
- items.push(serializeInner(value[index], depth + 1, tracking, metrics));
1249
+ if (!items.first) addBytes(metrics, 1);
1250
+ items.first = false;
1251
+ items.items?.push(serializeInner(value[index], depth + 1, path, childAllocate, metrics));
762
1252
  }
763
1253
  if (value.length > limits.maxArrayElements) {
764
- items.push(truncation("max_array_elements", { __original_length: value.length }));
1254
+ if (!items.first) addBytes(metrics, 1);
1255
+ items.first = false;
1256
+ items.items?.push(
1257
+ writeTruncation(metrics, childAllocate, "max_array_elements", {
1258
+ __original_length: value.length
1259
+ })
1260
+ );
765
1261
  }
766
- return items;
1262
+ return items.items;
767
1263
  }
1264
+ const object = openObject(metrics, childAllocate);
768
1265
  const prototype = Object.getPrototypeOf(value);
769
- const serialized = {};
770
1266
  if (prototype && prototype !== Object.prototype) {
771
- serialized.__rasputin_type = prototype.constructor?.name ?? "instance";
1267
+ writeLiteralField(
1268
+ metrics,
1269
+ object,
1270
+ "__rasputin_type",
1271
+ prototype.constructor?.name ?? "instance"
1272
+ );
772
1273
  }
773
1274
  const keys = Object.keys(value);
774
1275
  const maxKeys = keys.length > limits.maxObjectKeys ? limits.maxObjectKeys - 1 : keys.length;
775
1276
  for (let index = 0; index < maxKeys; index++) {
776
1277
  const key = keys[index];
777
1278
  if (key === void 0) continue;
778
- if (redactKeys.has(key.toLowerCase())) {
779
- serialized[key] = REDACTED;
1279
+ if (isRedactedKey(key)) {
1280
+ writeLiteralField(metrics, object, key, REDACTED);
780
1281
  continue;
781
1282
  }
782
1283
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
783
- serialized[key] = descriptor && "value" in descriptor ? serializeInner(descriptor.value, depth + 1, tracking, metrics) : typeMarker("accessor");
1284
+ if (descriptor && "value" in descriptor) {
1285
+ beginField(metrics, object, key);
1286
+ assignField(
1287
+ object,
1288
+ key,
1289
+ serializeInner(descriptor.value, depth + 1, path, childAllocate, metrics)
1290
+ );
1291
+ } else {
1292
+ beginField(metrics, object, key);
1293
+ assignField(object, key, writeTypeMarker(metrics, childAllocate, "accessor"));
1294
+ }
784
1295
  }
785
1296
  if (keys.length > limits.maxObjectKeys) {
786
- Object.assign(
787
- serialized,
788
- truncation("max_object_keys", { __original_length: keys.length })
789
- );
1297
+ writeLiteralField(metrics, object, "__rasputin_truncated", true);
1298
+ writeLiteralField(metrics, object, "__reason", "max_object_keys");
1299
+ writeLiteralField(metrics, object, "__original_length", keys.length);
790
1300
  }
791
- return serialized;
1301
+ return object.target;
792
1302
  } catch (error) {
793
- return typeMarker("unserializable", error instanceof Error ? error.message : void 0);
1303
+ metrics.bytes = bytesBefore;
1304
+ metrics.oversize = oversizeBefore;
1305
+ return writeTypeMarker(
1306
+ metrics,
1307
+ allocate && !metrics.oversize,
1308
+ "unserializable",
1309
+ error instanceof Error ? error.message : void 0
1310
+ );
794
1311
  } finally {
795
- tracking.delete(value);
1312
+ path.delete(value);
796
1313
  }
797
1314
  };
798
- const boundedOversize = (bytes, visitedNodes) => {
799
- const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
800
- return {
801
- value: bounded,
802
- bytes: Buffer2.byteLength(JSON.stringify(bounded), "utf8"),
803
- visitedNodes
804
- };
805
- };
806
1315
  const serializeWithBytes = (value) => {
807
1316
  const fast = primitiveFastPath(value, limits.maxStringLength);
808
1317
  if (fast) {
809
1318
  return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
810
1319
  }
811
- const metrics = { visitedNodes: 0 };
1320
+ const metrics = { visitedNodes: 0, bytes: 0, oversize: false };
1321
+ const reentrant = serializing;
1322
+ const path = reentrant ? /* @__PURE__ */ new Set() : sharedPath;
1323
+ if (!reentrant) {
1324
+ serializing = true;
1325
+ sharedPath.clear();
1326
+ }
812
1327
  try {
813
- const serialized = serializeInner(value, 0, void 0, metrics);
814
- const bytes = Buffer2.byteLength(JSON.stringify(serialized), "utf8");
815
- if (bytes <= limits.maxSerializedValueBytes) {
816
- return { value: serialized, bytes, visitedNodes: metrics.visitedNodes };
1328
+ const serialized = serializeInner(value, 0, path, true, metrics);
1329
+ if (metrics.bytes > limits.maxSerializedValueBytes) {
1330
+ return boundedOversize(metrics.bytes, metrics.visitedNodes);
817
1331
  }
818
- return boundedOversize(bytes, metrics.visitedNodes);
1332
+ return { value: serialized, bytes: metrics.bytes, visitedNodes: metrics.visitedNodes };
819
1333
  } catch {
820
1334
  const failed = typeMarker("unserializable");
821
1335
  return {
822
1336
  value: failed,
823
- bytes: Buffer2.byteLength(JSON.stringify(failed), "utf8"),
1337
+ bytes: jsonLiteralUtf8Bytes(failed),
824
1338
  visitedNodes: metrics.visitedNodes
825
1339
  };
1340
+ } finally {
1341
+ path.clear();
1342
+ if (!reentrant) serializing = false;
826
1343
  }
827
1344
  };
828
1345
  return {
@@ -898,6 +1415,7 @@ var createSourceExclusionMatcher = (exclusions) => {
898
1415
 
899
1416
  // src/execution-recorder/execution-recorder.ts
900
1417
  var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
1418
+ var phaseTimingEnabled = process.env.RASPUTIN_RECORDER_PHASE_TIMING === "1";
901
1419
  var manualFunctionDefinition = (value) => {
902
1420
  const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
903
1421
  const named = located ? void 0 : /^(.+):([^:@]+)$/.exec(value);
@@ -912,8 +1430,8 @@ var manualFunctionDefinition = (value) => {
912
1430
  return { ...definition, functionId: runtimeFunctionId2(definition) };
913
1431
  };
914
1432
  var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualFunctionDefinition(value) : value;
915
- var elapsedMs = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
916
- var roundedMilliseconds = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
1433
+ var elapsedMs2 = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
1434
+ var roundedMilliseconds2 = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
917
1435
  var addRecorderTime = (recording, nanoseconds) => {
918
1436
  if (nanoseconds > 0n) recording.inlineRecorderTimeNs += nanoseconds;
919
1437
  };
@@ -1005,7 +1523,11 @@ var emptyStats = {
1005
1523
  totalInlineWallTimeMs: 0,
1006
1524
  maxInlineWallTimeMs: 0,
1007
1525
  activeEstimatedBytes: 0,
1008
- peakActiveEstimatedBytes: 0
1526
+ peakActiveEstimatedBytes: 0,
1527
+ journalPoolHits: 0,
1528
+ journalPoolMisses: 0,
1529
+ journalPoolSize: 0,
1530
+ journalAllocatedCapacity: 0
1009
1531
  };
1010
1532
  var noOpExecution = {
1011
1533
  createScope: () => ({
@@ -1028,10 +1550,26 @@ var mergeExecutionMetadata = (target, metadata) => {
1028
1550
  if (metadata.name !== void 0) target.name = metadata.name;
1029
1551
  if (metadata.request) target.request = { ...target.request, ...metadata.request };
1030
1552
  };
1553
+ var newRepeatedGroup = (plan) => ({
1554
+ observedCalls: 0,
1555
+ functionId: plan.functionId,
1556
+ runtimePlanId: plan.runtimePlanId
1557
+ });
1558
+ var newSuppression = (group, parentCallId, startedAtNs, endedAtNs) => ({
1559
+ count: 1,
1560
+ firstTimestampNs: startedAtNs,
1561
+ lastTimestampNs: endedAtNs,
1562
+ totalDurationNs: endedAtNs - startedAtNs,
1563
+ functionId: group.functionId,
1564
+ runtimePlanId: group.runtimePlanId,
1565
+ ...parentCallId === void 0 ? {} : { parentCallId },
1566
+ storageIndex: -1,
1567
+ retainedIndex: -1
1568
+ });
1031
1569
  var createExecutionRecorder = (options) => {
1032
1570
  if (!options?.enabled) return noOpExecution;
1033
1571
  const storage = new AsyncLocalStorage();
1034
- const maxEventsPerExecution = Math.max(2, Math.floor(options.maxEventsPerExecution ?? 500));
1572
+ const maxEventsPerExecution = sanitizeJournalCapacity(options.maxEventsPerExecution);
1035
1573
  const maxCapturedCallsPerFunction = Math.max(
1036
1574
  1,
1037
1575
  Math.floor(options.maxCapturedCallsPerFunction ?? 3)
@@ -1046,11 +1584,14 @@ var createExecutionRecorder = (options) => {
1046
1584
  );
1047
1585
  const serializer = createSafeSerializer(options);
1048
1586
  const excludesSource = createSourceExclusionMatcher(options.excludeSources);
1587
+ const journalPool = new ExecutionJournalPool(maxEventsPerExecution);
1588
+ const plansByRuntimeId = [];
1049
1589
  let executionCounter = 0;
1050
1590
  let nextRuntimePlanId = 1;
1051
1591
  const internedPlans = /* @__PURE__ */ new Map();
1052
1592
  const preparedModules = /* @__PURE__ */ new WeakMap();
1053
1593
  const errorExecutions = /* @__PURE__ */ new WeakMap();
1594
+ const phases = phaseTimingEnabled ? { alsNs: 0n, materializeNs: 0n } : void 0;
1054
1595
  const stats = {
1055
1596
  functionCallsObserved: 0,
1056
1597
  functionCallsCaptured: 0,
@@ -1069,8 +1610,11 @@ var createExecutionRecorder = (options) => {
1069
1610
  totalInlineWallTimeMs: 0,
1070
1611
  maxInlineWallTimeMs: 0
1071
1612
  };
1613
+ const addPhase = (key, nanoseconds) => {
1614
+ if (phases && nanoseconds > 0n) phases[key] += nanoseconds;
1615
+ };
1072
1616
  const recordInlineTiming = (recording) => {
1073
- const inlineWallTimeMs = roundedMilliseconds(recording.inlineRecorderTimeNs);
1617
+ const inlineWallTimeMs = roundedMilliseconds2(recording.inlineRecorderTimeNs);
1074
1618
  stats.measuredExecutions++;
1075
1619
  stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
1076
1620
  stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
@@ -1083,16 +1627,20 @@ var createExecutionRecorder = (options) => {
1083
1627
  return serialized;
1084
1628
  };
1085
1629
  const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => serializeAndCount(value));
1630
+ const storePlan = (plan) => {
1631
+ plansByRuntimeId[plan.runtimePlanId] = plan;
1632
+ return plan;
1633
+ };
1086
1634
  const preparePlan = (definition) => {
1087
1635
  const existing = internedPlans.get(definition.functionId);
1088
1636
  if (existing) return existing;
1089
- const plan = {
1637
+ const plan = storePlan({
1090
1638
  runtimePlanId: nextRuntimePlanId++,
1091
1639
  definition,
1092
1640
  functionId: definition.functionId,
1093
1641
  excluded: excludesSource(definition),
1094
1642
  estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
1095
- };
1643
+ });
1096
1644
  internedPlans.set(definition.functionId, plan);
1097
1645
  return plan;
1098
1646
  };
@@ -1101,62 +1649,66 @@ var createExecutionRecorder = (options) => {
1101
1649
  if (cached) return cached;
1102
1650
  const prepared = plans.map((encoded) => {
1103
1651
  const definition = definitionFromEncodedPlan(encoded);
1104
- return {
1652
+ return storePlan({
1105
1653
  runtimePlanId: nextRuntimePlanId++,
1106
1654
  definition,
1107
1655
  functionId: definition.functionId,
1108
1656
  excluded: excludesSource(definition),
1109
1657
  estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
1110
- };
1658
+ });
1111
1659
  });
1112
1660
  preparedModules.set(plans, prepared);
1113
1661
  return prepared;
1114
1662
  };
1115
- const snapshotSuppressed = (group, startedAtNs) => ({
1116
- type: "function_calls_suppressed",
1117
- functionId: group.functionId,
1118
- timestampMs: elapsedMs(startedAtNs, group.firstTimestampNs),
1119
- lastTimestampMs: elapsedMs(startedAtNs, group.lastTimestampNs),
1120
- suppressedCallCount: group.count,
1121
- totalDurationMs: roundedMilliseconds(group.totalDurationNs),
1122
- ...group.parentCallId === void 0 ? {} : { parentCallId: group.parentCallId }
1123
- });
1124
1663
  const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
1125
1664
  const recorderStartedAtNs = process.hrtime.bigint();
1126
- const events = recording.events.values().map(
1127
- (item) => isSuppressionPlaceholder(item) ? snapshotSuppressed(item.group, recording.startedAtNs) : item
1128
- );
1129
- const referencedFunctionIds = new Set(
1130
- events.flatMap(
1131
- (event) => event.type === "function_enter" || event.type === "function_calls_suppressed" ? [event.functionId] : []
1132
- )
1133
- );
1665
+ let events = [];
1666
+ let functions = [];
1667
+ let truncated;
1668
+ let capture;
1669
+ if (recording.cachedState) {
1670
+ events = recording.cachedState.events;
1671
+ functions = recording.cachedState.functions;
1672
+ truncated = recording.cachedState.truncated;
1673
+ capture = recording.cachedState.capture;
1674
+ } else {
1675
+ if (recording.journal) {
1676
+ const materialized = recording.journal.materialize(plansByRuntimeId, recording.startedAtNs);
1677
+ events = materialized.events;
1678
+ functions = materialized.functions;
1679
+ truncated = recording.journal.dropped > 0 ? { eventsDropped: recording.journal.dropped } : void 0;
1680
+ }
1681
+ capture = recording.memory.underPressure ? {
1682
+ completeness: "partial",
1683
+ reason: "process_memory_budget",
1684
+ valuesDropped: recording.memory.valuesDropped,
1685
+ eventsDropped: recording.memory.eventsDropped
1686
+ } : void 0;
1687
+ if (recording.finished && recording.inFlightCalls === 0 && recording.journal) {
1688
+ recording.cachedState = { events, functions, truncated, capture };
1689
+ journalPool.release(recording.journal);
1690
+ recording.journal = void 0;
1691
+ }
1692
+ }
1134
1693
  const state = {
1135
1694
  version: 2,
1136
1695
  executionId: recording.executionId,
1137
1696
  startedAt: recording.startedAt,
1138
- durationMs: elapsedMs(recording.startedAtNs, endedAtNs),
1697
+ durationMs: elapsedMs2(recording.startedAtNs, endedAtNs),
1139
1698
  recorder: { inlineWallTimeMs: 0 },
1140
1699
  execution: {
1141
1700
  ...recording.execution,
1142
1701
  ...recording.execution.request ? { request: { ...recording.execution.request } } : {}
1143
1702
  },
1144
- functions: [...recording.functions.values()].filter(
1145
- (definition) => referencedFunctionIds.has(definition.functionId)
1146
- ),
1147
- events,
1148
- ...recording.events.dropped > 0 ? { truncated: { eventsDropped: recording.events.dropped } } : {},
1149
- ...recording.memory.underPressure ? {
1150
- capture: {
1151
- completeness: "partial",
1152
- reason: "process_memory_budget",
1153
- valuesDropped: recording.memory.valuesDropped,
1154
- eventsDropped: recording.memory.eventsDropped
1155
- }
1156
- } : {}
1703
+ functions: functions.slice(),
1704
+ events: events.slice(),
1705
+ ...truncated ? { truncated: { ...truncated } } : {},
1706
+ ...capture ? { capture: { ...capture } } : {}
1157
1707
  };
1708
+ if (phaseTimingEnabled)
1709
+ addPhase("materializeNs", process.hrtime.bigint() - recorderStartedAtNs);
1158
1710
  addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
1159
- state.recorder = { inlineWallTimeMs: roundedMilliseconds(recording.inlineRecorderTimeNs) };
1711
+ state.recorder = { inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs) };
1160
1712
  return state;
1161
1713
  };
1162
1714
  const rememberError = (error, recording) => {
@@ -1172,32 +1724,38 @@ var createExecutionRecorder = (options) => {
1172
1724
  errorExecutions.set(error, recording);
1173
1725
  };
1174
1726
  const countDroppedEvents = (recording, droppedBefore) => {
1175
- stats.truncatedEvents += recording.events.dropped - droppedBefore;
1727
+ const dropped = recording.journal?.dropped ?? droppedBefore;
1728
+ stats.truncatedEvents += dropped - droppedBefore;
1176
1729
  };
1177
1730
  const appendSuppressedPlaceholder = (recording, group) => {
1731
+ if (!recording.journal) return;
1178
1732
  if (!memoryBudget.reserveStandaloneEvent(recording.memory)) return;
1179
- const droppedBefore = recording.events.dropped;
1180
- recording.events.appendSuppressed(group);
1733
+ const droppedBefore = recording.journal.dropped;
1734
+ recording.journal.appendSuppressed(group);
1181
1735
  countDroppedEvents(recording, droppedBefore);
1182
1736
  };
1183
- const repeatedCallGroup = (recording, runtimePlanId, parentCallId) => {
1737
+ const repeatedCallGroup = (recording, plan, parentCallId) => {
1184
1738
  const slots = recording.repeatedCalls;
1185
- let slot = slots[runtimePlanId];
1739
+ let slot = slots[plan.runtimePlanId];
1186
1740
  if (!slot) {
1187
1741
  slot = {};
1188
- slots[runtimePlanId] = slot;
1742
+ slots[plan.runtimePlanId] = slot;
1189
1743
  }
1190
1744
  if (parentCallId === void 0) {
1191
- if (!slot.root) slot.root = { observedCalls: 0 };
1745
+ if (!slot.root) slot.root = newRepeatedGroup(plan);
1192
1746
  return slot.root;
1193
1747
  }
1748
+ if (slot.lastParentGroup && slot.lastParentCallId === parentCallId) {
1749
+ return slot.lastParentGroup;
1750
+ }
1194
1751
  if (!slot.byParent) slot.byParent = /* @__PURE__ */ new Map();
1195
- const byParent = slot.byParent;
1196
- let group = byParent.get(parentCallId);
1752
+ let group = slot.byParent.get(parentCallId);
1197
1753
  if (!group) {
1198
- group = { observedCalls: 0 };
1199
- byParent.set(parentCallId, group);
1754
+ group = newRepeatedGroup(plan);
1755
+ slot.byParent.set(parentCallId, group);
1200
1756
  }
1757
+ slot.lastParentCallId = parentCallId;
1758
+ slot.lastParentGroup = group;
1201
1759
  return group;
1202
1760
  };
1203
1761
  const serializedError = (recording, error, callId) => {
@@ -1220,29 +1778,30 @@ var createExecutionRecorder = (options) => {
1220
1778
  };
1221
1779
  };
1222
1780
  const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
1781
+ if (!recording.journal) {
1782
+ rememberError(error, recording);
1783
+ return;
1784
+ }
1223
1785
  if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
1224
1786
  rememberError(error, recording);
1225
1787
  return;
1226
1788
  }
1227
1789
  const callId = ++recording.nextCallId;
1228
1790
  const capturedError = serializedError(recording, error, callId);
1229
- const enter = {
1230
- type: "function_enter",
1791
+ const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
1792
+ const endedAtNs = process.hrtime.bigint();
1793
+ const droppedBefore = recording.journal.dropped;
1794
+ const retained = recording.journal.forceCompletedCall(
1795
+ plan.runtimePlanId,
1231
1796
  callId,
1232
- functionId: plan.functionId,
1233
- timestampMs: elapsedMs(recording.startedAtNs, startedAtNs),
1234
- args: Array.from(args, (argument) => captureValue(recording, argument)),
1235
- ...parentCallId === void 0 ? {} : { parentCallId }
1236
- };
1237
- const terminal = {
1238
- type: "function_throw",
1239
- callId,
1240
- timestampMs: elapsedMs(recording.startedAtNs),
1241
- durationMs: elapsedMs(startedAtNs),
1242
- error: capturedError.value
1243
- };
1244
- const droppedBefore = recording.events.dropped;
1245
- const retained = recording.events.forceCompletedCall(enter, terminal);
1797
+ parentCallId,
1798
+ startedAtNs - recording.startedAtNs,
1799
+ capturedArgs,
1800
+ KIND_THROW,
1801
+ endedAtNs - recording.startedAtNs,
1802
+ endedAtNs - startedAtNs,
1803
+ capturedError.value
1804
+ );
1246
1805
  if (retained) {
1247
1806
  stats.functionCallsCaptured++;
1248
1807
  capturedError.commit();
@@ -1250,29 +1809,46 @@ var createExecutionRecorder = (options) => {
1250
1809
  countDroppedEvents(recording, droppedBefore);
1251
1810
  rememberError(error, recording);
1252
1811
  };
1253
- const recordSuppressedCall = (recording, group, functionId, parentCallId, startedAtNs, endedAtNs) => {
1812
+ const recordSuppressedCall = (recording, group, parentCallId, startedAtNs, endedAtNs) => {
1254
1813
  stats.repeatedCallsSuppressed++;
1255
- const durationNs = endedAtNs - startedAtNs;
1256
1814
  if (!group.suppressed) {
1257
- group.suppressed = {
1258
- count: 1,
1259
- firstTimestampNs: startedAtNs,
1260
- lastTimestampNs: endedAtNs,
1261
- totalDurationNs: durationNs,
1262
- functionId,
1263
- ...parentCallId === void 0 ? {} : { parentCallId }
1264
- };
1815
+ group.suppressed = newSuppression(group, parentCallId, startedAtNs, endedAtNs);
1265
1816
  appendSuppressedPlaceholder(recording, group.suppressed);
1266
1817
  return;
1267
1818
  }
1268
1819
  const suppressed = group.suppressed;
1269
1820
  suppressed.count++;
1270
1821
  suppressed.lastTimestampNs = endedAtNs;
1271
- suppressed.totalDurationNs += durationNs;
1272
- if (!suppressed.retainedSlot) {
1822
+ suppressed.totalDurationNs += endedAtNs - startedAtNs;
1823
+ if (suppressed.retainedIndex < 0) {
1273
1824
  appendSuppressedPlaceholder(recording, suppressed);
1274
1825
  }
1275
1826
  };
1827
+ const releaseJournalIfIdle = (recording) => {
1828
+ if (!recording.finished || recording.hasError || recording.inFlightCalls > 0) return;
1829
+ if (!recording.journal) return;
1830
+ journalPool.release(recording.journal);
1831
+ recording.journal = void 0;
1832
+ };
1833
+ const acquireJournal = (recording) => {
1834
+ if (recording.journal) return recording.journal;
1835
+ try {
1836
+ const journal = journalPool.acquire();
1837
+ if (!memoryBudget.reserveStorage(recording.memory, journal.allocatedBytes)) {
1838
+ journalPool.release(journal);
1839
+ return void 0;
1840
+ }
1841
+ journal.onGrow = (deltaBytes) => memoryBudget.reserveStorage(recording.memory, deltaBytes);
1842
+ recording.journal = journal;
1843
+ return journal;
1844
+ } catch {
1845
+ return void 0;
1846
+ }
1847
+ };
1848
+ const settleInFlight = (recording) => {
1849
+ if (recording.inFlightCalls > 0) recording.inFlightCalls--;
1850
+ releaseJournalIfIdle(recording);
1851
+ };
1276
1852
  const finish = (store, metadata) => {
1277
1853
  const { recording } = store;
1278
1854
  if (recording.finished) return;
@@ -1281,11 +1857,22 @@ var createExecutionRecorder = (options) => {
1281
1857
  if (metadata) mergeExecutionMetadata(recording.execution, metadata);
1282
1858
  memoryBudget.release(recording.memory);
1283
1859
  stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
1284
- if (!recording.hasError) stats.successfulExecutionsDiscarded++;
1860
+ if (!recording.hasError) {
1861
+ stats.successfulExecutionsDiscarded++;
1862
+ releaseJournalIfIdle(recording);
1863
+ }
1285
1864
  recording.finishedAtNs = process.hrtime.bigint();
1286
1865
  addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
1287
1866
  recordInlineTiming(recording);
1288
1867
  };
1868
+ const runStore = (store, callback) => {
1869
+ if (!phaseTimingEnabled) return storage.run(store, callback);
1870
+ const alsStartedAtNs = process.hrtime.bigint();
1871
+ return storage.run(store, () => {
1872
+ addPhase("alsNs", process.hrtime.bigint() - alsStartedAtNs);
1873
+ return callback();
1874
+ });
1875
+ };
1289
1876
  const createScope = (metadata) => {
1290
1877
  const recorderStartedAtNs = process.hrtime.bigint();
1291
1878
  try {
@@ -1298,11 +1885,11 @@ var createExecutionRecorder = (options) => {
1298
1885
  ...metadata,
1299
1886
  ...metadata.request ? { request: { ...metadata.request } } : {}
1300
1887
  },
1301
- events: new CallAwareEventBuffer(maxEventsPerExecution),
1302
- functions: /* @__PURE__ */ new Map(),
1888
+ journal: void 0,
1303
1889
  repeatedCalls: [],
1304
1890
  capturedErrors: /* @__PURE__ */ new WeakMap(),
1305
1891
  nextCallId: 0,
1892
+ inFlightCalls: 0,
1306
1893
  finished: false,
1307
1894
  hasError: false,
1308
1895
  memory: memoryBudget.startExecution(),
@@ -1315,7 +1902,7 @@ var createExecutionRecorder = (options) => {
1315
1902
  return {
1316
1903
  run: (callback) => {
1317
1904
  const runStartedAtNs = process.hrtime.bigint();
1318
- return storage.run(store, () => {
1905
+ return runStore(store, () => {
1319
1906
  addRecorderTime(recording, process.hrtime.bigint() - runStartedAtNs);
1320
1907
  return callback();
1321
1908
  });
@@ -1375,132 +1962,145 @@ var createExecutionRecorder = (options) => {
1375
1962
  const recorderStartedAtNs = process.hrtime.bigint();
1376
1963
  if (store.suppressCapture || plan.excluded) {
1377
1964
  stats.functionCallsExcluded++;
1378
- return storage.run({ ...store, suppressCapture: true }, () => {
1965
+ return runStore({ ...store, suppressCapture: true }, () => {
1379
1966
  addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
1380
1967
  return callback();
1381
1968
  });
1382
1969
  }
1970
+ const recording = store.recording;
1971
+ recording.inFlightCalls++;
1383
1972
  const parentCallId = store.currentCallId;
1384
- const group = repeatedCallGroup(store.recording, plan.runtimePlanId, parentCallId);
1973
+ const group = repeatedCallGroup(recording, plan, parentCallId);
1385
1974
  group.observedCalls++;
1386
- if (group.observedCalls === 1) {
1387
- store.recording.functions.set(plan.functionId, plan.definition);
1388
- }
1975
+ const journal = acquireJournal(recording);
1976
+ if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
1389
1977
  if (group.observedCalls > maxCapturedCallsPerFunction) {
1390
1978
  const startedAtNs2 = process.hrtime.bigint();
1391
1979
  try {
1392
1980
  const result = callback();
1393
1981
  if (isPromiseLike(result)) {
1394
- addRecorderTime(store.recording, startedAtNs2 - recorderStartedAtNs);
1982
+ addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
1395
1983
  return result.then(
1396
1984
  (value) => {
1397
1985
  const callbackEndedAtNs2 = process.hrtime.bigint();
1398
- recordSuppressedCall(
1399
- store.recording,
1400
- group,
1401
- plan.functionId,
1402
- parentCallId,
1403
- startedAtNs2,
1404
- callbackEndedAtNs2
1405
- );
1406
- addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs2);
1986
+ recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs2);
1987
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
1988
+ settleInFlight(recording);
1407
1989
  return value;
1408
1990
  },
1409
1991
  (error) => {
1410
1992
  const callbackEndedAtNs2 = process.hrtime.bigint();
1411
- captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs2, error);
1412
- addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs2);
1993
+ captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
1994
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
1995
+ settleInFlight(recording);
1413
1996
  throw error;
1414
1997
  }
1415
1998
  );
1416
1999
  }
1417
2000
  const callbackEndedAtNs = process.hrtime.bigint();
1418
- recordSuppressedCall(
1419
- store.recording,
1420
- group,
1421
- plan.functionId,
1422
- parentCallId,
1423
- startedAtNs2,
1424
- callbackEndedAtNs
1425
- );
1426
- addRecorderTime(store.recording, startedAtNs2 - recorderStartedAtNs);
1427
- addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs);
2001
+ recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs);
2002
+ addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2003
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
2004
+ settleInFlight(recording);
1428
2005
  return result;
1429
2006
  } catch (error) {
1430
2007
  const callbackEndedAtNs = process.hrtime.bigint();
1431
- captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs2, error);
1432
- addRecorderTime(store.recording, startedAtNs2 - recorderStartedAtNs);
1433
- addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs);
2008
+ captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
2009
+ addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2010
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
2011
+ settleInFlight(recording);
1434
2012
  throw error;
1435
2013
  }
1436
2014
  }
1437
2015
  const startedAtNs = process.hrtime.bigint();
1438
- if (!store.recording.events.canStartCall()) {
2016
+ if (!journal) {
2017
+ memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
2018
+ return runStore(
2019
+ store,
2020
+ () => observeRecordedCallback(
2021
+ recording,
2022
+ recorderStartedAtNs,
2023
+ callback,
2024
+ () => settleInFlight(recording),
2025
+ (error) => {
2026
+ rememberError(error, recording);
2027
+ settleInFlight(recording);
2028
+ }
2029
+ )
2030
+ );
2031
+ }
2032
+ if (!journal.canStartCall()) {
1439
2033
  const captureSuccess = () => {
1440
- const droppedBefore = store.recording.events.dropped;
1441
- store.recording.events.dropCall();
1442
- countDroppedEvents(store.recording, droppedBefore);
2034
+ const droppedBefore = recording.journal?.dropped ?? 0;
2035
+ recording.journal?.dropCall();
2036
+ countDroppedEvents(recording, droppedBefore);
2037
+ settleInFlight(recording);
1443
2038
  };
1444
- return storage.run(
2039
+ return runStore(
1445
2040
  store,
1446
2041
  () => observeRecordedCallback(
1447
- store.recording,
2042
+ recording,
1448
2043
  recorderStartedAtNs,
1449
2044
  callback,
1450
2045
  captureSuccess,
1451
- (error) => captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs, error)
2046
+ (error) => {
2047
+ captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
2048
+ settleInFlight(recording);
2049
+ }
1452
2050
  )
1453
2051
  );
1454
2052
  }
1455
- if (!memoryBudget.reserveCall(store.recording.memory, plan.estimatedCallBytes)) {
2053
+ if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
1456
2054
  return observeRecordedCallback(
1457
- store.recording,
2055
+ recording,
1458
2056
  recorderStartedAtNs,
1459
2057
  callback,
1460
- () => {
1461
- },
1462
- (error) => rememberError(error, store.recording)
2058
+ () => settleInFlight(recording),
2059
+ (error) => {
2060
+ rememberError(error, recording);
2061
+ settleInFlight(recording);
2062
+ }
1463
2063
  );
1464
2064
  }
1465
- const callId = ++store.recording.nextCallId;
1466
- const enter = {
1467
- type: "function_enter",
1468
- callId,
1469
- functionId: plan.functionId,
1470
- timestampMs: elapsedMs(store.recording.startedAtNs),
1471
- args: Array.from(args, (argument) => captureValue(store.recording, argument)),
1472
- ...parentCallId === void 0 ? {} : { parentCallId }
1473
- };
1474
- store.recording.events.startCall(enter);
1475
- const callStore = { recording: store.recording, currentCallId: callId };
1476
- return storage.run(
2065
+ const callId = ++recording.nextCallId;
2066
+ const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
2067
+ const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
2068
+ journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
2069
+ const callStore = { recording, currentCallId: callId };
2070
+ return runStore(
1477
2071
  callStore,
1478
2072
  () => observeRecordedCallback(
1479
- store.recording,
2073
+ recording,
1480
2074
  recorderStartedAtNs,
1481
2075
  callback,
1482
2076
  (value) => {
1483
- store.recording.events.finishCall({
1484
- type: "function_exit",
1485
- callId,
1486
- timestampMs: elapsedMs(store.recording.startedAtNs),
1487
- durationMs: elapsedMs(startedAtNs),
1488
- returnValue: captureValue(store.recording, value)
1489
- });
1490
- stats.functionCallsCaptured++;
2077
+ if (recording.journal) {
2078
+ const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
2079
+ const durationNs = process.hrtime.bigint() - startedAtNs;
2080
+ const returnValue = captureValue(recording, value);
2081
+ recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
2082
+ stats.functionCallsCaptured++;
2083
+ }
2084
+ settleInFlight(recording);
1491
2085
  },
1492
2086
  (error) => {
1493
- const capturedError = serializedError(store.recording, error, callId);
1494
- store.recording.events.finishCall({
1495
- type: "function_throw",
2087
+ if (!recording.journal) {
2088
+ rememberError(error, recording);
2089
+ settleInFlight(recording);
2090
+ return;
2091
+ }
2092
+ const capturedError = serializedError(recording, error, callId);
2093
+ recording.journal.finishCall(
2094
+ KIND_THROW,
1496
2095
  callId,
1497
- timestampMs: elapsedMs(store.recording.startedAtNs),
1498
- durationMs: elapsedMs(startedAtNs),
1499
- error: capturedError.value
1500
- });
2096
+ process.hrtime.bigint() - recording.startedAtNs,
2097
+ process.hrtime.bigint() - startedAtNs,
2098
+ capturedError.value
2099
+ );
1501
2100
  stats.functionCallsCaptured++;
1502
2101
  capturedError.commit();
1503
- rememberError(error, store.recording);
2102
+ rememberError(error, recording);
2103
+ settleInFlight(recording);
1504
2104
  }
1505
2105
  )
1506
2106
  );
@@ -1527,7 +2127,15 @@ var createExecutionRecorder = (options) => {
1527
2127
  prepareFunctionPlans,
1528
2128
  runPreparedFunction,
1529
2129
  trace,
1530
- getStats: () => ({ ...stats, ...memoryBudget.getStats() })
2130
+ getStats: () => ({
2131
+ ...stats,
2132
+ ...memoryBudget.getStats(),
2133
+ ...journalPool.stats(),
2134
+ ...phases ? {
2135
+ phaseAlsNs: Number(phases.alsNs),
2136
+ phaseMaterializeNs: Number(phases.materializeNs)
2137
+ } : {}
2138
+ })
1531
2139
  };
1532
2140
  };
1533
2141
 
@@ -1644,7 +2252,7 @@ import {
1644
2252
 
1645
2253
  // src/sdk-meta.ts
1646
2254
  var SDK_NAME = "@rasputin-ai/node";
1647
- var SDK_VERSION = "0.5.0-alpha.4";
2255
+ var SDK_VERSION = "0.5.0-alpha.6";
1648
2256
 
1649
2257
  // src/rasputin-init.ts
1650
2258
  var withExecution = (client, execution, installRuntime, manifest) => {