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