@usebruno/js 0.46.0 → 0.47.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 +8 -7
- package/src/bru.js +173 -75
- package/src/bruno-request.js +2 -0
- package/src/cookie-list.js +272 -0
- package/src/index.js +27 -2
- package/src/property-list.js +184 -0
- package/src/readonly-property-list.js +227 -0
- package/src/runtime/assert-runtime.js +8 -10
- package/src/runtime/script-runtime.js +55 -6
- package/src/runtime/test-runtime.js +19 -1
- package/src/runtime/vars-runtime.js +20 -3
- package/src/sandbox/bundle-libraries.js +1 -1
- package/src/sandbox/quickjs/index.js +2 -34
- package/src/sandbox/quickjs/shims/bru.js +31 -1
- package/src/sandbox/quickjs/shims/bruno-response.js +29 -2
- package/src/sandbox/quickjs/shims/bruno-response.spec.js +91 -0
- package/src/sandbox/quickjs/shims/lib/uuid.spec.js +166 -0
- package/src/sandbox/quickjs/shims/require.js +56 -0
- package/src/sandbox/quickjs/shims/require.spec.js +154 -0
- package/src/sandbox/quickjs/shims/test.js +2 -2
- package/src/sandbox/quickjs/utils/property-list-bridge.js +165 -0
- package/src/sandbox/quickjs/utils/test-helpers.js +31 -0
- package/src/utils/error-formatter.js +345 -20
- package/src/utils/error-formatter.spec.js +683 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const ReadOnlyPropertyList = require('./readonly-property-list');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PropertyList - A mutable collection data structure.
|
|
5
|
+
*
|
|
6
|
+
* Extends ReadOnlyPropertyList with mutation methods that operate on the
|
|
7
|
+
* internal _items array in static mode. In dynamic mode, all mutations
|
|
8
|
+
* throw — subclasses (e.g. CookieList) override with async implementations.
|
|
9
|
+
*
|
|
10
|
+
* Class hierarchy:
|
|
11
|
+
* ReadOnlyPropertyList (read-only, both modes)
|
|
12
|
+
* └── PropertyList (sync mutations in static mode; throws in dynamic mode)
|
|
13
|
+
* └── CookieList (overrides add/upsert/remove/clear/delete with async jar ops)
|
|
14
|
+
*/
|
|
15
|
+
class PropertyList extends ReadOnlyPropertyList {
|
|
16
|
+
/**
|
|
17
|
+
* Guard that throws in dynamic mode. Called by all mutation methods.
|
|
18
|
+
* @param {string} method - Name of the calling method (for error message)
|
|
19
|
+
*/
|
|
20
|
+
#ensureStaticMode(method) {
|
|
21
|
+
if (this._dynamic) {
|
|
22
|
+
throw new Error(`${method}() is not supported in dynamic mode. Override in subclass.`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── Mutation methods ──────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Append an item to the end of the list.
|
|
30
|
+
* @param {object} item
|
|
31
|
+
*/
|
|
32
|
+
add(item) {
|
|
33
|
+
this.#ensureStaticMode('add');
|
|
34
|
+
this._items.push(item);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Alias for add().
|
|
39
|
+
* @param {object} item
|
|
40
|
+
*/
|
|
41
|
+
append(item) {
|
|
42
|
+
return this.add(item);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Insert an item at the beginning of the list.
|
|
47
|
+
* @param {object} item
|
|
48
|
+
*/
|
|
49
|
+
prepend(item) {
|
|
50
|
+
this.#ensureStaticMode('prepend');
|
|
51
|
+
this._items.unshift(item);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Insert an item before a reference item.
|
|
56
|
+
* @param {object} item - The item to insert
|
|
57
|
+
* @param {string|object} before - Key string or item object to insert before
|
|
58
|
+
*/
|
|
59
|
+
insert(item, before) {
|
|
60
|
+
this.#ensureStaticMode('insert');
|
|
61
|
+
const idx = this.#findIndex(before);
|
|
62
|
+
if (idx === -1) {
|
|
63
|
+
this._items.push(item);
|
|
64
|
+
} else {
|
|
65
|
+
this._items.splice(idx, 0, item);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Insert an item after a reference item.
|
|
71
|
+
* @param {object} item - The item to insert
|
|
72
|
+
* @param {string|object} after - Key string or item object to insert after
|
|
73
|
+
*/
|
|
74
|
+
insertAfter(item, after) {
|
|
75
|
+
this.#ensureStaticMode('insertAfter');
|
|
76
|
+
const idx = this.#findIndex(after);
|
|
77
|
+
if (idx === -1) {
|
|
78
|
+
this._items.push(item);
|
|
79
|
+
} else {
|
|
80
|
+
this._items.splice(idx + 1, 0, item);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Remove items matching a predicate, key string, or item reference.
|
|
86
|
+
* @param {Function|string|object} predicate
|
|
87
|
+
*/
|
|
88
|
+
remove(predicate) {
|
|
89
|
+
this.#ensureStaticMode('remove');
|
|
90
|
+
if (typeof predicate === 'function') {
|
|
91
|
+
this._items = this._items.filter((item) => !predicate(item));
|
|
92
|
+
} else if (typeof predicate === 'string') {
|
|
93
|
+
this._items = this._items.filter((item) => item[this._keyProperty] !== predicate);
|
|
94
|
+
} else if (predicate && typeof predicate === 'object') {
|
|
95
|
+
const idx = this.indexOf(predicate);
|
|
96
|
+
if (idx !== -1) {
|
|
97
|
+
this._items.splice(idx, 1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Remove all items from the list.
|
|
104
|
+
*/
|
|
105
|
+
clear() {
|
|
106
|
+
this.#ensureStaticMode('clear');
|
|
107
|
+
this._items = [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Update an existing item by key, or append if not found.
|
|
112
|
+
* @param {object} item
|
|
113
|
+
*/
|
|
114
|
+
upsert(item) {
|
|
115
|
+
this.#ensureStaticMode('upsert');
|
|
116
|
+
const key = item[this._keyProperty];
|
|
117
|
+
const idx = this._items.findIndex((i) => i[this._keyProperty] === key);
|
|
118
|
+
if (idx !== -1) {
|
|
119
|
+
this._items[idx] = item;
|
|
120
|
+
} else {
|
|
121
|
+
this._items.push(item);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Replace all items with a new array.
|
|
127
|
+
* @param {Array} items
|
|
128
|
+
*/
|
|
129
|
+
populate(items) {
|
|
130
|
+
this.#ensureStaticMode('populate');
|
|
131
|
+
this._items = Array.isArray(items) ? [...items] : [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clear and repopulate with new items.
|
|
136
|
+
* @param {Array} items
|
|
137
|
+
*/
|
|
138
|
+
repopulate(items) {
|
|
139
|
+
this.#ensureStaticMode('repopulate');
|
|
140
|
+
this.populate(items);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Merge items from another PropertyList or array.
|
|
145
|
+
* @param {PropertyList|Array} source - Source of items to merge
|
|
146
|
+
* @param {boolean} [prune=false] - If true, clear existing items first
|
|
147
|
+
*/
|
|
148
|
+
assimilate(source, prune) {
|
|
149
|
+
this.#ensureStaticMode('assimilate');
|
|
150
|
+
if (prune) {
|
|
151
|
+
this._items = [];
|
|
152
|
+
}
|
|
153
|
+
let items;
|
|
154
|
+
if (ReadOnlyPropertyList.isPropertyList(source)) {
|
|
155
|
+
items = source.all();
|
|
156
|
+
} else if (Array.isArray(source)) {
|
|
157
|
+
items = source;
|
|
158
|
+
} else {
|
|
159
|
+
items = [];
|
|
160
|
+
}
|
|
161
|
+
for (const item of items) {
|
|
162
|
+
this._items.push(item);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── Internal helpers ──────────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Find the index of a reference (key string or item object).
|
|
170
|
+
* @param {string|object} ref
|
|
171
|
+
* @returns {number}
|
|
172
|
+
*/
|
|
173
|
+
#findIndex(ref) {
|
|
174
|
+
if (typeof ref === 'string') {
|
|
175
|
+
return this._items.findIndex((i) => i[this._keyProperty] === ref);
|
|
176
|
+
}
|
|
177
|
+
if (ref && typeof ref === 'object') {
|
|
178
|
+
return this.indexOf(ref);
|
|
179
|
+
}
|
|
180
|
+
return -1;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = PropertyList;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReadOnlyPropertyList - A read-only collection data structure.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - Static mode: items stored internally in an array (for headers, query params, etc.)
|
|
6
|
+
* - Dynamic mode: a dataSource function returns fresh items on every read (for cookies)
|
|
7
|
+
*
|
|
8
|
+
* Items are plain objects with a configurable key property (keyProperty) and value property (valueProperty).
|
|
9
|
+
*
|
|
10
|
+
* This base class provides only read/search/iteration/transform methods.
|
|
11
|
+
* See PropertyList for static-mode mutation methods.
|
|
12
|
+
* See CookieList for async cookie-jar write methods.
|
|
13
|
+
*
|
|
14
|
+
* Convention:
|
|
15
|
+
* #field / #method – truly private, inaccessible to subclasses
|
|
16
|
+
* _field / _method – protected, intended for subclass access only
|
|
17
|
+
*/
|
|
18
|
+
class ReadOnlyPropertyList {
|
|
19
|
+
// ── Private fields (not accessible by subclasses) ────────────────────
|
|
20
|
+
#valueProperty;
|
|
21
|
+
#dataSource;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} options
|
|
25
|
+
* @param {string} [options.keyProperty='key'] - The property name used as the unique key
|
|
26
|
+
* @param {string} [options.valueProperty='value'] - The property name used as the value
|
|
27
|
+
* @param {Function} [options.dataSource] - Dynamic data source function (returns array of items)
|
|
28
|
+
* @param {Array} [options.items] - Initial items for static mode
|
|
29
|
+
*/
|
|
30
|
+
// Items are stored in an array (not a Map) to support positional access (idx, indexOf),
|
|
31
|
+
// ordered insertion (insert, insertAfter, prepend in PropertyList), and duplicate keys.
|
|
32
|
+
// At typical list sizes (cookies, headers) the O(n) key lookup is negligible.
|
|
33
|
+
constructor({ keyProperty = 'key', valueProperty = 'value', dataSource, items } = {}) {
|
|
34
|
+
this._keyProperty = keyProperty;
|
|
35
|
+
this.#valueProperty = valueProperty;
|
|
36
|
+
this._dynamic = typeof dataSource === 'function';
|
|
37
|
+
if (this._dynamic) {
|
|
38
|
+
this.#dataSource = dataSource;
|
|
39
|
+
} else {
|
|
40
|
+
this._items = Array.isArray(items) ? [...items] : [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns the current list of items.
|
|
46
|
+
* In dynamic mode, calls the dataSource function.
|
|
47
|
+
* In static mode, returns the internal array.
|
|
48
|
+
*/
|
|
49
|
+
#getItems() {
|
|
50
|
+
return this._dynamic ? this.#dataSource() : this._items;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Retrieval ──────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the value of an item by its key.
|
|
57
|
+
* @param {string} name
|
|
58
|
+
* @returns {*} The value property of the matching item, or undefined
|
|
59
|
+
*/
|
|
60
|
+
get(name) {
|
|
61
|
+
const items = this.#getItems();
|
|
62
|
+
// Use findLast so that duplicate keys resolve to the last entry,
|
|
63
|
+
// consistent with toObject() which also gives last-wins semantics.
|
|
64
|
+
const item = items.findLast((i) => i[this._keyProperty] === name);
|
|
65
|
+
return item ? item[this.#valueProperty] : undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get the full item object by its key.
|
|
70
|
+
* @param {string} name
|
|
71
|
+
* @returns {object|undefined}
|
|
72
|
+
*/
|
|
73
|
+
one(name) {
|
|
74
|
+
const items = this.#getItems();
|
|
75
|
+
// Use findLast so that duplicate keys resolve to the last entry,
|
|
76
|
+
// consistent with get() and toObject() which also give last-wins semantics.
|
|
77
|
+
return items.findLast((i) => i[this._keyProperty] === name);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get a cloned array of all items.
|
|
82
|
+
* @returns {Array}
|
|
83
|
+
*/
|
|
84
|
+
all() {
|
|
85
|
+
return [...this.#getItems()];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get an item by its positional index.
|
|
90
|
+
* @param {number} index
|
|
91
|
+
* @returns {object|undefined}
|
|
92
|
+
*/
|
|
93
|
+
idx(index) {
|
|
94
|
+
return this.#getItems()[index];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get the number of items.
|
|
99
|
+
* @returns {number}
|
|
100
|
+
*/
|
|
101
|
+
count() {
|
|
102
|
+
return this.#getItems().length;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get the index of an item.
|
|
107
|
+
* Uses structural equality (matching by key and value) so it works
|
|
108
|
+
* even when the item is a copy rather than the same reference.
|
|
109
|
+
* @param {object} item
|
|
110
|
+
* @returns {number} -1 if not found
|
|
111
|
+
*/
|
|
112
|
+
indexOf(item) {
|
|
113
|
+
if (!item || typeof item !== 'object') return -1;
|
|
114
|
+
const items = this.#getItems();
|
|
115
|
+
const keyProp = this._keyProperty;
|
|
116
|
+
return items.findIndex(
|
|
117
|
+
(i) => i[keyProp] === item[keyProp] && i[this.#valueProperty] === item[this.#valueProperty]
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Search ─────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Check if an item with the given key exists.
|
|
125
|
+
* If value is provided, also checks that the item's value matches.
|
|
126
|
+
* @param {string} name
|
|
127
|
+
* @param {*} [value]
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
has(name, value) {
|
|
131
|
+
const items = this.#getItems();
|
|
132
|
+
if (value !== undefined) {
|
|
133
|
+
return items.some((i) => i[this._keyProperty] === name && i[this.#valueProperty] === value);
|
|
134
|
+
}
|
|
135
|
+
return items.some((i) => i[this._keyProperty] === name);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Find the first item matching a predicate.
|
|
140
|
+
* @param {Function} predicate
|
|
141
|
+
* @returns {object|undefined}
|
|
142
|
+
*/
|
|
143
|
+
find(predicate) {
|
|
144
|
+
return this.#getItems().find(predicate);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Filter items by a predicate.
|
|
149
|
+
* @param {Function} predicate
|
|
150
|
+
* @returns {Array}
|
|
151
|
+
*/
|
|
152
|
+
filter(predicate) {
|
|
153
|
+
return this.#getItems().filter(predicate);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Iteration ──────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Iterate over each item.
|
|
160
|
+
* @param {Function} fn - Called with (item, index)
|
|
161
|
+
*/
|
|
162
|
+
each(fn) {
|
|
163
|
+
this.#getItems().forEach(fn);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Map over items.
|
|
168
|
+
* @param {Function} fn
|
|
169
|
+
* @returns {Array}
|
|
170
|
+
*/
|
|
171
|
+
map(fn) {
|
|
172
|
+
return this.#getItems().map(fn);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Reduce items.
|
|
177
|
+
* @param {Function} fn
|
|
178
|
+
* @param {*} [initialValue] - Optional initial accumulator value
|
|
179
|
+
* @returns {*}
|
|
180
|
+
*/
|
|
181
|
+
reduce(fn, ...rest) {
|
|
182
|
+
return rest.length ? this.#getItems().reduce(fn, rest[0]) : this.#getItems().reduce(fn);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── Transformation ─────────────────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Convert to a plain object { key: value }.
|
|
189
|
+
* @returns {object}
|
|
190
|
+
*/
|
|
191
|
+
toObject() {
|
|
192
|
+
const result = {};
|
|
193
|
+
for (const item of this.#getItems()) {
|
|
194
|
+
result[item[this._keyProperty]] = item[this.#valueProperty];
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Convert to a string "key=value; key2=value2".
|
|
201
|
+
* @returns {string}
|
|
202
|
+
*/
|
|
203
|
+
toString() {
|
|
204
|
+
return this.#getItems()
|
|
205
|
+
.map((i) => `${i[this._keyProperty]}=${i[this.#valueProperty]}`)
|
|
206
|
+
.join('; ');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Convert to JSON (returns the same as all()).
|
|
211
|
+
* @returns {Array}
|
|
212
|
+
*/
|
|
213
|
+
toJSON() {
|
|
214
|
+
return this.all();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Check if an object is an instance of ReadOnlyPropertyList.
|
|
219
|
+
* @param {*} obj
|
|
220
|
+
* @returns {boolean}
|
|
221
|
+
*/
|
|
222
|
+
static isPropertyList(obj) {
|
|
223
|
+
return obj instanceof ReadOnlyPropertyList;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = ReadOnlyPropertyList;
|
|
@@ -17,8 +17,8 @@ chai.use(function (chai, utils) {
|
|
|
17
17
|
// Objects created inside Node's vm.createContext() have a different Object constructor,
|
|
18
18
|
// so obj.constructor === Object fails for objects passed via res.setBody() from scripts.
|
|
19
19
|
// Note: toString check is more permissive than constructor check — custom class instances
|
|
20
|
-
const isJson = typeof obj === 'object' && obj !== null
|
|
21
|
-
&& Object.prototype.toString.call(obj) === '[object Object]';
|
|
20
|
+
const isJson = typeof obj === 'object' && obj !== null
|
|
21
|
+
&& (Array.isArray(obj) || Object.prototype.toString.call(obj) === '[object Object]');
|
|
22
22
|
|
|
23
23
|
this.assert(isJson, `expected ${utils.inspect(obj)} to be JSON`, `expected ${utils.inspect(obj)} not to be JSON`);
|
|
24
24
|
});
|
|
@@ -263,14 +263,12 @@ class AssertRuntime {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
const certsAndProxyConfig = request?.certsAndProxyConfig;
|
|
266
|
-
const bru = new Bru(
|
|
267
|
-
this.runtime,
|
|
266
|
+
const bru = new Bru({
|
|
267
|
+
runtime: this.runtime,
|
|
268
268
|
envVariables,
|
|
269
269
|
runtimeVariables,
|
|
270
270
|
processEnvVars,
|
|
271
|
-
|
|
272
|
-
undefined, // historyLogger,
|
|
273
|
-
undefined, // setVisualizations,
|
|
271
|
+
historyLogger,
|
|
274
272
|
secretVariables,
|
|
275
273
|
collectionVariables,
|
|
276
274
|
folderVariables,
|
|
@@ -278,10 +276,10 @@ class AssertRuntime {
|
|
|
278
276
|
globalEnvironmentVariables,
|
|
279
277
|
oauth2CredentialVariables,
|
|
280
278
|
iterationDetails,
|
|
281
|
-
undefined,
|
|
282
279
|
promptVariables,
|
|
283
|
-
certsAndProxyConfig
|
|
284
|
-
|
|
280
|
+
certsAndProxyConfig,
|
|
281
|
+
requestUrl: request?.url
|
|
282
|
+
});
|
|
285
283
|
const req = new BrunoRequest(request, historyLogger);
|
|
286
284
|
const res = createResponseParser(response);
|
|
287
285
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chai = require('chai');
|
|
2
2
|
const Bru = require('../bru');
|
|
3
|
+
const { VISUALIZATION_CLEAR } = require('../bru');
|
|
3
4
|
const BrunoRequest = require('../bruno-request');
|
|
4
5
|
const BrunoResponse = require('../bruno-response');
|
|
5
6
|
const { cleanJson } = require('../utils');
|
|
@@ -31,7 +32,11 @@ class ScriptRuntime {
|
|
|
31
32
|
) {
|
|
32
33
|
let visualizations = [];
|
|
33
34
|
let setVisualizations = (data) => {
|
|
34
|
-
|
|
35
|
+
if (data.type === VISUALIZATION_CLEAR) {
|
|
36
|
+
visualizations = [];
|
|
37
|
+
} else {
|
|
38
|
+
visualizations.push(data);
|
|
39
|
+
}
|
|
35
40
|
};
|
|
36
41
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
|
37
42
|
const oauth2CredentialVariables = request?.oauth2CredentialVariables || {};
|
|
@@ -43,8 +48,28 @@ class ScriptRuntime {
|
|
|
43
48
|
const assertionResults = request?.assertionResults || [];
|
|
44
49
|
const certsAndProxyConfig = request?.certsAndProxyConfig;
|
|
45
50
|
const scriptPath = request?.pathname;
|
|
46
|
-
const bru = new Bru(
|
|
47
|
-
|
|
51
|
+
const bru = new Bru({
|
|
52
|
+
runtime: this.runtime,
|
|
53
|
+
envVariables,
|
|
54
|
+
runtimeVariables,
|
|
55
|
+
processEnvVars,
|
|
56
|
+
collectionPath,
|
|
57
|
+
historyLogger,
|
|
58
|
+
setVisualizations,
|
|
59
|
+
secretVariables,
|
|
60
|
+
collectionVariables,
|
|
61
|
+
folderVariables,
|
|
62
|
+
requestVariables,
|
|
63
|
+
globalEnvironmentVariables,
|
|
64
|
+
oauth2CredentialVariables,
|
|
65
|
+
iterationDetails,
|
|
66
|
+
collectionName,
|
|
67
|
+
promptVariables,
|
|
68
|
+
certsAndProxyConfig,
|
|
69
|
+
requestUrl: request?.url,
|
|
70
|
+
onConsoleLog
|
|
71
|
+
});
|
|
72
|
+
const req = new BrunoRequest(request, historyLogger);
|
|
48
73
|
|
|
49
74
|
// extend bru with result getter methods
|
|
50
75
|
const { __brunoTestResults, test } = createBruTestResultMethods(bru, assertionResults, chai);
|
|
@@ -158,7 +183,11 @@ class ScriptRuntime {
|
|
|
158
183
|
) {
|
|
159
184
|
let visualizations = [];
|
|
160
185
|
let setVisualizations = (data) => {
|
|
161
|
-
|
|
186
|
+
if (data.type === VISUALIZATION_CLEAR) {
|
|
187
|
+
visualizations = [];
|
|
188
|
+
} else {
|
|
189
|
+
visualizations.push(data);
|
|
190
|
+
}
|
|
162
191
|
};
|
|
163
192
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
|
164
193
|
const oauth2CredentialVariables = request?.oauth2CredentialVariables || {};
|
|
@@ -170,8 +199,28 @@ class ScriptRuntime {
|
|
|
170
199
|
const assertionResults = request?.assertionResults || [];
|
|
171
200
|
const certsAndProxyConfig = request?.certsAndProxyConfig;
|
|
172
201
|
const scriptPath = request?.pathname;
|
|
173
|
-
const bru = new Bru(
|
|
174
|
-
|
|
202
|
+
const bru = new Bru({
|
|
203
|
+
runtime: this.runtime,
|
|
204
|
+
envVariables,
|
|
205
|
+
runtimeVariables,
|
|
206
|
+
processEnvVars,
|
|
207
|
+
collectionPath,
|
|
208
|
+
historyLogger,
|
|
209
|
+
setVisualizations,
|
|
210
|
+
secretVariables,
|
|
211
|
+
collectionVariables,
|
|
212
|
+
folderVariables,
|
|
213
|
+
requestVariables,
|
|
214
|
+
globalEnvironmentVariables,
|
|
215
|
+
oauth2CredentialVariables,
|
|
216
|
+
iterationDetails,
|
|
217
|
+
collectionName,
|
|
218
|
+
promptVariables,
|
|
219
|
+
certsAndProxyConfig,
|
|
220
|
+
requestUrl: request?.url,
|
|
221
|
+
onConsoleLog
|
|
222
|
+
});
|
|
223
|
+
const req = new BrunoRequest(request, historyLogger);
|
|
175
224
|
const res = new BrunoResponse(response);
|
|
176
225
|
|
|
177
226
|
// extend bru with result getter methods
|
|
@@ -40,7 +40,25 @@ class TestRuntime {
|
|
|
40
40
|
const assertionResults = request?.assertionResults || [];
|
|
41
41
|
const certsAndProxyConfig = request?.certsAndProxyConfig;
|
|
42
42
|
const scriptPath = request?.pathname;
|
|
43
|
-
const bru = new Bru(
|
|
43
|
+
const bru = new Bru({
|
|
44
|
+
runtime: this.runtime,
|
|
45
|
+
envVariables,
|
|
46
|
+
runtimeVariables,
|
|
47
|
+
processEnvVars,
|
|
48
|
+
collectionPath,
|
|
49
|
+
historyLogger,
|
|
50
|
+
secretVariables,
|
|
51
|
+
collectionVariables,
|
|
52
|
+
folderVariables,
|
|
53
|
+
requestVariables,
|
|
54
|
+
globalEnvironmentVariables,
|
|
55
|
+
oauth2CredentialVariables,
|
|
56
|
+
iterationDetails,
|
|
57
|
+
collectionName,
|
|
58
|
+
promptVariables,
|
|
59
|
+
certsAndProxyConfig,
|
|
60
|
+
requestUrl: request?.url
|
|
61
|
+
});
|
|
44
62
|
const req = new BrunoRequest(request, historyLogger);
|
|
45
63
|
const res = new BrunoResponse(response);
|
|
46
64
|
|
|
@@ -24,7 +24,7 @@ class VarsRuntime {
|
|
|
24
24
|
this.mode = props?.mode || 'developer';
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
runPostResponseVars(vars, request, response, envVariables, runtimeVariables, collectionPath, processEnvVars, historyLogger,
|
|
27
|
+
runPostResponseVars(vars, request, response, envVariables, runtimeVariables, collectionPath, processEnvVars, historyLogger, secretVariables = {}) {
|
|
28
28
|
const requestVariables = request?.requestVariables || {};
|
|
29
29
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
|
30
30
|
const oauth2CredentialVariables = request?.oauth2CredentialVariables || {};
|
|
@@ -38,7 +38,24 @@ class VarsRuntime {
|
|
|
38
38
|
|
|
39
39
|
const promptVariables = request?.promptVariables || {};
|
|
40
40
|
const certsAndProxyConfig = request?.certsAndProxyConfig;
|
|
41
|
-
const bru = new Bru(
|
|
41
|
+
const bru = new Bru({
|
|
42
|
+
runtime: this.runtime,
|
|
43
|
+
envVariables,
|
|
44
|
+
runtimeVariables,
|
|
45
|
+
processEnvVars,
|
|
46
|
+
collectionPath,
|
|
47
|
+
historyLogger,
|
|
48
|
+
secretVariables,
|
|
49
|
+
collectionVariables,
|
|
50
|
+
folderVariables,
|
|
51
|
+
requestVariables,
|
|
52
|
+
globalEnvironmentVariables,
|
|
53
|
+
oauth2CredentialVariables,
|
|
54
|
+
iterationDetails,
|
|
55
|
+
promptVariables,
|
|
56
|
+
certsAndProxyConfig,
|
|
57
|
+
requestUrl: request?.url
|
|
58
|
+
});
|
|
42
59
|
const req = new BrunoRequest(request, historyLogger);
|
|
43
60
|
const res = createResponseParser(response);
|
|
44
61
|
|
|
@@ -51,7 +68,7 @@ class VarsRuntime {
|
|
|
51
68
|
const context = {
|
|
52
69
|
...envVariables,
|
|
53
70
|
...runtimeVariables,
|
|
54
|
-
...
|
|
71
|
+
...secretVariables,
|
|
55
72
|
...bruContext
|
|
56
73
|
};
|
|
57
74
|
|
|
@@ -2,7 +2,7 @@ const rollup = require('rollup');
|
|
|
2
2
|
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
|
3
3
|
const commonjs = require('@rollup/plugin-commonjs');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const
|
|
5
|
+
const terser = require('@rollup/plugin-terser').default;
|
|
6
6
|
|
|
7
7
|
const bundleLibraries = async () => {
|
|
8
8
|
const codeScript = `
|
|
@@ -5,6 +5,7 @@ const addBrunoResponseShimToContext = require('./shims/bruno-response');
|
|
|
5
5
|
const addTestShimToContext = require('./shims/test');
|
|
6
6
|
const addLibraryShimsToContext = require('./shims/lib');
|
|
7
7
|
const addLocalModuleLoaderShimToContext = require('./shims/local-module');
|
|
8
|
+
const { getRequireCode } = require('./shims/require');
|
|
8
9
|
const { newQuickJSWASMModule, memoizePromiseFactory } = require('quickjs-emscripten');
|
|
9
10
|
|
|
10
11
|
// execute `npm run sandbox:bundle-libraries` if the below file doesn't exist
|
|
@@ -104,44 +105,11 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
|
|
|
104
105
|
await addCryptoUtilsShimToContext(vm);
|
|
105
106
|
|
|
106
107
|
const bundledCode = getBundledCode?.toString() || '';
|
|
107
|
-
const moduleLoaderCode = function () {
|
|
108
|
-
return `
|
|
109
|
-
globalThis.require = (mod) => {
|
|
110
|
-
let lib = globalThis.requireObject[mod];
|
|
111
|
-
let isModuleAPath = (module) => (module?.startsWith('.') || module?.startsWith?.(bru.cwd()))
|
|
112
|
-
if (lib) {
|
|
113
|
-
return lib;
|
|
114
|
-
}
|
|
115
|
-
else if (isModuleAPath(mod)) {
|
|
116
|
-
// fetch local module
|
|
117
|
-
let localModuleCode = globalThis.__brunoLoadLocalModule(mod);
|
|
118
|
-
|
|
119
|
-
// compile local module as iife
|
|
120
|
-
(function (){
|
|
121
|
-
const initModuleExportsCode = "const module = { exports: {} };"
|
|
122
|
-
const copyModuleExportsCode = "\\n;globalThis.requireObject[mod] = module.exports;";
|
|
123
|
-
const patchedRequire = ${`
|
|
124
|
-
"\\n;" +
|
|
125
|
-
"let require = (subModule) => isModuleAPath(subModule) ? globalThis.require(path.resolve(bru.cwd(), mod, '..', subModule)) : globalThis.require(subModule)" +
|
|
126
|
-
"\\n;"
|
|
127
|
-
`}
|
|
128
|
-
eval(initModuleExportsCode + patchedRequire + localModuleCode + copyModuleExportsCode);
|
|
129
|
-
})();
|
|
130
|
-
|
|
131
|
-
// resolve module
|
|
132
|
-
return globalThis.requireObject[mod];
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
throw new Error("Cannot find module " + mod);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
`;
|
|
139
|
-
};
|
|
140
108
|
|
|
141
109
|
vm.evalCode(
|
|
142
110
|
`
|
|
143
111
|
(${bundledCode})()
|
|
144
|
-
${
|
|
112
|
+
${getRequireCode()}
|
|
145
113
|
`
|
|
146
114
|
);
|
|
147
115
|
|