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