@usebruno/js 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +22 -4
- package/src/bru.js +48 -22
- package/src/bruno-request.js +101 -3
- package/src/interpolate-string.js +4 -2
- package/src/runtime/assert-runtime.js +52 -20
- package/src/runtime/script-runtime.js +64 -39
- package/src/runtime/test-runtime.js +62 -55
- package/src/runtime/vars-runtime.js +22 -60
- package/src/sandbox/bundle-browser-rollup.js +502 -0
- package/src/sandbox/bundle-libraries.js +88 -0
- package/src/sandbox/quickjs/index.js +193 -0
- package/src/sandbox/quickjs/shims/bru.js +99 -0
- package/src/sandbox/quickjs/shims/bruno-request.js +112 -0
- package/src/sandbox/quickjs/shims/bruno-response.js +55 -0
- package/src/sandbox/quickjs/shims/console.js +46 -0
- package/src/sandbox/quickjs/shims/lib/axios.js +72 -0
- package/src/sandbox/quickjs/shims/lib/index.js +13 -0
- package/src/sandbox/quickjs/shims/lib/nanoid.js +24 -0
- package/src/sandbox/quickjs/shims/lib/path.js +28 -0
- package/src/sandbox/quickjs/shims/lib/uuid.js +30 -0
- package/src/sandbox/quickjs/shims/local-module.js +35 -0
- package/src/sandbox/quickjs/shims/test.js +63 -0
- package/src/sandbox/quickjs/utils/index.js +33 -0
- package/src/utils.js +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usebruno/js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
"@usebruno/vm2": "^3.9.13"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "jest --testPathIgnorePatterns test.js"
|
|
14
|
+
"test": "node --experimental-vm-modules $(npx which jest) --testPathIgnorePatterns test.js",
|
|
15
|
+
"sandbox:bundle-libraries": "node ./src/sandbox/bundle-libraries.js"
|
|
15
16
|
},
|
|
16
17
|
"dependencies": {
|
|
17
|
-
"@usebruno/common": "0.
|
|
18
|
+
"@usebruno/common": "0.3.0",
|
|
18
19
|
"@usebruno/query": "0.1.0",
|
|
19
20
|
"ajv": "^8.12.0",
|
|
20
21
|
"ajv-formats": "^2.1.1",
|
|
@@ -24,12 +25,29 @@
|
|
|
24
25
|
"chai": "^4.3.7",
|
|
25
26
|
"chai-string": "^1.5.0",
|
|
26
27
|
"crypto-js": "^4.1.1",
|
|
28
|
+
"crypto-js-3.1.9-1": "npm:crypto-js@^3.1.9-1",
|
|
27
29
|
"json-query": "^2.2.2",
|
|
28
30
|
"lodash": "^4.17.21",
|
|
29
31
|
"moment": "^2.29.4",
|
|
30
32
|
"nanoid": "3.3.4",
|
|
31
|
-
"node-fetch": "2
|
|
33
|
+
"node-fetch": "^2.7.0",
|
|
32
34
|
"node-vault": "^0.10.2",
|
|
35
|
+
"path": "^0.12.7",
|
|
36
|
+
"quickjs-emscripten": "^0.29.2",
|
|
33
37
|
"uuid": "^9.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@rollup/plugin-commonjs": "^23.0.2",
|
|
41
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
42
|
+
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
43
|
+
"rollup": "3.2.5",
|
|
44
|
+
"rollup-plugin-node-builtins": "^2.1.2",
|
|
45
|
+
"rollup-plugin-node-globals": "^1.4.0",
|
|
46
|
+
"rollup-plugin-polyfill-node": "^0.13.0",
|
|
47
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
48
|
+
"stream": "^0.0.2",
|
|
49
|
+
"terser": "^5.31.1",
|
|
50
|
+
"uglify-js": "^3.18.0",
|
|
51
|
+
"util": "^0.12.5"
|
|
34
52
|
}
|
|
35
53
|
}
|
package/src/bru.js
CHANGED
|
@@ -5,24 +5,17 @@ const { interpolate } = require('@usebruno/common');
|
|
|
5
5
|
const variableNameRegex = /^[\w-.]*$/;
|
|
6
6
|
|
|
7
7
|
class Bru {
|
|
8
|
-
constructor(
|
|
9
|
-
envVariables,
|
|
10
|
-
collectionVariables,
|
|
11
|
-
processEnvVars,
|
|
12
|
-
collectionPath,
|
|
13
|
-
historyLogger,
|
|
14
|
-
setHtmlVisualizationString,
|
|
15
|
-
secretVariables,
|
|
16
|
-
requestVariables
|
|
17
|
-
) {
|
|
8
|
+
constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, historyLogger, setVisualizations, secretVariables, collectionVariables, folderVariables, requestVariables) {
|
|
18
9
|
this.envVariables = envVariables || {};
|
|
19
|
-
this.
|
|
10
|
+
this.runtimeVariables = runtimeVariables || {};
|
|
20
11
|
this.processEnvVars = cloneDeep(processEnvVars || {});
|
|
21
12
|
this.secretVariables = cloneDeep(secretVariables || {});
|
|
13
|
+
this.collectionVariables = collectionVariables || {};
|
|
14
|
+
this.folderVariables = folderVariables || {};
|
|
22
15
|
this.requestVariables = requestVariables || {};
|
|
23
16
|
this.collectionPath = collectionPath;
|
|
24
17
|
this.historyLogger = historyLogger;
|
|
25
|
-
this.
|
|
18
|
+
this.setVisualizations = setVisualizations;
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
_interpolate = (str) => {
|
|
@@ -31,9 +24,11 @@ class Bru {
|
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
const combinedVars = {
|
|
27
|
+
...this.collectionVariables,
|
|
34
28
|
...this.envVariables,
|
|
29
|
+
...this.folderVariables,
|
|
35
30
|
...this.requestVariables,
|
|
36
|
-
...this.
|
|
31
|
+
...this.runtimeVariables,
|
|
37
32
|
process: {
|
|
38
33
|
env: {
|
|
39
34
|
...this.processEnvVars
|
|
@@ -82,7 +77,7 @@ class Bru {
|
|
|
82
77
|
}
|
|
83
78
|
|
|
84
79
|
hasVar(key) {
|
|
85
|
-
return Object.hasOwn(this.
|
|
80
|
+
return Object.hasOwn(this.runtimeVariables, key);
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
setVar(key, value) {
|
|
@@ -93,7 +88,7 @@ class Bru {
|
|
|
93
88
|
if (variableNameRegex.test(key) === false) {
|
|
94
89
|
throw new Error(
|
|
95
90
|
`Variable name: "${key}" contains invalid characters!` +
|
|
96
|
-
|
|
91
|
+
' Names must only contain alpha-numeric characters, "-", "_", "."'
|
|
97
92
|
);
|
|
98
93
|
}
|
|
99
94
|
|
|
@@ -106,22 +101,30 @@ class Bru {
|
|
|
106
101
|
});
|
|
107
102
|
}
|
|
108
103
|
|
|
109
|
-
this.
|
|
104
|
+
this.runtimeVariables[key] = value;
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
getVar(key) {
|
|
113
108
|
if (variableNameRegex.test(key) === false) {
|
|
114
109
|
throw new Error(
|
|
115
110
|
`Variable name: "${key}" contains invalid characters!` +
|
|
116
|
-
|
|
111
|
+
' Names must only contain alpha-numeric characters, "-", "_", "."'
|
|
117
112
|
);
|
|
118
113
|
}
|
|
119
114
|
|
|
120
|
-
return this._interpolate(this.
|
|
115
|
+
return this._interpolate(this.runtimeVariables[key]);
|
|
121
116
|
}
|
|
122
117
|
|
|
123
118
|
deleteVar(key) {
|
|
124
|
-
delete this.
|
|
119
|
+
delete this.runtimeVariables[key];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getCollectionVar(key) {
|
|
123
|
+
return this._interpolate(this.collectionVariables[key]);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getFolderVar(key) {
|
|
127
|
+
return this._interpolate(this.folderVariables[key]);
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
getRequestVar(key) {
|
|
@@ -132,13 +135,36 @@ class Bru {
|
|
|
132
135
|
this.nextRequest = nextRequest;
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
visualize(htmlString) {
|
|
136
|
-
this.setHtmlVisualizationString(htmlString);
|
|
137
|
-
}
|
|
138
138
|
|
|
139
139
|
getSecretVar(key) {
|
|
140
140
|
return this.secretVariables?.[`$secrets.${key}`];
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
visualize(type, data) {
|
|
145
|
+
if (type == 'table') {
|
|
146
|
+
if (data?.provider == 'ag-grid') {
|
|
147
|
+
if (!data?.props?.columnDefinitions) {
|
|
148
|
+
throw new Error(`columns definitions are required`);
|
|
149
|
+
}
|
|
150
|
+
if (!data?.props?.rowData) {
|
|
151
|
+
throw new Error(`row data is required`);
|
|
152
|
+
}
|
|
153
|
+
this.setVisualizations({ uid: uuid(), type, data });
|
|
154
|
+
} else if (data?.provider == 'react-table') {
|
|
155
|
+
this.setVisualizations({ uid: uuid(), type, data });
|
|
156
|
+
}
|
|
157
|
+
} else if (type == 'html') {
|
|
158
|
+
if (!data?.content) {
|
|
159
|
+
throw new Error(`html content is required`);
|
|
160
|
+
}
|
|
161
|
+
this.setVisualizations({ uid: uuid(), type, data });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
sleep(ms) {
|
|
166
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
167
|
+
}
|
|
142
168
|
}
|
|
143
169
|
|
|
144
170
|
module.exports = Bru;
|
package/src/bruno-request.js
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
const { uuid } = require('./utils');
|
|
2
2
|
|
|
3
3
|
class BrunoRequest {
|
|
4
|
+
/**
|
|
5
|
+
* The following properties are available as shorthand:
|
|
6
|
+
* - req.url
|
|
7
|
+
* - req.method
|
|
8
|
+
* - req.headers
|
|
9
|
+
* - req.timeout
|
|
10
|
+
* - req.body
|
|
11
|
+
*
|
|
12
|
+
* Above shorthands are useful for accessing the request properties directly in the scripts
|
|
13
|
+
* It must be noted that the user cannot set these properties directly.
|
|
14
|
+
* They should use the respective setter methods to set these properties.
|
|
15
|
+
*/
|
|
4
16
|
constructor(req, historyLogger) {
|
|
5
17
|
this.req = req;
|
|
6
18
|
this.url = req.url;
|
|
7
19
|
this.method = req.method;
|
|
8
20
|
this.headers = req.headers;
|
|
9
|
-
this.body = req.data;
|
|
10
21
|
this.timeout = req.timeout;
|
|
11
22
|
this.historyLogger = historyLogger;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* We automatically parse the JSON body if the content type is JSON
|
|
26
|
+
* This is to make it easier for the user to access the body directly
|
|
27
|
+
*
|
|
28
|
+
* It must be noted that the request data is always a string and is what gets sent over the network
|
|
29
|
+
* If the user wants to access the raw data, they can use getBody({raw: true}) method
|
|
30
|
+
*/
|
|
31
|
+
const isJson = this.hasJSONContentType(this.req.headers);
|
|
32
|
+
if (isJson) {
|
|
33
|
+
this.body = this.__safeParseJSON(req.data);
|
|
34
|
+
}
|
|
12
35
|
}
|
|
13
36
|
|
|
14
37
|
getUrl() {
|
|
@@ -16,6 +39,7 @@ class BrunoRequest {
|
|
|
16
39
|
}
|
|
17
40
|
|
|
18
41
|
setUrl(url) {
|
|
42
|
+
this.url = url;
|
|
19
43
|
this.req.url = url;
|
|
20
44
|
}
|
|
21
45
|
|
|
@@ -40,6 +64,7 @@ class BrunoRequest {
|
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
setMethod(method) {
|
|
67
|
+
this.method = method;
|
|
43
68
|
this.req.method = method;
|
|
44
69
|
}
|
|
45
70
|
|
|
@@ -48,6 +73,7 @@ class BrunoRequest {
|
|
|
48
73
|
}
|
|
49
74
|
|
|
50
75
|
setHeaders(headers) {
|
|
76
|
+
this.headers = headers;
|
|
51
77
|
this.req.headers = headers;
|
|
52
78
|
}
|
|
53
79
|
|
|
@@ -64,14 +90,45 @@ class BrunoRequest {
|
|
|
64
90
|
createdAt: new Date().toISOString()
|
|
65
91
|
});
|
|
66
92
|
}
|
|
93
|
+
this.headers[name] = value;
|
|
67
94
|
this.req.headers[name] = value;
|
|
68
95
|
}
|
|
69
96
|
|
|
70
|
-
|
|
97
|
+
hasJSONContentType(headers) {
|
|
98
|
+
const contentType = headers?.['Content-Type'] || headers?.['content-type'] || '';
|
|
99
|
+
return contentType.includes('json');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get the body of the request
|
|
104
|
+
*
|
|
105
|
+
* We automatically parse and return the JSON body if the content type is JSON
|
|
106
|
+
* If the user wants the raw body, they can pass the raw option as true
|
|
107
|
+
*/
|
|
108
|
+
getBody(options = {}) {
|
|
109
|
+
if (options.raw) {
|
|
110
|
+
return this.req.data;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const isJson = this.hasJSONContentType(this.req.headers);
|
|
114
|
+
if (isJson) {
|
|
115
|
+
return this.__safeParseJSON(this.req.data);
|
|
116
|
+
}
|
|
117
|
+
|
|
71
118
|
return this.req.data;
|
|
72
119
|
}
|
|
73
120
|
|
|
74
|
-
|
|
121
|
+
/**
|
|
122
|
+
* If the content type is JSON and if the data is an object
|
|
123
|
+
* - We set the body property as the object itself
|
|
124
|
+
* - We set the request data as the stringified JSON as it is what gets sent over the network
|
|
125
|
+
* Otherwise
|
|
126
|
+
* - We set the request data as the data itself
|
|
127
|
+
* - We set the body property as the data itself
|
|
128
|
+
*
|
|
129
|
+
* If the user wants to override this behavior, they can pass the raw option as true
|
|
130
|
+
*/
|
|
131
|
+
setBody(data, options = {}) {
|
|
75
132
|
if (this.historyLogger) {
|
|
76
133
|
this.historyLogger({
|
|
77
134
|
uid: uuid(),
|
|
@@ -80,7 +137,22 @@ class BrunoRequest {
|
|
|
80
137
|
createdAt: new Date().toISOString()
|
|
81
138
|
});
|
|
82
139
|
}
|
|
140
|
+
|
|
141
|
+
if (options.raw) {
|
|
142
|
+
this.req.data = data;
|
|
143
|
+
this.body = data;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isJson = this.hasJSONContentType(this.req.headers);
|
|
148
|
+
if (isJson && this.__isObject(data)) {
|
|
149
|
+
this.body = data;
|
|
150
|
+
this.req.data = this.__safeStringifyJSON(data);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
83
154
|
this.req.data = data;
|
|
155
|
+
this.body = data;
|
|
84
156
|
}
|
|
85
157
|
|
|
86
158
|
setMaxRedirects(maxRedirects) {
|
|
@@ -92,8 +164,34 @@ class BrunoRequest {
|
|
|
92
164
|
}
|
|
93
165
|
|
|
94
166
|
setTimeout(timeout) {
|
|
167
|
+
this.timeout = timeout;
|
|
95
168
|
this.req.timeout = timeout;
|
|
96
169
|
}
|
|
170
|
+
|
|
171
|
+
__safeParseJSON(str) {
|
|
172
|
+
try {
|
|
173
|
+
return JSON.parse(str);
|
|
174
|
+
} catch (e) {
|
|
175
|
+
return str;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
__safeStringifyJSON(obj) {
|
|
180
|
+
try {
|
|
181
|
+
return JSON.stringify(obj);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
return obj;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
__isObject(obj) {
|
|
188
|
+
return obj !== null && typeof obj === 'object';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
disableParsingResponseJson() {
|
|
193
|
+
this.req.__brunoDisableParsingResponseJson = true;
|
|
194
|
+
}
|
|
97
195
|
}
|
|
98
196
|
|
|
99
197
|
module.exports = BrunoRequest;
|
|
@@ -2,16 +2,18 @@ const { interpolate } = require('@usebruno/common');
|
|
|
2
2
|
|
|
3
3
|
const interpolateString = (
|
|
4
4
|
str,
|
|
5
|
-
{ envVariables = {},
|
|
5
|
+
{ envVariables = {}, runtimeVariables = {}, processEnvVars = {}, collectionVariables = {}, folderVariables = {}, requestVariables = {} }
|
|
6
6
|
) => {
|
|
7
7
|
if (!str || !str.length || typeof str !== 'string') {
|
|
8
8
|
return str;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const combinedVars = {
|
|
12
|
+
...collectionVariables,
|
|
12
13
|
...envVariables,
|
|
14
|
+
...folderVariables,
|
|
13
15
|
...requestVariables,
|
|
14
|
-
...
|
|
16
|
+
...runtimeVariables,
|
|
15
17
|
process: {
|
|
16
18
|
env: {
|
|
17
19
|
...processEnvVars
|
|
@@ -5,6 +5,7 @@ const Bru = require('../bru');
|
|
|
5
5
|
const BrunoRequest = require('../bruno-request');
|
|
6
6
|
const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser, uuid } = require('../utils');
|
|
7
7
|
const { interpolateString } = require('../interpolate-string');
|
|
8
|
+
const { executeQuickJsVm } = require('../sandbox/quickjs');
|
|
8
9
|
|
|
9
10
|
const { expect } = chai;
|
|
10
11
|
chai.use(require('chai-string'));
|
|
@@ -161,14 +162,40 @@ const isUnaryOperator = (operator) => {
|
|
|
161
162
|
return unaryOperators.includes(operator);
|
|
162
163
|
};
|
|
163
164
|
|
|
164
|
-
const
|
|
165
|
+
const evaluateJsTemplateLiteralBasedOnRuntime = (literal, context, runtime) => {
|
|
166
|
+
if (runtime === 'quickjs') {
|
|
167
|
+
return executeQuickJsVm({
|
|
168
|
+
script: literal,
|
|
169
|
+
context,
|
|
170
|
+
scriptType: 'template-literal'
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return evaluateJsTemplateLiteral(literal, context);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const evaluateJsExpressionBasedOnRuntime = (expr, context, runtime) => {
|
|
178
|
+
if (runtime === 'quickjs') {
|
|
179
|
+
return executeQuickJsVm({
|
|
180
|
+
script: expr,
|
|
181
|
+
context,
|
|
182
|
+
scriptType: 'expression'
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return evaluateJsExpression(expr, context);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const evaluateRhsOperand = (rhsOperand, operator, context, runtime) => {
|
|
165
190
|
if (isUnaryOperator(operator)) {
|
|
166
191
|
return;
|
|
167
192
|
}
|
|
168
193
|
|
|
169
194
|
const interpolationContext = {
|
|
170
|
-
requestVariables: context.bru.requestVariables,
|
|
171
195
|
collectionVariables: context.bru.collectionVariables,
|
|
196
|
+
folderVariables: context.bru.folderVariables,
|
|
197
|
+
requestVariables: context.bru.requestVariables,
|
|
198
|
+
runtimeVariables: context.bru.runtimeVariables,
|
|
172
199
|
envVariables: context.bru.envVariables,
|
|
173
200
|
processEnvVars: context.bru.processEnvVars
|
|
174
201
|
};
|
|
@@ -181,13 +208,17 @@ const evaluateRhsOperand = (rhsOperand, operator, context) => {
|
|
|
181
208
|
|
|
182
209
|
return rhsOperand
|
|
183
210
|
.split(',')
|
|
184
|
-
.map((v) =>
|
|
211
|
+
.map((v) =>
|
|
212
|
+
evaluateJsTemplateLiteralBasedOnRuntime(interpolateString(v.trim(), interpolationContext), context, runtime)
|
|
213
|
+
);
|
|
185
214
|
}
|
|
186
215
|
|
|
187
216
|
if (operator === 'between') {
|
|
188
217
|
const [lhs, rhs] = rhsOperand
|
|
189
218
|
.split(',')
|
|
190
|
-
.map((v) =>
|
|
219
|
+
.map((v) =>
|
|
220
|
+
evaluateJsTemplateLiteralBasedOnRuntime(interpolateString(v.trim(), interpolationContext), context, runtime)
|
|
221
|
+
);
|
|
191
222
|
return [lhs, rhs];
|
|
192
223
|
}
|
|
193
224
|
|
|
@@ -200,20 +231,17 @@ const evaluateRhsOperand = (rhsOperand, operator, context) => {
|
|
|
200
231
|
return interpolateString(rhsOperand, interpolationContext);
|
|
201
232
|
}
|
|
202
233
|
|
|
203
|
-
return
|
|
234
|
+
return evaluateJsTemplateLiteralBasedOnRuntime(interpolateString(rhsOperand, interpolationContext), context, runtime);
|
|
204
235
|
};
|
|
205
236
|
|
|
206
237
|
class AssertRuntime {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
collectionVariables
|
|
213
|
-
|
|
214
|
-
historyLogger,
|
|
215
|
-
secretVariables
|
|
216
|
-
) {
|
|
238
|
+
constructor(props) {
|
|
239
|
+
this.runtime = props?.runtime || 'vm2';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
runAssertions(assertions, request, response, envVariables, runtimeVariables, processEnvVars, historyLogger, secretVariables) {
|
|
243
|
+
const collectionVariables = request?.collectionVariables || {};
|
|
244
|
+
const folderVariables = request?.folderVariables || {};
|
|
217
245
|
const requestVariables = request?.requestVariables || {};
|
|
218
246
|
const enabledAssertions = _.filter(assertions, (a) => a.enabled);
|
|
219
247
|
if (!enabledAssertions.length) {
|
|
@@ -222,12 +250,14 @@ class AssertRuntime {
|
|
|
222
250
|
|
|
223
251
|
const bru = new Bru(
|
|
224
252
|
envVariables,
|
|
225
|
-
|
|
253
|
+
runtimeVariables,
|
|
226
254
|
processEnvVars,
|
|
227
255
|
undefined, // collectionPath,
|
|
228
256
|
undefined, // historyLogger,
|
|
229
|
-
undefined, //
|
|
257
|
+
undefined, // setVisualizations,
|
|
230
258
|
secretVariables,
|
|
259
|
+
collectionVariables,
|
|
260
|
+
folderVariables,
|
|
231
261
|
requestVariables
|
|
232
262
|
);
|
|
233
263
|
const req = new BrunoRequest(request, historyLogger);
|
|
@@ -240,9 +270,11 @@ class AssertRuntime {
|
|
|
240
270
|
};
|
|
241
271
|
|
|
242
272
|
const context = {
|
|
273
|
+
...collectionVariables,
|
|
243
274
|
...envVariables,
|
|
275
|
+
...folderVariables,
|
|
244
276
|
...requestVariables,
|
|
245
|
-
...
|
|
277
|
+
...runtimeVariables,
|
|
246
278
|
...processEnvVars,
|
|
247
279
|
...bruContext
|
|
248
280
|
};
|
|
@@ -256,8 +288,8 @@ class AssertRuntime {
|
|
|
256
288
|
const { operator, value: rhsOperand } = parseAssertionOperator(rhsExpr);
|
|
257
289
|
|
|
258
290
|
try {
|
|
259
|
-
const lhs =
|
|
260
|
-
const rhs = evaluateRhsOperand(rhsOperand, operator, context);
|
|
291
|
+
const lhs = evaluateJsExpressionBasedOnRuntime(lhsExpr, context, this.runtime);
|
|
292
|
+
const rhs = evaluateRhsOperand(rhsOperand, operator, context, this.runtime);
|
|
261
293
|
|
|
262
294
|
switch (operator) {
|
|
263
295
|
case 'eq':
|
|
@@ -27,10 +27,13 @@ const axios = require('axios');
|
|
|
27
27
|
const fetch = require('node-fetch');
|
|
28
28
|
const chai = require('chai');
|
|
29
29
|
const CryptoJS = require('crypto-js');
|
|
30
|
-
const
|
|
30
|
+
const NodeVault = require('node-vault');
|
|
31
|
+
const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
|
|
31
32
|
|
|
32
33
|
class ScriptRuntime {
|
|
33
|
-
constructor() {
|
|
34
|
+
constructor(props) {
|
|
35
|
+
this.runtime = props?.runtime || 'vm2';
|
|
36
|
+
}
|
|
34
37
|
|
|
35
38
|
// This approach is getting out of hand
|
|
36
39
|
// Need to refactor this to use a single arg (object) instead of 7
|
|
@@ -38,7 +41,7 @@ class ScriptRuntime {
|
|
|
38
41
|
script,
|
|
39
42
|
request,
|
|
40
43
|
envVariables,
|
|
41
|
-
|
|
44
|
+
runtimeVariables,
|
|
42
45
|
collectionPath,
|
|
43
46
|
onConsoleLog,
|
|
44
47
|
processEnvVars,
|
|
@@ -46,21 +49,14 @@ class ScriptRuntime {
|
|
|
46
49
|
historyLogger,
|
|
47
50
|
secretVariables
|
|
48
51
|
) {
|
|
49
|
-
let
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
}
|
|
52
|
+
let visualizations = [];
|
|
53
|
+
let setVisualizations = (data) => {
|
|
54
|
+
visualizations.push(data);
|
|
55
|
+
}
|
|
56
|
+
const collectionVariables = request?.collectionVariables || {};
|
|
57
|
+
const folderVariables = request?.folderVariables || {};
|
|
53
58
|
const requestVariables = request?.requestVariables || {};
|
|
54
|
-
const bru = new Bru(
|
|
55
|
-
envVariables,
|
|
56
|
-
collectionVariables,
|
|
57
|
-
processEnvVars,
|
|
58
|
-
collectionPath,
|
|
59
|
-
historyLogger,
|
|
60
|
-
setHtmlVisualizationString,
|
|
61
|
-
secretVariables,
|
|
62
|
-
requestVariables
|
|
63
|
-
);
|
|
59
|
+
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, historyLogger, setVisualizations, secretVariables, collectionVariables, folderVariables, requestVariables);
|
|
64
60
|
const req = new BrunoRequest(request, historyLogger);
|
|
65
61
|
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
|
66
62
|
const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []);
|
|
@@ -101,6 +97,23 @@ class ScriptRuntime {
|
|
|
101
97
|
};
|
|
102
98
|
}
|
|
103
99
|
|
|
100
|
+
if (this.runtime === 'quickjs') {
|
|
101
|
+
await executeQuickJsVmAsync({
|
|
102
|
+
script: script,
|
|
103
|
+
context: context,
|
|
104
|
+
collectionPath
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
request,
|
|
109
|
+
envVariables: cleanJson(envVariables),
|
|
110
|
+
runtimeVariables: cleanJson(runtimeVariables),
|
|
111
|
+
visualizations,
|
|
112
|
+
nextRequestName: bru.nextRequest
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// default runtime is vm2
|
|
104
117
|
const vm = new NodeVM({
|
|
105
118
|
sandbox: context,
|
|
106
119
|
require: {
|
|
@@ -132,17 +145,18 @@ class ScriptRuntime {
|
|
|
132
145
|
'crypto-js': CryptoJS,
|
|
133
146
|
...whitelistedModules,
|
|
134
147
|
fs: allowScriptFilesystemAccess ? fs : undefined,
|
|
135
|
-
'node-vault':
|
|
148
|
+
'node-vault': NodeVault
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
});
|
|
139
152
|
const asyncVM = vm.run(`module.exports = async () => { ${script} }`, path.join(collectionPath, 'vm.js'));
|
|
140
153
|
await asyncVM();
|
|
154
|
+
|
|
141
155
|
return {
|
|
142
156
|
request,
|
|
143
157
|
envVariables: cleanJson(envVariables),
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
runtimeVariables: cleanJson(runtimeVariables),
|
|
159
|
+
visualizations,
|
|
146
160
|
nextRequestName: bru.nextRequest
|
|
147
161
|
};
|
|
148
162
|
}
|
|
@@ -152,7 +166,7 @@ class ScriptRuntime {
|
|
|
152
166
|
request,
|
|
153
167
|
response,
|
|
154
168
|
envVariables,
|
|
155
|
-
|
|
169
|
+
runtimeVariables,
|
|
156
170
|
collectionPath,
|
|
157
171
|
onConsoleLog,
|
|
158
172
|
processEnvVars,
|
|
@@ -160,21 +174,14 @@ class ScriptRuntime {
|
|
|
160
174
|
historyLogger,
|
|
161
175
|
secretVariables
|
|
162
176
|
) {
|
|
163
|
-
let
|
|
164
|
-
let
|
|
165
|
-
|
|
166
|
-
}
|
|
177
|
+
let visualizations = [];
|
|
178
|
+
let setVisualizations = (data) => {
|
|
179
|
+
visualizations.push(data);
|
|
180
|
+
}
|
|
181
|
+
const collectionVariables = request?.collectionVariables || {};
|
|
182
|
+
const folderVariables = request?.folderVariables || {};
|
|
167
183
|
const requestVariables = request?.requestVariables || {};
|
|
168
|
-
const bru = new Bru(
|
|
169
|
-
envVariables,
|
|
170
|
-
collectionVariables,
|
|
171
|
-
processEnvVars,
|
|
172
|
-
collectionPath,
|
|
173
|
-
historyLogger,
|
|
174
|
-
setHtmlVisualizationString,
|
|
175
|
-
secretVariables,
|
|
176
|
-
requestVariables
|
|
177
|
-
);
|
|
184
|
+
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, historyLogger, setVisualizations, secretVariables, collectionVariables, folderVariables, requestVariables);
|
|
178
185
|
const req = new BrunoRequest(request, historyLogger);
|
|
179
186
|
const res = new BrunoResponse(response);
|
|
180
187
|
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
|
@@ -207,10 +214,28 @@ class ScriptRuntime {
|
|
|
207
214
|
log: customLogger('log'),
|
|
208
215
|
info: customLogger('info'),
|
|
209
216
|
warn: customLogger('warn'),
|
|
210
|
-
error: customLogger('error')
|
|
217
|
+
error: customLogger('error'),
|
|
218
|
+
debug: customLogger('debug')
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (this.runtime === 'quickjs') {
|
|
223
|
+
await executeQuickJsVmAsync({
|
|
224
|
+
script: script,
|
|
225
|
+
context: context,
|
|
226
|
+
collectionPath
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
response,
|
|
231
|
+
envVariables: cleanJson(envVariables),
|
|
232
|
+
runtimeVariables: cleanJson(runtimeVariables),
|
|
233
|
+
visualizations,
|
|
234
|
+
nextRequestName: bru.nextRequest
|
|
211
235
|
};
|
|
212
236
|
}
|
|
213
237
|
|
|
238
|
+
// default runtime is vm2
|
|
214
239
|
const vm = new NodeVM({
|
|
215
240
|
sandbox: context,
|
|
216
241
|
require: {
|
|
@@ -241,7 +266,7 @@ class ScriptRuntime {
|
|
|
241
266
|
'crypto-js': CryptoJS,
|
|
242
267
|
...whitelistedModules,
|
|
243
268
|
fs: allowScriptFilesystemAccess ? fs : undefined,
|
|
244
|
-
'node-vault':
|
|
269
|
+
'node-vault': NodeVault
|
|
245
270
|
}
|
|
246
271
|
}
|
|
247
272
|
});
|
|
@@ -252,8 +277,8 @@ class ScriptRuntime {
|
|
|
252
277
|
return {
|
|
253
278
|
response,
|
|
254
279
|
envVariables: cleanJson(envVariables),
|
|
255
|
-
|
|
256
|
-
|
|
280
|
+
runtimeVariables: cleanJson(runtimeVariables),
|
|
281
|
+
visualizations,
|
|
257
282
|
nextRequestName: bru.nextRequest
|
|
258
283
|
};
|
|
259
284
|
}
|