@usebruno/js 0.43.0 → 0.45.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.
@@ -0,0 +1,42 @@
1
+ const path = require('node:path');
2
+ const nodeModule = require('node:module');
3
+
4
+ /**
5
+ * Check if a module is a Node.js builtin
6
+ * @param {string} moduleName - Module name to check
7
+ * @returns {boolean} True if module is a builtin
8
+ */
9
+ function isBuiltinModule(moduleName) {
10
+ const normalized = moduleName.startsWith('node:') ? moduleName.slice(5) : moduleName;
11
+ return nodeModule.builtinModules.includes(normalized);
12
+ }
13
+
14
+ /**
15
+ * Validate that a path is within allowed context roots
16
+ * @param {string} normalizedPath - Normalized file path
17
+ * @param {Array<string>} additionalContextRootsAbsolute - Allowed roots
18
+ * @returns {boolean} True if path is within allowed roots
19
+ */
20
+ function isPathWithinAllowedRoots(normalizedPath, additionalContextRootsAbsolute) {
21
+ return additionalContextRootsAbsolute.some((allowedRoot) => {
22
+ const normalizedAllowedRoot = path.normalize(allowedRoot);
23
+ const relativePath = path.relative(normalizedAllowedRoot, normalizedPath);
24
+ return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
25
+ });
26
+ }
27
+
28
+ class ScriptError extends Error {
29
+ constructor(error, script) {
30
+ super(error.message);
31
+ this.name = 'ScriptError';
32
+ this.originalError = error;
33
+ this.script = script;
34
+ this.stack = error.stack;
35
+ }
36
+ }
37
+
38
+ module.exports = {
39
+ isBuiltinModule,
40
+ isPathWithinAllowedRoots,
41
+ ScriptError
42
+ };
@@ -24,7 +24,7 @@ const toNumber = (value) => {
24
24
  };
25
25
 
26
26
  const removeQuotes = (str) => {
27
- if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
27
+ if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith('\'') && str.endsWith('\''))) {
28
28
  return str.slice(1, -1);
29
29
  }
30
30
  return str;
@@ -36,7 +36,7 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
36
36
  }
37
37
  externalScript = externalScript?.trim();
38
38
 
39
- if(scriptType === 'template-literal') {
39
+ if (scriptType === 'template-literal') {
40
40
  if (!isNaN(Number(externalScript))) {
41
41
  const number = Number(externalScript);
42
42
 
@@ -24,6 +24,12 @@ const addBruShimToContext = (vm, bru) => {
24
24
  vm.setProp(bruObject, 'getCollectionName', getCollectionName);
25
25
  getCollectionName.dispose();
26
26
 
27
+ let isSafeMode = vm.newFunction('isSafeMode', function () {
28
+ return marshallToVm(bru.isSafeMode(), vm);
29
+ });
30
+ vm.setProp(bruObject, 'isSafeMode', isSafeMode);
31
+ isSafeMode.dispose();
32
+
27
33
  let getProcessEnv = vm.newFunction('getProcessEnv', function (key) {
28
34
  return marshallToVm(bru.getProcessEnv(vm.dump(key)), vm);
29
35
  });
@@ -341,7 +347,7 @@ const addBruShimToContext = (vm, bru) => {
341
347
  const promise = vm.newPromise();
342
348
  const dumpedUrl = vm.dump(url);
343
349
  const dumpedNameOrObj = vm.dump(nameOrCookieObj);
344
-
350
+
345
351
  // Check if the second argument is an object (cookie object case)
346
352
  if (typeof dumpedNameOrObj === 'object' && dumpedNameOrObj !== null) {
347
353
  // Cookie object case: setCookie(url, cookieObject, callback)
@@ -363,7 +369,7 @@ const addBruShimToContext = (vm, bru) => {
363
369
  }
364
370
  });
365
371
  }
366
-
372
+
367
373
  promise.settled.then(vm.runtime.executePendingJobs);
368
374
  return promise.handle;
369
375
  });
@@ -371,7 +377,7 @@ const addBruShimToContext = (vm, bru) => {
371
377
 
372
378
  const _setCookiesFn = vm.newFunction('_setCookies', (url, cookiesArray) => {
373
379
  const promise = vm.newPromise();
374
-
380
+
375
381
  nativeJar.setCookies(vm.dump(url), vm.dump(cookiesArray), (err) => {
376
382
  if (err) {
377
383
  promise.reject(marshallToVm(cleanJson(err), vm));
@@ -9,6 +9,7 @@ const addBrunoRequestShimToContext = (vm, req) => {
9
9
  const body = marshallToVm(req.getBody(), vm);
10
10
  const timeout = marshallToVm(req.getTimeout(), vm);
11
11
  const name = marshallToVm(req.getName(), vm);
12
+ const pathParams = marshallToVm(req.getPathParams(), vm);
12
13
  const tags = marshallToVm(req.getTags(), vm);
13
14
 
14
15
  vm.setProp(reqObject, 'url', url);
@@ -17,6 +18,7 @@ const addBrunoRequestShimToContext = (vm, req) => {
17
18
  vm.setProp(reqObject, 'body', body);
18
19
  vm.setProp(reqObject, 'timeout', timeout);
19
20
  vm.setProp(reqObject, 'name', name);
21
+ vm.setProp(reqObject, 'pathParams', pathParams);
20
22
  vm.setProp(reqObject, 'tags', tags);
21
23
 
22
24
  url.dispose();
@@ -25,6 +27,7 @@ const addBrunoRequestShimToContext = (vm, req) => {
25
27
  body.dispose();
26
28
  timeout.dispose();
27
29
  name.dispose();
30
+ pathParams.dispose();
28
31
  tags.dispose();
29
32
 
30
33
  let getUrl = vm.newFunction('getUrl', function () {
@@ -39,6 +42,24 @@ const addBrunoRequestShimToContext = (vm, req) => {
39
42
  vm.setProp(reqObject, 'setUrl', setUrl);
40
43
  setUrl.dispose();
41
44
 
45
+ let getHost = vm.newFunction('getHost', function () {
46
+ return marshallToVm(req.getHost(), vm);
47
+ });
48
+ vm.setProp(reqObject, 'getHost', getHost);
49
+ getHost.dispose();
50
+
51
+ let getPath = vm.newFunction('getPath', function () {
52
+ return marshallToVm(req.getPath(), vm);
53
+ });
54
+ vm.setProp(reqObject, 'getPath', getPath);
55
+ getPath.dispose();
56
+
57
+ let getQueryString = vm.newFunction('getQueryString', function () {
58
+ return marshallToVm(req.getQueryString(), vm);
59
+ });
60
+ vm.setProp(reqObject, 'getQueryString', getQueryString);
61
+ getQueryString.dispose();
62
+
42
63
  let getMethod = vm.newFunction('getMethod', function () {
43
64
  return marshallToVm(req.getMethod(), vm);
44
65
  });
@@ -57,6 +78,12 @@ const addBrunoRequestShimToContext = (vm, req) => {
57
78
  vm.setProp(reqObject, 'getName', getName);
58
79
  getName.dispose();
59
80
 
81
+ let getPathParams = vm.newFunction('getPathParams', function () {
82
+ return marshallToVm(req.getPathParams(), vm);
83
+ });
84
+ vm.setProp(reqObject, 'getPathParams', getPathParams);
85
+ getPathParams.dispose();
86
+
60
87
  let setMethod = vm.newFunction('setMethod', function (method) {
61
88
  req.setMethod(vm.dump(method));
62
89
  });
@@ -10,7 +10,7 @@ const addCryptoUtilsShimToContext = async (vm) => {
10
10
  let randomBytesHandle = vm.newFunction('randomBytes', function (sizeHandle) {
11
11
  try {
12
12
  let size = vm.dump(sizeHandle);
13
-
13
+
14
14
  if (typeof size !== 'number') {
15
15
  throw new TypeError('The "size" argument must be of type number');
16
16
  }
@@ -30,15 +30,14 @@ const addCryptoUtilsShimToContext = async (vm) => {
30
30
  }
31
31
 
32
32
  const buffer = crypto.randomBytes(size);
33
-
33
+
34
34
  const byteArray = Array.from(buffer);
35
-
35
+
36
36
  return marshallToVm(byteArray, vm);
37
-
38
37
  } catch (error) {
39
38
  const vmError = vm.newError(error.message);
40
39
  vm.setProp(vmError, 'name', vm.newString(error.name));
41
-
40
+
42
41
  throw vmError;
43
42
  }
44
43
  });
@@ -48,7 +47,7 @@ const addCryptoUtilsShimToContext = async (vm) => {
48
47
  // Receive the serialized array data directly
49
48
  const serializedArray = vm.dump(arrayHandle);
50
49
  const typedArray = deserializeTypedArray(serializedArray);
51
-
50
+
52
51
  if (typedArray.length === 0) {
53
52
  return marshallToVm([], vm);
54
53
  }
@@ -62,11 +61,10 @@ const addCryptoUtilsShimToContext = async (vm) => {
62
61
  const byteArray = Array.from(typedArray);
63
62
 
64
63
  return marshallToVm(byteArray, vm);
65
-
66
64
  } catch (error) {
67
65
  const vmError = vm.newError(error.message);
68
66
  vm.setProp(vmError, 'name', vm.newString(error.name));
69
-
67
+
70
68
  throw vmError;
71
69
  }
72
70
  });
@@ -101,4 +99,4 @@ const addCryptoUtilsShimToContext = async (vm) => {
101
99
  `);
102
100
  };
103
101
 
104
- module.exports = addCryptoUtilsShimToContext;
102
+ module.exports = addCryptoUtilsShimToContext;
@@ -27,7 +27,7 @@ describe('crypto-utils shims tests', () => {
27
27
  const handle = vm.unwrapResult(result);
28
28
  const type = vm.dump(handle);
29
29
  handle.dispose();
30
-
30
+
31
31
  expect(type).toBe('function');
32
32
  });
33
33
 
@@ -36,7 +36,7 @@ describe('crypto-utils shims tests', () => {
36
36
  const handle = vm.unwrapResult(result);
37
37
  const type = vm.dump(handle);
38
38
  handle.dispose();
39
-
39
+
40
40
  expect(type).toBe('function');
41
41
  });
42
42
 
@@ -45,7 +45,7 @@ describe('crypto-utils shims tests', () => {
45
45
  const handle = vm.unwrapResult(result);
46
46
  const length = vm.dump(handle);
47
47
  handle.dispose();
48
-
48
+
49
49
  expect(length).toBe(8);
50
50
  });
51
51
 
@@ -54,7 +54,7 @@ describe('crypto-utils shims tests', () => {
54
54
  const handle = vm.unwrapResult(result);
55
55
  const hexLength = vm.dump(handle);
56
56
  handle.dispose();
57
-
57
+
58
58
  expect(hexLength).toBe(8); // 4 bytes = 8 hex chars
59
59
  });
60
60
 
@@ -67,7 +67,7 @@ describe('crypto-utils shims tests', () => {
67
67
  const handle = vm.unwrapResult(result);
68
68
  const length = vm.dump(handle);
69
69
  handle.dispose();
70
-
70
+
71
71
  expect(length).toBe(5);
72
72
  });
73
- });
73
+ });
@@ -45,4 +45,4 @@ function deserializeTypedArray(obj) {
45
45
  module.exports = {
46
46
  serializeTypedArray,
47
47
  deserializeTypedArray
48
- }
48
+ };
@@ -7,7 +7,7 @@ const getResultsSummary = (results) => {
7
7
  total: results.length,
8
8
  passed: 0,
9
9
  failed: 0,
10
- skipped: 0,
10
+ skipped: 0
11
11
  };
12
12
 
13
13
  results.forEach((r) => {
@@ -34,7 +34,7 @@ const setupBruTestMethods = (bru, __brunoTestResults, assertionResults) => {
34
34
  const summary = getResultsSummary(results);
35
35
  return {
36
36
  summary,
37
- results: results.map(r => ({
37
+ results: results.map((r) => ({
38
38
  status: r.status,
39
39
  description: r.description,
40
40
  expected: r.expected,
@@ -49,7 +49,7 @@ const setupBruTestMethods = (bru, __brunoTestResults, assertionResults) => {
49
49
  const summary = getResultsSummary(results);
50
50
  return {
51
51
  summary,
52
- results: results.map(r => ({
52
+ results: results.map((r) => ({
53
53
  status: r.status,
54
54
  lhsExpr: r.lhsExpr,
55
55
  rhsExpr: r.rhsExpr,
@@ -77,4 +77,4 @@ module.exports = {
77
77
  getResultsSummary,
78
78
  createBruTestResultMethods,
79
79
  setupBruTestMethods
80
- };
80
+ };
package/src/utils.js CHANGED
@@ -90,7 +90,7 @@ const evaluateJsTemplateLiteral = (templateLiteral, context) => {
90
90
  return templateLiteral.slice(1, -1);
91
91
  }
92
92
 
93
- if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) {
93
+ if (templateLiteral.startsWith('\'') && templateLiteral.endsWith('\'')) {
94
94
  return templateLiteral.slice(1, -1);
95
95
  }
96
96
 
@@ -129,7 +129,7 @@ const createResponseParser = (response = {}) => {
129
129
  };
130
130
 
131
131
  /**
132
- * Objects that are created inside vm2 execution context result in an serialization error when sent to the renderer process
132
+ * Objects that are created inside developer mode execution context result in an serialization error when sent to the renderer process
133
133
  * Error sending from webFrameMain: Error: Failed to serialize arguments
134
134
  * at s.send (node:electron/js2c/browser_init:169:631)
135
135
  * at g.send (node:electron/js2c/browser_init:165:2156)
@@ -201,7 +201,7 @@ const uuid = () => {
201
201
  const customNanoId = customAlphabet(urlAlphabet, 21);
202
202
 
203
203
  return customNanoId();
204
- }
204
+ };
205
205
 
206
206
  const appendAwaitToTestFunc = (str) => {
207
207
  return str.replace(/(?<!\.\s*)(?<!await\s)(test\()/g, 'await $1');
@@ -211,18 +211,18 @@ const cleanCircularJson = (data) => {
211
211
  try {
212
212
  // Handle circular references by keeping track of seen objects
213
213
  const seen = new WeakSet();
214
-
214
+
215
215
  const replacer = (key, value) => {
216
216
  // Skip non-objects and null
217
217
  if (typeof value !== 'object' || value === null) {
218
218
  return value;
219
219
  }
220
-
220
+
221
221
  // Detect circular reference
222
222
  if (seen.has(value)) {
223
223
  return '[Circular Reference]';
224
224
  }
225
-
225
+
226
226
  seen.add(value);
227
227
  return value;
228
228
  };