This pull request introduces the socket:vm module. It is similar in API surface to the node:vm module, but all exported functions are async as the internal semantics, context execution, and JavaScript environment are completely different.
import vm from 'socket:vm'
const result = await vm.runInContext('1 + 2 + 3')
console.log(result) // 6
Users of this module can supply a custom context object that is available in the globalThis scope of the execution context. Values that can be passed to a script virtual machine are the same that can be passed to a worker. We introduce a "reference proxy" that can be used to reference object instances in a VM to the caller. Functions are automatically detected, referenced, and made available as a proxy call.
import vm from 'socket:vm'
const context = {
scope: {}
}
await vm.runInContext(
`scope.decode = (buffer) => new TextDecoder().decode(buffer)`,
{ context }
)
const text = await scope.decode(new TextEncoder().encode('hello world')) // hello world
Virtual machine source scripts can be used in a module module or classic (default). When source scripts are modules, they can use import/export syntax. By default, all virtual machine scripts are executed in an async context granting "top level await" to the script.
Virtual machine source scripts run in isolated contexts that are actually a mostly complete implementation of a Shadow Realm context. All environment intrinsics are preserved and non-configurable. Every script VM has a context and global scope that can the caller can supply and interact with.
import vm from 'socket:vm'
const channel = new MessageChannel()
const context = { scope: {} }
const source = `
let port = null
export function setMessagePort (messagePort) {
port = messagePort
port.start()
}
export function postMessage (message) {
const transfer = vm.getTransferables(message)
port.postMessage(message, { transfer })
}
`
const module = await rm.runInContext(source, { context })
const decoder = new TextDecoder()
const encoder = new TextEncoder()
channel.port1.start()
channel.port1.onmessage = (event) => {
console.log(decoder.decode(event.data)) // 'hello world'
}
// send 'hello world' as buffer to VM module which
// will echo it back to us to decode above in the `onmessage`
// event handler for the `MessageChannel` we are sharing with
// the VM module
module.postMessage(encoder.encode('hello world'))
This pull request introduces the
socket:vm
module. It is similar in API surface to thenode:vm
module, but all exported functions are async as the internal semantics, context execution, and JavaScript environment are completely different.Users of this module can supply a custom context object that is available in the
globalThis
scope of the execution context. Values that can be passed to a script virtual machine are the same that can be passed to a worker. We introduce a "reference proxy" that can be used to reference object instances in a VM to the caller. Functions are automatically detected, referenced, and made available as a proxy call.Virtual machine source scripts can be used in a
module
module orclassic
(default). When source scripts are modules, they can useimport/export
syntax. By default, all virtual machine scripts are executed in an async context granting "top level await" to the script.Virtual machine source scripts run in isolated contexts that are actually a mostly complete implementation of a Shadow Realm context. All environment intrinsics are preserved and non-configurable. Every script VM has a context and global scope that can the caller can supply and interact with.