diff --git a/packages/builder/src/components/integration/QueryViewer.svelte b/packages/builder/src/components/integration/QueryViewer.svelte
index 59a3289731..8e390068df 100644
--- a/packages/builder/src/components/integration/QueryViewer.svelte
+++ b/packages/builder/src/components/integration/QueryViewer.svelte
@@ -41,6 +41,7 @@
let autoSchema = {}
let rows = []
+ let keys = {}
const parseQuery = query => {
modified = false
@@ -137,8 +138,20 @@
const handleScroll = e => {
scrolling = e.target.scrollTop !== 0
}
+
+ async function handleKeyDown(evt) {
+ keys[evt.key] = true
+ if ((keys["Meta"] || keys["Control"]) && keys["Enter"]) {
+ await runQuery({ suppressErrors: false })
+ }
+ }
+
+ function handleKeyUp(evt) {
+ delete keys[evt.key]
+ }
+
checkIsModified(newQuery)}
attemptSave={() => runQuery({ suppressErrors: false }).then(saveQuery)}
diff --git a/packages/server/package.json b/packages/server/package.json
index 66220c9f45..b8dcab3642 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -109,7 +109,6 @@
"undici-types": "^6.0.1",
"uuid": "3.3.2",
"validate.js": "0.13.1",
- "vm2": "^3.9.19",
"worker-farm": "1.7.0",
"xml2js": "0.5.0"
},
diff --git a/packages/server/src/utilities/scriptRunner.ts b/packages/server/src/utilities/scriptRunner.ts
index fee0215d2e..e6df8fa829 100644
--- a/packages/server/src/utilities/scriptRunner.ts
+++ b/packages/server/src/utilities/scriptRunner.ts
@@ -1,29 +1,64 @@
-import fetch from "node-fetch"
-import { VM, VMScript } from "vm2"
+import ivm, { Context, Script } from "isolated-vm"
const JS_TIMEOUT_MS = 1000
class ScriptRunner {
- vm: VM
- results: { out: string }
- script: VMScript
+ vm: IsolatedVM
constructor(script: string, context: any) {
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
- this.vm = new VM({
- timeout: JS_TIMEOUT_MS,
- })
- this.results = { out: "" }
- this.vm.setGlobals(context)
- this.vm.setGlobal("fetch", fetch)
- this.vm.setGlobal("results", this.results)
- this.script = new VMScript(code)
+ this.vm = new IsolatedVM(8)
+ this.vm.context = {
+ data: context.data,
+ params: context.params,
+ results: { out: "" },
+ }
+ this.vm.code = code
}
execute() {
- this.vm.run(this.script)
- return this.results.out
+ this.vm.runScript()
+ const results = this.vm.getValue("results")
+ return results.out
}
}
+class IsolatedVM {
+ isolate: ivm.Isolate
+ vm: ivm.Context
+ jail: ivm.Reference
+ script: any
+
+ constructor(memoryLimit: number) {
+ this.isolate = new ivm.Isolate({ memoryLimit })
+ this.vm = this.isolate.createContextSync()
+ this.jail = this.vm.global
+ this.jail.setSync("global", this.jail.derefInto())
+ }
+
+ getValue(key: string) {
+ const ref = this.vm.global.getSync(key, { reference: true })
+ const result = ref.copySync()
+ ref.release()
+ return result
+ }
+
+ set context(context: Record) {
+ for (let key in context) {
+ this.jail.setSync(key, this.copyRefToVm(context[key]))
+ }
+ }
+
+ set code(code: string) {
+ this.script = this.isolate.compileScriptSync(code)
+ }
+
+ runScript() {
+ this.script.runSync(this.vm, { timeout: JS_TIMEOUT_MS })
+ }
+
+ copyRefToVm(value: Object): ivm.Copy