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