chore: migrate Node.js implementation for js-sandbox to isolated-vm (#3973)
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
2
packages/hoppscotch-js-sandbox/src/web/index.ts
Normal file
2
packages/hoppscotch-js-sandbox/src/web/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { runPreRequestScript } from "./pre-request"
|
||||
export { runTestScript } from "./test-runner"
|
||||
24
packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts
Normal file
24
packages/hoppscotch-js-sandbox/src/web/pre-request/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import * as E from "fp-ts/Either"
|
||||
|
||||
import { TestResult } from "~/types"
|
||||
|
||||
import Worker from "./worker?worker&inline"
|
||||
|
||||
export const runPreRequestScript = (
|
||||
preRequestScript: string,
|
||||
envs: TestResult["envs"]
|
||||
): Promise<E.Either<string, TestResult["envs"]>> =>
|
||||
new Promise((resolve) => {
|
||||
const worker = new Worker()
|
||||
|
||||
// Listen for the results from the web worker
|
||||
worker.addEventListener("message", (event: MessageEvent) =>
|
||||
resolve(event.data.results)
|
||||
)
|
||||
|
||||
// Send the script to the web worker
|
||||
worker.postMessage({
|
||||
preRequestScript,
|
||||
envs,
|
||||
})
|
||||
})
|
||||
33
packages/hoppscotch-js-sandbox/src/web/pre-request/worker.ts
Normal file
33
packages/hoppscotch-js-sandbox/src/web/pre-request/worker.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
|
||||
import { TestResult } from "~/types"
|
||||
import { getPreRequestScriptMethods } from "~/shared-utils"
|
||||
|
||||
const executeScriptInContext = (
|
||||
preRequestScript: string,
|
||||
envs: TestResult["envs"]
|
||||
): TE.TaskEither<string, TestResult["envs"]> => {
|
||||
try {
|
||||
const { pw, updatedEnvs } = getPreRequestScriptMethods(envs)
|
||||
|
||||
// Create a function from the pre request script using the `Function` constructor
|
||||
const executeScript = new Function("pw", preRequestScript)
|
||||
|
||||
// Execute the script
|
||||
executeScript(pw)
|
||||
|
||||
return TE.right(updatedEnvs)
|
||||
} catch (error) {
|
||||
return TE.left(`Script execution failed: ${(error as Error).message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for messages from the main thread
|
||||
self.addEventListener("message", async (event) => {
|
||||
const { preRequestScript, envs } = event.data
|
||||
|
||||
const results = await executeScriptInContext(preRequestScript, envs)()
|
||||
|
||||
// Post the result back to the main thread
|
||||
self.postMessage({ results })
|
||||
})
|
||||
27
packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts
Normal file
27
packages/hoppscotch-js-sandbox/src/web/test-runner/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as E from "fp-ts/Either"
|
||||
|
||||
import { SandboxTestResult, TestResponse, TestResult } from "~/types"
|
||||
|
||||
import Worker from "./worker?worker&inline"
|
||||
|
||||
export const runTestScript = (
|
||||
testScript: string,
|
||||
envs: TestResult["envs"],
|
||||
response: TestResponse
|
||||
): Promise<E.Either<string, SandboxTestResult>> => {
|
||||
return new Promise((resolve) => {
|
||||
const worker = new Worker()
|
||||
|
||||
// Listen for the results from the web worker
|
||||
worker.addEventListener("message", (event: MessageEvent) =>
|
||||
resolve(event.data.results)
|
||||
)
|
||||
|
||||
// Send the script to the web worker
|
||||
worker.postMessage({
|
||||
testScript,
|
||||
envs,
|
||||
response,
|
||||
})
|
||||
})
|
||||
}
|
||||
46
packages/hoppscotch-js-sandbox/src/web/test-runner/worker.ts
Normal file
46
packages/hoppscotch-js-sandbox/src/web/test-runner/worker.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as E from "fp-ts/Either"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
|
||||
import { SandboxTestResult, TestResponse, TestResult } from "~/types"
|
||||
import {
|
||||
getTestRunnerScriptMethods,
|
||||
preventCyclicObjects,
|
||||
} from "~/shared-utils"
|
||||
|
||||
const executeScriptInContext = (
|
||||
testScript: string,
|
||||
envs: TestResult["envs"],
|
||||
response: TestResponse
|
||||
): TE.TaskEither<string, SandboxTestResult> => {
|
||||
try {
|
||||
const responseObjHandle = preventCyclicObjects(response)
|
||||
if (E.isLeft(responseObjHandle)) {
|
||||
return TE.left(`Response marshalling failed: ${responseObjHandle.left}`)
|
||||
}
|
||||
|
||||
const { pw, testRunStack, updatedEnvs } = getTestRunnerScriptMethods(envs)
|
||||
|
||||
// Create a function from the test script using the `Function` constructor
|
||||
const executeScript = new Function("pw", testScript)
|
||||
|
||||
// Execute the script
|
||||
executeScript({ ...pw, response: responseObjHandle.right })
|
||||
|
||||
return TE.right(<SandboxTestResult>{
|
||||
tests: testRunStack[0],
|
||||
envs: updatedEnvs,
|
||||
})
|
||||
} catch (error) {
|
||||
return TE.left(`Script execution failed: ${(error as Error).message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for messages from the main thread
|
||||
self.addEventListener("message", async (event) => {
|
||||
const { testScript, envs, response } = event.data
|
||||
|
||||
const results = await executeScriptInContext(testScript, envs, response)()
|
||||
|
||||
// Post the result back to the main thread
|
||||
self.postMessage({ results })
|
||||
})
|
||||
Reference in New Issue
Block a user