@rasputin-ai/node 0.5.0-alpha.9 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +219 -188
  2. package/dist/auto-instrumentation/bun-plugin.d.ts.map +1 -1
  3. package/dist/auto-instrumentation/format-configuration-report.d.ts +4 -0
  4. package/dist/auto-instrumentation/format-configuration-report.d.ts.map +1 -1
  5. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts +1 -3
  6. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts.map +1 -1
  7. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts +10 -2
  8. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts.map +1 -1
  9. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +6 -0
  10. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
  11. package/dist/auto-instrumentation/node-hooks.d.ts.map +1 -1
  12. package/dist/auto-instrumentation/parameter-initializer-may-run-code.d.ts +3 -0
  13. package/dist/auto-instrumentation/parameter-initializer-may-run-code.d.ts.map +1 -0
  14. package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts +1 -1
  15. package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts.map +1 -1
  16. package/dist/auto-instrumentation/source-map-locations.d.ts +1 -0
  17. package/dist/auto-instrumentation/source-map-locations.d.ts.map +1 -1
  18. package/dist/auto-instrumentation/suspension-whitelist.d.ts +33 -0
  19. package/dist/auto-instrumentation/suspension-whitelist.d.ts.map +1 -0
  20. package/dist/auto-instrumentation/transform-disk-cache.d.ts +7 -0
  21. package/dist/auto-instrumentation/transform-disk-cache.d.ts.map +1 -0
  22. package/dist/auto-instrumentation/transform-source.d.ts +9 -6
  23. package/dist/auto-instrumentation/transform-source.d.ts.map +1 -1
  24. package/dist/auto-instrumentation/verify-instrumentation-isomorphism.d.ts +2 -0
  25. package/dist/auto-instrumentation/verify-instrumentation-isomorphism.d.ts.map +1 -0
  26. package/dist/auto-instrumentation/verify-transformed-source.d.ts +2 -0
  27. package/dist/auto-instrumentation/verify-transformed-source.d.ts.map +1 -0
  28. package/dist/execution-recorder/automatic-runtime.d.ts +17 -7
  29. package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
  30. package/dist/execution-recorder/encode-frozen.d.ts +16 -0
  31. package/dist/execution-recorder/encode-frozen.d.ts.map +1 -0
  32. package/dist/execution-recorder/execution-journal.d.ts.map +1 -1
  33. package/dist/execution-recorder/execution-recorder-types.d.ts +124 -36
  34. package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
  35. package/dist/execution-recorder/execution-recorder.d.ts +2 -2
  36. package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
  37. package/dist/execution-recorder/function-plan.d.ts +8 -1
  38. package/dist/execution-recorder/function-plan.d.ts.map +1 -1
  39. package/dist/execution-recorder/index.d.ts +1 -1
  40. package/dist/execution-recorder/index.d.ts.map +1 -1
  41. package/dist/execution-recorder/recorder-memory-budget.d.ts +1 -0
  42. package/dist/execution-recorder/recorder-memory-budget.d.ts.map +1 -1
  43. package/dist/execution-recorder/redact-keys.d.ts +4 -0
  44. package/dist/execution-recorder/redact-keys.d.ts.map +1 -0
  45. package/dist/execution-recorder/run-exactly-once.d.ts +7 -0
  46. package/dist/execution-recorder/run-exactly-once.d.ts.map +1 -0
  47. package/dist/execution-recorder/runtime-state-size-budget.d.ts +14 -0
  48. package/dist/execution-recorder/runtime-state-size-budget.d.ts.map +1 -0
  49. package/dist/execution-recorder/safe-serialize.d.ts +9 -3
  50. package/dist/execution-recorder/safe-serialize.d.ts.map +1 -1
  51. package/dist/execution-recorder/value-freeze.d.ts +43 -0
  52. package/dist/execution-recorder/value-freeze.d.ts.map +1 -0
  53. package/dist/execution-recorder/warn-missing-async-context-frame.d.ts +10 -0
  54. package/dist/execution-recorder/warn-missing-async-context-frame.d.ts.map +1 -0
  55. package/dist/index.d.ts +1 -6
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +2612 -893
  58. package/dist/install-global-handlers.d.ts +29 -8
  59. package/dist/install-global-handlers.d.ts.map +1 -1
  60. package/dist/instrument/build.js +947 -805
  61. package/dist/instrument/bun.js +1098 -778
  62. package/dist/instrument/node.js +1078 -780
  63. package/dist/internal.d.ts +7 -0
  64. package/dist/internal.d.ts.map +1 -0
  65. package/dist/internal.js +4072 -0
  66. package/dist/rasputin-init.d.ts +25 -5
  67. package/dist/rasputin-init.d.ts.map +1 -1
  68. package/dist/sdk-meta.d.ts +1 -1
  69. package/dist/sdk-meta.d.ts.map +1 -1
  70. package/package.json +8 -3
  71. package/dist/derivation/analyze-function.d.ts +0 -42
  72. package/dist/derivation/analyze-function.d.ts.map +0 -1
  73. package/dist/derivation/build-dependency-graph.d.ts +0 -21
  74. package/dist/derivation/build-dependency-graph.d.ts.map +0 -1
  75. package/dist/derivation/derivation-ir.d.ts +0 -33
  76. package/dist/derivation/derivation-ir.d.ts.map +0 -1
  77. package/dist/derivation/derivation-proof.d.ts +0 -14
  78. package/dist/derivation/derivation-proof.d.ts.map +0 -1
  79. package/dist/derivation/emit-capture-plan.d.ts +0 -8
  80. package/dist/derivation/emit-capture-plan.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,107 +1,10 @@
1
- // src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts
1
+ // src/rasputin-init.ts
2
+ import { join } from "node:path";
2
3
  import {
3
- detectRelease,
4
- resolveEndpointUrls,
5
- uploadInstrumentationManifest
4
+ createClient,
5
+ isClientEnabled
6
6
  } from "@rasputin-ai/core";
7
7
 
8
- // src/auto-instrumentation/format-configuration-report.ts
9
- var RULE = "-".repeat(64);
10
- var BANNER = [
11
- RULE,
12
- " ____ _ ____ ____ _ _ _____ ___ _ _",
13
- "| _ \\ / \\ / ___| | _ \\ | | | | |_ _| |_ _| | \\ | |",
14
- "| |_) | / _ \\ \\___ \\ | |_) | | | | | | | | | | \\| |",
15
- "| _ < / ___ \\ ___) | | __/ | |_| | | | | | | |\\ |",
16
- "|_| \\_\\ /_/ \\_\\ |____/ |_| \\___/ |_| |___| |_| \\_|",
17
- "",
18
- "",
19
- "CONFIGURATION:"
20
- ];
21
- var counted = (n, singular, plural) => `${n} ${n === 1 ? singular : plural}`;
22
- var issueHeadline = (issue) => {
23
- const target = issue.packageName ? `package ${issue.packageName}` : issue.packageRelativePath;
24
- if (issue.reason === "ambiguous") return `Could not uniquely locate ${target}.`;
25
- if (issue.reason === "not_found") return `Could not find ${target} in this Git release.`;
26
- if (issue.reason === "invalid_mapping") {
27
- return `The configured package root for ${target} does not match this Git release.`;
28
- }
29
- return `GitHub could not be reached while locating ${target}.`;
30
- };
31
- var formatIssue = (issue) => {
32
- const lines = [
33
- `! ${issueHeadline(issue)}`,
34
- "",
35
- " Captured:",
36
- ` ${issue.packageRelativePath}`
37
- ];
38
- if (issue.candidates?.length) {
39
- lines.push("", " Possible repository locations:");
40
- for (const candidate of issue.candidates) lines.push(` ${candidate}`);
41
- }
42
- return lines;
43
- };
44
- var formatConfigurationReport = (input) => {
45
- const packages = input.verification.packages ?? [];
46
- const unresolved = input.verification.unresolved;
47
- const mappingIssues = unresolved.filter((issue) => issue.reason !== "github_unavailable");
48
- const githubUnavailable = input.verification.status === "unavailable" || unresolved.some((issue) => issue.reason === "github_unavailable");
49
- const verified = input.uploaded && input.verification.status === "verified";
50
- const lines = [
51
- ...BANNER,
52
- "",
53
- "Release",
54
- `\u2713 ${input.release}`,
55
- "",
56
- "Runtime",
57
- `\u2713 ${input.runtime}`,
58
- "",
59
- "Instrumentation",
60
- `\u2713 ${counted(input.modules, "application module", "application modules")} observed`,
61
- `\u2713 ${counted(input.functions, "function", "functions")} instrumented`,
62
- `\u2713 ${counted(input.packageNames.length, "workspace package", "workspace packages")} detected`
63
- ];
64
- if (packages.length > 0 || mappingIssues.length > 0) {
65
- lines.push("", "Package roots");
66
- for (const mapping of packages) {
67
- lines.push(
68
- mapping.packageName ? `\u2713 ${mapping.packageName} \u2192 ${mapping.repositoryRoot}` : `\u2713 ${mapping.repositoryRoot}`
69
- );
70
- }
71
- for (const [index, issue] of mappingIssues.entries()) {
72
- if (packages.length > 0 || index > 0) lines.push("");
73
- lines.push(...formatIssue(issue));
74
- }
75
- }
76
- lines.push("", "Manifest");
77
- if (!input.uploaded) {
78
- lines.push("! upload failed");
79
- } else {
80
- lines.push("\u2713 uploaded");
81
- lines.push(
82
- verified ? "\u2713 verified against GitHub" : "! some source files could not be mapped to this Git release"
83
- );
84
- }
85
- lines.push("", "GitHub");
86
- if (!input.uploaded) {
87
- lines.push("! not verified");
88
- } else if (githubUnavailable) {
89
- lines.push("! repository is not connected, or this release could not be read");
90
- } else {
91
- lines.push("\u2713 repository connected");
92
- }
93
- if (input.uploaded && input.verification.status !== "verified") {
94
- lines.push("", "Runtime recording is unaffected.");
95
- }
96
- lines.push(RULE);
97
- return lines.join("\n");
98
- };
99
- var runtimeLabel = () => {
100
- const bun = globalThis.Bun;
101
- if (typeof bun?.version === "string" && bun.version) return `Bun ${bun.version}`;
102
- return `Node ${process.versions.node}`;
103
- };
104
-
105
8
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
106
9
  import { createHash } from "node:crypto";
107
10
  import { existsSync, readFileSync } from "node:fs";
@@ -115,6 +18,8 @@ import {
115
18
  runtimeFunctionId,
116
19
  sourceLocatorFromFile
117
20
  } from "@rasputin-ai/core";
21
+ var encodedPlanOmitsCallValues = (plan) => plan[6] === 1;
22
+ var encodedPlanHasPreBodyParameterEvaluation = (plan) => plan[7] === 1;
118
23
  var EVENT_PAIR_BASE_ESTIMATED_BYTES = 512;
119
24
  var definitionFromEncodedPlan = (plan) => {
120
25
  const [functionId, name, packageName, packageRelativePath, line, column] = plan;
@@ -127,7 +32,8 @@ var definitionFromEncodedPlan = (plan) => {
127
32
  return {
128
33
  functionId,
129
34
  name,
130
- ...source ? { source } : {}
35
+ ...source ? { source } : {},
36
+ ...encodedPlanHasPreBodyParameterEvaluation(plan) ? { parentAttribution: "pre_body_parameter_evaluation" } : {}
131
37
  };
132
38
  };
133
39
  var estimatedCallBytesFor = (functionId) => EVENT_PAIR_BASE_ESTIMATED_BYTES + Buffer.byteLength(functionId, "utf8") * 2;
@@ -138,13 +44,16 @@ var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
138
44
  var getRegistry = () => {
139
45
  const existing = Reflect.get(globalThis, registrySymbol);
140
46
  if (existing?.__rasputinManifestRegistry && existing.files instanceof Map && typeof existing.generation === "number" && typeof existing.uploadedGeneration === "number") {
141
- return existing;
47
+ const registry2 = existing;
48
+ if (typeof registry2.alreadyInstrumented !== "number") registry2.alreadyInstrumented = 0;
49
+ return registry2;
142
50
  }
143
51
  const registry = {
144
52
  __rasputinManifestRegistry: true,
145
53
  files: /* @__PURE__ */ new Map(),
146
54
  generation: 0,
147
- uploadedGeneration: 0
55
+ uploadedGeneration: 0,
56
+ alreadyInstrumented: 0
148
57
  };
149
58
  Reflect.set(globalThis, registrySymbol, registry);
150
59
  return registry;
@@ -180,18 +89,60 @@ var isInstrumentationManifestDirty = () => {
180
89
  return registry.generation !== registry.uploadedGeneration && (registry.files.size > 0 || registry.prebuilt !== void 0);
181
90
  };
182
91
  var instrumentationManifestGeneration = () => getRegistry().generation;
92
+ var instrumentationCoverageStats = () => {
93
+ const registry = getRegistry();
94
+ let instrumented = 0;
95
+ let instrumentedAsync = 0;
96
+ const skippedByReason = {};
97
+ for (const delta of registry.files.values()) {
98
+ for (const fn of delta.functions) {
99
+ if (fn.instrumented === false) {
100
+ if (!fn.skipReason) continue;
101
+ skippedByReason[fn.skipReason] = (skippedByReason[fn.skipReason] ?? 0) + 1;
102
+ } else {
103
+ instrumented += 1;
104
+ if (fn.asyncFunction) instrumentedAsync += 1;
105
+ }
106
+ }
107
+ }
108
+ if (registry.alreadyInstrumented > 0) {
109
+ skippedByReason.already_instrumented = registry.alreadyInstrumented;
110
+ }
111
+ return {
112
+ instrumented,
113
+ instrumentedAsync,
114
+ alreadyInstrumented: registry.alreadyInstrumented,
115
+ skippedByReason
116
+ };
117
+ };
183
118
  var instrumentationManifestModuleCount = () => {
184
119
  const registry = getRegistry();
185
120
  if (registry.files.size > 0) return registry.files.size;
186
121
  if (!registry.prebuilt) return 0;
187
122
  return new Set(registry.prebuilt.functions.map((fn) => fn.source.packageRelativePath)).size;
188
123
  };
124
+ var snapshotOptionsKey = (options) => JSON.stringify({
125
+ sourceRoot: options.sourceRoot ?? "",
126
+ sourceRoots: options.sourceRoots ?? {}
127
+ });
189
128
  var snapshotInstrumentationManifest = (options = {}) => {
129
+ const registry = getRegistry();
130
+ const optionsKey = snapshotOptionsKey(options);
131
+ if (registry.snapshotCache && registry.snapshotCache.generation === registry.generation && registry.snapshotCache.optionsKey === optionsKey) {
132
+ return registry.snapshotCache.manifest;
133
+ }
190
134
  const functions = [];
191
135
  const callSites = [];
192
136
  const destructures = [];
193
- const derivationPlans = [];
194
- for (const delta of getRegistry().files.values()) {
137
+ const remember = (manifest) => {
138
+ registry.snapshotCache = {
139
+ generation: registry.generation,
140
+ optionsKey,
141
+ manifest
142
+ };
143
+ return manifest;
144
+ };
145
+ for (const delta of registry.files.values()) {
195
146
  for (const fn of delta.functions) {
196
147
  const definition = definitionFromEncodedPlan(fn.plan);
197
148
  if (!definition.source) continue;
@@ -203,7 +154,8 @@ var snapshotInstrumentationManifest = (options = {}) => {
203
154
  startColumn: fn.startColumn,
204
155
  endLine: fn.endLine,
205
156
  endColumn: fn.endColumn,
206
- params: fn.params
157
+ params: fn.params,
158
+ ...fn.instrumented === false ? { instrumented: false, skipReason: fn.skipReason } : {}
207
159
  });
208
160
  }
209
161
  for (const site of delta.callSites) {
@@ -242,25 +194,23 @@ var snapshotInstrumentationManifest = (options = {}) => {
242
194
  binding: destructure.binding
243
195
  });
244
196
  }
245
- derivationPlans.push(...delta.derivationPlans ?? []);
246
197
  }
247
- const registry = getRegistry();
248
198
  if (registry.prebuilt && registry.files.size === 0) {
249
199
  const prebuilt = registry.prebuilt;
250
- if (!options.sourceRoot && !options.sourceRoots) return prebuilt;
251
- return {
200
+ if (!options.sourceRoot && !options.sourceRoots) return remember(prebuilt);
201
+ return remember({
252
202
  ...prebuilt,
253
203
  sourceRoots: {
254
204
  ...options.sourceRoot ? { default: options.sourceRoot } : {},
255
205
  packages: { ...options.sourceRoots ?? {} }
256
206
  }
257
- };
207
+ });
258
208
  }
259
209
  if (functions.length === 0 && callSites.length === 0 && destructures.length === 0) {
260
- return void 0;
210
+ return remember(void 0);
261
211
  }
262
212
  const packages = { ...options.sourceRoots ?? {} };
263
- return {
213
+ return remember({
264
214
  schema_version: INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
265
215
  ...options.sourceRoot || Object.keys(packages).length > 0 ? {
266
216
  sourceRoots: {
@@ -270,9 +220,8 @@ var snapshotInstrumentationManifest = (options = {}) => {
270
220
  } : {},
271
221
  functions,
272
222
  callSites,
273
- destructures,
274
- derivationPlans
275
- };
223
+ destructures
224
+ });
276
225
  };
277
226
  var markInstrumentationManifestUploaded = (generation) => {
278
227
  const registry = getRegistry();
@@ -282,6 +231,116 @@ var setInstrumentationManifestOnDirty = (onDirty) => {
282
231
  getRegistry().onDirty = onDirty;
283
232
  };
284
233
 
234
+ // src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts
235
+ import {
236
+ detectRelease,
237
+ resolveEndpointUrls,
238
+ uploadInstrumentationManifest
239
+ } from "@rasputin-ai/core";
240
+
241
+ // src/auto-instrumentation/format-configuration-report.ts
242
+ var RULE = "-".repeat(64);
243
+ var BANNER = [
244
+ RULE,
245
+ " ____ _ ____ ____ _ _ _____ ___ _ _",
246
+ "| _ \\ / \\ / ___| | _ \\ | | | | |_ _| |_ _| | \\ | |",
247
+ "| |_) | / _ \\ \\___ \\ | |_) | | | | | | | | | | \\| |",
248
+ "| _ < / ___ \\ ___) | | __/ | |_| | | | | | | |\\ |",
249
+ "|_| \\_\\ /_/ \\_\\ |____/ |_| \\___/ |_| |___| |_| \\_|",
250
+ "",
251
+ "",
252
+ "CONFIGURATION:"
253
+ ];
254
+ var counted = (n, singular, plural) => `${n} ${n === 1 ? singular : plural}`;
255
+ var issueHeadline = (issue) => {
256
+ const target = issue.packageName ? `package ${issue.packageName}` : issue.packageRelativePath;
257
+ if (issue.reason === "ambiguous") return `Could not uniquely locate ${target}.`;
258
+ if (issue.reason === "not_found") return `Could not find ${target} in this Git release.`;
259
+ if (issue.reason === "invalid_mapping") {
260
+ return `The configured package root for ${target} does not match this Git release.`;
261
+ }
262
+ return `GitHub could not be reached while locating ${target}.`;
263
+ };
264
+ var formatIssue = (issue) => {
265
+ const lines = [
266
+ `! ${issueHeadline(issue)}`,
267
+ "",
268
+ " Captured:",
269
+ ` ${issue.packageRelativePath}`
270
+ ];
271
+ if (issue.candidates?.length) {
272
+ lines.push("", " Possible repository locations:");
273
+ for (const candidate of issue.candidates) lines.push(` ${candidate}`);
274
+ }
275
+ return lines;
276
+ };
277
+ var formatConfigurationReport = (input) => {
278
+ const packages = input.verification.packages ?? [];
279
+ const unresolved = input.verification.unresolved;
280
+ const mappingIssues = unresolved.filter((issue) => issue.reason !== "github_unavailable");
281
+ const githubUnavailable = input.verification.status === "unavailable" || unresolved.some((issue) => issue.reason === "github_unavailable");
282
+ const verified = input.uploaded && input.verification.status === "verified";
283
+ const lines = [
284
+ ...BANNER,
285
+ "",
286
+ "Release",
287
+ `\u2713 ${input.release}`,
288
+ "",
289
+ "Runtime",
290
+ `\u2713 ${input.runtime}`,
291
+ "",
292
+ "Instrumentation",
293
+ `\u2713 ${counted(input.modules, "application module", "application modules")} observed`,
294
+ `\u2713 ${counted(input.functions, "function", "functions")} instrumented`,
295
+ ...input.instrumentedAsync ? [`\u2713 ${counted(input.instrumentedAsync, "async function", "async functions")} instrumented`] : [],
296
+ ...input.skippedFunctions ? [`! ${counted(input.skippedFunctions, "function", "functions")} skipped`] : [],
297
+ ...Object.entries(input.skippedByReason ?? {}).filter(([, count]) => (count ?? 0) > 0).sort(([left], [right]) => left.localeCompare(right)).map(([reason, count]) => ` ${reason}: ${count}`),
298
+ ...input.attributionDegradations ? [
299
+ `! ${counted(input.attributionDegradations, "runtime attribution degradation", "runtime attribution degradations")}`
300
+ ] : [],
301
+ `\u2713 ${counted(input.packageNames.length, "workspace package", "workspace packages")} detected`
302
+ ];
303
+ if (packages.length > 0 || mappingIssues.length > 0) {
304
+ lines.push("", "Package roots");
305
+ for (const mapping of packages) {
306
+ lines.push(
307
+ mapping.packageName ? `\u2713 ${mapping.packageName} \u2192 ${mapping.repositoryRoot}` : `\u2713 ${mapping.repositoryRoot}`
308
+ );
309
+ }
310
+ for (const [index, issue] of mappingIssues.entries()) {
311
+ if (packages.length > 0 || index > 0) lines.push("");
312
+ lines.push(...formatIssue(issue));
313
+ }
314
+ }
315
+ lines.push("", "Manifest");
316
+ if (!input.uploaded) {
317
+ lines.push("! upload failed");
318
+ } else {
319
+ lines.push("\u2713 uploaded");
320
+ lines.push(
321
+ verified ? "\u2713 verified against GitHub" : "! some source files could not be mapped to this Git release"
322
+ );
323
+ }
324
+ lines.push("", "GitHub");
325
+ if (!input.uploaded) {
326
+ lines.push("! not verified");
327
+ } else if (githubUnavailable) {
328
+ lines.push("! repository is not connected, or this release could not be read");
329
+ } else {
330
+ lines.push("\u2713 repository connected");
331
+ }
332
+ if (input.uploaded && input.verification.status !== "verified") {
333
+ lines.push("", "Runtime recording is unaffected.");
334
+ }
335
+ lines.push(RULE);
336
+ return lines.join("\n");
337
+ };
338
+ var runtimeLabel = () => {
339
+ const bun = globalThis.Bun;
340
+ if (typeof bun?.version === "string" && bun.version) return `Bun ${bun.version}`;
341
+ return `Node ${process.versions.node}`;
342
+ };
343
+
285
344
  // src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts
286
345
  var unavailable = () => ({
287
346
  status: "unavailable",
@@ -301,81 +360,162 @@ var noopHandle = {
301
360
  }
302
361
  };
303
362
  var scheduleInstrumentationManifestUpload = (options) => {
304
- const release = detectRelease({ release: options.release });
305
- if (!options.enabled || !release || !options.projectApiKey.trim()) {
363
+ if (!options.enabled || !(options.projectApiKey ?? "").trim()) {
306
364
  return noopHandle;
307
365
  }
366
+ const release = detectRelease({ release: options.release });
367
+ if (!release) return noopHandle;
308
368
  const { instrumentationManifestUrl } = resolveEndpointUrls(options.apiUrl);
309
- let inflight;
369
+ let inflight = Promise.resolve();
310
370
  let verification = unavailable();
311
371
  let loggedSuccess = false;
312
372
  let loggedFailure = false;
373
+ let stopped = false;
374
+ let working = false;
375
+ let debounceTimer;
376
+ const sessionAbort = new AbortController();
377
+ const debounceMs = 500;
313
378
  const packageNamesOf = (manifest) => [
314
379
  ...new Set(
315
380
  manifest.functions.map((fn) => fn.source.packageName).filter((name) => Boolean(name))
316
381
  )
317
382
  ].sort();
318
383
  const report = (manifest, uploaded, next) => {
384
+ const coverage = instrumentationCoverageStats();
319
385
  return formatConfigurationReport({
320
386
  release,
321
387
  runtime: runtimeLabel(),
322
388
  modules: instrumentationManifestModuleCount(),
323
- functions: manifest.functions.length,
389
+ functions: manifest.functions.filter((fn) => fn.instrumented !== false).length,
390
+ skippedFunctions: manifest.functions.filter((fn) => fn.instrumented === false).length,
391
+ instrumentedAsync: coverage.instrumentedAsync,
392
+ skippedByReason: coverage.skippedByReason,
324
393
  packageNames: packageNamesOf(manifest),
325
394
  verification: next,
326
395
  uploaded
327
396
  });
328
397
  };
398
+ const clearDebounce = () => {
399
+ if (debounceTimer === void 0) return;
400
+ clearTimeout(debounceTimer);
401
+ debounceTimer = void 0;
402
+ };
329
403
  const flushSoon = () => {
330
- if (!isInstrumentationManifestDirty()) return;
331
- const generation = instrumentationManifestGeneration();
332
- const manifest = snapshotInstrumentationManifest({
333
- sourceRoot: options.sourceRoot,
334
- sourceRoots: options.sourceRoots
335
- });
336
- if (!manifest) {
337
- markInstrumentationManifestUploaded(generation);
338
- return;
339
- }
340
- const work = uploadInstrumentationManifest({
341
- url: instrumentationManifestUrl,
342
- projectApiKey: options.projectApiKey,
343
- release,
344
- manifest,
345
- fetch: options.fetch
346
- }).then((result) => {
347
- if (result.ok) {
348
- verification = result.verification;
349
- markInstrumentationManifestUploaded(generation);
350
- if (verification.status === "verified") {
351
- if (!loggedSuccess && options.logSuccess !== false) {
352
- loggedSuccess = true;
353
- console.info(report(manifest, true, verification));
404
+ clearDebounce();
405
+ if (stopped || !isInstrumentationManifestDirty() || working) return;
406
+ working = true;
407
+ inflight = inflight.catch(() => {
408
+ }).then(async () => {
409
+ try {
410
+ while (!stopped && isInstrumentationManifestDirty()) {
411
+ const generation = instrumentationManifestGeneration();
412
+ const manifest = snapshotInstrumentationManifest({
413
+ sourceRoot: options.sourceRoot,
414
+ sourceRoots: options.sourceRoots
415
+ });
416
+ if (!manifest) {
417
+ markInstrumentationManifestUploaded(generation);
418
+ continue;
419
+ }
420
+ const controller = new AbortController();
421
+ const timeout = setTimeout(() => controller.abort(), 2e3);
422
+ timeout.unref?.();
423
+ const abortUpload = () => controller.abort();
424
+ sessionAbort.signal.addEventListener("abort", abortUpload, { once: true });
425
+ if (sessionAbort.signal.aborted) controller.abort();
426
+ const aborted = new Promise((_, reject) => {
427
+ const fail = () => reject(controller.signal.reason ?? new Error("aborted"));
428
+ if (controller.signal.aborted) {
429
+ fail();
430
+ return;
431
+ }
432
+ controller.signal.addEventListener("abort", fail, { once: true });
433
+ });
434
+ try {
435
+ const result = await Promise.race([
436
+ uploadInstrumentationManifest({
437
+ url: instrumentationManifestUrl,
438
+ projectApiKey: options.projectApiKey,
439
+ release,
440
+ manifest,
441
+ fetch: options.fetch,
442
+ signal: controller.signal
443
+ }),
444
+ aborted
445
+ ]);
446
+ if (stopped) return;
447
+ if (result.ok) {
448
+ verification = result.verification;
449
+ markInstrumentationManifestUploaded(generation);
450
+ if (verification.status === "verified") {
451
+ if (!loggedSuccess && options.logSuccess !== false) {
452
+ loggedSuccess = true;
453
+ console.info(report(manifest, true, verification));
454
+ }
455
+ continue;
456
+ }
457
+ if (!loggedFailure) {
458
+ loggedFailure = true;
459
+ console.warn(report(manifest, true, verification));
460
+ }
461
+ continue;
462
+ }
463
+ if (!loggedFailure) {
464
+ loggedFailure = true;
465
+ console.warn(report(manifest, false, unavailable()));
466
+ }
467
+ break;
468
+ } catch {
469
+ if (stopped) return;
470
+ break;
471
+ } finally {
472
+ clearTimeout(timeout);
473
+ sessionAbort.signal.removeEventListener("abort", abortUpload);
354
474
  }
355
- return;
356
- }
357
- if (!loggedFailure) {
358
- loggedFailure = true;
359
- console.warn(report(manifest, true, verification));
360
475
  }
361
- return;
362
- }
363
- if (!loggedFailure) {
364
- loggedFailure = true;
365
- console.warn(report(manifest, false, unavailable()));
476
+ } finally {
477
+ working = false;
366
478
  }
367
479
  });
368
- inflight = inflight ? inflight.then(() => work) : work;
369
480
  };
370
- setInstrumentationManifestOnDirty(flushSoon);
371
- flushSoon();
481
+ const armFlush = () => {
482
+ if (stopped || !isInstrumentationManifestDirty()) return;
483
+ clearDebounce();
484
+ debounceTimer = setTimeout(() => {
485
+ debounceTimer = void 0;
486
+ flushSoon();
487
+ }, debounceMs);
488
+ debounceTimer.unref?.();
489
+ };
490
+ setInstrumentationManifestOnDirty(armFlush);
491
+ if (isInstrumentationManifestDirty()) armFlush();
372
492
  return {
373
493
  flushSoon,
374
- wait: async () => {
375
- await inflight;
376
- },
377
- disconnect: () => {
494
+ wait: async (timeoutMs) => {
495
+ flushSoon();
496
+ if (timeoutMs === void 0) {
497
+ await inflight;
498
+ return;
499
+ }
500
+ await new Promise((resolve) => {
501
+ const timer = setTimeout(resolve, timeoutMs);
502
+ void inflight.then(
503
+ () => {
504
+ clearTimeout(timer);
505
+ resolve();
506
+ },
507
+ () => {
508
+ clearTimeout(timer);
509
+ resolve();
510
+ }
511
+ );
512
+ });
513
+ },
514
+ disconnect: () => {
515
+ stopped = true;
516
+ clearDebounce();
378
517
  setInstrumentationManifestOnDirty(void 0);
518
+ sessionAbort.abort();
379
519
  },
380
520
  verify: async () => {
381
521
  flushSoon();
@@ -388,8 +528,6 @@ var scheduleInstrumentationManifestUpload = (options) => {
388
528
  // src/execution-recorder/execution-recorder.ts
389
529
  import { AsyncLocalStorage } from "node:async_hooks";
390
530
  import {
391
- capturedValueCompleteness,
392
- hashInstrumentationManifest,
393
531
  rasputinOmitted,
394
532
  rasputinTagKind,
395
533
  runtimeFunctionId as runtimeFunctionId2
@@ -476,13 +614,18 @@ var ExecutionJournal = class {
476
614
  args,
477
615
  NO_SUPPRESSION
478
616
  )) {
617
+ this.dropped += 2;
479
618
  return;
480
619
  }
481
620
  this.openCallIds.add(callId);
482
621
  }
483
622
  finishCall(kind, callId, timestampNs, durationNs, payload) {
484
- if (!this.openCallIds.delete(callId)) return;
485
- this.write(kind, 0, callId, void 0, timestampNs, durationNs, payload, NO_SUPPRESSION);
623
+ if (!this.openCallIds.has(callId)) return;
624
+ if (!this.write(kind, 0, callId, void 0, timestampNs, durationNs, payload, NO_SUPPRESSION)) {
625
+ this.dropped++;
626
+ return;
627
+ }
628
+ this.openCallIds.delete(callId);
486
629
  }
487
630
  dropCall() {
488
631
  this.dropped += 2;
@@ -813,6 +956,10 @@ var RecorderMemoryBudget = class {
813
956
  return allocation;
814
957
  }
815
958
  captureValue(allocation, serialize) {
959
+ if (allocation.released) {
960
+ this.dropValues(allocation, 1);
961
+ return MEMORY_BUDGET_VALUE_MARKER;
962
+ }
816
963
  if (allocation.mode !== "full") {
817
964
  this.dropValues(allocation, 1);
818
965
  return MEMORY_BUDGET_VALUE_MARKER;
@@ -857,6 +1004,13 @@ var RecorderMemoryBudget = class {
857
1004
  this.markPressure(allocation, "metadata-only");
858
1005
  return false;
859
1006
  }
1007
+ releaseStorage(allocation, bytes) {
1008
+ if (allocation.released) return;
1009
+ const boundedBytes = Math.max(0, Math.ceil(bytes));
1010
+ allocation.estimatedBytes = Math.max(0, allocation.estimatedBytes - boundedBytes);
1011
+ this.activeEstimatedBytes = Math.max(0, this.activeEstimatedBytes - boundedBytes);
1012
+ this.stats.activeEstimatedBytes = this.activeEstimatedBytes;
1013
+ }
860
1014
  release(allocation) {
861
1015
  if (allocation.released) return;
862
1016
  allocation.released = true;
@@ -867,6 +1021,7 @@ var RecorderMemoryBudget = class {
867
1021
  return { ...this.stats };
868
1022
  }
869
1023
  reserve(allocation, bytes) {
1024
+ if (allocation.released) return false;
870
1025
  const boundedBytes = Math.max(0, Math.ceil(bytes));
871
1026
  if (this.activeEstimatedBytes + boundedBytes > this.maximumBytes) return false;
872
1027
  this.activeEstimatedBytes += boundedBytes;
@@ -899,17 +1054,248 @@ var RecorderMemoryBudget = class {
899
1054
  }
900
1055
  };
901
1056
 
902
- // src/execution-recorder/safe-serialize.ts
1057
+ // src/execution-recorder/run-exactly-once.ts
1058
+ var runExactlyOnce = function __rasputinHandleRun__(invoke, callback) {
1059
+ let outcome;
1060
+ const wrapped = function __rasputinHandleRun__3() {
1061
+ try {
1062
+ const value = callback();
1063
+ outcome = { kind: "value", value };
1064
+ return value;
1065
+ } catch (caught) {
1066
+ outcome = { kind: "throw", error: caught };
1067
+ throw caught;
1068
+ }
1069
+ };
1070
+ try {
1071
+ invoke(wrapped);
1072
+ } catch {
1073
+ }
1074
+ if (outcome?.kind === "throw") throw outcome.error;
1075
+ if (outcome?.kind === "value") return outcome.value;
1076
+ return callback();
1077
+ };
1078
+
1079
+ // src/execution-recorder/runtime-state-size-budget.ts
1080
+ import {
1081
+ rasputinUnavailable
1082
+ } from "@rasputin-ai/core";
1083
+ var DEFAULT_RUNTIME_STATE_TARGET_BYTES = 256 * 1024;
1084
+ var DEFAULT_MAX_RUNTIME_STATE_BYTES = 512 * 1024;
1085
+ var VALUE_OMITTED_REASON = "runtime_state_size_budget";
1086
+ var encodedBytes = (value) => Buffer.byteLength(JSON.stringify(value), "utf8");
1087
+ var boundedLimit = (value, fallback) => Number.isFinite(value) ? Math.max(4 * 1024, Math.floor(value)) : fallback;
1088
+ var sizeMetadata = (originalBytes, targetBytes, maximumBytes) => ({
1089
+ reason: "runtime_state_size_budget",
1090
+ originalBytes,
1091
+ finalBytes: 0,
1092
+ targetBytes,
1093
+ maximumBytes,
1094
+ eventValuesDropped: 0,
1095
+ eventsDropped: 0,
1096
+ functionDefinitionsDropped: 0
1097
+ });
1098
+ var withSizeMetadata = (state, size) => ({
1099
+ ...state,
1100
+ truncated: {
1101
+ eventsDropped: state.truncated?.eventsDropped ?? 0,
1102
+ ...state.truncated,
1103
+ size
1104
+ }
1105
+ });
1106
+ var settleFinalBytes = (state) => {
1107
+ const size = state.truncated?.size;
1108
+ if (!size) return state;
1109
+ for (let attempt = 0; attempt < 3; attempt++) {
1110
+ const encoded = encodedBytes(state);
1111
+ if (size.finalBytes === encoded) break;
1112
+ size.finalBytes = encoded;
1113
+ }
1114
+ return state;
1115
+ };
1116
+ var dropEventValues = (events) => {
1117
+ let dropped = 0;
1118
+ const marker = () => rasputinUnavailable(VALUE_OMITTED_REASON);
1119
+ const bounded = events.map((event) => {
1120
+ if (event.type === "function_enter") {
1121
+ dropped += event.args.length;
1122
+ return { ...event, args: event.args.map(marker) };
1123
+ }
1124
+ if (event.type === "function_exit" && "returnValue" in event) {
1125
+ dropped++;
1126
+ return { ...event, returnValue: marker() };
1127
+ }
1128
+ if (event.type === "function_throw" && "error" in event) {
1129
+ dropped++;
1130
+ return { ...event, error: marker() };
1131
+ }
1132
+ return { ...event };
1133
+ });
1134
+ return { events: bounded, dropped };
1135
+ };
1136
+ var truncateUtf8 = (value, maximumBytes) => {
1137
+ if (value === void 0 || Buffer.byteLength(value, "utf8") <= maximumBytes) return value;
1138
+ let low = 0;
1139
+ let high = value.length;
1140
+ while (low < high) {
1141
+ const middle = Math.ceil((low + high) / 2);
1142
+ if (Buffer.byteLength(value.slice(0, middle), "utf8") <= maximumBytes) low = middle;
1143
+ else high = middle - 1;
1144
+ }
1145
+ return value.slice(0, low);
1146
+ };
1147
+ var minimalState = (state, size) => {
1148
+ const request = state.execution.request;
1149
+ const execution = {
1150
+ kind: state.execution.kind,
1151
+ ...state.execution.name === void 0 ? {} : { name: truncateUtf8(state.execution.name, 4 * 1024) },
1152
+ ...request ? {
1153
+ request: {
1154
+ ...request.method == null ? {} : { method: truncateUtf8(request.method, 1024) },
1155
+ ...request.route == null ? {} : { route: truncateUtf8(request.route, 4 * 1024) },
1156
+ ...request.status == null ? {} : { status: request.status }
1157
+ }
1158
+ } : {}
1159
+ };
1160
+ return withSizeMetadata(
1161
+ {
1162
+ version: 4,
1163
+ captureProfile: {
1164
+ source: state.captureProfile.source,
1165
+ functionBoundaries: state.captureProfile.functionBoundaries === "none" ? "none" : "partial",
1166
+ functionValues: "none",
1167
+ timings: state.captureProfile.timings === "none" ? "none" : "partial"
1168
+ },
1169
+ executionId: truncateUtf8(state.executionId, 256) ?? "",
1170
+ startedAt: truncateUtf8(state.startedAt, 128) ?? "",
1171
+ durationMs: Number.isFinite(state.durationMs) ? state.durationMs : 0,
1172
+ recorder: {
1173
+ inlineWallTimeMs: Number.isFinite(state.recorder?.inlineWallTimeMs) ? state.recorder.inlineWallTimeMs : 0
1174
+ },
1175
+ execution,
1176
+ functions: [],
1177
+ events: [],
1178
+ ...state.capture ? { capture: { ...state.capture } } : {}
1179
+ },
1180
+ size
1181
+ );
1182
+ };
1183
+ var enforceRuntimeStateSizeBudget = (input, options = {}) => {
1184
+ const maximumBytes = boundedLimit(options.maximumBytes, DEFAULT_MAX_RUNTIME_STATE_BYTES);
1185
+ const targetBytes = Math.min(
1186
+ maximumBytes,
1187
+ boundedLimit(options.targetBytes, DEFAULT_RUNTIME_STATE_TARGET_BYTES)
1188
+ );
1189
+ const initialBytes = encodedBytes(input);
1190
+ const existingSize = input.truncated?.size;
1191
+ if (existingSize && initialBytes <= maximumBytes) return settleFinalBytes(input);
1192
+ if (initialBytes <= maximumBytes) return input;
1193
+ const originalBytes = existingSize?.originalBytes ?? initialBytes;
1194
+ const size = sizeMetadata(originalBytes, targetBytes, maximumBytes);
1195
+ let state = input;
1196
+ const stripped = dropEventValues(state.events);
1197
+ size.eventValuesDropped += stripped.dropped;
1198
+ state = settleFinalBytes(
1199
+ withSizeMetadata(
1200
+ {
1201
+ ...state,
1202
+ captureProfile: {
1203
+ ...state.captureProfile,
1204
+ functionValues: state.captureProfile.functionValues === "none" ? "none" : "selective"
1205
+ },
1206
+ events: stripped.events
1207
+ },
1208
+ size
1209
+ )
1210
+ );
1211
+ if (encodedBytes(state) <= maximumBytes) return state;
1212
+ size.eventsDropped += state.events.length;
1213
+ size.functionDefinitionsDropped += state.functions.length;
1214
+ state = settleFinalBytes(
1215
+ withSizeMetadata(
1216
+ {
1217
+ ...state,
1218
+ captureProfile: {
1219
+ ...state.captureProfile,
1220
+ functionBoundaries: state.captureProfile.functionBoundaries === "none" ? "none" : "partial",
1221
+ functionValues: "none",
1222
+ timings: state.captureProfile.timings === "none" ? "none" : "partial"
1223
+ },
1224
+ functions: [],
1225
+ events: [],
1226
+ truncated: {
1227
+ eventsDropped: (state.truncated?.eventsDropped ?? 0) + size.eventsDropped,
1228
+ size
1229
+ }
1230
+ },
1231
+ size
1232
+ )
1233
+ );
1234
+ if (encodedBytes(state) <= maximumBytes) return state;
1235
+ state = settleFinalBytes(minimalState(state, size));
1236
+ if (encodedBytes(state) <= maximumBytes) return state;
1237
+ const emergency = {
1238
+ version: 4,
1239
+ captureProfile: {
1240
+ source: state.captureProfile.source,
1241
+ functionBoundaries: "partial",
1242
+ functionValues: "none",
1243
+ timings: "partial"
1244
+ },
1245
+ executionId: "",
1246
+ startedAt: "",
1247
+ durationMs: 0,
1248
+ execution: { kind: state.execution.kind },
1249
+ functions: [],
1250
+ events: [],
1251
+ truncated: { eventsDropped: size.eventsDropped, size }
1252
+ };
1253
+ return settleFinalBytes(emergency);
1254
+ };
1255
+
1256
+ // src/execution-recorder/encode-frozen.ts
1257
+ import { Buffer as Buffer3 } from "node:buffer";
1258
+
1259
+ // src/execution-recorder/value-freeze.ts
903
1260
  import { Buffer as Buffer2 } from "node:buffer";
904
- var DEFAULT_REDACT_KEYS = [
905
- "password",
906
- "token",
907
- "authorization",
908
- "cookie",
909
- "secret",
910
- "apikey",
911
- "creditcard"
912
- ];
1261
+ import { types } from "node:util";
1262
+ import { RASPUTIN_WIRE_TAG } from "@rasputin-ai/core";
1263
+
1264
+ // src/execution-recorder/redact-keys.ts
1265
+ import { defaultSensitivePropertyNames, propertyNameIsSensitive } from "@rasputin-ai/core";
1266
+ var compactKey = (key) => {
1267
+ let compacted = "";
1268
+ for (let index = 0; index < key.length; index++) {
1269
+ const code = key.charCodeAt(index);
1270
+ if (code === 45 || code === 46 || code === 95) continue;
1271
+ compacted += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : key[index];
1272
+ }
1273
+ return compacted;
1274
+ };
1275
+ var stripTrailingDigits = (value) => {
1276
+ let end = value.length;
1277
+ while (end > 0) {
1278
+ const code = value.charCodeAt(end - 1);
1279
+ if (code < 48 || code > 57) break;
1280
+ end--;
1281
+ }
1282
+ return end === 0 ? value : value.slice(0, end);
1283
+ };
1284
+ var normalizeKey = (key) => stripTrailingDigits(compactKey(key));
1285
+ var compileRedactKeys = (extra) => {
1286
+ if (!extra?.length) return defaultSensitivePropertyNames();
1287
+ return /* @__PURE__ */ new Set([...defaultSensitivePropertyNames(), ...extra.map(normalizeKey)]);
1288
+ };
1289
+ var keyIsRedacted = (key, redactKeys) => {
1290
+ if (propertyNameIsSensitive(key)) return true;
1291
+ if (redactKeys.has(key)) return true;
1292
+ const compacted = compactKey(key);
1293
+ if (redactKeys.has(compacted)) return true;
1294
+ return redactKeys.has(stripTrailingDigits(compacted));
1295
+ };
1296
+
1297
+ // src/execution-recorder/value-freeze.ts
1298
+ var REDACTED = "[RASPUTIN_REDACTED]";
913
1299
  var defaults = {
914
1300
  maxDepth: 3,
915
1301
  maxObjectKeys: 30,
@@ -917,441 +1303,1017 @@ var defaults = {
917
1303
  maxStringLength: 500,
918
1304
  maxSerializedValueBytes: 8 * 1024
919
1305
  };
920
- var REDACTED = "[RASPUTIN_REDACTED]";
921
- var truncation = (reason, extra = {}) => ({
922
- __rasputin_truncated: true,
923
- __reason: reason,
924
- ...extra
1306
+ var compileFreezeLimits = (options) => ({
1307
+ maxDepth: options.maxDepth ?? defaults.maxDepth,
1308
+ maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
1309
+ maxArrayElements: options.maxArrayElements ?? defaults.maxArrayElements,
1310
+ maxStringLength: options.maxStringLength ?? defaults.maxStringLength,
1311
+ maxSerializedValueBytes: options.maxSerializedValueBytes ?? defaults.maxSerializedValueBytes
925
1312
  });
926
- var typeMarker = (type, value) => ({
927
- __rasputin_type: type,
928
- ...value === void 0 ? {} : { value }
1313
+ var FROZEN = Symbol("rasputin.frozen");
1314
+ var NODE = 24;
1315
+ var taggedNumberKind = (value) => {
1316
+ if (Number.isNaN(value)) return "NaN";
1317
+ if (value === Infinity) return "Infinity";
1318
+ if (value === -Infinity) return "-Infinity";
1319
+ if (Object.is(value, -0)) return "-0";
1320
+ return void 0;
1321
+ };
1322
+ var atom = (kind, extra = {}) => ({
1323
+ [FROZEN]: kind,
1324
+ ...extra
929
1325
  });
930
- var jsonStringUtf8Bytes = (value) => {
931
- let bytes = 2;
932
- for (let index = 0; index < value.length; index++) {
933
- const code = value.charCodeAt(index);
934
- if (code === 34 || code === 92) {
935
- bytes += 2;
936
- continue;
937
- }
938
- if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
939
- bytes += 2;
940
- continue;
1326
+ var ownData = (value, key) => {
1327
+ try {
1328
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1329
+ if (!descriptor) return void 0;
1330
+ if ("value" in descriptor) return { present: true, value: descriptor.value };
1331
+ return void 0;
1332
+ } catch {
1333
+ return void 0;
1334
+ }
1335
+ };
1336
+ var nativeErrorStackGet = (() => {
1337
+ try {
1338
+ return Object.getOwnPropertyDescriptor(Error.prototype, "stack")?.get;
1339
+ } catch {
1340
+ return void 0;
1341
+ }
1342
+ })();
1343
+ var nativeInstanceStackGet = (() => {
1344
+ try {
1345
+ const probe = new Error("rasputin-stack-probe");
1346
+ return Object.getOwnPropertyDescriptor(probe, "stack")?.get;
1347
+ } catch {
1348
+ return void 0;
1349
+ }
1350
+ })();
1351
+ var nativeErrorMessageGet = (() => {
1352
+ try {
1353
+ return Object.getOwnPropertyDescriptor(Error.prototype, "message")?.get;
1354
+ } catch {
1355
+ return void 0;
1356
+ }
1357
+ })();
1358
+ var typedArrayProto = Object.getPrototypeOf(Uint8Array.prototype);
1359
+ var typedArrayByteLengthGet = typedArrayProto ? Object.getOwnPropertyDescriptor(typedArrayProto, "byteLength")?.get : void 0;
1360
+ var typedArrayByteOffsetGet = typedArrayProto ? Object.getOwnPropertyDescriptor(typedArrayProto, "byteOffset")?.get : void 0;
1361
+ var typedArrayBufferGet = typedArrayProto ? Object.getOwnPropertyDescriptor(typedArrayProto, "buffer")?.get : void 0;
1362
+ var dataViewByteLengthGet = Object.getOwnPropertyDescriptor(
1363
+ DataView.prototype,
1364
+ "byteLength"
1365
+ )?.get;
1366
+ var domExceptionNameGet = typeof DOMException === "undefined" ? void 0 : Object.getOwnPropertyDescriptor(DOMException.prototype, "name")?.get;
1367
+ var domExceptionMessageGet = typeof DOMException === "undefined" ? void 0 : Object.getOwnPropertyDescriptor(DOMException.prototype, "message")?.get;
1368
+ var prepareStackTraceDepth = 0;
1369
+ var savedPrepareStackTrace;
1370
+ var withoutPrepareStackTrace = (read) => {
1371
+ if (prepareStackTraceDepth === 0) {
1372
+ savedPrepareStackTrace = Error.prepareStackTrace;
1373
+ Error.prepareStackTrace = void 0;
1374
+ }
1375
+ prepareStackTraceDepth += 1;
1376
+ try {
1377
+ return read();
1378
+ } finally {
1379
+ prepareStackTraceDepth -= 1;
1380
+ if (prepareStackTraceDepth === 0) Error.prepareStackTrace = savedPrepareStackTrace;
1381
+ }
1382
+ };
1383
+ var isDomException = (value) => {
1384
+ try {
1385
+ return typeof DOMException !== "undefined" && value instanceof DOMException;
1386
+ } catch {
1387
+ return false;
1388
+ }
1389
+ };
1390
+ var functionNameOf = (value) => {
1391
+ const own = ownData(value, "name");
1392
+ if (own && typeof own.value === "string" && own.value.length > 0) return own.value;
1393
+ return "anonymous";
1394
+ };
1395
+ var errorNameOf = (value) => {
1396
+ if (isDomException(value) && domExceptionNameGet) {
1397
+ try {
1398
+ const name = domExceptionNameGet.call(value);
1399
+ if (typeof name === "string" && name.length > 0) return name;
1400
+ } catch {
941
1401
  }
942
- if (code < 32) {
943
- bytes += 6;
944
- continue;
1402
+ }
1403
+ let current = value;
1404
+ while (current) {
1405
+ const slot = ownData(current, "name");
1406
+ if (slot && typeof slot.value === "string" && slot.value.length > 0) return slot.value;
1407
+ try {
1408
+ current = Object.getPrototypeOf(current);
1409
+ } catch {
1410
+ break;
945
1411
  }
946
- if (code < 128) {
947
- bytes += 1;
948
- continue;
1412
+ }
1413
+ return "Error";
1414
+ };
1415
+ var errorMessageOf = (value) => {
1416
+ if (isDomException(value) && domExceptionMessageGet) {
1417
+ try {
1418
+ return domExceptionMessageGet.call(value);
1419
+ } catch {
949
1420
  }
950
- if (code < 2048) {
951
- bytes += 2;
952
- continue;
1421
+ }
1422
+ const own = ownData(value, "message");
1423
+ if (own) return own.value;
1424
+ if (!nativeErrorMessageGet) return void 0;
1425
+ try {
1426
+ return nativeErrorMessageGet.call(value);
1427
+ } catch {
1428
+ return void 0;
1429
+ }
1430
+ };
1431
+ var errorStackOf = (value) => withoutPrepareStackTrace(() => {
1432
+ const own = ownData(value, "stack");
1433
+ if (own && typeof own.value === "string" && own.value.length > 0) return own.value;
1434
+ try {
1435
+ const getter = Object.getOwnPropertyDescriptor(value, "stack")?.get;
1436
+ if (getter && nativeInstanceStackGet && getter === nativeInstanceStackGet) {
1437
+ const stack = getter.call(value);
1438
+ if (typeof stack === "string" && stack.length > 0) return stack;
953
1439
  }
954
- if (code >= 55296 && code <= 56319) {
955
- const next = value.charCodeAt(index + 1);
956
- if (index + 1 < value.length && next >= 56320 && next <= 57343) {
957
- bytes += 4;
958
- index++;
959
- continue;
960
- }
961
- bytes += 6;
962
- continue;
1440
+ } catch {
1441
+ }
1442
+ if (!nativeErrorStackGet) return void 0;
1443
+ try {
1444
+ const stack = nativeErrorStackGet.call(value);
1445
+ return typeof stack === "string" && stack.length > 0 ? stack : void 0;
1446
+ } catch {
1447
+ return void 0;
1448
+ }
1449
+ });
1450
+ var viewByteLength = (value) => {
1451
+ try {
1452
+ if (types.isDataView(value)) {
1453
+ return dataViewByteLengthGet ? dataViewByteLengthGet.call(value) : 0;
963
1454
  }
964
- if (code >= 56320 && code <= 57343) {
965
- bytes += 6;
966
- continue;
1455
+ return typedArrayByteLengthGet ? typedArrayByteLengthGet.call(value) : 0;
1456
+ } catch {
1457
+ return 0;
1458
+ }
1459
+ };
1460
+ var typedArrayName = (value) => {
1461
+ if (types.isUint8Array(value)) return "Uint8Array";
1462
+ if (types.isUint8ClampedArray(value)) return "Uint8ClampedArray";
1463
+ if (types.isInt8Array(value)) return "Int8Array";
1464
+ if (types.isUint16Array(value)) return "Uint16Array";
1465
+ if (types.isInt16Array(value)) return "Int16Array";
1466
+ if (types.isUint32Array(value)) return "Uint32Array";
1467
+ if (types.isInt32Array(value)) return "Int32Array";
1468
+ if (types.isFloat32Array(value)) return "Float32Array";
1469
+ if (types.isFloat64Array(value)) return "Float64Array";
1470
+ if (types.isBigUint64Array(value)) return "BigUint64Array";
1471
+ if (types.isBigInt64Array(value)) return "BigInt64Array";
1472
+ return "TypedArray";
1473
+ };
1474
+ var prototypeChainHasProxy = (value) => {
1475
+ let current = value;
1476
+ for (let depth = 0; depth < 8; depth++) {
1477
+ try {
1478
+ current = Object.getPrototypeOf(current);
1479
+ } catch {
1480
+ return true;
967
1481
  }
968
- bytes += 3;
1482
+ if (!current) return false;
1483
+ if (types.isProxy(current)) return true;
969
1484
  }
970
- return bytes;
1485
+ return true;
971
1486
  };
972
- var jsonLiteralUtf8Bytes = (value) => {
973
- if (value === null) return 4;
974
- switch (typeof value) {
975
- case "boolean":
976
- return value ? 4 : 5;
977
- case "number":
978
- if (!Number.isFinite(value)) return 4;
979
- if (Object.is(value, -0)) return 1;
980
- return String(value).length;
981
- case "string":
982
- return jsonStringUtf8Bytes(value);
983
- case "object": {
984
- if (Array.isArray(value)) {
985
- let bytes2 = 2;
986
- for (let index = 0; index < value.length; index++) {
987
- if (index > 0) bytes2 += 1;
988
- bytes2 += jsonLiteralUtf8Bytes(value[index]);
989
- }
990
- return bytes2;
991
- }
992
- const record = value;
993
- let bytes = 2;
994
- let first = true;
995
- for (const key of Object.keys(record)) {
996
- if (!first) bytes += 1;
997
- first = false;
998
- bytes += jsonStringUtf8Bytes(key) + 1;
999
- bytes += jsonLiteralUtf8Bytes(record[key]);
1000
- }
1001
- return bytes;
1487
+ var sampleBytes = (bytes, max) => {
1488
+ const length = Math.min(max, bytes.length);
1489
+ const sample = new Array(length);
1490
+ for (let index = 0; index < length; index++) sample[index] = bytes[index] ?? 0;
1491
+ return sample;
1492
+ };
1493
+ var RESERVED_USER_KEYS = /* @__PURE__ */ new Set([
1494
+ "__proto__",
1495
+ "__rasputin_type",
1496
+ "__rasputin_truncated",
1497
+ "__rasputin_fields",
1498
+ "__reason",
1499
+ "__original_length",
1500
+ "__serialized_bytes"
1501
+ ]);
1502
+ var assignFrozenField = (fields, key, value) => {
1503
+ if (RESERVED_USER_KEYS.has(key) || key.startsWith("__rasputin_")) {
1504
+ const escaped = fields.__rasputin_fields ?? [];
1505
+ escaped.push({ name: key, value });
1506
+ fields.__rasputin_fields = escaped;
1507
+ return;
1508
+ }
1509
+ fields[key] = value;
1510
+ };
1511
+ var ownEnumerableKeys = (value, maxKeys) => {
1512
+ const keys = [];
1513
+ let proto = null;
1514
+ try {
1515
+ proto = Object.getPrototypeOf(value);
1516
+ } catch {
1517
+ proto = null;
1518
+ }
1519
+ const protoIsProxy = proto !== null && types.isProxy(proto);
1520
+ try {
1521
+ for (const key in value) {
1522
+ if (protoIsProxy && !Object.hasOwn(value, key)) break;
1523
+ if (!Object.hasOwn(value, key)) continue;
1524
+ if (keys.length >= maxKeys) return { keys, truncated: true };
1525
+ keys.push(key);
1002
1526
  }
1003
- default:
1004
- return Buffer2.byteLength(JSON.stringify(value) ?? "null", "utf8");
1527
+ } catch {
1528
+ return { keys, truncated: keys.length >= maxKeys };
1005
1529
  }
1530
+ return { keys, truncated: false };
1006
1531
  };
1007
- var compileLimits = (options) => ({
1008
- maxDepth: options.maxDepth ?? defaults.maxDepth,
1009
- maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
1010
- maxArrayElements: options.maxArrayElements ?? defaults.maxArrayElements,
1011
- maxStringLength: options.maxStringLength ?? defaults.maxStringLength,
1012
- maxSerializedValueBytes: options.maxSerializedValueBytes ?? defaults.maxSerializedValueBytes
1013
- });
1014
- var compileRedactKeys = (options) => {
1015
- if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
1016
- return /* @__PURE__ */ new Set([...DEFAULT_REDACT_KEYS, ...options.redactKeys.map((key) => key.toLowerCase())]);
1532
+ var bufferByteLength = (value) => {
1533
+ try {
1534
+ return Buffer2.byteLength(value);
1535
+ } catch {
1536
+ return 0;
1537
+ }
1017
1538
  };
1018
- var keyNeedsCaseFold = (key) => {
1539
+ var stringEstimate = (value) => NODE + 2 + Buffer2.byteLength(value, "utf8");
1540
+ var URL_LIKE_PROPERTY_NAMES = /* @__PURE__ */ new Set([
1541
+ "url",
1542
+ "href",
1543
+ "originalurl",
1544
+ "path",
1545
+ "pathname",
1546
+ "search",
1547
+ "query",
1548
+ "requesturl",
1549
+ "requesturi",
1550
+ "location",
1551
+ "referer",
1552
+ "referrer",
1553
+ "uri",
1554
+ "connectionuri",
1555
+ "connectionurl",
1556
+ "databaseuri",
1557
+ "databaseurl",
1558
+ "mongouri",
1559
+ "mongourl",
1560
+ "redisuri",
1561
+ "redisurl",
1562
+ "postgresuri",
1563
+ "postgresurl"
1564
+ ]);
1565
+ var compactPropertyName = (key) => {
1566
+ let compacted = "";
1019
1567
  for (let index = 0; index < key.length; index++) {
1020
1568
  const code = key.charCodeAt(index);
1021
- if (code > 127 || code >= 65 && code <= 90) return true;
1569
+ if (code === 45 || code === 46 || code === 95) continue;
1570
+ compacted += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : key[index];
1022
1571
  }
1023
- return false;
1572
+ return compacted;
1024
1573
  };
1025
- var isJsonSafeString = (value) => {
1026
- for (let index = 0; index < value.length; index++) {
1027
- const code = value.charCodeAt(index);
1028
- if (code < 32 || code === 34 || code === 92) return false;
1029
- if (code >= 55296 && code <= 56319) {
1030
- const next = value.charCodeAt(index + 1);
1031
- if (index + 1 >= value.length || next < 56320 || next > 57343) return false;
1032
- index++;
1033
- continue;
1034
- }
1035
- if (code >= 56320 && code <= 57343) return false;
1574
+ var propertyNameLooksLikeUrl = (key) => URL_LIKE_PROPERTY_NAMES.has(compactPropertyName(key));
1575
+ var looksLikeBareQueryString = (text) => {
1576
+ if (!text.includes("=") || /\s/.test(text)) return false;
1577
+ if (/^[a-z][a-z0-9+.-]*:/i.test(text) || text.startsWith("/")) return false;
1578
+ return /^[^\s=]+=[^\s]*(&[^\s=]+=[^\s]*)*$/.test(text);
1579
+ };
1580
+ var redactSensitiveQuery = (text, redactKeys) => {
1581
+ const queryAt = text.indexOf("?");
1582
+ let prefix = "";
1583
+ let query = "";
1584
+ let suffix = "";
1585
+ if (queryAt >= 0) {
1586
+ if (queryAt === text.length - 1) return text;
1587
+ const hashAt = text.indexOf("#", queryAt + 1);
1588
+ prefix = text.slice(0, queryAt + 1);
1589
+ query = hashAt < 0 ? text.slice(queryAt + 1) : text.slice(queryAt + 1, hashAt);
1590
+ suffix = hashAt < 0 ? "" : text.slice(hashAt);
1591
+ } else if (looksLikeBareQueryString(text)) {
1592
+ query = text;
1593
+ } else {
1594
+ return text;
1036
1595
  }
1037
- return true;
1596
+ if (!query.includes("=")) return text;
1597
+ let changed = false;
1598
+ const next = query.split("&").map((part) => {
1599
+ const equals = part.indexOf("=");
1600
+ const rawKey = equals < 0 ? part : part.slice(0, equals);
1601
+ if (!rawKey) return part;
1602
+ let decoded = rawKey;
1603
+ try {
1604
+ decoded = decodeURIComponent(rawKey.replace(/\+/g, " "));
1605
+ } catch {
1606
+ decoded = rawKey;
1607
+ }
1608
+ if (!keyIsRedacted(decoded, redactKeys) && !keyIsRedacted(rawKey, redactKeys)) return part;
1609
+ changed = true;
1610
+ return `${rawKey}=${REDACTED}`;
1611
+ });
1612
+ if (!changed) return text;
1613
+ return `${prefix}${next.join("&")}${suffix}`;
1038
1614
  };
1039
- var primitiveFastPath = (value, maxStringLength) => {
1040
- if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
1041
- if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
1042
- if (typeof value === "number") {
1043
- if (!Number.isFinite(value)) return { value, bytes: 4, visitedNodes: 1 };
1044
- if (Object.is(value, -0)) return { value, bytes: 1, visitedNodes: 1 };
1045
- return { value, bytes: String(value).length, visitedNodes: 1 };
1046
- }
1047
- if (typeof value === "string") {
1048
- if (value.length > maxStringLength || !isJsonSafeString(value)) return void 0;
1049
- return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
1050
- }
1051
- if (typeof value === "undefined") {
1052
- const serialized = typeMarker("undefined");
1053
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1054
- }
1055
- if (typeof value === "bigint") {
1056
- const serialized = typeMarker("bigint", value.toString());
1057
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1058
- }
1059
- if (typeof value === "symbol") {
1060
- const text = String(value);
1061
- if (!isJsonSafeString(text)) return void 0;
1062
- const serialized = typeMarker("symbol", text);
1063
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1064
- }
1065
- if (typeof value === "function") {
1066
- const name = value.name || "anonymous";
1067
- if (!isJsonSafeString(name)) return void 0;
1068
- const serialized = typeMarker("function", name);
1069
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1615
+ var redactUrlUserinfo = (text) => {
1616
+ const schemeEnd = text.indexOf("://");
1617
+ if (schemeEnd <= 0) return text;
1618
+ const rest = text.slice(schemeEnd + 3);
1619
+ let authorityEnd = rest.length;
1620
+ for (const marker of ["/", "?", "#"]) {
1621
+ const at = rest.indexOf(marker);
1622
+ if (at >= 0 && at < authorityEnd) authorityEnd = at;
1070
1623
  }
1071
- return void 0;
1624
+ const authority = rest.slice(0, authorityEnd);
1625
+ const userinfoEnd = authority.lastIndexOf("@");
1626
+ if (userinfoEnd < 0) return text;
1627
+ return `${text.slice(0, schemeEnd + 3)}${REDACTED}@${authority.slice(userinfoEnd + 1)}${rest.slice(authorityEnd)}`;
1072
1628
  };
1073
- var createSafeSerializer = (options = {}) => {
1074
- const limits = compileLimits(options);
1075
- const redactKeys = compileRedactKeys(options);
1629
+ var redactUrlLikeString = (text, redactKeys) => redactSensitiveQuery(redactUrlUserinfo(text), redactKeys);
1630
+ var isFrozenAtom = (value) => typeof value === "object" && value !== null && FROZEN in value;
1631
+ var createValueFreezer = (options = {}) => {
1632
+ const limits = compileFreezeLimits(options);
1633
+ const redactKeys = compileRedactKeys(options.redactKeys);
1076
1634
  const sharedPath = /* @__PURE__ */ new Set();
1077
- let serializing = false;
1078
- const isRedactedKey = (key) => {
1079
- if (redactKeys.has(key)) return true;
1080
- if (!keyNeedsCaseFold(key)) return false;
1081
- return redactKeys.has(key.toLowerCase());
1082
- };
1083
- const addBytes = (metrics, count) => {
1084
- metrics.bytes += count;
1085
- if (metrics.bytes > limits.maxSerializedValueBytes) metrics.oversize = true;
1635
+ let freezing = false;
1636
+ const add = (metrics, count) => {
1637
+ metrics.estimatedBytes += count;
1638
+ if (metrics.estimatedBytes > limits.maxSerializedValueBytes) metrics.oversize = true;
1086
1639
  };
1087
- const boundedOversize = (bytes, visitedNodes) => {
1088
- const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
1089
- return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
1090
- };
1091
- const openObject = (metrics, allocate) => {
1092
- addBytes(metrics, 2);
1093
- return {
1094
- target: allocate && !metrics.oversize ? {} : void 0,
1095
- first: true
1096
- };
1097
- };
1098
- const openArray = (metrics, allocate) => {
1099
- addBytes(metrics, 2);
1100
- return {
1101
- items: allocate && !metrics.oversize ? [] : void 0,
1102
- first: true
1103
- };
1104
- };
1105
- const beginField = (metrics, object, key) => {
1106
- if (!object.first) addBytes(metrics, 1);
1107
- object.first = false;
1108
- addBytes(metrics, jsonStringUtf8Bytes(key) + 1);
1109
- };
1110
- const assignField = (object, key, fieldValue) => {
1111
- if (object.target) object.target[key] = fieldValue;
1112
- };
1113
- const writeLiteralField = (metrics, object, key, jsonValue) => {
1114
- beginField(metrics, object, key);
1115
- addBytes(metrics, jsonLiteralUtf8Bytes(jsonValue));
1116
- assignField(object, key, jsonValue);
1117
- };
1118
- const writeTypeMarker = (metrics, allocate, type, nestedValue) => {
1119
- const object = openObject(metrics, allocate);
1120
- writeLiteralField(metrics, object, "__rasputin_type", type);
1121
- if (nestedValue !== void 0) writeLiteralField(metrics, object, "value", nestedValue);
1122
- return object.target;
1123
- };
1124
- const writeTruncation = (metrics, allocate, reason, extra = {}) => {
1125
- const object = openObject(metrics, allocate);
1126
- writeLiteralField(metrics, object, "__rasputin_truncated", true);
1127
- writeLiteralField(metrics, object, "__reason", reason);
1128
- for (const key of Object.keys(extra)) writeLiteralField(metrics, object, key, extra[key]);
1129
- return object.target;
1130
- };
1131
- const serializeInner = (value, depth, path, allocate, metrics) => {
1640
+ const freezeInner = (value, depth, path, metrics) => {
1641
+ if (metrics.oversize) return void 0;
1132
1642
  metrics.visitedNodes++;
1133
- const store = allocate && !metrics.oversize;
1134
1643
  if (value === null) {
1135
- addBytes(metrics, 4);
1136
- return store ? null : void 0;
1644
+ add(metrics, 4);
1645
+ return null;
1137
1646
  }
1138
1647
  if (typeof value === "boolean") {
1139
- addBytes(metrics, value ? 4 : 5);
1140
- return store ? value : void 0;
1648
+ add(metrics, value ? 4 : 5);
1649
+ return value;
1141
1650
  }
1142
1651
  if (typeof value === "number") {
1143
- if (!Number.isFinite(value)) addBytes(metrics, 4);
1144
- else if (Object.is(value, -0)) addBytes(metrics, 1);
1145
- else addBytes(metrics, String(value).length);
1146
- return store ? value : void 0;
1652
+ const kind = taggedNumberKind(value);
1653
+ if (kind) {
1654
+ add(metrics, NODE + 16);
1655
+ return atom(kind);
1656
+ }
1657
+ add(metrics, NODE + String(value).length);
1658
+ return value;
1147
1659
  }
1148
1660
  if (typeof value === "string") {
1149
1661
  if (value.length <= limits.maxStringLength) {
1150
- addBytes(metrics, jsonStringUtf8Bytes(value));
1151
- return store ? value : void 0;
1662
+ add(metrics, stringEstimate(value));
1663
+ return value;
1152
1664
  }
1153
- return writeTruncation(metrics, store, "max_string_length", {
1154
- __original_length: value.length,
1155
- value: value.slice(0, limits.maxStringLength)
1665
+ const sliced = value.slice(0, limits.maxStringLength);
1666
+ add(metrics, NODE + stringEstimate(sliced) + 48);
1667
+ return atom("truncated", {
1668
+ reason: "max_string_length",
1669
+ originalLength: value.length,
1670
+ value: sliced
1156
1671
  });
1157
1672
  }
1158
- if (typeof value === "undefined") return writeTypeMarker(metrics, store, "undefined");
1673
+ if (typeof value === "undefined") {
1674
+ add(metrics, NODE + 16);
1675
+ return atom("undefined");
1676
+ }
1159
1677
  if (typeof value === "bigint") {
1160
- return writeTypeMarker(metrics, store, "bigint", value.toString());
1678
+ const text = value.toString();
1679
+ add(metrics, NODE + stringEstimate(text));
1680
+ return atom("bigint", { value: text });
1161
1681
  }
1162
1682
  if (typeof value === "symbol") {
1163
- return writeTypeMarker(metrics, store, "symbol", String(value));
1683
+ const text = String(value);
1684
+ add(metrics, NODE + stringEstimate(text));
1685
+ return atom("symbol", { value: text });
1164
1686
  }
1165
1687
  if (typeof value === "function") {
1166
- return writeTypeMarker(metrics, store, "function", value.name || "anonymous");
1688
+ if (types.isProxy(value)) {
1689
+ add(metrics, NODE + 16);
1690
+ return atom("Proxy");
1691
+ }
1692
+ const name = functionNameOf(value);
1693
+ add(metrics, NODE + stringEstimate(name));
1694
+ return atom("function", { value: name });
1695
+ }
1696
+ if (typeof value !== "object") {
1697
+ add(metrics, NODE + 16);
1698
+ return atom("unserializable");
1699
+ }
1700
+ if (path.has(value)) {
1701
+ add(metrics, NODE + 16);
1702
+ return atom("circular");
1167
1703
  }
1168
- if (depth >= limits.maxDepth) return writeTruncation(metrics, store, "max_depth");
1169
- if (typeof value !== "object") return writeTypeMarker(metrics, store, typeof value);
1170
- if (path.has(value)) return writeTypeMarker(metrics, store, "circular");
1171
1704
  path.add(value);
1172
- const bytesBefore = metrics.bytes;
1173
- const oversizeBefore = metrics.oversize;
1174
1705
  try {
1175
- const childAllocate = allocate && !metrics.oversize;
1176
- if (value instanceof Error) {
1177
- const object2 = openObject(metrics, childAllocate);
1178
- writeLiteralField(metrics, object2, "__rasputin_type", "Error");
1179
- writeLiteralField(metrics, object2, "name", value.name);
1180
- beginField(metrics, object2, "message");
1181
- assignField(
1182
- object2,
1183
- "message",
1184
- serializeInner(value.message, depth + 1, path, childAllocate, metrics)
1185
- );
1186
- if (value.stack) {
1187
- beginField(metrics, object2, "stack");
1188
- assignField(
1189
- object2,
1190
- "stack",
1191
- serializeInner(value.stack, depth + 1, path, childAllocate, metrics)
1192
- );
1193
- }
1194
- return object2.target;
1706
+ if (types.isProxy(value) || prototypeChainHasProxy(value)) {
1707
+ add(metrics, NODE + 16);
1708
+ return atom("Proxy");
1195
1709
  }
1196
- if (value instanceof Date) {
1197
- return writeTypeMarker(metrics, childAllocate, "Date", value.toISOString());
1710
+ if (types.isDate(value)) {
1711
+ const time = Date.prototype.getTime.call(value);
1712
+ const iso = Number.isFinite(time) ? new Date(time).toISOString() : "Invalid Date";
1713
+ add(metrics, NODE + stringEstimate(iso));
1714
+ return atom("Date", { value: iso });
1715
+ }
1716
+ if (depth >= limits.maxDepth) {
1717
+ add(metrics, NODE + 32);
1718
+ return atom("truncated", { reason: "max_depth" });
1719
+ }
1720
+ if (types.isNativeError(value) || isDomException(value)) {
1721
+ add(metrics, NODE + 32);
1722
+ const name = errorNameOf(value);
1723
+ add(metrics, stringEstimate(name));
1724
+ const message = freezeInner(errorMessageOf(value), depth + 1, path, metrics);
1725
+ const stack = errorStackOf(value);
1726
+ const extras = {};
1727
+ for (const key of ["code", "cause", "statusCode"]) {
1728
+ const slot = ownData(value, key);
1729
+ if (!slot) continue;
1730
+ extras[key] = freezeInner(slot.value, depth + 1, path, metrics);
1731
+ }
1732
+ return atom("Error", {
1733
+ name,
1734
+ message,
1735
+ ...extras,
1736
+ ...stack ? { stack: freezeInner(stack, depth + 1, path, metrics) } : {}
1737
+ });
1198
1738
  }
1199
1739
  if (Buffer2.isBuffer(value)) {
1200
- return writeTypeMarker(metrics, childAllocate, "Buffer", {
1201
- byteLength: value.byteLength,
1202
- base64: value.subarray(0, limits.maxStringLength).toString("base64"),
1203
- ...value.byteLength > limits.maxStringLength ? { __rasputin_truncated: true } : {}
1740
+ const byteLength = bufferByteLength(value);
1741
+ const slice = Buffer2.prototype.subarray.call(value, 0, limits.maxStringLength);
1742
+ const base64 = Buffer2.prototype.toString.call(slice, "base64");
1743
+ add(metrics, NODE + stringEstimate(base64) + 24);
1744
+ return atom("Buffer", {
1745
+ byteLength,
1746
+ base64,
1747
+ ...byteLength > limits.maxStringLength ? { truncated: true } : {}
1204
1748
  });
1205
1749
  }
1206
- if (value instanceof Promise) return writeTypeMarker(metrics, childAllocate, "Promise");
1207
- if (value instanceof Map) {
1208
- const object2 = openObject(metrics, childAllocate);
1209
- writeLiteralField(metrics, object2, "__rasputin_type", "Map");
1210
- beginField(metrics, object2, "entries");
1211
- const entries = openArray(metrics, childAllocate);
1750
+ if (types.isPromise(value)) {
1751
+ add(metrics, NODE + 16);
1752
+ return atom("Promise");
1753
+ }
1754
+ if (types.isMap(value)) {
1755
+ add(metrics, NODE + 16);
1756
+ const entries = [];
1212
1757
  let counted2 = 0;
1213
- for (const entry of value.entries()) {
1214
- if (counted2 >= limits.maxArrayElements) break;
1215
- if (!entries.first) addBytes(metrics, 1);
1216
- entries.first = false;
1217
- addBytes(metrics, 2);
1218
- const key = serializeInner(entry[0], depth + 1, path, childAllocate, metrics);
1219
- addBytes(metrics, 1);
1220
- const mapped = serializeInner(entry[1], depth + 1, path, childAllocate, metrics);
1221
- entries.items?.push([key, mapped]);
1758
+ const mapSize = Object.getOwnPropertyDescriptor(Map.prototype, "size")?.get;
1759
+ const size = mapSize ? mapSize.call(value) : 0;
1760
+ for (const mapKey of Map.prototype.keys.call(value)) {
1761
+ if (counted2 >= limits.maxArrayElements || metrics.oversize) break;
1762
+ const key = freezeInner(mapKey, depth + 1, path, metrics);
1763
+ if (typeof mapKey === "string" && keyIsRedacted(mapKey, redactKeys)) {
1764
+ add(metrics, stringEstimate(REDACTED));
1765
+ entries.push([key, REDACTED]);
1766
+ } else {
1767
+ entries.push([
1768
+ key,
1769
+ freezeInner(Map.prototype.get.call(value, mapKey), depth + 1, path, metrics)
1770
+ ]);
1771
+ }
1222
1772
  counted2++;
1223
1773
  }
1224
- assignField(object2, "entries", entries.items ?? []);
1225
- if (value.size > limits.maxArrayElements) {
1226
- writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1227
- writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1228
- writeLiteralField(metrics, object2, "__original_length", value.size);
1229
- }
1230
- return object2.target;
1774
+ return atom("Map", {
1775
+ entries,
1776
+ ...size > limits.maxArrayElements ? { truncated: true, reason: "max_array_elements", originalLength: size } : {}
1777
+ });
1231
1778
  }
1232
- if (value instanceof Set) {
1233
- const object2 = openObject(metrics, childAllocate);
1234
- writeLiteralField(metrics, object2, "__rasputin_type", "Set");
1235
- beginField(metrics, object2, "values");
1236
- const items = openArray(metrics, childAllocate);
1779
+ if (types.isSet(value)) {
1780
+ add(metrics, NODE + 16);
1781
+ const values = [];
1237
1782
  let counted2 = 0;
1238
- for (const item of value.values()) {
1239
- if (counted2 >= limits.maxArrayElements) break;
1240
- if (!items.first) addBytes(metrics, 1);
1241
- items.first = false;
1242
- const serializedItem = serializeInner(item, depth + 1, path, childAllocate, metrics);
1243
- items.items?.push(serializedItem);
1783
+ const setSize = Object.getOwnPropertyDescriptor(Set.prototype, "size")?.get;
1784
+ const size = setSize ? setSize.call(value) : 0;
1785
+ for (const item of Set.prototype.values.call(value)) {
1786
+ if (counted2 >= limits.maxArrayElements || metrics.oversize) break;
1787
+ values.push(freezeInner(item, depth + 1, path, metrics));
1244
1788
  counted2++;
1245
1789
  }
1246
- assignField(object2, "values", items.items ?? []);
1247
- if (value.size > limits.maxArrayElements) {
1248
- writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1249
- writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1250
- writeLiteralField(metrics, object2, "__original_length", value.size);
1251
- }
1252
- return object2.target;
1790
+ return atom("Set", {
1791
+ values,
1792
+ ...size > limits.maxArrayElements ? { truncated: true, reason: "max_array_elements", originalLength: size } : {}
1793
+ });
1253
1794
  }
1254
1795
  if (Array.isArray(value)) {
1255
- const items = openArray(metrics, childAllocate);
1796
+ add(metrics, 2);
1797
+ const items = [];
1256
1798
  const maxItems = value.length > limits.maxArrayElements ? limits.maxArrayElements - 1 : value.length;
1799
+ let redactNext = false;
1257
1800
  for (let index = 0; index < maxItems; index++) {
1258
- if (!items.first) addBytes(metrics, 1);
1259
- items.first = false;
1260
- items.items?.push(serializeInner(value[index], depth + 1, path, childAllocate, metrics));
1801
+ if (metrics.oversize) break;
1802
+ let descriptor;
1803
+ try {
1804
+ descriptor = Object.getOwnPropertyDescriptor(value, index);
1805
+ } catch {
1806
+ descriptor = void 0;
1807
+ }
1808
+ if (!descriptor) {
1809
+ add(metrics, NODE + 16);
1810
+ items.push(atom("hole"));
1811
+ redactNext = false;
1812
+ continue;
1813
+ }
1814
+ if (!("value" in descriptor)) {
1815
+ add(metrics, NODE + 16);
1816
+ items.push(atom("accessor"));
1817
+ redactNext = false;
1818
+ continue;
1819
+ }
1820
+ if (redactNext) {
1821
+ add(metrics, stringEstimate(REDACTED));
1822
+ items.push(REDACTED);
1823
+ redactNext = false;
1824
+ } else {
1825
+ items.push(freezeInner(descriptor.value, depth + 1, path, metrics));
1826
+ redactNext = typeof descriptor.value === "string" && keyIsRedacted(descriptor.value, redactKeys);
1827
+ }
1261
1828
  }
1262
1829
  if (value.length > limits.maxArrayElements) {
1263
- if (!items.first) addBytes(metrics, 1);
1264
- items.first = false;
1265
- items.items?.push(
1266
- writeTruncation(metrics, childAllocate, "max_array_elements", {
1267
- __original_length: value.length
1830
+ add(metrics, NODE + 32);
1831
+ items.push(
1832
+ atom("truncated", {
1833
+ reason: "max_array_elements",
1834
+ originalLength: value.length
1268
1835
  })
1269
1836
  );
1270
1837
  }
1271
- return items.items;
1838
+ if (items[0] === RASPUTIN_WIRE_TAG) {
1839
+ return atom("instance", { type: "Array", value: { items } });
1840
+ }
1841
+ return items;
1842
+ }
1843
+ if (types.isTypedArray(value)) {
1844
+ const view = value;
1845
+ const byteLength = viewByteLength(view);
1846
+ const sampleLimit = Math.min(32, limits.maxStringLength);
1847
+ let sample = [];
1848
+ try {
1849
+ const buffer = typedArrayBufferGet?.call(view);
1850
+ const byteOffset = typedArrayByteOffsetGet?.call(view);
1851
+ if (buffer) {
1852
+ const bytes = new Uint8Array(
1853
+ buffer,
1854
+ byteOffset ?? 0,
1855
+ Math.min(sampleLimit, byteLength)
1856
+ );
1857
+ sample = sampleBytes(bytes, sampleLimit);
1858
+ }
1859
+ } catch {
1860
+ sample = [];
1861
+ }
1862
+ const typeName2 = typedArrayName(value);
1863
+ add(metrics, NODE + stringEstimate(typeName2) + 48);
1864
+ return atom("instance", {
1865
+ type: typeName2,
1866
+ value: {
1867
+ byteLength,
1868
+ ...sample.length > 0 ? { sample } : {},
1869
+ ...byteLength > sampleLimit ? { truncated: true } : {}
1870
+ }
1871
+ });
1872
+ }
1873
+ if (types.isDataView(value)) {
1874
+ const view = value;
1875
+ const byteLength = viewByteLength(view);
1876
+ add(metrics, NODE + 32);
1877
+ return atom("instance", {
1878
+ type: "DataView",
1879
+ value: { byteLength }
1880
+ });
1881
+ }
1882
+ if (types.isArrayBuffer(value) || types.isSharedArrayBuffer(value)) {
1883
+ const buffer = value;
1884
+ let byteLength = 0;
1885
+ try {
1886
+ byteLength = buffer.byteLength;
1887
+ } catch {
1888
+ byteLength = 0;
1889
+ }
1890
+ add(metrics, NODE + 32);
1891
+ return atom("instance", {
1892
+ type: types.isSharedArrayBuffer(value) ? "SharedArrayBuffer" : "ArrayBuffer",
1893
+ value: { byteLength }
1894
+ });
1895
+ }
1896
+ if (types.isStringObject(value) || types.isNumberObject(value) || types.isBooleanObject(value)) {
1897
+ try {
1898
+ if (types.isStringObject(value)) {
1899
+ return freezeInner(String.prototype.valueOf.call(value), depth, path, metrics);
1900
+ }
1901
+ if (types.isNumberObject(value)) {
1902
+ return freezeInner(Number.prototype.valueOf.call(value), depth, path, metrics);
1903
+ }
1904
+ return freezeInner(Boolean.prototype.valueOf.call(value), depth, path, metrics);
1905
+ } catch {
1906
+ return atom("unserializable");
1907
+ }
1908
+ }
1909
+ add(metrics, 2);
1910
+ const fields = /* @__PURE__ */ Object.create(null);
1911
+ let typeName;
1912
+ let prototype = null;
1913
+ try {
1914
+ prototype = Object.getPrototypeOf(value);
1915
+ } catch {
1916
+ prototype = null;
1917
+ }
1918
+ if (prototype && types.isProxy(prototype)) {
1919
+ add(metrics, NODE + 16);
1920
+ return atom("instance", { type: "Proxy", value: fields });
1272
1921
  }
1273
- const object = openObject(metrics, childAllocate);
1274
- const prototype = Object.getPrototypeOf(value);
1275
1922
  if (prototype && prototype !== Object.prototype) {
1276
- writeLiteralField(
1277
- metrics,
1278
- object,
1279
- "__rasputin_type",
1280
- prototype.constructor?.name ?? "instance"
1281
- );
1923
+ typeName = "instance";
1924
+ if (!types.isProxy(prototype)) {
1925
+ const ctor = ownData(prototype, "constructor")?.value;
1926
+ if (typeof ctor === "function") {
1927
+ const name = functionNameOf(ctor);
1928
+ if (name && name !== "anonymous") typeName = name;
1929
+ }
1930
+ }
1931
+ add(metrics, NODE + stringEstimate(typeName));
1282
1932
  }
1283
- const keys = Object.keys(value);
1284
- const maxKeys = keys.length > limits.maxObjectKeys ? limits.maxObjectKeys - 1 : keys.length;
1933
+ const pairLabel = ownData(value, "name") ?? ownData(value, "key");
1934
+ const pairIsSensitive = pairLabel !== void 0 && typeof pairLabel.value === "string" && keyIsRedacted(pairLabel.value, redactKeys);
1935
+ const { keys, truncated } = ownEnumerableKeys(value, limits.maxObjectKeys);
1936
+ const maxKeys = truncated ? Math.max(0, limits.maxObjectKeys - 1) : keys.length;
1285
1937
  for (let index = 0; index < maxKeys; index++) {
1286
1938
  const key = keys[index];
1287
- if (key === void 0) continue;
1288
- if (isRedactedKey(key)) {
1289
- writeLiteralField(metrics, object, key, REDACTED);
1939
+ if (key === void 0 || metrics.oversize) continue;
1940
+ add(metrics, stringEstimate(key));
1941
+ if (keyIsRedacted(key, redactKeys) || key === "value" && pairIsSensitive) {
1942
+ add(metrics, stringEstimate(REDACTED));
1943
+ assignFrozenField(fields, key, REDACTED);
1290
1944
  continue;
1291
1945
  }
1292
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
1293
- if (descriptor && "value" in descriptor) {
1294
- beginField(metrics, object, key);
1295
- assignField(
1296
- object,
1297
- key,
1298
- serializeInner(descriptor.value, depth + 1, path, childAllocate, metrics)
1299
- );
1946
+ const slot = ownData(value, key);
1947
+ if (slot) {
1948
+ const field = typeof slot.value === "string" && propertyNameLooksLikeUrl(key) ? redactUrlLikeString(slot.value, redactKeys) : slot.value;
1949
+ assignFrozenField(fields, key, freezeInner(field, depth + 1, path, metrics));
1300
1950
  } else {
1301
- beginField(metrics, object, key);
1302
- assignField(object, key, writeTypeMarker(metrics, childAllocate, "accessor"));
1951
+ add(metrics, NODE + 16);
1952
+ assignFrozenField(fields, key, atom("accessor"));
1303
1953
  }
1304
1954
  }
1305
- if (keys.length > limits.maxObjectKeys) {
1306
- writeLiteralField(metrics, object, "__rasputin_truncated", true);
1307
- writeLiteralField(metrics, object, "__reason", "max_object_keys");
1308
- writeLiteralField(metrics, object, "__original_length", keys.length);
1955
+ if (truncated) {
1956
+ return atom("instance", {
1957
+ type: typeName,
1958
+ value: fields,
1959
+ truncated: true,
1960
+ reason: "max_object_keys"
1961
+ });
1309
1962
  }
1310
- return object.target;
1963
+ if (typeName) return atom("instance", { type: typeName, value: fields });
1964
+ return fields;
1311
1965
  } catch (error) {
1312
- metrics.bytes = bytesBefore;
1313
- metrics.oversize = oversizeBefore;
1314
- return writeTypeMarker(
1315
- metrics,
1316
- allocate && !metrics.oversize,
1317
- "unserializable",
1318
- error instanceof Error ? error.message : void 0
1319
- );
1966
+ add(metrics, NODE + 32);
1967
+ return atom("unserializable", {
1968
+ value: error instanceof Error ? error.message : void 0
1969
+ });
1320
1970
  } finally {
1321
1971
  path.delete(value);
1322
1972
  }
1323
1973
  };
1324
- const serializeWithBytes = (value) => {
1325
- const fast = primitiveFastPath(value, limits.maxStringLength);
1326
- if (fast) {
1327
- return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
1328
- }
1329
- const metrics = { visitedNodes: 0, bytes: 0, oversize: false };
1330
- const reentrant = serializing;
1974
+ const freeze = (value) => {
1975
+ const metrics = { visitedNodes: 0, estimatedBytes: 0, oversize: false };
1976
+ const reentrant = freezing;
1331
1977
  const path = reentrant ? /* @__PURE__ */ new Set() : sharedPath;
1332
1978
  if (!reentrant) {
1333
- serializing = true;
1979
+ freezing = true;
1334
1980
  sharedPath.clear();
1335
1981
  }
1336
1982
  try {
1337
- const serialized = serializeInner(value, 0, path, true, metrics);
1338
- if (metrics.bytes > limits.maxSerializedValueBytes) {
1339
- return boundedOversize(metrics.bytes, metrics.visitedNodes);
1983
+ const frozen = freezeInner(value, 0, path, metrics);
1984
+ if (metrics.oversize) {
1985
+ return {
1986
+ value: atom("truncated", {
1987
+ reason: "max_serialized_value_bytes",
1988
+ serializedBytes: metrics.estimatedBytes
1989
+ }),
1990
+ estimatedBytes: metrics.estimatedBytes,
1991
+ visitedNodes: metrics.visitedNodes,
1992
+ oversize: true
1993
+ };
1340
1994
  }
1341
- return { value: serialized, bytes: metrics.bytes, visitedNodes: metrics.visitedNodes };
1995
+ return {
1996
+ value: frozen,
1997
+ estimatedBytes: metrics.estimatedBytes,
1998
+ visitedNodes: metrics.visitedNodes,
1999
+ oversize: false
2000
+ };
1342
2001
  } catch {
1343
- const failed = typeMarker("unserializable");
1344
2002
  return {
1345
- value: failed,
1346
- bytes: jsonLiteralUtf8Bytes(failed),
1347
- visitedNodes: metrics.visitedNodes
2003
+ value: atom("unserializable"),
2004
+ estimatedBytes: NODE + 16,
2005
+ visitedNodes: Math.max(1, metrics.visitedNodes),
2006
+ oversize: false
1348
2007
  };
1349
2008
  } finally {
1350
2009
  path.clear();
1351
- if (!reentrant) serializing = false;
2010
+ if (!reentrant) freezing = false;
2011
+ }
2012
+ };
2013
+ return { freeze, limits };
2014
+ };
2015
+
2016
+ // src/execution-recorder/encode-frozen.ts
2017
+ var typeMarker = (type, value) => ({
2018
+ __rasputin_type: type,
2019
+ ...value === void 0 ? {} : { value }
2020
+ });
2021
+ var truncation = (reason, extra = {}) => ({
2022
+ __rasputin_truncated: true,
2023
+ __reason: reason,
2024
+ ...extra
2025
+ });
2026
+ var taggedNumber = (value) => {
2027
+ if (Number.isNaN(value)) return { __rasputin_type: "NaN" };
2028
+ if (value === Infinity) return { __rasputin_type: "Infinity" };
2029
+ if (value === -Infinity) return { __rasputin_type: "-Infinity" };
2030
+ if (Object.is(value, -0)) return { __rasputin_type: "-0" };
2031
+ return void 0;
2032
+ };
2033
+ var jsonStringUtf8Bytes = (value) => {
2034
+ let bytes = 2;
2035
+ for (let index = 0; index < value.length; index++) {
2036
+ const code = value.charCodeAt(index);
2037
+ if (code === 34 || code === 92) {
2038
+ bytes += 2;
2039
+ continue;
2040
+ }
2041
+ if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
2042
+ bytes += 2;
2043
+ continue;
2044
+ }
2045
+ if (code < 32) {
2046
+ bytes += 6;
2047
+ continue;
2048
+ }
2049
+ if (code < 128) {
2050
+ bytes += 1;
2051
+ continue;
2052
+ }
2053
+ if (code < 2048) {
2054
+ bytes += 2;
2055
+ continue;
2056
+ }
2057
+ if (code >= 55296 && code <= 56319) {
2058
+ const next = value.charCodeAt(index + 1);
2059
+ if (index + 1 < value.length && next >= 56320 && next <= 57343) {
2060
+ bytes += 4;
2061
+ index++;
2062
+ continue;
2063
+ }
2064
+ bytes += 6;
2065
+ continue;
2066
+ }
2067
+ if (code >= 56320 && code <= 57343) {
2068
+ bytes += 6;
2069
+ continue;
2070
+ }
2071
+ bytes += 3;
2072
+ }
2073
+ return bytes;
2074
+ };
2075
+ var ownData2 = (value, key) => {
2076
+ try {
2077
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
2078
+ if (descriptor && "value" in descriptor) return descriptor.value;
2079
+ return void 0;
2080
+ } catch {
2081
+ return void 0;
2082
+ }
2083
+ };
2084
+ var jsonLiteralUtf8Bytes = (value) => {
2085
+ if (value === null) return 4;
2086
+ switch (typeof value) {
2087
+ case "boolean":
2088
+ return value ? 4 : 5;
2089
+ case "number": {
2090
+ const tagged = taggedNumber(value);
2091
+ if (tagged) return jsonLiteralUtf8Bytes(tagged);
2092
+ return String(value).length;
2093
+ }
2094
+ case "string":
2095
+ return jsonStringUtf8Bytes(value);
2096
+ case "object": {
2097
+ if (Array.isArray(value)) {
2098
+ let bytes2 = 2;
2099
+ for (let index = 0; index < value.length; index++) {
2100
+ if (index > 0) bytes2 += 1;
2101
+ bytes2 += jsonLiteralUtf8Bytes(ownData2(value, index));
2102
+ }
2103
+ return bytes2;
2104
+ }
2105
+ const record = value;
2106
+ let bytes = 2;
2107
+ let first = true;
2108
+ for (const key of Object.keys(record)) {
2109
+ if (!first) bytes += 1;
2110
+ first = false;
2111
+ bytes += jsonStringUtf8Bytes(key) + 1;
2112
+ bytes += jsonLiteralUtf8Bytes(ownData2(record, key));
2113
+ }
2114
+ return bytes;
2115
+ }
2116
+ default:
2117
+ return Buffer3.byteLength(JSON.stringify(value) ?? "null", "utf8");
2118
+ }
2119
+ };
2120
+ var BUILTIN_INSTANCE_TYPES = /* @__PURE__ */ new Set([
2121
+ "Uint8Array",
2122
+ "Uint8ClampedArray",
2123
+ "Int8Array",
2124
+ "Uint16Array",
2125
+ "Int16Array",
2126
+ "Uint32Array",
2127
+ "Int32Array",
2128
+ "Float32Array",
2129
+ "Float64Array",
2130
+ "BigUint64Array",
2131
+ "BigInt64Array",
2132
+ "TypedArray",
2133
+ "ArrayBuffer",
2134
+ "SharedArrayBuffer",
2135
+ "DataView",
2136
+ "Proxy"
2137
+ ]);
2138
+ var RESERVED_WIRE_KEYS = /* @__PURE__ */ new Set([
2139
+ "__proto__",
2140
+ "__rasputin_type",
2141
+ "__rasputin_truncated",
2142
+ "__rasputin_fields",
2143
+ "__reason",
2144
+ "__original_length",
2145
+ "__serialized_bytes"
2146
+ ]);
2147
+ var encodePlainObject = (value) => {
2148
+ const record = value;
2149
+ if (typeof record.__rasputin_type === "string") {
2150
+ const encoded2 = /* @__PURE__ */ Object.create(null);
2151
+ for (const key of Object.keys(record)) {
2152
+ if (key === "__proto__") continue;
2153
+ encoded2[key] = encodeFrozen(record[key]);
2154
+ }
2155
+ encoded2.__rasputin_type = record.__rasputin_type;
2156
+ return encoded2;
2157
+ }
2158
+ const encoded = /* @__PURE__ */ Object.create(null);
2159
+ const escaped = [];
2160
+ for (const key of Object.keys(record)) {
2161
+ const encodedValue = encodeFrozen(record[key]);
2162
+ if (key === "__proto__" || RESERVED_WIRE_KEYS.has(key) || key.startsWith("__rasputin_")) {
2163
+ if (key === "__rasputin_fields") {
2164
+ encoded.__rasputin_fields = encodedValue;
2165
+ continue;
2166
+ }
2167
+ escaped.push({ name: key, value: encodedValue });
2168
+ } else {
2169
+ encoded[key] = encodedValue;
2170
+ }
2171
+ }
2172
+ if (escaped.length > 0) {
2173
+ const existing = Array.isArray(encoded.__rasputin_fields) ? encoded.__rasputin_fields : [];
2174
+ encoded.__rasputin_fields = [...existing, ...escaped];
2175
+ }
2176
+ return encoded;
2177
+ };
2178
+ var encodeAtom = (frozen) => {
2179
+ const kind = frozen[FROZEN];
2180
+ switch (kind) {
2181
+ case "undefined":
2182
+ case "NaN":
2183
+ case "Infinity":
2184
+ case "-Infinity":
2185
+ case "-0":
2186
+ case "Proxy":
2187
+ case "circular":
2188
+ case "Promise":
2189
+ case "accessor":
2190
+ case "hole":
2191
+ return typeMarker(kind);
2192
+ case "bigint":
2193
+ case "symbol":
2194
+ case "function":
2195
+ case "Date":
2196
+ return typeMarker(kind, encodeFrozen(frozen.value));
2197
+ case "unserializable":
2198
+ return frozen.value === void 0 ? typeMarker("unserializable") : typeMarker("unserializable", encodeFrozen(frozen.value));
2199
+ case "Error": {
2200
+ const encoded = {
2201
+ __rasputin_type: "Error",
2202
+ name: frozen.name,
2203
+ message: encodeFrozen(frozen.message)
2204
+ };
2205
+ if (frozen.stack !== void 0) encoded.stack = encodeFrozen(frozen.stack);
2206
+ if (frozen.code !== void 0) encoded.code = encodeFrozen(frozen.code);
2207
+ if (frozen.cause !== void 0) encoded.cause = encodeFrozen(frozen.cause);
2208
+ if (frozen.statusCode !== void 0) encoded.statusCode = encodeFrozen(frozen.statusCode);
2209
+ return encoded;
1352
2210
  }
2211
+ case "Buffer":
2212
+ return typeMarker("Buffer", {
2213
+ byteLength: frozen.byteLength,
2214
+ base64: frozen.base64,
2215
+ ...frozen.truncated ? { __rasputin_truncated: true } : {}
2216
+ });
2217
+ case "Map": {
2218
+ const encoded = {
2219
+ __rasputin_type: "Map",
2220
+ entries: encodeFrozen(frozen.entries)
2221
+ };
2222
+ if (frozen.truncated) {
2223
+ encoded.__rasputin_truncated = true;
2224
+ encoded.__reason = frozen.reason;
2225
+ encoded.__original_length = frozen.originalLength;
2226
+ }
2227
+ return encoded;
2228
+ }
2229
+ case "Set": {
2230
+ const encoded = {
2231
+ __rasputin_type: "Set",
2232
+ values: encodeFrozen(frozen.values)
2233
+ };
2234
+ if (frozen.truncated) {
2235
+ encoded.__rasputin_truncated = true;
2236
+ encoded.__reason = frozen.reason;
2237
+ encoded.__original_length = frozen.originalLength;
2238
+ }
2239
+ return encoded;
2240
+ }
2241
+ case "truncated":
2242
+ return truncation(frozen.reason ?? "max_depth", {
2243
+ ...frozen.originalLength === void 0 ? {} : { __original_length: frozen.originalLength },
2244
+ ...frozen.serializedBytes === void 0 ? {} : { __serialized_bytes: frozen.serializedBytes },
2245
+ ...frozen.value === void 0 ? {} : { value: encodeFrozen(frozen.value) }
2246
+ });
2247
+ case "instance": {
2248
+ const fields = typeof frozen.value === "object" && frozen.value !== null && !Array.isArray(frozen.value) ? encodePlainObject(frozen.value) : encodeFrozen(frozen.value);
2249
+ const encoded = /* @__PURE__ */ Object.create(null);
2250
+ if (typeof fields === "object" && fields !== null && !Array.isArray(fields)) {
2251
+ for (const key of Object.keys(fields)) {
2252
+ encoded[key] = fields[key];
2253
+ }
2254
+ }
2255
+ if (frozen.type && BUILTIN_INSTANCE_TYPES.has(frozen.type)) {
2256
+ encoded.__rasputin_type = frozen.type;
2257
+ } else if (frozen.type) {
2258
+ encoded.__rasputin_type = "instance";
2259
+ encoded.__rasputin_class = frozen.type;
2260
+ } else if (!frozen.truncated) {
2261
+ encoded.__rasputin_type = "instance";
2262
+ }
2263
+ if (frozen.truncated) {
2264
+ encoded.__rasputin_truncated = true;
2265
+ encoded.__reason = frozen.reason;
2266
+ if (frozen.originalLength !== void 0) encoded.__original_length = frozen.originalLength;
2267
+ }
2268
+ return encoded;
2269
+ }
2270
+ default:
2271
+ return typeMarker("unserializable");
2272
+ }
2273
+ };
2274
+ var encodeFrozen = (value) => {
2275
+ if (value === REDACTED) return REDACTED;
2276
+ if (isFrozenAtom(value)) return encodeAtom(value);
2277
+ if (Array.isArray(value)) {
2278
+ const items = new Array(value.length);
2279
+ for (let index = 0; index < value.length; index++) {
2280
+ items[index] = encodeFrozen(value[index]);
2281
+ }
2282
+ return items;
2283
+ }
2284
+ if (typeof value === "object" && value !== null) {
2285
+ return encodePlainObject(value);
2286
+ }
2287
+ return value;
2288
+ };
2289
+ var encodeFrozenWithBytes = (frozen, visitedNodes, maxSerializedValueBytes) => {
2290
+ const encoded = encodeFrozen(frozen);
2291
+ if (typeof encoded === "object" && encoded !== null && !Array.isArray(encoded) && encoded.__reason === "max_serialized_value_bytes") {
2292
+ const bytes2 = jsonLiteralUtf8Bytes(encoded);
2293
+ return { value: encoded, bytes: bytes2, visitedNodes };
2294
+ }
2295
+ const bytes = jsonLiteralUtf8Bytes(encoded);
2296
+ if (bytes > maxSerializedValueBytes) {
2297
+ const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
2298
+ return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
2299
+ }
2300
+ return { value: encoded, bytes, visitedNodes };
2301
+ };
2302
+
2303
+ // src/execution-recorder/safe-serialize.ts
2304
+ var createSafeSerializer = (options = {}) => {
2305
+ const freezer = createValueFreezer(options);
2306
+ const serializeWithBytes = (value) => {
2307
+ const frozen = freezer.freeze(value);
2308
+ return encodeFrozenWithBytes(
2309
+ frozen.value,
2310
+ frozen.visitedNodes,
2311
+ freezer.limits.maxSerializedValueBytes
2312
+ );
1353
2313
  };
1354
2314
  return {
2315
+ freeze: freezer.freeze,
2316
+ encode: encodeFrozen,
1355
2317
  serialize: (value) => serializeWithBytes(value).value,
1356
2318
  serializeWithBytes
1357
2319
  };
@@ -1422,9 +2384,40 @@ var createSourceExclusionMatcher = (exclusions) => {
1422
2384
  return matchers.length === 0 ? () => false : (definition) => matchers.some((matcher) => matcher(definition));
1423
2385
  };
1424
2386
 
2387
+ // src/execution-recorder/warn-missing-async-context-frame.ts
2388
+ var ASYNC_CONTEXT_FRAME_FLAG = "--experimental-async-context-frame";
2389
+ var ASYNC_CONTEXT_FRAME_WARNING_SUPPRESS_ENV = "RASPUTIN_SUPPRESS_ASYNC_CONTEXT_FRAME_WARNING";
2390
+ var warnedSymbol = Symbol.for("rasputin.asyncContextFrameWarning");
2391
+ var hasFlag = (execArgv, nodeOptions) => {
2392
+ if (execArgv.includes(ASYNC_CONTEXT_FRAME_FLAG)) return true;
2393
+ if (!nodeOptions) return false;
2394
+ return nodeOptions.split(/\s+/).includes(ASYNC_CONTEXT_FRAME_FLAG);
2395
+ };
2396
+ var missingAsyncContextFrameWarning = (runtime) => {
2397
+ if (runtime.bun || !runtime.node) return void 0;
2398
+ const major = Number(runtime.node.split(".")[0]);
2399
+ if (!Number.isInteger(major) || major >= 24) return void 0;
2400
+ if (hasFlag(runtime.execArgv, runtime.nodeOptions)) return void 0;
2401
+ return `[rasputin] Node.js ${major} is running without ${ASYNC_CONTEXT_FRAME_FLAG}. AsyncLocalStorage is faster with that flag, which is the default on Node.js 24+. Start Node with ${ASYNC_CONTEXT_FRAME_FLAG}, or use Node.js 24 or newer. Set ${ASYNC_CONTEXT_FRAME_WARNING_SUPPRESS_ENV}=1 to hide this warning.`;
2402
+ };
2403
+ var warnIfMissingAsyncContextFrame = () => {
2404
+ if (process.env[ASYNC_CONTEXT_FRAME_WARNING_SUPPRESS_ENV] === "1") return;
2405
+ if (Reflect.get(globalThis, warnedSymbol)) return;
2406
+ const message = missingAsyncContextFrameWarning({
2407
+ bun: process.versions.bun,
2408
+ node: process.versions.node,
2409
+ execArgv: process.execArgv,
2410
+ nodeOptions: process.env.NODE_OPTIONS
2411
+ });
2412
+ if (!message) return;
2413
+ Reflect.set(globalThis, warnedSymbol, true);
2414
+ console.warn(message);
2415
+ };
2416
+
1425
2417
  // src/execution-recorder/execution-recorder.ts
1426
2418
  var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
1427
- var DERIVATION_ROOT_RECORD_BYTES = 64;
2419
+ var DEFAULT_MAX_EXECUTION_HOLD_MS = 6e4;
2420
+ var DEFAULT_MAX_RETAINED_ERROR_RECORDINGS = 32;
1428
2421
  var phaseTimingEnabled = process.env.RASPUTIN_RECORDER_PHASE_TIMING === "1";
1429
2422
  var manualFunctionDefinition = (value) => {
1430
2423
  const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
@@ -1443,72 +2436,39 @@ var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualF
1443
2436
  var elapsedMs2 = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
1444
2437
  var roundedMilliseconds2 = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
1445
2438
  var addRecorderTime = (recording, nanoseconds) => {
1446
- if (nanoseconds > 0n) recording.inlineRecorderTimeNs += nanoseconds;
2439
+ if (process.env.RASPUTIN_RECORDER_PHASE_TIMING !== "1" || nanoseconds <= 0n) return;
2440
+ recording.inlineRecorderTimeNs += nanoseconds;
2441
+ };
2442
+ var mapArrayLike = (args, map) => {
2443
+ const mapped = new Array(args.length);
2444
+ for (let index = 0; index < args.length; index++) {
2445
+ mapped[index] = map(args[index], index);
2446
+ }
2447
+ return mapped;
1447
2448
  };
1448
- var isPromiseLike = (value) => Boolean(value) && typeof value.then === "function";
1449
2449
  var notifyObserver = (observer, value) => {
1450
2450
  try {
1451
2451
  observer(value);
1452
2452
  } catch {
1453
2453
  }
1454
2454
  };
1455
- var observeCallback = (callback, onReturn, onThrow) => {
1456
- let result;
1457
- try {
1458
- result = callback();
1459
- } catch (error) {
1460
- notifyObserver(onThrow, error);
1461
- throw error;
1462
- }
1463
- if (isPromiseLike(result)) {
1464
- return result.then(
1465
- (value) => {
1466
- notifyObserver(onReturn, value);
1467
- return value;
1468
- },
1469
- (error) => {
1470
- notifyObserver(onThrow, error);
1471
- throw error;
1472
- }
1473
- );
1474
- }
1475
- notifyObserver(onReturn, result);
1476
- return result;
1477
- };
1478
- var observeRecordedCallback = (recording, recorderStartedAtNs, callback, onReturn, onThrow) => {
1479
- const callbackStartedAtNs = process.hrtime.bigint();
1480
- const recordExitWork = (callbackEndedAtNs2) => {
2455
+ var observeRecordedCallback = function __rasputinHandleRun__2(recording, recorderStartedAtNs, callback, onReturn, onThrow) {
2456
+ const callbackStartedAtNs = phaseTimingEnabled ? process.hrtime.bigint() : recorderStartedAtNs;
2457
+ const recordExitWork = (callbackEndedAtNs) => {
2458
+ if (!phaseTimingEnabled) return;
1481
2459
  addRecorderTime(recording, callbackStartedAtNs - recorderStartedAtNs);
1482
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2460
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
1483
2461
  };
1484
2462
  let result;
1485
2463
  try {
1486
2464
  result = callback();
1487
2465
  } catch (error) {
1488
- const callbackEndedAtNs2 = process.hrtime.bigint();
1489
2466
  notifyObserver(onThrow, error);
1490
- recordExitWork(callbackEndedAtNs2);
2467
+ recordExitWork(phaseTimingEnabled ? process.hrtime.bigint() : recorderStartedAtNs);
1491
2468
  throw error;
1492
2469
  }
1493
- if (isPromiseLike(result)) {
1494
- return result.then(
1495
- (value) => {
1496
- const callbackEndedAtNs2 = process.hrtime.bigint();
1497
- notifyObserver(onReturn, value);
1498
- recordExitWork(callbackEndedAtNs2);
1499
- return value;
1500
- },
1501
- (error) => {
1502
- const callbackEndedAtNs2 = process.hrtime.bigint();
1503
- notifyObserver(onThrow, error);
1504
- recordExitWork(callbackEndedAtNs2);
1505
- throw error;
1506
- }
1507
- );
1508
- }
1509
- const callbackEndedAtNs = process.hrtime.bigint();
1510
2470
  notifyObserver(onReturn, result);
1511
- recordExitWork(callbackEndedAtNs);
2471
+ recordExitWork(phaseTimingEnabled ? process.hrtime.bigint() : recorderStartedAtNs);
1512
2472
  return result;
1513
2473
  };
1514
2474
  var emptyStats = {
@@ -1538,32 +2498,34 @@ var emptyStats = {
1538
2498
  journalPoolMisses: 0,
1539
2499
  journalPoolSize: 0,
1540
2500
  journalAllocatedCapacity: 0,
1541
- derivationCandidateFunctions: 0,
1542
- derivationElidedFunctionCalls: 0,
1543
- derivationRootsCaptured: 0,
1544
- derivationControlFactsCaptured: 0,
1545
- derivationValuesAvoided: 0,
1546
- derivationFallbackFunctions: 0,
1547
- derivationFallbackExpressions: 0,
1548
- derivationFallbackReasons: {},
1549
- derivationRootBytes: 0
2501
+ attributionDegradations: 0
1550
2502
  };
1551
2503
  var noOpExecution = {
1552
2504
  createScope: () => ({
1553
2505
  run: (callback) => callback(),
1554
2506
  getErrorState: () => void 0,
2507
+ associateError: () => {
2508
+ },
1555
2509
  finish: () => {
1556
2510
  }
1557
2511
  }),
1558
- run: (_metadata, callback) => callback(),
1559
2512
  getErrorState: () => void 0,
1560
2513
  runFunction: (_functionId, _args, callback) => callback(),
1561
2514
  runFunctionPlans: (_plans, _planIndex, _args, callback) => callback(),
1562
2515
  prepareFunctionPlans: () => [],
1563
2516
  runPreparedFunction: (_plan, _args, callback) => callback(),
2517
+ enterPreparedFunction: () => ({
2518
+ leave: (value) => value,
2519
+ fail: () => {
2520
+ },
2521
+ end: () => {
2522
+ },
2523
+ run: (callback) => callback(),
2524
+ suspend: (value) => value,
2525
+ resume: (value) => value
2526
+ }),
1564
2527
  trace: (_functionId, fn) => fn,
1565
- getStats: () => ({ ...emptyStats, derivationFallbackReasons: {} }),
1566
- captureDerivationRoot: (_rootId, value) => value
2528
+ getStats: () => ({ ...emptyStats })
1567
2529
  };
1568
2530
  var mergeExecutionMetadata = (target, metadata) => {
1569
2531
  if (metadata.kind) target.kind = metadata.kind;
@@ -1588,7 +2550,41 @@ var newSuppression = (group, parentCallId, startedAtNs, endedAtNs) => ({
1588
2550
  });
1589
2551
  var createExecutionRecorder = (options) => {
1590
2552
  if (!options?.enabled) return noOpExecution;
2553
+ warnIfMissingAsyncContextFrame();
1591
2554
  const storage = new AsyncLocalStorage();
2555
+ const currentStore = () => {
2556
+ try {
2557
+ return storage.getStore();
2558
+ } catch {
2559
+ return void 0;
2560
+ }
2561
+ };
2562
+ const degradeAttribution = (recording, plan) => {
2563
+ if (!recording.attributionDegraded) {
2564
+ recording.attributionDegraded = true;
2565
+ stats.attributionDegradations++;
2566
+ const eventsDropped = Math.max(
2567
+ 1,
2568
+ recording.journal?.dropped ?? recording.memory.eventsDropped
2569
+ );
2570
+ recording.cachedState = {
2571
+ events: [],
2572
+ functions: [],
2573
+ truncated: { eventsDropped },
2574
+ capture: {
2575
+ completeness: "unavailable",
2576
+ reason: "attribution_invariant",
2577
+ valuesDropped: recording.memory.valuesDropped,
2578
+ eventsDropped
2579
+ }
2580
+ };
2581
+ }
2582
+ if (plan) plan.disabled = true;
2583
+ };
2584
+ const noteDisabledPlan = (recording) => {
2585
+ if (recording.finished || recording.evicted || recording.attributionDegraded) return;
2586
+ recording.disabledPlanEncountered = true;
2587
+ };
1592
2588
  const maxEventsPerExecution = sanitizeJournalCapacity(options.maxEventsPerExecution);
1593
2589
  const maxCapturedCallsPerFunction = Math.max(
1594
2590
  1,
@@ -1598,6 +2594,14 @@ var createExecutionRecorder = (options) => {
1598
2594
  0,
1599
2595
  Math.floor(options.maxActiveMemoryBytes ?? DEFAULT_MAX_ACTIVE_MEMORY_BYTES)
1600
2596
  );
2597
+ const maxExecutionHoldNs = BigInt(Math.max(1, Math.floor(options.maxExecutionHoldMs ?? DEFAULT_MAX_EXECUTION_HOLD_MS))) * 1000000n;
2598
+ const maxRetainedErrorRecordings = Math.max(
2599
+ 1,
2600
+ Math.floor(options.maxRetainedErrorRecordings ?? DEFAULT_MAX_RETAINED_ERROR_RECORDINGS)
2601
+ );
2602
+ const liveRecordings = [];
2603
+ let lastSweepNs = 0n;
2604
+ const sweepIntervalNs = maxExecutionHoldNs / 4n < 50000000n ? maxExecutionHoldNs / 4n : 50000000n;
1601
2605
  const memoryBudget = new RecorderMemoryBudget(
1602
2606
  maxActiveMemoryBytes,
1603
2607
  options.maxSerializedValueBytes ?? 8 * 1024
@@ -1605,12 +2609,17 @@ var createExecutionRecorder = (options) => {
1605
2609
  const serializer = createSafeSerializer(options);
1606
2610
  const excludesSource = createSourceExclusionMatcher(options.excludeSources);
1607
2611
  const journalPool = new ExecutionJournalPool(maxEventsPerExecution);
2612
+ const runtimeStateSizeBudget = {
2613
+ targetBytes: options.runtimeStateTargetBytes,
2614
+ maximumBytes: options.maxRuntimeStateBytes
2615
+ };
1608
2616
  const plansByRuntimeId = [];
1609
2617
  let executionCounter = 0;
1610
2618
  let nextRuntimePlanId = 1;
1611
2619
  const internedPlans = /* @__PURE__ */ new Map();
1612
2620
  const preparedModules = /* @__PURE__ */ new WeakMap();
1613
2621
  const errorExecutions = /* @__PURE__ */ new WeakMap();
2622
+ const retainedErrorRecordings = [];
1614
2623
  const phases = phaseTimingEnabled ? { alsNs: 0n, materializeNs: 0n } : void 0;
1615
2624
  const stats = {
1616
2625
  functionCallsObserved: 0,
@@ -1629,15 +2638,7 @@ var createExecutionRecorder = (options) => {
1629
2638
  measuredExecutions: 0,
1630
2639
  totalInlineWallTimeMs: 0,
1631
2640
  maxInlineWallTimeMs: 0,
1632
- derivationCandidateFunctions: 0,
1633
- derivationElidedFunctionCalls: 0,
1634
- derivationRootsCaptured: 0,
1635
- derivationControlFactsCaptured: 0,
1636
- derivationValuesAvoided: 0,
1637
- derivationFallbackFunctions: 0,
1638
- derivationFallbackExpressions: 0,
1639
- derivationFallbackReasons: {},
1640
- derivationRootBytes: 0
2641
+ attributionDegradations: 0
1641
2642
  };
1642
2643
  const addPhase = (key, nanoseconds) => {
1643
2644
  if (phases && nanoseconds > 0n) phases[key] += nanoseconds;
@@ -1648,14 +2649,36 @@ var createExecutionRecorder = (options) => {
1648
2649
  stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
1649
2650
  stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
1650
2651
  };
1651
- const serializeAndCount = (value) => {
1652
- const serialized = serializer.serializeWithBytes(value);
2652
+ const freezeAndCount = (value) => {
2653
+ const frozen = serializer.freeze(value);
1653
2654
  stats.serializedValues++;
1654
- stats.serializedValueNodes += serialized.visitedNodes;
1655
- stats.serializedValueBytes += serialized.bytes;
1656
- return serialized;
2655
+ stats.serializedValueNodes += frozen.visitedNodes;
2656
+ stats.serializedValueBytes += frozen.estimatedBytes;
2657
+ return {
2658
+ value: frozen.value,
2659
+ bytes: frozen.estimatedBytes,
2660
+ visitedNodes: frozen.visitedNodes
2661
+ };
2662
+ };
2663
+ const captureValue = (recording, value) => {
2664
+ try {
2665
+ return memoryBudget.captureValue(recording.memory, () => freezeAndCount(value));
2666
+ } catch {
2667
+ return { __rasputin_type: "unserializable" };
2668
+ }
1657
2669
  };
1658
- const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => serializeAndCount(value));
2670
+ const encodeEventValues = (events) => events.map((event) => {
2671
+ if (event.type === "function_enter") {
2672
+ return { ...event, args: event.args.map((argument) => serializer.encode(argument)) };
2673
+ }
2674
+ if (event.type === "function_exit") {
2675
+ return { ...event, returnValue: serializer.encode(event.returnValue) };
2676
+ }
2677
+ if (event.type === "function_throw") {
2678
+ return { ...event, error: serializer.encode(event.error) };
2679
+ }
2680
+ return event;
2681
+ });
1659
2682
  const storePlan = (plan) => {
1660
2683
  plansByRuntimeId[plan.runtimePlanId] = plan;
1661
2684
  return plan;
@@ -1668,7 +2691,8 @@ var createExecutionRecorder = (options) => {
1668
2691
  definition,
1669
2692
  functionId: definition.functionId,
1670
2693
  excluded: excludesSource(definition),
1671
- estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
2694
+ estimatedCallBytes: estimatedCallBytesFor(definition.functionId),
2695
+ omitCallValues: false
1672
2696
  });
1673
2697
  internedPlans.set(definition.functionId, plan);
1674
2698
  return plan;
@@ -1683,28 +2707,13 @@ var createExecutionRecorder = (options) => {
1683
2707
  definition,
1684
2708
  functionId: definition.functionId,
1685
2709
  excluded: excludesSource(definition),
1686
- estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
2710
+ estimatedCallBytes: estimatedCallBytesFor(definition.functionId),
2711
+ omitCallValues: encodedPlanOmitsCallValues(encoded)
1687
2712
  });
1688
2713
  });
1689
2714
  preparedModules.set(plans, prepared);
1690
2715
  return prepared;
1691
2716
  };
1692
- const derivationMetrics = (recording) => {
1693
- const manifest = snapshotInstrumentationManifest();
1694
- const plans = manifest?.derivationPlans ?? [];
1695
- const reasons = { ...stats.derivationFallbackReasons };
1696
- return {
1697
- derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
1698
- derivationElidedFunctionCalls: stats.derivationElidedFunctionCalls,
1699
- derivationRootsCaptured: recording.derivationRoots.length,
1700
- derivationControlFactsCaptured: stats.derivationControlFactsCaptured,
1701
- derivationValuesAvoided: stats.derivationValuesAvoided,
1702
- derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
1703
- derivationFallbackExpressions: recording.derivationRoots.length,
1704
- derivationFallbackReasons: reasons,
1705
- derivationRootBytes: recording.derivationRootBytes
1706
- };
1707
- };
1708
2717
  const eventsHaveOmittedValues = (events) => {
1709
2718
  for (const event of events) {
1710
2719
  if (event.type === "function_enter" && event.args.some((arg) => rasputinTagKind(arg) === "omitted")) {
@@ -1716,37 +2725,46 @@ var createExecutionRecorder = (options) => {
1716
2725
  }
1717
2726
  return false;
1718
2727
  };
1719
- const resolveCaptureProfile = (recording, events, truncated, capture, derivation) => {
2728
+ const resolveCaptureProfile = (recording, events, truncated, capture) => {
1720
2729
  const source = recording.sawAutomatic ? "automatic" : recording.sawManual ? "manual" : "scope-only";
1721
2730
  if (source === "scope-only") {
1722
2731
  return {
1723
2732
  source,
1724
2733
  functionBoundaries: "none",
1725
2734
  functionValues: "none",
1726
- timings: "none",
1727
- derivation: derivation ? "available" : "none"
2735
+ timings: "none"
1728
2736
  };
1729
2737
  }
1730
- const droppedEvents = Boolean(truncated?.eventsDropped || capture?.eventsDropped);
1731
- return {
1732
- source,
1733
- functionBoundaries: droppedEvents ? "partial" : "full",
1734
- functionValues: eventsHaveOmittedValues(events) ? "selective" : "full",
1735
- timings: droppedEvents ? "partial" : "full",
1736
- derivation: derivation ? "available" : "none"
1737
- };
1738
- };
1739
- const derivationCapture = (recording) => {
1740
- const manifest = snapshotInstrumentationManifest();
1741
- if (!manifest) return void 0;
1742
- const plans = manifest.derivationPlans ?? [];
1743
- if (!plans.some((plan) => recording.executedFunctionIds.has(plan.functionId))) {
1744
- return void 0;
2738
+ if (recording.evicted || capture?.completeness === "unavailable") {
2739
+ return {
2740
+ source,
2741
+ functionBoundaries: "none",
2742
+ functionValues: "none",
2743
+ timings: "none"
2744
+ };
2745
+ }
2746
+ if (recording.budgetExpired || capture?.reason === "long_lived_execution_budget") {
2747
+ return {
2748
+ source,
2749
+ functionBoundaries: events.length > 0 ? "partial" : "none",
2750
+ functionValues: events.length > 0 ? "selective" : "none",
2751
+ timings: events.length > 0 ? "partial" : "none"
2752
+ };
2753
+ }
2754
+ if (capture?.reason === "plan_disabled_after_attribution_invariant") {
2755
+ return {
2756
+ source,
2757
+ functionBoundaries: events.length > 0 ? "partial" : "none",
2758
+ functionValues: eventsHaveOmittedValues(events) ? "selective" : events.length > 0 ? "full" : "none",
2759
+ timings: events.length > 0 ? "partial" : "none"
2760
+ };
1745
2761
  }
2762
+ const droppedEvents = Boolean(truncated?.eventsDropped || capture?.eventsDropped);
1746
2763
  return {
1747
- manifestHash: hashInstrumentationManifest(manifest),
1748
- roots: recording.derivationRoots.slice(),
1749
- controlFacts: []
2764
+ source,
2765
+ functionBoundaries: droppedEvents ? "partial" : "full",
2766
+ functionValues: eventsHaveOmittedValues(events) ? "selective" : "full",
2767
+ timings: droppedEvents ? "partial" : "full"
1750
2768
  };
1751
2769
  };
1752
2770
  const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
@@ -1755,40 +2773,58 @@ var createExecutionRecorder = (options) => {
1755
2773
  let functions = [];
1756
2774
  let truncated;
1757
2775
  let capture;
1758
- let derivation;
1759
2776
  if (recording.cachedState) {
1760
2777
  events = recording.cachedState.events;
1761
2778
  functions = recording.cachedState.functions;
1762
2779
  truncated = recording.cachedState.truncated;
1763
2780
  capture = recording.cachedState.capture;
1764
- derivation = recording.cachedState.derivation;
1765
2781
  } else {
1766
2782
  if (recording.journal) {
1767
2783
  const materialized = recording.journal.materialize(plansByRuntimeId, recording.startedAtNs);
1768
- events = materialized.events;
2784
+ events = encodeEventValues(materialized.events);
2785
+ if (recording.lateCapturedCallIds && recording.lateCapturedCallIds.size > 0) {
2786
+ events = events.map(
2787
+ (event) => event.type === "function_enter" && recording.lateCapturedCallIds?.has(event.callId) ? { ...event, capturedAt: "throw" } : event
2788
+ );
2789
+ }
1769
2790
  functions = materialized.functions;
1770
2791
  truncated = recording.journal.dropped > 0 ? { eventsDropped: recording.journal.dropped } : void 0;
1771
2792
  }
1772
- capture = recording.memory.underPressure ? {
1773
- completeness: "partial",
1774
- reason: "process_memory_budget",
1775
- valuesDropped: recording.memory.valuesDropped,
1776
- eventsDropped: recording.memory.eventsDropped
1777
- } : void 0;
1778
- derivation = derivationCapture(recording);
2793
+ if (recording.budgetExpired) {
2794
+ capture = {
2795
+ completeness: "partial",
2796
+ reason: "long_lived_execution_budget",
2797
+ valuesDropped: recording.memory.valuesDropped,
2798
+ eventsDropped: recording.memory.eventsDropped
2799
+ };
2800
+ } else if (recording.disabledPlanEncountered) {
2801
+ capture = {
2802
+ completeness: "partial",
2803
+ reason: "plan_disabled_after_attribution_invariant",
2804
+ valuesDropped: recording.memory.valuesDropped,
2805
+ eventsDropped: recording.memory.eventsDropped
2806
+ };
2807
+ } else if (recording.memory.underPressure) {
2808
+ capture = {
2809
+ completeness: "partial",
2810
+ reason: "process_memory_budget",
2811
+ valuesDropped: recording.memory.valuesDropped,
2812
+ eventsDropped: recording.memory.eventsDropped
2813
+ };
2814
+ }
1779
2815
  if (recording.finished && recording.inFlightCalls === 0 && recording.journal) {
1780
- recording.cachedState = { events, functions, truncated, capture, derivation };
2816
+ recording.cachedState = { events, functions, truncated, capture };
1781
2817
  journalPool.release(recording.journal);
1782
2818
  recording.journal = void 0;
1783
2819
  }
1784
2820
  }
1785
2821
  const state = {
1786
2822
  version: 4,
1787
- captureProfile: resolveCaptureProfile(recording, events, truncated, capture, derivation),
2823
+ captureProfile: resolveCaptureProfile(recording, events, truncated, capture),
1788
2824
  executionId: recording.executionId,
1789
2825
  startedAt: recording.startedAt,
1790
2826
  durationMs: elapsedMs2(recording.startedAtNs, endedAtNs),
1791
- recorder: { inlineWallTimeMs: 0, derivation: derivationMetrics(recording) },
2827
+ recorder: { inlineWallTimeMs: 0 },
1792
2828
  execution: {
1793
2829
  ...recording.execution,
1794
2830
  ...recording.execution.request ? { request: { ...recording.execution.request } } : {}
@@ -1796,29 +2832,153 @@ var createExecutionRecorder = (options) => {
1796
2832
  functions: functions.slice(),
1797
2833
  events: events.slice(),
1798
2834
  ...truncated ? { truncated: { ...truncated } } : {},
1799
- ...capture ? { capture: { ...capture } } : {},
1800
- ...derivation ? { derivation: { ...derivation, roots: derivation.roots.slice() } } : {}
2835
+ ...capture ? { capture: { ...capture } } : {}
1801
2836
  };
1802
2837
  if (phaseTimingEnabled)
1803
2838
  addPhase("materializeNs", process.hrtime.bigint() - recorderStartedAtNs);
1804
- addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
2839
+ const sizeBudgetStartedAtNs = process.hrtime.bigint();
2840
+ addRecorderTime(recording, sizeBudgetStartedAtNs - recorderStartedAtNs);
1805
2841
  state.recorder = {
1806
- inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs),
1807
- derivation: derivationMetrics(recording)
2842
+ inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs)
2843
+ };
2844
+ const boundedState = enforceRuntimeStateSizeBudget(state, runtimeStateSizeBudget);
2845
+ addRecorderTime(recording, process.hrtime.bigint() - sizeBudgetStartedAtNs);
2846
+ boundedState.recorder = {
2847
+ inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs)
2848
+ };
2849
+ return boundedState.truncated?.size ? enforceRuntimeStateSizeBudget(boundedState, runtimeStateSizeBudget) : boundedState;
2850
+ };
2851
+ const evictRetainedRecording = (recording) => {
2852
+ const eventCount = recording.cachedState?.events.length ?? recording.journal?.eventCount ?? 0;
2853
+ const dropped = (recording.cachedState?.truncated?.eventsDropped ?? recording.journal?.dropped ?? 0) + eventCount;
2854
+ try {
2855
+ memoryBudget.release(recording.memory);
2856
+ } catch {
2857
+ }
2858
+ if (recording.journal) {
2859
+ journalPool.release(recording.journal);
2860
+ recording.journal = void 0;
2861
+ }
2862
+ recording.evicted = true;
2863
+ detachLiveRecording(recording);
2864
+ recording.cachedState = {
2865
+ events: [],
2866
+ functions: [],
2867
+ truncated: { eventsDropped: Math.max(1, dropped) },
2868
+ capture: {
2869
+ completeness: "unavailable",
2870
+ reason: "retained_state_evicted",
2871
+ valuesDropped: 0,
2872
+ eventsDropped: Math.max(1, dropped)
2873
+ }
2874
+ };
2875
+ };
2876
+ const trimFinishedRetainedRecordings = (keep) => {
2877
+ while (retainedErrorRecordings.length > maxRetainedErrorRecordings) {
2878
+ const evictIndex = retainedErrorRecordings.findIndex(
2879
+ (candidate) => candidate !== keep && candidate.finished
2880
+ );
2881
+ if (evictIndex < 0) break;
2882
+ const [evicted] = retainedErrorRecordings.splice(evictIndex, 1);
2883
+ if (evicted) evictRetainedRecording(evicted);
2884
+ }
2885
+ };
2886
+ const retainErrorRecording = (recording) => {
2887
+ if (recording.retainedForError) return;
2888
+ recording.retainedForError = true;
2889
+ retainedErrorRecordings.push(recording);
2890
+ trimFinishedRetainedRecordings(recording);
2891
+ };
2892
+ const detachLiveRecording = (recording) => {
2893
+ const index = liveRecordings.indexOf(recording);
2894
+ if (index >= 0) liveRecordings.splice(index, 1);
2895
+ };
2896
+ const expireLongLivedRecording = (recording, nowNs) => {
2897
+ if (recording.evicted || recording.budgetExpired) return;
2898
+ recording.budgetExpired = true;
2899
+ recording.memory.underPressure = true;
2900
+ const journalEvents = recording.journal?.eventCount ?? 0;
2901
+ const cachedEvents = recording.cachedState?.events.length ?? 0;
2902
+ const eventsDropped = Math.max(
2903
+ 1,
2904
+ recording.memory.eventsDropped + journalEvents + cachedEvents
2905
+ );
2906
+ try {
2907
+ memoryBudget.release(recording.memory);
2908
+ } catch {
2909
+ }
2910
+ if (recording.journal) {
2911
+ journalPool.release(recording.journal);
2912
+ recording.journal = void 0;
2913
+ }
2914
+ recording.cachedState = {
2915
+ events: [],
2916
+ functions: [],
2917
+ truncated: { eventsDropped },
2918
+ capture: {
2919
+ completeness: "partial",
2920
+ reason: "long_lived_execution_budget",
2921
+ valuesDropped: recording.memory.valuesDropped,
2922
+ eventsDropped
2923
+ }
1808
2924
  };
1809
- return state;
2925
+ if (!recording.finished) {
2926
+ recording.finished = true;
2927
+ stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
2928
+ recording.finishedAtNs = nowNs;
2929
+ if (!recording.hasError) {
2930
+ stats.successfulExecutionsDiscarded++;
2931
+ }
2932
+ }
2933
+ detachLiveRecording(recording);
2934
+ };
2935
+ const sweepLongLivedExecutions = (nowNs) => {
2936
+ if (nowNs - lastSweepNs < sweepIntervalNs && liveRecordings.length < 256) return;
2937
+ lastSweepNs = nowNs;
2938
+ for (let index = liveRecordings.length - 1; index >= 0; index--) {
2939
+ const recording = liveRecordings[index];
2940
+ if (!recording) continue;
2941
+ if (recording.evicted || recording.memory.released || recording.budgetExpired) {
2942
+ liveRecordings.splice(index, 1);
2943
+ continue;
2944
+ }
2945
+ if (nowNs - recording.startedAtNs < maxExecutionHoldNs) continue;
2946
+ try {
2947
+ expireLongLivedRecording(recording, nowNs);
2948
+ } catch {
2949
+ }
2950
+ }
1810
2951
  };
1811
2952
  const rememberError = (error, recording) => {
1812
2953
  recording.hasError = true;
1813
- if (typeof error !== "object" && typeof error !== "function" || error === null) return;
1814
- if (!errorExecutions.has(error)) {
2954
+ const key = (typeof error === "object" || typeof error === "function") && error !== null ? error : void 0;
2955
+ if (recording.budgetExpired && !(key && errorExecutions.has(key))) {
2956
+ const eventsDropped = Math.max(
2957
+ 1,
2958
+ recording.cachedState?.capture?.eventsDropped ?? recording.cachedState?.truncated?.eventsDropped ?? recording.memory.eventsDropped
2959
+ );
2960
+ recording.cachedState = {
2961
+ events: [],
2962
+ functions: [],
2963
+ truncated: { eventsDropped },
2964
+ capture: {
2965
+ completeness: "unavailable",
2966
+ reason: "long_lived_execution_budget",
2967
+ valuesDropped: recording.memory.valuesDropped,
2968
+ eventsDropped
2969
+ }
2970
+ };
2971
+ }
2972
+ retainErrorRecording(recording);
2973
+ if (!key) return;
2974
+ if (!errorExecutions.has(key)) {
1815
2975
  stats.errorSnapshots++;
1816
2976
  if (recording.memory.underPressure && !recording.partialSnapshotCounted) {
1817
2977
  recording.partialSnapshotCounted = true;
1818
2978
  stats.partialErrorSnapshots++;
1819
2979
  }
1820
2980
  }
1821
- errorExecutions.set(error, recording);
2981
+ errorExecutions.set(key, recording);
1822
2982
  };
1823
2983
  const countDroppedEvents = (recording, droppedBefore) => {
1824
2984
  const dropped = recording.journal?.dropped ?? droppedBefore;
@@ -1868,13 +3028,19 @@ var createExecutionRecorder = (options) => {
1868
3028
  return {
1869
3029
  // Keep the bounded thrown value even after surrounding capture degrades. A partial
1870
3030
  // snapshot without the exception itself would not be useful for investigation.
1871
- value: serializeAndCount(error).value,
3031
+ value: (() => {
3032
+ try {
3033
+ return freezeAndCount(error).value;
3034
+ } catch {
3035
+ return { __rasputin_type: "unserializable" };
3036
+ }
3037
+ })(),
1872
3038
  commit: () => {
1873
3039
  if (key) recording.capturedErrors.set(key, callId);
1874
3040
  }
1875
3041
  };
1876
3042
  };
1877
- const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
3043
+ const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error, capturedArgs) => {
1878
3044
  if (!recording.journal) {
1879
3045
  rememberError(error, recording);
1880
3046
  return;
@@ -1885,7 +3051,7 @@ var createExecutionRecorder = (options) => {
1885
3051
  }
1886
3052
  const callId = ++recording.nextCallId;
1887
3053
  const capturedError = serializedError(recording, error, callId);
1888
- const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
3054
+ const recordedArgs = capturedArgs ?? mapArrayLike(args, (argument) => captureValue(recording, argument));
1889
3055
  const endedAtNs = process.hrtime.bigint();
1890
3056
  const droppedBefore = recording.journal.dropped;
1891
3057
  const retained = recording.journal.forceCompletedCall(
@@ -1893,13 +3059,15 @@ var createExecutionRecorder = (options) => {
1893
3059
  callId,
1894
3060
  parentCallId,
1895
3061
  startedAtNs - recording.startedAtNs,
1896
- capturedArgs,
3062
+ recordedArgs,
1897
3063
  KIND_THROW,
1898
3064
  endedAtNs - recording.startedAtNs,
1899
3065
  endedAtNs - startedAtNs,
1900
3066
  capturedError.value
1901
3067
  );
1902
3068
  if (retained) {
3069
+ recording.lateCapturedCallIds ??= /* @__PURE__ */ new Set();
3070
+ recording.lateCapturedCallIds.add(callId);
1903
3071
  stats.functionCallsCaptured++;
1904
3072
  capturedError.commit();
1905
3073
  }
@@ -1944,35 +3112,47 @@ var createExecutionRecorder = (options) => {
1944
3112
  };
1945
3113
  const settleInFlight = (recording) => {
1946
3114
  if (recording.inFlightCalls > 0) recording.inFlightCalls--;
1947
- releaseJournalIfIdle(recording);
3115
+ releaseWhenIdle(recording);
1948
3116
  };
1949
- const finish = (store, metadata) => {
1950
- const { recording } = store;
1951
- if (recording.finished) return;
1952
- const recorderStartedAtNs = process.hrtime.bigint();
1953
- recording.finished = true;
1954
- if (metadata) mergeExecutionMetadata(recording.execution, metadata);
1955
- memoryBudget.release(recording.memory);
1956
- stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
1957
- if (!recording.hasError) {
1958
- stats.successfulExecutionsDiscarded++;
3117
+ const releaseWhenIdle = (recording) => {
3118
+ try {
3119
+ if (!recording.finished || recording.inFlightCalls > 0) return;
3120
+ memoryBudget.release(recording.memory);
1959
3121
  releaseJournalIfIdle(recording);
3122
+ } catch {
1960
3123
  }
1961
- recording.finishedAtNs = process.hrtime.bigint();
1962
- addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
1963
- recordInlineTiming(recording);
1964
3124
  };
1965
- const runStore = (store, callback) => {
3125
+ const finish = (store, metadata) => {
3126
+ try {
3127
+ const { recording } = store;
3128
+ if (recording.finished) return;
3129
+ const recorderStartedAtNs = process.hrtime.bigint();
3130
+ recording.finished = true;
3131
+ if (metadata) mergeExecutionMetadata(recording.execution, metadata);
3132
+ stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
3133
+ if (!recording.hasError) {
3134
+ stats.successfulExecutionsDiscarded++;
3135
+ }
3136
+ recording.finishedAtNs = process.hrtime.bigint();
3137
+ addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
3138
+ recordInlineTiming(recording);
3139
+ releaseWhenIdle(recording);
3140
+ if (recording.inFlightCalls === 0) detachLiveRecording(recording);
3141
+ } catch {
3142
+ }
3143
+ };
3144
+ const runStore = function __rasputinHandleRun__3(store, callback) {
1966
3145
  if (!phaseTimingEnabled) return storage.run(store, callback);
1967
3146
  const alsStartedAtNs = process.hrtime.bigint();
1968
- return storage.run(store, () => {
3147
+ return storage.run(store, function __rasputinHandleRun__4() {
1969
3148
  addPhase("alsNs", process.hrtime.bigint() - alsStartedAtNs);
1970
3149
  return callback();
1971
3150
  });
1972
3151
  };
1973
3152
  const createScope = (metadata) => {
1974
- const recorderStartedAtNs = process.hrtime.bigint();
1975
3153
  try {
3154
+ const recorderStartedAtNs = process.hrtime.bigint();
3155
+ sweepLongLivedExecutions(recorderStartedAtNs);
1976
3156
  const recording = {
1977
3157
  executionId: `${Date.now()}-${process.pid}-${++executionCounter}`,
1978
3158
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1991,30 +3171,52 @@ var createExecutionRecorder = (options) => {
1991
3171
  hasError: false,
1992
3172
  memory: memoryBudget.startExecution(),
1993
3173
  partialSnapshotCounted: false,
1994
- derivationRoots: [],
1995
- derivationRootBytes: 0,
1996
3174
  sawAutomatic: false,
1997
- sawManual: false,
1998
- executedFunctionIds: /* @__PURE__ */ new Set()
3175
+ sawManual: false
1999
3176
  };
2000
3177
  stats.activeExecutions++;
2001
3178
  stats.peakActiveExecutions = Math.max(stats.peakActiveExecutions, stats.activeExecutions);
3179
+ liveRecordings.push(recording);
2002
3180
  addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
2003
3181
  const store = { recording };
2004
3182
  return {
2005
- run: (callback) => {
2006
- const runStartedAtNs = process.hrtime.bigint();
2007
- return runStore(store, () => {
2008
- addRecorderTime(recording, process.hrtime.bigint() - runStartedAtNs);
3183
+ run: function __rasputinHandleRun__3(callback) {
3184
+ let startedCallback = false;
3185
+ try {
3186
+ const runStartedAtNs = process.hrtime.bigint();
3187
+ return runStore(store, function __rasputinHandleRun__4() {
3188
+ startedCallback = true;
3189
+ addRecorderTime(recording, process.hrtime.bigint() - runStartedAtNs);
3190
+ try {
3191
+ return callback();
3192
+ } catch (error) {
3193
+ if (recording.budgetExpired || recording.evicted) {
3194
+ rememberError(error, recording);
3195
+ }
3196
+ throw error;
3197
+ }
3198
+ });
3199
+ } catch (error) {
3200
+ if (startedCallback) throw error;
2009
3201
  return callback();
2010
- });
3202
+ }
2011
3203
  },
2012
3204
  getErrorState: (error, errorMetadata) => {
2013
- const getStateStartedAtNs = process.hrtime.bigint();
2014
- if (errorMetadata) mergeExecutionMetadata(recording.execution, errorMetadata);
2015
- rememberError(error, recording);
2016
- addRecorderTime(recording, process.hrtime.bigint() - getStateStartedAtNs);
2017
- return stateFrom(recording, recording.finishedAtNs);
3205
+ try {
3206
+ const getStateStartedAtNs = process.hrtime.bigint();
3207
+ if (errorMetadata) mergeExecutionMetadata(recording.execution, errorMetadata);
3208
+ rememberError(error, recording);
3209
+ addRecorderTime(recording, process.hrtime.bigint() - getStateStartedAtNs);
3210
+ return stateFrom(recording, recording.finishedAtNs);
3211
+ } catch {
3212
+ return void 0;
3213
+ }
3214
+ },
3215
+ associateError: (error) => {
3216
+ try {
3217
+ rememberError(error, recording);
3218
+ } catch {
3219
+ }
2018
3220
  },
2019
3221
  finish: (finishMetadata) => finish(store, finishMetadata)
2020
3222
  };
@@ -2022,32 +3224,11 @@ var createExecutionRecorder = (options) => {
2022
3224
  return noOpExecution.createScope(metadata);
2023
3225
  }
2024
3226
  };
2025
- const run = (metadata, callback) => {
2026
- const scope = createScope(metadata);
2027
- return scope.run(
2028
- () => observeCallback(
2029
- callback,
2030
- () => scope.finish(),
2031
- (error) => {
2032
- try {
2033
- const store = storage.getStore();
2034
- if (store) {
2035
- const recorderStartedAtNs = process.hrtime.bigint();
2036
- rememberError(error, store.recording);
2037
- addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
2038
- }
2039
- } finally {
2040
- scope.finish();
2041
- }
2042
- }
2043
- )
2044
- );
2045
- };
2046
3227
  const getErrorState = (error, metadata) => {
2047
3228
  const getStateStartedAtNs = process.hrtime.bigint();
2048
3229
  try {
2049
3230
  const weakKey = (typeof error === "object" || typeof error === "function") && error !== null ? error : void 0;
2050
- const recording = (weakKey ? errorExecutions.get(weakKey) : void 0) ?? storage.getStore()?.recording;
3231
+ const recording = (weakKey ? errorExecutions.get(weakKey) : void 0) ?? currentStore()?.recording;
2051
3232
  if (!recording) return void 0;
2052
3233
  if (metadata) mergeExecutionMetadata(recording.execution, metadata);
2053
3234
  rememberError(error, recording);
@@ -2057,14 +3238,46 @@ var createExecutionRecorder = (options) => {
2057
3238
  return void 0;
2058
3239
  }
2059
3240
  };
2060
- const runPreparedFunction = (plan, args, callback, omitValues) => {
2061
- const store = storage.getStore();
2062
- if (!store || store.recording.finished) return callback();
3241
+ const runPreparedFunctionFromStore = function __rasputinHandleRun__3(store, plan, args, callback, omitValues) {
3242
+ let startedCallback = false;
3243
+ try {
3244
+ return runPreparedFunctionFromStoreInner(
3245
+ store,
3246
+ plan,
3247
+ args,
3248
+ function __rasputinHandleRun__4() {
3249
+ startedCallback = true;
3250
+ return callback();
3251
+ },
3252
+ omitValues
3253
+ );
3254
+ } catch (error) {
3255
+ if (startedCallback) throw error;
3256
+ return callback();
3257
+ }
3258
+ };
3259
+ const runPreparedFunctionFromStoreInner = function __rasputinHandleRun__3(store, plan, args, callback, omitValues) {
3260
+ const omitCallValues = omitValues === true || plan.omitCallValues;
3261
+ if (!store) return callback();
3262
+ if (plan.disabled) {
3263
+ noteDisabledPlan(store.recording);
3264
+ return callback();
3265
+ }
3266
+ if (store.recording.finished) {
3267
+ try {
3268
+ return callback();
3269
+ } catch (error) {
3270
+ if (store.recording.budgetExpired || store.recording.evicted) {
3271
+ rememberError(error, store.recording);
3272
+ }
3273
+ throw error;
3274
+ }
3275
+ }
2063
3276
  stats.functionCallsObserved++;
2064
3277
  const recorderStartedAtNs = process.hrtime.bigint();
2065
3278
  if (store.suppressCapture || plan.excluded) {
2066
3279
  stats.functionCallsExcluded++;
2067
- return runStore({ ...store, suppressCapture: true }, () => {
3280
+ return runStore({ ...store, suppressCapture: true }, function __rasputinHandleRun__4() {
2068
3281
  addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
2069
3282
  return callback();
2070
3283
  });
@@ -2075,41 +3288,21 @@ var createExecutionRecorder = (options) => {
2075
3288
  const group = repeatedCallGroup(recording, plan, parentCallId);
2076
3289
  group.observedCalls++;
2077
3290
  const journal = acquireJournal(recording);
2078
- if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
3291
+ try {
3292
+ if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
3293
+ } catch {
3294
+ }
2079
3295
  if (group.observedCalls > maxCapturedCallsPerFunction) {
2080
3296
  const startedAtNs2 = process.hrtime.bigint();
2081
3297
  try {
2082
- const result = callback();
2083
- if (isPromiseLike(result)) {
2084
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2085
- return result.then(
2086
- (value) => {
2087
- const callbackEndedAtNs2 = process.hrtime.bigint();
2088
- recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs2);
2089
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2090
- settleInFlight(recording);
2091
- return value;
2092
- },
2093
- (error) => {
2094
- const callbackEndedAtNs2 = process.hrtime.bigint();
2095
- captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
2096
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2097
- settleInFlight(recording);
2098
- throw error;
2099
- }
2100
- );
2101
- }
2102
- const callbackEndedAtNs = process.hrtime.bigint();
2103
- recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs);
2104
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2105
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
3298
+ const result = runStore(store, function __rasputinHandleRun__4() {
3299
+ return callback();
3300
+ });
3301
+ recordSuppressedCall(recording, group, parentCallId, startedAtNs2, process.hrtime.bigint());
2106
3302
  settleInFlight(recording);
2107
3303
  return result;
2108
3304
  } catch (error) {
2109
- const callbackEndedAtNs = process.hrtime.bigint();
2110
3305
  captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
2111
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2112
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
2113
3306
  settleInFlight(recording);
2114
3307
  throw error;
2115
3308
  }
@@ -2117,9 +3310,8 @@ var createExecutionRecorder = (options) => {
2117
3310
  const startedAtNs = process.hrtime.bigint();
2118
3311
  if (!journal) {
2119
3312
  memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
2120
- return runStore(
2121
- store,
2122
- () => observeRecordedCallback(
3313
+ return runStore(store, function __rasputinHandleRun__4() {
3314
+ return observeRecordedCallback(
2123
3315
  recording,
2124
3316
  recorderStartedAtNs,
2125
3317
  callback,
@@ -2128,8 +3320,8 @@ var createExecutionRecorder = (options) => {
2128
3320
  rememberError(error, recording);
2129
3321
  settleInFlight(recording);
2130
3322
  }
2131
- )
2132
- );
3323
+ );
3324
+ });
2133
3325
  }
2134
3326
  if (!journal.canStartCall()) {
2135
3327
  const captureSuccess = () => {
@@ -2138,9 +3330,8 @@ var createExecutionRecorder = (options) => {
2138
3330
  countDroppedEvents(recording, droppedBefore);
2139
3331
  settleInFlight(recording);
2140
3332
  };
2141
- return runStore(
2142
- store,
2143
- () => observeRecordedCallback(
3333
+ return runStore(store, function __rasputinHandleRun__4() {
3334
+ return observeRecordedCallback(
2144
3335
  recording,
2145
3336
  recorderStartedAtNs,
2146
3337
  callback,
@@ -2149,8 +3340,8 @@ var createExecutionRecorder = (options) => {
2149
3340
  captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
2150
3341
  settleInFlight(recording);
2151
3342
  }
2152
- )
2153
- );
3343
+ );
3344
+ });
2154
3345
  }
2155
3346
  if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
2156
3347
  return observeRecordedCallback(
@@ -2166,12 +3357,27 @@ var createExecutionRecorder = (options) => {
2166
3357
  }
2167
3358
  const callId = ++recording.nextCallId;
2168
3359
  const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
2169
- const capturedArgs = omitValues ? Array.from(args, () => rasputinOmitted()) : Array.from(args, (argument) => captureValue(recording, argument));
2170
- journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
3360
+ const capturedArgs = omitCallValues ? mapArrayLike(args, () => rasputinOmitted()) : mapArrayLike(args, (argument) => captureValue(recording, argument));
3361
+ try {
3362
+ journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
3363
+ } catch {
3364
+ journal.dropCall();
3365
+ return runStore(store, function __rasputinHandleRun__4() {
3366
+ return observeRecordedCallback(
3367
+ recording,
3368
+ recorderStartedAtNs,
3369
+ callback,
3370
+ () => settleInFlight(recording),
3371
+ (error) => {
3372
+ rememberError(error, recording);
3373
+ settleInFlight(recording);
3374
+ }
3375
+ );
3376
+ });
3377
+ }
2171
3378
  const callStore = { recording, currentCallId: callId };
2172
- return runStore(
2173
- callStore,
2174
- () => observeRecordedCallback(
3379
+ return runStore(callStore, function __rasputinHandleRun__4() {
3380
+ return observeRecordedCallback(
2175
3381
  recording,
2176
3382
  recorderStartedAtNs,
2177
3383
  callback,
@@ -2179,7 +3385,7 @@ var createExecutionRecorder = (options) => {
2179
3385
  if (recording.journal) {
2180
3386
  const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
2181
3387
  const durationNs = process.hrtime.bigint() - startedAtNs;
2182
- const returnValue = omitValues ? rasputinOmitted() : captureValue(recording, value);
3388
+ const returnValue = omitCallValues ? rasputinOmitted() : captureValue(recording, value);
2183
3389
  recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
2184
3390
  stats.functionCallsCaptured++;
2185
3391
  }
@@ -2204,113 +3410,519 @@ var createExecutionRecorder = (options) => {
2204
3410
  rememberError(error, recording);
2205
3411
  settleInFlight(recording);
2206
3412
  }
2207
- )
2208
- );
3413
+ );
3414
+ });
3415
+ };
3416
+ const noopHandle2 = {
3417
+ leave: (value) => value,
3418
+ fail: () => {
3419
+ },
3420
+ end: () => {
3421
+ },
3422
+ run: function __rasputinHandleRun__3(callback) {
3423
+ return runExactlyOnce((invoke) => invoke(), callback);
3424
+ },
3425
+ suspend: (value) => value,
3426
+ resume: (value) => value
3427
+ };
3428
+ const bindStoreTransitions = (active, parent, recording, plan) => {
3429
+ let suspended = false;
3430
+ const enter = (next) => {
3431
+ try {
3432
+ storage.enterWith(next);
3433
+ } catch {
3434
+ degradeAttribution(recording, plan);
3435
+ }
3436
+ };
3437
+ const expectStore = (expected) => {
3438
+ if (currentStore() !== expected) degradeAttribution(recording, plan);
3439
+ };
3440
+ return {
3441
+ enterActive: () => enter(active),
3442
+ run: function __rasputinHandleRun__3(callback) {
3443
+ return runExactlyOnce((invoke) => {
3444
+ try {
3445
+ enter(parent);
3446
+ } catch {
3447
+ }
3448
+ return storage.run(active, invoke);
3449
+ }, callback);
3450
+ },
3451
+ suspend: (value) => {
3452
+ expectStore(active);
3453
+ suspended = true;
3454
+ enter(parent);
3455
+ return value;
3456
+ },
3457
+ resume: (value) => {
3458
+ if (suspended) {
3459
+ expectStore(parent);
3460
+ suspended = false;
3461
+ enter(active);
3462
+ } else {
3463
+ expectStore(active);
3464
+ }
3465
+ return value;
3466
+ },
3467
+ restore: () => {
3468
+ expectStore(active);
3469
+ enter(parent);
3470
+ }
3471
+ };
3472
+ };
3473
+ const enterPreparedFunctionFromStore = (store, plan, args, omitValues) => {
3474
+ if (!store) return noopHandle2;
3475
+ if (plan.disabled) {
3476
+ noteDisabledPlan(store.recording);
3477
+ return noopHandle2;
3478
+ }
3479
+ if (store.recording.finished) {
3480
+ if (!store.recording.budgetExpired && !store.recording.evicted) return noopHandle2;
3481
+ const expired = store.recording;
3482
+ const expiredStore = { recording: expired };
3483
+ return {
3484
+ leave: (value) => value,
3485
+ fail: (error) => {
3486
+ rememberError(error, expired);
3487
+ },
3488
+ end: () => {
3489
+ },
3490
+ run: function __rasputinHandleRun__3(callback) {
3491
+ return runExactlyOnce((invoke) => storage.run(expiredStore, invoke), callback);
3492
+ },
3493
+ suspend: (value) => value,
3494
+ resume: (value) => value
3495
+ };
3496
+ }
3497
+ stats.functionCallsObserved++;
3498
+ const recording = store.recording;
3499
+ const omitCallValues = omitValues === true || plan.omitCallValues;
3500
+ const parentCallId = store.currentCallId;
3501
+ if (store.suppressCapture || plan.excluded) {
3502
+ stats.functionCallsExcluded++;
3503
+ const excludedStore = { ...store, suppressCapture: true };
3504
+ const excluded = bindStoreTransitions(excludedStore, store, recording, plan);
3505
+ excluded.enterActive();
3506
+ let ended2 = false;
3507
+ return {
3508
+ leave: (value) => value,
3509
+ fail: () => {
3510
+ },
3511
+ end: () => {
3512
+ if (ended2) return;
3513
+ ended2 = true;
3514
+ excluded.restore();
3515
+ },
3516
+ run: excluded.run,
3517
+ suspend: excluded.suspend,
3518
+ resume: excluded.resume
3519
+ };
3520
+ }
3521
+ recording.inFlightCalls++;
3522
+ const group = repeatedCallGroup(recording, plan, parentCallId);
3523
+ group.observedCalls++;
3524
+ const journal = acquireJournal(recording);
3525
+ try {
3526
+ if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
3527
+ } catch {
3528
+ }
3529
+ let status = "open";
3530
+ let pendingReturn;
3531
+ let ended = false;
3532
+ const startedAtNs = process.hrtime.bigint();
3533
+ const parentStore = store;
3534
+ const uncaptured = bindStoreTransitions(parentStore, parentStore, recording, plan);
3535
+ const finishEnd = () => {
3536
+ if (ended) return;
3537
+ ended = true;
3538
+ settleInFlight(recording);
3539
+ uncaptured.restore();
3540
+ };
3541
+ const context = {
3542
+ run: uncaptured.run,
3543
+ suspend: uncaptured.suspend,
3544
+ resume: uncaptured.resume
3545
+ };
3546
+ if (group.observedCalls > maxCapturedCallsPerFunction) {
3547
+ uncaptured.enterActive();
3548
+ return {
3549
+ leave: (value) => {
3550
+ if (status !== "failed") {
3551
+ status = "left";
3552
+ pendingReturn = value;
3553
+ }
3554
+ return value;
3555
+ },
3556
+ fail: (error, liveArgs) => {
3557
+ if (status === "failed") return;
3558
+ status = "failed";
3559
+ captureCompletedThrow(
3560
+ recording,
3561
+ plan,
3562
+ liveArgs ?? args,
3563
+ parentCallId,
3564
+ startedAtNs,
3565
+ error
3566
+ );
3567
+ },
3568
+ end: () => {
3569
+ if (status !== "failed") {
3570
+ recordSuppressedCall(
3571
+ recording,
3572
+ group,
3573
+ parentCallId,
3574
+ startedAtNs,
3575
+ process.hrtime.bigint()
3576
+ );
3577
+ }
3578
+ finishEnd();
3579
+ },
3580
+ ...context
3581
+ };
3582
+ }
3583
+ const dropWithoutCapture = (onThrow) => {
3584
+ uncaptured.enterActive();
3585
+ return {
3586
+ leave: (value) => {
3587
+ if (status !== "failed") {
3588
+ status = "left";
3589
+ pendingReturn = value;
3590
+ }
3591
+ return value;
3592
+ },
3593
+ fail: (error) => {
3594
+ if (status === "failed") return;
3595
+ status = "failed";
3596
+ onThrow(error);
3597
+ },
3598
+ end: () => {
3599
+ if (status !== "failed") {
3600
+ const droppedBefore = recording.journal?.dropped ?? 0;
3601
+ recording.journal?.dropCall();
3602
+ countDroppedEvents(recording, droppedBefore);
3603
+ }
3604
+ finishEnd();
3605
+ },
3606
+ ...context
3607
+ };
3608
+ };
3609
+ if (!journal) {
3610
+ memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
3611
+ uncaptured.enterActive();
3612
+ return {
3613
+ leave: (value) => {
3614
+ if (status !== "failed") {
3615
+ status = "left";
3616
+ pendingReturn = value;
3617
+ }
3618
+ return value;
3619
+ },
3620
+ fail: (error) => {
3621
+ if (status === "failed") return;
3622
+ status = "failed";
3623
+ rememberError(error, recording);
3624
+ },
3625
+ end: finishEnd,
3626
+ ...context
3627
+ };
3628
+ }
3629
+ if (!journal.canStartCall()) {
3630
+ return dropWithoutCapture((error) => {
3631
+ captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
3632
+ });
3633
+ }
3634
+ if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
3635
+ uncaptured.enterActive();
3636
+ return {
3637
+ leave: (value) => {
3638
+ if (status !== "failed") {
3639
+ status = "left";
3640
+ pendingReturn = value;
3641
+ }
3642
+ return value;
3643
+ },
3644
+ fail: (error) => {
3645
+ if (status === "failed") return;
3646
+ status = "failed";
3647
+ rememberError(error, recording);
3648
+ },
3649
+ end: finishEnd,
3650
+ ...context
3651
+ };
3652
+ }
3653
+ const callId = ++recording.nextCallId;
3654
+ const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
3655
+ const capturedArgs = omitCallValues ? mapArrayLike(args, () => rasputinOmitted()) : mapArrayLike(args, (argument) => captureValue(recording, argument));
3656
+ try {
3657
+ journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
3658
+ } catch {
3659
+ journal.dropCall();
3660
+ return dropWithoutCapture((error) => rememberError(error, recording));
3661
+ }
3662
+ const callStore = { recording, currentCallId: callId };
3663
+ const captured = bindStoreTransitions(callStore, parentStore, recording, plan);
3664
+ captured.enterActive();
3665
+ const writeExit = (value) => {
3666
+ if (!recording.journal) return;
3667
+ const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
3668
+ const durationNs = process.hrtime.bigint() - startedAtNs;
3669
+ const returnValue = omitCallValues ? rasputinOmitted() : captureValue(recording, value);
3670
+ recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
3671
+ stats.functionCallsCaptured++;
3672
+ };
3673
+ const writeThrow = (error) => {
3674
+ if (!recording.journal) {
3675
+ rememberError(error, recording);
3676
+ return;
3677
+ }
3678
+ const capturedError = serializedError(recording, error, callId);
3679
+ recording.journal.finishCall(
3680
+ KIND_THROW,
3681
+ callId,
3682
+ process.hrtime.bigint() - recording.startedAtNs,
3683
+ process.hrtime.bigint() - startedAtNs,
3684
+ capturedError.value
3685
+ );
3686
+ stats.functionCallsCaptured++;
3687
+ capturedError.commit();
3688
+ rememberError(error, recording);
3689
+ };
3690
+ return {
3691
+ leave: (value) => {
3692
+ if (status !== "failed") {
3693
+ status = "left";
3694
+ pendingReturn = value;
3695
+ }
3696
+ return value;
3697
+ },
3698
+ fail: (error) => {
3699
+ if (status === "failed") return;
3700
+ status = "failed";
3701
+ try {
3702
+ writeThrow(error);
3703
+ } catch {
3704
+ rememberError(error, recording);
3705
+ }
3706
+ },
3707
+ end: () => {
3708
+ try {
3709
+ if (status !== "failed") writeExit(status === "left" ? pendingReturn : void 0);
3710
+ } catch {
3711
+ }
3712
+ if (ended) return;
3713
+ ended = true;
3714
+ settleInFlight(recording);
3715
+ captured.restore();
3716
+ },
3717
+ run: captured.run,
3718
+ suspend: captured.suspend,
3719
+ resume: captured.resume
3720
+ };
3721
+ };
3722
+ const runPreparedFunction = (plan, args, callback, omitValues) => {
3723
+ const store = currentStore();
3724
+ if (store && !store.recording.finished && !store.recording.sawAutomatic) {
3725
+ store.recording.sawAutomatic = true;
3726
+ }
3727
+ return runPreparedFunctionFromStore(store, plan, args, callback, omitValues);
3728
+ };
3729
+ const isolateHandle2 = (handle) => ({
3730
+ leave: (value) => {
3731
+ try {
3732
+ return handle.leave(value);
3733
+ } catch {
3734
+ return value;
3735
+ }
3736
+ },
3737
+ fail: (error, liveArgs) => {
3738
+ try {
3739
+ handle.fail(error, liveArgs);
3740
+ } catch {
3741
+ }
3742
+ },
3743
+ end: () => {
3744
+ try {
3745
+ handle.end();
3746
+ } catch {
3747
+ }
3748
+ },
3749
+ run: function __rasputinHandleRun__3(callback) {
3750
+ return runExactlyOnce((invoke) => handle.run(invoke), callback);
3751
+ },
3752
+ suspend: (value) => {
3753
+ try {
3754
+ return handle.suspend(value);
3755
+ } catch {
3756
+ return value;
3757
+ }
3758
+ },
3759
+ resume: (value) => {
3760
+ try {
3761
+ return handle.resume(value);
3762
+ } catch {
3763
+ return value;
3764
+ }
3765
+ }
3766
+ });
3767
+ const enterPreparedFunction = (plan, args, omitValues) => {
3768
+ try {
3769
+ const store = currentStore();
3770
+ if (store && !store.recording.finished && !store.recording.sawAutomatic) {
3771
+ store.recording.sawAutomatic = true;
3772
+ }
3773
+ return isolateHandle2(enterPreparedFunctionFromStore(store, plan, args, omitValues));
3774
+ } catch {
3775
+ return noopHandle2;
3776
+ }
2209
3777
  };
2210
3778
  const runFunction = (input, args, callback) => {
2211
- const store = storage.getStore();
3779
+ const store = currentStore();
2212
3780
  if (store && !store.recording.finished) store.recording.sawManual = true;
2213
- return runPreparedFunction(preparePlan(normalizeFunctionDefinition(input)), args, callback);
3781
+ return runPreparedFunctionFromStore(
3782
+ store,
3783
+ preparePlan(normalizeFunctionDefinition(input)),
3784
+ args,
3785
+ callback
3786
+ );
2214
3787
  };
2215
3788
  const runFunctionPlans = (plans, planIndex, args, callback, omitValues) => {
2216
- const store = storage.getStore();
3789
+ const store = currentStore();
2217
3790
  const plan = preparedPlansFor(plans)[planIndex];
2218
- if (store && !store.recording.finished) {
3791
+ if (store && !store.recording.finished && !store.recording.sawAutomatic) {
2219
3792
  store.recording.sawAutomatic = true;
2220
- if (plan) store.recording.executedFunctionIds.add(plan.functionId);
2221
3793
  }
2222
- return plan ? runPreparedFunction(plan, args, callback, omitValues) : callback();
3794
+ return plan ? runPreparedFunctionFromStore(store, plan, args, callback, omitValues) : callback();
2223
3795
  };
2224
3796
  const prepareFunctionPlans = (plans) => preparedPlansFor(plans);
2225
3797
  function trace(input, fn) {
2226
3798
  const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
2227
3799
  const plan = preparePlan(definition);
2228
- return function traced(...args) {
2229
- const store = storage.getStore();
3800
+ return function __rasputinHandleRun__3(...args) {
3801
+ if (new.target) {
3802
+ throw new TypeError("execution.trace() wraps function calls, not constructors");
3803
+ }
3804
+ const receiver = this;
3805
+ const store = currentStore();
2230
3806
  if (store && !store.recording.finished) store.recording.sawManual = true;
2231
- return runPreparedFunction(plan, args, () => fn.apply(this, args));
3807
+ return runPreparedFunctionFromStore(store, plan, args, function __rasputinHandleRun__4() {
3808
+ return fn.apply(receiver, args);
3809
+ });
2232
3810
  };
2233
3811
  }
2234
- const captureDerivationRoot = (rootId, value) => {
2235
- const store = storage.getStore();
2236
- if (!store || store.recording.finished || store.suppressCapture) return value;
2237
- const recording = store.recording;
2238
- if (recording.memory.mode !== "full") return value;
2239
- if (recording.derivationRoots.length >= maxEventsPerExecution) return value;
2240
- const recorderStartedAtNs = process.hrtime.bigint();
2241
- try {
2242
- const serialized = captureValue(recording, value);
2243
- if (recording.memory.mode !== "full") return value;
2244
- if (!memoryBudget.reserveStorage(recording.memory, DERIVATION_ROOT_RECORD_BYTES)) {
2245
- return value;
2246
- }
2247
- const completeness = capturedValueCompleteness(serialized);
2248
- const bytes = jsonLiteralUtf8Bytes(serialized);
2249
- recording.derivationRoots.push({
2250
- rootId,
2251
- callId: store.currentCallId ?? 0,
2252
- value: serialized,
2253
- completeness
2254
- });
2255
- recording.derivationRootBytes += bytes;
2256
- stats.derivationRootsCaptured++;
2257
- stats.derivationRootBytes += bytes;
2258
- stats.derivationFallbackExpressions++;
2259
- return value;
2260
- } finally {
2261
- addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
2262
- }
2263
- };
2264
3812
  return {
2265
3813
  createScope,
2266
- run,
2267
3814
  getErrorState,
2268
3815
  runFunction,
2269
3816
  runFunctionPlans,
2270
3817
  prepareFunctionPlans,
2271
3818
  runPreparedFunction,
3819
+ enterPreparedFunction,
2272
3820
  trace,
2273
- captureDerivationRoot,
2274
- getStats: () => {
2275
- const manifest = snapshotInstrumentationManifest();
2276
- const plans = manifest?.derivationPlans ?? [];
2277
- return {
2278
- ...stats,
2279
- ...memoryBudget.getStats(),
2280
- ...journalPool.stats(),
2281
- derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
2282
- derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
2283
- derivationFallbackReasons: { ...stats.derivationFallbackReasons },
2284
- ...phases ? {
2285
- phaseAlsNs: Number(phases.alsNs),
2286
- phaseMaterializeNs: Number(phases.materializeNs)
2287
- } : {}
2288
- };
2289
- }
3821
+ getStats: () => ({
3822
+ ...stats,
3823
+ ...memoryBudget.getStats(),
3824
+ ...journalPool.stats(),
3825
+ ...phases ? {
3826
+ phaseAlsNs: Number(phases.alsNs),
3827
+ phaseMaterializeNs: Number(phases.materializeNs)
3828
+ } : {}
3829
+ })
2290
3830
  };
2291
3831
  };
2292
3832
 
2293
3833
  // src/execution-recorder/automatic-runtime.ts
2294
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
3834
+ var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v3";
2295
3835
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
2296
- var passthroughCapture = (_rootId, value) => value;
2297
- var passthrough = (_planIndex, _args, callback) => callback();
3836
+ var passthroughHandle = () => ({
3837
+ leave: (value) => value,
3838
+ fail: () => {
3839
+ },
3840
+ end: () => {
3841
+ },
3842
+ run: function __rasputinHandleRun__3(callback) {
3843
+ return runExactlyOnce((invoke) => invoke(), callback);
3844
+ },
3845
+ suspend: (value) => value,
3846
+ resume: (value) => value
3847
+ });
3848
+ var isolateHandle = (handle) => ({
3849
+ leave: (value) => {
3850
+ try {
3851
+ return handle.leave(value);
3852
+ } catch {
3853
+ return value;
3854
+ }
3855
+ },
3856
+ fail: (error, liveArgs) => {
3857
+ try {
3858
+ handle.fail(error, liveArgs);
3859
+ } catch {
3860
+ }
3861
+ },
3862
+ end: () => {
3863
+ try {
3864
+ handle.end();
3865
+ } catch {
3866
+ }
3867
+ },
3868
+ run: function __rasputinHandleRun__3(callback) {
3869
+ return runExactlyOnce((invoke) => handle.run(invoke), callback);
3870
+ },
3871
+ suspend: (value) => {
3872
+ try {
3873
+ return handle.suspend(value);
3874
+ } catch {
3875
+ return value;
3876
+ }
3877
+ },
3878
+ resume: (value) => {
3879
+ try {
3880
+ return handle.resume(value);
3881
+ } catch {
3882
+ return value;
3883
+ }
3884
+ }
3885
+ });
3886
+ var passthroughRun = (_planIndex, _args, callback) => callback();
3887
+ var passthroughEnter = () => passthroughHandle();
2298
3888
  var bindPassthrough = (module) => {
2299
- module.cell.run = passthrough;
3889
+ module.cell.run = passthroughRun;
3890
+ module.cell.enter = passthroughEnter;
3891
+ };
3892
+ var attachRunner = (cell) => {
3893
+ const run = ((planIndex, args, callback, omitValues) => cell.run(planIndex, args, callback, omitValues));
3894
+ run.enter = (planIndex, args, omitValues) => cell.enter(planIndex, args, omitValues);
3895
+ return run;
3896
+ };
3897
+ var bindExecution = (execution, module) => {
3898
+ const prepared = execution.prepareFunctionPlans(module.plans);
3899
+ module.cell.run = (planIndex, args, callback, omitValues) => {
3900
+ const plan = prepared[planIndex];
3901
+ return plan ? execution.runPreparedFunction(plan, args, callback, omitValues) : callback();
3902
+ };
3903
+ module.cell.enter = (planIndex, args, omitValues) => {
3904
+ try {
3905
+ const plan = prepared[planIndex];
3906
+ return isolateHandle(
3907
+ plan ? execution.enterPreparedFunction(plan, args, omitValues) : passthroughEnter(planIndex, args, omitValues)
3908
+ );
3909
+ } catch {
3910
+ return passthroughHandle();
3911
+ }
3912
+ };
2300
3913
  };
2301
3914
  var isRegistry = (value) => Array.isArray(Reflect.get(value, "runtimes")) && Array.isArray(Reflect.get(value, "modules")) && typeof Reflect.get(value, "register") === "function";
2302
3915
  var registerModule = (registry, plans) => {
2303
- const cell = { run: passthrough };
3916
+ const cell = { run: passthroughRun, enter: passthroughEnter };
2304
3917
  const module = { plans, cell };
2305
3918
  registry.modules.push(module);
2306
3919
  registry.runtimes.at(-1)?.bind(module);
2307
- return (planIndex, args, callback, omitValues) => cell.run(planIndex, args, callback, omitValues);
3920
+ return attachRunner(cell);
2308
3921
  };
2309
3922
  var createRegistry = () => {
2310
3923
  const registry = {
2311
3924
  runtimes: [],
2312
3925
  modules: [],
2313
- captureRoot: passthroughCapture,
2314
3926
  register(plans) {
2315
3927
  return registerModule(registry, plans);
2316
3928
  }
@@ -2320,9 +3932,6 @@ var createRegistry = () => {
2320
3932
  var getAutomaticRuntimeRegistry = () => {
2321
3933
  const existing = Reflect.get(globalThis, runtimeSymbol);
2322
3934
  if (existing && typeof existing === "object" && isRegistry(existing)) {
2323
- if (typeof existing.captureRoot !== "function") {
2324
- existing.captureRoot = passthroughCapture;
2325
- }
2326
3935
  return existing;
2327
3936
  }
2328
3937
  const registry = createRegistry();
@@ -2333,18 +3942,15 @@ var installAutomaticExecutionRuntime = (execution) => {
2333
3942
  const registry = getAutomaticRuntimeRegistry();
2334
3943
  const runtime = {
2335
3944
  bind(module) {
2336
- module.cell.run = (planIndex, args, callback, omitValues) => execution.runFunctionPlans(module.plans, planIndex, args, callback, omitValues);
2337
- },
2338
- captureRoot: (rootId, value) => execution.captureDerivationRoot(rootId, value)
3945
+ bindExecution(execution, module);
3946
+ }
2339
3947
  };
2340
3948
  registry.runtimes.push(runtime);
2341
- registry.captureRoot = runtime.captureRoot;
2342
3949
  for (const module of registry.modules) runtime.bind(module);
2343
3950
  return () => {
2344
3951
  const index = registry.runtimes.lastIndexOf(runtime);
2345
3952
  if (index >= 0) registry.runtimes.splice(index, 1);
2346
3953
  const current = registry.runtimes.at(-1);
2347
- registry.captureRoot = current?.captureRoot ?? passthroughCapture;
2348
3954
  for (const module of registry.modules) {
2349
3955
  if (current) current.bind(module);
2350
3956
  else bindPassthrough(module);
@@ -2353,117 +3959,234 @@ var installAutomaticExecutionRuntime = (execution) => {
2353
3959
  };
2354
3960
 
2355
3961
  // src/install-global-handlers.ts
3962
+ var RASPUTIN_PROCESS_LISTENER = Symbol.for("rasputin.process.listener.v1");
3963
+ var unhandledRejectionMode = () => {
3964
+ const tokens = [
3965
+ ...process.execArgv,
3966
+ ...(process.env.NODE_OPTIONS?.match(/(?:[^\s"]+|"[^"]*")+/g) ?? []).map(
3967
+ (token) => token.replace(/^"|"$/g, "")
3968
+ )
3969
+ ];
3970
+ for (let index = tokens.length - 1; index >= 0; index--) {
3971
+ const token = tokens[index];
3972
+ if (!token) continue;
3973
+ if (token.startsWith("--unhandled-rejections="))
3974
+ return token.slice("--unhandled-rejections=".length);
3975
+ if (token === "--unhandled-rejections") return tokens[index + 1] ?? "";
3976
+ }
3977
+ return "throw";
3978
+ };
3979
+ var isBun = typeof process.versions.bun === "string";
3980
+ var unhandledRejectionIsFatal = () => {
3981
+ const mode = unhandledRejectionMode();
3982
+ return mode === "throw" || mode === "strict";
3983
+ };
3984
+ var printDiagnostic = (error) => {
3985
+ if (error instanceof Error) {
3986
+ console.error(error.stack ?? `${error.name}: ${error.message}`);
3987
+ return;
3988
+ }
3989
+ console.error(error);
3990
+ };
2356
3991
  var removeProcessListener = process.off.bind(process);
2357
- var installGlobalHandlers = (client, options = {}) => {
2358
- const exitOnUncaught = options.exitOnUncaughtException ?? true;
2359
- const flushTimeoutMs = options.flushTimeoutMs ?? 2e3;
2360
- let handlingUncaught = false;
2361
- const onUnhandledRejection = (reason) => {
3992
+ var tagListener = (listener) => {
3993
+ Object.defineProperty(listener, RASPUTIN_PROCESS_LISTENER, { value: true });
3994
+ return listener;
3995
+ };
3996
+ var hostListenerCount = (event) => {
3997
+ const listeners = event === "uncaughtException" ? process.listeners("uncaughtException") : process.listeners("unhandledRejection");
3998
+ return listeners.filter((listener) => !(RASPUTIN_PROCESS_LISTENER in listener)).length;
3999
+ };
4000
+ var registered = [];
4001
+ var uninstallProcess;
4002
+ var handlingUncaught = false;
4003
+ var captureOnAll = (error) => {
4004
+ for (const entry of registered) {
2362
4005
  try {
2363
- client.captureException(reason);
4006
+ entry.client.captureException(error);
2364
4007
  } catch {
2365
4008
  }
2366
- };
2367
- const onUncaughtException = (error) => {
4009
+ }
4010
+ };
4011
+ var flushAll = async (timeoutMs) => {
4012
+ await Promise.all(
4013
+ registered.map(
4014
+ (entry) => entry.client.flush(timeoutMs).catch(() => {
4015
+ })
4016
+ )
4017
+ );
4018
+ };
4019
+ var installSharedListeners = () => {
4020
+ if (uninstallProcess) return;
4021
+ const onUnhandledRejection = tagListener((reason) => {
4022
+ captureOnAll(reason);
4023
+ if (hostListenerCount("unhandledRejection") > 0) return;
4024
+ const mode = unhandledRejectionMode();
4025
+ if (mode !== "none") printDiagnostic(reason);
4026
+ if (mode === "warn-with-error-code") process.exitCode = 1;
4027
+ });
4028
+ const onUncaughtException = tagListener((error, origin) => {
4029
+ const exitOnUncaught = registered.some((entry) => entry.exitOnUncaught);
4030
+ const flushTimeoutMs = registered.reduce(
4031
+ (max, entry) => Math.max(max, entry.flushTimeoutMs),
4032
+ 2e3
4033
+ );
2368
4034
  if (handlingUncaught) {
2369
- process.exit(1);
4035
+ if (exitOnUncaught && hostListenerCount("uncaughtException") === 0) {
4036
+ process.exit(1);
4037
+ }
2370
4038
  return;
2371
4039
  }
2372
4040
  handlingUncaught = true;
2373
- try {
2374
- client.captureException(error);
2375
- } catch {
2376
- }
2377
- const soleListener = process.listenerCount("uncaughtException") <= 1;
4041
+ captureOnAll(error);
4042
+ const hostOwns = hostListenerCount("uncaughtException") > 0;
4043
+ const shouldExit = exitOnUncaught && !hostOwns && !(isBun && origin === "unhandledRejection");
4044
+ if (!hostOwns) printDiagnostic(error);
4045
+ if (shouldExit) process.exitCode = 1;
2378
4046
  const shutdown = async () => {
2379
4047
  try {
2380
- await client.flush(flushTimeoutMs);
4048
+ await flushAll(flushTimeoutMs);
2381
4049
  } catch {
2382
4050
  }
2383
- if (exitOnUncaught && soleListener) process.exit(1);
4051
+ if (shouldExit) {
4052
+ process.exit(1);
4053
+ return;
4054
+ }
4055
+ handlingUncaught = false;
2384
4056
  };
4057
+ if (shouldExit) {
4058
+ const watchdog = setTimeout(() => process.exit(1), flushTimeoutMs + 50);
4059
+ void shutdown().finally(() => clearTimeout(watchdog));
4060
+ return;
4061
+ }
2385
4062
  void shutdown();
2386
- };
4063
+ });
2387
4064
  try {
2388
4065
  process.on("uncaughtException", onUncaughtException);
2389
- process.on("unhandledRejection", onUnhandledRejection);
4066
+ if (!unhandledRejectionIsFatal()) {
4067
+ process.on("unhandledRejection", onUnhandledRejection);
4068
+ }
2390
4069
  } catch {
2391
- return () => {
2392
- };
4070
+ return;
2393
4071
  }
2394
- return () => {
4072
+ uninstallProcess = () => {
2395
4073
  try {
2396
4074
  removeProcessListener("uncaughtException", onUncaughtException);
2397
4075
  removeProcessListener("unhandledRejection", onUnhandledRejection);
2398
4076
  } catch {
2399
4077
  }
4078
+ uninstallProcess = void 0;
4079
+ handlingUncaught = false;
4080
+ };
4081
+ };
4082
+ var installGlobalHandlers = (client, options = {}) => {
4083
+ const entry = {
4084
+ client,
4085
+ exitOnUncaught: options.exitOnUncaughtException ?? true,
4086
+ flushTimeoutMs: options.flushTimeoutMs ?? 2e3
4087
+ };
4088
+ registered.push(entry);
4089
+ installSharedListeners();
4090
+ return () => {
4091
+ const index = registered.indexOf(entry);
4092
+ if (index >= 0) registered.splice(index, 1);
4093
+ if (registered.length === 0) uninstallProcess?.();
2400
4094
  };
2401
4095
  };
2402
-
2403
- // src/rasputin-init.ts
2404
- import { join } from "node:path";
2405
- import {
2406
- createClient,
2407
- isClientEnabled
2408
- } from "@rasputin-ai/core";
2409
4096
 
2410
4097
  // src/sdk-meta.ts
2411
4098
  var SDK_NAME = "@rasputin-ai/node";
2412
- var SDK_VERSION = "0.5.0-alpha.9";
4099
+ var SDK_VERSION = "0.5.1";
2413
4100
 
2414
4101
  // src/rasputin-init.ts
2415
- var withExecution = (client, execution, installRuntime, manifest) => {
2416
- const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(execution) : () => {
4102
+ var publicExecution = (runtime) => ({
4103
+ createScope: (metadata) => {
4104
+ const scope = runtime.createScope(metadata);
4105
+ return {
4106
+ run: scope.run,
4107
+ associateError: scope.associateError,
4108
+ finish: scope.finish
4109
+ };
4110
+ },
4111
+ trace: runtime.trace,
4112
+ getStats: runtime.getStats
4113
+ });
4114
+ var withExecution = (client, runtime, installRuntime, manifest, uninstallHandlers = () => {
4115
+ }) => {
4116
+ const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(runtime) : () => {
2417
4117
  };
2418
4118
  const manifestUpload = scheduleInstrumentationManifestUpload(manifest);
4119
+ const execution = publicExecution(runtime);
2419
4120
  return {
2420
4121
  ...client,
2421
4122
  execution,
2422
4123
  getStats: () => ({ ...client.getStats(), recorder: execution.getStats() }),
2423
4124
  verifyConfiguration: manifestUpload.verify,
2424
4125
  captureException: (error, context) => {
2425
- const runtimeState = context?.runtimeState ?? execution.getErrorState(
2426
- error,
2427
- context?.request ? { kind: "http", request: context.request } : void 0
2428
- );
2429
- const result = client.captureException(error, { ...context, runtimeState });
4126
+ const result = client.captureException(error, context);
2430
4127
  manifestUpload.flushSoon();
2431
4128
  return result;
2432
4129
  },
2433
4130
  flush: async (timeoutMs) => {
4131
+ const startedAt = Date.now();
2434
4132
  await client.flush(timeoutMs);
2435
- await manifestUpload.wait();
4133
+ if (timeoutMs === void 0) {
4134
+ await manifestUpload.wait();
4135
+ return;
4136
+ }
4137
+ await manifestUpload.wait(Math.max(0, timeoutMs - (Date.now() - startedAt)));
2436
4138
  },
2437
4139
  close: async () => {
4140
+ uninstallHandlers();
2438
4141
  uninstallRuntime();
2439
4142
  manifestUpload.disconnect();
4143
+ const startedAt = Date.now();
2440
4144
  await client.close();
2441
- await manifestUpload.wait();
4145
+ await manifestUpload.wait(Math.max(0, 2e3 - (Date.now() - startedAt)));
2442
4146
  }
2443
4147
  };
2444
4148
  };
2445
4149
  var RasputinInit = (options) => {
2446
4150
  try {
2447
- const client = createClient(options, { sdkVersion: SDK_VERSION, sdkName: SDK_NAME });
2448
- const recorderEnabled = isClientEnabled(options) && options.executionRecorder?.enabled !== false;
2449
- const execution = createExecutionRecorder({
4151
+ const enabled = isClientEnabled(options);
4152
+ const recorderEnabled = enabled && options.executionRecorder?.enabled !== false;
4153
+ const runtime = createExecutionRecorder({
2450
4154
  ...options.executionRecorder,
2451
4155
  enabled: recorderEnabled
2452
4156
  });
2453
- loadInstrumentationManifestIfPresent(
2454
- options.instrumentationManifestPath ?? process.env.RASPUTIN_INSTRUMENTATION_MANIFEST ?? join(process.cwd(), ".rasputin", "instrumentation-manifest.json")
2455
- );
2456
- const wrappedClient = withExecution(client, execution, recorderEnabled, {
2457
- projectApiKey: options.projectApiKey,
2458
- release: options.release,
2459
- apiUrl: options.apiUrl,
2460
- enabled: isClientEnabled(options),
2461
- sourceRoot: options.sourceRoot,
2462
- sourceRoots: options.sourceRoots,
2463
- logSuccess: options.logSuccess
4157
+ const client = createClient(options, {
4158
+ sdkVersion: SDK_VERSION,
4159
+ sdkName: SDK_NAME,
4160
+ installTransportSignalHandlers: options.installTransportSignalHandlers,
4161
+ resolveRuntimeState: (error, context) => runtime.getErrorState(
4162
+ error,
4163
+ context?.request ? { kind: "http", request: context.request } : void 0
4164
+ )
2464
4165
  });
2465
- if (isClientEnabled(options)) {
2466
- installGlobalHandlers(wrappedClient);
4166
+ if (enabled) {
4167
+ loadInstrumentationManifestIfPresent(
4168
+ options.instrumentationManifestPath ?? process.env.RASPUTIN_INSTRUMENTATION_MANIFEST ?? join(process.cwd(), ".rasputin", "instrumentation-manifest.json")
4169
+ );
4170
+ }
4171
+ let uninstallHandlers = () => {
4172
+ };
4173
+ const wrappedClient = withExecution(
4174
+ client,
4175
+ runtime,
4176
+ recorderEnabled,
4177
+ {
4178
+ projectApiKey: options.projectApiKey ?? "",
4179
+ release: options.release,
4180
+ apiUrl: options.apiUrl,
4181
+ enabled,
4182
+ sourceRoot: options.sourceRoot,
4183
+ sourceRoots: options.sourceRoots,
4184
+ logSuccess: options.logSuccess
4185
+ },
4186
+ () => uninstallHandlers()
4187
+ );
4188
+ if (enabled && options.installGlobalHandlers !== false) {
4189
+ uninstallHandlers = installGlobalHandlers(wrappedClient);
2467
4190
  }
2468
4191
  return wrappedClient;
2469
4192
  } catch {
@@ -2472,7 +4195,7 @@ var RasputinInit = (options) => {
2472
4195
  createExecutionRecorder({ enabled: false }),
2473
4196
  false,
2474
4197
  {
2475
- projectApiKey: options.projectApiKey,
4198
+ projectApiKey: options.projectApiKey ?? "",
2476
4199
  release: options.release,
2477
4200
  apiUrl: options.apiUrl,
2478
4201
  enabled: false,
@@ -2484,9 +4207,5 @@ var RasputinInit = (options) => {
2484
4207
  }
2485
4208
  };
2486
4209
  export {
2487
- RasputinInit,
2488
- createExecutionRecorder,
2489
- installAutomaticExecutionRuntime,
2490
- installGlobalHandlers,
2491
- scheduleInstrumentationManifestUpload
4210
+ RasputinInit
2492
4211
  };