| 117 | * @throws Error if `isolated-vm` is not compatible with the current Node.js version |
| 118 | */ |
| 119 | export function createNodeIsolateDriver( |
| 120 | config: NodeIsolateDriverConfig = {}, |
| 121 | ): IsolateDriver { |
| 122 | if (!config.skipProbe) { |
| 123 | const probe = probeIsolatedVm() |
| 124 | if (!probe.compatible) { |
| 125 | throw new Error( |
| 126 | `isolated-vm is not compatible with the current Node.js version (${process.version}). ` + |
| 127 | `The native addon crashes the process (segfault) when used. ` + |
| 128 | `${probe.error ? probe.error + ' ' : ''}` + |
| 129 | `Use the QuickJS isolate driver as an alternative, or use a Node.js version supported by isolated-vm.`, |
| 130 | ) |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | const defaultMemoryLimit = config.memoryLimit ?? 128 |
| 135 | const defaultTimeout = config.timeout ?? 30000 |
| 136 | |
| 137 | return { |
| 138 | async createContext(isolateConfig: IsolateConfig): Promise<IsolateContext> { |
| 139 | const memoryLimit = isolateConfig.memoryLimit ?? defaultMemoryLimit |
| 140 | const timeout = isolateConfig.timeout ?? defaultTimeout |
| 141 | |
| 142 | // Create isolate with memory limit |
| 143 | const isolate = new ivm.Isolate({ memoryLimit }) |
| 144 | |
| 145 | // Create context |
| 146 | const context = await isolate.createContext() |
| 147 | |
| 148 | // Get reference to global object |
| 149 | const jail = context.global |
| 150 | |
| 151 | // Set up global reference |
| 152 | await jail.set('global', jail.derefInto()) |
| 153 | |
| 154 | // Set up console.log capture |
| 155 | const logs: Array<string> = [] |
| 156 | await jail.set( |
| 157 | '__captureLog', |
| 158 | new ivm.Reference((msg: string) => { |
| 159 | logs.push(msg) |
| 160 | }), |
| 161 | ) |
| 162 | |
| 163 | // Inject console object |
| 164 | await context.eval(` |
| 165 | const console = { |
| 166 | log: (...args) => { |
| 167 | const msg = args.map(a => |
| 168 | typeof a === 'object' ? JSON.stringify(a) : String(a) |
| 169 | ).join(' '); |
| 170 | __captureLog.applySync(undefined, [msg]); |
| 171 | }, |
| 172 | error: (...args) => { |
| 173 | const msg = 'ERROR: ' + args.map(a => |
| 174 | typeof a === 'object' ? JSON.stringify(a) : String(a) |
| 175 | ).join(' '); |
| 176 | __captureLog.applySync(undefined, [msg]); |