@vibe-validate/extractors 0.17.0-rc2 → 0.17.0-rc4

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 (158) hide show
  1. package/dist/extractor-registry.d.ts +72 -0
  2. package/dist/extractor-registry.d.ts.map +1 -0
  3. package/dist/extractor-registry.js +243 -0
  4. package/dist/extractor-registry.js.map +1 -0
  5. package/dist/extractors/ava/index.d.ts +23 -0
  6. package/dist/extractors/ava/index.d.ts.map +1 -0
  7. package/dist/extractors/ava/index.js +507 -0
  8. package/dist/extractors/ava/index.js.map +1 -0
  9. package/dist/extractors/ava/index.test.d.ts +7 -0
  10. package/dist/extractors/ava/index.test.d.ts.map +1 -0
  11. package/dist/extractors/ava/index.test.js +408 -0
  12. package/dist/extractors/ava/index.test.js.map +1 -0
  13. package/dist/extractors/eslint/index.d.ts +18 -0
  14. package/dist/extractors/eslint/index.d.ts.map +1 -0
  15. package/dist/extractors/eslint/index.js +206 -0
  16. package/dist/extractors/eslint/index.js.map +1 -0
  17. package/dist/extractors/eslint/index.test.d.ts +9 -0
  18. package/dist/extractors/eslint/index.test.d.ts.map +1 -0
  19. package/dist/extractors/eslint/index.test.js +191 -0
  20. package/dist/extractors/eslint/index.test.js.map +1 -0
  21. package/dist/extractors/generic/index.d.ts +30 -0
  22. package/dist/extractors/generic/index.d.ts.map +1 -0
  23. package/dist/extractors/generic/index.js +140 -0
  24. package/dist/extractors/generic/index.js.map +1 -0
  25. package/dist/extractors/generic/index.test.d.ts +7 -0
  26. package/dist/extractors/generic/index.test.d.ts.map +1 -0
  27. package/dist/extractors/generic/index.test.js +61 -0
  28. package/dist/extractors/generic/index.test.js.map +1 -0
  29. package/dist/extractors/jasmine/index.d.ts +17 -0
  30. package/dist/extractors/jasmine/index.d.ts.map +1 -0
  31. package/dist/extractors/jasmine/index.js +242 -0
  32. package/dist/extractors/jasmine/index.js.map +1 -0
  33. package/dist/extractors/jasmine/index.test.d.ts +7 -0
  34. package/dist/extractors/jasmine/index.test.d.ts.map +1 -0
  35. package/dist/extractors/jasmine/index.test.js +318 -0
  36. package/dist/extractors/jasmine/index.test.js.map +1 -0
  37. package/dist/extractors/jest/index.d.ts +17 -0
  38. package/dist/extractors/jest/index.d.ts.map +1 -0
  39. package/dist/extractors/jest/index.js +273 -0
  40. package/dist/extractors/jest/index.js.map +1 -0
  41. package/dist/extractors/jest/index.test.d.ts +9 -0
  42. package/dist/extractors/jest/index.test.d.ts.map +1 -0
  43. package/dist/extractors/jest/index.test.js +338 -0
  44. package/dist/extractors/jest/index.test.js.map +1 -0
  45. package/dist/extractors/junit/index.d.ts +18 -0
  46. package/dist/extractors/junit/index.d.ts.map +1 -0
  47. package/dist/extractors/junit/index.js +259 -0
  48. package/dist/extractors/junit/index.js.map +1 -0
  49. package/dist/extractors/junit/index.test.d.ts +7 -0
  50. package/dist/extractors/junit/index.test.d.ts.map +1 -0
  51. package/dist/extractors/junit/index.test.js +341 -0
  52. package/dist/extractors/junit/index.test.js.map +1 -0
  53. package/dist/extractors/maven-checkstyle/index.d.ts +23 -0
  54. package/dist/extractors/maven-checkstyle/index.d.ts.map +1 -0
  55. package/dist/extractors/maven-checkstyle/index.js +263 -0
  56. package/dist/extractors/maven-checkstyle/index.js.map +1 -0
  57. package/dist/extractors/maven-checkstyle/index.test.d.ts +2 -0
  58. package/dist/extractors/maven-checkstyle/index.test.d.ts.map +1 -0
  59. package/dist/extractors/maven-checkstyle/index.test.js +197 -0
  60. package/dist/extractors/maven-checkstyle/index.test.js.map +1 -0
  61. package/dist/extractors/maven-compiler/index.d.ts +23 -0
  62. package/dist/extractors/maven-compiler/index.d.ts.map +1 -0
  63. package/dist/extractors/maven-compiler/index.js +271 -0
  64. package/dist/extractors/maven-compiler/index.js.map +1 -0
  65. package/dist/extractors/maven-compiler/index.test.d.ts +2 -0
  66. package/dist/extractors/maven-compiler/index.test.d.ts.map +1 -0
  67. package/dist/extractors/maven-compiler/index.test.js +189 -0
  68. package/dist/extractors/maven-compiler/index.test.js.map +1 -0
  69. package/dist/extractors/maven-surefire/index.d.ts +23 -0
  70. package/dist/extractors/maven-surefire/index.d.ts.map +1 -0
  71. package/dist/extractors/maven-surefire/index.js +292 -0
  72. package/dist/extractors/maven-surefire/index.js.map +1 -0
  73. package/dist/extractors/maven-surefire/index.test.d.ts +2 -0
  74. package/dist/extractors/maven-surefire/index.test.d.ts.map +1 -0
  75. package/dist/extractors/maven-surefire/index.test.js +163 -0
  76. package/dist/extractors/maven-surefire/index.test.js.map +1 -0
  77. package/dist/extractors/mocha/index.d.ts +17 -0
  78. package/dist/extractors/mocha/index.d.ts.map +1 -0
  79. package/dist/extractors/mocha/index.js +241 -0
  80. package/dist/extractors/mocha/index.js.map +1 -0
  81. package/dist/extractors/mocha/index.test.d.ts +7 -0
  82. package/dist/extractors/mocha/index.test.d.ts.map +1 -0
  83. package/dist/extractors/mocha/index.test.js +300 -0
  84. package/dist/extractors/mocha/index.test.js.map +1 -0
  85. package/dist/extractors/playwright/index.d.ts +17 -0
  86. package/dist/extractors/playwright/index.d.ts.map +1 -0
  87. package/dist/extractors/playwright/index.js +320 -0
  88. package/dist/extractors/playwright/index.js.map +1 -0
  89. package/dist/extractors/playwright/index.test.d.ts +7 -0
  90. package/dist/extractors/playwright/index.test.d.ts.map +1 -0
  91. package/dist/extractors/playwright/index.test.js +274 -0
  92. package/dist/extractors/playwright/index.test.js.map +1 -0
  93. package/dist/extractors/tap/index.d.ts +23 -0
  94. package/dist/extractors/tap/index.d.ts.map +1 -0
  95. package/dist/extractors/tap/index.js +352 -0
  96. package/dist/extractors/tap/index.js.map +1 -0
  97. package/dist/extractors/tap/index.test.d.ts +7 -0
  98. package/dist/extractors/tap/index.test.d.ts.map +1 -0
  99. package/dist/extractors/tap/index.test.js +100 -0
  100. package/dist/extractors/tap/index.test.js.map +1 -0
  101. package/dist/extractors/typescript/index.d.ts +17 -0
  102. package/dist/extractors/typescript/index.d.ts.map +1 -0
  103. package/dist/extractors/typescript/index.js +150 -0
  104. package/dist/extractors/typescript/index.js.map +1 -0
  105. package/dist/extractors/typescript/index.test.d.ts +9 -0
  106. package/dist/extractors/typescript/index.test.d.ts.map +1 -0
  107. package/dist/extractors/typescript/index.test.js +177 -0
  108. package/dist/extractors/typescript/index.test.js.map +1 -0
  109. package/dist/extractors/vitest/index.d.ts +17 -0
  110. package/dist/extractors/vitest/index.d.ts.map +1 -0
  111. package/dist/extractors/vitest/index.js +564 -0
  112. package/dist/extractors/vitest/index.js.map +1 -0
  113. package/dist/extractors/vitest/index.test.d.ts +9 -0
  114. package/dist/extractors/vitest/index.test.d.ts.map +1 -0
  115. package/dist/extractors/vitest/index.test.js +373 -0
  116. package/dist/extractors/vitest/index.test.js.map +1 -0
  117. package/dist/index.d.ts +27 -13
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +27 -13
  120. package/dist/index.js.map +1 -1
  121. package/dist/maven-checkstyle-extractor.d.ts.map +1 -1
  122. package/dist/maven-checkstyle-extractor.js +2 -17
  123. package/dist/maven-checkstyle-extractor.js.map +1 -1
  124. package/dist/maven-compiler-extractor.d.ts +20 -0
  125. package/dist/maven-compiler-extractor.d.ts.map +1 -0
  126. package/dist/maven-compiler-extractor.js +218 -0
  127. package/dist/maven-compiler-extractor.js.map +1 -0
  128. package/dist/maven-utils.d.ts +24 -0
  129. package/dist/maven-utils.d.ts.map +1 -0
  130. package/dist/maven-utils.js +36 -0
  131. package/dist/maven-utils.js.map +1 -0
  132. package/dist/plugin-loader.d.ts +82 -0
  133. package/dist/plugin-loader.d.ts.map +1 -0
  134. package/dist/plugin-loader.js +200 -0
  135. package/dist/plugin-loader.js.map +1 -0
  136. package/dist/sandbox.d.ts +161 -0
  137. package/dist/sandbox.d.ts.map +1 -0
  138. package/dist/sandbox.js +254 -0
  139. package/dist/sandbox.js.map +1 -0
  140. package/dist/sandbox.test.d.ts +8 -0
  141. package/dist/sandbox.test.d.ts.map +1 -0
  142. package/dist/sandbox.test.js +395 -0
  143. package/dist/sandbox.test.js.map +1 -0
  144. package/dist/sandboxed-extractor.d.ts +51 -0
  145. package/dist/sandboxed-extractor.d.ts.map +1 -0
  146. package/dist/sandboxed-extractor.js +172 -0
  147. package/dist/sandboxed-extractor.js.map +1 -0
  148. package/dist/sandboxed-extractor.test.d.ts +5 -0
  149. package/dist/sandboxed-extractor.test.d.ts.map +1 -0
  150. package/dist/sandboxed-extractor.test.js +346 -0
  151. package/dist/sandboxed-extractor.test.js.map +1 -0
  152. package/dist/smart-extractor.d.ts +22 -10
  153. package/dist/smart-extractor.d.ts.map +1 -1
  154. package/dist/smart-extractor.js +116 -186
  155. package/dist/smart-extractor.js.map +1 -1
  156. package/dist/types.d.ts +94 -0
  157. package/dist/types.d.ts.map +1 -1
  158. package/package.json +2 -1
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Sandbox Module for Secure Extractor Execution
3
+ *
4
+ * Uses isolated-vm to run extractor plugins in a secure V8 Isolate.
5
+ * This provides true security isolation by preventing access to Node.js APIs
6
+ * and limiting memory/CPU usage.
7
+ *
8
+ * @see docs/sandbox-research.md for detailed architecture and security model
9
+ */
10
+ import type { FormattedError } from './types.js';
11
+ export interface SandboxOptions {
12
+ /**
13
+ * Memory limit in MB (default: 128)
14
+ * Prevents memory exhaustion attacks
15
+ */
16
+ memoryLimitMB?: number;
17
+ /**
18
+ * Execution timeout in milliseconds (default: 5000)
19
+ * Prevents infinite loop attacks
20
+ */
21
+ timeoutMs?: number;
22
+ /**
23
+ * Extractor function code to execute
24
+ * Must define a function named 'extract' that takes string input
25
+ */
26
+ code: string;
27
+ /**
28
+ * Input data to pass to the extractor
29
+ * This is the command output to parse for errors
30
+ */
31
+ input: string;
32
+ /**
33
+ * Extractor name for debugging/logging
34
+ */
35
+ extractorName: string;
36
+ }
37
+ export interface SandboxResult {
38
+ /**
39
+ * Whether execution succeeded without errors
40
+ */
41
+ success: boolean;
42
+ /**
43
+ * Extracted errors if successful
44
+ */
45
+ errors?: FormattedError[];
46
+ /**
47
+ * Error message if execution failed
48
+ */
49
+ error?: string;
50
+ /**
51
+ * Execution statistics
52
+ */
53
+ stats: {
54
+ /**
55
+ * Execution duration in milliseconds
56
+ */
57
+ durationMs: number;
58
+ /**
59
+ * Peak memory usage in MB
60
+ */
61
+ memoryUsedMB: number;
62
+ };
63
+ }
64
+ /**
65
+ * Error thrown when sandbox execution fails
66
+ */
67
+ export declare class SandboxExecutionError extends Error {
68
+ readonly extractorName: string;
69
+ readonly _cause?: unknown | undefined;
70
+ constructor(message: string, extractorName: string, _cause?: unknown | undefined);
71
+ }
72
+ /**
73
+ * Run extractor code in a secure V8 Isolate
74
+ *
75
+ * Security features:
76
+ * - Isolated V8 heap (no access to Node.js globals)
77
+ * - Memory limit enforcement
78
+ * - Execution timeout protection
79
+ * - No filesystem, network, or process access
80
+ *
81
+ * @param options - Sandbox configuration
82
+ * @returns Result containing extracted errors or error details
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const result = await runInSandbox({
87
+ * code: 'function extract(input) { return []; }',
88
+ * input: 'error output',
89
+ * extractorName: 'test-extractor'
90
+ * });
91
+ *
92
+ * if (result.success) {
93
+ * console.log('Extracted errors:', result.errors);
94
+ * } else {
95
+ * console.error('Execution failed:', result.error);
96
+ * }
97
+ * ```
98
+ */
99
+ export declare function runInSandbox(options: SandboxOptions): Promise<SandboxResult>;
100
+ /**
101
+ * Create sandboxed code from an extractor function
102
+ *
103
+ * Converts a regular function to a string that can be executed in the sandbox.
104
+ * The function must:
105
+ * - Be named 'extract'
106
+ * - Take a single string parameter
107
+ * - Return ExtractedError[]
108
+ *
109
+ * @param extractFn - The extractor function to sandbox
110
+ * @returns Sandboxed code string
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * function extract(content: string): ExtractedError[] {
115
+ * const errors = [];
116
+ * const pattern = /ERROR: (.+)/g;
117
+ * let match;
118
+ * while ((match = pattern.exec(content)) !== null) {
119
+ * errors.push({ message: match[1], severity: 'error' });
120
+ * }
121
+ * return errors;
122
+ * }
123
+ *
124
+ * const code = createSandboxedCode(extract);
125
+ * // code is now a string that can be passed to runInSandbox
126
+ * ```
127
+ */
128
+ export declare function createSandboxedCode(extractFn: (_content: string) => FormattedError[]): string;
129
+ /**
130
+ * Performance statistics for sandbox operations
131
+ * Used for monitoring and optimization
132
+ */
133
+ export interface SandboxStats {
134
+ totalExecutions: number;
135
+ successfulExecutions: number;
136
+ failedExecutions: number;
137
+ averageDurationMs: number;
138
+ averageMemoryUsedMB: number;
139
+ }
140
+ /**
141
+ * Sandbox performance tracker
142
+ * Collects statistics across multiple executions
143
+ */
144
+ export declare class SandboxStatsCollector {
145
+ private stats;
146
+ private totalDurationMs;
147
+ private totalMemoryUsedMB;
148
+ /**
149
+ * Record a sandbox execution result
150
+ */
151
+ record(result: SandboxResult): void;
152
+ /**
153
+ * Get current statistics
154
+ */
155
+ getStats(): Readonly<SandboxStats>;
156
+ /**
157
+ * Reset statistics
158
+ */
159
+ reset(): void;
160
+ }
161
+ //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAsBjD,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAE1B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,KAAK,EAAE;QACL;;WAEG;QACH,UAAU,EAAE,MAAM,CAAC;QAEnB;;WAEG;QACH,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAG5B,aAAa,EAAE,MAAM;aACrB,MAAM,CAAC,EAAE,OAAO;gBAFhC,OAAO,EAAE,MAAM,EACC,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,OAAO,YAAA;CAKnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAmGxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,cAAc,EAAE,GAChD,MAAM,CAuBR;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,KAAK,CAMX;IAEF,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,iBAAiB,CAAK;IAE9B;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAmBnC;;OAEG;IACH,QAAQ,IAAI,QAAQ,CAAC,YAAY,CAAC;IAIlC;;OAEG;IACH,KAAK,IAAI,IAAI;CAWd"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Sandbox Module for Secure Extractor Execution
3
+ *
4
+ * Uses isolated-vm to run extractor plugins in a secure V8 Isolate.
5
+ * This provides true security isolation by preventing access to Node.js APIs
6
+ * and limiting memory/CPU usage.
7
+ *
8
+ * @see docs/sandbox-research.md for detailed architecture and security model
9
+ */
10
+ // Lazy-load isolated-vm (CommonJS module)
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- isolated-vm has no types
12
+ let ivm;
13
+ async function getIVM() {
14
+ if (!ivm) {
15
+ try {
16
+ // isolated-vm is CommonJS, use dynamic import and createRequire
17
+ const { createRequire } = await import('node:module');
18
+ const require = createRequire(import.meta.url);
19
+ ivm = require('isolated-vm');
20
+ }
21
+ catch {
22
+ // If isolated-vm is not installed, throw helpful error
23
+ throw new Error('isolated-vm is required for sandbox execution. Install with: pnpm add isolated-vm');
24
+ }
25
+ }
26
+ return ivm;
27
+ }
28
+ /**
29
+ * Error thrown when sandbox execution fails
30
+ */
31
+ export class SandboxExecutionError extends Error {
32
+ extractorName;
33
+ _cause;
34
+ constructor(message, extractorName, _cause) {
35
+ super(`Sandbox execution failed for ${extractorName}: ${message}`);
36
+ this.extractorName = extractorName;
37
+ this._cause = _cause;
38
+ this.name = 'SandboxExecutionError';
39
+ }
40
+ }
41
+ /**
42
+ * Run extractor code in a secure V8 Isolate
43
+ *
44
+ * Security features:
45
+ * - Isolated V8 heap (no access to Node.js globals)
46
+ * - Memory limit enforcement
47
+ * - Execution timeout protection
48
+ * - No filesystem, network, or process access
49
+ *
50
+ * @param options - Sandbox configuration
51
+ * @returns Result containing extracted errors or error details
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const result = await runInSandbox({
56
+ * code: 'function extract(input) { return []; }',
57
+ * input: 'error output',
58
+ * extractorName: 'test-extractor'
59
+ * });
60
+ *
61
+ * if (result.success) {
62
+ * console.log('Extracted errors:', result.errors);
63
+ * } else {
64
+ * console.error('Execution failed:', result.error);
65
+ * }
66
+ * ```
67
+ */
68
+ export async function runInSandbox(options) {
69
+ const startTime = performance.now();
70
+ const ivm = await getIVM();
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- isolated-vm has no types
72
+ let isolate;
73
+ try {
74
+ // Create V8 Isolate with memory limit
75
+ isolate = new ivm.Isolate({
76
+ memoryLimit: options.memoryLimitMB ?? 128
77
+ });
78
+ const context = await isolate.createContext();
79
+ // Wrap extractor code to return JSON-serializable result
80
+ const wrappedCode = `
81
+ ${options.code}
82
+
83
+ function __executeExtractor(input) {
84
+ try {
85
+ const errors = extract(input);
86
+ return JSON.stringify({ success: true, errors });
87
+ } catch (error) {
88
+ return JSON.stringify({
89
+ success: false,
90
+ error: error instanceof Error ? error.message : String(error)
91
+ });
92
+ }
93
+ }
94
+ `;
95
+ // Compile code (cached by V8)
96
+ const script = await isolate.compileScript(wrappedCode);
97
+ await script.run(context);
98
+ // Transfer input to isolate (copy, don't share reference)
99
+ const inputCopy = new ivm.ExternalCopy(options.input);
100
+ await context.global.set('input', inputCopy.copyInto());
101
+ // Execute with timeout
102
+ const resultJson = await context.eval('__executeExtractor(input)', {
103
+ timeout: options.timeoutMs ?? 5000,
104
+ promise: true
105
+ });
106
+ const result = JSON.parse(resultJson);
107
+ // Get memory stats before disposal
108
+ const heapStats = isolate.getHeapStatisticsSync();
109
+ const memoryUsedMB = heapStats.used_heap_size / 1024 / 1024;
110
+ isolate.dispose();
111
+ const durationMs = performance.now() - startTime;
112
+ if (!result.success) {
113
+ return {
114
+ success: false,
115
+ error: result.error,
116
+ stats: {
117
+ durationMs,
118
+ memoryUsedMB
119
+ }
120
+ };
121
+ }
122
+ return {
123
+ success: true,
124
+ errors: result.errors ?? [],
125
+ stats: {
126
+ durationMs,
127
+ memoryUsedMB
128
+ }
129
+ };
130
+ }
131
+ catch (error) {
132
+ // Clean up isolate on error
133
+ if (isolate) {
134
+ try {
135
+ isolate.dispose();
136
+ }
137
+ catch {
138
+ // Ignore disposal errors
139
+ }
140
+ }
141
+ const durationMs = performance.now() - startTime;
142
+ return {
143
+ success: false,
144
+ error: error instanceof Error ? error.message : String(error),
145
+ stats: {
146
+ durationMs,
147
+ memoryUsedMB: 0
148
+ }
149
+ };
150
+ }
151
+ }
152
+ /**
153
+ * Create sandboxed code from an extractor function
154
+ *
155
+ * Converts a regular function to a string that can be executed in the sandbox.
156
+ * The function must:
157
+ * - Be named 'extract'
158
+ * - Take a single string parameter
159
+ * - Return ExtractedError[]
160
+ *
161
+ * @param extractFn - The extractor function to sandbox
162
+ * @returns Sandboxed code string
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * function extract(content: string): ExtractedError[] {
167
+ * const errors = [];
168
+ * const pattern = /ERROR: (.+)/g;
169
+ * let match;
170
+ * while ((match = pattern.exec(content)) !== null) {
171
+ * errors.push({ message: match[1], severity: 'error' });
172
+ * }
173
+ * return errors;
174
+ * }
175
+ *
176
+ * const code = createSandboxedCode(extract);
177
+ * // code is now a string that can be passed to runInSandbox
178
+ * ```
179
+ */
180
+ export function createSandboxedCode(extractFn) {
181
+ // Convert function to string and rename to 'extract' if needed
182
+ const fnString = extractFn.toString();
183
+ // Check if function is already named 'extract'
184
+ if (fnString.startsWith('function extract(')) {
185
+ return fnString;
186
+ }
187
+ // Anonymous or arrow function - wrap it
188
+ if (fnString.startsWith('(') || fnString.includes('=>')) {
189
+ return `function extract(content) { return (${fnString})(content); }`;
190
+ }
191
+ // Named function - extract body and create 'extract' wrapper
192
+ const functionPattern = /function\s+\w+\s*\([^)]*\)\s*{([\s\S]*)}$/;
193
+ const bodyMatch = functionPattern.exec(fnString);
194
+ if (bodyMatch) {
195
+ return `function extract(content) { ${bodyMatch[1]} }`;
196
+ }
197
+ // Fallback - assume it's valid code
198
+ return fnString;
199
+ }
200
+ /**
201
+ * Sandbox performance tracker
202
+ * Collects statistics across multiple executions
203
+ */
204
+ export class SandboxStatsCollector {
205
+ stats = {
206
+ totalExecutions: 0,
207
+ successfulExecutions: 0,
208
+ failedExecutions: 0,
209
+ averageDurationMs: 0,
210
+ averageMemoryUsedMB: 0
211
+ };
212
+ totalDurationMs = 0;
213
+ totalMemoryUsedMB = 0;
214
+ /**
215
+ * Record a sandbox execution result
216
+ */
217
+ record(result) {
218
+ this.stats.totalExecutions++;
219
+ if (result.success) {
220
+ this.stats.successfulExecutions++;
221
+ }
222
+ else {
223
+ this.stats.failedExecutions++;
224
+ }
225
+ this.totalDurationMs += result.stats.durationMs;
226
+ this.totalMemoryUsedMB += result.stats.memoryUsedMB;
227
+ // Update averages
228
+ this.stats.averageDurationMs =
229
+ this.totalDurationMs / this.stats.totalExecutions;
230
+ this.stats.averageMemoryUsedMB =
231
+ this.totalMemoryUsedMB / this.stats.totalExecutions;
232
+ }
233
+ /**
234
+ * Get current statistics
235
+ */
236
+ getStats() {
237
+ return { ...this.stats };
238
+ }
239
+ /**
240
+ * Reset statistics
241
+ */
242
+ reset() {
243
+ this.stats = {
244
+ totalExecutions: 0,
245
+ successfulExecutions: 0,
246
+ failedExecutions: 0,
247
+ averageDurationMs: 0,
248
+ averageMemoryUsedMB: 0
249
+ };
250
+ this.totalDurationMs = 0;
251
+ this.totalMemoryUsedMB = 0;
252
+ }
253
+ }
254
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sandbox Module Tests
3
+ *
4
+ * Tests secure extractor execution using isolated-vm.
5
+ * These tests validate the sandbox can execute real extractor code safely.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=sandbox.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.test.d.ts","sourceRoot":"","sources":["../src/sandbox.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}