mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-22 07:53:34 +01:00
wip: code cleanup, added axios shim to quick js vm (#2851)
* wip: code cleanup, added axios, nanoid shims for quickjs vm * wip: test fn fix * wip: scrip exec fix * wip: added node-fetch & uuid shims
This commit is contained in:
parent
a42689a717
commit
126c648d7d
@ -33,7 +33,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"nanoid": "3.3.4",
|
||||
"node-fetch": "2.*",
|
||||
"node-fetch": "^2.7.0",
|
||||
"node-vault": "^0.10.2",
|
||||
"quickjs-emscripten": "^0.29.2",
|
||||
"uuid": "^9.0.0"
|
||||
|
@ -96,14 +96,14 @@ class ScriptRuntime {
|
||||
modules: {},
|
||||
scriptType: 'jsScript'
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
request,
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
};
|
||||
return {
|
||||
request,
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
};
|
||||
}
|
||||
|
||||
// default runtime is vm2
|
||||
const vm = new NodeVM({
|
||||
|
@ -8,6 +8,7 @@ const { newQuickJSWASMModule, memoizePromiseFactory } = require('quickjs-emscrip
|
||||
|
||||
// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist
|
||||
const getBundledCode = require('../../bundle-browser-rollup');
|
||||
const addSleepShimToContext = require('./shims/sleep');
|
||||
|
||||
let QuickJSSyncContext;
|
||||
const loader = memoizePromiseFactory(() => newQuickJSWASMModule());
|
||||
@ -33,17 +34,6 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
|
||||
req && addBrunoRequestShimToContext(vm, req);
|
||||
res && addBrunoResponseShimToContext(vm, res);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const logHandle = vm.newFunction('log', (...args) => {
|
||||
const nativeArgs = args.map(vm.dump);
|
||||
console.log(...nativeArgs);
|
||||
});
|
||||
vm.setProp(vm.global, 'log', logHandle);
|
||||
logHandle.dispose();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const templateLiteralText = `\`${externalScript}\`;`;
|
||||
|
||||
const jsExpressionText = `${externalScript};`;
|
||||
@ -81,15 +71,15 @@ const executeQuickJsVmAsync = async ({
|
||||
const vm = module.newContext();
|
||||
|
||||
const bundledCode = getBundledCode?.toString() || '';
|
||||
let bundledScript = `
|
||||
(${bundledCode})()
|
||||
`;
|
||||
|
||||
bundledScript += `
|
||||
globalThis.require = (module) => {
|
||||
return globalThis.requireObject[module];
|
||||
}
|
||||
`;
|
||||
vm.evalCode(
|
||||
`
|
||||
(${bundledCode})()
|
||||
globalThis.require = (module) => {
|
||||
return globalThis.requireObject[module];
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const { bru, req, res, test, __brunoTestResults, console: consoleFn } = externalContext;
|
||||
|
||||
@ -97,72 +87,13 @@ const executeQuickJsVmAsync = async ({
|
||||
req && addBrunoRequestShimToContext(vm, req);
|
||||
res && addBrunoResponseShimToContext(vm, res);
|
||||
consoleFn && addConsoleShimToContext(vm, consoleFn);
|
||||
addSleepShimToContext(vm);
|
||||
|
||||
// await addLibraryShimsToContext(context);
|
||||
await addLibraryShimsToContext(vm);
|
||||
|
||||
test && __brunoTestResults && addTestShimToContext(vm, __brunoTestResults);
|
||||
|
||||
bundledScript += `
|
||||
globalThis.expect = require('chai').expect;
|
||||
globalThis.assert = require('chai').assert;
|
||||
|
||||
globalThis.__brunoTestResults = {
|
||||
addResult: globalThis.__bruno__addResult,
|
||||
getResults: globalThis.__bruno__getResults,
|
||||
}
|
||||
|
||||
globalThis.DummyChaiAssertionError = class DummyChaiAssertionError extends Error {
|
||||
constructor(message, props, ssf) {
|
||||
super(message);
|
||||
this.name = "AssertionError";
|
||||
Object.assign(this, props);
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.Test = (__brunoTestResults) => async (description, callback) => {
|
||||
try {
|
||||
await callback();
|
||||
__brunoTestResults.addResult({ description, status: "pass" });
|
||||
} catch (error) {
|
||||
if (error instanceof DummyChaiAssertionError) {
|
||||
const { message, actual, expected } = error;
|
||||
__brunoTestResults.addResult({
|
||||
description,
|
||||
status: "fail",
|
||||
error: message,
|
||||
actual,
|
||||
expected,
|
||||
});
|
||||
} else {
|
||||
globalThis.__bruno__addResult({
|
||||
description,
|
||||
status: "fail",
|
||||
error: error.message || "An unexpected error occurred.",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
globalThis.test = Test(__brunoTestResults);
|
||||
`;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const sleep = vm.newFunction('sleep', (timer) => {
|
||||
const t = vm.getString(timer);
|
||||
const promise = vm.newPromise();
|
||||
setTimeout(() => {
|
||||
promise.resolve(vm.newString('slept'));
|
||||
}, t);
|
||||
promise.settled.then(vm.runtime.executePendingJobs);
|
||||
return promise.handle;
|
||||
});
|
||||
sleep.consume((handle) => vm.setProp(vm.global, 'sleep', handle));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const script = `
|
||||
${bundledScript}
|
||||
(async () => {
|
||||
const setTimeout = async(fn, timer) => {
|
||||
v = await sleep(timer);
|
||||
|
72
packages/bruno-js/src/sandbox/quickjs/shims/lib/axios.js
Normal file
72
packages/bruno-js/src/sandbox/quickjs/shims/lib/axios.js
Normal file
@ -0,0 +1,72 @@
|
||||
const axios = require('axios');
|
||||
const { cleanJson } = require('../../../../utils');
|
||||
const { marshallToVm } = require('../../utils');
|
||||
|
||||
const methods = ['get', 'post', 'put', 'patch', 'delete'];
|
||||
|
||||
const addAxiosShimToContext = async (vm) => {
|
||||
methods?.forEach((method) => {
|
||||
const axiosHandle = vm.newFunction(method, (...args) => {
|
||||
const nativeArgs = args.map(vm.dump);
|
||||
const promise = vm.newPromise();
|
||||
axios[method](...nativeArgs)
|
||||
.then((response) => {
|
||||
const { status, headers, data } = response || {};
|
||||
promise.resolve(marshallToVm(cleanJson({ status, headers, data }), vm));
|
||||
})
|
||||
.catch((err) => {
|
||||
promise.resolve(
|
||||
marshallToVm(
|
||||
cleanJson({
|
||||
message: err.message
|
||||
}),
|
||||
vm
|
||||
)
|
||||
);
|
||||
});
|
||||
promise.settled.then(vm.runtime.executePendingJobs);
|
||||
return promise.handle;
|
||||
});
|
||||
axiosHandle.consume((handle) => vm.setProp(vm.global, `__bruno__axios__${method}`, handle));
|
||||
});
|
||||
|
||||
const axiosHandle = vm.newFunction('axios', (...args) => {
|
||||
const nativeArgs = args.map(vm.dump);
|
||||
const promise = vm.newPromise();
|
||||
axios(...nativeArgs)
|
||||
.then((response) => {
|
||||
const { status, headers, data } = response || {};
|
||||
promise.resolve(marshallToVm(cleanJson({ status, headers, data }), vm));
|
||||
})
|
||||
.catch((err) => {
|
||||
promise.resolve(
|
||||
marshallToVm(
|
||||
cleanJson({
|
||||
message: err.message
|
||||
}),
|
||||
vm
|
||||
)
|
||||
);
|
||||
});
|
||||
promise.settled.then(vm.runtime.executePendingJobs);
|
||||
return promise.handle;
|
||||
});
|
||||
axiosHandle.consume((handle) => vm.setProp(vm.global, `__bruno__axios`, handle));
|
||||
|
||||
vm.evalCode(
|
||||
`
|
||||
globalThis.axios = __bruno__axios;
|
||||
${methods
|
||||
?.map((method) => {
|
||||
return `globalThis.axios.${method} = __bruno__axios__${method};`;
|
||||
})
|
||||
?.join('\n')}
|
||||
globalThis.requireObject = {
|
||||
...globalThis.requireObject,
|
||||
axios: globalThis.axios,
|
||||
}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = addAxiosShimToContext;
|
@ -1,7 +1,13 @@
|
||||
const addAxiosShimToContext = require('./axios');
|
||||
const addNanoidShimToContext = require('./nanoid');
|
||||
const addNodeFetchShimToContext = require('./node-fetch');
|
||||
const addUuidShimToContext = require('./uuid');
|
||||
|
||||
const addLibraryShimsToContext = async (context) => {
|
||||
await addNanoidShimToContext(context);
|
||||
const addLibraryShimsToContext = async (vm) => {
|
||||
await addNanoidShimToContext(vm);
|
||||
await addAxiosShimToContext(vm);
|
||||
await addNodeFetchShimToContext(vm);
|
||||
await addUuidShimToContext(vm);
|
||||
};
|
||||
|
||||
module.exports = addLibraryShimsToContext;
|
||||
|
@ -1,5 +1,24 @@
|
||||
const { nanoid } = require('nanoid');
|
||||
const { marshallToVm } = require('../../utils');
|
||||
|
||||
const addNanoidShimToContext = async (context) => {};
|
||||
const addNanoidShimToContext = async (vm) => {
|
||||
let _nanoid = vm.newFunction('nanoid', function () {
|
||||
let v = nanoid();
|
||||
return marshallToVm(v, vm);
|
||||
});
|
||||
vm.setProp(vm.global, '__bruno__nanoid', _nanoid);
|
||||
_nanoid.dispose();
|
||||
|
||||
vm.evalCode(
|
||||
`
|
||||
globalThis.nanoid = {};
|
||||
globalThis.nanoid.nanoid = globalThis.__bruno__nanoid;
|
||||
globalThis.requireObject = {
|
||||
...globalThis.requireObject,
|
||||
'nanoid': globalThis.nanoid
|
||||
}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = addNanoidShimToContext;
|
||||
|
@ -0,0 +1,41 @@
|
||||
const fetch = require('node-fetch');
|
||||
const { cleanJson } = require('../../../../utils');
|
||||
const { marshallToVm } = require('../../utils');
|
||||
|
||||
const addNodeFetchShimToContext = async (vm) => {
|
||||
const nodeFetchHandle = vm.newFunction('node_fetch', (...args) => {
|
||||
const nativeArgs = args.map(vm.dump);
|
||||
const promise = vm.newPromise();
|
||||
fetch(...nativeArgs)
|
||||
.then(async (response) => {
|
||||
const { status, headers } = response || {};
|
||||
const data = await response.json();
|
||||
promise.resolve(marshallToVm(cleanJson({ status, headers, data }), vm));
|
||||
})
|
||||
.catch((err) => {
|
||||
promise.resolve(
|
||||
marshallToVm(
|
||||
cleanJson({
|
||||
message: err.message
|
||||
}),
|
||||
vm
|
||||
)
|
||||
);
|
||||
});
|
||||
promise.settled.then(vm.runtime.executePendingJobs);
|
||||
return promise.handle;
|
||||
});
|
||||
|
||||
nodeFetchHandle.consume((handle) => vm.setProp(vm.global, `__bruno__node_fetch`, handle));
|
||||
vm.evalCode(
|
||||
`
|
||||
globalThis.nodeFetch = __bruno__node_fetch;
|
||||
globalThis.requireObject = {
|
||||
...globalThis.requireObject,
|
||||
'node-fetch': globalThis.nodeFetch,
|
||||
}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = addNodeFetchShimToContext;
|
30
packages/bruno-js/src/sandbox/quickjs/shims/lib/uuid.js
Normal file
30
packages/bruno-js/src/sandbox/quickjs/shims/lib/uuid.js
Normal file
@ -0,0 +1,30 @@
|
||||
const uuid = require('uuid');
|
||||
const { marshallToVm } = require('../../utils');
|
||||
|
||||
const fns = ['version', 'parse', 'stringify', 'v1', 'v1ToV6', 'v3', 'v4', 'v5', 'v6', 'v6ToV1', 'v7', 'validate'];
|
||||
|
||||
const addUuidShimToContext = async (vm) => {
|
||||
fns.forEach((fn) => {
|
||||
let fnHandle = vm.newFunction(fn, function (...args) {
|
||||
const nativeArgs = args.map(vm.dump);
|
||||
return marshallToVm(uuid[fn](...nativeArgs), vm);
|
||||
});
|
||||
vm.setProp(vm.global, `__bruno__uuid__${fn}`, fnHandle);
|
||||
fnHandle.dispose();
|
||||
});
|
||||
|
||||
vm.evalCode(
|
||||
`
|
||||
globalThis.uuid = {};
|
||||
${['version', 'parse', 'stringify', 'v1', 'v1ToV6', 'v3', 'v4', 'v5', 'v6', 'v6ToV1', 'v7', 'validate']
|
||||
?.map((fn, idx) => `globalThis.uuid.${fn} = __bruno__uuid__${fn}`)
|
||||
.join('\n')}
|
||||
globalThis.requireObject = {
|
||||
...globalThis.requireObject,
|
||||
uuid: globalThis.uuid,
|
||||
}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = addUuidShimToContext;
|
14
packages/bruno-js/src/sandbox/quickjs/shims/sleep.js
Normal file
14
packages/bruno-js/src/sandbox/quickjs/shims/sleep.js
Normal file
@ -0,0 +1,14 @@
|
||||
const addSleepShimToContext = (vm) => {
|
||||
const sleepHandle = vm.newFunction('sleep', (timer) => {
|
||||
const t = vm.getString(timer);
|
||||
const promise = vm.newPromise();
|
||||
setTimeout(() => {
|
||||
promise.resolve(vm.newString('slept'));
|
||||
}, t);
|
||||
promise.settled.then(vm.runtime.executePendingJobs);
|
||||
return promise.handle;
|
||||
});
|
||||
sleepHandle.consume((handle) => vm.setProp(vm.global, 'sleep', handle));
|
||||
};
|
||||
|
||||
module.exports = addSleepShimToContext;
|
@ -13,53 +13,51 @@ const addBruShimToContext = (vm, __brunoTestResults) => {
|
||||
vm.setProp(vm.global, '__bruno__getResults', getResults);
|
||||
getResults.dispose();
|
||||
|
||||
// vm.evalCode(
|
||||
// `
|
||||
// globalThis.expect = require('chai').expect;
|
||||
// globalThis.assert = require('chai').assert;
|
||||
vm.evalCode(
|
||||
`
|
||||
globalThis.expect = require('chai').expect;
|
||||
globalThis.assert = require('chai').assert;
|
||||
|
||||
// globalThis.__brunoTestResults = {
|
||||
// addResult: globalThis.addResult,
|
||||
// getResults: globalThis.getResults,
|
||||
// }
|
||||
globalThis.__brunoTestResults = {
|
||||
addResult: globalThis.__bruno__addResult,
|
||||
getResults: globalThis.__bruno__getResults,
|
||||
}
|
||||
|
||||
// globalThis.DummyChaiAssertionError = class DummyChaiAssertionError extends Error {
|
||||
// constructor(message, props, ssf) {
|
||||
// super(message);
|
||||
// this.name = "AssertionError";
|
||||
// Object.assign(this, props);
|
||||
// }
|
||||
// }
|
||||
globalThis.DummyChaiAssertionError = class DummyChaiAssertionError extends Error {
|
||||
constructor(message, props, ssf) {
|
||||
super(message);
|
||||
this.name = "AssertionError";
|
||||
Object.assign(this, props);
|
||||
}
|
||||
}
|
||||
|
||||
// globalThis.Test = (__brunoTestResults) => async (description, callback) => {
|
||||
// try {
|
||||
// await callback();
|
||||
// __brunoTestResults.addResult({ description, status: "pass" });
|
||||
// } catch (error) {
|
||||
// if (error instanceof DummyChaiAssertionError) {
|
||||
// const { message, actual, expected } = error;
|
||||
// __brunoTestResults.addResult({
|
||||
// description,
|
||||
// status: "fail",
|
||||
// error: message,
|
||||
// actual,
|
||||
// expected,
|
||||
// });
|
||||
// } else {
|
||||
// __brunoTestResults.addResult({
|
||||
// description,
|
||||
// status: "fail",
|
||||
// error: error.message || "An unexpected error occurred.",
|
||||
// });
|
||||
// }
|
||||
// console.log(error);
|
||||
// }
|
||||
// };
|
||||
// let foobar = 'foobar3000';
|
||||
// log("from test shim");
|
||||
// globalThis.test = Test(__brunoTestResults);
|
||||
// `
|
||||
// );
|
||||
globalThis.Test = (__brunoTestResults) => async (description, callback) => {
|
||||
try {
|
||||
await callback();
|
||||
__brunoTestResults.addResult({ description, status: "pass" });
|
||||
} catch (error) {
|
||||
if (error instanceof DummyChaiAssertionError) {
|
||||
const { message, actual, expected } = error;
|
||||
__brunoTestResults.addResult({
|
||||
description,
|
||||
status: "fail",
|
||||
error: message,
|
||||
actual,
|
||||
expected,
|
||||
});
|
||||
} else {
|
||||
globalThis.__bruno__addResult({
|
||||
description,
|
||||
status: "fail",
|
||||
error: error.message || "An unexpected error occurred.",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
globalThis.test = Test(__brunoTestResults);
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = addBruShimToContext;
|
||||
|
@ -0,0 +1,17 @@
|
||||
meta {
|
||||
name: nanoid
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
const { nanoid } = require("nanoid");
|
||||
|
||||
req.setHeader("transaction-id", nanoid());
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
meta {
|
||||
name: node-fetch-pre-req-script
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
const fetch = require("node-fetch");
|
||||
|
||||
const url = "https://testbench-sanity.usebruno.com/api/echo/json";
|
||||
const response = await fetch(url, {
|
||||
method: 'post',
|
||||
body: JSON.stringify({hello:'bruno'}),
|
||||
headers: {'Content-Type': 'application/json'}
|
||||
});
|
||||
|
||||
req.setBody(response.data);
|
||||
req.setMethod("POST");
|
||||
req.setUrl(url);
|
||||
}
|
||||
|
||||
tests {
|
||||
test("req.getBody()", function() {
|
||||
const data = res.getBody();
|
||||
expect(data).to.eql({
|
||||
"hello": "bruno"
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
meta {
|
||||
name: uuid
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
const { v4 } = require("uuid");
|
||||
|
||||
req.setHeader("transaction-id", v4());
|
||||
}
|
Loading…
Reference in New Issue
Block a user