@rasputin-ai/node 0.4.1 → 0.5.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +188 -162
  2. package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts +2 -37
  3. package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts.map +1 -1
  4. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts +19 -0
  5. package/dist/auto-instrumentation/instrument-compiled-esm.d.ts.map +1 -0
  6. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts +41 -0
  7. package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts.map +1 -0
  8. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +5 -2
  9. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
  10. package/dist/auto-instrumentation/transform-source.d.ts +7 -1
  11. package/dist/auto-instrumentation/transform-source.d.ts.map +1 -1
  12. package/dist/auto-instrumentation/warn-production-runtime-transform.d.ts +8 -0
  13. package/dist/auto-instrumentation/warn-production-runtime-transform.d.ts.map +1 -0
  14. package/dist/derivation/analyze-function.d.ts +42 -0
  15. package/dist/derivation/analyze-function.d.ts.map +1 -0
  16. package/dist/derivation/build-dependency-graph.d.ts +21 -0
  17. package/dist/derivation/build-dependency-graph.d.ts.map +1 -0
  18. package/dist/derivation/derivation-ir.d.ts +33 -0
  19. package/dist/derivation/derivation-ir.d.ts.map +1 -0
  20. package/dist/derivation/derivation-proof.d.ts +14 -0
  21. package/dist/derivation/derivation-proof.d.ts.map +1 -0
  22. package/dist/derivation/emit-capture-plan.d.ts +8 -0
  23. package/dist/derivation/emit-capture-plan.d.ts.map +1 -0
  24. package/dist/execution-recorder/automatic-runtime.d.ts +21 -10
  25. package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
  26. package/dist/execution-recorder/execution-journal.d.ts +84 -0
  27. package/dist/execution-recorder/execution-journal.d.ts.map +1 -0
  28. package/dist/execution-recorder/execution-recorder-types.d.ts +36 -0
  29. package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
  30. package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
  31. package/dist/execution-recorder/function-plan.d.ts +26 -0
  32. package/dist/execution-recorder/function-plan.d.ts.map +1 -0
  33. package/dist/execution-recorder/recorder-memory-budget.d.ts +8 -1
  34. package/dist/execution-recorder/recorder-memory-budget.d.ts.map +1 -1
  35. package/dist/execution-recorder/safe-serialize.d.ts +8 -0
  36. package/dist/execution-recorder/safe-serialize.d.ts.map +1 -1
  37. package/dist/index.js +1432 -418
  38. package/dist/instrument/build.d.ts +2 -0
  39. package/dist/instrument/build.d.ts.map +1 -0
  40. package/dist/instrument/build.js +1430 -0
  41. package/dist/instrument/bun.js +825 -82
  42. package/dist/instrument/node.js +825 -82
  43. package/dist/rasputin-init.d.ts +5 -5
  44. package/dist/rasputin-init.d.ts.map +1 -1
  45. package/dist/sdk-meta.d.ts +1 -1
  46. package/dist/sdk-meta.d.ts.map +1 -1
  47. package/package.json +10 -2
  48. package/dist/execution-recorder/call-aware-event-buffer.d.ts +0 -23
  49. package/dist/execution-recorder/call-aware-event-buffer.d.ts.map +0 -1
@@ -12,25 +12,29 @@ import {
12
12
  sourceLocatorFromFile as sourceLocatorFromFile2
13
13
  } from "@rasputin-ai/core";
14
14
 
15
- // src/execution-recorder/automatic-runtime.ts
15
+ // src/execution-recorder/function-plan.ts
16
16
  import {
17
17
  runtimeFunctionId,
18
18
  sourceLocatorFromFile
19
19
  } from "@rasputin-ai/core";
20
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
21
- var AUTOMATIC_SOURCE_PREFIX = "rasputin-source-v2:";
22
- var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
23
- var encodeAutomaticFunctionSource = (source) => {
20
+ var encodeFunctionPlan = (source) => {
24
21
  const locator = sourceLocatorFromFile(source.filePath);
25
- const value = {
22
+ const definition = {
26
23
  name: source.name,
27
24
  ...locator ? { source: { ...locator, line: source.line, column: source.column } } : {}
28
25
  };
29
- return `${AUTOMATIC_SOURCE_PREFIX}${JSON.stringify(value)}`;
26
+ return [
27
+ runtimeFunctionId(definition),
28
+ source.name,
29
+ locator?.packageName ?? null,
30
+ locator?.packageRelativePath ?? null,
31
+ source.line,
32
+ source.column
33
+ ];
30
34
  };
31
35
 
32
36
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
33
- var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
37
+ var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v3";
34
38
  var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
35
39
  var getRegistry = () => {
36
40
  const existing = Reflect.get(globalThis, registrySymbol);
@@ -84,16 +88,663 @@ var isApplicationSource = (filePath, options = {}) => {
84
88
 
85
89
  // src/auto-instrumentation/transform-source.ts
86
90
  import { resolve as resolve3 } from "node:path";
87
- import ts2 from "typescript";
91
+ import ts3 from "typescript";
88
92
 
89
- // src/auto-instrumentation/collect-instrumentation-delta.ts
93
+ // src/derivation/analyze-function.ts
90
94
  import ts from "typescript";
95
+
96
+ // src/derivation/build-dependency-graph.ts
97
+ var buildDependencyGraph = (functions, edges) => {
98
+ const names = new Set(functions.map((fn) => fn.name));
99
+ const localEdges = edges.filter((edge) => names.has(edge.calleeName));
100
+ const calleesByCaller = /* @__PURE__ */ new Map();
101
+ for (const edge of localEdges) {
102
+ const existing = calleesByCaller.get(edge.callerFunctionId) ?? [];
103
+ existing.push(edge.calleeName);
104
+ calleesByCaller.set(edge.callerFunctionId, existing);
105
+ }
106
+ return {
107
+ functions: functions.map((fn) => fn.functionId),
108
+ edges: localEdges,
109
+ calleesByCaller
110
+ };
111
+ };
112
+ var topologicalFunctionOrder = (functions, graph) => {
113
+ const idByName = new Map(functions.map((fn) => [fn.name, fn.functionId]));
114
+ const remainingCallees = new Map(
115
+ functions.map((fn) => {
116
+ const unique = new Set(
117
+ (graph.calleesByCaller.get(fn.functionId) ?? []).map((name) => idByName.get(name)).filter((id) => Boolean(id) && id !== fn.functionId)
118
+ );
119
+ return [fn.functionId, unique.size];
120
+ })
121
+ );
122
+ const callersOf = /* @__PURE__ */ new Map();
123
+ for (const fn of functions) {
124
+ for (const calleeName of graph.calleesByCaller.get(fn.functionId) ?? []) {
125
+ const calleeId = idByName.get(calleeName);
126
+ if (!calleeId || calleeId === fn.functionId) continue;
127
+ const callers = callersOf.get(calleeId) ?? [];
128
+ callers.push(fn.functionId);
129
+ callersOf.set(calleeId, callers);
130
+ }
131
+ }
132
+ const queue = functions.filter((fn) => (remainingCallees.get(fn.functionId) ?? 0) === 0).map((fn) => fn.functionId);
133
+ const ordered = [];
134
+ const queued = new Set(queue);
135
+ while (queue.length > 0) {
136
+ const current = queue.shift();
137
+ if (current === void 0) break;
138
+ ordered.push(current);
139
+ for (const caller of callersOf.get(current) ?? []) {
140
+ const next = (remainingCallees.get(caller) ?? 0) - 1;
141
+ remainingCallees.set(caller, next);
142
+ if (next === 0 && !queued.has(caller)) {
143
+ queued.add(caller);
144
+ queue.push(caller);
145
+ }
146
+ }
147
+ }
148
+ for (const fn of functions) {
149
+ if (!queued.has(fn.functionId)) ordered.push(fn.functionId);
150
+ }
151
+ return ordered;
152
+ };
153
+
154
+ // src/derivation/derivation-ir.ts
155
+ var DerivationIrBuilder = class {
156
+ expressions = [];
157
+ nextId = 0;
158
+ constValue(value) {
159
+ return this.add({ id: this.nextId++, kind: "const", value });
160
+ }
161
+ param(index) {
162
+ return this.add({ id: this.nextId++, kind: "param", index });
163
+ }
164
+ root(rootId) {
165
+ return this.add({ id: this.nextId++, kind: "root", rootId });
166
+ }
167
+ alias(from) {
168
+ return this.add({ id: this.nextId++, kind: "alias", from });
169
+ }
170
+ binary(op, left, right, guard) {
171
+ return this.add({ id: this.nextId++, kind: "binary", op, left, right, guard });
172
+ }
173
+ unary(op, operand) {
174
+ return this.add({ id: this.nextId++, kind: "unary", op, operand });
175
+ }
176
+ logical(op, left, right) {
177
+ return this.add({ id: this.nextId++, kind: "logical", op, left, right });
178
+ }
179
+ cond(test, consequent, alternate) {
180
+ return this.add({ id: this.nextId++, kind: "cond", test, consequent, alternate });
181
+ }
182
+ object(properties) {
183
+ return this.add({ id: this.nextId++, kind: "object", properties });
184
+ }
185
+ array(elements) {
186
+ return this.add({ id: this.nextId++, kind: "array", elements });
187
+ }
188
+ prop(object, key) {
189
+ return this.add({ id: this.nextId++, kind: "prop", object, key });
190
+ }
191
+ index(array, index) {
192
+ return this.add({ id: this.nextId++, kind: "index", array, index });
193
+ }
194
+ pureCall(calleeFunctionId, args) {
195
+ return this.add({ id: this.nextId++, kind: "pure_call", calleeFunctionId, args });
196
+ }
197
+ template(parts) {
198
+ return this.add({ id: this.nextId++, kind: "template", parts });
199
+ }
200
+ add(expression) {
201
+ this.expressions.push(expression);
202
+ return expression.id;
203
+ }
204
+ };
205
+ var emptyPlan = (functionId) => ({
206
+ planId: `dp_${functionId}`,
207
+ functionId,
208
+ expressions: [],
209
+ variables: [],
210
+ captureBoundaries: [],
211
+ controlFacts: []
212
+ });
213
+
214
+ // src/derivation/analyze-function.ts
215
+ var loc = (node, sourceFile) => {
216
+ const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
217
+ return { line: position.line + 1, column: position.character + 1 };
218
+ };
219
+ var lookup = (ctx, name) => {
220
+ for (let index = ctx.scopes.length - 1; index >= 0; index--) {
221
+ const binding = ctx.scopes[index]?.get(name);
222
+ if (binding) return binding;
223
+ }
224
+ return void 0;
225
+ };
226
+ var fallback = (ctx, reason) => {
227
+ ctx.fallback ??= reason;
228
+ return { expressionId: ctx.ir.constValue({ type: "undefined" }), shape: "unknown" };
229
+ };
230
+ var capture = (ctx, node, reason) => {
231
+ const rootId = ctx.nextRootId.value++;
232
+ const position = loc(node, ctx.sourceFile);
233
+ const expressionId = ctx.ir.root(rootId);
234
+ ctx.captureWraps.push({
235
+ rootId,
236
+ reason,
237
+ start: node.getStart(ctx.sourceFile),
238
+ end: node.end,
239
+ line: position.line,
240
+ column: position.column,
241
+ expressionId
242
+ });
243
+ return { expressionId, shape: "unknown", captured: true };
244
+ };
245
+ var binaryOp = (kind) => {
246
+ switch (kind) {
247
+ case ts.SyntaxKind.PlusToken:
248
+ return "add";
249
+ case ts.SyntaxKind.MinusToken:
250
+ return "sub";
251
+ case ts.SyntaxKind.AsteriskToken:
252
+ return "mul";
253
+ case ts.SyntaxKind.SlashToken:
254
+ return "div";
255
+ case ts.SyntaxKind.PercentToken:
256
+ return "mod";
257
+ case ts.SyntaxKind.EqualsEqualsToken:
258
+ return "eq";
259
+ case ts.SyntaxKind.ExclamationEqualsToken:
260
+ return "neq";
261
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
262
+ return "seq";
263
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
264
+ return "sneq";
265
+ case ts.SyntaxKind.LessThanToken:
266
+ return "lt";
267
+ case ts.SyntaxKind.LessThanEqualsToken:
268
+ return "lte";
269
+ case ts.SyntaxKind.GreaterThanToken:
270
+ return "gt";
271
+ case ts.SyntaxKind.GreaterThanEqualsToken:
272
+ return "gte";
273
+ default:
274
+ return void 0;
275
+ }
276
+ };
277
+ var isNumericBinaryOp = (op) => op === "add" || op === "sub" || op === "mul" || op === "div" || op === "mod";
278
+ var unwrapParens = (node) => {
279
+ while (ts.isParenthesizedExpression(node)) node = node.expression;
280
+ return node;
281
+ };
282
+ var numericLiteralValue = (node) => {
283
+ const value = Number(node.text);
284
+ return { type: "number", value };
285
+ };
286
+ var analyzeExpression = (ctx, node) => {
287
+ if (ctx.fallback) return fallback(ctx, ctx.fallback);
288
+ if (ts.isParenthesizedExpression(node)) return analyzeExpression(ctx, node.expression);
289
+ if (ts.isAsExpression(node) || ts.isNonNullExpression(node)) {
290
+ return analyzeExpression(ctx, node.expression);
291
+ }
292
+ if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
293
+ return analyzeExpression(ctx, node.expression);
294
+ }
295
+ if (ts.isSatisfiesExpression(node)) return analyzeExpression(ctx, node.expression);
296
+ if (node.kind === ts.SyntaxKind.NullKeyword) {
297
+ return { expressionId: ctx.ir.constValue({ type: "null" }), shape: "primitive" };
298
+ }
299
+ if (node.kind === ts.SyntaxKind.TrueKeyword) {
300
+ return {
301
+ expressionId: ctx.ir.constValue({ type: "boolean", value: true }),
302
+ shape: "primitive"
303
+ };
304
+ }
305
+ if (node.kind === ts.SyntaxKind.FalseKeyword) {
306
+ return {
307
+ expressionId: ctx.ir.constValue({ type: "boolean", value: false }),
308
+ shape: "primitive"
309
+ };
310
+ }
311
+ if (ts.isNumericLiteral(node)) {
312
+ return { expressionId: ctx.ir.constValue(numericLiteralValue(node)), shape: "primitive" };
313
+ }
314
+ if (ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand) && node.operator === ts.SyntaxKind.MinusToken) {
315
+ const value = -Number(node.operand.text);
316
+ return {
317
+ expressionId: ctx.ir.constValue(
318
+ Object.is(value, -0) ? { type: "number", value: 0, negativeZero: true } : { type: "number", value }
319
+ ),
320
+ shape: "primitive"
321
+ };
322
+ }
323
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
324
+ return {
325
+ expressionId: ctx.ir.constValue({ type: "string", value: node.text }),
326
+ shape: "primitive"
327
+ };
328
+ }
329
+ if (ts.isBigIntLiteral(node)) {
330
+ return {
331
+ expressionId: ctx.ir.constValue({ type: "bigint", value: node.text.replace(/n$/, "") }),
332
+ shape: "primitive"
333
+ };
334
+ }
335
+ if (ts.isIdentifier(node)) {
336
+ if (node.text === "undefined") {
337
+ return { expressionId: ctx.ir.constValue({ type: "undefined" }), shape: "primitive" };
338
+ }
339
+ const binding = lookup(ctx, node.text);
340
+ if (!binding) return capture(ctx, node, "external_state");
341
+ if (binding.mutable) return capture(ctx, node, "mutable_object");
342
+ return {
343
+ expressionId: ctx.ir.alias(binding.expressionId),
344
+ shape: binding.shape
345
+ };
346
+ }
347
+ if (ts.isTemplateExpression(node)) {
348
+ const parts = [
349
+ { kind: "lit", value: node.head.text }
350
+ ];
351
+ for (const span of node.templateSpans) {
352
+ const nested = analyzeExpression(ctx, span.expression);
353
+ if (nested.shape !== "primitive" && !nested.captured) {
354
+ return capture(ctx, node, "unsupported_expression");
355
+ }
356
+ parts.push({ kind: "expr", expressionId: nested.expressionId });
357
+ parts.push({ kind: "lit", value: span.literal.text });
358
+ }
359
+ return { expressionId: ctx.ir.template(parts), shape: "primitive" };
360
+ }
361
+ if (ts.isArrayLiteralExpression(node)) {
362
+ if (node.elements.some((element) => ts.isSpreadElement(element))) {
363
+ return capture(ctx, node, "unsupported_expression");
364
+ }
365
+ const elements = node.elements.map((element) => {
366
+ if (ts.isOmittedExpression(element)) return { kind: "hole" };
367
+ return analyzeExpression(ctx, element).expressionId;
368
+ });
369
+ return { expressionId: ctx.ir.array(elements), shape: "array" };
370
+ }
371
+ if (ts.isObjectLiteralExpression(node)) {
372
+ const properties = [];
373
+ for (const property of node.properties) {
374
+ if (ts.isShorthandPropertyAssignment(property)) {
375
+ const nested = analyzeExpression(ctx, property.name);
376
+ if (nested.captured) {
377
+ const wrap = ctx.captureWraps.find(
378
+ (candidate) => candidate.expressionId === nested.expressionId
379
+ );
380
+ if (wrap) wrap.shorthandPropertyName = property.name.text;
381
+ }
382
+ properties.push({ key: property.name.text, value: nested.expressionId });
383
+ continue;
384
+ }
385
+ if (!ts.isPropertyAssignment(property)) {
386
+ return capture(ctx, node, "unsupported_expression");
387
+ }
388
+ if (ts.isPrivateIdentifier(property.name) || ts.isComputedPropertyName(property.name)) {
389
+ return capture(ctx, node, "unsupported_expression");
390
+ }
391
+ const key = ts.isIdentifier(property.name) ? property.name.text : ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name) ? property.name.text : void 0;
392
+ if (key === void 0) return capture(ctx, node, "unsupported_expression");
393
+ properties.push({ key, value: analyzeExpression(ctx, property.initializer).expressionId });
394
+ }
395
+ return { expressionId: ctx.ir.object(properties), shape: "object" };
396
+ }
397
+ if (ts.isPropertyAccessExpression(node)) {
398
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
399
+ const object = analyzeExpression(ctx, node.expression);
400
+ if (object.shape === "object" && ts.isIdentifier(node.name)) {
401
+ return { expressionId: ctx.ir.prop(object.expressionId, node.name.text), shape: "unknown" };
402
+ }
403
+ return capture(ctx, node, "unknown_property");
404
+ }
405
+ if (ts.isElementAccessExpression(node)) {
406
+ if (node.questionDotToken) return capture(ctx, node, "unknown_property");
407
+ const array = analyzeExpression(ctx, node.expression);
408
+ if (array.shape === "array" && ts.isNumericLiteral(node.argumentExpression)) {
409
+ return {
410
+ expressionId: ctx.ir.index(array.expressionId, Number(node.argumentExpression.text)),
411
+ shape: "unknown"
412
+ };
413
+ }
414
+ return capture(ctx, node, "unknown_property");
415
+ }
416
+ if (ts.isCallExpression(node)) {
417
+ if (node.questionDotToken || node.typeArguments?.length) {
418
+ return capture(ctx, node, "unsupported_expression");
419
+ }
420
+ if (!ts.isIdentifier(node.expression)) return capture(ctx, node, "dynamic_callee");
421
+ const calleeName = node.expression.text;
422
+ if (lookup(ctx, calleeName)) return capture(ctx, node, "opaque_call");
423
+ const provenId = ctx.moduleCallees.get(calleeName);
424
+ ctx.callEdges.push({
425
+ callerFunctionId: ctx.functionId,
426
+ calleeName,
427
+ ...provenId ? { calleeFunctionId: provenId } : {}
428
+ });
429
+ if (!provenId) return capture(ctx, node, "opaque_call");
430
+ const args = node.arguments.map((argument) => {
431
+ if (ts.isSpreadElement(argument)) return void 0;
432
+ return analyzeExpression(ctx, argument).expressionId;
433
+ });
434
+ if (args.some((argument) => argument === void 0))
435
+ return capture(ctx, node, "unsupported_expression");
436
+ return {
437
+ expressionId: ctx.ir.pureCall(
438
+ provenId,
439
+ args.filter((id) => id !== void 0)
440
+ ),
441
+ shape: "unknown"
442
+ };
443
+ }
444
+ if (ts.isNewExpression(node) || ts.isAwaitExpression(node) || ts.isYieldExpression(node)) {
445
+ return capture(
446
+ ctx,
447
+ node,
448
+ node.kind === ts.SyntaxKind.AwaitExpression ? "nondeterministic" : "unsupported_expression"
449
+ );
450
+ }
451
+ if (ts.isConditionalExpression(node)) {
452
+ const test = analyzeExpression(ctx, node.condition);
453
+ const consequent = analyzeExpression(ctx, node.whenTrue);
454
+ const alternate = analyzeExpression(ctx, node.whenFalse);
455
+ return {
456
+ expressionId: ctx.ir.cond(test.expressionId, consequent.expressionId, alternate.expressionId),
457
+ shape: consequent.shape === alternate.shape ? consequent.shape : "unknown"
458
+ };
459
+ }
460
+ if (ts.isBinaryExpression(node)) {
461
+ if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
462
+ ctx.fallback ??= "mutable_state";
463
+ return capture(ctx, node, "mutable_object");
464
+ }
465
+ if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken || node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
466
+ const left2 = analyzeExpression(ctx, node.left);
467
+ const right2 = analyzeExpression(ctx, node.right);
468
+ const op2 = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ? "and" : node.operatorToken.kind === ts.SyntaxKind.BarBarToken ? "or" : "nullish";
469
+ return {
470
+ expressionId: ctx.ir.logical(op2, left2.expressionId, right2.expressionId),
471
+ shape: "unknown"
472
+ };
473
+ }
474
+ const op = binaryOp(node.operatorToken.kind);
475
+ if (!op) return capture(ctx, node, "unsupported_expression");
476
+ if (!ts.isExpression(node.left)) return capture(ctx, node, "unsupported_expression");
477
+ const left = analyzeExpression(ctx, node.left);
478
+ const right = analyzeExpression(ctx, node.right);
479
+ const numeric = isNumericBinaryOp(op);
480
+ const expressionId = ctx.ir.binary(
481
+ op,
482
+ left.expressionId,
483
+ right.expressionId,
484
+ numeric ? "numeric" : "primitive"
485
+ );
486
+ if (numeric && (left.captured || right.captured || left.shape !== "primitive" || right.shape !== "primitive")) {
487
+ ctx.hasCoercionGuard = true;
488
+ const fallbackRootId = ctx.nextRootId.value++;
489
+ ctx.guardWraps.push({
490
+ fallbackRootId,
491
+ start: node.getStart(ctx.sourceFile),
492
+ end: node.end,
493
+ op
494
+ });
495
+ }
496
+ return { expressionId, shape: "primitive" };
497
+ }
498
+ if (ts.isPrefixUnaryExpression(node)) {
499
+ const operand = analyzeExpression(ctx, node.operand);
500
+ if (node.operator === ts.SyntaxKind.ExclamationToken) {
501
+ return { expressionId: ctx.ir.unary("not", operand.expressionId), shape: "primitive" };
502
+ }
503
+ if (node.operator === ts.SyntaxKind.PlusToken || node.operator === ts.SyntaxKind.MinusToken) {
504
+ if (operand.captured || operand.shape !== "primitive") ctx.hasCoercionGuard = true;
505
+ return {
506
+ expressionId: ctx.ir.unary(
507
+ node.operator === ts.SyntaxKind.MinusToken ? "minus" : "plus",
508
+ operand.expressionId
509
+ ),
510
+ shape: "primitive"
511
+ };
512
+ }
513
+ return capture(ctx, node, "unsupported_expression");
514
+ }
515
+ if (ts.isTypeOfExpression(node)) {
516
+ const operand = unwrapParens(node.expression);
517
+ if (ts.isIdentifier(operand) && operand.text !== "undefined" && !lookup(ctx, operand.text)) {
518
+ return capture(ctx, node, "external_state");
519
+ }
520
+ const inner = analyzeExpression(ctx, node.expression);
521
+ return { expressionId: ctx.ir.unary("typeof", inner.expressionId), shape: "primitive" };
522
+ }
523
+ return capture(ctx, node, "unsupported_expression");
524
+ };
525
+ var bindIdentifier = (ctx, name, result, declaration) => {
526
+ const current = ctx.scopes[ctx.scopes.length - 1];
527
+ current?.set(name.text, {
528
+ expressionId: result.expressionId,
529
+ shape: result.shape,
530
+ mutable: false
531
+ });
532
+ const position = loc(name, ctx.sourceFile);
533
+ const available = loc(declaration, ctx.sourceFile);
534
+ ctx.variables.push({
535
+ id: ctx.nextVariableId.value++,
536
+ name: name.text,
537
+ functionId: ctx.functionId,
538
+ scopeId: `${ctx.functionId}:${ctx.scopes.length}`,
539
+ line: position.line,
540
+ column: position.column,
541
+ assignmentId: ctx.nextAssignmentId.value++,
542
+ expressionId: result.expressionId,
543
+ availableAtLine: available.line,
544
+ availableAtColumn: available.column
545
+ });
546
+ };
547
+ var analyzeStatement = (ctx, node) => {
548
+ if (ctx.fallback) return;
549
+ if (ts.isEmptyStatement(node) || ts.isDebuggerStatement(node)) return;
550
+ if (ts.isBlock(node)) {
551
+ ctx.scopes.push(/* @__PURE__ */ new Map());
552
+ for (const statement of node.statements) analyzeStatement(ctx, statement);
553
+ ctx.scopes.pop();
554
+ return;
555
+ }
556
+ if (ts.isReturnStatement(node)) {
557
+ if (!node.expression) {
558
+ ctx.returnExpressionId = ctx.ir.constValue({ type: "undefined" });
559
+ return;
560
+ }
561
+ ctx.returnExpressionId = analyzeExpression(ctx, node.expression).expressionId;
562
+ return;
563
+ }
564
+ if (ts.isVariableStatement(node)) {
565
+ if (node.declarationList.flags & ts.NodeFlags.Using) {
566
+ fallback(ctx, "side_effect");
567
+ return;
568
+ }
569
+ for (const declaration of node.declarationList.declarations) {
570
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
571
+ fallback(ctx, "unsupported_expression");
572
+ return;
573
+ }
574
+ const result = analyzeExpression(ctx, declaration.initializer);
575
+ bindIdentifier(ctx, declaration.name, result, declaration);
576
+ }
577
+ return;
578
+ }
579
+ if (ts.isExpressionStatement(node)) {
580
+ analyzeExpression(ctx, node.expression);
581
+ return;
582
+ }
583
+ if (ts.isThrowStatement(node)) {
584
+ ctx.hasThrow = true;
585
+ analyzeExpression(ctx, node.expression);
586
+ return;
587
+ }
588
+ if (ts.isIfStatement(node) || ts.isSwitchStatement(node) || ts.isTryStatement(node)) {
589
+ fallback(ctx, "unsupported_expression");
590
+ return;
591
+ }
592
+ if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node) || ts.isWhileStatement(node) || ts.isDoStatement(node)) {
593
+ fallback(ctx, "has_loop");
594
+ return;
595
+ }
596
+ fallback(ctx, "unsupported_expression");
597
+ };
598
+ var bindParams = (ctx, node) => {
599
+ let index = 0;
600
+ for (const parameter of node.parameters) {
601
+ if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
602
+ if (!ts.isIdentifier(parameter.name) || parameter.dotDotDotToken) {
603
+ fallback(ctx, "unsupported_expression");
604
+ index++;
605
+ continue;
606
+ }
607
+ const expressionId = ctx.ir.param(index);
608
+ ctx.identifierParams.push(parameter.name.text);
609
+ bindIdentifier(ctx, parameter.name, { expressionId, shape: "unknown" }, parameter);
610
+ index++;
611
+ }
612
+ };
613
+ var analyzeOne = (node, functionId, name, sourceFile, moduleCallees) => {
614
+ const ctx = {
615
+ sourceFile,
616
+ functionId,
617
+ name,
618
+ ir: new DerivationIrBuilder(),
619
+ variables: [],
620
+ captureWraps: [],
621
+ guardWraps: [],
622
+ callEdges: [],
623
+ scopes: [/* @__PURE__ */ new Map()],
624
+ nextRootId: { value: 0 },
625
+ nextVariableId: { value: 0 },
626
+ nextAssignmentId: { value: 0 },
627
+ hasThrow: false,
628
+ hasCoercionGuard: false,
629
+ moduleCallees,
630
+ identifierParams: []
631
+ };
632
+ if (node.asteriskToken || node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword)) {
633
+ ctx.fallback = "async";
634
+ } else {
635
+ bindParams(ctx, node);
636
+ if (ts.isBlock(node.body)) {
637
+ for (const statement of node.body.statements) analyzeStatement(ctx, statement);
638
+ } else {
639
+ ctx.returnExpressionId = analyzeExpression(ctx, node.body).expressionId;
640
+ }
641
+ }
642
+ const plan = {
643
+ ...emptyPlan(functionId),
644
+ expressions: ctx.ir.expressions,
645
+ variables: ctx.variables,
646
+ captureBoundaries: ctx.captureWraps.map((wrap) => ({
647
+ id: wrap.rootId,
648
+ reason: wrap.reason,
649
+ expressionId: wrap.expressionId,
650
+ line: wrap.line,
651
+ column: wrap.column
652
+ })),
653
+ controlFacts: [],
654
+ ...ctx.returnExpressionId === void 0 ? {} : { returnExpressionId: ctx.returnExpressionId },
655
+ ...ctx.fallback ? { fallbackReason: ctx.fallback } : {}
656
+ };
657
+ return {
658
+ functionId,
659
+ name,
660
+ node,
661
+ plan,
662
+ captureWraps: ctx.fallback ? [] : ctx.captureWraps,
663
+ guardWraps: ctx.fallback ? [] : ctx.guardWraps,
664
+ callEdges: ctx.callEdges,
665
+ hasThrow: ctx.hasThrow,
666
+ hasCoercionGuard: ctx.hasCoercionGuard
667
+ };
668
+ };
669
+ var analyzeModuleFunctions = (sourceFile, targets) => {
670
+ const nameCounts = /* @__PURE__ */ new Map();
671
+ for (const target of targets) {
672
+ nameCounts.set(target.name, (nameCounts.get(target.name) ?? 0) + 1);
673
+ }
674
+ const firstPass = targets.map(
675
+ (target) => analyzeOne(target.node, target.functionId, target.name, sourceFile, /* @__PURE__ */ new Map())
676
+ );
677
+ const graph = buildDependencyGraph(
678
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
679
+ firstPass.flatMap((fn) => fn.callEdges)
680
+ );
681
+ const order = topologicalFunctionOrder(
682
+ firstPass.map((fn) => ({ functionId: fn.functionId, name: fn.name })),
683
+ graph
684
+ );
685
+ const byId = new Map(targets.map((target) => [target.functionId, target]));
686
+ const moduleCallees = /* @__PURE__ */ new Map();
687
+ const analyzed = [];
688
+ for (const functionId of order) {
689
+ const target = byId.get(functionId);
690
+ if (!target) continue;
691
+ const result = analyzeOne(
692
+ target.node,
693
+ target.functionId,
694
+ target.name,
695
+ sourceFile,
696
+ moduleCallees
697
+ );
698
+ if (nameCounts.get(result.name) === 1) {
699
+ moduleCallees.set(result.name, result.functionId);
700
+ }
701
+ analyzed.push(result);
702
+ }
703
+ const remaining = targets.filter(
704
+ (target) => !analyzed.some((fn) => fn.functionId === target.functionId)
705
+ );
706
+ for (const target of remaining) {
707
+ analyzed.push(
708
+ analyzeOne(target.node, target.functionId, target.name, sourceFile, moduleCallees)
709
+ );
710
+ }
711
+ return analyzed;
712
+ };
713
+
714
+ // src/derivation/derivation-proof.ts
715
+ var functionIsExact = (plan) => plan.fallbackReason === void 0 && plan.captureBoundaries.length === 0 && plan.controlFacts.length === 0;
716
+
717
+ // src/derivation/emit-capture-plan.ts
718
+ var captureWrapEdits = (wraps, capName) => {
719
+ const edits = [];
720
+ let order = 0;
721
+ for (const wrap of wraps) {
722
+ edits.push({
723
+ position: wrap.start,
724
+ text: `${wrap.shorthandPropertyName ? `${wrap.shorthandPropertyName}:` : ""}${capName}(${wrap.rootId},`,
725
+ order: order++
726
+ });
727
+ edits.push({
728
+ position: wrap.end,
729
+ text: ")",
730
+ order: order++
731
+ });
732
+ }
733
+ return edits;
734
+ };
735
+
736
+ // src/execution-recorder/automatic-runtime.ts
737
+ var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
738
+ var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
739
+
740
+ // src/auto-instrumentation/collect-instrumentation-delta.ts
741
+ import ts2 from "typescript";
91
742
  var paramBindingFromName = (name, sourceFile) => {
92
- if (ts.isIdentifier(name)) return { kind: "identifier", name: name.text };
93
- if (ts.isArrayBindingPattern(name)) {
743
+ if (ts2.isIdentifier(name)) return { kind: "identifier", name: name.text };
744
+ if (ts2.isArrayBindingPattern(name)) {
94
745
  const elements = name.elements.map(
95
746
  (element) => {
96
- if (ts.isOmittedExpression(element)) return { kind: "omitted" };
747
+ if (ts2.isOmittedExpression(element)) return { kind: "omitted" };
97
748
  const binding = paramBindingFromName(element.name, sourceFile);
98
749
  if (element.dotDotDotToken) return { kind: "rest", binding };
99
750
  return binding;
@@ -103,7 +754,7 @@ var paramBindingFromName = (name, sourceFile) => {
103
754
  }
104
755
  const properties = name.elements.map((element) => {
105
756
  const binding = paramBindingFromName(element.name, sourceFile);
106
- const key = element.propertyName ? element.propertyName.getText(sourceFile).replace(/^['"]|['"]$/g, "") : ts.isIdentifier(element.name) ? element.name.text : element.name.getText(sourceFile);
757
+ const key = element.propertyName ? element.propertyName.getText(sourceFile).replace(/^['"]|['"]$/g, "") : ts2.isIdentifier(element.name) ? element.name.text : element.name.getText(sourceFile);
107
758
  if (element.dotDotDotToken) {
108
759
  const rest = { kind: "rest", binding };
109
760
  return { key, binding: rest };
@@ -115,7 +766,7 @@ var paramBindingFromName = (name, sourceFile) => {
115
766
  var collectFunctionParams = (node, sourceFile) => {
116
767
  const params = [];
117
768
  for (const parameter of node.parameters) {
118
- if (ts.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
769
+ if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") continue;
119
770
  const binding = paramBindingFromName(parameter.name, sourceFile);
120
771
  params.push(parameter.dotDotDotToken ? { kind: "rest", binding } : binding);
121
772
  }
@@ -156,18 +807,18 @@ var mappedLocation = (sourceFile, position, absolutePath, mapLocation) => {
156
807
  };
157
808
  var unwrapExpression = (expression) => {
158
809
  let current = expression;
159
- while (ts.isParenthesizedExpression(current) || ts.isNonNullExpression(current)) {
810
+ while (ts2.isParenthesizedExpression(current) || ts2.isNonNullExpression(current)) {
160
811
  current = current.expression;
161
812
  }
162
- if (ts.isAwaitExpression(current)) return unwrapExpression(current.expression);
813
+ if (ts2.isAwaitExpression(current)) return unwrapExpression(current.expression);
163
814
  return current;
164
815
  };
165
816
  var calleeFromExpression = (expression, sourceFile) => {
166
817
  const current = unwrapExpression(expression);
167
- if (ts.isIdentifier(current)) {
818
+ if (ts2.isIdentifier(current)) {
168
819
  return { calleeName: current.text, calleeText: current.text };
169
820
  }
170
- if (ts.isPropertyAccessExpression(current) && ts.isIdentifier(current.name)) {
821
+ if (ts2.isPropertyAccessExpression(current) && ts2.isIdentifier(current.name)) {
171
822
  return {
172
823
  calleeName: current.name.text,
173
824
  calleeText: current.getText(sourceFile).replace(/\s+/g, "")
@@ -177,9 +828,9 @@ var calleeFromExpression = (expression, sourceFile) => {
177
828
  };
178
829
  var resultBindingForCall = (call) => {
179
830
  let node = call.parent;
180
- if (ts.isAwaitExpression(node)) node = node.parent;
181
- if (!ts.isVariableDeclaration(node)) return null;
182
- if (!ts.isIdentifier(node.name)) return null;
831
+ if (ts2.isAwaitExpression(node)) node = node.parent;
832
+ if (!ts2.isVariableDeclaration(node)) return null;
833
+ if (!ts2.isIdentifier(node.name)) return null;
183
834
  const initializer = node.initializer;
184
835
  if (!initializer) return null;
185
836
  const inner = unwrapExpression(initializer);
@@ -189,18 +840,18 @@ var resultBindingForCall = (call) => {
189
840
  var argIdentifiersForCall = (call) => {
190
841
  const identifiers = [];
191
842
  call.arguments?.forEach((argument, index) => {
192
- if (ts.isIdentifier(argument)) {
843
+ if (ts2.isIdentifier(argument)) {
193
844
  identifiers.push({ index, kind: "identifier", name: argument.text });
194
845
  return;
195
846
  }
196
- if (!ts.isObjectLiteralExpression(argument)) return;
847
+ if (!ts2.isObjectLiteralExpression(argument)) return;
197
848
  const properties = [];
198
849
  for (const property of argument.properties) {
199
- if (ts.isShorthandPropertyAssignment(property)) {
850
+ if (ts2.isShorthandPropertyAssignment(property)) {
200
851
  properties.push({ key: property.name.text, name: property.name.text });
201
852
  continue;
202
853
  }
203
- if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && ts.isIdentifier(property.initializer)) {
854
+ if (ts2.isPropertyAssignment(property) && ts2.isIdentifier(property.name) && ts2.isIdentifier(property.initializer)) {
204
855
  properties.push({ key: property.name.text, name: property.initializer.text });
205
856
  }
206
857
  }
@@ -227,7 +878,7 @@ var collectCallSite = (call, caller, context) => {
227
878
  );
228
879
  if (!start || !end) return null;
229
880
  return {
230
- callerSourceToken: caller.sourceToken,
881
+ callerFunctionId: caller.functionId,
231
882
  calleeName: callee.calleeName,
232
883
  calleeText: callee.calleeText,
233
884
  filePath: start.filePath,
@@ -240,8 +891,8 @@ var collectCallSite = (call, caller, context) => {
240
891
  };
241
892
  };
242
893
  var collectParamDestructure = (declaration, caller, context) => {
243
- if (!declaration.initializer || !ts.isIdentifier(declaration.initializer)) return null;
244
- if (!ts.isObjectBindingPattern(declaration.name) && !ts.isArrayBindingPattern(declaration.name)) {
894
+ if (!declaration.initializer || !ts2.isIdentifier(declaration.initializer)) return null;
895
+ if (!ts2.isObjectBindingPattern(declaration.name) && !ts2.isArrayBindingPattern(declaration.name)) {
245
896
  return null;
246
897
  }
247
898
  const sourceParam = declaration.initializer.text;
@@ -254,7 +905,7 @@ var collectParamDestructure = (declaration, caller, context) => {
254
905
  );
255
906
  if (!start) return null;
256
907
  return {
257
- callerSourceToken: caller.sourceToken,
908
+ callerFunctionId: caller.functionId,
258
909
  sourceParam,
259
910
  filePath: start.filePath,
260
911
  line: start.line,
@@ -265,33 +916,33 @@ var collectParamDestructure = (declaration, caller, context) => {
265
916
 
266
917
  // src/auto-instrumentation/transform-source.ts
267
918
  var scriptKindFor = (filePath) => {
268
- if (/\.tsx$/i.test(filePath)) return ts2.ScriptKind.TSX;
269
- if (/\.jsx$/i.test(filePath)) return ts2.ScriptKind.JSX;
270
- if (/\.[cm]?ts$/i.test(filePath)) return ts2.ScriptKind.TS;
271
- return ts2.ScriptKind.JS;
919
+ if (/\.tsx$/i.test(filePath)) return ts3.ScriptKind.TSX;
920
+ if (/\.jsx$/i.test(filePath)) return ts3.ScriptKind.JSX;
921
+ if (/\.[cm]?ts$/i.test(filePath)) return ts3.ScriptKind.TS;
922
+ return ts3.ScriptKind.JS;
272
923
  };
273
924
  var functionName = (node, sourceFile) => {
274
925
  if (node.name) return node.name.getText(sourceFile).replace(/^['"]|['"]$/g, "");
275
926
  const parent = node.parent;
276
- if (ts2.isVariableDeclaration(parent) && ts2.isIdentifier(parent.name)) return parent.name.text;
277
- if (ts2.isPropertyAssignment(parent)) return parent.name.getText(sourceFile);
278
- if (ts2.isPropertyDeclaration(parent) && parent.name) return parent.name.getText(sourceFile);
927
+ if (ts3.isVariableDeclaration(parent) && ts3.isIdentifier(parent.name)) return parent.name.text;
928
+ if (ts3.isPropertyAssignment(parent)) return parent.name.getText(sourceFile);
929
+ if (ts3.isPropertyDeclaration(parent) && parent.name) return parent.name.getText(sourceFile);
279
930
  const location = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
280
931
  return `anonymous@${location.line + 1}:${location.character + 1}`;
281
932
  };
282
933
  var functionLocationPosition = (node, sourceFile) => {
283
934
  if (node.name) return node.name.getStart(sourceFile);
284
935
  const parent = node.parent;
285
- if ((ts2.isVariableDeclaration(parent) || ts2.isPropertyAssignment(parent)) && parent.name) {
936
+ if ((ts3.isVariableDeclaration(parent) || ts3.isPropertyAssignment(parent)) && parent.name) {
286
937
  return parent.name.getStart(sourceFile);
287
938
  }
288
939
  return node.getStart(sourceFile);
289
940
  };
290
941
  var bindingValue = (name, sourceFile) => {
291
- if (ts2.isIdentifier(name)) return name.text;
292
- if (ts2.isArrayBindingPattern(name)) {
942
+ if (ts3.isIdentifier(name)) return name.text;
943
+ if (ts3.isArrayBindingPattern(name)) {
293
944
  const values = name.elements.map((element) => {
294
- if (ts2.isOmittedExpression(element)) return "";
945
+ if (ts3.isOmittedExpression(element)) return "";
295
946
  const value = bindingValue(element.name, sourceFile);
296
947
  return element.dotDotDotToken ? `...${value}` : value;
297
948
  });
@@ -307,20 +958,40 @@ var bindingValue = (name, sourceFile) => {
307
958
  };
308
959
  var arrowArguments = (node) => {
309
960
  const values = node.parameters.flatMap((parameter) => {
310
- if (ts2.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
961
+ if (ts3.isIdentifier(parameter.name) && parameter.name.text === "this") return [];
311
962
  const value = bindingValue(parameter.name, node.getSourceFile());
312
963
  return [parameter.dotDotDotToken ? `...${value}` : value];
313
964
  });
314
965
  return `[${values.join(",")}]`;
315
966
  };
316
967
  var isSupportedFunction = (node) => {
317
- if (!ts2.isFunctionDeclaration(node) && !ts2.isFunctionExpression(node) && !ts2.isArrowFunction(node) && !ts2.isMethodDeclaration(node) && !ts2.isGetAccessorDeclaration(node) && !ts2.isSetAccessorDeclaration(node)) {
968
+ if (!ts3.isFunctionDeclaration(node) && !ts3.isFunctionExpression(node) && !ts3.isArrowFunction(node) && !ts3.isMethodDeclaration(node) && !ts3.isGetAccessorDeclaration(node) && !ts3.isSetAccessorDeclaration(node)) {
318
969
  return false;
319
970
  }
320
971
  if (!node.body || "asteriskToken" in node && node.asteriskToken) return false;
321
972
  return true;
322
973
  };
323
- var helperDeclaration = (helperName) => `const ${helperName}=(functionId,args,callback)=>{const runtime=Reflect.get(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));return runtime?runtime.run(functionId,args,callback):callback()};`;
974
+ var uniqueName = (source, base) => {
975
+ let name = base;
976
+ while (source.includes(name)) name += "_";
977
+ return name;
978
+ };
979
+ var isDirectivePrologue = (statement) => ts3.isExpressionStatement(statement) && ts3.isStringLiteral(statement.expression);
980
+ var insertPositionAfterPrologue = (source, sourceFile) => {
981
+ const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
982
+ let end = shebangEnd;
983
+ for (const statement of sourceFile.statements) {
984
+ if (!isDirectivePrologue(statement)) break;
985
+ end = statement.end;
986
+ }
987
+ return end;
988
+ };
989
+ var preambleInsert = (source, position, preamble) => {
990
+ if (position <= 0) return preamble;
991
+ const previous = source[position - 1];
992
+ return previous === ";" || previous === "\n" || previous === "\r" ? preamble : `;${preamble}`;
993
+ };
994
+ var modulePreamble = (runName, capName, plansName, plansJson) => `const ${plansName}=${plansJson};const ${runName}=((g,k)=>{const r=g[k]??(g[k]={runtimes:[],modules:[],captureRoot(i,v){return v},register(p){const d={run:(i,a,c)=>c()};const m={plans:p,cell:d};this.modules.push(m);const n=this.runtimes.at(-1);if(n)n.bind(m);return(i,a,c,l)=>d.run(i,a,c,l)}});return r.register(${plansName})})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));const ${capName}=((g,k)=>{const r=g[k];return(i,v)=>typeof r?.captureRoot==='function'?r.captureRoot(i,v):v})(globalThis,Symbol.for(${JSON.stringify(AUTOMATIC_RUNTIME_SYMBOL)}));`;
324
995
  var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
325
996
  const start = mappedLocation(
326
997
  sourceFile,
@@ -332,13 +1003,15 @@ var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
332
1003
  const end = mappedLocation(sourceFile, node.end, absolutePath, mapLocation) ?? start;
333
1004
  const name = functionName(node, sourceFile).replace(/@\d+:\d+$/, "");
334
1005
  const { params, paramNames } = collectFunctionParams(node, sourceFile);
1006
+ const plan = encodeFunctionPlan({
1007
+ filePath: start.filePath,
1008
+ name,
1009
+ line: start.line,
1010
+ column: start.column
1011
+ });
335
1012
  return {
336
- sourceToken: encodeAutomaticFunctionSource({
337
- filePath: start.filePath,
338
- name,
339
- line: start.line,
340
- column: start.column
341
- }),
1013
+ plan,
1014
+ functionId: plan[0],
342
1015
  filePath: start.filePath,
343
1016
  name,
344
1017
  startLine: start.line,
@@ -349,74 +1022,130 @@ var collectWrappedFunction = (node, sourceFile, absolutePath, mapLocation) => {
349
1022
  paramNames
350
1023
  };
351
1024
  };
1025
+ var canOmitCallValues = (analysis, analyzed) => {
1026
+ if (!functionIsExact(analysis.plan) || analysis.hasThrow || analysis.hasCoercionGuard) {
1027
+ return false;
1028
+ }
1029
+ const callers = analyzed.filter(
1030
+ (caller) => caller.callEdges.some((edge) => edge.calleeFunctionId === analysis.functionId)
1031
+ );
1032
+ if (callers.length === 0) return false;
1033
+ return callers.every((caller) => caller.plan.fallbackReason === void 0 && !caller.hasThrow);
1034
+ };
352
1035
  var transformSource = (source, options) => {
353
1036
  if (source.includes("@rasputin-ignore-file")) return void 0;
354
- const sourceFile = ts2.createSourceFile(
1037
+ const sourceFile = ts3.createSourceFile(
355
1038
  options.filePath,
356
1039
  source,
357
- ts2.ScriptTarget.Latest,
1040
+ ts3.ScriptTarget.Latest,
358
1041
  true,
359
1042
  scriptKindFor(options.filePath)
360
1043
  );
361
- let helperName = "__rasputinAutoRun__";
362
- while (source.includes(helperName)) helperName += "_";
1044
+ const runName = uniqueName(source, "__rasputinRun__");
1045
+ const capName = uniqueName(source, "__rasputinCap__");
1046
+ const plansName = uniqueName(source, "__rasputinPlans__");
363
1047
  const absolutePath = resolve3(options.filePath);
1048
+ const derivationMode = options.derivationMode ?? "analysis";
364
1049
  const edits = [];
365
1050
  let order = 0;
366
1051
  const delta = {
367
1052
  functions: [],
368
1053
  callSites: [],
369
- destructures: []
1054
+ destructures: [],
1055
+ derivationPlans: []
370
1056
  };
371
1057
  const collectContext = {
372
1058
  sourceFile,
373
1059
  mapLocation: options.mapLocation,
374
1060
  absolutePath
375
1061
  };
1062
+ const pending = [];
376
1063
  const visit = (node, caller) => {
377
1064
  if (isSupportedFunction(node)) {
378
1065
  const collected = collectWrappedFunction(node, sourceFile, absolutePath, options.mapLocation);
379
1066
  if (!collected) {
380
- ts2.forEachChild(node, (child) => visit(child, caller));
1067
+ ts3.forEachChild(node, (child) => visit(child, caller));
381
1068
  return;
382
1069
  }
1070
+ pending.push({ node, collected });
383
1071
  delta.functions.push(collected);
384
- const args = ts2.isArrowFunction(node) ? arrowArguments(node) : "arguments";
385
- const asyncCallback = node.modifiers?.some(
386
- (modifier) => modifier.kind === ts2.SyntaxKind.AsyncKeyword
387
- ) ? "async " : "";
388
- if (ts2.isBlock(node.body)) {
389
- edits.push({
390
- position: node.body.getStart(sourceFile) + 1,
391
- text: `return ${helperName}(${JSON.stringify(collected.sourceToken)},${args},${asyncCallback}()=>{`,
392
- order: order++
393
- });
394
- edits.push({ position: node.body.end - 1, text: "});", order: order++ });
395
- } else {
396
- edits.push({
397
- position: node.body.getStart(sourceFile),
398
- text: `${helperName}(${JSON.stringify(collected.sourceToken)},${args},${asyncCallback}()=>(`,
399
- order: order++
400
- });
401
- edits.push({ position: node.body.end, text: "))", order: order++ });
402
- }
403
- ts2.forEachChild(node, (child) => visit(child, collected));
1072
+ ts3.forEachChild(node, (child) => visit(child, collected));
404
1073
  return;
405
1074
  }
406
- if (caller && (ts2.isCallExpression(node) || ts2.isNewExpression(node))) {
1075
+ if (caller && (ts3.isCallExpression(node) || ts3.isNewExpression(node))) {
407
1076
  const site = collectCallSite(node, caller, collectContext);
408
1077
  if (site) delta.callSites.push(site);
409
1078
  }
410
- if (caller && ts2.isVariableDeclaration(node)) {
1079
+ if (caller && ts3.isVariableDeclaration(node)) {
411
1080
  const destructure = collectParamDestructure(node, caller, collectContext);
412
1081
  if (destructure) delta.destructures.push(destructure);
413
1082
  }
414
- ts2.forEachChild(node, (child) => visit(child, caller));
1083
+ ts3.forEachChild(node, (child) => visit(child, caller));
415
1084
  };
416
1085
  visit(sourceFile);
417
- if (edits.length === 0) return void 0;
418
- const shebangEnd = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
419
- edits.push({ position: shebangEnd, text: helperDeclaration(helperName), order: -1 });
1086
+ if (pending.length === 0) return void 0;
1087
+ const analyzed = analyzeModuleFunctions(
1088
+ sourceFile,
1089
+ pending.map((entry) => ({
1090
+ functionId: entry.collected.functionId,
1091
+ name: entry.collected.name,
1092
+ node: entry.node
1093
+ }))
1094
+ );
1095
+ delta.derivationPlans = analyzed.map((fn) => fn.plan);
1096
+ const analyzedById = new Map(analyzed.map((fn) => [fn.functionId, fn]));
1097
+ for (const [planIndex, entry] of pending.entries()) {
1098
+ const analysis = analyzedById.get(entry.collected.functionId);
1099
+ const omitValues = derivationMode === "selective" && analysis && canOmitCallValues(analysis, analyzed);
1100
+ const valueFlag = omitValues ? ",1" : "";
1101
+ const args = ts3.isArrowFunction(entry.node) ? arrowArguments(entry.node) : "arguments";
1102
+ const asyncCallback = entry.node.modifiers?.some(
1103
+ (modifier) => modifier.kind === ts3.SyntaxKind.AsyncKeyword
1104
+ ) ? "async " : "";
1105
+ if (ts3.isBlock(entry.node.body)) {
1106
+ edits.push({
1107
+ position: entry.node.body.getStart(sourceFile) + 1,
1108
+ text: `return ${runName}(${planIndex},${args},${asyncCallback}()=>{`,
1109
+ order: order++
1110
+ });
1111
+ edits.push({
1112
+ position: entry.node.body.end - 1,
1113
+ text: `}${valueFlag});`,
1114
+ order: order++
1115
+ });
1116
+ } else {
1117
+ edits.push({
1118
+ position: entry.node.body.getStart(sourceFile),
1119
+ text: `${runName}(${planIndex},${args},${asyncCallback}()=>(`,
1120
+ order: order++
1121
+ });
1122
+ edits.push({
1123
+ position: entry.node.body.end,
1124
+ text: `)${valueFlag})`,
1125
+ order: order++
1126
+ });
1127
+ }
1128
+ if (analysis) {
1129
+ for (const edit of captureWrapEdits(analysis.captureWraps, capName)) {
1130
+ edits.push({ ...edit, order: order++ });
1131
+ }
1132
+ }
1133
+ }
1134
+ const insertAt = insertPositionAfterPrologue(source, sourceFile);
1135
+ edits.push({
1136
+ position: insertAt,
1137
+ text: preambleInsert(
1138
+ source,
1139
+ insertAt,
1140
+ modulePreamble(
1141
+ runName,
1142
+ capName,
1143
+ plansName,
1144
+ JSON.stringify(delta.functions.map((fn) => fn.plan))
1145
+ )
1146
+ ),
1147
+ order: -1
1148
+ });
420
1149
  edits.sort((left, right) => right.position - left.position || right.order - left.order);
421
1150
  let transformed = source;
422
1151
  for (const edit of edits) {
@@ -481,7 +1210,21 @@ import { dirname, resolve as resolve5 } from "node:path";
481
1210
  import { fileURLToPath } from "node:url";
482
1211
  var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve5(dirname(fileURLToPath(instrumentEntryUrl)), "../../..");
483
1212
 
1213
+ // src/auto-instrumentation/warn-production-runtime-transform.ts
1214
+ var RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV = "RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING";
1215
+ var warnedSymbol = Symbol.for("rasputin.runtimeTransformWarning");
1216
+ var warnIfProductionRuntimeTransform = () => {
1217
+ if (process.env.NODE_ENV !== "production") return;
1218
+ if (process.env[RUNTIME_TRANSFORM_WARNING_SUPPRESS_ENV] === "1") return;
1219
+ if (Reflect.get(globalThis, warnedSymbol)) return;
1220
+ Reflect.set(globalThis, warnedSymbol, true);
1221
+ console.warn(
1222
+ "[rasputin] Production is using load-time source transformation (`--import` / `--preload`). Prefer build-time `rasputin-instrument` so the process does not load the TypeScript compiler. Set RASPUTIN_SUPPRESS_RUNTIME_TRANSFORM_WARNING=1 to hide this warning."
1223
+ );
1224
+ };
1225
+
484
1226
  // src/instrument/bun.ts
1227
+ warnIfProductionRuntimeTransform();
485
1228
  plugin(
486
1229
  createRasputinBunPlugin({
487
1230
  excludedRoots: [sdkPackageScopeRootFrom(import.meta.url)]