@n8n/expression-runtime 0.2.0 → 0.3.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 (77) hide show
  1. package/ARCHITECTURE.md +5 -6
  2. package/LICENSE_EE.md +27 -0
  3. package/README.md +8 -8
  4. package/dist/bridge/isolated-vm-bridge.d.ts +132 -0
  5. package/dist/bridge/isolated-vm-bridge.d.ts.map +1 -0
  6. package/dist/bridge/isolated-vm-bridge.js +427 -0
  7. package/dist/bridge/isolated-vm-bridge.js.map +1 -0
  8. package/dist/build.tsbuildinfo +1 -1
  9. package/dist/bundle/runtime.esm.js +45 -0
  10. package/dist/bundle/runtime.esm.js.map +7 -0
  11. package/dist/bundle/runtime.iife.js +45 -0
  12. package/dist/bundle/runtime.iife.js.map +7 -0
  13. package/dist/extensions/array-extensions.d.ts +34 -0
  14. package/dist/extensions/array-extensions.d.ts.map +1 -0
  15. package/dist/extensions/array-extensions.js +610 -0
  16. package/dist/extensions/array-extensions.js.map +1 -0
  17. package/dist/extensions/boolean-extensions.d.ts +6 -0
  18. package/dist/extensions/boolean-extensions.d.ts.map +1 -0
  19. package/dist/extensions/boolean-extensions.js +33 -0
  20. package/dist/extensions/boolean-extensions.js.map +1 -0
  21. package/dist/extensions/date-extensions.d.ts +3 -0
  22. package/dist/extensions/date-extensions.d.ts.map +1 -0
  23. package/dist/extensions/date-extensions.js +515 -0
  24. package/dist/extensions/date-extensions.js.map +1 -0
  25. package/dist/extensions/expression-extension-error.d.ts +7 -0
  26. package/dist/extensions/expression-extension-error.d.ts.map +1 -0
  27. package/dist/extensions/expression-extension-error.js +11 -0
  28. package/dist/extensions/expression-extension-error.js.map +1 -0
  29. package/dist/extensions/extend.d.ts +12 -0
  30. package/dist/extensions/extend.d.ts.map +1 -0
  31. package/dist/extensions/extend.js +134 -0
  32. package/dist/extensions/extend.js.map +1 -0
  33. package/dist/extensions/extensions.d.ts +43 -0
  34. package/dist/extensions/extensions.d.ts.map +1 -0
  35. package/dist/extensions/extensions.js +2 -0
  36. package/dist/extensions/extensions.js.map +1 -0
  37. package/dist/extensions/number-extensions.d.ts +27 -0
  38. package/dist/extensions/number-extensions.d.ts.map +1 -0
  39. package/dist/extensions/number-extensions.js +221 -0
  40. package/dist/extensions/number-extensions.js.map +1 -0
  41. package/dist/extensions/object-extensions.d.ts +46 -0
  42. package/dist/extensions/object-extensions.d.ts.map +1 -0
  43. package/dist/extensions/object-extensions.js +277 -0
  44. package/dist/extensions/object-extensions.js.map +1 -0
  45. package/dist/extensions/string-extensions.d.ts +38 -0
  46. package/dist/extensions/string-extensions.d.ts.map +1 -0
  47. package/dist/extensions/string-extensions.js +735 -0
  48. package/dist/extensions/string-extensions.js.map +1 -0
  49. package/dist/extensions/utils.d.ts +4 -0
  50. package/dist/extensions/utils.d.ts.map +1 -0
  51. package/dist/extensions/utils.js +27 -0
  52. package/dist/extensions/utils.js.map +1 -0
  53. package/dist/runtime/index.d.ts +17 -0
  54. package/dist/runtime/index.d.ts.map +1 -0
  55. package/dist/runtime/index.js +23 -0
  56. package/dist/runtime/index.js.map +1 -0
  57. package/dist/runtime/lazy-proxy.d.ts +18 -0
  58. package/dist/runtime/lazy-proxy.d.ts.map +1 -0
  59. package/dist/runtime/lazy-proxy.js +150 -0
  60. package/dist/runtime/lazy-proxy.js.map +1 -0
  61. package/dist/runtime/reset.d.ts +16 -0
  62. package/dist/runtime/reset.d.ts.map +1 -0
  63. package/dist/runtime/reset.js +124 -0
  64. package/dist/runtime/reset.js.map +1 -0
  65. package/dist/runtime/safe-globals.d.ts +21 -0
  66. package/dist/runtime/safe-globals.d.ts.map +1 -0
  67. package/dist/runtime/safe-globals.js +110 -0
  68. package/dist/runtime/safe-globals.js.map +1 -0
  69. package/dist/types/index.d.ts +0 -1
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/dist/types/index.js +1 -0
  72. package/dist/types/index.js.map +1 -1
  73. package/dist/types/runtime.d.ts +0 -102
  74. package/dist/types/runtime.d.ts.map +1 -1
  75. package/dist/types/runtime.js +0 -6
  76. package/dist/types/runtime.js.map +1 -1
  77. package/package.json +15 -3
package/ARCHITECTURE.md CHANGED
@@ -306,7 +306,7 @@ packages/@n8n/expression-runtime/
306
306
 
307
307
  **Future-Proofing**: Frontend will use Web Workers. Backend uses isolated-vm. Abstract bridge allows adding new environments without changing other layers.
308
308
 
309
- **Testing**: NodeVmBridge allows fast testing without native isolated-vm dependency.
309
+ **Testing**: Integration tests use `IsolatedVmBridge` directly (see `src/__tests__/integration.test.ts`).
310
310
 
311
311
  ## Known Limitations
312
312
 
@@ -361,16 +361,15 @@ The runtime has **no access** to:
361
361
  - ❌ Cookies
362
362
 
363
363
  The runtime **can only**:
364
- - ✅ Call `getDataSync()` to fetch workflow data
364
+ - ✅ Call back to host via `ivm.Reference` callbacks to fetch workflow data
365
365
  - ✅ Access lodash and Luxon libraries
366
366
  - ✅ Execute pure JavaScript code
367
367
 
368
368
  ## Testing Strategy
369
369
 
370
- **Runtime Tests** (vitest):
371
- - Use NodeVmBridge for fast, isolated tests
372
- - Test lazy loading, helpers, error handling
373
- - No native dependencies required
370
+ **Integration Tests** (vitest):
371
+ - Use `IsolatedVmBridge` with real `isolated-vm`
372
+ - Test lazy loading, helpers, error handling, security wrappers
374
373
 
375
374
  **Bridge Tests** (vitest):
376
375
  - Test each bridge implementation
package/LICENSE_EE.md ADDED
@@ -0,0 +1,27 @@
1
+ # The n8n Enterprise License (the “Enterprise License”)
2
+
3
+ Copyright (c) 2022-present n8n GmbH.
4
+
5
+ With regard to the n8n Software:
6
+
7
+ This software and associated documentation files (the "Software") may only be used in production, if
8
+ you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
9
+ usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
10
+ to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
11
+ interest in and to all such modifications and/or patches, and all such modifications and/or patches
12
+ may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
13
+ Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
14
+ modify the Software for development and testing purposes, without requiring a subscription. You
15
+ agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
16
+ all such modifications. You are not granted any other rights beyond what is expressly stated herein.
17
+ Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
18
+ sell the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
21
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
23
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ For all third party components incorporated into the n8n Software, those components are licensed
27
+ under the original license provided by the owner of the applicable component.
package/README.md CHANGED
@@ -7,12 +7,12 @@ Secure, isolated expression evaluation runtime for n8n workflows.
7
7
  **In progress — landing as a series of incremental PRs.**
8
8
 
9
9
  Implemented so far:
10
- - ✅ TypeScript interfaces and architecture design
11
- - ✅ Core architecture documentation
10
+ - ✅ TypeScript interfaces and architecture design (PR 1)
11
+ - ✅ Core architecture documentation (PR 1)
12
+ - ✅ Runtime bundle: extension functions, deep lazy proxy system (PR 2)
13
+ - ✅ `IsolatedVmBridge`: V8 isolate management via `isolated-vm` (PR 3)
12
14
 
13
15
  Coming in later PRs:
14
- - 🚧 Runtime bundle: extension functions, deep lazy proxy system (PR 2)
15
- - 🚧 `IsolatedVmBridge`: V8 isolate management via `isolated-vm` (PR 3)
16
16
  - 🚧 `ExpressionEvaluator`: tournament integration, expression code caching (PR 4)
17
17
  - 🚧 Integration tests (PR 4)
18
18
  - 🚧 Workflow integration behind `N8N_EXPRESSION_ENGINE=vm` flag (PR 5)
@@ -165,7 +165,7 @@ interface RuntimeBridge {
165
165
 
166
166
  ### Bridge Implementations
167
167
 
168
- - **IsolatedVmBridge**: 🚧 For Node.js backend (isolated-vm with V8 isolates) - coming in PR 3
168
+ - **IsolatedVmBridge**: For Node.js backend (isolated-vm with V8 isolates)
169
169
  - Memory isolation with hard 128MB limit
170
170
  - Timeout enforcement (5s default)
171
171
  - Deep lazy proxy system for workflow data
@@ -185,9 +185,9 @@ interface EvaluatorConfig {
185
185
  }
186
186
 
187
187
  interface BridgeConfig {
188
- memoryLimit?: number; // Default: 128 MB (PR 3)
189
- timeout?: number; // Default: 5000 ms (PR 3)
190
- debug?: boolean; // Default: false (PR 3)
188
+ memoryLimit?: number; // Default: 128 MB
189
+ timeout?: number; // Default: 5000 ms
190
+ debug?: boolean; // Default: false
191
191
  }
192
192
  ```
193
193
 
@@ -0,0 +1,132 @@
1
+ import type { RuntimeBridge, BridgeConfig } from '../types';
2
+ /**
3
+ * IsolatedVmBridge - Runtime bridge using isolated-vm for secure expression evaluation.
4
+ *
5
+ * This bridge creates a V8 isolate with:
6
+ * - Hard memory limit (128MB default)
7
+ * - No access to Node.js APIs
8
+ * - Timeout enforcement
9
+ * - Complete isolation from host process
10
+ *
11
+ * Context reuse pattern: Create isolate/context once, reset state between evaluations.
12
+ */
13
+ export declare class IsolatedVmBridge implements RuntimeBridge {
14
+ private isolate;
15
+ private context?;
16
+ private initialized;
17
+ private disposed;
18
+ private config;
19
+ private scriptCache;
20
+ private valueAtPathRef?;
21
+ private arrayElementRef?;
22
+ private callFunctionRef?;
23
+ constructor(config?: BridgeConfig);
24
+ /**
25
+ * Initialize the isolate and create execution context.
26
+ *
27
+ * Steps:
28
+ * 1. Create context
29
+ * 2. Set up basic globals (global reference)
30
+ * 3. Load runtime bundle (DateTime, extend, proxy system)
31
+ * 4. Verify proxy system
32
+ *
33
+ * Must be called before execute().
34
+ */
35
+ initialize(): Promise<void>;
36
+ /**
37
+ * Load runtime bundle into the isolate.
38
+ *
39
+ * The runtime bundle includes:
40
+ * - DateTime, extend, extendOptional (expression engine globals)
41
+ * - SafeObject and SafeError wrappers
42
+ * - createDeepLazyProxy function
43
+ * - __data object initialization
44
+ *
45
+ * @private
46
+ * @throws {Error} If context not initialized or bundle loading fails
47
+ */
48
+ private loadVendorLibraries;
49
+ /**
50
+ * Verify the proxy system loaded correctly.
51
+ *
52
+ * The proxy system is loaded as part of the runtime bundle in loadVendorLibraries().
53
+ * This method verifies all required components are available.
54
+ *
55
+ * @private
56
+ * @throws {Error} If context not initialized or proxy system verification fails
57
+ */
58
+ private verifyProxySystem;
59
+ /**
60
+ * Inject the E() error handler into the isolate context.
61
+ *
62
+ * Tournament wraps expressions with try-catch that calls E(error, this).
63
+ * This handler:
64
+ * - Re-throws security violations from __sanitize
65
+ * - Swallows TypeErrors (failed attack attempts return undefined)
66
+ * - Re-throws all other errors
67
+ *
68
+ * @private
69
+ * @throws {Error} If context not initialized
70
+ */
71
+ private injectErrorHandler;
72
+ /**
73
+ * Reset data proxies in the isolate context.
74
+ *
75
+ * This method should be called before each execute() to:
76
+ * 1. Clear proxy caches from previous evaluations
77
+ * 2. Initialize fresh workflow data references
78
+ * 3. Expose workflow properties to globalThis
79
+ *
80
+ * The reset function runs in the isolate and calls back to the host
81
+ * via ivm.Reference callbacks to fetch workflow data.
82
+ *
83
+ * @private
84
+ * @throws {Error} If context not initialized or reset fails
85
+ */
86
+ private resetDataProxies;
87
+ /**
88
+ * Register callback functions for cross-isolate communication.
89
+ *
90
+ * Creates three ivm.Reference callbacks that the runtime bundle uses
91
+ * to fetch data from the host process:
92
+ *
93
+ * - __getValueAtPath: Returns metadata or primitive for a property path
94
+ * - __getArrayElement: Returns individual array elements
95
+ * - __callFunctionAtPath: Executes functions in host context
96
+ *
97
+ * These callbacks are called synchronously from isolate proxy traps.
98
+ *
99
+ * @param data - Current workflow data to use for callback responses
100
+ * @private
101
+ */
102
+ private registerCallbacks;
103
+ /**
104
+ * Execute JavaScript code in the isolated context.
105
+ *
106
+ * Flow:
107
+ * 1. Register callbacks as ivm.Reference for cross-isolate communication
108
+ * 2. Call resetDataProxies() to initialize workflow data proxies
109
+ * 3. Compile script (with caching for performance)
110
+ * 4. Execute with timeout enforcement
111
+ * 5. Return result (copied from isolate)
112
+ *
113
+ * @param code - JavaScript expression to evaluate
114
+ * @param data - Workflow data (e.g., { $json: {...}, $runIndex: 0 })
115
+ * @returns Result of the expression
116
+ * @throws {Error} If bridge not initialized or execution fails
117
+ */
118
+ execute(code: string, data: Record<string, unknown>): unknown;
119
+ /**
120
+ * Dispose of the isolate and free resources.
121
+ *
122
+ * After disposal, the bridge cannot be used again.
123
+ */
124
+ dispose(): Promise<void>;
125
+ /**
126
+ * Check if the bridge has been disposed.
127
+ *
128
+ * @returns true if disposed, false otherwise
129
+ */
130
+ isDisposed(): boolean;
131
+ }
132
+ //# sourceMappingURL=isolated-vm-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolated-vm-bridge.d.ts","sourceRoot":"","sources":["../../src/bridge/isolated-vm-bridge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAM5D;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,aAAa;IACrD,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAyB;IAIvC,OAAO,CAAC,WAAW,CAAiC;IAIpD,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAgB;gBAE5B,MAAM,GAAE,YAAiB;IAYrC;;;;;;;;;;OAUG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCjC;;;;;;;;;;;OAWG;YACW,mBAAmB;IAsCjC;;;;;;;;OAQG;YACW,iBAAiB;IA+B/B;;;;;;;;;;;OAWG;YACW,kBAAkB;IA0BhC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IA8HzB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IA6C7D;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B;;;;OAIG;IACH,UAAU,IAAI,OAAO;CAGrB"}
@@ -0,0 +1,427 @@
1
+ import ivm from 'isolated-vm';
2
+ import { readFile } from 'node:fs/promises';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ // Get __dirname equivalent for ES modules
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ /**
9
+ * IsolatedVmBridge - Runtime bridge using isolated-vm for secure expression evaluation.
10
+ *
11
+ * This bridge creates a V8 isolate with:
12
+ * - Hard memory limit (128MB default)
13
+ * - No access to Node.js APIs
14
+ * - Timeout enforcement
15
+ * - Complete isolation from host process
16
+ *
17
+ * Context reuse pattern: Create isolate/context once, reset state between evaluations.
18
+ */
19
+ export class IsolatedVmBridge {
20
+ isolate;
21
+ context;
22
+ initialized = false;
23
+ disposed = false;
24
+ config;
25
+ // Script compilation cache for performance
26
+ // Maps expression code -> compiled ivm.Script
27
+ scriptCache = new Map();
28
+ // Active ivm.Reference callbacks — released before each re-registration
29
+ // to prevent reference accumulation across execute() calls
30
+ valueAtPathRef;
31
+ arrayElementRef;
32
+ callFunctionRef;
33
+ constructor(config = {}) {
34
+ this.config = {
35
+ memoryLimit: config.memoryLimit ?? 128,
36
+ timeout: config.timeout ?? 5000,
37
+ debug: config.debug ?? false,
38
+ };
39
+ // Create isolate with memory limit
40
+ // Note: memoryLimit is in MB
41
+ this.isolate = new ivm.Isolate({ memoryLimit: this.config.memoryLimit });
42
+ }
43
+ /**
44
+ * Initialize the isolate and create execution context.
45
+ *
46
+ * Steps:
47
+ * 1. Create context
48
+ * 2. Set up basic globals (global reference)
49
+ * 3. Load runtime bundle (DateTime, extend, proxy system)
50
+ * 4. Verify proxy system
51
+ *
52
+ * Must be called before execute().
53
+ */
54
+ async initialize() {
55
+ if (this.initialized) {
56
+ return;
57
+ }
58
+ // Create context in the isolate
59
+ this.context = await this.isolate.createContext();
60
+ // Set up basic globals
61
+ // jail is a reference to the context's global object
62
+ const jail = this.context.global;
63
+ // Set 'global' to reference itself (pattern from POC)
64
+ // This allows code in isolate to access 'global.something'
65
+ await jail.set('global', jail.derefInto());
66
+ // Load runtime bundle (DateTime, extend, SafeObject, proxy system)
67
+ await this.loadVendorLibraries();
68
+ // Verify proxy system loaded correctly
69
+ await this.verifyProxySystem();
70
+ // Inject E() error handler needed by tournament-generated try-catch code
71
+ await this.injectErrorHandler();
72
+ this.initialized = true;
73
+ if (this.config.debug) {
74
+ console.log('[IsolatedVmBridge] Initialized successfully');
75
+ }
76
+ }
77
+ /**
78
+ * Load runtime bundle into the isolate.
79
+ *
80
+ * The runtime bundle includes:
81
+ * - DateTime, extend, extendOptional (expression engine globals)
82
+ * - SafeObject and SafeError wrappers
83
+ * - createDeepLazyProxy function
84
+ * - __data object initialization
85
+ *
86
+ * @private
87
+ * @throws {Error} If context not initialized or bundle loading fails
88
+ */
89
+ async loadVendorLibraries() {
90
+ if (!this.context) {
91
+ throw new Error('Context not initialized');
92
+ }
93
+ try {
94
+ // Load runtime bundle (includes vendor libraries + proxy system)
95
+ // Path: dist/bundle/runtime.iife.js
96
+ const runtimeBundlePath = path.join(__dirname, '../../dist/bundle/runtime.iife.js');
97
+ const runtimeBundle = await readFile(runtimeBundlePath, 'utf-8');
98
+ // Evaluate bundle in isolate context
99
+ // This makes all exported globals available (DateTime, extend, extendOptional, SafeObject, SafeError, createDeepLazyProxy, resetDataProxies, __data)
100
+ await this.context.eval(runtimeBundle);
101
+ if (this.config.debug) {
102
+ console.log('[IsolatedVmBridge] Runtime bundle loaded from:', runtimeBundlePath);
103
+ }
104
+ // Verify vendor libraries loaded correctly
105
+ const hasDateTime = await this.context.eval('typeof DateTime !== "undefined"');
106
+ const hasExtend = await this.context.eval('typeof extend !== "undefined"');
107
+ if (!hasDateTime || !hasExtend) {
108
+ throw new Error(`Library verification failed: DateTime=${hasDateTime}, extend=${hasExtend}`);
109
+ }
110
+ if (this.config.debug) {
111
+ console.log('[IsolatedVmBridge] Vendor libraries verified successfully');
112
+ }
113
+ }
114
+ catch (error) {
115
+ const errorMessage = error instanceof Error ? error.message : String(error);
116
+ throw new Error(`Failed to load runtime bundle: ${errorMessage}`);
117
+ }
118
+ }
119
+ /**
120
+ * Verify the proxy system loaded correctly.
121
+ *
122
+ * The proxy system is loaded as part of the runtime bundle in loadVendorLibraries().
123
+ * This method verifies all required components are available.
124
+ *
125
+ * @private
126
+ * @throws {Error} If context not initialized or proxy system verification fails
127
+ */
128
+ async verifyProxySystem() {
129
+ if (!this.context) {
130
+ throw new Error('Context not initialized');
131
+ }
132
+ try {
133
+ // Verify proxy system components loaded correctly
134
+ const hasProxyCreator = await this.context.eval('typeof createDeepLazyProxy !== "undefined"');
135
+ const hasData = await this.context.eval('typeof __data !== "undefined"');
136
+ const hasSafeObject = await this.context.eval('typeof SafeObject !== "undefined"');
137
+ const hasSafeError = await this.context.eval('typeof SafeError !== "undefined"');
138
+ const hasResetFunction = await this.context.eval('typeof resetDataProxies !== "undefined"');
139
+ if (!hasProxyCreator || !hasData || !hasSafeObject || !hasSafeError || !hasResetFunction) {
140
+ throw new Error(`Proxy system verification failed: ` +
141
+ `createDeepLazyProxy=${hasProxyCreator}, __data=${hasData}, ` +
142
+ `SafeObject=${hasSafeObject}, SafeError=${hasSafeError}, ` +
143
+ `resetDataProxies=${hasResetFunction}`);
144
+ }
145
+ if (this.config.debug) {
146
+ console.log('[IsolatedVmBridge] Proxy system verified successfully');
147
+ }
148
+ }
149
+ catch (error) {
150
+ const errorMessage = error instanceof Error ? error.message : String(error);
151
+ throw new Error(`Failed to verify proxy system: ${errorMessage}`);
152
+ }
153
+ }
154
+ /**
155
+ * Inject the E() error handler into the isolate context.
156
+ *
157
+ * Tournament wraps expressions with try-catch that calls E(error, this).
158
+ * This handler:
159
+ * - Re-throws security violations from __sanitize
160
+ * - Swallows TypeErrors (failed attack attempts return undefined)
161
+ * - Re-throws all other errors
162
+ *
163
+ * @private
164
+ * @throws {Error} If context not initialized
165
+ */
166
+ async injectErrorHandler() {
167
+ if (!this.context) {
168
+ throw new Error('Context not initialized');
169
+ }
170
+ await this.context.eval(`
171
+ if (typeof E === 'undefined') {
172
+ globalThis.E = function(error, _context) {
173
+ // Re-throw security violations from __sanitize
174
+ if (error && error.message && error.message.includes('due to security concerns')) {
175
+ throw error;
176
+ }
177
+ // Swallow TypeErrors (failed attack attempts return undefined)
178
+ if (error instanceof TypeError) {
179
+ return undefined;
180
+ }
181
+ throw error;
182
+ };
183
+ }
184
+ `);
185
+ if (this.config.debug) {
186
+ console.log('[IsolatedVmBridge] Error handler injected successfully');
187
+ }
188
+ }
189
+ /**
190
+ * Reset data proxies in the isolate context.
191
+ *
192
+ * This method should be called before each execute() to:
193
+ * 1. Clear proxy caches from previous evaluations
194
+ * 2. Initialize fresh workflow data references
195
+ * 3. Expose workflow properties to globalThis
196
+ *
197
+ * The reset function runs in the isolate and calls back to the host
198
+ * via ivm.Reference callbacks to fetch workflow data.
199
+ *
200
+ * @private
201
+ * @throws {Error} If context not initialized or reset fails
202
+ */
203
+ resetDataProxies() {
204
+ if (!this.context) {
205
+ throw new Error('Context not initialized');
206
+ }
207
+ try {
208
+ // Call the resetDataProxies function in the isolate
209
+ // This function is loaded as part of the runtime bundle
210
+ this.context.evalSync('resetDataProxies()');
211
+ if (this.config.debug) {
212
+ console.log('[IsolatedVmBridge] Data proxies reset successfully');
213
+ }
214
+ }
215
+ catch (error) {
216
+ const errorMessage = error instanceof Error ? error.message : String(error);
217
+ throw new Error(`Failed to reset data proxies: ${errorMessage}`);
218
+ }
219
+ }
220
+ /**
221
+ * Register callback functions for cross-isolate communication.
222
+ *
223
+ * Creates three ivm.Reference callbacks that the runtime bundle uses
224
+ * to fetch data from the host process:
225
+ *
226
+ * - __getValueAtPath: Returns metadata or primitive for a property path
227
+ * - __getArrayElement: Returns individual array elements
228
+ * - __callFunctionAtPath: Executes functions in host context
229
+ *
230
+ * These callbacks are called synchronously from isolate proxy traps.
231
+ *
232
+ * @param data - Current workflow data to use for callback responses
233
+ * @private
234
+ */
235
+ registerCallbacks(data) {
236
+ if (!this.context) {
237
+ throw new Error('Context not initialized');
238
+ }
239
+ // Callback 1: Get value/metadata at path
240
+ // Used by createDeepLazyProxy when accessing properties
241
+ const getValueAtPath = new ivm.Reference((path) => {
242
+ // Navigate to value
243
+ let value = data;
244
+ for (const key of path) {
245
+ value = value?.[key];
246
+ if (value === undefined || value === null) {
247
+ return value;
248
+ }
249
+ }
250
+ // Handle functions - return metadata marker
251
+ if (typeof value === 'function') {
252
+ const fnString = value.toString();
253
+ // Block native functions for security
254
+ if (fnString.includes('[native code]')) {
255
+ return undefined;
256
+ }
257
+ return { __isFunction: true, __name: path[path.length - 1] };
258
+ }
259
+ // Handle arrays - always lazy, only transfer length
260
+ if (Array.isArray(value)) {
261
+ return {
262
+ __isArray: true,
263
+ __length: value.length,
264
+ __data: null,
265
+ };
266
+ }
267
+ // Handle objects - return metadata with keys
268
+ if (value !== null && typeof value === 'object') {
269
+ return {
270
+ __isObject: true,
271
+ __keys: Object.keys(value),
272
+ };
273
+ }
274
+ // Primitive value
275
+ return value;
276
+ });
277
+ // Callback 2: Get array element at index
278
+ // Used by array proxy when accessing numeric indices
279
+ const getArrayElement = new ivm.Reference((path, index) => {
280
+ // Navigate to array
281
+ let arr = data;
282
+ for (const key of path) {
283
+ arr = arr?.[key];
284
+ }
285
+ if (!Array.isArray(arr)) {
286
+ return undefined;
287
+ }
288
+ const element = arr[index];
289
+ // If element is object/array, return metadata
290
+ if (element !== null && typeof element === 'object') {
291
+ if (Array.isArray(element)) {
292
+ return {
293
+ __isArray: true,
294
+ __length: element.length,
295
+ __data: null,
296
+ };
297
+ }
298
+ return {
299
+ __isObject: true,
300
+ __keys: Object.keys(element),
301
+ };
302
+ }
303
+ // Primitive element
304
+ return element;
305
+ });
306
+ // Callback 3: Call function at path with arguments
307
+ // Used when expressions invoke functions from workflow data
308
+ const callFunctionAtPath = new ivm.Reference((path, ...args) => {
309
+ // Navigate to function, tracking parent to preserve `this` context
310
+ let fn = data;
311
+ let parent = undefined;
312
+ for (const key of path) {
313
+ parent = fn;
314
+ fn = fn?.[key];
315
+ }
316
+ if (typeof fn !== 'function') {
317
+ throw new Error(`${path.join('.')} is not a function`);
318
+ }
319
+ // Block native functions for security (same check as getValueAtPath)
320
+ if (fn.toString().includes('[native code]')) {
321
+ throw new Error(`${path.join('.')} is a native function and cannot be called`);
322
+ }
323
+ // Execute function with parent as `this` to preserve method context
324
+ return fn.call(parent, ...args);
325
+ });
326
+ // Release previous references before replacing to avoid accumulation
327
+ this.valueAtPathRef?.release();
328
+ this.arrayElementRef?.release();
329
+ this.callFunctionRef?.release();
330
+ // Store references so they can be released on the next call or on dispose()
331
+ this.valueAtPathRef = getValueAtPath;
332
+ this.arrayElementRef = getArrayElement;
333
+ this.callFunctionRef = callFunctionAtPath;
334
+ // Register all callbacks in isolate global context
335
+ this.context.global.setSync('__getValueAtPath', getValueAtPath);
336
+ this.context.global.setSync('__getArrayElement', getArrayElement);
337
+ this.context.global.setSync('__callFunctionAtPath', callFunctionAtPath);
338
+ if (this.config.debug) {
339
+ console.log('[IsolatedVmBridge] Callbacks registered successfully');
340
+ }
341
+ }
342
+ /**
343
+ * Execute JavaScript code in the isolated context.
344
+ *
345
+ * Flow:
346
+ * 1. Register callbacks as ivm.Reference for cross-isolate communication
347
+ * 2. Call resetDataProxies() to initialize workflow data proxies
348
+ * 3. Compile script (with caching for performance)
349
+ * 4. Execute with timeout enforcement
350
+ * 5. Return result (copied from isolate)
351
+ *
352
+ * @param code - JavaScript expression to evaluate
353
+ * @param data - Workflow data (e.g., { $json: {...}, $runIndex: 0 })
354
+ * @returns Result of the expression
355
+ * @throws {Error} If bridge not initialized or execution fails
356
+ */
357
+ execute(code, data) {
358
+ if (!this.initialized || !this.context) {
359
+ throw new Error('Bridge not initialized. Call initialize() first.');
360
+ }
361
+ try {
362
+ // Step 1: Register callbacks with current data context
363
+ this.registerCallbacks(data);
364
+ // Step 2: Reset proxies for this evaluation
365
+ // This initializes $json, $binary, etc. as lazy proxies
366
+ this.resetDataProxies();
367
+ // Step 3: Wrap transformed code so 'this' === __data in the isolate.
368
+ // Tournament generates: this.$json.email, this.$items(), etc.
369
+ // __data has $json, $items, etc. as lazy proxies (set in resetDataProxies).
370
+ const wrappedCode = `(function() {\n${code}\n}).call(__data)`;
371
+ let script = this.scriptCache.get(code);
372
+ if (!script) {
373
+ script = this.isolate.compileScriptSync(wrappedCode);
374
+ this.scriptCache.set(code, script);
375
+ if (this.config.debug) {
376
+ console.log('[IsolatedVmBridge] Script compiled and cached');
377
+ }
378
+ }
379
+ // Step 4: Execute with timeout and copy result back
380
+ const result = script.runSync(this.context, {
381
+ timeout: this.config.timeout,
382
+ copy: true,
383
+ });
384
+ if (this.config.debug) {
385
+ console.log('[IsolatedVmBridge] Expression executed successfully');
386
+ }
387
+ return result;
388
+ }
389
+ catch (error) {
390
+ const errorMessage = error instanceof Error ? error.message : String(error);
391
+ throw new Error(`Expression evaluation failed: ${errorMessage}`);
392
+ }
393
+ }
394
+ /**
395
+ * Dispose of the isolate and free resources.
396
+ *
397
+ * After disposal, the bridge cannot be used again.
398
+ */
399
+ async dispose() {
400
+ if (this.disposed) {
401
+ return;
402
+ }
403
+ // Dispose isolate (this also disposes all contexts, references, etc.)
404
+ if (!this.isolate.isDisposed) {
405
+ this.isolate.dispose();
406
+ }
407
+ // Release callback references
408
+ this.valueAtPathRef?.release();
409
+ this.arrayElementRef?.release();
410
+ this.callFunctionRef?.release();
411
+ this.disposed = true;
412
+ this.initialized = false;
413
+ this.scriptCache.clear();
414
+ if (this.config.debug) {
415
+ console.log('[IsolatedVmBridge] Disposed');
416
+ }
417
+ }
418
+ /**
419
+ * Check if the bridge has been disposed.
420
+ *
421
+ * @returns true if disposed, false otherwise
422
+ */
423
+ isDisposed() {
424
+ return this.disposed;
425
+ }
426
+ }
427
+ //# sourceMappingURL=isolated-vm-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolated-vm-bridge.js","sourceRoot":"","sources":["../../src/bridge/isolated-vm-bridge.ts"],"names":[],"mappings":"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"}