@rasputin-ai/node 0.5.0-alpha.8 → 0.5.0

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 +2637 -894
  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 -797
  61. package/dist/instrument/bun.js +1098 -770
  62. package/dist/instrument/node.js +1078 -772
  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,9 +528,8 @@ 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,
532
+ rasputinTagKind,
394
533
  runtimeFunctionId as runtimeFunctionId2
395
534
  } from "@rasputin-ai/core";
396
535
 
@@ -475,13 +614,18 @@ var ExecutionJournal = class {
475
614
  args,
476
615
  NO_SUPPRESSION
477
616
  )) {
617
+ this.dropped += 2;
478
618
  return;
479
619
  }
480
620
  this.openCallIds.add(callId);
481
621
  }
482
622
  finishCall(kind, callId, timestampNs, durationNs, payload) {
483
- if (!this.openCallIds.delete(callId)) return;
484
- 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);
485
629
  }
486
630
  dropCall() {
487
631
  this.dropped += 2;
@@ -812,6 +956,10 @@ var RecorderMemoryBudget = class {
812
956
  return allocation;
813
957
  }
814
958
  captureValue(allocation, serialize) {
959
+ if (allocation.released) {
960
+ this.dropValues(allocation, 1);
961
+ return MEMORY_BUDGET_VALUE_MARKER;
962
+ }
815
963
  if (allocation.mode !== "full") {
816
964
  this.dropValues(allocation, 1);
817
965
  return MEMORY_BUDGET_VALUE_MARKER;
@@ -856,6 +1004,13 @@ var RecorderMemoryBudget = class {
856
1004
  this.markPressure(allocation, "metadata-only");
857
1005
  return false;
858
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
+ }
859
1014
  release(allocation) {
860
1015
  if (allocation.released) return;
861
1016
  allocation.released = true;
@@ -866,6 +1021,7 @@ var RecorderMemoryBudget = class {
866
1021
  return { ...this.stats };
867
1022
  }
868
1023
  reserve(allocation, bytes) {
1024
+ if (allocation.released) return false;
869
1025
  const boundedBytes = Math.max(0, Math.ceil(bytes));
870
1026
  if (this.activeEstimatedBytes + boundedBytes > this.maximumBytes) return false;
871
1027
  this.activeEstimatedBytes += boundedBytes;
@@ -898,17 +1054,248 @@ var RecorderMemoryBudget = class {
898
1054
  }
899
1055
  };
900
1056
 
901
- // 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
902
1260
  import { Buffer as Buffer2 } from "node:buffer";
903
- var DEFAULT_REDACT_KEYS = [
904
- "password",
905
- "token",
906
- "authorization",
907
- "cookie",
908
- "secret",
909
- "apikey",
910
- "creditcard"
911
- ];
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]";
912
1299
  var defaults = {
913
1300
  maxDepth: 3,
914
1301
  maxObjectKeys: 30,
@@ -916,441 +1303,1017 @@ var defaults = {
916
1303
  maxStringLength: 500,
917
1304
  maxSerializedValueBytes: 8 * 1024
918
1305
  };
919
- var REDACTED = "[RASPUTIN_REDACTED]";
920
- var truncation = (reason, extra = {}) => ({
921
- __rasputin_truncated: true,
922
- __reason: reason,
923
- ...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
924
1312
  });
925
- var typeMarker = (type, value) => ({
926
- __rasputin_type: type,
927
- ...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
928
1325
  });
929
- var jsonStringUtf8Bytes = (value) => {
930
- let bytes = 2;
931
- for (let index = 0; index < value.length; index++) {
932
- const code = value.charCodeAt(index);
933
- if (code === 34 || code === 92) {
934
- bytes += 2;
935
- continue;
936
- }
937
- if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
938
- bytes += 2;
939
- 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 {
940
1401
  }
941
- if (code < 32) {
942
- bytes += 6;
943
- 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;
944
1411
  }
945
- if (code < 128) {
946
- bytes += 1;
947
- continue;
1412
+ }
1413
+ return "Error";
1414
+ };
1415
+ var errorMessageOf = (value) => {
1416
+ if (isDomException(value) && domExceptionMessageGet) {
1417
+ try {
1418
+ return domExceptionMessageGet.call(value);
1419
+ } catch {
948
1420
  }
949
- if (code < 2048) {
950
- bytes += 2;
951
- 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;
952
1439
  }
953
- if (code >= 55296 && code <= 56319) {
954
- const next = value.charCodeAt(index + 1);
955
- if (index + 1 < value.length && next >= 56320 && next <= 57343) {
956
- bytes += 4;
957
- index++;
958
- continue;
959
- }
960
- bytes += 6;
961
- 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;
962
1454
  }
963
- if (code >= 56320 && code <= 57343) {
964
- bytes += 6;
965
- 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;
966
1481
  }
967
- bytes += 3;
1482
+ if (!current) return false;
1483
+ if (types.isProxy(current)) return true;
968
1484
  }
969
- return bytes;
1485
+ return true;
970
1486
  };
971
- var jsonLiteralUtf8Bytes = (value) => {
972
- if (value === null) return 4;
973
- switch (typeof value) {
974
- case "boolean":
975
- return value ? 4 : 5;
976
- case "number":
977
- if (!Number.isFinite(value)) return 4;
978
- if (Object.is(value, -0)) return 1;
979
- return String(value).length;
980
- case "string":
981
- return jsonStringUtf8Bytes(value);
982
- case "object": {
983
- if (Array.isArray(value)) {
984
- let bytes2 = 2;
985
- for (let index = 0; index < value.length; index++) {
986
- if (index > 0) bytes2 += 1;
987
- bytes2 += jsonLiteralUtf8Bytes(value[index]);
988
- }
989
- return bytes2;
990
- }
991
- const record = value;
992
- let bytes = 2;
993
- let first = true;
994
- for (const key of Object.keys(record)) {
995
- if (!first) bytes += 1;
996
- first = false;
997
- bytes += jsonStringUtf8Bytes(key) + 1;
998
- bytes += jsonLiteralUtf8Bytes(record[key]);
999
- }
1000
- 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);
1001
1526
  }
1002
- default:
1003
- return Buffer2.byteLength(JSON.stringify(value) ?? "null", "utf8");
1527
+ } catch {
1528
+ return { keys, truncated: keys.length >= maxKeys };
1004
1529
  }
1530
+ return { keys, truncated: false };
1005
1531
  };
1006
- var compileLimits = (options) => ({
1007
- maxDepth: options.maxDepth ?? defaults.maxDepth,
1008
- maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
1009
- maxArrayElements: options.maxArrayElements ?? defaults.maxArrayElements,
1010
- maxStringLength: options.maxStringLength ?? defaults.maxStringLength,
1011
- maxSerializedValueBytes: options.maxSerializedValueBytes ?? defaults.maxSerializedValueBytes
1012
- });
1013
- var compileRedactKeys = (options) => {
1014
- if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
1015
- 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
+ }
1016
1538
  };
1017
- 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 = "";
1018
1567
  for (let index = 0; index < key.length; index++) {
1019
1568
  const code = key.charCodeAt(index);
1020
- 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];
1021
1571
  }
1022
- return false;
1572
+ return compacted;
1023
1573
  };
1024
- var isJsonSafeString = (value) => {
1025
- for (let index = 0; index < value.length; index++) {
1026
- const code = value.charCodeAt(index);
1027
- if (code < 32 || code === 34 || code === 92) return false;
1028
- if (code >= 55296 && code <= 56319) {
1029
- const next = value.charCodeAt(index + 1);
1030
- if (index + 1 >= value.length || next < 56320 || next > 57343) return false;
1031
- index++;
1032
- continue;
1033
- }
1034
- 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;
1035
1595
  }
1036
- 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}`;
1037
1614
  };
1038
- var primitiveFastPath = (value, maxStringLength) => {
1039
- if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
1040
- if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
1041
- if (typeof value === "number") {
1042
- if (!Number.isFinite(value)) return { value, bytes: 4, visitedNodes: 1 };
1043
- if (Object.is(value, -0)) return { value, bytes: 1, visitedNodes: 1 };
1044
- return { value, bytes: String(value).length, visitedNodes: 1 };
1045
- }
1046
- if (typeof value === "string") {
1047
- if (value.length > maxStringLength || !isJsonSafeString(value)) return void 0;
1048
- return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
1049
- }
1050
- if (typeof value === "undefined") {
1051
- const serialized = typeMarker("undefined");
1052
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1053
- }
1054
- if (typeof value === "bigint") {
1055
- const serialized = typeMarker("bigint", value.toString());
1056
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1057
- }
1058
- if (typeof value === "symbol") {
1059
- const text = String(value);
1060
- if (!isJsonSafeString(text)) return void 0;
1061
- const serialized = typeMarker("symbol", text);
1062
- return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
1063
- }
1064
- if (typeof value === "function") {
1065
- const name = value.name || "anonymous";
1066
- if (!isJsonSafeString(name)) return void 0;
1067
- const serialized = typeMarker("function", name);
1068
- 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;
1069
1623
  }
1070
- 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)}`;
1071
1628
  };
1072
- var createSafeSerializer = (options = {}) => {
1073
- const limits = compileLimits(options);
1074
- 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);
1075
1634
  const sharedPath = /* @__PURE__ */ new Set();
1076
- let serializing = false;
1077
- const isRedactedKey = (key) => {
1078
- if (redactKeys.has(key)) return true;
1079
- if (!keyNeedsCaseFold(key)) return false;
1080
- return redactKeys.has(key.toLowerCase());
1081
- };
1082
- const addBytes = (metrics, count) => {
1083
- metrics.bytes += count;
1084
- if (metrics.bytes > limits.maxSerializedValueBytes) metrics.oversize = true;
1085
- };
1086
- const boundedOversize = (bytes, visitedNodes) => {
1087
- const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
1088
- return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
1089
- };
1090
- const openObject = (metrics, allocate) => {
1091
- addBytes(metrics, 2);
1092
- return {
1093
- target: allocate && !metrics.oversize ? {} : void 0,
1094
- first: true
1095
- };
1635
+ let freezing = false;
1636
+ const add = (metrics, count) => {
1637
+ metrics.estimatedBytes += count;
1638
+ if (metrics.estimatedBytes > limits.maxSerializedValueBytes) metrics.oversize = true;
1096
1639
  };
1097
- const openArray = (metrics, allocate) => {
1098
- addBytes(metrics, 2);
1099
- return {
1100
- items: allocate && !metrics.oversize ? [] : void 0,
1101
- first: true
1102
- };
1103
- };
1104
- const beginField = (metrics, object, key) => {
1105
- if (!object.first) addBytes(metrics, 1);
1106
- object.first = false;
1107
- addBytes(metrics, jsonStringUtf8Bytes(key) + 1);
1108
- };
1109
- const assignField = (object, key, fieldValue) => {
1110
- if (object.target) object.target[key] = fieldValue;
1111
- };
1112
- const writeLiteralField = (metrics, object, key, jsonValue) => {
1113
- beginField(metrics, object, key);
1114
- addBytes(metrics, jsonLiteralUtf8Bytes(jsonValue));
1115
- assignField(object, key, jsonValue);
1116
- };
1117
- const writeTypeMarker = (metrics, allocate, type, nestedValue) => {
1118
- const object = openObject(metrics, allocate);
1119
- writeLiteralField(metrics, object, "__rasputin_type", type);
1120
- if (nestedValue !== void 0) writeLiteralField(metrics, object, "value", nestedValue);
1121
- return object.target;
1122
- };
1123
- const writeTruncation = (metrics, allocate, reason, extra = {}) => {
1124
- const object = openObject(metrics, allocate);
1125
- writeLiteralField(metrics, object, "__rasputin_truncated", true);
1126
- writeLiteralField(metrics, object, "__reason", reason);
1127
- for (const key of Object.keys(extra)) writeLiteralField(metrics, object, key, extra[key]);
1128
- return object.target;
1129
- };
1130
- const serializeInner = (value, depth, path, allocate, metrics) => {
1640
+ const freezeInner = (value, depth, path, metrics) => {
1641
+ if (metrics.oversize) return void 0;
1131
1642
  metrics.visitedNodes++;
1132
- const store = allocate && !metrics.oversize;
1133
1643
  if (value === null) {
1134
- addBytes(metrics, 4);
1135
- return store ? null : void 0;
1644
+ add(metrics, 4);
1645
+ return null;
1136
1646
  }
1137
1647
  if (typeof value === "boolean") {
1138
- addBytes(metrics, value ? 4 : 5);
1139
- return store ? value : void 0;
1648
+ add(metrics, value ? 4 : 5);
1649
+ return value;
1140
1650
  }
1141
1651
  if (typeof value === "number") {
1142
- if (!Number.isFinite(value)) addBytes(metrics, 4);
1143
- else if (Object.is(value, -0)) addBytes(metrics, 1);
1144
- else addBytes(metrics, String(value).length);
1145
- 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;
1146
1659
  }
1147
1660
  if (typeof value === "string") {
1148
1661
  if (value.length <= limits.maxStringLength) {
1149
- addBytes(metrics, jsonStringUtf8Bytes(value));
1150
- return store ? value : void 0;
1662
+ add(metrics, stringEstimate(value));
1663
+ return value;
1151
1664
  }
1152
- return writeTruncation(metrics, store, "max_string_length", {
1153
- __original_length: value.length,
1154
- 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
1155
1671
  });
1156
1672
  }
1157
- if (typeof value === "undefined") return writeTypeMarker(metrics, store, "undefined");
1673
+ if (typeof value === "undefined") {
1674
+ add(metrics, NODE + 16);
1675
+ return atom("undefined");
1676
+ }
1158
1677
  if (typeof value === "bigint") {
1159
- return writeTypeMarker(metrics, store, "bigint", value.toString());
1678
+ const text = value.toString();
1679
+ add(metrics, NODE + stringEstimate(text));
1680
+ return atom("bigint", { value: text });
1160
1681
  }
1161
1682
  if (typeof value === "symbol") {
1162
- return writeTypeMarker(metrics, store, "symbol", String(value));
1683
+ const text = String(value);
1684
+ add(metrics, NODE + stringEstimate(text));
1685
+ return atom("symbol", { value: text });
1163
1686
  }
1164
1687
  if (typeof value === "function") {
1165
- 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");
1166
1703
  }
1167
- if (depth >= limits.maxDepth) return writeTruncation(metrics, store, "max_depth");
1168
- if (typeof value !== "object") return writeTypeMarker(metrics, store, typeof value);
1169
- if (path.has(value)) return writeTypeMarker(metrics, store, "circular");
1170
1704
  path.add(value);
1171
- const bytesBefore = metrics.bytes;
1172
- const oversizeBefore = metrics.oversize;
1173
1705
  try {
1174
- const childAllocate = allocate && !metrics.oversize;
1175
- if (value instanceof Error) {
1176
- const object2 = openObject(metrics, childAllocate);
1177
- writeLiteralField(metrics, object2, "__rasputin_type", "Error");
1178
- writeLiteralField(metrics, object2, "name", value.name);
1179
- beginField(metrics, object2, "message");
1180
- assignField(
1181
- object2,
1182
- "message",
1183
- serializeInner(value.message, depth + 1, path, childAllocate, metrics)
1184
- );
1185
- if (value.stack) {
1186
- beginField(metrics, object2, "stack");
1187
- assignField(
1188
- object2,
1189
- "stack",
1190
- serializeInner(value.stack, depth + 1, path, childAllocate, metrics)
1191
- );
1192
- }
1193
- return object2.target;
1706
+ if (types.isProxy(value) || prototypeChainHasProxy(value)) {
1707
+ add(metrics, NODE + 16);
1708
+ return atom("Proxy");
1709
+ }
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" });
1194
1719
  }
1195
- if (value instanceof Date) {
1196
- return writeTypeMarker(metrics, childAllocate, "Date", value.toISOString());
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
+ });
1197
1738
  }
1198
1739
  if (Buffer2.isBuffer(value)) {
1199
- return writeTypeMarker(metrics, childAllocate, "Buffer", {
1200
- byteLength: value.byteLength,
1201
- base64: value.subarray(0, limits.maxStringLength).toString("base64"),
1202
- ...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 } : {}
1203
1748
  });
1204
1749
  }
1205
- if (value instanceof Promise) return writeTypeMarker(metrics, childAllocate, "Promise");
1206
- if (value instanceof Map) {
1207
- const object2 = openObject(metrics, childAllocate);
1208
- writeLiteralField(metrics, object2, "__rasputin_type", "Map");
1209
- beginField(metrics, object2, "entries");
1210
- 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 = [];
1211
1757
  let counted2 = 0;
1212
- for (const entry of value.entries()) {
1213
- if (counted2 >= limits.maxArrayElements) break;
1214
- if (!entries.first) addBytes(metrics, 1);
1215
- entries.first = false;
1216
- addBytes(metrics, 2);
1217
- const key = serializeInner(entry[0], depth + 1, path, childAllocate, metrics);
1218
- addBytes(metrics, 1);
1219
- const mapped = serializeInner(entry[1], depth + 1, path, childAllocate, metrics);
1220
- 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
+ }
1221
1772
  counted2++;
1222
1773
  }
1223
- assignField(object2, "entries", entries.items ?? []);
1224
- if (value.size > limits.maxArrayElements) {
1225
- writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1226
- writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1227
- writeLiteralField(metrics, object2, "__original_length", value.size);
1228
- }
1229
- return object2.target;
1774
+ return atom("Map", {
1775
+ entries,
1776
+ ...size > limits.maxArrayElements ? { truncated: true, reason: "max_array_elements", originalLength: size } : {}
1777
+ });
1230
1778
  }
1231
- if (value instanceof Set) {
1232
- const object2 = openObject(metrics, childAllocate);
1233
- writeLiteralField(metrics, object2, "__rasputin_type", "Set");
1234
- beginField(metrics, object2, "values");
1235
- const items = openArray(metrics, childAllocate);
1779
+ if (types.isSet(value)) {
1780
+ add(metrics, NODE + 16);
1781
+ const values = [];
1236
1782
  let counted2 = 0;
1237
- for (const item of value.values()) {
1238
- if (counted2 >= limits.maxArrayElements) break;
1239
- if (!items.first) addBytes(metrics, 1);
1240
- items.first = false;
1241
- const serializedItem = serializeInner(item, depth + 1, path, childAllocate, metrics);
1242
- 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));
1243
1788
  counted2++;
1244
1789
  }
1245
- assignField(object2, "values", items.items ?? []);
1246
- if (value.size > limits.maxArrayElements) {
1247
- writeLiteralField(metrics, object2, "__rasputin_truncated", true);
1248
- writeLiteralField(metrics, object2, "__reason", "max_array_elements");
1249
- writeLiteralField(metrics, object2, "__original_length", value.size);
1250
- }
1251
- return object2.target;
1790
+ return atom("Set", {
1791
+ values,
1792
+ ...size > limits.maxArrayElements ? { truncated: true, reason: "max_array_elements", originalLength: size } : {}
1793
+ });
1252
1794
  }
1253
1795
  if (Array.isArray(value)) {
1254
- const items = openArray(metrics, childAllocate);
1796
+ add(metrics, 2);
1797
+ const items = [];
1255
1798
  const maxItems = value.length > limits.maxArrayElements ? limits.maxArrayElements - 1 : value.length;
1799
+ let redactNext = false;
1256
1800
  for (let index = 0; index < maxItems; index++) {
1257
- if (!items.first) addBytes(metrics, 1);
1258
- items.first = false;
1259
- 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
+ }
1260
1828
  }
1261
1829
  if (value.length > limits.maxArrayElements) {
1262
- if (!items.first) addBytes(metrics, 1);
1263
- items.first = false;
1264
- items.items?.push(
1265
- writeTruncation(metrics, childAllocate, "max_array_elements", {
1266
- __original_length: value.length
1830
+ add(metrics, NODE + 32);
1831
+ items.push(
1832
+ atom("truncated", {
1833
+ reason: "max_array_elements",
1834
+ originalLength: value.length
1267
1835
  })
1268
1836
  );
1269
1837
  }
1270
- 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 });
1271
1921
  }
1272
- const object = openObject(metrics, childAllocate);
1273
- const prototype = Object.getPrototypeOf(value);
1274
1922
  if (prototype && prototype !== Object.prototype) {
1275
- writeLiteralField(
1276
- metrics,
1277
- object,
1278
- "__rasputin_type",
1279
- prototype.constructor?.name ?? "instance"
1280
- );
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));
1281
1932
  }
1282
- const keys = Object.keys(value);
1283
- 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;
1284
1937
  for (let index = 0; index < maxKeys; index++) {
1285
1938
  const key = keys[index];
1286
- if (key === void 0) continue;
1287
- if (isRedactedKey(key)) {
1288
- 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);
1289
1944
  continue;
1290
1945
  }
1291
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
1292
- if (descriptor && "value" in descriptor) {
1293
- beginField(metrics, object, key);
1294
- assignField(
1295
- object,
1296
- key,
1297
- serializeInner(descriptor.value, depth + 1, path, childAllocate, metrics)
1298
- );
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));
1299
1950
  } else {
1300
- beginField(metrics, object, key);
1301
- assignField(object, key, writeTypeMarker(metrics, childAllocate, "accessor"));
1951
+ add(metrics, NODE + 16);
1952
+ assignFrozenField(fields, key, atom("accessor"));
1302
1953
  }
1303
1954
  }
1304
- if (keys.length > limits.maxObjectKeys) {
1305
- writeLiteralField(metrics, object, "__rasputin_truncated", true);
1306
- writeLiteralField(metrics, object, "__reason", "max_object_keys");
1307
- 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
+ });
1308
1962
  }
1309
- return object.target;
1963
+ if (typeName) return atom("instance", { type: typeName, value: fields });
1964
+ return fields;
1310
1965
  } catch (error) {
1311
- metrics.bytes = bytesBefore;
1312
- metrics.oversize = oversizeBefore;
1313
- return writeTypeMarker(
1314
- metrics,
1315
- allocate && !metrics.oversize,
1316
- "unserializable",
1317
- error instanceof Error ? error.message : void 0
1318
- );
1966
+ add(metrics, NODE + 32);
1967
+ return atom("unserializable", {
1968
+ value: error instanceof Error ? error.message : void 0
1969
+ });
1319
1970
  } finally {
1320
1971
  path.delete(value);
1321
1972
  }
1322
1973
  };
1323
- const serializeWithBytes = (value) => {
1324
- const fast = primitiveFastPath(value, limits.maxStringLength);
1325
- if (fast) {
1326
- return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
1327
- }
1328
- const metrics = { visitedNodes: 0, bytes: 0, oversize: false };
1329
- const reentrant = serializing;
1974
+ const freeze = (value) => {
1975
+ const metrics = { visitedNodes: 0, estimatedBytes: 0, oversize: false };
1976
+ const reentrant = freezing;
1330
1977
  const path = reentrant ? /* @__PURE__ */ new Set() : sharedPath;
1331
1978
  if (!reentrant) {
1332
- serializing = true;
1979
+ freezing = true;
1333
1980
  sharedPath.clear();
1334
1981
  }
1335
1982
  try {
1336
- const serialized = serializeInner(value, 0, path, true, metrics);
1337
- if (metrics.bytes > limits.maxSerializedValueBytes) {
1338
- 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
+ };
1339
1994
  }
1340
- 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
+ };
1341
2001
  } catch {
1342
- const failed = typeMarker("unserializable");
1343
2002
  return {
1344
- value: failed,
1345
- bytes: jsonLiteralUtf8Bytes(failed),
1346
- visitedNodes: metrics.visitedNodes
2003
+ value: atom("unserializable"),
2004
+ estimatedBytes: NODE + 16,
2005
+ visitedNodes: Math.max(1, metrics.visitedNodes),
2006
+ oversize: false
1347
2007
  };
1348
2008
  } finally {
1349
2009
  path.clear();
1350
- 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;
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]);
1351
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
+ );
1352
2313
  };
1353
2314
  return {
2315
+ freeze: freezer.freeze,
2316
+ encode: encodeFrozen,
1354
2317
  serialize: (value) => serializeWithBytes(value).value,
1355
2318
  serializeWithBytes
1356
2319
  };
@@ -1421,9 +2384,40 @@ var createSourceExclusionMatcher = (exclusions) => {
1421
2384
  return matchers.length === 0 ? () => false : (definition) => matchers.some((matcher) => matcher(definition));
1422
2385
  };
1423
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
+
1424
2417
  // src/execution-recorder/execution-recorder.ts
1425
2418
  var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
1426
- var DERIVATION_ROOT_RECORD_BYTES = 64;
2419
+ var DEFAULT_MAX_EXECUTION_HOLD_MS = 6e4;
2420
+ var DEFAULT_MAX_RETAINED_ERROR_RECORDINGS = 32;
1427
2421
  var phaseTimingEnabled = process.env.RASPUTIN_RECORDER_PHASE_TIMING === "1";
1428
2422
  var manualFunctionDefinition = (value) => {
1429
2423
  const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
@@ -1442,72 +2436,39 @@ var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualF
1442
2436
  var elapsedMs2 = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
1443
2437
  var roundedMilliseconds2 = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
1444
2438
  var addRecorderTime = (recording, nanoseconds) => {
1445
- 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;
1446
2448
  };
1447
- var isPromiseLike = (value) => Boolean(value) && typeof value.then === "function";
1448
2449
  var notifyObserver = (observer, value) => {
1449
2450
  try {
1450
2451
  observer(value);
1451
2452
  } catch {
1452
2453
  }
1453
2454
  };
1454
- var observeCallback = (callback, onReturn, onThrow) => {
1455
- let result;
1456
- try {
1457
- result = callback();
1458
- } catch (error) {
1459
- notifyObserver(onThrow, error);
1460
- throw error;
1461
- }
1462
- if (isPromiseLike(result)) {
1463
- return result.then(
1464
- (value) => {
1465
- notifyObserver(onReturn, value);
1466
- return value;
1467
- },
1468
- (error) => {
1469
- notifyObserver(onThrow, error);
1470
- throw error;
1471
- }
1472
- );
1473
- }
1474
- notifyObserver(onReturn, result);
1475
- return result;
1476
- };
1477
- var observeRecordedCallback = (recording, recorderStartedAtNs, callback, onReturn, onThrow) => {
1478
- const callbackStartedAtNs = process.hrtime.bigint();
1479
- 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;
1480
2459
  addRecorderTime(recording, callbackStartedAtNs - recorderStartedAtNs);
1481
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2460
+ addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
1482
2461
  };
1483
2462
  let result;
1484
2463
  try {
1485
2464
  result = callback();
1486
2465
  } catch (error) {
1487
- const callbackEndedAtNs2 = process.hrtime.bigint();
1488
2466
  notifyObserver(onThrow, error);
1489
- recordExitWork(callbackEndedAtNs2);
2467
+ recordExitWork(phaseTimingEnabled ? process.hrtime.bigint() : recorderStartedAtNs);
1490
2468
  throw error;
1491
2469
  }
1492
- if (isPromiseLike(result)) {
1493
- return result.then(
1494
- (value) => {
1495
- const callbackEndedAtNs2 = process.hrtime.bigint();
1496
- notifyObserver(onReturn, value);
1497
- recordExitWork(callbackEndedAtNs2);
1498
- return value;
1499
- },
1500
- (error) => {
1501
- const callbackEndedAtNs2 = process.hrtime.bigint();
1502
- notifyObserver(onThrow, error);
1503
- recordExitWork(callbackEndedAtNs2);
1504
- throw error;
1505
- }
1506
- );
1507
- }
1508
- const callbackEndedAtNs = process.hrtime.bigint();
1509
2470
  notifyObserver(onReturn, result);
1510
- recordExitWork(callbackEndedAtNs);
2471
+ recordExitWork(phaseTimingEnabled ? process.hrtime.bigint() : recorderStartedAtNs);
1511
2472
  return result;
1512
2473
  };
1513
2474
  var emptyStats = {
@@ -1537,32 +2498,34 @@ var emptyStats = {
1537
2498
  journalPoolMisses: 0,
1538
2499
  journalPoolSize: 0,
1539
2500
  journalAllocatedCapacity: 0,
1540
- derivationCandidateFunctions: 0,
1541
- derivationElidedFunctionCalls: 0,
1542
- derivationRootsCaptured: 0,
1543
- derivationControlFactsCaptured: 0,
1544
- derivationValuesAvoided: 0,
1545
- derivationFallbackFunctions: 0,
1546
- derivationFallbackExpressions: 0,
1547
- derivationFallbackReasons: {},
1548
- derivationRootBytes: 0
2501
+ attributionDegradations: 0
1549
2502
  };
1550
2503
  var noOpExecution = {
1551
2504
  createScope: () => ({
1552
2505
  run: (callback) => callback(),
1553
2506
  getErrorState: () => void 0,
2507
+ associateError: () => {
2508
+ },
1554
2509
  finish: () => {
1555
2510
  }
1556
2511
  }),
1557
- run: (_metadata, callback) => callback(),
1558
2512
  getErrorState: () => void 0,
1559
2513
  runFunction: (_functionId, _args, callback) => callback(),
1560
2514
  runFunctionPlans: (_plans, _planIndex, _args, callback) => callback(),
1561
2515
  prepareFunctionPlans: () => [],
1562
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
+ }),
1563
2527
  trace: (_functionId, fn) => fn,
1564
- getStats: () => ({ ...emptyStats, derivationFallbackReasons: {} }),
1565
- captureDerivationRoot: (_rootId, value) => value
2528
+ getStats: () => ({ ...emptyStats })
1566
2529
  };
1567
2530
  var mergeExecutionMetadata = (target, metadata) => {
1568
2531
  if (metadata.kind) target.kind = metadata.kind;
@@ -1587,7 +2550,41 @@ var newSuppression = (group, parentCallId, startedAtNs, endedAtNs) => ({
1587
2550
  });
1588
2551
  var createExecutionRecorder = (options) => {
1589
2552
  if (!options?.enabled) return noOpExecution;
2553
+ warnIfMissingAsyncContextFrame();
1590
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
+ };
1591
2588
  const maxEventsPerExecution = sanitizeJournalCapacity(options.maxEventsPerExecution);
1592
2589
  const maxCapturedCallsPerFunction = Math.max(
1593
2590
  1,
@@ -1597,6 +2594,14 @@ var createExecutionRecorder = (options) => {
1597
2594
  0,
1598
2595
  Math.floor(options.maxActiveMemoryBytes ?? DEFAULT_MAX_ACTIVE_MEMORY_BYTES)
1599
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;
1600
2605
  const memoryBudget = new RecorderMemoryBudget(
1601
2606
  maxActiveMemoryBytes,
1602
2607
  options.maxSerializedValueBytes ?? 8 * 1024
@@ -1604,12 +2609,17 @@ var createExecutionRecorder = (options) => {
1604
2609
  const serializer = createSafeSerializer(options);
1605
2610
  const excludesSource = createSourceExclusionMatcher(options.excludeSources);
1606
2611
  const journalPool = new ExecutionJournalPool(maxEventsPerExecution);
2612
+ const runtimeStateSizeBudget = {
2613
+ targetBytes: options.runtimeStateTargetBytes,
2614
+ maximumBytes: options.maxRuntimeStateBytes
2615
+ };
1607
2616
  const plansByRuntimeId = [];
1608
2617
  let executionCounter = 0;
1609
2618
  let nextRuntimePlanId = 1;
1610
2619
  const internedPlans = /* @__PURE__ */ new Map();
1611
2620
  const preparedModules = /* @__PURE__ */ new WeakMap();
1612
2621
  const errorExecutions = /* @__PURE__ */ new WeakMap();
2622
+ const retainedErrorRecordings = [];
1613
2623
  const phases = phaseTimingEnabled ? { alsNs: 0n, materializeNs: 0n } : void 0;
1614
2624
  const stats = {
1615
2625
  functionCallsObserved: 0,
@@ -1628,15 +2638,7 @@ var createExecutionRecorder = (options) => {
1628
2638
  measuredExecutions: 0,
1629
2639
  totalInlineWallTimeMs: 0,
1630
2640
  maxInlineWallTimeMs: 0,
1631
- derivationCandidateFunctions: 0,
1632
- derivationElidedFunctionCalls: 0,
1633
- derivationRootsCaptured: 0,
1634
- derivationControlFactsCaptured: 0,
1635
- derivationValuesAvoided: 0,
1636
- derivationFallbackFunctions: 0,
1637
- derivationFallbackExpressions: 0,
1638
- derivationFallbackReasons: {},
1639
- derivationRootBytes: 0
2641
+ attributionDegradations: 0
1640
2642
  };
1641
2643
  const addPhase = (key, nanoseconds) => {
1642
2644
  if (phases && nanoseconds > 0n) phases[key] += nanoseconds;
@@ -1647,14 +2649,36 @@ var createExecutionRecorder = (options) => {
1647
2649
  stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
1648
2650
  stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
1649
2651
  };
1650
- const serializeAndCount = (value) => {
1651
- const serialized = serializer.serializeWithBytes(value);
2652
+ const freezeAndCount = (value) => {
2653
+ const frozen = serializer.freeze(value);
1652
2654
  stats.serializedValues++;
1653
- stats.serializedValueNodes += serialized.visitedNodes;
1654
- stats.serializedValueBytes += serialized.bytes;
1655
- 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
+ }
1656
2669
  };
1657
- 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
+ });
1658
2682
  const storePlan = (plan) => {
1659
2683
  plansByRuntimeId[plan.runtimePlanId] = plan;
1660
2684
  return plan;
@@ -1667,7 +2691,8 @@ var createExecutionRecorder = (options) => {
1667
2691
  definition,
1668
2692
  functionId: definition.functionId,
1669
2693
  excluded: excludesSource(definition),
1670
- estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
2694
+ estimatedCallBytes: estimatedCallBytesFor(definition.functionId),
2695
+ omitCallValues: false
1671
2696
  });
1672
2697
  internedPlans.set(definition.functionId, plan);
1673
2698
  return plan;
@@ -1682,89 +2707,124 @@ var createExecutionRecorder = (options) => {
1682
2707
  definition,
1683
2708
  functionId: definition.functionId,
1684
2709
  excluded: excludesSource(definition),
1685
- estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
2710
+ estimatedCallBytes: estimatedCallBytesFor(definition.functionId),
2711
+ omitCallValues: encodedPlanOmitsCallValues(encoded)
1686
2712
  });
1687
2713
  });
1688
2714
  preparedModules.set(plans, prepared);
1689
2715
  return prepared;
1690
2716
  };
1691
- const derivationMetrics = (recording) => {
1692
- const manifest = snapshotInstrumentationManifest();
1693
- const plans = manifest?.derivationPlans ?? [];
1694
- const reasons = { ...stats.derivationFallbackReasons };
1695
- return {
1696
- derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
1697
- derivationElidedFunctionCalls: stats.derivationElidedFunctionCalls,
1698
- derivationRootsCaptured: recording.derivationRoots.length,
1699
- derivationControlFactsCaptured: stats.derivationControlFactsCaptured,
1700
- derivationValuesAvoided: stats.derivationValuesAvoided,
1701
- derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
1702
- derivationFallbackExpressions: recording.derivationRoots.length,
1703
- derivationFallbackReasons: reasons,
1704
- derivationRootBytes: recording.derivationRootBytes
1705
- };
1706
- };
1707
- const resolveCaptureMode = (recording) => {
1708
- if (recording.derivationRoots.length > 0) return "derivation";
1709
- const plans = snapshotInstrumentationManifest()?.derivationPlans ?? [];
1710
- if (recording.sawAutomatic && plans.some(
1711
- (plan) => !plan.fallbackReason && recording.executedFunctionIds.has(plan.functionId)
1712
- )) {
1713
- return "derivation";
2717
+ const eventsHaveOmittedValues = (events) => {
2718
+ for (const event of events) {
2719
+ if (event.type === "function_enter" && event.args.some((arg) => rasputinTagKind(arg) === "omitted")) {
2720
+ return true;
2721
+ }
2722
+ if (event.type === "function_exit" && rasputinTagKind(event.returnValue) === "omitted") {
2723
+ return true;
2724
+ }
1714
2725
  }
1715
- if (recording.sawAutomatic) return "automatic-full";
1716
- if (recording.sawManual) return "manual";
1717
- return "scope-only";
1718
- };
1719
- const derivationCapture = (recording) => {
1720
- const manifest = snapshotInstrumentationManifest();
1721
- if (!manifest) return void 0;
1722
- return {
1723
- manifestHash: hashInstrumentationManifest(manifest),
1724
- roots: recording.derivationRoots.slice(),
1725
- controlFacts: []
1726
- };
2726
+ return false;
1727
2727
  };
1728
- const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
1729
- const recorderStartedAtNs = process.hrtime.bigint();
2728
+ const resolveCaptureProfile = (recording, events, truncated, capture) => {
2729
+ const source = recording.sawAutomatic ? "automatic" : recording.sawManual ? "manual" : "scope-only";
2730
+ if (source === "scope-only") {
2731
+ return {
2732
+ source,
2733
+ functionBoundaries: "none",
2734
+ functionValues: "none",
2735
+ timings: "none"
2736
+ };
2737
+ }
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
+ };
2761
+ }
2762
+ const droppedEvents = Boolean(truncated?.eventsDropped || capture?.eventsDropped);
2763
+ return {
2764
+ source,
2765
+ functionBoundaries: droppedEvents ? "partial" : "full",
2766
+ functionValues: eventsHaveOmittedValues(events) ? "selective" : "full",
2767
+ timings: droppedEvents ? "partial" : "full"
2768
+ };
2769
+ };
2770
+ const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
2771
+ const recorderStartedAtNs = process.hrtime.bigint();
1730
2772
  let events = [];
1731
2773
  let functions = [];
1732
2774
  let truncated;
1733
2775
  let capture;
1734
- let derivation;
1735
2776
  if (recording.cachedState) {
1736
2777
  events = recording.cachedState.events;
1737
2778
  functions = recording.cachedState.functions;
1738
2779
  truncated = recording.cachedState.truncated;
1739
2780
  capture = recording.cachedState.capture;
1740
- derivation = recording.cachedState.derivation;
1741
2781
  } else {
1742
2782
  if (recording.journal) {
1743
2783
  const materialized = recording.journal.materialize(plansByRuntimeId, recording.startedAtNs);
1744
- 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
+ }
1745
2790
  functions = materialized.functions;
1746
2791
  truncated = recording.journal.dropped > 0 ? { eventsDropped: recording.journal.dropped } : void 0;
1747
2792
  }
1748
- capture = recording.memory.underPressure ? {
1749
- completeness: "partial",
1750
- reason: "process_memory_budget",
1751
- valuesDropped: recording.memory.valuesDropped,
1752
- eventsDropped: recording.memory.eventsDropped
1753
- } : void 0;
1754
- 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
+ }
1755
2815
  if (recording.finished && recording.inFlightCalls === 0 && recording.journal) {
1756
- recording.cachedState = { events, functions, truncated, capture, derivation };
2816
+ recording.cachedState = { events, functions, truncated, capture };
1757
2817
  journalPool.release(recording.journal);
1758
2818
  recording.journal = void 0;
1759
2819
  }
1760
2820
  }
1761
2821
  const state = {
1762
- version: 3,
1763
- captureMode: resolveCaptureMode(recording),
2822
+ version: 4,
2823
+ captureProfile: resolveCaptureProfile(recording, events, truncated, capture),
1764
2824
  executionId: recording.executionId,
1765
2825
  startedAt: recording.startedAt,
1766
2826
  durationMs: elapsedMs2(recording.startedAtNs, endedAtNs),
1767
- recorder: { inlineWallTimeMs: 0, derivation: derivationMetrics(recording) },
2827
+ recorder: { inlineWallTimeMs: 0 },
1768
2828
  execution: {
1769
2829
  ...recording.execution,
1770
2830
  ...recording.execution.request ? { request: { ...recording.execution.request } } : {}
@@ -1772,29 +2832,153 @@ var createExecutionRecorder = (options) => {
1772
2832
  functions: functions.slice(),
1773
2833
  events: events.slice(),
1774
2834
  ...truncated ? { truncated: { ...truncated } } : {},
1775
- ...capture ? { capture: { ...capture } } : {},
1776
- ...derivation ? { derivation: { ...derivation, roots: derivation.roots.slice() } } : {}
2835
+ ...capture ? { capture: { ...capture } } : {}
1777
2836
  };
1778
2837
  if (phaseTimingEnabled)
1779
2838
  addPhase("materializeNs", process.hrtime.bigint() - recorderStartedAtNs);
1780
- addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
2839
+ const sizeBudgetStartedAtNs = process.hrtime.bigint();
2840
+ addRecorderTime(recording, sizeBudgetStartedAtNs - recorderStartedAtNs);
1781
2841
  state.recorder = {
1782
- inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs),
1783
- 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)
1784
2848
  };
1785
- return state;
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
+ }
2924
+ };
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
+ }
1786
2951
  };
1787
2952
  const rememberError = (error, recording) => {
1788
2953
  recording.hasError = true;
1789
- if (typeof error !== "object" && typeof error !== "function" || error === null) return;
1790
- 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)) {
1791
2975
  stats.errorSnapshots++;
1792
2976
  if (recording.memory.underPressure && !recording.partialSnapshotCounted) {
1793
2977
  recording.partialSnapshotCounted = true;
1794
2978
  stats.partialErrorSnapshots++;
1795
2979
  }
1796
2980
  }
1797
- errorExecutions.set(error, recording);
2981
+ errorExecutions.set(key, recording);
1798
2982
  };
1799
2983
  const countDroppedEvents = (recording, droppedBefore) => {
1800
2984
  const dropped = recording.journal?.dropped ?? droppedBefore;
@@ -1844,13 +3028,19 @@ var createExecutionRecorder = (options) => {
1844
3028
  return {
1845
3029
  // Keep the bounded thrown value even after surrounding capture degrades. A partial
1846
3030
  // snapshot without the exception itself would not be useful for investigation.
1847
- value: serializeAndCount(error).value,
3031
+ value: (() => {
3032
+ try {
3033
+ return freezeAndCount(error).value;
3034
+ } catch {
3035
+ return { __rasputin_type: "unserializable" };
3036
+ }
3037
+ })(),
1848
3038
  commit: () => {
1849
3039
  if (key) recording.capturedErrors.set(key, callId);
1850
3040
  }
1851
3041
  };
1852
3042
  };
1853
- const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
3043
+ const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error, capturedArgs) => {
1854
3044
  if (!recording.journal) {
1855
3045
  rememberError(error, recording);
1856
3046
  return;
@@ -1861,7 +3051,7 @@ var createExecutionRecorder = (options) => {
1861
3051
  }
1862
3052
  const callId = ++recording.nextCallId;
1863
3053
  const capturedError = serializedError(recording, error, callId);
1864
- const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
3054
+ const recordedArgs = capturedArgs ?? mapArrayLike(args, (argument) => captureValue(recording, argument));
1865
3055
  const endedAtNs = process.hrtime.bigint();
1866
3056
  const droppedBefore = recording.journal.dropped;
1867
3057
  const retained = recording.journal.forceCompletedCall(
@@ -1869,13 +3059,15 @@ var createExecutionRecorder = (options) => {
1869
3059
  callId,
1870
3060
  parentCallId,
1871
3061
  startedAtNs - recording.startedAtNs,
1872
- capturedArgs,
3062
+ recordedArgs,
1873
3063
  KIND_THROW,
1874
3064
  endedAtNs - recording.startedAtNs,
1875
3065
  endedAtNs - startedAtNs,
1876
3066
  capturedError.value
1877
3067
  );
1878
3068
  if (retained) {
3069
+ recording.lateCapturedCallIds ??= /* @__PURE__ */ new Set();
3070
+ recording.lateCapturedCallIds.add(callId);
1879
3071
  stats.functionCallsCaptured++;
1880
3072
  capturedError.commit();
1881
3073
  }
@@ -1920,35 +3112,47 @@ var createExecutionRecorder = (options) => {
1920
3112
  };
1921
3113
  const settleInFlight = (recording) => {
1922
3114
  if (recording.inFlightCalls > 0) recording.inFlightCalls--;
1923
- releaseJournalIfIdle(recording);
3115
+ releaseWhenIdle(recording);
1924
3116
  };
1925
- const finish = (store, metadata) => {
1926
- const { recording } = store;
1927
- if (recording.finished) return;
1928
- const recorderStartedAtNs = process.hrtime.bigint();
1929
- recording.finished = true;
1930
- if (metadata) mergeExecutionMetadata(recording.execution, metadata);
1931
- memoryBudget.release(recording.memory);
1932
- stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
1933
- if (!recording.hasError) {
1934
- stats.successfulExecutionsDiscarded++;
3117
+ const releaseWhenIdle = (recording) => {
3118
+ try {
3119
+ if (!recording.finished || recording.inFlightCalls > 0) return;
3120
+ memoryBudget.release(recording.memory);
1935
3121
  releaseJournalIfIdle(recording);
3122
+ } catch {
1936
3123
  }
1937
- recording.finishedAtNs = process.hrtime.bigint();
1938
- addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
1939
- recordInlineTiming(recording);
1940
3124
  };
1941
- 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) {
1942
3145
  if (!phaseTimingEnabled) return storage.run(store, callback);
1943
3146
  const alsStartedAtNs = process.hrtime.bigint();
1944
- return storage.run(store, () => {
3147
+ return storage.run(store, function __rasputinHandleRun__4() {
1945
3148
  addPhase("alsNs", process.hrtime.bigint() - alsStartedAtNs);
1946
3149
  return callback();
1947
3150
  });
1948
3151
  };
1949
3152
  const createScope = (metadata) => {
1950
- const recorderStartedAtNs = process.hrtime.bigint();
1951
3153
  try {
3154
+ const recorderStartedAtNs = process.hrtime.bigint();
3155
+ sweepLongLivedExecutions(recorderStartedAtNs);
1952
3156
  const recording = {
1953
3157
  executionId: `${Date.now()}-${process.pid}-${++executionCounter}`,
1954
3158
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1967,30 +3171,52 @@ var createExecutionRecorder = (options) => {
1967
3171
  hasError: false,
1968
3172
  memory: memoryBudget.startExecution(),
1969
3173
  partialSnapshotCounted: false,
1970
- derivationRoots: [],
1971
- derivationRootBytes: 0,
1972
3174
  sawAutomatic: false,
1973
- sawManual: false,
1974
- executedFunctionIds: /* @__PURE__ */ new Set()
3175
+ sawManual: false
1975
3176
  };
1976
3177
  stats.activeExecutions++;
1977
3178
  stats.peakActiveExecutions = Math.max(stats.peakActiveExecutions, stats.activeExecutions);
3179
+ liveRecordings.push(recording);
1978
3180
  addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
1979
3181
  const store = { recording };
1980
3182
  return {
1981
- run: (callback) => {
1982
- const runStartedAtNs = process.hrtime.bigint();
1983
- return runStore(store, () => {
1984
- 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;
1985
3201
  return callback();
1986
- });
3202
+ }
1987
3203
  },
1988
3204
  getErrorState: (error, errorMetadata) => {
1989
- const getStateStartedAtNs = process.hrtime.bigint();
1990
- if (errorMetadata) mergeExecutionMetadata(recording.execution, errorMetadata);
1991
- rememberError(error, recording);
1992
- addRecorderTime(recording, process.hrtime.bigint() - getStateStartedAtNs);
1993
- 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
+ }
1994
3220
  },
1995
3221
  finish: (finishMetadata) => finish(store, finishMetadata)
1996
3222
  };
@@ -1998,32 +3224,11 @@ var createExecutionRecorder = (options) => {
1998
3224
  return noOpExecution.createScope(metadata);
1999
3225
  }
2000
3226
  };
2001
- const run = (metadata, callback) => {
2002
- const scope = createScope(metadata);
2003
- return scope.run(
2004
- () => observeCallback(
2005
- callback,
2006
- () => scope.finish(),
2007
- (error) => {
2008
- try {
2009
- const store = storage.getStore();
2010
- if (store) {
2011
- const recorderStartedAtNs = process.hrtime.bigint();
2012
- rememberError(error, store.recording);
2013
- addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
2014
- }
2015
- } finally {
2016
- scope.finish();
2017
- }
2018
- }
2019
- )
2020
- );
2021
- };
2022
3227
  const getErrorState = (error, metadata) => {
2023
3228
  const getStateStartedAtNs = process.hrtime.bigint();
2024
3229
  try {
2025
3230
  const weakKey = (typeof error === "object" || typeof error === "function") && error !== null ? error : void 0;
2026
- const recording = (weakKey ? errorExecutions.get(weakKey) : void 0) ?? storage.getStore()?.recording;
3231
+ const recording = (weakKey ? errorExecutions.get(weakKey) : void 0) ?? currentStore()?.recording;
2027
3232
  if (!recording) return void 0;
2028
3233
  if (metadata) mergeExecutionMetadata(recording.execution, metadata);
2029
3234
  rememberError(error, recording);
@@ -2033,14 +3238,46 @@ var createExecutionRecorder = (options) => {
2033
3238
  return void 0;
2034
3239
  }
2035
3240
  };
2036
- const runPreparedFunction = (plan, args, callback, omitValues) => {
2037
- const store = storage.getStore();
2038
- 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
+ }
2039
3276
  stats.functionCallsObserved++;
2040
3277
  const recorderStartedAtNs = process.hrtime.bigint();
2041
3278
  if (store.suppressCapture || plan.excluded) {
2042
3279
  stats.functionCallsExcluded++;
2043
- return runStore({ ...store, suppressCapture: true }, () => {
3280
+ return runStore({ ...store, suppressCapture: true }, function __rasputinHandleRun__4() {
2044
3281
  addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
2045
3282
  return callback();
2046
3283
  });
@@ -2051,41 +3288,21 @@ var createExecutionRecorder = (options) => {
2051
3288
  const group = repeatedCallGroup(recording, plan, parentCallId);
2052
3289
  group.observedCalls++;
2053
3290
  const journal = acquireJournal(recording);
2054
- if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
3291
+ try {
3292
+ if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
3293
+ } catch {
3294
+ }
2055
3295
  if (group.observedCalls > maxCapturedCallsPerFunction) {
2056
3296
  const startedAtNs2 = process.hrtime.bigint();
2057
3297
  try {
2058
- const result = callback();
2059
- if (isPromiseLike(result)) {
2060
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2061
- return result.then(
2062
- (value) => {
2063
- const callbackEndedAtNs2 = process.hrtime.bigint();
2064
- recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs2);
2065
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2066
- settleInFlight(recording);
2067
- return value;
2068
- },
2069
- (error) => {
2070
- const callbackEndedAtNs2 = process.hrtime.bigint();
2071
- captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
2072
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
2073
- settleInFlight(recording);
2074
- throw error;
2075
- }
2076
- );
2077
- }
2078
- const callbackEndedAtNs = process.hrtime.bigint();
2079
- recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs);
2080
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2081
- 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());
2082
3302
  settleInFlight(recording);
2083
3303
  return result;
2084
3304
  } catch (error) {
2085
- const callbackEndedAtNs = process.hrtime.bigint();
2086
3305
  captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
2087
- addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
2088
- addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
2089
3306
  settleInFlight(recording);
2090
3307
  throw error;
2091
3308
  }
@@ -2093,9 +3310,8 @@ var createExecutionRecorder = (options) => {
2093
3310
  const startedAtNs = process.hrtime.bigint();
2094
3311
  if (!journal) {
2095
3312
  memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
2096
- return runStore(
2097
- store,
2098
- () => observeRecordedCallback(
3313
+ return runStore(store, function __rasputinHandleRun__4() {
3314
+ return observeRecordedCallback(
2099
3315
  recording,
2100
3316
  recorderStartedAtNs,
2101
3317
  callback,
@@ -2104,8 +3320,8 @@ var createExecutionRecorder = (options) => {
2104
3320
  rememberError(error, recording);
2105
3321
  settleInFlight(recording);
2106
3322
  }
2107
- )
2108
- );
3323
+ );
3324
+ });
2109
3325
  }
2110
3326
  if (!journal.canStartCall()) {
2111
3327
  const captureSuccess = () => {
@@ -2114,9 +3330,8 @@ var createExecutionRecorder = (options) => {
2114
3330
  countDroppedEvents(recording, droppedBefore);
2115
3331
  settleInFlight(recording);
2116
3332
  };
2117
- return runStore(
2118
- store,
2119
- () => observeRecordedCallback(
3333
+ return runStore(store, function __rasputinHandleRun__4() {
3334
+ return observeRecordedCallback(
2120
3335
  recording,
2121
3336
  recorderStartedAtNs,
2122
3337
  callback,
@@ -2125,8 +3340,8 @@ var createExecutionRecorder = (options) => {
2125
3340
  captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
2126
3341
  settleInFlight(recording);
2127
3342
  }
2128
- )
2129
- );
3343
+ );
3344
+ });
2130
3345
  }
2131
3346
  if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
2132
3347
  return observeRecordedCallback(
@@ -2142,12 +3357,27 @@ var createExecutionRecorder = (options) => {
2142
3357
  }
2143
3358
  const callId = ++recording.nextCallId;
2144
3359
  const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
2145
- const capturedArgs = omitValues ? Array.from(args, () => rasputinOmitted()) : Array.from(args, (argument) => captureValue(recording, argument));
2146
- 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
+ }
2147
3378
  const callStore = { recording, currentCallId: callId };
2148
- return runStore(
2149
- callStore,
2150
- () => observeRecordedCallback(
3379
+ return runStore(callStore, function __rasputinHandleRun__4() {
3380
+ return observeRecordedCallback(
2151
3381
  recording,
2152
3382
  recorderStartedAtNs,
2153
3383
  callback,
@@ -2155,7 +3385,7 @@ var createExecutionRecorder = (options) => {
2155
3385
  if (recording.journal) {
2156
3386
  const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
2157
3387
  const durationNs = process.hrtime.bigint() - startedAtNs;
2158
- const returnValue = omitValues ? rasputinOmitted() : captureValue(recording, value);
3388
+ const returnValue = omitCallValues ? rasputinOmitted() : captureValue(recording, value);
2159
3389
  recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
2160
3390
  stats.functionCallsCaptured++;
2161
3391
  }
@@ -2180,113 +3410,519 @@ var createExecutionRecorder = (options) => {
2180
3410
  rememberError(error, recording);
2181
3411
  settleInFlight(recording);
2182
3412
  }
2183
- )
2184
- );
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
+ }
2185
3777
  };
2186
3778
  const runFunction = (input, args, callback) => {
2187
- const store = storage.getStore();
3779
+ const store = currentStore();
2188
3780
  if (store && !store.recording.finished) store.recording.sawManual = true;
2189
- return runPreparedFunction(preparePlan(normalizeFunctionDefinition(input)), args, callback);
3781
+ return runPreparedFunctionFromStore(
3782
+ store,
3783
+ preparePlan(normalizeFunctionDefinition(input)),
3784
+ args,
3785
+ callback
3786
+ );
2190
3787
  };
2191
3788
  const runFunctionPlans = (plans, planIndex, args, callback, omitValues) => {
2192
- const store = storage.getStore();
3789
+ const store = currentStore();
2193
3790
  const plan = preparedPlansFor(plans)[planIndex];
2194
- if (store && !store.recording.finished) {
3791
+ if (store && !store.recording.finished && !store.recording.sawAutomatic) {
2195
3792
  store.recording.sawAutomatic = true;
2196
- if (plan) store.recording.executedFunctionIds.add(plan.functionId);
2197
3793
  }
2198
- return plan ? runPreparedFunction(plan, args, callback, omitValues) : callback();
3794
+ return plan ? runPreparedFunctionFromStore(store, plan, args, callback, omitValues) : callback();
2199
3795
  };
2200
3796
  const prepareFunctionPlans = (plans) => preparedPlansFor(plans);
2201
3797
  function trace(input, fn) {
2202
3798
  const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
2203
3799
  const plan = preparePlan(definition);
2204
- return function traced(...args) {
2205
- 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();
2206
3806
  if (store && !store.recording.finished) store.recording.sawManual = true;
2207
- return runPreparedFunction(plan, args, () => fn.apply(this, args));
3807
+ return runPreparedFunctionFromStore(store, plan, args, function __rasputinHandleRun__4() {
3808
+ return fn.apply(receiver, args);
3809
+ });
2208
3810
  };
2209
3811
  }
2210
- const captureDerivationRoot = (rootId, value) => {
2211
- const store = storage.getStore();
2212
- if (!store || store.recording.finished || store.suppressCapture) return value;
2213
- const recording = store.recording;
2214
- if (recording.memory.mode !== "full") return value;
2215
- if (recording.derivationRoots.length >= maxEventsPerExecution) return value;
2216
- const recorderStartedAtNs = process.hrtime.bigint();
2217
- try {
2218
- const serialized = captureValue(recording, value);
2219
- if (recording.memory.mode !== "full") return value;
2220
- if (!memoryBudget.reserveStorage(recording.memory, DERIVATION_ROOT_RECORD_BYTES)) {
2221
- return value;
2222
- }
2223
- const completeness = capturedValueCompleteness(serialized);
2224
- const bytes = jsonLiteralUtf8Bytes(serialized);
2225
- recording.derivationRoots.push({
2226
- rootId,
2227
- callId: store.currentCallId ?? 0,
2228
- value: serialized,
2229
- completeness
2230
- });
2231
- recording.derivationRootBytes += bytes;
2232
- stats.derivationRootsCaptured++;
2233
- stats.derivationRootBytes += bytes;
2234
- stats.derivationFallbackExpressions++;
2235
- return value;
2236
- } finally {
2237
- addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
2238
- }
2239
- };
2240
3812
  return {
2241
3813
  createScope,
2242
- run,
2243
3814
  getErrorState,
2244
3815
  runFunction,
2245
3816
  runFunctionPlans,
2246
3817
  prepareFunctionPlans,
2247
3818
  runPreparedFunction,
3819
+ enterPreparedFunction,
2248
3820
  trace,
2249
- captureDerivationRoot,
2250
- getStats: () => {
2251
- const manifest = snapshotInstrumentationManifest();
2252
- const plans = manifest?.derivationPlans ?? [];
2253
- return {
2254
- ...stats,
2255
- ...memoryBudget.getStats(),
2256
- ...journalPool.stats(),
2257
- derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
2258
- derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
2259
- derivationFallbackReasons: { ...stats.derivationFallbackReasons },
2260
- ...phases ? {
2261
- phaseAlsNs: Number(phases.alsNs),
2262
- phaseMaterializeNs: Number(phases.materializeNs)
2263
- } : {}
2264
- };
2265
- }
3821
+ getStats: () => ({
3822
+ ...stats,
3823
+ ...memoryBudget.getStats(),
3824
+ ...journalPool.stats(),
3825
+ ...phases ? {
3826
+ phaseAlsNs: Number(phases.alsNs),
3827
+ phaseMaterializeNs: Number(phases.materializeNs)
3828
+ } : {}
3829
+ })
2266
3830
  };
2267
3831
  };
2268
3832
 
2269
3833
  // src/execution-recorder/automatic-runtime.ts
2270
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
3834
+ var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v3";
2271
3835
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
2272
- var passthroughCapture = (_rootId, value) => value;
2273
- 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();
2274
3888
  var bindPassthrough = (module) => {
2275
- 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
+ };
2276
3913
  };
2277
3914
  var isRegistry = (value) => Array.isArray(Reflect.get(value, "runtimes")) && Array.isArray(Reflect.get(value, "modules")) && typeof Reflect.get(value, "register") === "function";
2278
3915
  var registerModule = (registry, plans) => {
2279
- const cell = { run: passthrough };
3916
+ const cell = { run: passthroughRun, enter: passthroughEnter };
2280
3917
  const module = { plans, cell };
2281
3918
  registry.modules.push(module);
2282
3919
  registry.runtimes.at(-1)?.bind(module);
2283
- return (planIndex, args, callback, omitValues) => cell.run(planIndex, args, callback, omitValues);
3920
+ return attachRunner(cell);
2284
3921
  };
2285
3922
  var createRegistry = () => {
2286
3923
  const registry = {
2287
3924
  runtimes: [],
2288
3925
  modules: [],
2289
- captureRoot: passthroughCapture,
2290
3926
  register(plans) {
2291
3927
  return registerModule(registry, plans);
2292
3928
  }
@@ -2296,9 +3932,6 @@ var createRegistry = () => {
2296
3932
  var getAutomaticRuntimeRegistry = () => {
2297
3933
  const existing = Reflect.get(globalThis, runtimeSymbol);
2298
3934
  if (existing && typeof existing === "object" && isRegistry(existing)) {
2299
- if (typeof existing.captureRoot !== "function") {
2300
- existing.captureRoot = passthroughCapture;
2301
- }
2302
3935
  return existing;
2303
3936
  }
2304
3937
  const registry = createRegistry();
@@ -2309,18 +3942,15 @@ var installAutomaticExecutionRuntime = (execution) => {
2309
3942
  const registry = getAutomaticRuntimeRegistry();
2310
3943
  const runtime = {
2311
3944
  bind(module) {
2312
- module.cell.run = (planIndex, args, callback, omitValues) => execution.runFunctionPlans(module.plans, planIndex, args, callback, omitValues);
2313
- },
2314
- captureRoot: (rootId, value) => execution.captureDerivationRoot(rootId, value)
3945
+ bindExecution(execution, module);
3946
+ }
2315
3947
  };
2316
3948
  registry.runtimes.push(runtime);
2317
- registry.captureRoot = runtime.captureRoot;
2318
3949
  for (const module of registry.modules) runtime.bind(module);
2319
3950
  return () => {
2320
3951
  const index = registry.runtimes.lastIndexOf(runtime);
2321
3952
  if (index >= 0) registry.runtimes.splice(index, 1);
2322
3953
  const current = registry.runtimes.at(-1);
2323
- registry.captureRoot = current?.captureRoot ?? passthroughCapture;
2324
3954
  for (const module of registry.modules) {
2325
3955
  if (current) current.bind(module);
2326
3956
  else bindPassthrough(module);
@@ -2329,117 +3959,234 @@ var installAutomaticExecutionRuntime = (execution) => {
2329
3959
  };
2330
3960
 
2331
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
+ };
2332
3991
  var removeProcessListener = process.off.bind(process);
2333
- var installGlobalHandlers = (client, options = {}) => {
2334
- const exitOnUncaught = options.exitOnUncaughtException ?? true;
2335
- const flushTimeoutMs = options.flushTimeoutMs ?? 2e3;
2336
- let handlingUncaught = false;
2337
- 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) {
2338
4005
  try {
2339
- client.captureException(reason);
4006
+ entry.client.captureException(error);
2340
4007
  } catch {
2341
4008
  }
2342
- };
2343
- 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
+ );
2344
4034
  if (handlingUncaught) {
2345
- process.exit(1);
4035
+ if (exitOnUncaught && hostListenerCount("uncaughtException") === 0) {
4036
+ process.exit(1);
4037
+ }
2346
4038
  return;
2347
4039
  }
2348
4040
  handlingUncaught = true;
2349
- try {
2350
- client.captureException(error);
2351
- } catch {
2352
- }
2353
- 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;
2354
4046
  const shutdown = async () => {
2355
4047
  try {
2356
- await client.flush(flushTimeoutMs);
4048
+ await flushAll(flushTimeoutMs);
2357
4049
  } catch {
2358
4050
  }
2359
- if (exitOnUncaught && soleListener) process.exit(1);
4051
+ if (shouldExit) {
4052
+ process.exit(1);
4053
+ return;
4054
+ }
4055
+ handlingUncaught = false;
2360
4056
  };
4057
+ if (shouldExit) {
4058
+ const watchdog = setTimeout(() => process.exit(1), flushTimeoutMs + 50);
4059
+ void shutdown().finally(() => clearTimeout(watchdog));
4060
+ return;
4061
+ }
2361
4062
  void shutdown();
2362
- };
4063
+ });
2363
4064
  try {
2364
4065
  process.on("uncaughtException", onUncaughtException);
2365
- process.on("unhandledRejection", onUnhandledRejection);
4066
+ if (!unhandledRejectionIsFatal()) {
4067
+ process.on("unhandledRejection", onUnhandledRejection);
4068
+ }
2366
4069
  } catch {
2367
- return () => {
2368
- };
4070
+ return;
2369
4071
  }
2370
- return () => {
4072
+ uninstallProcess = () => {
2371
4073
  try {
2372
4074
  removeProcessListener("uncaughtException", onUncaughtException);
2373
4075
  removeProcessListener("unhandledRejection", onUnhandledRejection);
2374
4076
  } catch {
2375
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?.();
2376
4094
  };
2377
4095
  };
2378
-
2379
- // src/rasputin-init.ts
2380
- import { join } from "node:path";
2381
- import {
2382
- createClient,
2383
- isClientEnabled
2384
- } from "@rasputin-ai/core";
2385
4096
 
2386
4097
  // src/sdk-meta.ts
2387
4098
  var SDK_NAME = "@rasputin-ai/node";
2388
- var SDK_VERSION = "0.5.0-alpha.8";
4099
+ var SDK_VERSION = "0.5.0";
2389
4100
 
2390
4101
  // src/rasputin-init.ts
2391
- var withExecution = (client, execution, installRuntime, manifest) => {
2392
- 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) : () => {
2393
4117
  };
2394
4118
  const manifestUpload = scheduleInstrumentationManifestUpload(manifest);
4119
+ const execution = publicExecution(runtime);
2395
4120
  return {
2396
4121
  ...client,
2397
4122
  execution,
2398
4123
  getStats: () => ({ ...client.getStats(), recorder: execution.getStats() }),
2399
4124
  verifyConfiguration: manifestUpload.verify,
2400
4125
  captureException: (error, context) => {
2401
- const runtimeState = context?.runtimeState ?? execution.getErrorState(
2402
- error,
2403
- context?.request ? { kind: "http", request: context.request } : void 0
2404
- );
2405
- const result = client.captureException(error, { ...context, runtimeState });
4126
+ const result = client.captureException(error, context);
2406
4127
  manifestUpload.flushSoon();
2407
4128
  return result;
2408
4129
  },
2409
4130
  flush: async (timeoutMs) => {
4131
+ const startedAt = Date.now();
2410
4132
  await client.flush(timeoutMs);
2411
- 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)));
2412
4138
  },
2413
4139
  close: async () => {
4140
+ uninstallHandlers();
2414
4141
  uninstallRuntime();
2415
4142
  manifestUpload.disconnect();
4143
+ const startedAt = Date.now();
2416
4144
  await client.close();
2417
- await manifestUpload.wait();
4145
+ await manifestUpload.wait(Math.max(0, 2e3 - (Date.now() - startedAt)));
2418
4146
  }
2419
4147
  };
2420
4148
  };
2421
4149
  var RasputinInit = (options) => {
2422
4150
  try {
2423
- const client = createClient(options, { sdkVersion: SDK_VERSION, sdkName: SDK_NAME });
2424
- const recorderEnabled = isClientEnabled(options) && options.executionRecorder?.enabled !== false;
2425
- const execution = createExecutionRecorder({
4151
+ const enabled = isClientEnabled(options);
4152
+ const recorderEnabled = enabled && options.executionRecorder?.enabled !== false;
4153
+ const runtime = createExecutionRecorder({
2426
4154
  ...options.executionRecorder,
2427
4155
  enabled: recorderEnabled
2428
4156
  });
2429
- loadInstrumentationManifestIfPresent(
2430
- options.instrumentationManifestPath ?? process.env.RASPUTIN_INSTRUMENTATION_MANIFEST ?? join(process.cwd(), ".rasputin", "instrumentation-manifest.json")
2431
- );
2432
- const wrappedClient = withExecution(client, execution, recorderEnabled, {
2433
- projectApiKey: options.projectApiKey,
2434
- release: options.release,
2435
- apiUrl: options.apiUrl,
2436
- enabled: isClientEnabled(options),
2437
- sourceRoot: options.sourceRoot,
2438
- sourceRoots: options.sourceRoots,
2439
- 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
+ )
2440
4165
  });
2441
- if (isClientEnabled(options)) {
2442
- 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);
2443
4190
  }
2444
4191
  return wrappedClient;
2445
4192
  } catch {
@@ -2448,7 +4195,7 @@ var RasputinInit = (options) => {
2448
4195
  createExecutionRecorder({ enabled: false }),
2449
4196
  false,
2450
4197
  {
2451
- projectApiKey: options.projectApiKey,
4198
+ projectApiKey: options.projectApiKey ?? "",
2452
4199
  release: options.release,
2453
4200
  apiUrl: options.apiUrl,
2454
4201
  enabled: false,
@@ -2460,9 +4207,5 @@ var RasputinInit = (options) => {
2460
4207
  }
2461
4208
  };
2462
4209
  export {
2463
- RasputinInit,
2464
- createExecutionRecorder,
2465
- installAutomaticExecutionRuntime,
2466
- installGlobalHandlers,
2467
- scheduleInstrumentationManifestUpload
4210
+ RasputinInit
2468
4211
  };