@n8n/expression-runtime 0.31.0 → 0.32.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.
- package/ARCHITECTURE.md +16 -42
- package/README.md +6 -3
- package/dist/bundle/runtime.esm.js +5 -5
- package/dist/bundle/runtime.esm.js.map +3 -3
- package/dist/bundle/runtime.iife.js +5 -5
- package/dist/bundle/runtime.iife.js.map +3 -3
- package/dist/cjs/bridge/quickjs-bridge.d.ts.map +1 -1
- package/dist/cjs/bridge/quickjs-bridge.js +13 -2
- package/dist/cjs/bridge/quickjs-bridge.js.map +1 -1
- package/dist/cjs/build.tsbuildinfo +1 -1
- package/dist/cjs/extensions/function-extensions.d.ts +2 -0
- package/dist/cjs/extensions/function-extensions.d.ts.map +1 -1
- package/dist/cjs/extensions/function-extensions.js +11 -0
- package/dist/cjs/extensions/function-extensions.js.map +1 -1
- package/dist/cjs/pool/idle-scaling-pool.d.ts.map +1 -1
- package/dist/cjs/pool/idle-scaling-pool.js +3 -1
- package/dist/cjs/pool/idle-scaling-pool.js.map +1 -1
- package/dist/cjs/pool/isolate-pool.d.ts.map +1 -1
- package/dist/cjs/pool/isolate-pool.js +4 -1
- package/dist/cjs/pool/isolate-pool.js.map +1 -1
- package/dist/cjs/types/bridge.d.ts +6 -0
- package/dist/cjs/types/bridge.d.ts.map +1 -1
- package/dist/cjs/types/bridge.js +1 -0
- package/dist/cjs/types/bridge.js.map +1 -1
- package/dist/esm/bridge/quickjs-bridge.d.ts.map +1 -1
- package/dist/esm/bridge/quickjs-bridge.js +13 -2
- package/dist/esm/bridge/quickjs-bridge.js.map +1 -1
- package/dist/esm/build.tsbuildinfo +1 -1
- package/dist/esm/extensions/function-extensions.d.ts +2 -0
- package/dist/esm/extensions/function-extensions.d.ts.map +1 -1
- package/dist/esm/extensions/function-extensions.js +11 -0
- package/dist/esm/extensions/function-extensions.js.map +1 -1
- package/dist/esm/pool/idle-scaling-pool.d.ts.map +1 -1
- package/dist/esm/pool/idle-scaling-pool.js +3 -1
- package/dist/esm/pool/idle-scaling-pool.js.map +1 -1
- package/dist/esm/pool/isolate-pool.d.ts.map +1 -1
- package/dist/esm/pool/isolate-pool.js +4 -1
- package/dist/esm/pool/isolate-pool.js.map +1 -1
- package/dist/esm/types/bridge.d.ts +6 -0
- package/dist/esm/types/bridge.d.ts.map +1 -1
- package/dist/esm/types/bridge.js +1 -0
- package/dist/esm/types/bridge.js.map +1 -1
- package/package.json +3 -2
package/ARCHITECTURE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Expression Runtime Architecture
|
|
2
2
|
|
|
3
|
-
This package provides a secure, isolated expression evaluation runtime that works across multiple execution environments (isolated-vm,
|
|
3
|
+
This package provides a secure, isolated expression evaluation runtime that works across multiple execution environments (isolated-vm, QuickJS in WASM, and task runners).
|
|
4
4
|
|
|
5
5
|
## Design Goals
|
|
6
6
|
|
|
7
|
-
1. **Environment Agnostic**: Single codebase that works in Node.js (isolated-vm), browsers (
|
|
7
|
+
1. **Environment Agnostic**: Single codebase that works in Node.js (isolated-vm), browsers (QuickJS in WASM), and task runner processes
|
|
8
8
|
2. **Security**: Expressions run in isolated contexts with memory limits and timeouts
|
|
9
9
|
3. **Performance**: Lazy data loading, code caching, and efficient data transfer
|
|
10
10
|
4. **Observability**: Built-in metrics, traces, and logs
|
|
@@ -29,7 +29,7 @@ The architecture is split into three distinct layers:
|
|
|
29
29
|
│ ┌────────────────▼───────────────────────────────┐ │
|
|
30
30
|
│ │ Bridge (Layer 2) │ │
|
|
31
31
|
│ │ - IsolatedVmBridge (Phase 1.1) │ │
|
|
32
|
-
│ │ -
|
|
32
|
+
│ │ - QuickJsBridge (WASM) │ │
|
|
33
33
|
│ │ - Task Runner Integration (TBD) │ │
|
|
34
34
|
│ └────────────────┬───────────────────────────────┘ │
|
|
35
35
|
│ │ IPC/Message Passing │
|
|
@@ -62,7 +62,7 @@ The architecture is split into three distinct layers:
|
|
|
62
62
|
- **Libraries**: lodash, Luxon (bundled)
|
|
63
63
|
- **No Node.js APIs**: Pure JavaScript only
|
|
64
64
|
|
|
65
|
-
**Bundle**: IIFE format for isolated-vm
|
|
65
|
+
**Bundle**: IIFE format for both isolated-vm and QuickJS
|
|
66
66
|
|
|
67
67
|
### Layer 2: Bridge (Host Process)
|
|
68
68
|
|
|
@@ -73,7 +73,7 @@ The architecture is split into three distinct layers:
|
|
|
73
73
|
**Key Components**:
|
|
74
74
|
- **RuntimeBridge Interface**: Abstract interface for all bridge implementations
|
|
75
75
|
- **IsolatedVmBridge**: Uses isolated-vm API for Node.js backend (Phase 1.1)
|
|
76
|
-
- **
|
|
76
|
+
- **QuickJsBridge**: Uses quickjs-emscripten (WASM) for Node.js and the browser
|
|
77
77
|
- **Task Runner Integration**: TBD - May use IsolatedVmBridge locally or direct evaluation (Phase 2+)
|
|
78
78
|
|
|
79
79
|
**Responsibilities**:
|
|
@@ -175,24 +175,12 @@ class IsolatedVmBridge implements RuntimeBridge {
|
|
|
175
175
|
}
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
###
|
|
178
|
+
### QuickJsBridge (Browser Frontend)
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
private worker: Worker;
|
|
185
|
-
|
|
186
|
-
async initialize(): Promise<void> {
|
|
187
|
-
this.worker = new Worker('/runtime.worker.js');
|
|
188
|
-
// Setup message handlers
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async execute(code: string, dataId: string): Promise<unknown> {
|
|
192
|
-
// Implementation...
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
```
|
|
180
|
+
The editor runs the same `QuickJsBridge` as Node.
|
|
181
|
+
The browser has no filesystem, so the host passes the runtime bundle in with the
|
|
182
|
+
`runtimeBundle` option. The vite stub in `packages/frontend/editor-ui/vite/` maps
|
|
183
|
+
`@n8n/expression-runtime` to the real bridge for the browser build.
|
|
196
184
|
|
|
197
185
|
### Task Runner Integration (TBD - Phase 2+)
|
|
198
186
|
|
|
@@ -294,7 +282,7 @@ packages/@n8n/expression-runtime/
|
|
|
294
282
|
**Limitation**: Lazy loading requires **synchronous** callbacks from runtime to host. This works for:
|
|
295
283
|
- ✅ **isolated-vm**: Uses `ivm.Reference` for true synchronous callbacks
|
|
296
284
|
- ✅ **Node.js vm**: Direct synchronous function calls
|
|
297
|
-
-
|
|
285
|
+
- ✅ **QuickJS**: host functions are plain synchronous calls in the WASM context
|
|
298
286
|
|
|
299
287
|
### 3. Why Bundle the Runtime?
|
|
300
288
|
|
|
@@ -304,7 +292,7 @@ packages/@n8n/expression-runtime/
|
|
|
304
292
|
|
|
305
293
|
### 4. Why Abstract Bridge?
|
|
306
294
|
|
|
307
|
-
**
|
|
295
|
+
**Portability**: The backend uses isolated-vm. The browser uses QuickJS in WASM. The abstract bridge allows adding new environments without changing other layers.
|
|
308
296
|
|
|
309
297
|
**Testing**: Integration tests use `IsolatedVmBridge` directly (see `src/__tests__/integration.test.ts`).
|
|
310
298
|
|
|
@@ -334,23 +322,9 @@ const proxy = new Proxy({}, {
|
|
|
334
322
|
- Direct synchronous function calls
|
|
335
323
|
- Full lazy loading support (used for testing)
|
|
336
324
|
|
|
337
|
-
3. **
|
|
338
|
-
-
|
|
339
|
-
-
|
|
340
|
-
- **Future Enhancement (Phase 2+)**: Explore `SharedArrayBuffer` + `Atomics` for synchronous data access
|
|
341
|
-
|
|
342
|
-
### Web Worker Support Roadmap
|
|
343
|
-
|
|
344
|
-
**Phase 1** (Initial implementation):
|
|
345
|
-
- WebWorkerBridge will pre-fetch all workflow data
|
|
346
|
-
- Transfer complete data object to worker before evaluation
|
|
347
|
-
- Works for small/medium datasets (< 50MB)
|
|
348
|
-
- No lazy loading benefit
|
|
349
|
-
|
|
350
|
-
**Phase 2+** (Future enhancement):
|
|
351
|
-
- Investigate `SharedArrayBuffer` + `Atomics` for sync access
|
|
352
|
-
- Or accept pre-fetching as the Web Worker approach
|
|
353
|
-
- Decision based on real-world usage patterns
|
|
325
|
+
3. **QuickJS (WASM)** ✅
|
|
326
|
+
- Host functions are plain synchronous calls in the QuickJS context
|
|
327
|
+
- Full lazy loading support, in Node.js and in the browser
|
|
354
328
|
|
|
355
329
|
### Security Boundaries
|
|
356
330
|
|
|
@@ -422,5 +396,5 @@ See observability package documentation for details.
|
|
|
422
396
|
## References
|
|
423
397
|
|
|
424
398
|
- [isolated-vm GitHub](https://github.com/laverdet/isolated-vm)
|
|
425
|
-
- [
|
|
399
|
+
- [quickjs-emscripten GitHub](https://github.com/justjake/quickjs-emscripten)
|
|
426
400
|
- [n8n workflow package](../workflow/)
|
package/README.md
CHANGED
|
@@ -11,10 +11,10 @@ Secure, isolated expression evaluation runtime for n8n workflows.
|
|
|
11
11
|
- ✅ `IsolatedVmBridge`: V8 isolate management via `isolated-vm`
|
|
12
12
|
- ✅ `ExpressionEvaluator`: tournament integration, expression code caching, isolate pooling
|
|
13
13
|
- ✅ Workflow integration — default engine; `N8N_EXPRESSION_ENGINE=legacy` opts out
|
|
14
|
+
- ✅ Editor support — the `QuickJsBridge` runs in the browser; `N8N_EXPRESSION_ENGINE_FRONTEND=quickjs` opts in
|
|
14
15
|
- ✅ Observability (metrics, traces, logs) wired up in `packages/cli`
|
|
15
16
|
|
|
16
17
|
Coming later:
|
|
17
|
-
- 🚧 Web Worker support (Phase 2+)
|
|
18
18
|
- 🚧 Performance optimizations (Phase 3)
|
|
19
19
|
|
|
20
20
|
## Overview
|
|
@@ -23,9 +23,9 @@ This package provides a secure runtime for evaluating expressions in isolated co
|
|
|
23
23
|
|
|
24
24
|
Currently supports:
|
|
25
25
|
- **Node.js Backend**: Uses `isolated-vm` for V8 isolate-based isolation with lazy data loading
|
|
26
|
+
- **Browser Frontend**: Uses `QuickJsBridge` (QuickJS compiled to WASM); `N8N_EXPRESSION_ENGINE_FRONTEND=quickjs` opts in
|
|
26
27
|
|
|
27
28
|
Future support (Phase 2+):
|
|
28
|
-
- **Browser Frontend**: Will use Web Workers for browser-based isolation
|
|
29
29
|
- **Task Runners**: Will use IPC for separate process isolation
|
|
30
30
|
|
|
31
31
|
## Features
|
|
@@ -170,7 +170,7 @@ interface RuntimeBridge {
|
|
|
170
170
|
- Synchronous callbacks via ivm.Reference
|
|
171
171
|
- Security wrappers (SafeObject, SafeError)
|
|
172
172
|
- `E()` error handler for tournament-generated try-catch code
|
|
173
|
-
- **
|
|
173
|
+
- **QuickJsBridge**: ✅ QuickJS in WASM, for the Node.js backend and the browser frontend
|
|
174
174
|
- **Task Runner Integration**: 🚧 TBD - May use IsolatedVmBridge locally or direct evaluation - Phase 2+
|
|
175
175
|
|
|
176
176
|
## Configuration
|
|
@@ -195,6 +195,9 @@ In n8n, the evaluator is configured via `ExpressionEngineConfig` (`@n8n/config`)
|
|
|
195
195
|
# Engine selection ('vm' is the default; 'legacy' opts out of isolation)
|
|
196
196
|
N8N_EXPRESSION_ENGINE=vm
|
|
197
197
|
|
|
198
|
+
# Editor engine selection ('legacy' is the default; 'quickjs' runs the WASM engine in the browser)
|
|
199
|
+
N8N_EXPRESSION_ENGINE_FRONTEND=legacy
|
|
200
|
+
|
|
198
201
|
# Isolate pool and code cache
|
|
199
202
|
N8N_EXPRESSION_ENGINE_POOL_SIZE=1
|
|
200
203
|
N8N_EXPRESSION_ENGINE_MAX_CODE_CACHE_SIZE=1024
|