@rasputin-ai/node 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts +6 -0
- package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts.map +1 -1
- package/dist/auto-instrumentation/format-configuration-report.d.ts +14 -0
- package/dist/auto-instrumentation/format-configuration-report.d.ts.map +1 -0
- package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +9 -3
- package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
- package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts +11 -1
- package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts.map +1 -1
- package/dist/execution-recorder/automatic-runtime.d.ts +11 -8
- package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
- package/dist/execution-recorder/execution-recorder-types.d.ts +10 -3
- package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
- package/dist/execution-recorder/execution-recorder.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/source-exclusions.d.ts +2 -1
- package/dist/execution-recorder/source-exclusions.d.ts.map +1 -1
- package/dist/index.js +322 -113
- package/dist/instrument/bun.js +33 -21
- package/dist/instrument/node.js +32 -20
- package/dist/rasputin-init.d.ts +3 -2
- package/dist/rasputin-init.d.ts.map +1 -1
- package/dist/sdk-meta.d.ts +2 -2
- package/dist/sdk-meta.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5,23 +5,133 @@ import {
|
|
|
5
5
|
uploadInstrumentationManifest
|
|
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
|
+
|
|
8
105
|
// src/auto-instrumentation/instrumentation-manifest-registry.ts
|
|
9
|
-
import {
|
|
106
|
+
import { createHash } from "node:crypto";
|
|
107
|
+
import {
|
|
108
|
+
INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
|
|
109
|
+
sourceLocatorFromFile as sourceLocatorFromFile2
|
|
110
|
+
} from "@rasputin-ai/core";
|
|
10
111
|
|
|
11
112
|
// src/execution-recorder/automatic-runtime.ts
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
113
|
+
import {
|
|
114
|
+
runtimeFunctionId,
|
|
115
|
+
sourceLocatorFromFile
|
|
116
|
+
} from "@rasputin-ai/core";
|
|
117
|
+
var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
|
|
118
|
+
var AUTOMATIC_SOURCE_PREFIX = "rasputin-source-v2:";
|
|
15
119
|
var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
|
|
16
|
-
var
|
|
17
|
-
if (!sourceToken.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
120
|
+
var decodeAutomaticFunctionSource = (sourceToken) => {
|
|
121
|
+
if (!sourceToken.startsWith(AUTOMATIC_SOURCE_PREFIX)) return void 0;
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(
|
|
124
|
+
sourceToken.slice(AUTOMATIC_SOURCE_PREFIX.length)
|
|
125
|
+
);
|
|
126
|
+
if (typeof parsed.name !== "string" || !parsed.name) return void 0;
|
|
127
|
+
const definition = {
|
|
128
|
+
name: parsed.name,
|
|
129
|
+
...parsed.source ? { source: parsed.source } : {}
|
|
130
|
+
};
|
|
131
|
+
return { ...definition, functionId: runtimeFunctionId(definition) };
|
|
132
|
+
} catch {
|
|
22
133
|
return void 0;
|
|
23
134
|
}
|
|
24
|
-
return `${fromRoot.replaceAll("\\", "/")}:${name}@${line}:${column}`;
|
|
25
135
|
};
|
|
26
136
|
var getRegistry = () => {
|
|
27
137
|
const existing = Reflect.get(globalThis, runtimeSymbol);
|
|
@@ -32,30 +142,25 @@ var getRegistry = () => {
|
|
|
32
142
|
const registry = {
|
|
33
143
|
__rasputinRuntimeRegistry: true,
|
|
34
144
|
runtimes,
|
|
35
|
-
run: (
|
|
145
|
+
run: (sourceToken, args, callback) => {
|
|
36
146
|
const runtime = runtimes.at(-1);
|
|
37
|
-
return runtime ? runtime.run(
|
|
147
|
+
return runtime ? runtime.run(sourceToken, args, callback) : callback();
|
|
38
148
|
}
|
|
39
149
|
};
|
|
40
150
|
Reflect.set(globalThis, runtimeSymbol, registry);
|
|
41
151
|
return registry;
|
|
42
152
|
};
|
|
43
|
-
var installAutomaticExecutionRuntime = (execution
|
|
153
|
+
var installAutomaticExecutionRuntime = (execution) => {
|
|
44
154
|
const registry = getRegistry();
|
|
45
|
-
const
|
|
46
|
-
const normalizedIds = /* @__PURE__ */ new Map();
|
|
155
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
47
156
|
const runtime = {
|
|
48
157
|
run: (sourceToken, args, callback) => {
|
|
49
|
-
|
|
50
|
-
|
|
158
|
+
let definition = definitions.get(sourceToken);
|
|
159
|
+
if (!definitions.has(sourceToken)) {
|
|
160
|
+
definition = decodeAutomaticFunctionSource(sourceToken);
|
|
161
|
+
definitions.set(sourceToken, definition);
|
|
51
162
|
}
|
|
52
|
-
|
|
53
|
-
let functionId = normalizedIds.get(sourceToken);
|
|
54
|
-
if (!normalizedIds.has(sourceToken)) {
|
|
55
|
-
functionId = normalizeAutomaticFunctionId(sourceToken, repoRoot);
|
|
56
|
-
normalizedIds.set(sourceToken, functionId);
|
|
57
|
-
}
|
|
58
|
-
return functionId ? execution.runFunction(functionId, args, callback) : callback();
|
|
163
|
+
return definition ? execution.runFunction(definition, args, callback) : callback();
|
|
59
164
|
}
|
|
60
165
|
};
|
|
61
166
|
registry.runtimes.push(runtime);
|
|
@@ -66,7 +171,7 @@ var installAutomaticExecutionRuntime = (execution, options = {}) => {
|
|
|
66
171
|
};
|
|
67
172
|
|
|
68
173
|
// src/auto-instrumentation/instrumentation-manifest-registry.ts
|
|
69
|
-
var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.
|
|
174
|
+
var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
|
|
70
175
|
var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
|
|
71
176
|
var getRegistry2 = () => {
|
|
72
177
|
const existing = Reflect.get(globalThis, registrySymbol);
|
|
@@ -82,31 +187,28 @@ var getRegistry2 = () => {
|
|
|
82
187
|
Reflect.set(globalThis, registrySymbol, registry);
|
|
83
188
|
return registry;
|
|
84
189
|
};
|
|
85
|
-
var
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
return void 0;
|
|
89
|
-
}
|
|
90
|
-
return fromRoot.replaceAll("\\", "/");
|
|
190
|
+
var sourceAt = (filePath, line, column) => {
|
|
191
|
+
const source = sourceLocatorFromFile2(filePath);
|
|
192
|
+
return source ? { ...source, line, column } : void 0;
|
|
91
193
|
};
|
|
194
|
+
var stableId = (kind, ...parts) => `${kind}_${createHash("sha256").update(parts.join("\0")).digest("base64url").slice(0, 24)}`;
|
|
92
195
|
var isInstrumentationManifestDirty = () => {
|
|
93
196
|
const registry = getRegistry2();
|
|
94
197
|
return registry.generation !== registry.uploadedGeneration && registry.files.size > 0;
|
|
95
198
|
};
|
|
96
199
|
var instrumentationManifestGeneration = () => getRegistry2().generation;
|
|
97
|
-
var
|
|
200
|
+
var instrumentationManifestModuleCount = () => getRegistry2().files.size;
|
|
201
|
+
var snapshotInstrumentationManifest = (options = {}) => {
|
|
98
202
|
const functions = [];
|
|
99
203
|
const callSites = [];
|
|
100
204
|
const destructures = [];
|
|
101
|
-
const root = resolve2(repoRoot);
|
|
102
205
|
for (const delta of getRegistry2().files.values()) {
|
|
103
206
|
for (const fn of delta.functions) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (!functionId || !path) continue;
|
|
207
|
+
const definition = decodeAutomaticFunctionSource(fn.sourceToken);
|
|
208
|
+
if (!definition?.source) continue;
|
|
107
209
|
functions.push({
|
|
108
|
-
functionId,
|
|
109
|
-
|
|
210
|
+
functionId: definition.functionId,
|
|
211
|
+
source: definition.source,
|
|
110
212
|
name: fn.name,
|
|
111
213
|
startLine: fn.startLine,
|
|
112
214
|
startColumn: fn.startColumn,
|
|
@@ -116,15 +218,22 @@ var snapshotInstrumentationManifest = (repoRoot) => {
|
|
|
116
218
|
});
|
|
117
219
|
}
|
|
118
220
|
for (const site of delta.callSites) {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
if (!
|
|
221
|
+
const caller = decodeAutomaticFunctionSource(site.callerSourceToken);
|
|
222
|
+
const source = sourceAt(site.filePath, site.line, site.column);
|
|
223
|
+
if (!caller || !source) continue;
|
|
122
224
|
callSites.push({
|
|
123
|
-
id:
|
|
124
|
-
|
|
225
|
+
id: stableId(
|
|
226
|
+
"cs",
|
|
227
|
+
caller.functionId,
|
|
228
|
+
source.packageName ?? "",
|
|
229
|
+
source.packageRelativePath,
|
|
230
|
+
site.line,
|
|
231
|
+
site.column
|
|
232
|
+
),
|
|
233
|
+
callerFunctionId: caller.functionId,
|
|
125
234
|
calleeName: site.calleeName,
|
|
126
235
|
calleeText: site.calleeText,
|
|
127
|
-
|
|
236
|
+
source,
|
|
128
237
|
line: site.line,
|
|
129
238
|
column: site.column,
|
|
130
239
|
endLine: site.endLine,
|
|
@@ -134,13 +243,13 @@ var snapshotInstrumentationManifest = (repoRoot) => {
|
|
|
134
243
|
});
|
|
135
244
|
}
|
|
136
245
|
for (const destructure of delta.destructures) {
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
if (!
|
|
246
|
+
const caller = decodeAutomaticFunctionSource(destructure.callerSourceToken);
|
|
247
|
+
const source = sourceAt(destructure.filePath, destructure.line, destructure.column);
|
|
248
|
+
if (!caller || !source) continue;
|
|
140
249
|
destructures.push({
|
|
141
|
-
callerFunctionId,
|
|
250
|
+
callerFunctionId: caller.functionId,
|
|
142
251
|
sourceParam: destructure.sourceParam,
|
|
143
|
-
|
|
252
|
+
source,
|
|
144
253
|
line: destructure.line,
|
|
145
254
|
column: destructure.column,
|
|
146
255
|
binding: destructure.binding
|
|
@@ -150,8 +259,15 @@ var snapshotInstrumentationManifest = (repoRoot) => {
|
|
|
150
259
|
if (functions.length === 0 && callSites.length === 0 && destructures.length === 0) {
|
|
151
260
|
return void 0;
|
|
152
261
|
}
|
|
262
|
+
const packages = { ...options.sourceRoots ?? {} };
|
|
153
263
|
return {
|
|
154
|
-
schema_version:
|
|
264
|
+
schema_version: INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
|
|
265
|
+
...options.sourceRoot || Object.keys(packages).length > 0 ? {
|
|
266
|
+
sourceRoots: {
|
|
267
|
+
...options.sourceRoot ? { default: options.sourceRoot } : {},
|
|
268
|
+
packages
|
|
269
|
+
}
|
|
270
|
+
} : {},
|
|
155
271
|
functions,
|
|
156
272
|
callSites,
|
|
157
273
|
destructures
|
|
@@ -159,35 +275,63 @@ var snapshotInstrumentationManifest = (repoRoot) => {
|
|
|
159
275
|
};
|
|
160
276
|
var markInstrumentationManifestUploaded = (generation) => {
|
|
161
277
|
const registry = getRegistry2();
|
|
162
|
-
if (registry.generation === generation)
|
|
163
|
-
registry.uploadedGeneration = generation;
|
|
164
|
-
}
|
|
278
|
+
if (registry.generation === generation) registry.uploadedGeneration = generation;
|
|
165
279
|
};
|
|
166
280
|
var setInstrumentationManifestOnDirty = (onDirty) => {
|
|
167
281
|
getRegistry2().onDirty = onDirty;
|
|
168
282
|
};
|
|
169
283
|
|
|
170
284
|
// src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts
|
|
285
|
+
var unavailable = () => ({
|
|
286
|
+
status: "unavailable",
|
|
287
|
+
verified: 0,
|
|
288
|
+
unresolved: [],
|
|
289
|
+
packages: []
|
|
290
|
+
});
|
|
171
291
|
var noopHandle = {
|
|
172
292
|
flushSoon() {
|
|
173
293
|
},
|
|
174
294
|
async wait() {
|
|
175
295
|
},
|
|
176
296
|
disconnect() {
|
|
297
|
+
},
|
|
298
|
+
async verify() {
|
|
299
|
+
return unavailable();
|
|
177
300
|
}
|
|
178
301
|
};
|
|
179
302
|
var scheduleInstrumentationManifestUpload = (options) => {
|
|
180
303
|
const release = detectRelease({ release: options.release });
|
|
181
|
-
|
|
182
|
-
if (!options.enabled || !release || !repoRoot || !options.projectApiKey.trim()) {
|
|
304
|
+
if (!options.enabled || !release || !options.projectApiKey.trim()) {
|
|
183
305
|
return noopHandle;
|
|
184
306
|
}
|
|
185
307
|
const { instrumentationManifestUrl } = resolveEndpointUrls(options.apiUrl);
|
|
186
308
|
let inflight;
|
|
309
|
+
let verification = unavailable();
|
|
310
|
+
let loggedSuccess = false;
|
|
311
|
+
let loggedFailure = false;
|
|
312
|
+
const packageNamesOf = (manifest) => [
|
|
313
|
+
...new Set(
|
|
314
|
+
manifest.functions.map((fn) => fn.source.packageName).filter((name) => Boolean(name))
|
|
315
|
+
)
|
|
316
|
+
].sort();
|
|
317
|
+
const report = (manifest, uploaded, next) => {
|
|
318
|
+
return formatConfigurationReport({
|
|
319
|
+
release,
|
|
320
|
+
runtime: runtimeLabel(),
|
|
321
|
+
modules: instrumentationManifestModuleCount(),
|
|
322
|
+
functions: manifest.functions.length,
|
|
323
|
+
packageNames: packageNamesOf(manifest),
|
|
324
|
+
verification: next,
|
|
325
|
+
uploaded
|
|
326
|
+
});
|
|
327
|
+
};
|
|
187
328
|
const flushSoon = () => {
|
|
188
329
|
if (!isInstrumentationManifestDirty()) return;
|
|
189
330
|
const generation = instrumentationManifestGeneration();
|
|
190
|
-
const manifest = snapshotInstrumentationManifest(
|
|
331
|
+
const manifest = snapshotInstrumentationManifest({
|
|
332
|
+
sourceRoot: options.sourceRoot,
|
|
333
|
+
sourceRoots: options.sourceRoots
|
|
334
|
+
});
|
|
191
335
|
if (!manifest) {
|
|
192
336
|
markInstrumentationManifestUploaded(generation);
|
|
193
337
|
return;
|
|
@@ -199,7 +343,26 @@ var scheduleInstrumentationManifestUpload = (options) => {
|
|
|
199
343
|
manifest,
|
|
200
344
|
fetch: options.fetch
|
|
201
345
|
}).then((result) => {
|
|
202
|
-
if (result
|
|
346
|
+
if (result.ok) {
|
|
347
|
+
verification = result.verification;
|
|
348
|
+
markInstrumentationManifestUploaded(generation);
|
|
349
|
+
if (verification.status === "verified") {
|
|
350
|
+
if (!loggedSuccess && options.logSuccess !== false) {
|
|
351
|
+
loggedSuccess = true;
|
|
352
|
+
console.info(report(manifest, true, verification));
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (!loggedFailure) {
|
|
357
|
+
loggedFailure = true;
|
|
358
|
+
console.warn(report(manifest, true, verification));
|
|
359
|
+
}
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!loggedFailure) {
|
|
363
|
+
loggedFailure = true;
|
|
364
|
+
console.warn(report(manifest, false, unavailable()));
|
|
365
|
+
}
|
|
203
366
|
});
|
|
204
367
|
inflight = inflight ? inflight.then(() => work) : work;
|
|
205
368
|
};
|
|
@@ -212,12 +375,18 @@ var scheduleInstrumentationManifestUpload = (options) => {
|
|
|
212
375
|
},
|
|
213
376
|
disconnect: () => {
|
|
214
377
|
setInstrumentationManifestOnDirty(void 0);
|
|
378
|
+
},
|
|
379
|
+
verify: async () => {
|
|
380
|
+
flushSoon();
|
|
381
|
+
await inflight;
|
|
382
|
+
return verification;
|
|
215
383
|
}
|
|
216
384
|
};
|
|
217
385
|
};
|
|
218
386
|
|
|
219
387
|
// src/execution-recorder/execution-recorder.ts
|
|
220
388
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
389
|
+
import { runtimeFunctionId as runtimeFunctionId2 } from "@rasputin-ai/core";
|
|
221
390
|
|
|
222
391
|
// src/execution-recorder/call-aware-event-buffer.ts
|
|
223
392
|
var CallAwareEventBuffer = class {
|
|
@@ -577,9 +746,10 @@ var safeSerializeWithBytes = (value, options = {}) => {
|
|
|
577
746
|
var safeSerialize = (value, options = {}) => safeSerializeWithBytes(value, options).value;
|
|
578
747
|
|
|
579
748
|
// src/execution-recorder/source-exclusions.ts
|
|
580
|
-
var sourcePathFrom = (
|
|
581
|
-
|
|
582
|
-
|
|
749
|
+
var sourcePathFrom = (definition) => definition.source?.packageRelativePath.replaceAll("\\", "/") ?? definition.name;
|
|
750
|
+
var searchableIdentity = (definition) => {
|
|
751
|
+
const source = definition.source;
|
|
752
|
+
return source ? `${source.packageName ? `${source.packageName}:` : ""}${source.packageRelativePath}:${definition.name}@${source.line ?? ""}:${source.column ?? ""}` : definition.name;
|
|
583
753
|
};
|
|
584
754
|
var normalizePattern = (pattern) => pattern.trim().replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
585
755
|
var globRegex = (pattern) => {
|
|
@@ -610,35 +780,51 @@ var globRegex = (pattern) => {
|
|
|
610
780
|
return new RegExp(`^${expression}$`);
|
|
611
781
|
};
|
|
612
782
|
var createSourceExclusionMatcher = (exclusions) => {
|
|
613
|
-
const matchers = (exclusions ?? []).flatMap(
|
|
614
|
-
|
|
783
|
+
const matchers = (exclusions ?? []).flatMap(
|
|
784
|
+
(exclusion) => {
|
|
785
|
+
if (exclusion instanceof RegExp) {
|
|
786
|
+
return [
|
|
787
|
+
(definition) => {
|
|
788
|
+
exclusion.lastIndex = 0;
|
|
789
|
+
const matched = exclusion.test(searchableIdentity(definition));
|
|
790
|
+
exclusion.lastIndex = 0;
|
|
791
|
+
return matched;
|
|
792
|
+
}
|
|
793
|
+
];
|
|
794
|
+
}
|
|
795
|
+
const pattern = normalizePattern(exclusion);
|
|
796
|
+
if (!pattern) return [];
|
|
797
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
798
|
+
const regex = globRegex(pattern);
|
|
799
|
+
return [(definition) => regex.test(sourcePathFrom(definition))];
|
|
800
|
+
}
|
|
615
801
|
return [
|
|
616
|
-
(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
exclusion.lastIndex = 0;
|
|
620
|
-
return matched;
|
|
802
|
+
(definition) => {
|
|
803
|
+
const sourcePath = sourcePathFrom(definition);
|
|
804
|
+
return sourcePath === pattern || sourcePath.startsWith(`${pattern}/`);
|
|
621
805
|
}
|
|
622
806
|
];
|
|
623
807
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (pattern.includes("*") || pattern.includes("?")) {
|
|
627
|
-
const regex = globRegex(pattern);
|
|
628
|
-
return [(functionId) => regex.test(sourcePathFrom(functionId))];
|
|
629
|
-
}
|
|
630
|
-
return [
|
|
631
|
-
(functionId) => {
|
|
632
|
-
const sourcePath = sourcePathFrom(functionId);
|
|
633
|
-
return sourcePath === pattern || sourcePath.startsWith(`${pattern}/`);
|
|
634
|
-
}
|
|
635
|
-
];
|
|
636
|
-
});
|
|
637
|
-
return matchers.length === 0 ? () => false : (functionId) => matchers.some((matcher) => matcher(functionId));
|
|
808
|
+
);
|
|
809
|
+
return matchers.length === 0 ? () => false : (definition) => matchers.some((matcher) => matcher(definition));
|
|
638
810
|
};
|
|
639
811
|
|
|
640
812
|
// src/execution-recorder/execution-recorder.ts
|
|
641
813
|
var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
|
|
814
|
+
var manualFunctionDefinition = (value) => {
|
|
815
|
+
const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
|
|
816
|
+
const named = located ? void 0 : /^(.+):([^:@]+)$/.exec(value);
|
|
817
|
+
const path = located?.[1] ?? named?.[1];
|
|
818
|
+
const name = located?.[2] ?? named?.[2] ?? value;
|
|
819
|
+
const source = path ? {
|
|
820
|
+
packageRelativePath: path.replaceAll("\\", "/").replace(/^\.\//, ""),
|
|
821
|
+
...located?.[3] ? { line: Number(located[3]) } : {},
|
|
822
|
+
...located?.[4] ? { column: Number(located[4]) } : {}
|
|
823
|
+
} : void 0;
|
|
824
|
+
const definition = { name, ...source ? { source } : {} };
|
|
825
|
+
return { ...definition, functionId: runtimeFunctionId2(definition) };
|
|
826
|
+
};
|
|
827
|
+
var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualFunctionDefinition(value) : value;
|
|
642
828
|
var elapsedMs = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
|
|
643
829
|
var roundedMilliseconds = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
|
|
644
830
|
var addRecorderTime = (recording, nanoseconds) => {
|
|
@@ -734,7 +920,10 @@ var noOpExecution = {
|
|
|
734
920
|
memoryPressureDegradations: 0,
|
|
735
921
|
valuesDroppedByMemoryBudget: 0,
|
|
736
922
|
eventsDroppedByMemoryBudget: 0,
|
|
737
|
-
partialErrorSnapshots: 0
|
|
923
|
+
partialErrorSnapshots: 0,
|
|
924
|
+
measuredExecutions: 0,
|
|
925
|
+
totalInlineWallTimeMs: 0,
|
|
926
|
+
maxInlineWallTimeMs: 0
|
|
738
927
|
})
|
|
739
928
|
};
|
|
740
929
|
var mergeExecutionMetadata = (target, metadata) => {
|
|
@@ -768,13 +957,28 @@ var createExecutionRecorder = (options) => {
|
|
|
768
957
|
repeatedCallsSuppressed: 0,
|
|
769
958
|
activeExecutions: 0,
|
|
770
959
|
peakActiveExecutions: 0,
|
|
771
|
-
partialErrorSnapshots: 0
|
|
960
|
+
partialErrorSnapshots: 0,
|
|
961
|
+
measuredExecutions: 0,
|
|
962
|
+
totalInlineWallTimeMs: 0,
|
|
963
|
+
maxInlineWallTimeMs: 0
|
|
964
|
+
};
|
|
965
|
+
const recordInlineTiming = (recording) => {
|
|
966
|
+
const inlineWallTimeMs = roundedMilliseconds(recording.inlineRecorderTimeNs);
|
|
967
|
+
stats.measuredExecutions++;
|
|
968
|
+
stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
|
|
969
|
+
stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
|
|
772
970
|
};
|
|
773
971
|
const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => safeSerializeWithBytes(value, options));
|
|
774
972
|
const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
|
|
775
973
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
974
|
+
const events = recording.events.values().map((event) => event.type === "function_calls_suppressed" ? { ...event } : event);
|
|
975
|
+
const referencedFunctionIds = new Set(
|
|
976
|
+
events.flatMap(
|
|
977
|
+
(event) => event.type === "function_enter" || event.type === "function_calls_suppressed" ? [event.functionId] : []
|
|
978
|
+
)
|
|
979
|
+
);
|
|
776
980
|
const state = {
|
|
777
|
-
version:
|
|
981
|
+
version: 2,
|
|
778
982
|
executionId: recording.executionId,
|
|
779
983
|
startedAt: recording.startedAt,
|
|
780
984
|
durationMs: elapsedMs(recording.startedAtNs, endedAtNs),
|
|
@@ -783,7 +987,10 @@ var createExecutionRecorder = (options) => {
|
|
|
783
987
|
...recording.execution,
|
|
784
988
|
...recording.execution.request ? { request: { ...recording.execution.request } } : {}
|
|
785
989
|
},
|
|
786
|
-
|
|
990
|
+
functions: [...recording.functions.values()].filter(
|
|
991
|
+
(definition) => referencedFunctionIds.has(definition.functionId)
|
|
992
|
+
),
|
|
993
|
+
events,
|
|
787
994
|
...recording.events.dropped > 0 ? { truncated: { eventsDropped: recording.events.dropped } } : {},
|
|
788
995
|
...recording.memory.underPressure ? {
|
|
789
996
|
capture: {
|
|
@@ -911,6 +1118,7 @@ var createExecutionRecorder = (options) => {
|
|
|
911
1118
|
if (!recording.hasError) stats.successfulExecutionsDiscarded++;
|
|
912
1119
|
recording.finishedAtNs = process.hrtime.bigint();
|
|
913
1120
|
addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
|
|
1121
|
+
recordInlineTiming(recording);
|
|
914
1122
|
};
|
|
915
1123
|
const createScope = (metadata) => {
|
|
916
1124
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
@@ -925,6 +1133,7 @@ var createExecutionRecorder = (options) => {
|
|
|
925
1133
|
...metadata.request ? { request: { ...metadata.request } } : {}
|
|
926
1134
|
},
|
|
927
1135
|
events: new CallAwareEventBuffer(maxEventsPerExecution),
|
|
1136
|
+
functions: /* @__PURE__ */ new Map(),
|
|
928
1137
|
repeatedCalls: /* @__PURE__ */ new Map(),
|
|
929
1138
|
capturedErrors: /* @__PURE__ */ new WeakMap(),
|
|
930
1139
|
nextCallId: 0,
|
|
@@ -993,16 +1202,19 @@ var createExecutionRecorder = (options) => {
|
|
|
993
1202
|
return void 0;
|
|
994
1203
|
}
|
|
995
1204
|
};
|
|
996
|
-
const runFunction = (
|
|
1205
|
+
const runFunction = (input, args, callback) => {
|
|
997
1206
|
const store = storage.getStore();
|
|
998
1207
|
if (!store || store.recording.finished) return callback();
|
|
1208
|
+
const definition = normalizeFunctionDefinition(input);
|
|
1209
|
+
const functionId = definition.functionId;
|
|
999
1210
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1000
|
-
if (store.suppressCapture || excludesSource(
|
|
1211
|
+
if (store.suppressCapture || excludesSource(definition)) {
|
|
1001
1212
|
return storage.run({ ...store, suppressCapture: true }, () => {
|
|
1002
1213
|
addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
1003
1214
|
return callback();
|
|
1004
1215
|
});
|
|
1005
1216
|
}
|
|
1217
|
+
store.recording.functions.set(functionId, definition);
|
|
1006
1218
|
const parentCallId = store.currentCallId;
|
|
1007
1219
|
const group = repeatedCallGroup(store.recording, functionId, parentCallId);
|
|
1008
1220
|
group.observedCalls++;
|
|
@@ -1111,9 +1323,10 @@ var createExecutionRecorder = (options) => {
|
|
|
1111
1323
|
)
|
|
1112
1324
|
);
|
|
1113
1325
|
};
|
|
1114
|
-
function trace(
|
|
1326
|
+
function trace(input, fn) {
|
|
1327
|
+
const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
|
|
1115
1328
|
return function traced(...args) {
|
|
1116
|
-
return runFunction(
|
|
1329
|
+
return runFunction(definition, args, () => fn.apply(this, args));
|
|
1117
1330
|
};
|
|
1118
1331
|
}
|
|
1119
1332
|
return {
|
|
@@ -1177,26 +1390,23 @@ var installGlobalHandlers = (client, options = {}) => {
|
|
|
1177
1390
|
// src/rasputin-init.ts
|
|
1178
1391
|
import {
|
|
1179
1392
|
createClient,
|
|
1180
|
-
isClientEnabled
|
|
1181
|
-
resolveRepoRoot
|
|
1393
|
+
isClientEnabled
|
|
1182
1394
|
} from "@rasputin-ai/core";
|
|
1183
1395
|
|
|
1184
1396
|
// src/sdk-meta.ts
|
|
1185
1397
|
var SDK_NAME = "@rasputin-ai/node";
|
|
1186
|
-
var SDK_VERSION = "0.
|
|
1398
|
+
var SDK_VERSION = "0.4.1";
|
|
1187
1399
|
|
|
1188
1400
|
// src/rasputin-init.ts
|
|
1189
|
-
var withExecution = (client, execution, installRuntime,
|
|
1190
|
-
const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(execution
|
|
1401
|
+
var withExecution = (client, execution, installRuntime, manifest) => {
|
|
1402
|
+
const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(execution) : () => {
|
|
1191
1403
|
};
|
|
1192
|
-
const manifestUpload = scheduleInstrumentationManifestUpload(
|
|
1193
|
-
...manifest,
|
|
1194
|
-
repoRoot
|
|
1195
|
-
});
|
|
1404
|
+
const manifestUpload = scheduleInstrumentationManifestUpload(manifest);
|
|
1196
1405
|
return {
|
|
1197
1406
|
...client,
|
|
1198
1407
|
execution,
|
|
1199
1408
|
getStats: () => ({ ...client.getStats(), recorder: execution.getStats() }),
|
|
1409
|
+
verifyConfiguration: manifestUpload.verify,
|
|
1200
1410
|
captureException: (error, context) => {
|
|
1201
1411
|
const runtimeState = context?.runtimeState ?? execution.getErrorState(
|
|
1202
1412
|
error,
|
|
@@ -1226,18 +1436,15 @@ var RasputinInit = (options) => {
|
|
|
1226
1436
|
...options.executionRecorder,
|
|
1227
1437
|
enabled: recorderEnabled
|
|
1228
1438
|
});
|
|
1229
|
-
const wrappedClient = withExecution(
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
enabled: isClientEnabled(options)
|
|
1239
|
-
}
|
|
1240
|
-
);
|
|
1439
|
+
const wrappedClient = withExecution(client, execution, recorderEnabled, {
|
|
1440
|
+
projectApiKey: options.projectApiKey,
|
|
1441
|
+
release: options.release,
|
|
1442
|
+
apiUrl: options.apiUrl,
|
|
1443
|
+
enabled: isClientEnabled(options),
|
|
1444
|
+
sourceRoot: options.sourceRoot,
|
|
1445
|
+
sourceRoots: options.sourceRoots,
|
|
1446
|
+
logSuccess: options.logSuccess
|
|
1447
|
+
});
|
|
1241
1448
|
if (isClientEnabled(options)) {
|
|
1242
1449
|
installGlobalHandlers(wrappedClient);
|
|
1243
1450
|
}
|
|
@@ -1247,12 +1454,14 @@ var RasputinInit = (options) => {
|
|
|
1247
1454
|
createClient({ ...options, enabled: false }),
|
|
1248
1455
|
createExecutionRecorder({ enabled: false }),
|
|
1249
1456
|
false,
|
|
1250
|
-
void 0,
|
|
1251
1457
|
{
|
|
1252
1458
|
projectApiKey: options.projectApiKey,
|
|
1253
1459
|
release: options.release,
|
|
1254
1460
|
apiUrl: options.apiUrl,
|
|
1255
|
-
enabled: false
|
|
1461
|
+
enabled: false,
|
|
1462
|
+
sourceRoot: options.sourceRoot,
|
|
1463
|
+
sourceRoots: options.sourceRoots,
|
|
1464
|
+
logSuccess: options.logSuccess
|
|
1256
1465
|
}
|
|
1257
1466
|
);
|
|
1258
1467
|
}
|