QoL improvement to query UI, switch out vm2 for isolated-vm
This commit is contained in:
parent
670ce0528f
commit
cc7c1d1576
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
let autoSchema = {}
|
let autoSchema = {}
|
||||||
let rows = []
|
let rows = []
|
||||||
|
let keys = {}
|
||||||
|
|
||||||
const parseQuery = query => {
|
const parseQuery = query => {
|
||||||
modified = false
|
modified = false
|
||||||
|
@ -137,8 +138,20 @@
|
||||||
const handleScroll = e => {
|
const handleScroll = e => {
|
||||||
scrolling = e.target.scrollTop !== 0
|
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]
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={handleKeyDown} on:keyup={handleKeyUp} />
|
||||||
<QueryViewerSavePromptModal
|
<QueryViewerSavePromptModal
|
||||||
checkIsModified={() => checkIsModified(newQuery)}
|
checkIsModified={() => checkIsModified(newQuery)}
|
||||||
attemptSave={() => runQuery({ suppressErrors: false }).then(saveQuery)}
|
attemptSave={() => runQuery({ suppressErrors: false }).then(saveQuery)}
|
||||||
|
|
|
@ -109,7 +109,6 @@
|
||||||
"undici-types": "^6.0.1",
|
"undici-types": "^6.0.1",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"validate.js": "0.13.1",
|
"validate.js": "0.13.1",
|
||||||
"vm2": "^3.9.19",
|
|
||||||
"worker-farm": "1.7.0",
|
"worker-farm": "1.7.0",
|
||||||
"xml2js": "0.5.0"
|
"xml2js": "0.5.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,29 +1,64 @@
|
||||||
import fetch from "node-fetch"
|
import ivm, { Context, Script } from "isolated-vm"
|
||||||
import { VM, VMScript } from "vm2"
|
|
||||||
|
|
||||||
const JS_TIMEOUT_MS = 1000
|
const JS_TIMEOUT_MS = 1000
|
||||||
|
|
||||||
class ScriptRunner {
|
class ScriptRunner {
|
||||||
vm: VM
|
vm: IsolatedVM
|
||||||
results: { out: string }
|
|
||||||
script: VMScript
|
|
||||||
|
|
||||||
constructor(script: string, context: any) {
|
constructor(script: string, context: any) {
|
||||||
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
|
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
|
||||||
this.vm = new VM({
|
this.vm = new IsolatedVM(8)
|
||||||
timeout: JS_TIMEOUT_MS,
|
this.vm.context = {
|
||||||
})
|
data: context.data,
|
||||||
this.results = { out: "" }
|
params: context.params,
|
||||||
this.vm.setGlobals(context)
|
results: { out: "" },
|
||||||
this.vm.setGlobal("fetch", fetch)
|
}
|
||||||
this.vm.setGlobal("results", this.results)
|
this.vm.code = code
|
||||||
this.script = new VMScript(code)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
execute() {
|
execute() {
|
||||||
this.vm.run(this.script)
|
this.vm.runScript()
|
||||||
return this.results.out
|
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<string, any>) {
|
||||||
|
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<Object> {
|
||||||
|
return new ivm.ExternalCopy(value).copyInto({ release: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
export default ScriptRunner
|
export default ScriptRunner
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"name": "@budibase/string-templates",
|
"name": "@budibase/string-templates",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "Handlebars wrapper for Budibase templating.",
|
"description": "Handlebars wrapper for Budibase templating.",
|
||||||
"main": "src/index.cjs",
|
|
||||||
"module": "dist/bundle.mjs",
|
"module": "dist/bundle.mjs",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
@ -28,8 +27,8 @@
|
||||||
"@budibase/handlebars-helpers": "^0.11.9",
|
"@budibase/handlebars-helpers": "^0.11.9",
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.6",
|
||||||
"lodash": "4.17.21",
|
"isolated-vm": "^4.6.0",
|
||||||
"vm2": "^3.9.19"
|
"lodash": "4.17.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^17.1.0",
|
"@rollup/plugin-commonjs": "^17.1.0",
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
const templates = require("./index.js")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CJS entrypoint for rollup
|
|
||||||
*/
|
|
||||||
module.exports.isValid = templates.isValid
|
|
||||||
module.exports.makePropSafe = templates.makePropSafe
|
|
||||||
module.exports.getManifest = templates.getManifest
|
|
||||||
module.exports.isJSBinding = templates.isJSBinding
|
|
||||||
module.exports.encodeJSBinding = templates.encodeJSBinding
|
|
||||||
module.exports.decodeJSBinding = templates.decodeJSBinding
|
|
||||||
module.exports.processStringSync = templates.processStringSync
|
|
||||||
module.exports.processObjectSync = templates.processObjectSync
|
|
||||||
module.exports.processString = templates.processString
|
|
||||||
module.exports.processObject = templates.processObject
|
|
||||||
module.exports.doesContainStrings = templates.doesContainStrings
|
|
||||||
module.exports.doesContainString = templates.doesContainString
|
|
||||||
module.exports.disableEscaping = templates.disableEscaping
|
|
||||||
module.exports.findHBSBlocks = templates.findHBSBlocks
|
|
||||||
module.exports.convertToJS = templates.convertToJS
|
|
||||||
module.exports.FIND_ANY_HBS_REGEX = templates.FIND_ANY_HBS_REGEX
|
|
||||||
|
|
||||||
if (!process.env.NO_JS) {
|
|
||||||
const { VM } = require("vm2")
|
|
||||||
const { setJSRunner } = require("./helpers/javascript")
|
|
||||||
/**
|
|
||||||
* Use vm2 to run JS scripts in a node env
|
|
||||||
*/
|
|
||||||
setJSRunner((js, context) => {
|
|
||||||
const vm = new VM({
|
|
||||||
sandbox: context,
|
|
||||||
timeout: 1000,
|
|
||||||
})
|
|
||||||
return vm.run(js)
|
|
||||||
})
|
|
||||||
}
|
|
16
yarn.lock
16
yarn.lock
|
@ -6322,7 +6322,7 @@ acorn@^7.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||||
|
|
||||||
acorn@^8.1.0, acorn@^8.10.0, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0:
|
acorn@^8.1.0, acorn@^8.10.0, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0:
|
||||||
version "8.11.2"
|
version "8.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b"
|
||||||
integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==
|
integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==
|
||||||
|
@ -11986,7 +11986,7 @@ http-assert@^1.3.0:
|
||||||
deep-equal "~1.0.1"
|
deep-equal "~1.0.1"
|
||||||
http-errors "~1.8.0"
|
http-errors "~1.8.0"
|
||||||
|
|
||||||
http-cache-semantics@3.8.1, http-cache-semantics@4.1.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1:
|
http-cache-semantics@3.8.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
||||||
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
|
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
|
||||||
|
@ -18772,7 +18772,7 @@ request@^2.88.0:
|
||||||
performance-now "^2.1.0"
|
performance-now "^2.1.0"
|
||||||
qs "~6.5.2"
|
qs "~6.5.2"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
tough-cookie "^4.1.3"
|
tough-cookie "~2.5.0"
|
||||||
tunnel-agent "^0.6.0"
|
tunnel-agent "^0.6.0"
|
||||||
uuid "^3.3.2"
|
uuid "^3.3.2"
|
||||||
|
|
||||||
|
@ -20931,7 +20931,7 @@ touch@^3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
nopt "~1.0.10"
|
nopt "~1.0.10"
|
||||||
|
|
||||||
"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@~2.5.0:
|
"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@^4.1.3, tough-cookie@~2.5.0:
|
||||||
version "4.1.3"
|
version "4.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
||||||
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
||||||
|
@ -21729,14 +21729,6 @@ vlq@^0.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
|
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
|
||||||
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
|
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
|
||||||
|
|
||||||
vm2@^3.9.19:
|
|
||||||
version "3.9.19"
|
|
||||||
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.19.tgz#be1e1d7a106122c6c492b4d51c2e8b93d3ed6a4a"
|
|
||||||
integrity sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==
|
|
||||||
dependencies:
|
|
||||||
acorn "^8.7.0"
|
|
||||||
acorn-walk "^8.2.0"
|
|
||||||
|
|
||||||
vuvuzela@1.0.3:
|
vuvuzela@1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b"
|
resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b"
|
||||||
|
|
Loading…
Reference in New Issue