CVE-2024-34347 (published 2024-05-08T15:15Z)

@hoppscotch/cli is a CLI to run Hoppscotch Test Scripts in CI environments. Prior to 0.8.0, the @hoppscotch/js-sandbox package provides a Javascript sandbox that uses the Node.js vm module. However, the vm module is not safe for sandboxing untrusted Javascript code. This is because code inside the vm context can break out if it can get a hold of any reference to an object created outside of the vm. In the case of @hoppscotch/js-sandbox, multiple references to external objects are passed into the vm context to allow pre-request scripts interactions with environment variables and more. But this also allows the pre-request script to escape the sandbox. This vulnerability is fixed in 0.8.0.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/hoppscotch/hoppscotch
commit_details: repo_url: https://github.com/hoppscotch/hoppscotch
author: James George
author_date: 2024-04-19 08:38:46-07:00
msg: chore: migrate `Node.js` implementation for `js-sandbox` to `isolated-vm` (#3973)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
repository: repo_url: https://github.com/hoppscotch/hoppscotch
repo_name: hoppscotch/hoppscotch
description: Open source API development ecosystem - https://hoppscotch.io (open-source alternative to Postman, Insomnia)
repo_language: TypeScript
owner: hoppscotch
file_changes: filename: tests.yml
change_type: ModificationType.MODIFY
diff: @@ -17,22 +17,21 @@ jobs:
 
     steps:
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Setup environment
         run: mv .env.example .env
 
+      - name: Setup node
+        uses: actions/setup-node@v4
+        with:
+          node-version: ${{ matrix.node-version }}
+
       - name: Setup pnpm
-        uses: pnpm/action-setup@v2.2.4
+        uses: pnpm/action-setup@v3
         with:
           version: 8
           run_install: true
 
-      - name: Setup node
-        uses: actions/setup-node@v3
-        with:
-          node-version: ${{ matrix.node }}
-          cache: pnpm
-
       - name: Run tests
         run: pnpm test

programming_language: Markdown
filename: hopp.js
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,31 @@
 #!/usr/bin/env node
 // * The entry point of the CLI
+// @ts-check
 
 import { cli } from "../dist/index.js";
 
-cli(process.argv);
+import { spawnSync } from "child_process";
+import { cloneDeep } from "lodash-es";
+
+const nodeVersion = parseInt(process.versions.node.split(".")[0]);
+
+// As per isolated-vm documentation, we need to supply `--no-node-snapshot` for node >= 20
+// src: https://github.com/laverdet/isolated-vm?tab=readme-ov-file#requirements
+if (nodeVersion >= 20 && !process.execArgv.includes("--no-node-snapshot")) {
+  const argCopy = cloneDeep(process.argv);
+
+  // Replace first argument with --no-node-snapshot
+  // We can get argv[0] from process.argv0
+  argCopy[0] = "--no-node-snapshot";
+
+  const result = spawnSync(
+    process.argv0,
+    argCopy,
+    { stdio: "inherit" }
+  );
+
+  // Exit with the same status code as the spawned process
+  process.exit(result.status ?? 0);
+} else {
+  cli(process.argv);
+}

programming_language: TypeScript
filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 {
   "name": "@hoppscotch/cli",
-  "version": "0.7.0",
+  "version": "0.7.1",
   "description": "A CLI to run Hoppscotch test scripts in CI environments.",
   "homepage": "https://hoppscotch.io",
   "type": "module",
@@ -44,6 +44,7 @@
     "axios": "1.6.7",
     "chalk": "5.3.0",
     "commander": "11.1.0",
+    "isolated-vm": "4.7.2",
     "lodash-es": "4.17.21",
     "qs": "6.11.2",
     "verzod": "0.2.2",

programming_language: CoffeeScript
filename: test.spec.ts
change_type: ModificationType.MODIFY
diff: @@ -224,7 +224,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
   });
 
   describe("Secret environment variables", () => {
-    jest.setTimeout(10000);
+    jest.setTimeout(100000);
 
     // Reads secret environment values from system environment
     test("Successfully picks the values for secret environment variables from `process.env` and persists the variables set from the pre-request script", async () => {

programming_language: TypeScript
filename: coll-v1-req-v0.json
change_type: ModificationType.MODIFY
diff: @@ -1,27 +1,55 @@
 {
-    "v": 1,
-    "name": "coll-v1",
-    "folders": [],
-    "requests": [
+  "v": 1,
+  "name": "coll-v1",
+  "folders": [
+    {
+      "v": 1,
+      "name": "coll-v1-child",
+      "folders": [],
+      "requests": [
         {
-            "url": "https://httpbin.org",
-            "path": "/get",
-            "headers": [
-              { "key": "Inactive-Header", "value": "Inactive Header", "active": false },
-              { "key": "Authorization", "value": "Bearer token123", "active": true }
-            ],
-            "params": [
-              { "key": "key", "value": "value", "active": true },
-              { "key": "inactive-key", "value": "inactive-param", "active": false }
-            ],
-            "name": "req-v0",
-            "method": "GET",
-            "preRequestScript": "",
-            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})",
-            "contentType": "application/json",
-            "body": "",
-            "auth": "Bearer Token",
-            "bearerToken": "token123"
-          }
-    ]
-}
\ No newline at end of file
+          "url": "https://echo.hoppscotch.io",
+          "path": "/get",
+          "headers": [
+            { "key": "Inactive-Header", "value": "Inactive Header", "active": false },
+            { "key": "Authorization", "value": "Bearer token123", "active": true }
+          ],
+          "params": [
+            { "key": "key", "value": "value", "active": true },
+            { "key": "inactive-key", "value": "inactive-param", "active": false }
+          ],
+          "name": "req-v0-II",
+          "method": "GET",
+          "preRequestScript": "",
+          "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
+          "contentType": "application/json",
+          "body": "",
+          "auth": "Bearer Token",
+          "bearerToken": "token123"
+        }
+      ]
+    }
+  ],
+  "requests": [
+    {
+      "url": "https://echo.hoppscotch.io",
+      "path": "/get",
+      "headers": [
+        { "key": "Inactive-Header", "value": "Inactive Header", "active": false },
+        { "key": "Authorization", "value": "Bearer token123", "active": true }
+      ],
+      "params": [
+        { "key": "key", "value": "value", "active": true },
+        { "key": "inactive-key", "value": "inactive-param", "active": false }
+      ],
+      "name": "req-v0",
+      "method": "GET",
+      "preRequestScript": "",
+      "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
+      "contentType": "application/json",
+      "body": "",
+      "auth": "Bearer Token",
+      "bearerToken": "token123"
+    }
+  ]
+}

programming_language: CoffeeScript
filename: coll-v1-req-v1.json
change_type: ModificationType.MODIFY
diff: @@ -1,11 +1,60 @@
 {
     "v": 1,
     "name": "coll-v1",
-    "folders": [],
+    "folders": [
+        {
+            "v": 1,
+            "name": "coll-v1-child",
+            "folders": [],
+            "requests": [
+                {
+                    "v": "1",
+                    "endpoint": "https://echo.hoppscotch.io",
+                    "headers": [
+                        {
+                            "key": "Inactive-Header",
+                            "value": "Inactive Header",
+                            "active": false
+                        },
+                        {
+                            "key": "Authorization",
+                            "value": "Bearer token123",
+                            "active": true
+                        }
+                    ],
+                    "params": [
+                        {
+                            "key": "key",
+                            "value": "value",
+                            "active": true
+                        },
+                        {
+                            "key": "inactive-key",
+                            "value": "inactive-param",
+                            "active": false
+                        }
+                    ],
+                    "name": "req-v1-II",
+                    "method": "GET",
+                    "preRequestScript": "",
+                    "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
+                    "body": {
+                        "contentType": null,
+                        "body": null
+                    },
+                    "auth": {
+                        "authType": "bearer",
+                        "authActive": true,
+                        "token": "token123"
+                    }
+                }
+            ]
+        }
+    ],
     "requests": [
         {
             "v": "1",
-            "endpoint": "https://httpbin.org/get",
+            "endpoint": "https://echo.hoppscotch.io",
             "headers": [
                 {
                     "key": "Inactive-Header",
@@ -33,7 +82,7 @@
             "name": "req-v1",
             "method": "GET",
             "preRequestScript": "",
-            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})",
+            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
             "body": {
                 "contentType": null,
                 "body": null

programming_language: TypeScript
filename: coll-v2-req-v2.json
change_type: ModificationType.MODIFY
diff: @@ -1,11 +1,66 @@
 {
     "v": 2,
     "name": "coll-v2",
-    "folders": [],
+    "folders": [
+        {
+            "v": 2,
+            "name": "coll-v2-child",
+            "folders": [],
+            "requests": [
+                {
+                    "v": "2",
+                    "endpoint": "https://echo.hoppscotch.io",
+                    "headers": [
+                        {
+                            "key": "Inactive-Header",
+                            "value": "Inactive Header",
+                            "active": false
+                        },
+                        {
+                            "key": "Authorization",
+                            "value": "Bearer token123",
+                            "active": true
+                        }
+                    ],
+                    "params": [
+                        {
+                            "key": "key",
+                            "value": "value",
+                            "active": true
+                        },
+                        {
+                            "key": "inactive-key",
+                            "value": "inactive-param",
+                            "active": false
+                        }
+                    ],
+                    "name": "req-v2-II",
+                    "method": "GET",
+                    "preRequestScript": "",
+                    "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
+                    "body": {
+                        "contentType": null,
+                        "body": null
+                    },
+                    "auth": {
+                        "authType": "bearer",
+                        "authActive": true,
+                        "token": "token123"
+                    },
+                    "requestVariables": []
+                }
+            ],
+            "auth": {
+                "authType": "inherit",
+                "authActive": true
+            },
+            "headers": []
+        }
+    ],
     "requests": [
         {
             "v": "2",
-            "endpoint": "https://httpbin.org/get",
+            "endpoint": "https://echo.hoppscotch.io",
             "headers": [
                 {
                     "key": "Inactive-Header",
@@ -33,7 +88,7 @@
             "name": "req-v2",
             "method": "GET",
             "preRequestScript": "",
-            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})",
+            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
             "body": {
                 "contentType": null,
                 "body": null

programming_language: TypeScript
filename: coll-v2-req-v3.json
change_type: ModificationType.MODIFY
diff: @@ -1,11 +1,66 @@
 {
     "v": 2,
     "name": "coll-v2",
-    "folders": [],
+    "folders": [
+        {
+            "v": 2,
+            "name": "coll-v2-child",
+            "folders": [],
+            "requests": [
+                {
+                    "v": "3",
+                    "endpoint": "https://echo.hoppscotch.io",
+                    "headers": [
+                        {
+                            "key": "Inactive-Header",
+                            "value": "Inactive Header",
+                            "active": false
+                        },
+                        {
+                            "key": "Authorization",
+                            "value": "Bearer token123",
+                            "active": true
+                        }
+                    ],
+                    "params": [
+                        {
+                            "key": "key",
+                            "value": "value",
+                            "active": true
+                        },
+                        {
+                            "key": "inactive-key",
+                            "value": "inactive-param",
+                            "active": false
+                        }
+                    ],
+                    "name": "req-v3-II",
+                    "method": "GET",
+                    "preRequestScript": "",
+                    "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
+                    "body": {
+                        "contentType": null,
+                        "body": null
+                    },
+                    "auth": {
+                        "authType": "bearer",
+                        "authActive": true,
+                        "token": "token123"
+                    },
+                    "requestVariables": []
+                }
+            ],
+            "auth": {
+                "authType": "inherit",
+                "authActive": true
+            },
+            "headers": []
+        }
+    ],
     "requests": [
         {
             "v": "3",
-            "endpoint": "https://httpbin.org/get",
+            "endpoint": "https://echo.hoppscotch.io",
             "headers": [
                 {
                     "key": "Inactive-Header",
@@ -33,7 +88,7 @@
             "name": "req-v3",
             "method": "GET",
             "preRequestScript": "",
-            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"Authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"Inactive-Header\"]).toBe(undefined)\n})",
+            "testScript": "pw.test(\"Asserts request params\", () => {\n  pw.expect(pw.response.body.args.key).toBe(\"value\")\n  pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n  pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n  pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
             "body": {
                 "contentType": null,
                 "body": null

programming_language: TypeScript
filename: secret-envs-coll.json
change_type: ModificationType.MODIFY
diff: @@ -5,8 +5,14 @@
   "requests": [
     {
       "v": "3",
-      "auth": { "authType": "none", "authActive": true },
-      "body": { "body": null, "contentType": null },
+      "auth": {
+        "authType": "none",
+        "authActive": true
+      },
+      "body": {
+        "body": null,
+        "contentType": null
+      },
       "name": "test-secret-headers",
       "method": "GET",
       "params": [],
@@ -18,13 +24,16 @@
         }
       ],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>/headers",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n    const secretHeaderValue = pw.env.get(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.get(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
+      "endpoint": "<<echoHoppBaseURL>>/headers",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n    const secretHeaderValue = pw.env.get(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.get(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
       "preRequestScript": "const secretHeaderValueFromPreReqScript = pw.env.get(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
     },
     {
       "v": "3",
-      "auth": { "authType": "none", "authActive": true },
+      "auth": {
+        "authType": "none",
+        "authActive": true
+      },
       "body": {
         "body": "{\n  \"secretBodyKey\": \"<<secretBodyValue>>\"\n}",
         "contentType": "application/json"
@@ -34,14 +43,20 @@
       "params": [],
       "headers": [],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>/post",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n    const secretBodyValue = pw.env.get(\"secretBodyValue\")\n    pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n  \n    if (secretBodyValue) {\n      pw.expect(pw.response.body.json.secretBodyKey).toBe(secretBodyValue)\n    }\n\n    pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
+      "endpoint": "<<echoHoppBaseURL>>/post",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n    const secretBodyValue = pw.env.get(\"secretBodyValue\")\n    pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n  \n    if (secretBodyValue) {\n      pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n    }\n\n    pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
       "preRequestScript": "const secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
     },
     {
       "v": "3",
-      "auth": { "authType": "none", "authActive": true },
-      "body": { "body": null, "contentType": null },
+      "auth": {
+        "authType": "none",
+        "authActive": true
+      },
+      "body": {
+        "body": null,
+        "contentType": null
+      },
       "name": "test-secret-query-params",
       "method": "GET",
       "params": [
@@ -53,7 +68,7 @@
       ],
       "headers": [],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>/get",
+      "endpoint": "<<echoHoppBaseURL>>",
       "testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n    const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n    pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n    \n    if (secretQueryParamValue) {\n      pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n    }\n\n    pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
       "preRequestScript": "const secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
     },
@@ -65,14 +80,17 @@
         "username": "<<secretBasicAuthUsername>>",
         "authActive": true
       },
-      "body": { "body": null, "contentType": null },
+      "body": {
+        "body": null,
+        "contentType": null
+      },
       "name": "test-secret-basic-auth",
       "method": "GET",
       "params": [],
       "headers": [],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
-      "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n  \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n    pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n    pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n    if (secretBasicAuthUsername && secretBasicAuthPassword) {\n      const { authenticated, user } = pw.response.body\n      pw.expect(authenticated).toBe(true)\n      pw.expect(user).toBe(secretBasicAuthUsername)\n    }\n});",
+      "endpoint": "<<httpbinBaseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
+      "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n  \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n    pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n    pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n    // The endpoint at times results in a `502` bad gateway\n    if (pw.response.status !== 200) {\n      return\n    }\n\n    if (secretBasicAuthUsername && secretBasicAuthPassword) {\n      const { authenticated, user } = pw.response.body\n      pw.expect(authenticated).toBe(true)\n      pw.expect(user).toBe(secretBasicAuthUsername)\n    }\n});",
       "preRequestScript": ""
     },
     {
@@ -84,30 +102,42 @@
         "username": "testuser",
         "authActive": true
       },
-      "body": { "body": null, "contentType": null },
+      "body": {
+        "body": null,
+        "contentType": null
+      },
       "name": "test-secret-bearer-auth",
       "method": "GET",
       "params": [],
       "headers": [],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>/bearer",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n    const secretBearerToken = pw.env.get(\"secretBearerToken\")\n  const preReqSecretBearerToken = pw.env.get(\"preReqSecretBearerToken\")\n\n    pw.expect(secretBearerToken).toBe(\"test-token\")\n\n    if (secretBearerToken) { \n      pw.expect(pw.response.body.token).toBe(secretBearerToken)\n      pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n    }\n});",
+      "endpoint": "<<httpbinBaseURL>>/bearer",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n    const secretBearerToken = pw.env.get(\"secretBearerToken\")\n  const preReqSecretBearerToken = pw.env.get(\"preReqSecretBearerToken\")\n\n    pw.expect(secretBearerToken).toBe(\"test-token\")\n\n    // Safeguard to prevent test failures due to the endpoint\n    if (pw.response.status !== 200) {\n      return\n    }\n\n    if (secretBearerToken) { \n      pw.expect(pw.response.body.token).toBe(secretBearerToken)\n      pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n    }\n});",
       "preRequestScript": "const secretBearerToken = pw.env.get(\"secretBearerToken\")\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
     },
     {
       "v": "3",
-      "auth": { "authType": "none", "authActive": true },
-      "body": { "body": null, "contentType": null },
+      "auth": {
+        "authType": "none",
+        "authActive": true
+      },
+      "body": {
+        "body": null,
+        "contentType": null
+      },
       "name": "test-secret-fallback",
       "method": "GET",
       "params": [],
       "headers": [],
       "requestVariables": [],
-      "endpoint": "<<baseURL>>",
+      "endpoint": "<<echoHoppBaseURL>>",
       "testScript": "pw.test(\"Returns an empty string if the value for a secret environment variable is not found in the system environment\", () => {\n  pw.expect(pw.env.get(\"nonExistentValueInSystemEnv\")).toBe(\"\")\n})",
       "preRequestScript": ""
     }
   ],
-  "auth": { "authType": "inherit", "authActive": false },
+  "auth": {
+    "authType": "inherit",
+    "authActive": false
+  },
   "headers": []
-}
+}
\ No newline at end of file

programming_language: TypeScript
filename: secret-envs-persistence-coll.json
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 {
   "v": 2,
-  "name": "secret-envs-setters-coll",
+  "name": "secret-envs-persistence-coll",
   "folders": [],
   "requests": [
     {
@@ -24,8 +24,8 @@
           "active": true
         }
       ],
-      "endpoint": "<<baseURL>>/headers",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n    const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
+      "endpoint": "<<echoHoppBaseURL>>",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n    const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
       "preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
     },
     {
@@ -49,8 +49,8 @@
           "active": true
         }
       ],
-      "endpoint": "<<baseURL>>/headers",
-      "testScript": "pw.test(\"Value set at the pre-request script takes precedence\", () => {\n    const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value-overriden\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value-overriden\")\n})",
+      "endpoint": "<<echoHoppBaseURL>>",
+      "testScript": "pw.test(\"Value set at the pre-request script takes precedence\", () => {\n    const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n    pw.expect(secretHeaderValue).toBe(\"secret-header-value-overriden\")\n    \n    if (secretHeaderValue) {\n      pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n    }\n\n    pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value-overriden\")\n})",
       "preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value-overriden\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
     },
     {
@@ -68,8 +68,8 @@
       "params": [],
       "requestVariables": [],
       "headers": [],
-      "endpoint": "<<baseURL>>/post",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n    const secretBodyValue = pw.env.get(\"secretBodyValue\")\n    pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n  \n    if (secretBodyValue) {\n      pw.expect(pw.response.body.json.secretBodyKey).toBe(secretBodyValue)\n    }\n\n    pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
+      "endpoint": "<<echoHoppBaseURL>>/post",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n    const secretBodyValue = pw.env.get(\"secretBodyValue\")\n    pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n  \n    if (secretBodyValue) {\n      pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n    }\n\n    pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
       "preRequestScript": "const secretBodyValue = pw.env.get(\"secretBodyValue\")\n\nif (!secretBodyValue) { \n  pw.env.set(\"secretBodyValue\", \"secret-body-value\")\n}\n\nconst secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
     },
     {
@@ -93,7 +93,7 @@
       ],
       "requestVariables": [],
       "headers": [],
-      "endpoint": "<<baseURL>>/get",
+      "endpoint": "<<echoHoppBaseURL>>",
       "testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n    const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n    pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n    \n    if (secretQueryParamValue) {\n      pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n    }\n\n    pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
       "preRequestScript": "const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n\nif (!secretQueryParamValue) {\n  pw.env.set(\"secretQueryParamValue\", \"secret-query-param-value\")\n}\n\nconst secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
     },
@@ -114,8 +114,8 @@
       "params": [],
       "requestVariables": [],
       "headers": [],
-      "endpoint": "<<baseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
-      "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n  \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n    pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n    pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n    if (secretBasicAuthUsername && secretBasicAuthPassword) {\n      const { authenticated, user } = pw.response.body\n      pw.expect(authenticated).toBe(true)\n      pw.expect(user).toBe(secretBasicAuthUsername)\n    }\n});",
+      "endpoint": "<<httpbinBaseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
+      "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n  \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n    pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n    pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n    // The endpoint at times results in a `502` bad gateway\n    if (pw.response.status !== 200) {\n      return\n    }\n\n    if (secretBasicAuthUsername && secretBasicAuthPassword) {\n      const { authenticated, user } = pw.response.body\n      pw.expect(authenticated).toBe(true)\n      pw.expect(user).toBe(secretBasicAuthUsername)\n    }\n});",
       "preRequestScript": "let secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n\nlet secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\nif (!secretBasicAuthUsername) {\n  pw.env.set(\"secretBasicAuthUsername\", \"test-user\")\n}\n\nif (!secretBasicAuthPassword) {\n  pw.env.set(\"secretBasicAuthPassword\", \"test-pass\")\n}"
     },
     {
@@ -136,8 +136,8 @@
       "params": [],
       "requestVariables": [],
       "headers": [],
-      "endpoint": "<<baseURL>>/bearer",
-      "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n    const secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n  const preReqSecretBearerToken = pw.env.resolve(\"<<preReqSecretBearerToken>>\")\n\n    pw.expect(secretBearerToken).toBe(\"test-token\")\n\n    if (secretBearerToken) { \n      pw.expect(pw.response.body.token).toBe(secretBearerToken)\n      pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n    }\n});",
+      "endpoint": "<<httpbinBaseURL>>/bearer",
+      "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n    const secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n  const preReqSecretBearerToken = pw.env.resolve(\"<<preReqSecretBearerToken>>\")\n\n    pw.expect(secretBearerToken).toBe(\"test-token\")\n\n    // Safeguard to prevent test failures due to the endpoint\n    if (pw.response.status !== 200) {\n      return\n    }\n\n    if (secretBearerToken) { \n      pw.expect(pw.response.body.token).toBe(secretBearerToken)\n      pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n    }\n});",
       "preRequestScript": "let secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n\nif (!secretBearerToken) {\n  pw.env.set(\"secretBearerToken\", \"test-token\")\n  secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n}\n\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
     }
   ],
@@ -146,4 +146,4 @@
     "authActive": false
   },
   "headers": []
-}
+}
\ No newline at end of file

programming_language: TypeScript
filename: secret-envs-persistence-scripting-coll.json
change_type: ModificationType.MODIFY
diff: @@ -5,7 +5,7 @@
   "requests": [
     {
       "v": "3",
-      "endpoint": "https://httpbin.org/post",
+      "endpoint": "https://echo.hoppscotch.io/post",
       "name": "req",
       "params": [],
       "headers": [
@@ -18,7 +18,7 @@
       "method": "POST",
       "auth": { "authType": "none", "authActive": true },
       "preRequestScript": "pw.env.set(\"preReqVarOne\", \"pre-req-value-one\")\n\npw.env.set(\"preReqVarTwo\", \"pre-req-value-two\")\n\npw.env.set(\"customHeaderValueFromSecretVar\", \"custom-header-secret-value\")\n\npw.env.set(\"customBodyValue\", \"custom-body-value\")",
-      "testScript": "pw.test(\"Secret environment value set from the pre-request script takes precedence\", () => {\n  pw.expect(pw.env.get(\"preReqVarOne\")).toBe(\"pre-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the pre-request script\", () => {\n  pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request headers that are set in pre-request sccript\", () => {\n  pw.expect(pw.response.body.headers[\"Custom-Header\"]).toBe(\"custom-header-secret-value\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request body that are set in pre-request sccript\", () => {\n  pw.expect(pw.response.body.json.key).toBe(\"custom-body-value\")\n})\n\npw.test(\"Secret environment variable set from the post-request script takes precedence\", () => {\n  pw.env.set(\"postReqVarOne\", \"post-req-value-one\")\n  pw.expect(pw.env.get(\"postReqVarOne\")).toBe(\"post-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the post-request script\", () => {\n  pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully removes environment variables via the pw.env.unset method\", () => {\n  pw.env.unset(\"preReqVarOne\")\n  pw.env.unset(\"postReqVarTwo\")\n\n  pw.expect(pw.env.get(\"preReqVarOne\")).toBe(undefined)\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(undefined)\n})",
+      "testScript": "pw.test(\"Secret environment value set from the pre-request script takes precedence\", () => {\n  pw.expect(pw.env.get(\"preReqVarOne\")).toBe(\"pre-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the pre-request script\", () => {\n  pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request headers that are set in pre-request script\", () => {\n  pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"custom-header-secret-value\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request body that are set in pre-request script\", () => {\n  pw.expect(JSON.parse(pw.response.body.data).key).toBe(\"custom-body-value\")\n})\n\npw.test(\"Secret environment variable set from the post-request script takes precedence\", () => {\n  pw.env.set(\"postReqVarOne\", \"post-req-value-one\")\n  pw.expect(pw.env.get(\"postReqVarOne\")).toBe(\"post-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the post-request script\", () => {\n  pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully removes environment variables via the pw.env.unset method\", () => {\n  pw.env.unset(\"preReqVarOne\")\n  pw.env.unset(\"postReqVarTwo\")\n\n  pw.expect(pw.env.get(\"preReqVarOne\")).toBe(undefined)\n  pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(undefined)\n})",
       "body": {
         "contentType": "application/json",
         "body": "{\n  \"key\": \"<<customBodyValue>>\"\n}"

programming_language: TypeScript
filename: secret-envs.json
change_type: ModificationType.MODIFY
diff: @@ -32,7 +32,12 @@
       "secret": true
     },
     {
-      "key": "baseURL",
+      "key": "echoHoppBaseURL",
+      "value": "https://echo.hoppscotch.io",
+      "secret": false
+    },
+    {
+      "key": "httpbinBaseURL",
       "value": "https://httpbin.org",
       "secret": false
     }

programming_language: TypeScript
filename: secret-supplied-values-envs.json
change_type: ModificationType.MODIFY
diff: @@ -38,7 +38,12 @@
       "secret": true
     },
     {
-      "key": "baseURL",
+      "key": "echoHoppBaseURL",
+      "value": "https://echo.hoppscotch.io",
+      "secret": false
+    },
+    {
+      "key": "httpbinBaseURL",
       "value": "https://httpbin.org",
       "secret": false
     }

programming_language: TypeScript
filename: utils.ts
change_type: ModificationType.MODIFY
diff: @@ -3,15 +3,16 @@ import { resolve } from "path";
 
 import { ExecResponse } from "./types";
 
-export const runCLI = (args: string, options = {}): Promise<ExecResponse> =>
-  {
-    const CLI_PATH = resolve(__dirname, "../../bin/hopp");
-    const command = `node ${CLI_PATH} ${args}`
-
-    return new Promise((resolve) =>
-      exec(command, options, (error, stdout, stderr) => resolve({ error, stdout, stderr }))
-    );
-  }
+export const runCLI = (args: string, options = {}): Promise<ExecResponse> => {
+  const CLI_PATH = resolve(__dirname, "../../bin/hopp.js");
+  const command = `node ${CLI_PATH} ${args}`;
+
+  return new Promise((resolve) =>
+    exec(command, options, (error, stdout, stderr) =>
+      resolve({ error, stdout, stderr })
+    )
+  );
+};
 
 export const trimAnsi = (target: string) => {
   const ansiRegex =
@@ -25,12 +26,18 @@ export const getErrorCode = (out: string) => {
   return ansiTrimmedStr.split(" ")[0];
 };
 
-export const getTestJsonFilePath = (file: string, kind: "collection" | "environment") => {
+export const getTestJsonFilePath = (
+  file: string,
+  kind: "collection" | "environment"
+) => {
   const kindDir = {
     collection: "collections",
     environment: "environments",
   }[kind];
 
-  const filePath = resolve(__dirname, `../../src/__tests__/samples/${kindDir}/${file}`);
+  const filePath = resolve(
+    __dirname,
+    `../../src/__tests__/samples/${kindDir}/${file}`
+  );
   return filePath;
 };

programming_language: TypeScript
filename: index.ts
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,7 @@
 import chalk from "chalk";
 import { Command } from "commander";
 import * as E from "fp-ts/Either";
+
 import { version } from "../package.json";
 import { test } from "./commands/test";
 import { handleError } from "./handlers/error";
@@ -20,7 +21,7 @@ const CLI_AFTER_ALL_TXT = `\nFor more help, head on to ${accent(
   "https://docs.hoppscotch.io/documentation/clients/cli"
 )}`;
 
-const program = new Command()
+const program = new Command();
 
 program
   .name("hopp")

programming_language: JavaScript
filename: mutators.ts
change_type: ModificationType.MODIFY
diff: @@ -7,6 +7,41 @@ import { error } from "../types/errors";
 import { FormDataEntry } from "../types/request";
 import { isHoppErrnoException } from "./checks";
 
+const getValidRequests = (
+  collections: HoppCollection[],
+  collectionFilePath: string
+) => {
+  return collections.map((collection) => {
+    // Validate requests using zod schema
+    const requestSchemaParsedResult = z
+      .array(entityReference(HoppRESTRequest))
+      .safeParse(collection.requests);
+
+    // Handle validation errors
+    if (!requestSchemaParsedResult.success) {
+      throw error({
+        code: "MALFORMED_COLLECTION",
+        path: collectionFilePath,
+        data: "Please check the collection data.",
+      });
+    }
+
+    // Recursively validate requests in nested folders
+    if (collection.folders.length > 0) {
+      collection.folders = getValidRequests(
+        collection.folders,
+        collectionFilePath
+      );
+    }
+
+    // Return validated collection
+    return {
+      ...collection,
+      requests: requestSchemaParsedResult.data,
+    };
+  });
+};
+
 /**
  * Parses array of FormDataEntry to FormData.
  * @param values Array of FormDataEntry.
@@ -82,22 +117,5 @@ export async function parseCollectionData(
     });
   }
 
-  return collectionSchemaParsedResult.data.map((collection) => {
-    const requestSchemaParsedResult = z
-      .array(entityReference(HoppRESTRequest))
-      .safeParse(collection.requests);
-
-    if (!requestSchemaParsedResult.success) {
-      throw error({
-        code: "MALFORMED_COLLECTION",
-        path,
-        data: "Please check the collection data.",
-      });
-    }
-
-    return {
-      ...collection,
-      requests: requestSchemaParsedResult.data,
-    };
-  });
+  return getValidRequests(collectionSchemaParsedResult.data, path);
 }

programming_language: TypeScript
filename: jest.config.js
change_type: ModificationType.DELETE
diff: @@ -1,10 +0,0 @@
-export default {
-  preset: "ts-jest",
-  testEnvironment: "jsdom",
-  collectCoverage: true,
-  setupFilesAfterEnv: ["./jest.setup.ts"],
-  moduleNameMapper: {
-    "~/(.*)": "<rootDir>/src/$1",
-    "^lodash-es$": "lodash",
-  },
-}

programming_language: unknown
filename: jest.setup.ts
change_type: ModificationType.DELETE
diff: @@ -1 +0,0 @@
-require("@relmify/jest-fp-ts")

programming_language: unknown
filename: node.d.ts
change_type: ModificationType.MODIFY
diff: @@ -1,2 +1,2 @@
-export { default } from "./dist/node.d.ts"
-export * from "./dist/node.d.ts"
+export { default } from "./dist/node/index.d.ts"
+export * from "./dist/node/index.d.ts"

programming_language: TypeScript
filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -30,7 +30,7 @@
   "scripts": {
     "lint": "eslint --ext .ts,.js --ignore-path .gitignore .",
     "lintfix": "eslint --fix --ext .ts,.js --ignore-path .gitignore .",
-    "test": "pnpm exec jest",
+    "test": "vitest run",
     "build": "vite build && tsc --emitDeclarationOnly",
     "clean": "pnpm tsc --build --clean",
     "postinstall": "pnpm run build",
@@ -69,10 +69,18 @@
     "eslint-config-prettier": "8.6.0",
     "eslint-plugin-prettier": "4.2.1",
     "io-ts": "2.2.16",
-    "jest": "27.5.1",
     "prettier": "2.8.4",
     "ts-jest": "27.1.5",
     "typescript": "4.9.5",
-    "vite": "5.0.5"
+    "vite": "5.0.5",
+    "vitest": "0.34.6"
+  },
+  "peerDependencies": {
+    "isolated-vm": "4.7.2"
+  },
+  "peerDependenciesMeta": {
+    "isolated-vm": {
+      "optional": true
+    }
   }
 }
\ No newline at end of file

programming_language: CoffeeScript
filename: setupFiles.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,15 @@
+// Vitest doesn't work without globals
+// Ref: https://github.com/relmify/jest-fp-ts/issues/11
+
+import decodeMatchers from "@relmify/jest-fp-ts/dist/decodeMatchers"
+import eitherMatchers from "@relmify/jest-fp-ts/dist/eitherMatchers"
+import optionMatchers from "@relmify/jest-fp-ts/dist/optionMatchers"
+import theseMatchers from "@relmify/jest-fp-ts/dist/theseMatchers"
+import eitherOrTheseMatchers from "@relmify/jest-fp-ts/dist/eitherOrTheseMatchers"
+import { expect } from "vitest"
+
+expect.extend(decodeMatchers.matchers)
+expect.extend(eitherMatchers.matchers)
+expect.extend(optionMatchers.matchers)
+expect.extend(theseMatchers.matchers)
+expect.extend(eitherOrTheseMatchers.matchers)

programming_language: Shell
filename: base64-helper-functions.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,8 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runPreRequestScript } from "~/pre-request/node-vm"
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runPreRequestScript, runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 describe("Base64 helper functions", () => {

programming_language: TypeScript
filename: get.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,8 +1,9 @@
-import "@relmify/jest-fp-ts"
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: getResolve.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,8 +1,9 @@
-import "@relmify/jest-fp-ts"
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: resolve.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: set.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: unset.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse, TestResult } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: toBe.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,8 +1,9 @@
-import "@relmify/jest-fp-ts"
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {
@@ -23,7 +24,7 @@ describe("toBe", () => {
       return expect(
         func(
           `
-              pw.expect(2).toBe(2)
+            pw.expect(2).toBe(2)
           `,
           fakeResponse
         )()

programming_language: TypeScript
filename: toBeLevelxxx.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,8 +1,9 @@
-import "@relmify/jest-fp-ts"
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: toBeType.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: toHaveLength.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: toInclude.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: pre-request.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,6 +1,6 @@
-import "@relmify/jest-fp-ts"
+import { describe, expect, test } from "vitest"
 
-import { runPreRequestScript } from "~/pre-request/node-vm"
+import { runPreRequestScript } from "~/node"
 
 describe("runPreRequestScript", () => {
   test("returns the updated environment properly", () => {

programming_language: TypeScript
filename: shared-utils.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,4 +1,6 @@
-import { preventCyclicObjects } from "~/utils"
+import { preventCyclicObjects } from "~/shared-utils"
+
+import { describe, expect, test } from "vitest"
 
 describe("preventCyclicObjects", () => {
   test("succeeds with a simple object", () => {

programming_language: TypeScript
filename: test-runner.spec.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,9 @@
 import * as TE from "fp-ts/TaskEither"
 import { pipe } from "fp-ts/function"
 
-import { runTestScript } from "~/test-runner/node-vm"
+import { describe, expect, test } from "vitest"
+
+import { runTestScript } from "~/node"
 import { TestResponse } from "~/types"
 
 const fakeResponse: TestResponse = {

programming_language: TypeScript
filename: node.ts
change_type: ModificationType.DELETE
diff: @@ -1,2 +0,0 @@
-export * from "./pre-request/node-vm"
-export * from "./test-runner/node-vm"

programming_language: unknown
filename: index.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+export { runPreRequestScript } from "./pre-request"
+export { runTestScript } from "./test-runner"

programming_language: TypeScript
filename: pre-request.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,91 @@
+import { pipe } from "fp-ts/function"
+import * as TE from "fp-ts/lib/TaskEither"
+import { createRequire } from "module"
+
+import type ivmT from "isolated-vm"
+
+import { TestResult } from "~/types"
+import { getPreRequestScriptMethods } from "~/shared-utils"
+import { getSerializedAPIMethods } from "./utils"
+
+const nodeRequire = createRequire(import.meta.url)
+const ivm = nodeRequire("isolated-vm")
+
+export const runPreRequestScript = (
+  preRequestScript: string,
+  envs: TestResult["envs"]
+): TE.TaskEither<string, TestResult["envs"]> =>
+  pipe(
+    TE.tryCatch(
+      async () => {
+        const isolate: ivmT.Isolate = new ivm.Isolate()
+        const context = await isolate.createContext()
+        return { isolate, context }
+      },
+      (reason) => `Context initialization failed: ${reason}`
+    ),
+    TE.chain(({ isolate, context }) =>
+      pipe(
+        TE.tryCatch(
+          async () => {
+            const jail = context.global
+
+            const { pw, updatedEnvs } = getPreRequestScriptMethods(envs)
+
+            const serializedAPIMethods = getSerializedAPIMethods(pw)
+            jail.setSync("serializedAPIMethods", serializedAPIMethods, {
+              copy: true,
+            })
+
+            jail.setSync("atob", atob)
+            jail.setSync("btoa", btoa)
+
+            // Methods in the isolate context can't be invoked straightaway
+            const finalScript = `
+              const pw = new Proxy(serializedAPIMethods, {
+                get: (pwObjTarget, pwObjProp) => {
+                  const topLevelEntry = pwObjTarget[pwObjProp]
+
+                  // "pw.env" set of API methods
+                    if (topLevelEntry && typeof topLevelEntry === "object") {
+                      return new Proxy(topLevelEntry, {
+                        get: (subTarget, subProp) => {
+                          const subLevelProperty = subTarget[subProp]
+                          if (subLevelProperty && subLevelProperty.typeof === "function") {
+                            return (...args) => subLevelProperty.applySync(null, args)
+                          }
+                        },
+                      })
+                    }
+                }
+              })
+
+              ${preRequestScript}
+            `
+
+            // Create a script and compile it
+            const script = await isolate.compileScript(finalScript)
+
+            // Run the pre-request script in the provided context
+            await script.run(context)
+
+            return updatedEnvs
+          },
+          (reason) => reason
+        ),
+        TE.fold(
+          (error) => TE.left(`Script execution failed: ${error}`),
+          (result) =>
+            pipe(
+              TE.tryCatch(
+                async () => {
+                  await isolate.dispose()
+                  return result
+                },
+                (disposeError) => `Isolate disposal failed: ${disposeError}`
+              )
+            )
+        )
+      )
+    )
+  )

programming_language: TypeScript
filename: test-runner.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,217 @@
+import * as E from "fp-ts/Either"
+import * as TE from "fp-ts/TaskEither"
+import { pipe } from "fp-ts/function"
+import { createRequire } from "module"
+
+import type ivmT from "isolated-vm"
+
+import { TestResponse, TestResult } from "~/types"
+import {
+  getTestRunnerScriptMethods,
+  preventCyclicObjects,
+} from "~/shared-utils"
+import { getSerializedAPIMethods } from "./utils"
+
+const nodeRequire = createRequire(import.meta.url)
+const ivm = nodeRequire("isolated-vm")
+
+export const runTestScript = (
+  testScript: string,
+  envs: TestResult["envs"],
+  response: TestResponse
+): TE.TaskEither<string, TestResult> =>
+  pipe(
+    TE.tryCatch(
+      async () => {
+        const isolate: ivmT.Isolate = new ivm.Isolate()
+        const context = await isolate.createContext()
+        return { isolate, context }
+      },
+      (reason) => `Context initialization failed: ${reason}`
+    ),
+    TE.chain(({ isolate, context }) =>
+      pipe(
+        TE.tryCatch(
+          async () =>
+            executeScriptInContext(
+              testScript,
+              envs,
+              response,
+              isolate,
+              context
+            ),
+          (reason) => `Script execution failed: ${reason}`
+        ),
+        TE.chain((result) =>
+          TE.tryCatch(
+            async () => {
+              await isolate.dispose()
+              return result
+            },
+            (disposeReason) => `Isolate disposal failed: ${disposeReason}`
+          )
+        )
+      )
+    )
+  )
+const executeScriptInContext = (
+  testScript: string,
+  envs: TestResult["envs"],
+  response: TestResponse,
+  isolate: ivmT.Isolate,
+  context: ivmT.Context
+): Promise<TestResult> => {
+  return new Promise((resolve, reject) => {
+    // Parse response object
+    const responseObjHandle = preventCyclicObjects(response)
+    if (E.isLeft(responseObjHandle)) {
+      return reject(`Response parsing failed: ${responseObjHandle.left}`)
+    }
+
+    const jail = context.global
+
+    const { pw, testRunStack, updatedEnvs } = getTestRunnerScriptMethods(envs)
+
+    const serializedAPIMethods = getSerializedAPIMethods({
+      ...pw,
+      response: responseObjHandle.right,
+    })
+    jail.setSync("serializedAPIMethods", serializedAPIMethods, { copy: true })
+
+    jail.setSync("atob", atob)
+    jail.setSync("btoa", btoa)
+
+    jail.setSync("ivm", ivm)
+
+    // Methods in the isolate context can't be invoked straightaway
+    const finalScript = `
+    const pw = new Proxy(serializedAPIMethods, {
+      get: (pwObj, pwObjProp) => {
+        // pw.expect(), pw.env, etc.
+        const topLevelEntry = pwObj[pwObjProp]
+
+        // If the entry exists and is a function
+        // pw.expect(), pw.test(), etc.
+        if (topLevelEntry && topLevelEntry.typeof === "function") {
+          // pw.test() just involves invoking the function via "applySync()"
+          if (pwObjProp === "test") {
+            return (...args) => topLevelEntry.applySync(null, args)
+          }
+
+          // pw.expect() returns an object with matcher methods
+          return (...args) => {
+            // Invoke "pw.expect()" and get access to the object with matcher methods
+            const expectFnResult = topLevelEntry.applySync(
+              null,
+              args.map((expectVal) => {
+                if (typeof expectVal === "object") {
+                  if (expectVal === null) {
+                    return null
+                  }
+
+                  // Only arrays and objects stringified here should be parsed from the "pw.expect()" method definition
+                  // The usecase is that any JSON string supplied should be preserved
+                  // An extra "isStringifiedWithinIsolate" prop is added to indicate it has to be parsed
+
+                  if (Array.isArray(expectVal)) {
+                    return JSON.stringify({
+                      arr: expectVal,
+                      isStringifiedWithinIsolate: true,
+                    })
+                  }
+
+                  return JSON.stringify({
+                    ...expectVal,
+                    isStringifiedWithinIsolate: true,
+                  })
+                }
+
+                return expectVal
+              })
+            )
+
+            // Matcher methods that can be chained with "pw.expect()"
+            // pw.expect().toBe(), etc
+            if (expectFnResult.typeof === "object") {
+              // Access the getter that points to the negated matcher methods via "{ accessors: true }"
+              const matcherMethods = {
+                not: expectFnResult.getSync("not", { accessors: true }),
+              }
+
+              // Serialize matcher methods for use in the isolate context
+              const matcherMethodNames = [
+                "toBe",
+                "toBeLevel2xx",
+                "toBeLevel3xx",
+                "toBeLevel4xx",
+                "toBeLevel5xx",
+                "toBeType",
+                "toHaveLength",
+                "toInclude",
+              ]
+              matcherMethodNames.forEach((methodName) => {
+                matcherMethods[methodName] = expectFnResult.getSync(methodName)
+              })
+
+              return new Proxy(matcherMethods, {
+                get: (matcherMethodTarget, matcherMethodProp) => {
+                  // pw.expect().not.toBe(), etc
+                  const matcherMethodEntry = matcherMethodTarget[matcherMethodProp]
+
+                  if (matcherMethodProp === "not") {
+                    return new Proxy(matcherMethodEntry, {
+                      get: (negatedObjTarget, negatedObjprop) => {
+                        // Return the negated matcher method defn that is invoked from the test script
+                        const negatedMatcherMethodDefn = negatedObjTarget.getSync(negatedObjprop)
+                        return negatedMatcherMethodDefn
+                      },
+                    })
+                  }
+
+                  // Return the matcher method defn that is invoked from the test script
+                  return matcherMethodEntry
+                },
+              })
+            }
+          }
+        }
+
+        // "pw.env" set of API methods
+        if (typeof topLevelEntry === "object" && pwObjProp !== "response") {
+          return new Proxy(topLevelEntry, {
+            get: (subTarget, subProp) => {
+              const subLevelProperty = subTarget[subProp]
+              if (
+                subLevelProperty &&
+                subLevelProperty.typeof === "function"
+              ) {
+                return (...args) => subLevelProperty.applySync(null, args)
+              }
+            },
+          })
+        }
+
+        return topLevelEntry
+      },
+    })
+
+      ${testScript}
+    `
+
+    // Create a script and compile it
+    const script = isolate.compileScript(finalScript)
+
+    // Run the test script in the provided context
+    script
+      .then((script) => script.run(context))
+      .then(() => {
+        resolve({
+          tests: testRunStack,
+          envs: updatedEnvs,
+        })
+      })
+      .catch((error: Error) => {
+        reject(error)
+      })
+  })
+}

programming_language: TypeScript
filename: utils.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,23 @@
+import { createRequire } from "module"
+
+const nodeRequire = createRequire(import.meta.url)
+const ivm = nodeRequire("isolated-vm")
+
+// Helper function to recursively wrap methods in `ivm.Reference`
+export const getSerializedAPIMethods = (
+  namespaceObj: Record<string, unknown>
+): Record<string, unknown> => {
+  const result: Record<string, unknown> = {}
+
+  for (const [key, value] of Object.entries(namespaceObj)) {
+    if (typeof value === "object" && value !== null && !Array.isArray(value)) {
+      result[key] = getSerializedAPIMethods(value as Record<string, unknown>)
+    } else if (typeof value === "function") {
+      result[key] = new ivm.Reference(value)
+    } else {
+      result[key] = value
+    }
+  }
+
+  return result
+}

programming_language: Scala
filename: index.ts
change_type: ModificationType.DELETE
diff: @@ -1,38 +0,0 @@
-import { pipe } from "fp-ts/function"
-import * as TE from "fp-ts/lib/TaskEither"
-import { createContext, runInContext } from "vm"
-
-import { TestResult } from "~/types"
-import { getPreRequestScriptMethods } from "~/utils"
-
-export const runPreRequestScript = (
-  preRequestScript: string,
-  envs: TestResult["envs"]
-): TE.TaskEither<string, TestResult["envs"]> =>
-  pipe(
-    TE.tryCatch(
-      async () => {
-        return createContext()
-      },
-      (reason) => `Context initialization failed: ${reason}`
-    ),
-    TE.chain((context) =>
-      TE.tryCatch(
-        () =>
-          new Promise((resolve) => {
-            const { pw, updatedEnvs } = getPreRequestScriptMethods(envs)
-
-            // Expose pw to the context
-            context.pw = pw
-            context.atob = atob
-            context.btoa = btoa
-
-            // Run the pre-request script in the provided context
-            runInContext(preRequestScript, context)
-
-            resolve(updatedEnvs)
-          }),
-        (reason) => `Script execution failed: ${reason}`
-      )
-    )
-  )

programming_language: unknown
filename: shared-utils.ts
change_type: ModificationType.RENAME
diff: @@ -182,6 +182,36 @@ const getSharedMethods = (envs: TestResult["envs"]) => {
   }
 }
 
+const getResolvedExpectValue = (expectVal: any) => {
+  if (typeof expectVal !== "string") {
+    return expectVal
+  }
+
+  try {
+    const parsedExpectVal = JSON.parse(expectVal)
+
+    // Supplying non-primitive values is not permitted in the `isStringifiedWithinIsolate` property indicates that the object was stringified before executing the script from the isolate context
+    // This is done to ensure a JSON string supplied as the "expectVal" is not parsed and preserved as is
+    if (typeof parsedExpectVal === "object") {
+      if (parsedExpectVal.isStringifiedWithinIsolate !== true) {
+        return expectVal
+      }
+
+      // For an array, the contents are stored in the `arr` property
+      if (Array.isArray(parsedExpectVal.arr)) {
+        return parsedExpectVal.arr
+      }
+
+      delete parsedExpectVal.isStringifiedWithinIsolate
+      return parsedExpectVal
+    }
+
+    return expectVal
+  } catch (_) {
+    return expectVal
+  }
+}
+
 export function preventCyclicObjects(
   obj: Record<string, any>
 ): E.Left<string> | E.Right<Record<string, any>> {
@@ -215,15 +245,18 @@ export const createExpectation = (
 ) => {
   const result: Record<string, unknown> = {}
 
+  // Non-primitive values supplied are stringified in the isolate context
+  const resolvedExpectVal = getResolvedExpectValue(expectVal)
+
   const toBeFn = (expectedVal: any) => {
-    let assertion = expectVal === expectedVal
+    let assertion = resolvedExpectVal === expectedVal
 
     if (negated) {
       assertion = !assertion
     }
 
     const status = assertion ? "pass" : "fail"
-    const message = `Expected '${expectVal}' to${
+    const message = `Expected '${resolvedExpectVal}' to${
       negated ? " not" : ""
     } be '${expectedVal}'`
 
@@ -240,7 +273,7 @@ export const createExpectation = (
     rangeStart: number,
     rangeEnd: number
   ) => {
-    const parsedExpectVal = parseInt(expectVal)
+    const parsedExpectVal = parseInt(resolvedExpectVal)
 
     if (!Number.isNaN(parsedExpectVal)) {
       let assertion =
@@ -260,7 +293,7 @@ export const createExpectation = (
         message,
       })
     } else {
-      const message = `Expected ${level}-level status but could not parse value '${expectVal}'`
+      const message = `Expected ${level}-level status but could not parse value '${resolvedExpectVal}'`
       currTestStack[currTestStack.length - 1].expectResults.push({
         status: "error",
         message,
@@ -288,14 +321,14 @@ export const createExpectation = (
         "function",
       ].includes(expectedType)
     ) {
-      let assertion = typeof expectVal === expectedType
+      let assertion = typeof resolvedExpectVal === expectedType
 
       if (negated) {
         assertion = !assertion
       }
 
       const status = assertion ? "pass" : "fail"
-      const message = `Expected '${expectVal}' to${
+      const message = `Expected '${resolvedExpectVal}' to${
         negated ? " not" : ""
       } be type '${expectedType}'`
 
@@ -316,7 +349,12 @@ export const createExpectation = (
   }
 
   const toHaveLengthFn = (expectedLength: any) => {
-    if (!(Array.isArray(expectVal) || typeof expectVal === "string")) {
+    if (
+      !(
+        Array.isArray(resolvedExpectVal) ||
+        typeof resolvedExpectVal === "string"
+      )
+    ) {
       const message =
         "Expected toHaveLength to be called for an array or string"
       currTestStack[currTestStack.length - 1].expectResults.push({
@@ -328,7 +366,7 @@ export const createExpectation = (
     }
 
     if (typeof expectedLength === "number" && !Number.isNaN(expectedLength)) {
-      let assertion = expectVal.length === expectedLength
+      let assertion = resolvedExpectVal.length === expectedLength
 
       if (negated) {
         assertion = !assertion
@@ -355,7 +393,12 @@ export const createExpectation = (
   }
 
   const toIncludeFn = (needle: any) => {
-    if (!(Array.isArray(expectVal) || typeof expectVal === "string")) {
+    if (
+      !(
+        Array.isArray(resolvedExpectVal) ||
+        typeof resolvedExpectVal === "string"
+      )
+    ) {
       const message = "Expected toInclude to be called for an array or string"
       currTestStack[currTestStack.length - 1].expectResults.push({
         status: "error",
@@ -382,13 +425,13 @@ export const createExpectation = (
       return undefined
     }
 
-    let assertion = expectVal.includes(needle)
+    let assertion = resolvedExpectVal.includes(needle)
 
     if (negated) {
       assertion = !assertion
     }
 
-    const expectValPretty = JSON.stringify(expectVal)
+    const expectValPretty = JSON.stringify(resolvedExpectVal)
     const needlePretty = JSON.stringify(needle)
     const status = assertion ? "pass" : "fail"
     const message = `Expected ${expectValPretty} to${

programming_language: TypeScript
filename: index.ts
change_type: ModificationType.DELETE
diff: @@ -1,57 +0,0 @@
-import * as E from "fp-ts/Either"
-import * as TE from "fp-ts/TaskEither"
-import { pipe } from "fp-ts/function"
-import { createContext, runInContext } from "vm"
-
-import { TestResponse, TestResult } from "~/types"
-import { getTestRunnerScriptMethods, preventCyclicObjects } from "~/utils"
-
-export const runTestScript = (
-  testScript: string,
-  envs: TestResult["envs"],
-  response: TestResponse
-): TE.TaskEither<string, TestResult> =>
-  pipe(
-    TE.tryCatch(
-      async () => {
-        return createContext()
-      },
-      (reason) => `Context initialization failed: ${reason}`
-    ),
-    TE.chain((context) =>
-      TE.tryCatch(
-        () => executeScriptInContext(testScript, envs, response, context),
-        (reason) => `Script execution failed: ${reason}`
-      )
-    )
-  )
-
-const executeScriptInContext = (
-  testScript: string,
-  envs: TestResult["envs"],
-  response: TestResponse,
-  context: any
-): Promise<TestResult> => {
-  return new Promise((resolve, reject) => {
-    // Parse response object
-    const responseObjHandle = preventCyclicObjects(response)
-    if (E.isLeft(responseObjHandle)) {
-      return reject(`Response parsing failed: ${responseObjHandle.left}`)
-    }
-
-    const { pw, testRunStack, updatedEnvs } = getTestRunnerScriptMethods(envs)
-
-    // Expose pw to the context
-    context.pw = { ...pw, response: responseObjHandle.right }
-    context.atob = atob
-    context.btoa = btoa
-
-    // Run the test script in the provided context
-    runInContext(testScript, context)
-
-    resolve({
-      tests: testRunStack,
-      envs: updatedEnvs,
-    })
-  })
-}

programming_language: unknown
filename: web.ts
change_type: ModificationType.DELETE
diff: @@ -1,2 +0,0 @@
-export * from "./pre-request/web-worker"
-export * from "./test-runner/web-worker"

programming_language: unknown
filename: index.ts
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+export { runPreRequestScript } from "./pre-request"
+export { runTestScript } from "./test-runner"

programming_language: TypeScript
filename: worker.ts
change_type: ModificationType.RENAME
diff: @@ -1,7 +1,7 @@
 import * as TE from "fp-ts/TaskEither"
 
 import { TestResult } from "~/types"
-import { getPreRequestScriptMethods } from "~/utils"
+import { getPreRequestScriptMethods } from "~/shared-utils"
 
 const executeScriptInContext = (
   preRequestScript: string,

programming_language: TypeScript
filename: worker.ts
change_type: ModificationType.RENAME
diff: @@ -2,7 +2,10 @@ import * as E from "fp-ts/Either"
 import * as TE from "fp-ts/TaskEither"
 
 import { SandboxTestResult, TestResponse, TestResult } from "~/types"
-import { getTestRunnerScriptMethods, preventCyclicObjects } from "~/utils"
+import {
+  getTestRunnerScriptMethods,
+  preventCyclicObjects,
+} from "~/shared-utils"
 
 const executeScriptInContext = (
   testScript: string,

programming_language: TypeScript
filename: vite.config.ts
change_type: ModificationType.MODIFY
diff: @@ -7,16 +7,20 @@ export default defineConfig({
     emptyOutDir: true,
     lib: {
       entry: {
-        web: "./src/web.ts",
-        node: "./src/node.ts",
+        web: "./src/web/index.ts",
+        node: "./src/node/index.ts",
       },
       name: "js-sandbox",
       formats: ["es", "cjs"],
     },
     rollupOptions: {
-      external: ["vm"],
+      external: ["module"],
     },
   },
+  test: {
+    environment: "node",
+    setupFiles: ["./setupFiles.ts"],
+  },
   resolve: {
     alias: {
       "~": resolve(__dirname, "./src"),

programming_language: TypeScript
filename: web.d.ts
change_type: ModificationType.MODIFY
diff: @@ -1,2 +1,2 @@
-export { default } from "./dist/web.d.ts"
-export * from "./dist/web.d.ts"
+export { default } from "./dist/web/index.d.ts"
+export * from "./dist/web/index.d.ts"

programming_language: TypeScript
filename: pnpm-lock.yaml
change_type: ModificationType.MODIFY
diff: @@ -309,6 +309,9 @@ importers:
       commander:
         specifier: 11.1.0
         version: 11.1.0
+      isolated-vm:
+        specifier: 4.7.2
+        version: 4.7.2
       lodash-es:
         specifier: 4.17.21
         version: 4.17.21
@@ -828,6 +831,9 @@ importers:
       fp-ts:
         specifier: 2.12.1
         version: 2.12.1
+      isolated-vm:
+        specifier: 4.7.2
+        version: 4.7.2
       lodash:
         specifier: 4.17.21
         version: 4.17.21
@@ -868,9 +874,6 @@ importers:
       io-ts:
         specifier: 2.2.16
         version: 2.2.16(fp-ts@2.12.1)
-      jest:
-        specifier: 27.5.1
-        version: 27.5.1
       prettier:
         specifier: 2.8.4
         version: 2.8.4
@@ -883,6 +886,9 @@ importers:
       vite:
         specifier: 5.0.5
         version: 5.0.5(@types/node@17.0.45)(terser@5.27.0)
+      vitest:
+        specifier: 0.34.6
+        version: 0.34.6(sass@1.69.5)(terser@5.27.0)
 
   packages/hoppscotch-selfhost-desktop:
     dependencies:
@@ -3061,7 +3067,7 @@ packages:
     peerDependencies:
       vue: 3.3.9
     dependencies:
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
 
   /@codemirror/autocomplete@6.13.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.25.1)(@lezer/common@1.2.1):
     resolution: {integrity: sha512-SuDrho1klTINfbcMPnyro1ZxU9xJtwDMtb62R8TjL/tOl71IoOsvBo1a9x+hDvHhIzkTcJHy2VC+rmpGgYkRSw==}
@@ -6120,7 +6126,7 @@ packages:
     peerDependencies:
       vue: 3.3.9
     dependencies:
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
 
   /@humanwhocodes/config-array@0.11.14:
     resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
@@ -8396,7 +8402,7 @@ packages:
   /@types/graceful-fs@4.1.5:
     resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==}
     dependencies:
-      '@types/node': 18.18.8
+      '@types/node': 17.0.45
     dev: true
 
   /@types/har-format@1.2.15:
@@ -9621,7 +9627,7 @@ packages:
       regenerator-runtime: 0.13.11
       systemjs: 6.14.2
       terser: 5.27.0
-      vite: 3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.27.0)
+      vite: 3.2.4(@types/node@17.0.27)(terser@5.27.0)
 
   /@vitejs/plugin-legacy@2.3.0(terser@5.27.0)(vite@4.5.0):
     resolution: {integrity: sha512-Bh62i0gzQvvT8AeAAb78nOnqSYXypkRmQmOTImdPZ39meHR9e2une3AIFmVo4s1SDmcmJ6qj18Sa/lRc/14KaA==}
@@ -10143,7 +10149,7 @@ packages:
       '@types/web-bluetooth': 0.0.14
       '@vueuse/metadata': 8.7.5
       '@vueuse/shared': 8.7.5(vue@3.3.9)
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
       vue-demi: 0.14.6(vue@3.3.9)
 
   /@vueuse/core@9.12.0(vue@3.3.9):
@@ -10202,7 +10208,7 @@ packages:
       vue:
         optional: true
     dependencies:
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
       vue-demi: 0.14.6(vue@3.3.9)
 
   /@vueuse/shared@9.12.0(vue@3.3.9):
@@ -11120,7 +11126,6 @@ packages:
       buffer: 5.7.1
       inherits: 2.0.4
       readable-stream: 3.6.0
-    dev: true
 
   /blob@0.0.5:
     resolution: {integrity: sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==}
@@ -11257,7 +11262,6 @@ packages:
     dependencies:
       base64-js: 1.5.1
       ieee754: 1.2.1
-    dev: true
 
   /buffer@6.0.3:
     resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
@@ -11519,6 +11523,10 @@ packages:
     optionalDependencies:
       fsevents: 2.3.3
 
+  /chownr@1.1.4:
+    resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+    dev: false
+
   /chownr@2.0.0:
     resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
     engines: {node: '>=10'}
@@ -12233,6 +12241,13 @@ packages:
     resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
     dev: true
 
+  /decompress-response@6.0.0:
+    resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      mimic-response: 3.1.0
+    dev: false
+
   /dedent@0.7.0:
     resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
     dev: true
@@ -12627,7 +12642,6 @@ packages:
     resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
     dependencies:
       once: 1.4.0
-    dev: true
 
   /engine.io-client@3.5.3:
     resolution: {integrity: sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==}
@@ -13991,6 +14005,11 @@ packages:
     engines: {node: '>= 0.8.0'}
     dev: true
 
+  /expand-template@2.0.3:
+    resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
+    engines: {node: '>=6'}
+    dev: false
+
   /expect@27.5.1:
     resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==}
     engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@@ -14409,6 +14428,10 @@ packages:
     resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
     dev: false
 
+  /fs-constants@1.0.0:
+    resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+    dev: false
+
   /fs-extra@10.1.0:
     resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
     engines: {node: '>=12'}
@@ -14592,6 +14615,10 @@ packages:
       through2: 4.0.2
     dev: true
 
+  /github-from-package@0.0.0:
+    resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+    dev: false
+
   /glob-parent@5.1.2:
     resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
     engines: {node: '>= 6'}
@@ -15969,6 +15996,14 @@ packages:
   /isexe@2.0.0:
     resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
 
+  /isolated-vm@4.7.2:
+    resolution: {integrity: sha512-JVEs5gzWObzZK5+OlBplCdYSpokMcdhLSs/xWYYxmYWVfOOFF4oZJsYh7E/FmfX8e7gMioXMpMMeEyX1afuKrg==}
+    engines: {node: '>=16.0.0'}
+    requiresBuild: true
+    dependencies:
+      prebuild-install: 7.1.2
+    dev: false
+
   /isomorphic-fetch@3.0.0:
     resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==}
     dependencies:
@@ -16954,7 +16989,7 @@ packages:
       jest-util: 27.5.1
       natural-compare: 1.4.0
       pretty-format: 27.5.1
-      semver: 7.5.4
+      semver: 7.6.0
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -17099,7 +17134,7 @@ packages:
     resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
     engines: {node: '>= 10.13.0'}
     dependencies:
-      '@types/node': 18.18.8
+      '@types/node': 17.0.45
       merge-stream: 2.0.0
       supports-color: 8.1.1
     dev: true
@@ -18004,6 +18039,11 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
+  /mimic-response@3.1.0:
+    resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
+    engines: {node: '>=10'}
+    dev: false
+
   /min-indent@1.0.1:
     resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
     engines: {node: '>=4'}
@@ -18446,6 +18486,10 @@ packages:
       - encoding
     dev: false
 
+  /mkdirp-classic@0.5.3:
+    resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+    dev: false
+
   /mkdirp@0.5.6:
     resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
     hasBin: true
@@ -18548,6 +18592,10 @@ packages:
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
 
+  /napi-build-utils@1.0.2:
+    resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
+    dev: false
+
   /natural-compare-lite@1.4.0:
     resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
     dev: true
@@ -18582,6 +18630,13 @@ packages:
       lower-case: 2.0.2
       tslib: 2.6.2
 
+  /node-abi@3.57.0:
+    resolution: {integrity: sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==}
+    engines: {node: '>=10'}
+    dependencies:
+      semver: 7.6.0
+    dev: false
+
   /node-abort-controller@3.1.1:
     resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
 
@@ -19457,6 +19512,25 @@ packages:
       punycode: 2.3.0
     dev: false
 
+  /prebuild-install@7.1.2:
+    resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      detect-libc: 2.0.1
+      expand-template: 2.0.3
+      github-from-package: 0.0.0
+      minimist: 1.2.6
+      mkdirp-classic: 0.5.3
+      napi-build-utils: 1.0.2
+      node-abi: 3.57.0
+      pump: 3.0.0
+      rc: 1.2.8
+      simple-get: 4.0.1
+      tar-fs: 2.1.1
+      tunnel-agent: 0.6.0
+    dev: false
+
   /prelude-ls@1.1.2:
     resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
     engines: {node: '>= 0.8.0'}
@@ -19819,7 +19893,6 @@ packages:
     dependencies:
       end-of-stream: 1.4.4
       once: 1.4.0
-    dev: true
 
   /punycode@1.4.1:
     resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
@@ -20577,7 +20650,6 @@ packages:
     hasBin: true
     dependencies:
       lru-cache: 6.0.0
-    dev: true
 
   /send@0.18.0:
     resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
@@ -20747,6 +20819,18 @@ packages:
     resolution: {integrity: sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==}
     dev: true
 
+  /simple-concat@1.0.1:
+    resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+    dev: false
+
+  /simple-get@4.0.1:
+    resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
+    dependencies:
+      decompress-response: 6.0.0
+      once: 1.4.0
+      simple-concat: 1.0.1
+    dev: false
+
   /sirv@2.0.3:
     resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
     engines: {node: '>= 10'}
@@ -21467,6 +21551,26 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
+  /tar-fs@2.1.1:
+    resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+    dependencies:
+      chownr: 1.1.4
+      mkdirp-classic: 0.5.3
+      pump: 3.0.0
+      tar-stream: 2.2.0
+    dev: false
+
+  /tar-stream@2.2.0:
+    resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+    engines: {node: '>=6'}
+    dependencies:
+      bl: 4.1.0
+      end-of-stream: 1.4.4
+      fs-constants: 1.0.0
+      inherits: 2.0.4
+      readable-stream: 3.6.0
+    dev: false
+
   /tar@6.1.13:
     resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
     engines: {node: '>=10'}
@@ -22137,6 +22241,12 @@ packages:
       typescript: 4.9.5
     dev: true
 
+  /tunnel-agent@0.6.0:
+    resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+    dependencies:
+      safe-buffer: 5.2.1
+    dev: false
+
   /type-check@0.3.2:
     resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
     engines: {node: '>= 0.8.0'}
@@ -23031,7 +23141,7 @@ packages:
       '@types/eslint': 8.56.2
       eslint: 8.57.0
       rollup: 2.79.1
-      vite: 3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.27.0)
+      vite: 3.2.4(@types/node@17.0.27)(terser@5.27.0)
 
   /vite-plugin-eslint@1.8.1(eslint@8.57.0)(vite@4.5.0):
     resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
@@ -23325,6 +23435,40 @@ packages:
       - supports-color
     dev: true
 
+  /vite@3.2.4(@types/node@17.0.27)(terser@5.27.0):
+    resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': '>= 14'
+      less: '*'
+      sass: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      less:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+    dependencies:
+      '@types/node': 17.0.27
+      esbuild: 0.15.18
+      postcss: 8.4.32
+      resolve: 1.22.8
+      rollup: 2.79.1
+      terser: 5.27.0
+    optionalDependencies:
+      fsevents: 2.3.3
+
   /vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.27.0):
     resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==}
     engines: {node: ^14.18.0 || >=16.0.0}
@@ -23746,7 +23890,7 @@ packages:
       '@vue/composition-api':
         optional: true
     dependencies:
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
 
   /vue-eslint-parser@9.3.1(eslint@8.47.0):
     resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==}
@@ -23978,7 +24122,7 @@ packages:
       vue: 3.3.9
     dependencies:
       sortablejs: 1.14.0
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.9(typescript@4.9.5)
 
   /w3c-hr-time@1.0.2:
     resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
@@ -24462,6 +24606,7 @@ packages:
 
   /workbox-google-analytics@6.6.0:
     resolution: {integrity: sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==}
+    deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
     dependencies:
       workbox-background-sync: 6.6.0
       workbox-core: 6.6.0
@@ -24471,6 +24616,7 @@ packages:
 
   /workbox-google-analytics@7.0.0:
     resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
+    deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
     dependencies:
       workbox-background-sync: 7.0.0
       workbox-core: 7.0.0

programming_language: CoffeeScript