@rasputin-ai/node 0.3.0 → 0.4.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.
Files changed (26) hide show
  1. package/README.md +18 -4
  2. package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts +6 -0
  3. package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts.map +1 -1
  4. package/dist/auto-instrumentation/format-configuration-report.d.ts +14 -0
  5. package/dist/auto-instrumentation/format-configuration-report.d.ts.map +1 -0
  6. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +9 -3
  7. package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
  8. package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts +11 -1
  9. package/dist/auto-instrumentation/schedule-instrumentation-manifest-upload.d.ts.map +1 -1
  10. package/dist/execution-recorder/automatic-runtime.d.ts +11 -8
  11. package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
  12. package/dist/execution-recorder/execution-recorder-types.d.ts +7 -3
  13. package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
  14. package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
  15. package/dist/execution-recorder/index.d.ts +1 -1
  16. package/dist/execution-recorder/index.d.ts.map +1 -1
  17. package/dist/execution-recorder/source-exclusions.d.ts +2 -1
  18. package/dist/execution-recorder/source-exclusions.d.ts.map +1 -1
  19. package/dist/index.js +307 -111
  20. package/dist/instrument/bun.js +33 -21
  21. package/dist/instrument/node.js +32 -20
  22. package/dist/rasputin-init.d.ts +3 -2
  23. package/dist/rasputin-init.d.ts.map +1 -1
  24. package/dist/sdk-meta.d.ts +2 -2
  25. package/dist/sdk-meta.d.ts.map +1 -1
  26. package/package.json +2 -2
package/README.md CHANGED
@@ -14,7 +14,6 @@ export const rasputin = RasputinInit({
14
14
  release: process.env.RASPUTIN_RELEASE!,
15
15
  environment: process.env.NODE_ENV ?? 'development',
16
16
  enabled: ['staging', 'production'].includes(process.env.NODE_ENV ?? 'development'),
17
- moduleUrl: import.meta.url,
18
17
  });
19
18
  ```
20
19
 
@@ -38,8 +37,23 @@ try {
38
37
  | `environment` | yes | Environment such as `production`, `staging`, or `preview` |
39
38
  | `release` | yes | Git commit SHA for the deployed version |
40
39
  | `enabled` | no | Enables or disables the SDK; defaults to `true` |
41
- | `moduleUrl` | one of these two | `import.meta.url` from the initialization file |
42
- | `repoRoot` | one of these two | Explicit source root for deployments with a different filesystem layout |
40
+ | `logSuccess` | no | Prints a configuration summary when setup succeeds; defaults to `true`. Failures always log. |
41
+ | `moduleUrl` | no | `import.meta.url` from the initialization file; helps normalize local stack paths |
42
+ | `sourceRoot` | no | Git repository folder for a single-package service, such as `apps/api` |
43
+ | `sourceRoots` | no | Package-name to Git-folder mappings for ambiguous monorepos |
44
+ | `repoRoot` | no | Local filesystem display root; it does not control instrumentation or Git identity |
45
+
46
+ Rasputin normally identifies source from the nearest `package.json` and verifies it against the exact release on the server. Filesystem paths such as `/container` are never used as source identity.
47
+
48
+ For deployment checks, call:
49
+
50
+ ```ts
51
+ const verification = await rasputin.verifyConfiguration();
52
+ ```
53
+
54
+ `verified` means every instrumented source file maps uniquely to the configured Git release. If a monorepo is ambiguous, set `sourceRoot` or `sourceRoots` using repository-relative folders, never Docker paths.
55
+
56
+ Rasputin also prints a configuration summary after the instrumentation manifest is uploaded. Set `logSuccess: false` if you do not want that banner in production logs. Mapping failures still warn.
43
57
 
44
58
  ## Shutdown
45
59
 
@@ -124,7 +138,7 @@ Defaults work for most apps. Customize to exclude noisy sources, redact fields,
124
138
  | `maxStringLength` | `500` | Maximum characters retained from one string |
125
139
  | `maxSerializedValueBytes` | `8 KiB` | Maximum retained size of one captured value |
126
140
  | `redactKeys` | `[]` | Additional case-insensitive property names to redact |
127
- | `excludeSources` | `[]` | Source globs or function-ID patterns to exclude |
141
+ | `excludeSources` | `[]` | Source globs or function-name patterns to exclude |
128
142
 
129
143
  ```ts
130
144
  const rasputin = RasputinInit({
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Walks the TypeScript AST while a module is being transformed and records the static facts
3
+ * Rasputin needs for replay: instrumented functions, call sites, and parameter destructuring
4
+ * bindings. transform-source calls these collectors and passes the delta to the manifest
5
+ * registry so the server can map runtime locations back to Git.
6
+ */
1
7
  import type { InstrumentationArgIdentifier, InstrumentationParamBinding } from '@rasputin-ai/core';
2
8
  import ts from 'typescript';
3
9
  type SourceLocation = {
@@ -1 +1 @@
1
- {"version":3,"file":"collect-instrumentation-delta.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/collect-instrumentation-delta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,KAAK,cAAc,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,oBAAoB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,cAAc,GAAG,SAAS,CAAC;AAErF,KAAK,mBAAmB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,4BAA4B,EAAE,CAAC;CAC/C,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAEF,KAAK,cAAc,GAAG;IACrB,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;IAC1B,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,2BAA2B,EAAE,CAAC;IACtC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IAC1C,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,YAAY,EAAE,sBAAsB,EAAE,CAAC;CACvC,CAAC;AAqCF,eAAO,MAAM,qBAAqB,GACjC,MAAM,EAAE,CAAC,uBAAuB,EAChC,YAAY,EAAE,CAAC,UAAU,KACvB;IAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAQlE,CAAC;AA2BF,eAAO,MAAM,cAAc,GAC1B,YAAY,EAAE,CAAC,UAAU,EACzB,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,cAAc,oBAAoB,+BASlC,CAAC;AAuEF,eAAO,MAAM,eAAe,GAC3B,MAAM,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,aAAa,EAC1C,QAAQ,mBAAmB,EAC3B,SAAS,cAAc,KACrB,mBAAmB,GAAG,IA4BxB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GACnC,aAAa,EAAE,CAAC,mBAAmB,EACnC,QAAQ,mBAAmB,EAC3B,SAAS,cAAc,KACrB,sBAAsB,GAAG,IAsB3B,CAAC"}
1
+ {"version":3,"file":"collect-instrumentation-delta.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/collect-instrumentation-delta.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,KAAK,cAAc,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,oBAAoB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,cAAc,GAAG,SAAS,CAAC;AAErF,KAAK,mBAAmB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,4BAA4B,EAAE,CAAC;CAC/C,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAEF,KAAK,cAAc,GAAG;IACrB,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;IAC1B,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,2BAA2B,EAAE,CAAC;IACtC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IAC1C,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,YAAY,EAAE,sBAAsB,EAAE,CAAC;CACvC,CAAC;AAqCF,eAAO,MAAM,qBAAqB,GACjC,MAAM,EAAE,CAAC,uBAAuB,EAChC,YAAY,EAAE,CAAC,UAAU,KACvB;IAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAQlE,CAAC;AA2BF,eAAO,MAAM,cAAc,GAC1B,YAAY,EAAE,CAAC,UAAU,EACzB,UAAU,MAAM,EAChB,cAAc,MAAM,EACpB,cAAc,oBAAoB,+BASlC,CAAC;AAuEF,eAAO,MAAM,eAAe,GAC3B,MAAM,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,aAAa,EAC1C,QAAQ,mBAAmB,EAC3B,SAAS,cAAc,KACrB,mBAAmB,GAAG,IA4BxB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GACnC,aAAa,EAAE,CAAC,mBAAmB,EACnC,QAAQ,mBAAmB,EAC3B,SAAS,cAAc,KACrB,sBAAsB,GAAG,IAsB3B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { SourceVerification } from '@rasputin-ai/core';
2
+ type ConfigurationReportInput = {
3
+ release: string;
4
+ runtime: string;
5
+ modules: number;
6
+ functions: number;
7
+ packageNames: string[];
8
+ verification: SourceVerification;
9
+ uploaded: boolean;
10
+ };
11
+ export declare const formatConfigurationReport: (input: ConfigurationReportInput) => string;
12
+ export declare const runtimeLabel: () => string;
13
+ export {};
14
+ //# sourceMappingURL=format-configuration-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-configuration-report.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/format-configuration-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,KAAK,wBAAwB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,kBAAkB,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;CAClB,CAAC;AA2CF,eAAO,MAAM,yBAAyB,GAAI,OAAO,wBAAwB,KAAG,MAkE3E,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,MAI/B,CAAC"}
@@ -1,11 +1,17 @@
1
- import type { InstrumentationManifestContent } from '@rasputin-ai/core';
1
+ import { type InstrumentationManifestContent } from '@rasputin-ai/core';
2
2
  import type { InstrumentationManifestDelta } from './collect-instrumentation-delta';
3
- export declare const INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v1";
3
+ export declare const INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
4
+ type SnapshotOptions = {
5
+ sourceRoot?: string;
6
+ sourceRoots?: Record<string, string>;
7
+ };
4
8
  export declare const recordInstrumentationManifestDelta: (filePath: string, delta: InstrumentationManifestDelta) => void;
5
9
  export declare const isInstrumentationManifestDirty: () => boolean;
6
10
  export declare const instrumentationManifestGeneration: () => number;
7
- export declare const snapshotInstrumentationManifest: (repoRoot: string) => InstrumentationManifestContent | undefined;
11
+ export declare const instrumentationManifestModuleCount: () => number;
12
+ export declare const snapshotInstrumentationManifest: (options?: SnapshotOptions) => InstrumentationManifestContent | undefined;
8
13
  export declare const markInstrumentationManifestUploaded: (generation: number) => void;
9
14
  export declare const setInstrumentationManifestOnDirty: (onDirty?: () => void) => void;
10
15
  export declare const resetInstrumentationManifestRegistry: () => void;
16
+ export {};
11
17
  //# sourceMappingURL=instrumentation-manifest-registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation-manifest-registry.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/instrumentation-manifest-registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEX,8BAA8B,EAG9B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAEpF,eAAO,MAAM,+BAA+B,yCAAyC,CAAC;AA2CtF,eAAO,MAAM,kCAAkC,GAC9C,UAAU,MAAM,EAChB,OAAO,4BAA4B,KACjC,IAKF,CAAC;AAEF,eAAO,MAAM,8BAA8B,QAAO,OAGjD,CAAC;AAEF,eAAO,MAAM,iCAAiC,QAAO,MAAkC,CAAC;AAExF,eAAO,MAAM,+BAA+B,GAC3C,UAAU,MAAM,KACd,8BAA8B,GAAG,SAmEnC,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAAI,YAAY,MAAM,KAAG,IAKxE,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAAI,UAAU,MAAM,IAAI,KAAG,IAExE,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC"}
1
+ {"version":3,"file":"instrumentation-manifest-registry.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/instrumentation-manifest-registry.ts"],"names":[],"mappings":"AAMA,OAAO,EAGN,KAAK,8BAA8B,EAKnC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAEpF,eAAO,MAAM,+BAA+B,yCAAyC,CAAC;AAYtF,KAAK,eAAe,GAAG;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAAC;AAiCF,eAAO,MAAM,kCAAkC,GAC9C,UAAU,MAAM,EAChB,OAAO,4BAA4B,KACjC,IAKF,CAAC;AAEF,eAAO,MAAM,8BAA8B,QAAO,OAGjD,CAAC;AAEF,eAAO,MAAM,iCAAiC,QAAO,MAAkC,CAAC;AAExF,eAAO,MAAM,kCAAkC,QAAO,MAAkC,CAAC;AAEzF,eAAO,MAAM,+BAA+B,GAC3C,UAAS,eAAoB,KAC3B,8BAA8B,GAAG,SAiFnC,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAAI,YAAY,MAAM,KAAG,IAGxE,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAAI,UAAU,MAAM,IAAI,KAAG,IAExE,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC"}
@@ -1,8 +1,17 @@
1
+ /**
2
+ * The manifest registry accumulates instrumentation facts as modules load, but Rasputin only
3
+ * learns about them after an upload. This schedules that upload after startup without blocking
4
+ * the process, debounces on registry changes, prints the configuration report once, and exposes
5
+ * verifyConfiguration().
6
+ */
7
+ import { type SourceVerification } from '@rasputin-ai/core';
1
8
  type ScheduleInstrumentationManifestUploadOptions = {
2
9
  projectApiKey: string;
3
10
  release?: string;
4
11
  apiUrl?: string;
5
- repoRoot?: string;
12
+ sourceRoot?: string;
13
+ sourceRoots?: Record<string, string>;
14
+ logSuccess?: boolean;
6
15
  fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
7
16
  enabled: boolean;
8
17
  };
@@ -10,6 +19,7 @@ type InstrumentationManifestUploadHandle = {
10
19
  flushSoon: () => void;
11
20
  wait: () => Promise<void>;
12
21
  disconnect: () => void;
22
+ verify: () => Promise<SourceVerification>;
13
23
  };
14
24
  export declare const scheduleInstrumentationManifestUpload: (options: ScheduleInstrumentationManifestUploadOptions) => InstrumentationManifestUploadHandle;
15
25
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-instrumentation-manifest-upload.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts"],"names":[],"mappings":"AAaA,KAAK,4CAA4C,GAAG;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjF,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,mCAAmC,GAAG;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,UAAU,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAQF,eAAO,MAAM,qCAAqC,GACjD,SAAS,4CAA4C,KACnD,mCA4CF,CAAC"}
1
+ {"version":3,"file":"schedule-instrumentation-manifest-upload.d.ts","sourceRoot":"","sources":["../../src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAGN,KAAK,kBAAkB,EAEvB,MAAM,mBAAmB,CAAC;AAW3B,KAAK,4CAA4C,GAAG;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjF,OAAO,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,mCAAmC,GAAG;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC1C,CAAC;AAkBF,eAAO,MAAM,qCAAqC,GACjD,SAAS,4CAA4C,KACnD,mCAwGF,CAAC"}
@@ -1,18 +1,21 @@
1
+ /**
2
+ * Compiler-instrumented functions and the initialized SDK can live in separate bundles. This
3
+ * versioned global registry joins them without generated code importing a physical SDK file. Source
4
+ * tokens contain only package-relative identity, so Docker paths never leak into runtime events.
5
+ */
6
+ import { type RuntimeFunctionDefinition } from '@rasputin-ai/core';
1
7
  import type { RasputinExecution } from './execution-recorder-types';
2
- export declare const AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v1";
8
+ export declare const AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
3
9
  type AutomaticFunctionSource = {
4
10
  filePath: string;
5
11
  name: string;
6
12
  line: number;
7
13
  column: number;
8
14
  };
9
- type AutomaticExecutionRuntimeOptions = {
10
- repoRoot?: string;
11
- };
12
- /** Encode source metadata once at transform time without allocating an object per function call. */
15
+ /** Resolve package ownership at transform time, never on the user's request hot path. */
13
16
  export declare const encodeAutomaticFunctionSource: (source: AutomaticFunctionSource) => string;
14
- export declare const normalizeAutomaticFunctionId: (sourceToken: string, repoRoot: string) => string | undefined;
15
- /** Connect compiler-instrumented application functions to this SDK instance. */
16
- export declare const installAutomaticExecutionRuntime: (execution: RasputinExecution, options?: AutomaticExecutionRuntimeOptions) => (() => void);
17
+ export declare const decodeAutomaticFunctionSource: (sourceToken: string) => RuntimeFunctionDefinition | undefined;
18
+ /** Connect transformed application functions to this SDK instance. */
19
+ export declare const installAutomaticExecutionRuntime: (execution: RasputinExecution) => (() => void);
17
20
  export {};
18
21
  //# sourceMappingURL=automatic-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"automatic-runtime.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/automatic-runtime.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAKxE,KAAK,uBAAuB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,gCAAgC,GAAG;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAWF,oGAAoG;AACpG,eAAO,MAAM,6BAA6B,GAAI,QAAQ,uBAAuB,KAAG,MAG9E,CAAC;AAEH,eAAO,MAAM,4BAA4B,GACxC,aAAa,MAAM,EACnB,UAAU,MAAM,KACd,MAAM,GAAG,SAWX,CAAC;AA0BF,gFAAgF;AAChF,eAAO,MAAM,gCAAgC,GAC5C,WAAW,iBAAiB,EAC5B,UAAS,gCAAqC,KAC5C,CAAC,MAAM,IAAI,CAwBb,CAAC"}
1
+ {"version":3,"file":"automatic-runtime.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/automatic-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACN,KAAK,yBAAyB,EAG9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAKxE,KAAK,uBAAuB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAaF,yFAAyF;AACzF,eAAO,MAAM,6BAA6B,GAAI,QAAQ,uBAAuB,KAAG,MAO/E,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACzC,aAAa,MAAM,KACjB,yBAAyB,GAAG,SAe9B,CAAC;AAuBF,sEAAsE;AACtE,eAAO,MAAM,gCAAgC,GAAI,WAAW,iBAAiB,KAAG,CAAC,MAAM,IAAI,CAkB1F,CAAC"}
@@ -3,7 +3,7 @@
3
3
  * event model explicit allows the same bounded state to represent HTTP requests, jobs, scheduled
4
4
  * work, and future serverless invocations without coupling the recorder to one framework lifecycle.
5
5
  */
6
- import type { RuntimeExecutionEvent, RuntimeExecutionKind, RuntimeExecutionMetadata, RuntimeExecutionState, RuntimeFunctionCallsSuppressedEvent, RuntimeFunctionEnterEvent } from '@rasputin-ai/core';
6
+ import type { RuntimeExecutionEvent, RuntimeExecutionKind, RuntimeExecutionMetadata, RuntimeExecutionState, RuntimeFunctionCallsSuppressedEvent, RuntimeFunctionDefinition, RuntimeFunctionEnterEvent, SourcePosition } from '@rasputin-ai/core';
7
7
  export type ExecutionSourceExclusion = string | RegExp;
8
8
  export type ExecutionRecorderOptions = {
9
9
  /** Disable runtime-state capture explicitly. It is enabled by SDK initializers by default. */
@@ -37,6 +37,10 @@ export type ExecutionFunctionEnterEvent = RuntimeFunctionEnterEvent;
37
37
  export type ExecutionFunctionCallsSuppressedEvent = RuntimeFunctionCallsSuppressedEvent;
38
38
  export type ExecutionEvent = RuntimeExecutionEvent;
39
39
  export type ExecutionState = RuntimeExecutionState;
40
+ export type ExecutionFunctionDescriptor = {
41
+ name: string;
42
+ source?: SourcePosition;
43
+ };
40
44
  export type ExecutionRecorderStats = {
41
45
  errorSnapshots: number;
42
46
  successfulExecutionsDiscarded: number;
@@ -63,9 +67,9 @@ export type RasputinExecution = {
63
67
  run: <T>(metadata: ExecutionMetadata, callback: () => T) => T;
64
68
  getErrorState: (error: unknown, metadata?: Partial<ExecutionMetadata>) => ExecutionState | undefined;
65
69
  /** Internal primitive used by SDK-owned source instrumentation. */
66
- runFunction: <T>(functionId: string, args: ArrayLike<unknown>, callback: () => T) => T;
70
+ runFunction: <T>(definition: RuntimeFunctionDefinition | string, args: ArrayLike<unknown>, callback: () => T) => T;
67
71
  /** Manual fallback for runtimes/build systems without automatic instrumentation. */
68
- trace: <TThis, TArgs extends unknown[], TResult>(functionId: string, fn: (this: TThis, ...args: TArgs) => TResult) => (this: TThis, ...args: TArgs) => TResult;
72
+ trace: <TThis, TArgs extends unknown[], TResult>(definition: string | ExecutionFunctionDescriptor, fn: (this: TThis, ...args: TArgs) => TResult) => (this: TThis, ...args: TArgs) => TResult;
69
73
  getStats: () => ExecutionRecorderStats;
70
74
  };
71
75
  //# sourceMappingURL=execution-recorder-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execution-recorder-types.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execution-recorder-types.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"execution-recorder.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAKX,wBAAwB,EAExB,iBAAiB,EACjB,MAAM,4BAA4B,CAAC;AAwKpC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GACnC,SAAS,wBAAwB,GAAG,SAAS,KAC3C,iBA+bF,CAAC"}
1
+ {"version":3,"file":"execution-recorder.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/execution-recorder.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAKX,wBAAwB,EAExB,iBAAiB,EACjB,MAAM,4BAA4B,CAAC;AA8LpC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GACnC,SAAS,wBAAwB,GAAG,SAAS,KAC3C,iBAkdF,CAAC"}
@@ -1,3 +1,3 @@
1
1
  export { createExecutionRecorder } from './execution-recorder';
2
- export type { ExecutionKind, ExecutionMetadata, ExecutionRecorderOptions, ExecutionRecorderStats, ExecutionScope, ExecutionSourceExclusion, ExecutionState, RasputinExecution, } from './execution-recorder-types';
2
+ export type { ExecutionFunctionDescriptor, ExecutionKind, ExecutionMetadata, ExecutionRecorderOptions, ExecutionRecorderStats, ExecutionScope, ExecutionSourceExclusion, ExecutionState, RasputinExecution, } from './execution-recorder-types';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EACX,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,cAAc,EACd,iBAAiB,GACjB,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EACX,2BAA2B,EAC3B,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,wBAAwB,EACxB,cAAc,EACd,iBAAiB,GACjB,MAAM,4BAA4B,CAAC"}
@@ -3,7 +3,8 @@
3
3
  * capture time avoids both CPU work and accidental retention of redundant logger/framework state,
4
4
  * while compiling patterns once keeps the exclusion feature off the hot path.
5
5
  */
6
+ import type { RuntimeFunctionDefinition } from '@rasputin-ai/core';
6
7
  import type { ExecutionSourceExclusion } from './execution-recorder-types';
7
8
  /** Compile exclusions once so skipped calls avoid serialization and repeated pattern work. */
8
- export declare const createSourceExclusionMatcher: (exclusions: ExecutionSourceExclusion[] | undefined) => ((functionId: string) => boolean);
9
+ export declare const createSourceExclusionMatcher: (exclusions: ExecutionSourceExclusion[] | undefined) => ((definition: RuntimeFunctionDefinition) => boolean);
9
10
  //# sourceMappingURL=source-exclusions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-exclusions.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/source-exclusions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAsC3E,8FAA8F;AAC9F,eAAO,MAAM,4BAA4B,GACxC,YAAY,wBAAwB,EAAE,GAAG,SAAS,KAChD,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CA8BlC,CAAC"}
1
+ {"version":3,"file":"source-exclusions.d.ts","sourceRoot":"","sources":["../../src/execution-recorder/source-exclusions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AA2C3E,8FAA8F;AAC9F,eAAO,MAAM,4BAA4B,GACxC,YAAY,wBAAwB,EAAE,GAAG,SAAS,KAChD,CAAC,CAAC,UAAU,EAAE,yBAAyB,KAAK,OAAO,CAgCrD,CAAC"}
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 { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
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 { isAbsolute, relative, resolve, sep } from "node:path";
13
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v1";
14
- var AUTOMATIC_SOURCE_SEPARATOR = "\0";
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 normalizeAutomaticFunctionId = (sourceToken, repoRoot) => {
17
- if (!sourceToken.includes(AUTOMATIC_SOURCE_SEPARATOR)) return sourceToken;
18
- const [filePath, name, line, column] = sourceToken.split(AUTOMATIC_SOURCE_SEPARATOR);
19
- if (!filePath || !name || !line || !column) return void 0;
20
- const fromRoot = relative(repoRoot, resolve(filePath));
21
- if (!fromRoot || fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
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: (functionId, args, callback) => {
145
+ run: (sourceToken, args, callback) => {
36
146
  const runtime = runtimes.at(-1);
37
- return runtime ? runtime.run(functionId, args, callback) : callback();
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, options = {}) => {
153
+ var installAutomaticExecutionRuntime = (execution) => {
44
154
  const registry = getRegistry();
45
- const repoRoot = options.repoRoot ? resolve(options.repoRoot) : void 0;
46
- const normalizedIds = /* @__PURE__ */ new Map();
155
+ const definitions = /* @__PURE__ */ new Map();
47
156
  const runtime = {
48
157
  run: (sourceToken, args, callback) => {
49
- if (!sourceToken.includes(AUTOMATIC_SOURCE_SEPARATOR)) {
50
- return execution.runFunction(sourceToken, args, callback);
51
- }
52
- if (!repoRoot) return callback();
53
- let functionId = normalizedIds.get(sourceToken);
54
- if (!normalizedIds.has(sourceToken)) {
55
- functionId = normalizeAutomaticFunctionId(sourceToken, repoRoot);
56
- normalizedIds.set(sourceToken, functionId);
158
+ let definition = definitions.get(sourceToken);
159
+ if (!definitions.has(sourceToken)) {
160
+ definition = decodeAutomaticFunctionSource(sourceToken);
161
+ definitions.set(sourceToken, definition);
57
162
  }
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.v1";
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 repoRelativePath = (filePath, repoRoot) => {
86
- const fromRoot = relative2(repoRoot, resolve2(filePath));
87
- if (!fromRoot || fromRoot === ".." || fromRoot.startsWith(`..${sep2}`) || isAbsolute2(fromRoot)) {
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 snapshotInstrumentationManifest = (repoRoot) => {
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 functionId = normalizeAutomaticFunctionId(fn.sourceToken, root);
105
- const path = repoRelativePath(fn.filePath, root);
106
- if (!functionId || !path) continue;
207
+ const definition = decodeAutomaticFunctionSource(fn.sourceToken);
208
+ if (!definition?.source) continue;
107
209
  functions.push({
108
- functionId,
109
- path,
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 callerFunctionId = normalizeAutomaticFunctionId(site.callerSourceToken, root);
120
- const path = repoRelativePath(site.filePath, root);
121
- if (!callerFunctionId || !path) continue;
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: `${path}:${site.line}:${site.column}`,
124
- callerFunctionId,
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
- path,
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 callerFunctionId = normalizeAutomaticFunctionId(destructure.callerSourceToken, root);
138
- const path = repoRelativePath(destructure.filePath, root);
139
- if (!callerFunctionId || !path) continue;
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
- path,
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: 1,
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
- const repoRoot = options.repoRoot;
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(repoRoot);
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 === "ok") markInstrumentationManifestUploaded(generation);
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 = (functionId) => {
581
- const separator = functionId.indexOf(":");
582
- return (separator < 0 ? functionId : functionId.slice(0, separator)).replaceAll("\\", "/");
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((exclusion) => {
614
- if (exclusion instanceof RegExp) {
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
- (functionId) => {
617
- exclusion.lastIndex = 0;
618
- const matched = exclusion.test(functionId);
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
- const pattern = normalizePattern(exclusion);
625
- if (!pattern) return [];
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) => {
@@ -773,8 +959,14 @@ var createExecutionRecorder = (options) => {
773
959
  const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => safeSerializeWithBytes(value, options));
774
960
  const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
775
961
  const recorderStartedAtNs = process.hrtime.bigint();
962
+ const events = recording.events.values().map((event) => event.type === "function_calls_suppressed" ? { ...event } : event);
963
+ const referencedFunctionIds = new Set(
964
+ events.flatMap(
965
+ (event) => event.type === "function_enter" || event.type === "function_calls_suppressed" ? [event.functionId] : []
966
+ )
967
+ );
776
968
  const state = {
777
- version: 1,
969
+ version: 2,
778
970
  executionId: recording.executionId,
779
971
  startedAt: recording.startedAt,
780
972
  durationMs: elapsedMs(recording.startedAtNs, endedAtNs),
@@ -783,7 +975,10 @@ var createExecutionRecorder = (options) => {
783
975
  ...recording.execution,
784
976
  ...recording.execution.request ? { request: { ...recording.execution.request } } : {}
785
977
  },
786
- events: recording.events.values().map((event) => event.type === "function_calls_suppressed" ? { ...event } : event),
978
+ functions: [...recording.functions.values()].filter(
979
+ (definition) => referencedFunctionIds.has(definition.functionId)
980
+ ),
981
+ events,
787
982
  ...recording.events.dropped > 0 ? { truncated: { eventsDropped: recording.events.dropped } } : {},
788
983
  ...recording.memory.underPressure ? {
789
984
  capture: {
@@ -925,6 +1120,7 @@ var createExecutionRecorder = (options) => {
925
1120
  ...metadata.request ? { request: { ...metadata.request } } : {}
926
1121
  },
927
1122
  events: new CallAwareEventBuffer(maxEventsPerExecution),
1123
+ functions: /* @__PURE__ */ new Map(),
928
1124
  repeatedCalls: /* @__PURE__ */ new Map(),
929
1125
  capturedErrors: /* @__PURE__ */ new WeakMap(),
930
1126
  nextCallId: 0,
@@ -993,16 +1189,19 @@ var createExecutionRecorder = (options) => {
993
1189
  return void 0;
994
1190
  }
995
1191
  };
996
- const runFunction = (functionId, args, callback) => {
1192
+ const runFunction = (input, args, callback) => {
997
1193
  const store = storage.getStore();
998
1194
  if (!store || store.recording.finished) return callback();
1195
+ const definition = normalizeFunctionDefinition(input);
1196
+ const functionId = definition.functionId;
999
1197
  const recorderStartedAtNs = process.hrtime.bigint();
1000
- if (store.suppressCapture || excludesSource(functionId)) {
1198
+ if (store.suppressCapture || excludesSource(definition)) {
1001
1199
  return storage.run({ ...store, suppressCapture: true }, () => {
1002
1200
  addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
1003
1201
  return callback();
1004
1202
  });
1005
1203
  }
1204
+ store.recording.functions.set(functionId, definition);
1006
1205
  const parentCallId = store.currentCallId;
1007
1206
  const group = repeatedCallGroup(store.recording, functionId, parentCallId);
1008
1207
  group.observedCalls++;
@@ -1111,9 +1310,10 @@ var createExecutionRecorder = (options) => {
1111
1310
  )
1112
1311
  );
1113
1312
  };
1114
- function trace(functionId, fn) {
1313
+ function trace(input, fn) {
1314
+ const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
1115
1315
  return function traced(...args) {
1116
- return runFunction(functionId, args, () => fn.apply(this, args));
1316
+ return runFunction(definition, args, () => fn.apply(this, args));
1117
1317
  };
1118
1318
  }
1119
1319
  return {
@@ -1177,26 +1377,23 @@ var installGlobalHandlers = (client, options = {}) => {
1177
1377
  // src/rasputin-init.ts
1178
1378
  import {
1179
1379
  createClient,
1180
- isClientEnabled,
1181
- resolveRepoRoot
1380
+ isClientEnabled
1182
1381
  } from "@rasputin-ai/core";
1183
1382
 
1184
1383
  // src/sdk-meta.ts
1185
1384
  var SDK_NAME = "@rasputin-ai/node";
1186
- var SDK_VERSION = "0.3.0";
1385
+ var SDK_VERSION = "0.4.0";
1187
1386
 
1188
1387
  // src/rasputin-init.ts
1189
- var withExecution = (client, execution, installRuntime, repoRoot, manifest) => {
1190
- const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(execution, { repoRoot }) : () => {
1388
+ var withExecution = (client, execution, installRuntime, manifest) => {
1389
+ const uninstallRuntime = installRuntime ? installAutomaticExecutionRuntime(execution) : () => {
1191
1390
  };
1192
- const manifestUpload = scheduleInstrumentationManifestUpload({
1193
- ...manifest,
1194
- repoRoot
1195
- });
1391
+ const manifestUpload = scheduleInstrumentationManifestUpload(manifest);
1196
1392
  return {
1197
1393
  ...client,
1198
1394
  execution,
1199
1395
  getStats: () => ({ ...client.getStats(), recorder: execution.getStats() }),
1396
+ verifyConfiguration: manifestUpload.verify,
1200
1397
  captureException: (error, context) => {
1201
1398
  const runtimeState = context?.runtimeState ?? execution.getErrorState(
1202
1399
  error,
@@ -1226,18 +1423,15 @@ var RasputinInit = (options) => {
1226
1423
  ...options.executionRecorder,
1227
1424
  enabled: recorderEnabled
1228
1425
  });
1229
- const wrappedClient = withExecution(
1230
- client,
1231
- execution,
1232
- recorderEnabled,
1233
- resolveRepoRoot(options),
1234
- {
1235
- projectApiKey: options.projectApiKey,
1236
- release: options.release,
1237
- apiUrl: options.apiUrl,
1238
- enabled: isClientEnabled(options)
1239
- }
1240
- );
1426
+ const wrappedClient = withExecution(client, execution, recorderEnabled, {
1427
+ projectApiKey: options.projectApiKey,
1428
+ release: options.release,
1429
+ apiUrl: options.apiUrl,
1430
+ enabled: isClientEnabled(options),
1431
+ sourceRoot: options.sourceRoot,
1432
+ sourceRoots: options.sourceRoots,
1433
+ logSuccess: options.logSuccess
1434
+ });
1241
1435
  if (isClientEnabled(options)) {
1242
1436
  installGlobalHandlers(wrappedClient);
1243
1437
  }
@@ -1247,12 +1441,14 @@ var RasputinInit = (options) => {
1247
1441
  createClient({ ...options, enabled: false }),
1248
1442
  createExecutionRecorder({ enabled: false }),
1249
1443
  false,
1250
- void 0,
1251
1444
  {
1252
1445
  projectApiKey: options.projectApiKey,
1253
1446
  release: options.release,
1254
1447
  apiUrl: options.apiUrl,
1255
- enabled: false
1448
+ enabled: false,
1449
+ sourceRoot: options.sourceRoot,
1450
+ sourceRoots: options.sourceRoots,
1451
+ logSuccess: options.logSuccess
1256
1452
  }
1257
1453
  );
1258
1454
  }
@@ -3,22 +3,34 @@ import { plugin } from "bun";
3
3
 
4
4
  // src/auto-instrumentation/bun-plugin.ts
5
5
  import { readFile } from "node:fs/promises";
6
- import { resolve as resolve5 } from "node:path";
6
+ import { resolve as resolve4 } from "node:path";
7
7
 
8
8
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
9
- import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
9
+ import { resolve } from "node:path";
10
+ import {
11
+ INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
12
+ sourceLocatorFromFile as sourceLocatorFromFile2
13
+ } from "@rasputin-ai/core";
10
14
 
11
15
  // src/execution-recorder/automatic-runtime.ts
12
- import { isAbsolute, relative, resolve, sep } from "node:path";
13
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v1";
14
- var AUTOMATIC_SOURCE_SEPARATOR = "\0";
16
+ import {
17
+ runtimeFunctionId,
18
+ sourceLocatorFromFile
19
+ } from "@rasputin-ai/core";
20
+ var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
21
+ var AUTOMATIC_SOURCE_PREFIX = "rasputin-source-v2:";
15
22
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
16
- var encodeAutomaticFunctionSource = (source) => [resolve(source.filePath), source.name, String(source.line), String(source.column)].join(
17
- AUTOMATIC_SOURCE_SEPARATOR
18
- );
23
+ var encodeAutomaticFunctionSource = (source) => {
24
+ const locator = sourceLocatorFromFile(source.filePath);
25
+ const value = {
26
+ name: source.name,
27
+ ...locator ? { source: { ...locator, line: source.line, column: source.column } } : {}
28
+ };
29
+ return `${AUTOMATIC_SOURCE_PREFIX}${JSON.stringify(value)}`;
30
+ };
19
31
 
20
32
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
21
- var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v1";
33
+ var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
22
34
  var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
23
35
  var getRegistry = () => {
24
36
  const existing = Reflect.get(globalThis, registrySymbol);
@@ -36,13 +48,13 @@ var getRegistry = () => {
36
48
  };
37
49
  var recordInstrumentationManifestDelta = (filePath, delta) => {
38
50
  const registry = getRegistry();
39
- registry.files.set(resolve2(filePath), delta);
51
+ registry.files.set(resolve(filePath), delta);
40
52
  registry.generation += 1;
41
53
  registry.onDirty?.();
42
54
  };
43
55
 
44
56
  // src/auto-instrumentation/source-classification.ts
45
- import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
57
+ import { isAbsolute, relative, resolve as resolve2, sep } from "node:path";
46
58
  var sourceExtension = /\.[cm]?[jt]sx?$/i;
47
59
  var alwaysExcludedDirectory = /(^|[\\/])(node_modules|coverage|generated|\.git|\.next|\.svelte-kit|\.output|\.vercel|\.rasputin|\.turbo|\.yarn|\.pnpm|\.bun)([\\/]|$)/;
48
60
  var buildOutputDirectory = /(^|[\\/])(dist|build|out)([\\/]|$)/;
@@ -53,11 +65,11 @@ var matches = (pattern, value) => {
53
65
  return result;
54
66
  };
55
67
  var isWithinRoot = (filePath, root) => {
56
- const fromRoot = relative3(resolve3(root), filePath);
57
- return fromRoot === "" || !fromRoot.startsWith(`..${sep3}`) && fromRoot !== ".." && !isAbsolute3(fromRoot);
68
+ const fromRoot = relative(resolve2(root), filePath);
69
+ return fromRoot === "" || !fromRoot.startsWith(`..${sep}`) && fromRoot !== ".." && !isAbsolute(fromRoot);
58
70
  };
59
71
  var isApplicationSource = (filePath, options = {}) => {
60
- const absolutePath = resolve3(filePath);
72
+ const absolutePath = resolve2(filePath);
61
73
  if (!sourceExtension.test(absolutePath) || alwaysExcludedDirectory.test(absolutePath))
62
74
  return false;
63
75
  if (options.includeBuildOutput !== true && buildOutputDirectory.test(absolutePath)) return false;
@@ -71,7 +83,7 @@ var isApplicationSource = (filePath, options = {}) => {
71
83
  };
72
84
 
73
85
  // src/auto-instrumentation/transform-source.ts
74
- import { resolve as resolve4 } from "node:path";
86
+ import { resolve as resolve3 } from "node:path";
75
87
  import ts2 from "typescript";
76
88
 
77
89
  // src/auto-instrumentation/collect-instrumentation-delta.ts
@@ -348,7 +360,7 @@ var transformSource = (source, options) => {
348
360
  );
349
361
  let helperName = "__rasputinAutoRun__";
350
362
  while (source.includes(helperName)) helperName += "_";
351
- const absolutePath = resolve4(options.filePath);
363
+ const absolutePath = resolve3(options.filePath);
352
364
  const edits = [];
353
365
  let order = 0;
354
366
  const delta = {
@@ -423,7 +435,7 @@ var loaderFor = (filePath) => {
423
435
  var loadedSourceFilter = /^(?!.*[\\/](?:node_modules|dist|build|out|coverage|generated|\.git|\.next|\.svelte-kit|\.output|\.vercel|\.rasputin|\.turbo|\.yarn|\.pnpm|\.bun)[\\/]).*\.[cm]?[jt]sx?$/i;
424
436
  var isLoadedApplicationSource = (filePath, options = {}) => isApplicationSource(filePath, { ...options, includeBuildOutput: false });
425
437
  var loadSourceForInstrumentation = async (filePath, options = {}) => {
426
- const absolutePath = resolve5(filePath);
438
+ const absolutePath = resolve4(filePath);
427
439
  const source = await readFile(absolutePath, "utf8");
428
440
  if (!isLoadedApplicationSource(absolutePath, options)) {
429
441
  return { contents: source, loader: loaderFor(absolutePath), transformed: false };
@@ -449,11 +461,11 @@ var createRasputinBunPlugin = (options = {}) => {
449
461
  setup(build) {
450
462
  if (debug) {
451
463
  console.info(
452
- options.rootDir ? `[rasputin] automatic instrumentation active (source root: ${resolve5(options.rootDir)})` : "[rasputin] automatic instrumentation active (loaded local source)"
464
+ options.rootDir ? `[rasputin] automatic instrumentation active (source root: ${resolve4(options.rootDir)})` : "[rasputin] automatic instrumentation active (loaded local source)"
453
465
  );
454
466
  }
455
467
  build.onLoad({ filter: loadedSourceFilter }, async ({ path }) => {
456
- const absolutePath = resolve5(path);
468
+ const absolutePath = resolve4(path);
457
469
  const result = await loadSourceForInstrumentation(absolutePath, options);
458
470
  if (debug && result.transformed) {
459
471
  console.info(`[rasputin] instrumented ${absolutePath}`);
@@ -465,9 +477,9 @@ var createRasputinBunPlugin = (options = {}) => {
465
477
  };
466
478
 
467
479
  // src/auto-instrumentation/sdk-source-boundary.ts
468
- import { dirname, resolve as resolve6 } from "node:path";
480
+ import { dirname, resolve as resolve5 } from "node:path";
469
481
  import { fileURLToPath } from "node:url";
470
- var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve6(dirname(fileURLToPath(instrumentEntryUrl)), "../../..");
482
+ var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve5(dirname(fileURLToPath(instrumentEntryUrl)), "../../..");
471
483
 
472
484
  // src/instrument/bun.ts
473
485
  plugin(
@@ -3,19 +3,31 @@ import * as nodeModule from "node:module";
3
3
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4
4
 
5
5
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
6
- import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
6
+ import { resolve } from "node:path";
7
+ import {
8
+ INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
9
+ sourceLocatorFromFile as sourceLocatorFromFile2
10
+ } from "@rasputin-ai/core";
7
11
 
8
12
  // src/execution-recorder/automatic-runtime.ts
9
- import { isAbsolute, relative, resolve, sep } from "node:path";
10
- var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v1";
11
- var AUTOMATIC_SOURCE_SEPARATOR = "\0";
13
+ import {
14
+ runtimeFunctionId,
15
+ sourceLocatorFromFile
16
+ } from "@rasputin-ai/core";
17
+ var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
18
+ var AUTOMATIC_SOURCE_PREFIX = "rasputin-source-v2:";
12
19
  var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
13
- var encodeAutomaticFunctionSource = (source) => [resolve(source.filePath), source.name, String(source.line), String(source.column)].join(
14
- AUTOMATIC_SOURCE_SEPARATOR
15
- );
20
+ var encodeAutomaticFunctionSource = (source) => {
21
+ const locator = sourceLocatorFromFile(source.filePath);
22
+ const value = {
23
+ name: source.name,
24
+ ...locator ? { source: { ...locator, line: source.line, column: source.column } } : {}
25
+ };
26
+ return `${AUTOMATIC_SOURCE_PREFIX}${JSON.stringify(value)}`;
27
+ };
16
28
 
17
29
  // src/auto-instrumentation/instrumentation-manifest-registry.ts
18
- var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v1";
30
+ var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v2";
19
31
  var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
20
32
  var getRegistry = () => {
21
33
  const existing = Reflect.get(globalThis, registrySymbol);
@@ -33,13 +45,13 @@ var getRegistry = () => {
33
45
  };
34
46
  var recordInstrumentationManifestDelta = (filePath, delta) => {
35
47
  const registry = getRegistry();
36
- registry.files.set(resolve2(filePath), delta);
48
+ registry.files.set(resolve(filePath), delta);
37
49
  registry.generation += 1;
38
50
  registry.onDirty?.();
39
51
  };
40
52
 
41
53
  // src/auto-instrumentation/source-classification.ts
42
- import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3, sep as sep3 } from "node:path";
54
+ import { isAbsolute, relative, resolve as resolve2, sep } from "node:path";
43
55
  var sourceExtension = /\.[cm]?[jt]sx?$/i;
44
56
  var alwaysExcludedDirectory = /(^|[\\/])(node_modules|coverage|generated|\.git|\.next|\.svelte-kit|\.output|\.vercel|\.rasputin|\.turbo|\.yarn|\.pnpm|\.bun)([\\/]|$)/;
45
57
  var buildOutputDirectory = /(^|[\\/])(dist|build|out)([\\/]|$)/;
@@ -50,11 +62,11 @@ var matches = (pattern, value) => {
50
62
  return result;
51
63
  };
52
64
  var isWithinRoot = (filePath, root) => {
53
- const fromRoot = relative3(resolve3(root), filePath);
54
- return fromRoot === "" || !fromRoot.startsWith(`..${sep3}`) && fromRoot !== ".." && !isAbsolute3(fromRoot);
65
+ const fromRoot = relative(resolve2(root), filePath);
66
+ return fromRoot === "" || !fromRoot.startsWith(`..${sep}`) && fromRoot !== ".." && !isAbsolute(fromRoot);
55
67
  };
56
68
  var isApplicationSource = (filePath, options = {}) => {
57
- const absolutePath = resolve3(filePath);
69
+ const absolutePath = resolve2(filePath);
58
70
  if (!sourceExtension.test(absolutePath) || alwaysExcludedDirectory.test(absolutePath))
59
71
  return false;
60
72
  if (options.includeBuildOutput !== true && buildOutputDirectory.test(absolutePath)) return false;
@@ -69,7 +81,7 @@ var isApplicationSource = (filePath, options = {}) => {
69
81
 
70
82
  // src/auto-instrumentation/source-map-locations.ts
71
83
  import { readFileSync } from "node:fs";
72
- import { dirname, isAbsolute as isAbsolute4, join, resolve as resolve4 } from "node:path";
84
+ import { dirname, isAbsolute as isAbsolute2, join, resolve as resolve3 } from "node:path";
73
85
  import { fileURLToPath, pathToFileURL } from "node:url";
74
86
  import { LEAST_UPPER_BOUND, originalPositionFor, TraceMap } from "@jridgewell/trace-mapping";
75
87
  var sourceMapComment = /(?:\/\/[#@][ \t]*sourceMappingURL=([^\s'"]+)|\/\*[#@][ \t]*sourceMappingURL=([^\s*'"]+)[ \t]*\*\/)\s*$/;
@@ -86,7 +98,7 @@ var sourceMapFor = (generatedPath, source) => {
86
98
  const payload = decodeDataUrl(reference);
87
99
  return payload ? { payload, mapUrl: pathToFileURL(generatedPath).href } : void 0;
88
100
  }
89
- const mapPath = reference ? resolve4(dirname(generatedPath), reference) : `${generatedPath}.map`;
101
+ const mapPath = reference ? resolve3(dirname(generatedPath), reference) : `${generatedPath}.map`;
90
102
  return {
91
103
  payload: readFileSync(mapPath, "utf8"),
92
104
  mapUrl: pathToFileURL(mapPath).href
@@ -94,7 +106,7 @@ var sourceMapFor = (generatedPath, source) => {
94
106
  };
95
107
  var toFilePath = (source, generatedPath) => {
96
108
  if (source.startsWith("file:")) return fileURLToPath(source);
97
- return isAbsolute4(source) ? source : join(dirname(generatedPath), source);
109
+ return isAbsolute2(source) ? source : join(dirname(generatedPath), source);
98
110
  };
99
111
  var createSourceMapLocationMapper = (generatedPath, source) => {
100
112
  try {
@@ -126,7 +138,7 @@ var createSourceMapLocationMapper = (generatedPath, source) => {
126
138
  };
127
139
 
128
140
  // src/auto-instrumentation/transform-source.ts
129
- import { resolve as resolve5 } from "node:path";
141
+ import { resolve as resolve4 } from "node:path";
130
142
  import ts2 from "typescript";
131
143
 
132
144
  // src/auto-instrumentation/collect-instrumentation-delta.ts
@@ -403,7 +415,7 @@ var transformSource = (source, options) => {
403
415
  );
404
416
  let helperName = "__rasputinAutoRun__";
405
417
  while (source.includes(helperName)) helperName += "_";
406
- const absolutePath = resolve5(options.filePath);
418
+ const absolutePath = resolve4(options.filePath);
407
419
  const edits = [];
408
420
  let order = 0;
409
421
  const delta = {
@@ -522,9 +534,9 @@ var registerRasputinNodeHooks = (options = {}) => {
522
534
  };
523
535
 
524
536
  // src/auto-instrumentation/sdk-source-boundary.ts
525
- import { dirname as dirname2, resolve as resolve6 } from "node:path";
537
+ import { dirname as dirname2, resolve as resolve5 } from "node:path";
526
538
  import { fileURLToPath as fileURLToPath3 } from "node:url";
527
- var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve6(dirname2(fileURLToPath3(instrumentEntryUrl)), "../../..");
539
+ var sdkPackageScopeRootFrom = (instrumentEntryUrl) => resolve5(dirname2(fileURLToPath3(instrumentEntryUrl)), "../../..");
528
540
 
529
541
  // src/instrument/node.ts
530
542
  registerRasputinNodeHooks({
@@ -3,7 +3,7 @@
3
3
  * recorder. Centralizing this wiring keeps initialization fail-safe and ensures every capture path
4
4
  * attaches runtime state using the same limits and lifecycle rules.
5
5
  */
6
- import { type RasputinClient, type RasputinClientStats, type RasputinOptions } from '@rasputin-ai/core';
6
+ import { type RasputinClient, type RasputinClientStats, type RasputinOptions, type SourceVerification } from '@rasputin-ai/core';
7
7
  import { type ExecutionRecorderOptions, type ExecutionRecorderStats, type RasputinExecution } from './execution-recorder';
8
8
  export type RasputinNodeOptions = RasputinOptions & {
9
9
  /** Bounded runtime-state capture. Enabled by default; successful executions are discarded. */
@@ -16,6 +16,8 @@ export type RasputinNodeClientStats = RasputinClientStats & {
16
16
  export type RasputinNodeClient = Omit<RasputinClient, 'getStats'> & {
17
17
  execution: RasputinExecution;
18
18
  getStats: () => RasputinNodeClientStats;
19
+ /** Verify package source locators against the configured Git repository and exact release. */
20
+ verifyConfiguration: () => Promise<SourceVerification>;
19
21
  };
20
22
  /**
21
23
  * Boot the Node/Bun SDK: client + process global handlers.
@@ -27,7 +29,6 @@ export type RasputinNodeClient = Omit<RasputinClient, 'getStats'> & {
27
29
  * release: process.env.RASPUTIN_RELEASE!,
28
30
  * environment: process.env.NODE_ENV ?? 'development',
29
31
  * enabled: ['staging', 'production'].includes(process.env.NODE_ENV ?? 'development'),
30
- * moduleUrl: import.meta.url,
31
32
  * });
32
33
  */
33
34
  export declare const RasputinInit: (options: RasputinNodeOptions) => RasputinNodeClient;
@@ -1 +1 @@
1
- {"version":3,"file":"rasputin-init.d.ts","sourceRoot":"","sources":["../src/rasputin-init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAIN,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EAEpB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAEN,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IACnD,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,GAAG;IAC3D,+EAA+E;IAC/E,QAAQ,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG;IACnE,SAAS,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,EAAE,MAAM,uBAAuB,CAAC;CACxC,CAAC;AAkDF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,mBAAmB,KAAG,kBA4C3D,CAAC"}
1
+ {"version":3,"file":"rasputin-init.d.ts","sourceRoot":"","sources":["../src/rasputin-init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAIN,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAEN,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IACnD,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,GAAG;IAC3D,+EAA+E;IAC/E,QAAQ,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG;IACnE,SAAS,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,EAAE,MAAM,uBAAuB,CAAC;IACxC,8FAA8F;IAC9F,mBAAmB,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACvD,CAAC;AAgDF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,mBAAmB,KAAG,kBA2C3D,CAAC"}
@@ -1,4 +1,4 @@
1
- /** Generated by packages/sdk/scripts/generate-sdk-meta.ts — do not edit. */
1
+ /** Generated by scripts/generate-sdk-meta.ts — do not edit. */
2
2
  export declare const SDK_NAME = "@rasputin-ai/node";
3
- export declare const SDK_VERSION = "0.3.0";
3
+ export declare const SDK_VERSION = "0.4.0";
4
4
  //# sourceMappingURL=sdk-meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-meta.d.ts","sourceRoot":"","sources":["../src/sdk-meta.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,sBAAsB,CAAC;AAC5C,eAAO,MAAM,WAAW,UAAU,CAAC"}
1
+ {"version":3,"file":"sdk-meta.d.ts","sourceRoot":"","sources":["../src/sdk-meta.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,sBAAsB,CAAC;AAC5C,eAAO,MAAM,WAAW,UAAU,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rasputin-ai/node",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Official Rasputin AI SDK for Node and Bun.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@jridgewell/trace-mapping": "0.3.31",
39
- "@rasputin-ai/core": "0.3.0",
39
+ "@rasputin-ai/core": "0.4.0",
40
40
  "typescript": "5"
41
41
  },
42
42
  "devDependencies": {