spike: QuickJS-WASM sandbox marshaling cost harness#10072
Draft
jackkav wants to merge 1 commit into
Draft
Conversation
Standalone, runnable spike measuring the boundary-crossing cost of running pre/post-request scripts inside a QuickJS-WASM engine instead of the current same-realm AsyncFunction model. Compares two architectures on the same representative script: proxying the live host object (today's pass-by-reference) vs. bulk-copying state in and rebuilding the pm/insomnia API inside the sandbox. Documents the async bridge finding (asyncify collides with user await chains; VM-native promises + a driver loop is the robust pattern). Not wired into the app; see README for results and implications.
✅ Circular References ReportGenerated at: 2026-06-12T09:33:52.409Z Summary
Click to view all circular references in PR (9)Click to view all circular references in base branch (9)Analysis✅ No Change: This PR does not introduce or remove any circular references. This report was generated automatically by comparing against the |
Contributor
|
The approach 2 seems better to me, there could be some objects that cannot be proxied. And tackling |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
A throwaway, runnable spike that measures the marshaling cost of moving pre/post-request scripts from the current same-realm
AsyncFunctionmodel (run-script.ts/sandbox.ts) into a separate QuickJS-WASM engine.Motivation: QuickJS-WASM is the most portable real-isolation option for sandboxing scripts/plugins across both the Electron environment (renderer / main / UtilityProcess) and the
insoNode CLI — one.wasm, no native rebuild, novm2. The open question was how expensive the WASM boundary is once you can no longer pass the liveInsomniaObjectby reference. This spike answers it with numbers.Not wired into the app. It lives under
packages/insomnia/src/scripting/quickjs-spike/and runs standalone so the results don't depend on the monorepo.What it does
Runs the same representative pre-request script (env get/set loops, header mutation,
console.log, and an awaitedinsomnia.sendRequestdoing real host async I/O) through two architectures and counts/times every boundary crossing:environment.get/set, header add, log, sendRequest crosses the boundary.pm/insomniaAPI inside the sandbox, bridge only what must escape (console + async sendRequest), copy mutated state out.Results (M-series, QuickJS 0.32, non-asyncify variant)
Fidelity passes both ways (awaited
sendRequestwriteslastStatus=200back; header added).Key findings
InsomniaObjectmethod-by-method. Serialize thetoObject()surface in once, rebuild the API in-sandbox over plain state, copy out once. Bulk JSON of a 7 KB payload is ~0.1 ms in / ~0.5 ms out.newAsyncifiedFunctiononly drives host calls on the synchronous eval path; a host call reached from a userawaitchain (every pm script) crashes the job pump. The robust pattern is VM-native promises (ctx.newPromise()) + a host driver loop, which also works with the smaller non-asyncify WASM.__bridgeReset__/__bridgeSettle__async-task monitor.Reviewer notes
package.json. To run:npm i quickjs-emscriptenin a scratch dir andnode harness.mjs(see the README).toObject()as the serialize/merge contract; onlysendRequest/console/vault need host bridges).