@rasputin-ai/node 0.5.0-alpha.1 → 0.5.0-alpha.3

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/README.md CHANGED
@@ -73,7 +73,7 @@ Optionally attach the runtime state that led to an error — arguments, return v
73
73
 
74
74
  ## Automatic instrumentation
75
75
 
76
- Build-time instrumentation is the preferred high-performance mode. Transform compiled unbundled JavaScript after `tsc` so the production process never loads TypeScript:
76
+ Build-time instrumentation is the production default. Transform compiled unbundled JavaScript after `tsc` so the running process never loads the TypeScript compiler:
77
77
 
78
78
  ```json
79
79
  {
@@ -87,7 +87,7 @@ Build-time instrumentation is the preferred high-performance mode. Transform com
87
87
 
88
88
  Emit adjacent source maps from TypeScript so function identities stay pointed at the original files. The instrumenter writes `.rasputin/instrumentation-manifest.json` next to the output. RasputinInit loads that file automatically, or from `RASPUTIN_INSTRUMENTATION_MANIFEST`.
89
89
 
90
- Load-time transformation remains available as a compatibility fallback. It imports the TypeScript compiler into the application process and increases RSS:
90
+ Node `--import` and Bun `--preload` remain compatibility and development fallbacks. They transform application source as it loads, which pulls compiler infrastructure into the process and has materially higher RSS. Do not use those loader measurements in low-overhead comparisons. In `NODE_ENV=production` the loaders print a one-time warning recommending `rasputin-instrument`. Set `RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING=1` to hide it.
91
91
 
92
92
  ```json
93
93
  {
@@ -173,16 +173,16 @@ Runtime state can include application data. Use `redactKeys` for sensitive field
173
173
  const { recorder, transport } = rasputin.getStats();
174
174
  ```
175
175
 
176
- Counters are local to the current process and reset on restart.
177
-
178
- Recorder work counters support performance diagnosis without retaining successful execution state:
179
-
180
- - `functionCallsObserved` counts hooks reached inside active execution scopes.
181
- - `functionCallsCaptured` counts complete enter/terminal pairs recorded before any later eviction.
182
- - `functionCallsExcluded` counts hooks omitted by source or excluded-subtree rules.
183
- - `repeatedCallsSuppressed` counts successful repetitions represented by suppression summaries.
184
- - `serializedValues`, `serializedValueNodes`, and `serializedValueBytes` describe bounded value
185
- capture work. Redacted subtrees are not traversed or included in the node count.
186
-
187
- All counters are cumulative. Compare before/after snapshots for a measurement window rather than
188
- dividing the process-lifetime totals by a single request count.
176
+ Counters are local to the current process and reset on restart.
177
+
178
+ Recorder work counters support performance diagnosis without retaining successful execution state:
179
+
180
+ - `functionCallsObserved` counts hooks reached inside active execution scopes.
181
+ - `functionCallsCaptured` counts complete enter/terminal pairs recorded before any later eviction.
182
+ - `functionCallsExcluded` counts hooks omitted by source or excluded-subtree rules.
183
+ - `repeatedCallsSuppressed` counts successful repetitions represented by suppression summaries.
184
+ - `serializedValues`, `serializedValueNodes`, and `serializedValueBytes` describe bounded value
185
+ capture work. Redacted subtrees are not traversed or included in the node count.
186
+
187
+ All counters are cumulative. Compare before/after snapshots for a measurement window rather than
188
+ dividing the process-lifetime totals by a single request count.
@@ -1 +1 @@
1
- {"version":3,"file":"transform-source.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/transform-source.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACX,4BAA4B,EAE5B,MAAM,kCAAkC,CAAC;AAI1C,MAAM,MAAM,sBAAsB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,oBAAoB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,4BAA4B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,cAAc,GAAG,SAAS,CAAC;AA+H5F,6FAA6F;AAC7F,eAAO,MAAM,eAAe,GAC3B,QAAQ,MAAM,EACd,SAAS,sBAAsB,KAC7B,iBAAiB,GAAG,SAsFtB,CAAC"}
1
+ {"version":3,"file":"transform-source.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/transform-source.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACX,4BAA4B,EAE5B,MAAM,kCAAkC,CAAC;AAI1C,MAAM,MAAM,sBAAsB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,oBAAoB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,4BAA4B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,cAAc,GAAG,SAAS,CAAC;AAkJ5F,6FAA6F;AAC7F,eAAO,MAAM,eAAe,GAC3B,QAAQ,MAAM,EACd,SAAS,sBAAsB,KAC7B,iBAAiB,GAAG,SA0FtB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Load-time transformation pulls the TypeScript compiler into the application process. Production
3
+ * should prefer `rasputin-instrument` at build time; this warning exists so that fallback stays
4
+ * available without being mistaken for the low-overhead path.
5
+ */
6
+ export declare const RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV = "RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING";
7
+ export declare const warnIfProductionRuntimeTransform: () => void;
8
+ //# sourceMappingURL=warn-production-runtime-transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warn-production-runtime-transform.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/warn-production-runtime-transform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,sCAAsC,gDAAgD,CAAC;AAIpG,eAAO,MAAM,gCAAgC,QAAO,IAQnD,CAAC"}
@@ -7,12 +7,19 @@ import type { RasputinExecution } from './execution-recorder-types';
7
7
  import type { EncodedFunctionPlan } from './function-plan';
8
8
  export declare const AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
9
9
  type ModuleRunner = <T>(planIndex: number, args: ArrayLike<unknown>, callback: () => T) => T;
10
+ type DispatchCell = {
11
+ run: ModuleRunner;
12
+ };
13
+ type RegisteredModule = {
14
+ plans: readonly EncodedFunctionPlan[];
15
+ cell: DispatchCell;
16
+ };
10
17
  type AutomaticRuntime = {
11
- run: <T>(plans: readonly EncodedFunctionPlan[], planIndex: number, args: ArrayLike<unknown>, callback: () => T) => T;
18
+ bind: (module: RegisteredModule) => void;
12
19
  };
13
20
  type AutomaticRuntimeRegistry = {
14
- __rasputinRuntimeRegistry: true;
15
21
  runtimes: AutomaticRuntime[];
22
+ modules: RegisteredModule[];
16
23
  register: (plans: readonly EncodedFunctionPlan[]) => ModuleRunner;
17
24
  };
18
25
  export declare const getAutomaticRuntimeRegistry: () => AutomaticRuntimeRegistry;
@@ -1 +1 @@
1
- {"version":3,"file":"automatic-runtime.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/automatic-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAIxE,KAAK,YAAY,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAE7F,KAAK,gBAAgB,GAAG;IACvB,GAAG,EAAE,CAAC,CAAC,EACN,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,KACb,CAAC,CAAC;CACP,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC/B,yBAAyB,EAAE,IAAI,CAAC;IAChC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,KAAK,YAAY,CAAC;CAClE,CAAC;AAgBF,eAAO,MAAM,2BAA2B,QAAO,wBAY9C,CAAC;AAEF,eAAO,MAAM,8BAA8B,QAAO,IAEjD,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,gCAAgC,GAAI,WAAW,iBAAiB,KAAG,CAAC,MAAM,IAAI,CAW1F,CAAC"}
1
+ {"version":3,"file":"automatic-runtime.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/automatic-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAIxE,KAAK,YAAY,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAE7F,KAAK,YAAY,GAAG;IACnB,GAAG,EAAE,YAAY,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACvB,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtC,IAAI,EAAE,YAAY,CAAC;CACnB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACvB,IAAI,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,KAAK,YAAY,CAAC;CAClE,CAAC;AAmCF,eAAO,MAAM,2BAA2B,QAAO,wBAO9C,CAAC;AAEF,eAAO,MAAM,8BAA8B,QAAO,IAEjD,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,gCAAgC,GAAI,WAAW,iBAAiB,KAAG,CAAC,MAAM,IAAI,CAsB1F,CAAC"}
@@ -4,21 +4,34 @@
4
4
  * keeps truncated snapshots usable by investigations and source-addressable debugging UIs.
5
5
  */
6
6
  import type { ExecutionEvent, ExecutionFunctionEnterEvent } from './execution-recorder-types';
7
+ export type CompactSuppression = {
8
+ count: number;
9
+ firstTimestampNs: bigint;
10
+ lastTimestampNs: bigint;
11
+ totalDurationNs: bigint;
12
+ functionId: string;
13
+ parentCallId?: number;
14
+ retainedSlot?: SuppressionPlaceholder;
15
+ };
16
+ export type SuppressionPlaceholder = {
17
+ kind: 'suppressed';
18
+ group: CompactSuppression;
19
+ };
20
+ export type BufferItem = ExecutionEvent | SuppressionPlaceholder;
21
+ export declare const isSuppressionPlaceholder: (item: BufferItem) => item is SuppressionPlaceholder;
7
22
  export declare class CallAwareEventBuffer {
8
23
  private readonly capacity;
9
24
  private readonly items;
10
25
  private readonly openCallIds;
11
- private readonly retainedSummaries;
12
26
  dropped: number;
13
27
  constructor(capacity: number);
14
28
  canStartCall(): boolean;
15
29
  startCall(event: ExecutionFunctionEnterEvent): void;
16
30
  finishCall(event: ExecutionEvent): void;
17
31
  dropCall(): void;
18
- append(event: ExecutionEvent): boolean;
19
- hasSummary(event: object): boolean;
32
+ appendSuppressed(group: CompactSuppression): boolean;
20
33
  forceCompletedCall(enter: ExecutionFunctionEnterEvent, terminal: ExecutionEvent): boolean;
21
- values(): ExecutionEvent[];
34
+ values(): BufferItem[];
22
35
  private evictCompletedLeafOrSummary;
23
36
  }
24
37
  //# sourceMappingURL=call-aware-event-buffer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"call-aware-event-buffer.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/call-aware-event-buffer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE9F,qBAAa,oBAAoB;IAOpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IANrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAyB;IAE3D,OAAO,SAAK;gBAEiB,QAAQ,EAAE,MAAM;IAE7C,YAAY,IAAI,OAAO;IAIvB,SAAS,CAAC,KAAK,EAAE,2BAA2B;IAK5C,UAAU,CAAC,KAAK,EAAE,cAAc;IAMhC,QAAQ;IAIR,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAWtC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIlC,kBAAkB,CAAC,KAAK,EAAE,2BAA2B,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO;IAYzF,MAAM,IAAI,cAAc,EAAE;IAI1B,OAAO,CAAC,2BAA2B;CAiDnC"}
1
+ {"version":3,"file":"call-aware-event-buffer.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/call-aware-event-buffer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE9F,MAAM,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,sBAAsB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,kBAAkB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,sBAAsB,CAAC;AAEjE,eAAO,MAAM,wBAAwB,GAAI,MAAM,UAAU,KAAG,IAAI,IAAI,sBACvB,CAAC;AAE9C,qBAAa,oBAAoB;IAMpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IALrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IAEjD,OAAO,SAAK;gBAEiB,QAAQ,EAAE,MAAM;IAE7C,YAAY,IAAI,OAAO;IAIvB,SAAS,CAAC,KAAK,EAAE,2BAA2B;IAK5C,UAAU,CAAC,KAAK,EAAE,cAAc;IAMhC,QAAQ;IAIR,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO;IAYpD,kBAAkB,CAAC,KAAK,EAAE,2BAA2B,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO;IAYzF,MAAM,IAAI,UAAU,EAAE;IAItB,OAAO,CAAC,2BAA2B;CAkDnC"}
@@ -86,6 +86,8 @@ export type RasputinExecution = {
86
86
  runFunction: <T>(definition: RuntimeFunctionDefinition | string, args: ArrayLike<unknown>, callback: () => T) => T;
87
87
  /** Internal prepared-plan path used by automatic instrumentation. */
88
88
  runFunctionPlans: <T>(plans: readonly EncodedFunctionPlan[], planIndex: number, args: ArrayLike<unknown>, callback: () => T) => T;
89
+ /** Resolve a module plan table once so generated wrappers can bind to prepared plans. */
90
+ prepareFunctionPlans: (plans: readonly EncodedFunctionPlan[]) => PreparedFunctionPlan[];
89
91
  /** Internal primitive used after a module's function plans have been resolved. */
90
92
  runPreparedFunction: <T>(plan: PreparedFunctionPlan, args: ArrayLike<unknown>, callback: () => T) => T;
91
93
  /** Manual fallback for runtimes/build systems without automatic instrumentation. */
@@ -1 +1 @@
1
- {"version":3,"file":"execution-recorder-types.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execution-recorder-types.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"execution-recorder.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAKX,wBAAwB,EAExB,iBAAiB,EACjB,MAAM,4BAA4B,CAAC;AAkNpC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GACnC,SAAS,wBAAwB,GAAG,SAAS,KAC3C,iBAqlBF,CAAC"}
1
+ {"version":3,"file":"execution-recorder.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAKX,wBAAwB,EAExB,iBAAiB,EACjB,MAAM,4BAA4B,CAAC;AAuNpC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GACnC,SAAS,wBAAwB,GAAG,SAAS,KAC3C,iBA4kBF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"safe-serialize.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/safe-serialize.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAsD3E,MAAM,MAAM,mBAAmB,GAAG;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IACvC,kBAAkB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,mBAAmB,CAAC;CAC5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,UAAS,wBAA6B,KAAG,cA8J7E,CAAC;AAYF,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,GAClC,OAAO,OAAO,EACd,UAAS,wBAA6B,KACpC,mBAIyB,CAAC;AAE7B,0EAA0E;AAC1E,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,EAAE,UAAS,wBAA6B,KAAG,OAC1C,CAAC"}
1
+ {"version":3,"file":"safe-serialize.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/safe-serialize.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAqI3E,MAAM,MAAM,mBAAmB,GAAG;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IACvC,kBAAkB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,mBAAmB,CAAC;CAC5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,UAAS,wBAA6B,KAAG,cAyK7E,CAAC;AAYF,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,GAClC,OAAO,OAAO,EACd,UAAS,wBAA6B,KACpC,mBAIyB,CAAC;AAE7B,0EAA0E;AAC1E,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,EAAE,UAAS,wBAA6B,KAAG,OAC1C,CAAC"}
package/dist/index.js CHANGED
@@ -387,13 +387,13 @@ import { AsyncLocalStorage } from "node:async_hooks";
387
387
  import { runtimeFunctionId as runtimeFunctionId2 } from "@rasputin-ai/core";
388
388
 
389
389
  // src/execution-recorder/call-aware-event-buffer.ts
390
+ var isSuppressionPlaceholder = (item) => "kind" in item && item.kind === "suppressed";
390
391
  var CallAwareEventBuffer = class {
391
392
  constructor(capacity) {
392
393
  this.capacity = capacity;
393
394
  }
394
395
  items = [];
395
396
  openCallIds = /* @__PURE__ */ new Set();
396
- retainedSummaries = /* @__PURE__ */ new WeakSet();
397
397
  dropped = 0;
398
398
  canStartCall() {
399
399
  return this.items.length + this.openCallIds.size + 2 <= this.capacity;
@@ -410,18 +410,16 @@ var CallAwareEventBuffer = class {
410
410
  dropCall() {
411
411
  this.dropped += 2;
412
412
  }
413
- append(event) {
413
+ appendSuppressed(group) {
414
414
  if (this.items.length + this.openCallIds.size + 1 > this.capacity) {
415
415
  this.dropped++;
416
416
  return false;
417
417
  }
418
- this.items.push(event);
419
- if (event.type === "function_calls_suppressed") this.retainedSummaries.add(event);
418
+ const placeholder = { kind: "suppressed", group };
419
+ this.items.push(placeholder);
420
+ group.retainedSlot = placeholder;
420
421
  return true;
421
422
  }
422
- hasSummary(event) {
423
- return this.retainedSummaries.has(event);
424
- }
425
423
  forceCompletedCall(enter, terminal) {
426
424
  while (this.items.length + this.openCallIds.size + 2 > this.capacity) {
427
425
  if (!this.evictCompletedLeafOrSummary()) {
@@ -436,29 +434,26 @@ var CallAwareEventBuffer = class {
436
434
  return [...this.items];
437
435
  }
438
436
  evictCompletedLeafOrSummary() {
439
- const summaryIndex = this.items.findIndex(
440
- (event) => event.type === "function_calls_suppressed"
441
- );
437
+ const summaryIndex = this.items.findIndex((item) => isSuppressionPlaceholder(item));
442
438
  if (summaryIndex >= 0) {
443
439
  const summary = this.items[summaryIndex];
444
- if (summary) this.retainedSummaries.delete(summary);
440
+ if (summary && isSuppressionPlaceholder(summary)) summary.group.retainedSlot = void 0;
445
441
  this.items.splice(summaryIndex, 1);
446
442
  this.dropped++;
447
443
  return true;
448
444
  }
449
445
  const parentCallIds = /* @__PURE__ */ new Set();
450
- for (const event of this.items) {
451
- if ((event.type === "function_enter" || event.type === "function_calls_suppressed") && event.parentCallId !== void 0) {
452
- parentCallIds.add(event.parentCallId);
453
- }
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);
454
449
  }
455
450
  for (let index = 0; index < this.items.length; index++) {
456
451
  const event = this.items[index];
457
- if (event?.type !== "function_enter" || this.openCallIds.has(event.callId) || parentCallIds.has(event.callId)) {
452
+ if (!event || isSuppressionPlaceholder(event) || event.type !== "function_enter" || this.openCallIds.has(event.callId) || parentCallIds.has(event.callId)) {
458
453
  continue;
459
454
  }
460
455
  const terminalIndex = this.items.findIndex(
461
- (candidate) => (candidate.type === "function_exit" || candidate.type === "function_throw") && candidate.callId === event.callId
456
+ (candidate) => !isSuppressionPlaceholder(candidate) && (candidate.type === "function_exit" || candidate.type === "function_throw") && candidate.callId === event.callId
462
457
  );
463
458
  if (terminalIndex < 0) continue;
464
459
  this.items.splice(Math.max(index, terminalIndex), 1);
@@ -605,6 +600,10 @@ var defaults = {
605
600
  maxStringLength: 500,
606
601
  maxSerializedValueBytes: 8 * 1024
607
602
  };
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;
608
607
  var truncation = (reason, extra = {}) => ({
609
608
  __rasputin_truncated: true,
610
609
  __reason: reason,
@@ -626,6 +625,68 @@ var compileRedactKeys = (options) => {
626
625
  if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
627
626
  return /* @__PURE__ */ new Set([...DEFAULT_REDACT_KEYS, ...options.redactKeys.map((key) => key.toLowerCase())]);
628
627
  };
628
+ var isJsonSafeString = (value) => {
629
+ for (let index = 0; index < value.length; index++) {
630
+ const code = value.charCodeAt(index);
631
+ if (code < 32 || code === 34 || code === 92) return false;
632
+ if (code >= 55296 && code <= 56319) {
633
+ const next = value.charCodeAt(index + 1);
634
+ if (index + 1 >= value.length || next < 56320 || next > 57343) return false;
635
+ index++;
636
+ continue;
637
+ }
638
+ if (code >= 56320 && code <= 57343) return false;
639
+ }
640
+ return true;
641
+ };
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
+ var primitiveFastPath = (value, maxStringLength) => {
644
+ if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
645
+ if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
646
+ if (typeof value === "number") {
647
+ if (!Number.isFinite(value)) return { value, bytes: 4, visitedNodes: 1 };
648
+ if (Object.is(value, -0)) return { value, bytes: 1, visitedNodes: 1 };
649
+ return { value, bytes: String(value).length, visitedNodes: 1 };
650
+ }
651
+ if (typeof value === "string") {
652
+ if (value.length > maxStringLength || !isJsonSafeString(value)) return void 0;
653
+ return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
654
+ }
655
+ if (typeof value === "undefined") {
656
+ return {
657
+ value: { __rasputin_type: "undefined" },
658
+ bytes: UNDEFINED_MARKER_BYTES,
659
+ visitedNodes: 1
660
+ };
661
+ }
662
+ 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
+ };
669
+ }
670
+ if (typeof value === "symbol") {
671
+ const text = String(value);
672
+ if (!isJsonSafeString(text)) return void 0;
673
+ return {
674
+ value: { __rasputin_type: "symbol", value: text },
675
+ bytes: typeMarkerWithValueBytes("symbol", text),
676
+ visitedNodes: 1
677
+ };
678
+ }
679
+ if (typeof value === "function") {
680
+ const name = value.name || "anonymous";
681
+ if (!isJsonSafeString(name)) return void 0;
682
+ return {
683
+ value: { __rasputin_type: "function", value: name },
684
+ bytes: typeMarkerWithValueBytes("function", name),
685
+ visitedNodes: 1
686
+ };
687
+ }
688
+ return void 0;
689
+ };
629
690
  var createSafeSerializer = (options = {}) => {
630
691
  const limits = compileLimits(options);
631
692
  const redactKeys = compileRedactKeys(options);
@@ -734,7 +795,19 @@ var createSafeSerializer = (options = {}) => {
734
795
  tracking.delete(value);
735
796
  }
736
797
  };
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
+ };
737
806
  const serializeWithBytes = (value) => {
807
+ const fast = primitiveFastPath(value, limits.maxStringLength);
808
+ if (fast) {
809
+ return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
810
+ }
738
811
  const metrics = { visitedNodes: 0 };
739
812
  try {
740
813
  const serialized = serializeInner(value, 0, void 0, metrics);
@@ -742,12 +815,7 @@ var createSafeSerializer = (options = {}) => {
742
815
  if (bytes <= limits.maxSerializedValueBytes) {
743
816
  return { value: serialized, bytes, visitedNodes: metrics.visitedNodes };
744
817
  }
745
- const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
746
- return {
747
- value: bounded,
748
- bytes: Buffer2.byteLength(JSON.stringify(bounded), "utf8"),
749
- visitedNodes: metrics.visitedNodes
750
- };
818
+ return boundedOversize(bytes, metrics.visitedNodes);
751
819
  } catch {
752
820
  const failed = typeMarker("unserializable");
753
821
  return {
@@ -950,6 +1018,7 @@ var noOpExecution = {
950
1018
  getErrorState: () => void 0,
951
1019
  runFunction: (_functionId, _args, callback) => callback(),
952
1020
  runFunctionPlans: (_plans, _planIndex, _args, callback) => callback(),
1021
+ prepareFunctionPlans: () => [],
953
1022
  runPreparedFunction: (_plan, _args, callback) => callback(),
954
1023
  trace: (_functionId, fn) => fn,
955
1024
  getStats: () => ({ ...emptyStats })
@@ -1043,16 +1112,20 @@ var createExecutionRecorder = (options) => {
1043
1112
  preparedModules.set(plans, prepared);
1044
1113
  return prepared;
1045
1114
  };
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
+ });
1046
1124
  const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
1047
1125
  const recorderStartedAtNs = process.hrtime.bigint();
1048
- for (const byParent of recording.repeatedCalls.values()) {
1049
- for (const group of byParent.values()) {
1050
- if (group.summary) {
1051
- group.summary.totalDurationMs = roundedMilliseconds(group.totalDurationNs);
1052
- }
1053
- }
1054
- }
1055
- const events = recording.events.values().map((event) => event.type === "function_calls_suppressed" ? { ...event } : event);
1126
+ const events = recording.events.values().map(
1127
+ (item) => isSuppressionPlaceholder(item) ? snapshotSuppressed(item.group, recording.startedAtNs) : item
1128
+ );
1056
1129
  const referencedFunctionIds = new Set(
1057
1130
  events.flatMap(
1058
1131
  (event) => event.type === "function_enter" || event.type === "function_calls_suppressed" ? [event.functionId] : []
@@ -1101,21 +1174,28 @@ var createExecutionRecorder = (options) => {
1101
1174
  const countDroppedEvents = (recording, droppedBefore) => {
1102
1175
  stats.truncatedEvents += recording.events.dropped - droppedBefore;
1103
1176
  };
1104
- const appendStandaloneEvent = (recording, event) => {
1177
+ const appendSuppressedPlaceholder = (recording, group) => {
1105
1178
  if (!memoryBudget.reserveStandaloneEvent(recording.memory)) return;
1106
1179
  const droppedBefore = recording.events.dropped;
1107
- recording.events.append(event);
1180
+ recording.events.appendSuppressed(group);
1108
1181
  countDroppedEvents(recording, droppedBefore);
1109
1182
  };
1110
1183
  const repeatedCallGroup = (recording, runtimePlanId, parentCallId) => {
1111
- let byParent = recording.repeatedCalls.get(runtimePlanId);
1112
- if (!byParent) {
1113
- byParent = /* @__PURE__ */ new Map();
1114
- recording.repeatedCalls.set(runtimePlanId, byParent);
1184
+ const slots = recording.repeatedCalls;
1185
+ let slot = slots[runtimePlanId];
1186
+ if (!slot) {
1187
+ slot = {};
1188
+ slots[runtimePlanId] = slot;
1115
1189
  }
1190
+ if (parentCallId === void 0) {
1191
+ if (!slot.root) slot.root = { observedCalls: 0 };
1192
+ return slot.root;
1193
+ }
1194
+ if (!slot.byParent) slot.byParent = /* @__PURE__ */ new Map();
1195
+ const byParent = slot.byParent;
1116
1196
  let group = byParent.get(parentCallId);
1117
1197
  if (!group) {
1118
- group = { observedCalls: 0, totalDurationNs: 0n };
1198
+ group = { observedCalls: 0 };
1119
1199
  byParent.set(parentCallId, group);
1120
1200
  }
1121
1201
  return group;
@@ -1139,7 +1219,7 @@ var createExecutionRecorder = (options) => {
1139
1219
  }
1140
1220
  };
1141
1221
  };
1142
- const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, startedAtMs, error) => {
1222
+ const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
1143
1223
  if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
1144
1224
  rememberError(error, recording);
1145
1225
  return;
@@ -1150,7 +1230,7 @@ var createExecutionRecorder = (options) => {
1150
1230
  type: "function_enter",
1151
1231
  callId,
1152
1232
  functionId: plan.functionId,
1153
- timestampMs: startedAtMs,
1233
+ timestampMs: elapsedMs(recording.startedAtNs, startedAtNs),
1154
1234
  args: Array.from(args, (argument) => captureValue(recording, argument)),
1155
1235
  ...parentCallId === void 0 ? {} : { parentCallId }
1156
1236
  };
@@ -1170,27 +1250,27 @@ var createExecutionRecorder = (options) => {
1170
1250
  countDroppedEvents(recording, droppedBefore);
1171
1251
  rememberError(error, recording);
1172
1252
  };
1173
- const recordSuppressedCall = (recording, group, functionId, parentCallId, startedAtMs, startedAtNs, endedAtNs) => {
1253
+ const recordSuppressedCall = (recording, group, functionId, parentCallId, startedAtNs, endedAtNs) => {
1174
1254
  stats.repeatedCallsSuppressed++;
1175
- group.totalDurationNs += endedAtNs - startedAtNs;
1176
- const endedAtMs = elapsedMs(recording.startedAtNs, endedAtNs);
1177
- if (!group.summary) {
1178
- group.summary = {
1179
- type: "function_calls_suppressed",
1255
+ const durationNs = endedAtNs - startedAtNs;
1256
+ if (!group.suppressed) {
1257
+ group.suppressed = {
1258
+ count: 1,
1259
+ firstTimestampNs: startedAtNs,
1260
+ lastTimestampNs: endedAtNs,
1261
+ totalDurationNs: durationNs,
1180
1262
  functionId,
1181
- timestampMs: startedAtMs,
1182
- lastTimestampMs: endedAtMs,
1183
- suppressedCallCount: 1,
1184
- totalDurationMs: 0,
1185
1263
  ...parentCallId === void 0 ? {} : { parentCallId }
1186
1264
  };
1187
- appendStandaloneEvent(recording, group.summary);
1265
+ appendSuppressedPlaceholder(recording, group.suppressed);
1188
1266
  return;
1189
1267
  }
1190
- group.summary.lastTimestampMs = endedAtMs;
1191
- group.summary.suppressedCallCount++;
1192
- if (!recording.events.hasSummary(group.summary)) {
1193
- appendStandaloneEvent(recording, group.summary);
1268
+ const suppressed = group.suppressed;
1269
+ suppressed.count++;
1270
+ suppressed.lastTimestampNs = endedAtNs;
1271
+ suppressed.totalDurationNs += durationNs;
1272
+ if (!suppressed.retainedSlot) {
1273
+ appendSuppressedPlaceholder(recording, suppressed);
1194
1274
  }
1195
1275
  };
1196
1276
  const finish = (store, metadata) => {
@@ -1220,7 +1300,7 @@ var createExecutionRecorder = (options) => {
1220
1300
  },
1221
1301
  events: new CallAwareEventBuffer(maxEventsPerExecution),
1222
1302
  functions: /* @__PURE__ */ new Map(),
1223
- repeatedCalls: /* @__PURE__ */ new Map(),
1303
+ repeatedCalls: [],
1224
1304
  capturedErrors: /* @__PURE__ */ new WeakMap(),
1225
1305
  nextCallId: 0,
1226
1306
  finished: false,
@@ -1308,7 +1388,6 @@ var createExecutionRecorder = (options) => {
1308
1388
  }
1309
1389
  if (group.observedCalls > maxCapturedCallsPerFunction) {
1310
1390
  const startedAtNs2 = process.hrtime.bigint();
1311
- const startedAtMs = elapsedMs(store.recording.startedAtNs, startedAtNs2);
1312
1391
  try {
1313
1392
  const result = callback();
1314
1393
  if (isPromiseLike(result)) {
@@ -1321,7 +1400,6 @@ var createExecutionRecorder = (options) => {
1321
1400
  group,
1322
1401
  plan.functionId,
1323
1402
  parentCallId,
1324
- startedAtMs,
1325
1403
  startedAtNs2,
1326
1404
  callbackEndedAtNs2
1327
1405
  );
@@ -1330,15 +1408,7 @@ var createExecutionRecorder = (options) => {
1330
1408
  },
1331
1409
  (error) => {
1332
1410
  const callbackEndedAtNs2 = process.hrtime.bigint();
1333
- captureCompletedThrow(
1334
- store.recording,
1335
- plan,
1336
- args,
1337
- parentCallId,
1338
- startedAtNs2,
1339
- startedAtMs,
1340
- error
1341
- );
1411
+ captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs2, error);
1342
1412
  addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs2);
1343
1413
  throw error;
1344
1414
  }
@@ -1350,7 +1420,6 @@ var createExecutionRecorder = (options) => {
1350
1420
  group,
1351
1421
  plan.functionId,
1352
1422
  parentCallId,
1353
- startedAtMs,
1354
1423
  startedAtNs2,
1355
1424
  callbackEndedAtNs
1356
1425
  );
@@ -1359,15 +1428,7 @@ var createExecutionRecorder = (options) => {
1359
1428
  return result;
1360
1429
  } catch (error) {
1361
1430
  const callbackEndedAtNs = process.hrtime.bigint();
1362
- captureCompletedThrow(
1363
- store.recording,
1364
- plan,
1365
- args,
1366
- parentCallId,
1367
- startedAtNs2,
1368
- startedAtMs,
1369
- error
1370
- );
1431
+ captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs2, error);
1371
1432
  addRecorderTime(store.recording, startedAtNs2 - recorderStartedAtNs);
1372
1433
  addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs);
1373
1434
  throw error;
@@ -1375,7 +1436,6 @@ var createExecutionRecorder = (options) => {
1375
1436
  }
1376
1437
  const startedAtNs = process.hrtime.bigint();
1377
1438
  if (!store.recording.events.canStartCall()) {
1378
- const startedAtMs = elapsedMs(store.recording.startedAtNs, startedAtNs);
1379
1439
  const captureSuccess = () => {
1380
1440
  const droppedBefore = store.recording.events.dropped;
1381
1441
  store.recording.events.dropCall();
@@ -1388,15 +1448,7 @@ var createExecutionRecorder = (options) => {
1388
1448
  recorderStartedAtNs,
1389
1449
  callback,
1390
1450
  captureSuccess,
1391
- (error) => captureCompletedThrow(
1392
- store.recording,
1393
- plan,
1394
- args,
1395
- parentCallId,
1396
- startedAtNs,
1397
- startedAtMs,
1398
- error
1399
- )
1451
+ (error) => captureCompletedThrow(store.recording, plan, args, parentCallId, startedAtNs, error)
1400
1452
  )
1401
1453
  );
1402
1454
  }
@@ -1458,6 +1510,7 @@ var createExecutionRecorder = (options) => {
1458
1510
  const plan = preparedPlansFor(plans)[planIndex];
1459
1511
  return plan ? runPreparedFunction(plan, args, callback) : callback();
1460
1512
  };
1513
+ const prepareFunctionPlans = (plans) => preparedPlansFor(plans);
1461
1514
  function trace(input, fn) {
1462
1515
  const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
1463
1516
  const plan = preparePlan(definition);
@@ -1471,6 +1524,7 @@ var createExecutionRecorder = (options) => {
1471
1524
  getErrorState,
1472
1525
  runFunction,
1473
1526
  runFunctionPlans,
1527
+ prepareFunctionPlans,
1474
1528
  runPreparedFunction,
1475
1529
  trace,
1476
1530
  getStats: () => ({ ...stats, ...memoryBudget.getStats() })
@@ -1480,25 +1534,31 @@ var createExecutionRecorder = (options) => {
1480
1534
  // src/execution-recorder/automatic-runtime.ts
1481
1535
  var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
1482
1536
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
1537
+ var passthrough = (_planIndex, _args, callback) => callback();
1538
+ var bindPassthrough = (module) => {
1539
+ module.cell.run = passthrough;
1540
+ };
1541
+ var isRegistry = (value) => Array.isArray(Reflect.get(value, "runtimes")) && Array.isArray(Reflect.get(value, "modules")) && typeof Reflect.get(value, "register") === "function";
1542
+ var registerModule = (registry, plans) => {
1543
+ const cell = { run: passthrough };
1544
+ const module = { plans, cell };
1545
+ registry.modules.push(module);
1546
+ registry.runtimes.at(-1)?.bind(module);
1547
+ return (planIndex, args, callback) => cell.run(planIndex, args, callback);
1548
+ };
1483
1549
  var createRegistry = () => {
1484
- const runtimes = [];
1485
- return {
1486
- __rasputinRuntimeRegistry: true,
1487
- runtimes,
1550
+ const registry = {
1551
+ runtimes: [],
1552
+ modules: [],
1488
1553
  register(plans) {
1489
- return (planIndex, args, callback) => {
1490
- const runtime = runtimes.at(-1);
1491
- return runtime ? runtime.run(plans, planIndex, args, callback) : callback();
1492
- };
1554
+ return registerModule(registry, plans);
1493
1555
  }
1494
1556
  };
1557
+ return registry;
1495
1558
  };
1496
1559
  var getAutomaticRuntimeRegistry = () => {
1497
1560
  const existing = Reflect.get(globalThis, runtimeSymbol);
1498
- if (existing && Array.isArray(existing.runtimes) && typeof existing.register === "function") {
1499
- existing.__rasputinRuntimeRegistry = true;
1500
- return existing;
1501
- }
1561
+ if (existing && typeof existing === "object" && isRegistry(existing)) return existing;
1502
1562
  const registry = createRegistry();
1503
1563
  Reflect.set(globalThis, runtimeSymbol, registry);
1504
1564
  return registry;
@@ -1506,12 +1566,24 @@ var getAutomaticRuntimeRegistry = () => {
1506
1566
  var installAutomaticExecutionRuntime = (execution) => {
1507
1567
  const registry = getAutomaticRuntimeRegistry();
1508
1568
  const runtime = {
1509
- run: (plans, planIndex, args, callback) => execution.runFunctionPlans(plans, planIndex, args, callback)
1569
+ bind(module) {
1570
+ const prepared = execution.prepareFunctionPlans(module.plans);
1571
+ module.cell.run = (planIndex, args, callback) => {
1572
+ const plan = prepared[planIndex];
1573
+ return plan ? execution.runPreparedFunction(plan, args, callback) : callback();
1574
+ };
1575
+ }
1510
1576
  };
1511
1577
  registry.runtimes.push(runtime);
1578
+ for (const module of registry.modules) runtime.bind(module);
1512
1579
  return () => {
1513
1580
  const index = registry.runtimes.lastIndexOf(runtime);
1514
1581
  if (index >= 0) registry.runtimes.splice(index, 1);
1582
+ const current = registry.runtimes.at(-1);
1583
+ for (const module of registry.modules) {
1584
+ if (current) current.bind(module);
1585
+ else bindPassthrough(module);
1586
+ }
1515
1587
  };
1516
1588
  };
1517
1589
 
@@ -1572,7 +1644,7 @@ import {
1572
1644
 
1573
1645
  // src/sdk-meta.ts
1574
1646
  var SDK_NAME = "@rasputin-ai/node";
1575
- var SDK_VERSION = "0.5.0-alpha.1";
1647
+ var SDK_VERSION = "0.5.0-alpha.3";
1576
1648
 
1577
1649
  // src/rasputin-init.ts
1578
1650
  var withExecution = (client, execution, installRuntime, manifest) => {
@@ -496,7 +496,22 @@ var uniqueName = (source, base) => {
496
496
  while (source.includes(name)) name += "_";
497
497
  return name;
498
498
  };
499
- var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],register(p){return(i,a,c)=>{const n=this.runtimes.at(-1);return n?n.run(p,i,a,c):c()}}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
499
+ var isDirectivePrologue = (statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression);
500
+ var insertPositionAfterPrologue = (source, sourceFile) => {
501
+ const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
502
+ let end = shebangEnd;
503
+ for (const statement of sourceFile.statements) {
504
+ if (!isDirectivePrologue(statement)) break;
505
+ end = statement.end;
506
+ }
507
+ return end;
508
+ };
509
+ var preambleInsert = (source, position, preamble) => {
510
+ if (position <= 0) return preamble;
511
+ const previous = source[position - 1];
512
+ return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
513
+ };
514
+ var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c)=>d.run(i,a,c)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
500
515
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
501
516
  const start = mappedLocation(
502
517
  sourceFile,
@@ -594,10 +609,14 @@ var transformSource = (source, options) => {
594
609
  };
595
610
  visit(sourceFile);
596
611
  if (edits.length === 0) return void 0;
597
- const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
612
+ const insertAt = insertPositionAfterPrologue(source, sourceFile);
598
613
  edits.push({
599
- position: shebangEnd,
600
- text: modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan))),
614
+ position: insertAt,
615
+ text: preambleInsert(
616
+ source,
617
+ insertAt,
618
+ modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan)))
619
+ ),
601
620
  order: -1
602
621
  });
603
622
  edits.sort((left, right) => right.position - left.position || right.order - left.order);
@@ -333,7 +333,22 @@ var uniqueName = (source, base) => {
333
333
  while (source.includes(name)) name += "_";
334
334
  return name;
335
335
  };
336
- var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],register(p){return(i,a,c)=>{const n=this.runtimes.at(-1);return n?n.run(p,i,a,c):c()}}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
336
+ var isDirectivePrologue = (statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression);
337
+ var insertPositionAfterPrologue = (source, sourceFile) => {
338
+ const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
339
+ let end = shebangEnd;
340
+ for (const statement of sourceFile.statements) {
341
+ if (!isDirectivePrologue(statement)) break;
342
+ end = statement.end;
343
+ }
344
+ return end;
345
+ };
346
+ var preambleInsert = (source, position, preamble) => {
347
+ if (position <= 0) return preamble;
348
+ const previous = source[position - 1];
349
+ return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
350
+ };
351
+ var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c)=>d.run(i,a,c)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
337
352
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
338
353
  const start = mappedLocation(
339
354
  sourceFile,
@@ -431,10 +446,14 @@ var transformSource = (source, options) => {
431
446
  };
432
447
  visit(sourceFile);
433
448
  if (edits.length === 0) return void 0;
434
- const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
449
+ const insertAt = insertPositionAfterPrologue(source, sourceFile);
435
450
  edits.push({
436
- position: shebangEnd,
437
- text: modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan))),
451
+ position: insertAt,
452
+ text: preambleInsert(
453
+ source,
454
+ insertAt,
455
+ modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan)))
456
+ ),
438
457
  order: -1
439
458
  });
440
459
  edits.sort((left, right) => right.position - left.position || right.order - left.order);
@@ -501,7 +520,21 @@ import { dirname, resolve as resolve5 } from "node:path";
501
520
  import { fileURLToPath } from "node:url";
502
521
  var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve5(dirname(fileURLToPath(instrumentEntryUrl)), "../../..");
503
522
 
523
+ // src/auto-instrumentation/warn-production-runtime-transform.ts
524
+ var RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV = "RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING";
525
+ var warnedSymbol = Symbol.for("rasputin.runtimeTransformWarning");
526
+ var warnIfProductionRuntimeTransform = () => {
527
+ if (process.env.NODE_ENV !== "production") return;
528
+ if (process.env[RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV] === "1") return;
529
+ if (Reflect.get(globalThis, warnedSymbol)) return;
530
+ Reflect.set(globalThis, warnedSymbol, true);
531
+ console.warn(
532
+ "[rasputin] Production is using load-time source transformation (`--import` / `--preload`). Prefer build-time `rasputin-instrument` so the process does not load the TypeScript compiler. Set RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING=1 to hide this warning."
533
+ );
534
+ };
535
+
504
536
  // src/instrument/bun.ts
537
+ warnIfProductionRuntimeTransform();
505
538
  plugin(
506
539
  createRasputinBunPlugin({
507
540
  excludedRoots: [sdkPackageScopeRootFrom(import.meta.url)]
@@ -388,7 +388,22 @@ var uniqueName = (source, base) => {
388
388
  while (source.includes(name)) name += "_";
389
389
  return name;
390
390
  };
391
- var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],register(p){return(i,a,c)=>{const n=this.runtimes.at(-1);return n?n.run(p,i,a,c):c()}}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
391
+ var isDirectivePrologue = (statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression);
392
+ var insertPositionAfterPrologue = (source, sourceFile) => {
393
+ const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
394
+ let end = shebangEnd;
395
+ for (const statement of sourceFile.statements) {
396
+ if (!isDirectivePrologue(statement)) break;
397
+ end = statement.end;
398
+ }
399
+ return end;
400
+ };
401
+ var preambleInsert = (source, position, preamble) => {
402
+ if (position <= 0) return preamble;
403
+ const previous = source[position - 1];
404
+ return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
405
+ };
406
+ var modulePreamble = (runName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c)=>d.run(i,a,c)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
392
407
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
393
408
  const start = mappedLocation(
394
409
  sourceFile,
@@ -486,10 +501,14 @@ var transformSource = (source, options) => {
486
501
  };
487
502
  visit(sourceFile);
488
503
  if (edits.length === 0) return void 0;
489
- const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
504
+ const insertAt = insertPositionAfterPrologue(source, sourceFile);
490
505
  edits.push({
491
- position: shebangEnd,
492
- text: modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan))),
506
+ position: insertAt,
507
+ text: preambleInsert(
508
+ source,
509
+ insertAt,
510
+ modulePreamble(runName, plansName, JSON.stringify(delta.functions.map((fn) => fn.plan)))
511
+ ),
493
512
  order: -1
494
513
  });
495
514
  edits.sort((left, right) => right.position - left.position || right.order - left.order);
@@ -558,7 +577,21 @@ import { dirname as dirname2, resolve as resolve5 } from "node:path";
558
577
  import { fileURLToPath as fileURLToPath3 } from "node:url";
559
578
  var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve5(dirname2(fileURLToPath3(instrumentEntryUrl)), "../../..");
560
579
 
580
+ // src/auto-instrumentation/warn-production-runtime-transform.ts
581
+ var RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV = "RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING";
582
+ var warnedSymbol = Symbol.for("rasputin.runtimeTransformWarning");
583
+ var warnIfProductionRuntimeTransform = () => {
584
+ if (process.env.NODE_ENV !== "production") return;
585
+ if (process.env[RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV] === "1") return;
586
+ if (Reflect.get(globalThis, warnedSymbol)) return;
587
+ Reflect.set(globalThis, warnedSymbol, true);
588
+ console.warn(
589
+ "[rasputin] Production is using load-time source transformation (`--import` / `--preload`). Prefer build-time `rasputin-instrument` so the process does not load the TypeScript compiler. Set RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING=1 to hide this warning."
590
+ );
591
+ };
592
+
561
593
  // src/instrument/node.ts
594
+ warnIfProductionRuntimeTransform();
562
595
  registerRasputinNodeHooks({
563
596
  excludedRoots: [sdkPackageScopeRootFrom(import.meta.url)]
564
597
  });
@@ -1,4 +1,4 @@
1
1
  /** Generated by scripts/generate-sdk-meta.ts — do not edit. */
2
2
  export declare const SDK_NAME = "@rasputin-ai/node";
3
- export declare const SDK_VERSION = "0.5.0-alpha.1";
3
+ export declare const SDK_VERSION = "0.5.0-alpha.3";
4
4
  //# sourceMappingURL=sdk-meta.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rasputin-ai/node",
3
- "version": "0.5.0-alpha.1",
3
+ "version": "0.5.0-alpha.3",
4
4
  "description": "Official Rasputin AI SDK for Node and Bun.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@jridgewell/trace-mapping": "0.3.31",
47
- "@rasputin-ai/core": "0.5.0-alpha.1",
47
+ "@rasputin-ai/core": "0.5.0-alpha.3",
48
48
  "typescript": "5"
49
49
  },
50
50
  "devDependencies": {