{"_id":"@apeleghq/lot","_rev":"2-59c19cac7a14632119fd8f250de1ba09","name":"@apeleghq/lot","dist-tags":{"latest":"0.0.29"},"versions":{"0.0.28":{"name":"@apeleghq/lot","version":"0.0.28","keywords":["Node.js","browser","csp","deno","ecmascript","iframe","isolation","sandbox","security","vm","webworker","worker"],"author":{"name":"Apeleg Limited"},"license":"ISC","_id":"@apeleghq/lot@0.0.28","maintainers":[{"name":"er-ci-bot","email":"npmjs.com+er-ci-bot+fd8b22b478b6fac7@apeleg.com"},{"name":"corrideat","email":"3857362+corrideat@users.noreply.github.com"}],"homepage":"https://github.com/ApelegHQ/lot#readme","bugs":{"url":"https://github.com/ApelegHQ/lot/issues"},"dist":{"shasum":"8c586b94258ac534823e05094c39be63a9ac5493","tarball":"https://registry.npmjs.org/@apeleghq/lot/-/lot-0.0.28.tgz","fileCount":221,"integrity":"sha512-VRKldciioEov8XKU61CQv7X7E25Rfjv9gEBYTKE9Lp+/+/Ie6lKtIfBNLJP8KvPf4OKQOVblOfR0K3bX9pwN4Q==","signatures":[{"sig":"MEUCIQCP7rVtiWwFXLUcwvFXjsOeEuWGnLA2agbrr03M8upY6AIgFpDw56ujB585CgyVMNihHPOHTfNkQGAbzx40w+RItTU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@apeleghq%2flot@0.0.28","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":436628},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.cts","module":"./dist/index.mjs","engines":{"npm":">=8.0.0","node":">=16.0.0"},"exports":{".":{"deno":{"types":"./dist/exports/worker.d.ts","default":"./dist/exports/worker.mjs"},"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"browser":{"types":{"default":"./dist/exports/browser.d.ts","require":"./dist/exports/browser.d.cts"},"import":"./dist/exports/browser.mjs","default":"./dist/exports/browser.mjs","require":"./dist/exports/browser.cjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"},"browser-window":{"types":{"default":"./dist/exports/browser-window.d.ts","require":"./dist/exports/browser-window.d.cts"},"import":"./dist/exports/browser-window.mjs","default":"./dist/exports/browser-window.mjs","require":"./dist/exports/browser-window.cjs"},"browser-worker":{"types":{"default":"./dist/exports/browser-worker.d.ts","require":"./dist/exports/browser-worker.d.cts"},"import":"./dist/exports/browser-worker.mjs","default":"./dist/exports/browser-worker.mjs","require":"./dist/exports/browser-worker.cjs"}},"./bare":{"import":{"types":"./dist/exports/bare.d.ts","default":"./dist/exports/bare.mjs"},"require":{"types":"./dist/exports/bare.d.cts","default":"./dist/exports/bare.cjs"}},"./nodejs":{"import":{"types":"./dist/exports/nodejs.d.ts","default":"./dist/exports/nodejs.mjs"},"require":{"types":"./dist/exports/nodejs.d.cts","default":"./dist/exports/nodejs.cjs"}},"./worker":{"import":{"types":"./dist/exports/worker.d.ts","default":"./dist/exports/worker.mjs"},"require":{"types":"./dist/exports/worker.d.cts","default":"./dist/exports/worker.cjs"}},"./browser":{"import":{"types":"./dist/exports/browser.d.ts","default":"./dist/exports/browser.mjs"},"require":{"types":"./dist/exports/browser.d.cts","default":"./dist/exports/browser.cjs"}},"./browser-window":{"import":{"types":"./dist/exports/browser-window.d.ts","default":"./dist/exports/browser-window.mjs"},"require":{"types":"./dist/exports/browser-window.d.cts","default":"./dist/exports/browser-window.cjs"}},"./browser-worker":{"import":{"types":"./dist/exports/browser-worker.d.ts","default":"./dist/exports/browser-worker.mjs"},"require":{"types":"./dist/exports/browser-worker.d.cts","default":"./dist/exports/browser-worker.cjs"}}},"gitHead":"97a7e9f7548f2ae43d88cc027e0379577047aef3","scripts":{"lint":"eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs,.cts,.mts,.json","test":"npm run test:unit && npm run build && npm run test:e2e","build":"npm run ts:declaration && node esbuild.mjs","prepack":"npm run build","version":"npm run lint && git add -A src","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs,.cts,.mts,.json --fix","test:e2e":"node test.mjs \"test/**/*.spec.ts\"","test:unit":"node test.mjs \"src/**/*.spec.ts\"","preversion":"npm run lint","postversion":"git push && git push --tags","prepublishOnly":"npm test && npm run lint","ts:declaration":"tspc --build --emitDeclarationOnly --declarationMap --declaration"},"_npmUser":{"name":"er-ci-bot","email":"npmjs.com+er-ci-bot+fd8b22b478b6fac7@apeleg.com"},"repository":{"url":"git+https://github.com/ApelegHQ/lot.git","type":"git"},"_npmVersion":"10.8.2","description":"Sandbox for isolating ECMAScript code","directories":{},"_nodeVersion":"20.17.0","_hasShrinkwrap":false,"devDependencies":{"glob":"^10.4.2","eslint":"^8.57.0","esbuild":"^0.23.1","ts-node":"^10.9.2","prettier":"^3.3.3","ts-patch":"^3.2.1","minimatch":"^9.0.5","typescript":"^5.5.2","selenium-webdriver":"^4.24.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","google-closure-compiler":"^20240317.0.0","@types/selenium-webdriver":"^4.1.26","@typescript-eslint/parser":"^8.5.0","typescript-transform-paths":"^3.5.0","@typescript-eslint/eslint-plugin":"^8.5.0","@apeleghq/esbuild-plugin-inline-js":"^1.1.9","@apeleghq/esbuild-plugin-closure-compiler":"^1.0.6"},"_npmOperationalInternal":{"tmp":"tmp/lot_0.0.28_1726080025439_0.041391484076251484","host":"s3://npm-registry-packages"}},"0.0.29":{"name":"@apeleghq/lot","version":"0.0.29","description":"Sandbox for isolating ECMAScript code","main":"./dist/index.cjs","types":"./dist/index.d.cts","module":"./dist/index.mjs","type":"module","exports":{".":{"browser":{"types":{"require":"./dist/exports/browser.d.cts","default":"./dist/exports/browser.d.ts"},"import":"./dist/exports/browser.mjs","require":"./dist/exports/browser.cjs","default":"./dist/exports/browser.mjs"},"browser-window":{"types":{"require":"./dist/exports/browser-window.d.cts","default":"./dist/exports/browser-window.d.ts"},"import":"./dist/exports/browser-window.mjs","require":"./dist/exports/browser-window.cjs","default":"./dist/exports/browser-window.mjs"},"browser-worker":{"types":{"require":"./dist/exports/browser-worker.d.cts","default":"./dist/exports/browser-worker.d.ts"},"import":"./dist/exports/browser-worker.mjs","require":"./dist/exports/browser-worker.cjs","default":"./dist/exports/browser-worker.mjs"},"deno":{"types":"./dist/exports/worker.d.ts","default":"./dist/exports/worker.mjs"},"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./bare":{"import":{"types":"./dist/exports/bare.d.ts","default":"./dist/exports/bare.mjs"},"require":{"types":"./dist/exports/bare.d.cts","default":"./dist/exports/bare.cjs"}},"./browser":{"import":{"types":"./dist/exports/browser.d.ts","default":"./dist/exports/browser.mjs"},"require":{"types":"./dist/exports/browser.d.cts","default":"./dist/exports/browser.cjs"}},"./browser-window":{"import":{"types":"./dist/exports/browser-window.d.ts","default":"./dist/exports/browser-window.mjs"},"require":{"types":"./dist/exports/browser-window.d.cts","default":"./dist/exports/browser-window.cjs"}},"./browser-worker":{"import":{"types":"./dist/exports/browser-worker.d.ts","default":"./dist/exports/browser-worker.mjs"},"require":{"types":"./dist/exports/browser-worker.d.cts","default":"./dist/exports/browser-worker.cjs"}},"./nodejs":{"import":{"types":"./dist/exports/nodejs.d.ts","default":"./dist/exports/nodejs.mjs"},"require":{"types":"./dist/exports/nodejs.d.cts","default":"./dist/exports/nodejs.cjs"}},"./worker":{"import":{"types":"./dist/exports/worker.d.ts","default":"./dist/exports/worker.mjs"},"require":{"types":"./dist/exports/worker.d.cts","default":"./dist/exports/worker.cjs"}}},"scripts":{"lint":"eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs,.cts,.mts,.json","lint:fix":"eslint . --ext .js,.jsx,.ts,.tsx,.cjs,.mjs,.cts,.mts,.json --fix","ts:declaration":"tspc --build --emitDeclarationOnly --declarationMap --declaration","build":"npm run ts:declaration && node esbuild.mjs","test:unit":"node test.mjs \"src/**/*.spec.ts\"","test:e2e":"node test.mjs \"test/**/*.spec.ts\"","test":"npm run test:unit && npm run build && npm run test:e2e","prepack":"npm run build","prepublishOnly":"npm test && npm run lint","preversion":"npm run lint","version":"npm run lint && git add -A src","postversion":"git push && git push --tags"},"repository":{"type":"git","url":"git+https://github.com/ApelegHQ/lot.git"},"author":{"name":"Apeleg Limited"},"license":"ISC","devDependencies":{"@apeleghq/esbuild-plugin-closure-compiler":"^1.0.7","@apeleghq/esbuild-plugin-inline-js":"^1.1.10","@types/node":"^22.13.11","@types/selenium-webdriver":"^4.1.28","@typescript-eslint/eslint-plugin":"^8.27.0","@typescript-eslint/parser":"^8.27.0","esbuild":"^0.25.1","eslint":"^9.23.0","eslint-config-prettier":"^10.1.1","eslint-plugin-prettier":"^5.2.3","glob":"^11.0.1","globals":"^16.0.0","google-closure-compiler":"^20240317.0.0","minimatch":"^10.0.1","prettier":"^3.5.3","selenium-webdriver":"^4.30.0","ts-node":"^10.9.2","ts-patch":"^3.3.0","typescript":"^5.8.2","typescript-transform-paths":"^3.5.5"},"engines":{"npm":">=8.0.0","node":">=16.0.0"},"keywords":["Node.js","browser","csp","deno","ecmascript","iframe","isolation","sandbox","security","vm","webworker","worker"],"_id":"@apeleghq/lot@0.0.29","gitHead":"ccbe0cdbe47c536a0a194e34b9ccf267d2184def","bugs":{"url":"https://github.com/ApelegHQ/lot/issues"},"homepage":"https://github.com/ApelegHQ/lot#readme","_nodeVersion":"20.19.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-JkjwI5vKrz4Hgm1sItnUJtYOTuutjU/yWAHAS849BhSnMPvhQADOVedbWlCs4AbvocpAgKJxa4vsnZmKD3Wf6g==","shasum":"54256e282997f8e107b8d4c503511e74fc1b4551","tarball":"https://registry.npmjs.org/@apeleghq/lot/-/lot-0.0.29.tgz","fileCount":221,"unpackedSize":438176,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@apeleghq%2flot@0.0.29","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFaABIwk3m8aruZwuEXW9vNFW49TppWPTn2OlI94yzXuAiEA3Q5BG6C3u3VM11x0XQHu8/6OvgU+pp4ZR+tPSi87QRY="}]},"_npmUser":{"name":"er-ci-bot","email":"npmjs.com+er-ci-bot+fd8b22b478b6fac7@apeleg.com"},"directories":{},"maintainers":[{"name":"er-ci-bot","email":"npmjs.com+er-ci-bot+fd8b22b478b6fac7@apeleg.com"},{"name":"corrideat","email":"3857362+corrideat@users.noreply.github.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lot_0.0.29_1742711619531_0.8636935132295605"},"_hasShrinkwrap":false}},"time":{"created":"2024-09-11T18:40:25.331Z","modified":"2025-03-23T06:33:40.286Z","0.0.28":"2024-09-11T18:40:25.732Z","0.0.29":"2025-03-23T06:33:39.733Z"},"bugs":{"url":"https://github.com/ApelegHQ/lot/issues"},"author":{"name":"Apeleg Limited"},"license":"ISC","homepage":"https://github.com/ApelegHQ/lot#readme","keywords":["Node.js","browser","csp","deno","ecmascript","iframe","isolation","sandbox","security","vm","webworker","worker"],"repository":{"type":"git","url":"git+https://github.com/ApelegHQ/lot.git"},"description":"Sandbox for isolating ECMAScript code","maintainers":[{"name":"er-ci-bot","email":"npmjs.com+er-ci-bot+fd8b22b478b6fac7@apeleg.com"},{"name":"corrideat","email":"3857362+corrideat@users.noreply.github.com"}],"readme":"# 🏜️ @apeleghq/lot 🏖️\r\n\r\n [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Exact-Realty_ecmascript-sandbox&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=Exact-Realty_ecmascript-sandbox)\r\n [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=Exact-Realty_ecmascript-sandbox&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=Exact-Realty_ecmascript-sandbox)\r\n [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=Exact-Realty_ecmascript-sandbox&metric=bugs)](https://sonarcloud.io/summary/new_code?id=Exact-Realty_ecmascript-sandbox)\r\n [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Exact-Realty_ecmascript-sandbox&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=Exact-Realty_ecmascript-sandbox)\r\n [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=Exact-Realty_ecmascript-sandbox&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=Exact-Realty_ecmascript-sandbox)\r\n ![NPM Downloads](https://img.shields.io/npm/dw/@apeleghq/lot?style=flat-square)\r\n\r\nWelcome to `@apeleghq/lot` — the versatile ECMAScript sandbox\r\nyou've been looking for!\r\n\r\nOur sandbox supports multiple runtimes and allows for bidirectional\r\ncommunication, ensuring you have the flexibility and security to run your code\r\nin various environments. \r\n\r\n### 🚀 Features\r\n\r\n- Support for multiple runtimes:\r\n    * Browser (using an iframe with a worker inside or just an iframe)\r\n    * Dedicated worker (can run in the browser or with Deno)\r\n    * Node.js\r\n- Browser isolation using Content Security Policy (CSP)\r\n- Message passing using the `MessageEvent` class and event listeners for secure\r\n  communication using the structured clone algorithm\r\n- Hardening of global variables, including `Function` and `eval`, to prevent\r\n  direct code execution\r\n- Bidirectional communication, enabling the parent to call into the sandbox and\r\n  vice versa\r\n\r\n### 💻 Installation\r\n\r\nTo install, run:\r\n\r\n```sh\r\nnpm install \"@apeleghq/lot\"\r\n```\r\n\r\n```sh\r\nyarn add \"@apeleghq/lot\"\r\n```\r\n\r\n### 📚 Usage\r\n\r\nUsing our sandbox is easy! First, import the desired sandbox function, then call\r\nit with your code and any additional parameters. Here's an example using\r\n`browserSandbox`:\r\n\r\n```js\r\nimport { browserSandbox } from '@apeleghq/lot';\r\n\r\nconst sandbox = await browserSandbox(`\r\n  /* sandboxed code*/;\r\n  module.exports={hello:(name)=>\\`Hello, ${name}!\\`}; \r\n`);\r\nconst result = await sandbox('hello', 'World');\r\nconsole.log(result); // Output: \"Hello, World!\"\r\n```\r\n\r\nOur sandbox provides two interfaces:\r\n\r\n```typescript\r\nexport interface IPerformTask {\r\n  (op: string, ...args: unknown[]): Promise<unknown>;\r\n}\r\n\r\nexport interface ISandbox {\r\n  (\r\n    script: string,\r\n    allowedGlobals?: string[] | undefined | null,\r\n    externalMethods?: Record<string, unknown> | null,\r\n    abort?: AbortSignal,\r\n    options?: TSandboxOptions,\r\n  ): Promise<IPerformTask>;\r\n}\r\n\r\nexport type TSandboxOptions = {\r\n\tbrowserRequireWorker?: boolean;\r\n\tworkerType?: WorkerOptions['type'];\r\n}\r\n```\r\n\r\n`ISandbox` is an interface for the `browserSandbox`, `nodejsSandbox` and\r\n`workerSandbox` functions. It takes a string `script` representing the code to\r\nbe sandboxed, an optional array of allowed global variables `allowedGlobals`, an\r\noptional object of external methods `externalMethods`, and an optional\r\nAbortSignal `abort`. It returns a promise that resolves to an implementation of\r\n`IPerformTask`.\r\n\r\n`IPerformTask` is an interface for the result of the various sandbox function.\r\nIt takes a string `op` representing the function name and a list of arguments,\r\nand it returns a promise that resolves to the result of the task.\r\n\r\nThe script to be sandboxed, `script`, must expose an object in `module.exports`\r\nwith a dictionary of the different functions that can be called from outside.\r\nThe type of `module.exports` is `Record<string, typeof Function.prototype>`.\r\n\r\n### 🤝 Contributing\r\n\r\nWe welcome any contributions and feedback! Please feel free to submit pull\r\nrequests, bug reports or feature requests to our GitHub repository.\r\n\r\n### ❗️ Disclaimer\r\n\r\n⚠️ Please note that even though we have implemented several security measures,\r\nit's important to understand that sandbox escapes are always a possibility.\r\nRunning untrusted code in Node.js is especially risky due to its inherent\r\nplatform limitations. Our sandbox relies on `node:vm`, which was not designed\r\nfor running untrusted code.\r\n\r\nTo mitigate these risks, we strongly recommend taking a security-in-depth\r\napproach and relying on additional security mechanisms such as process\r\nisolation, `seccomp(2)`, `pledge(2)`, `ProcessSystemCallDisablePolicy` and\r\nSELinux, to name a few. Where feasible, we also recommend static code analysis\r\nand code reviews, as well as adequate auditing and logging.\r\n\r\nNote that the sandbox does not prevent denial-of-service attacks such as\r\ninfinite loops or memory exhaustion. It's important to take appropriate measures\r\nto prevent these types of attacks, such as setting resource limits or using\r\ntimeouts.\r\n\r\n### 📜 License\r\n\r\nThis project is released under the ISC license. Check out the `LICENSE` file for\r\nmore information.\r\n","readmeFilename":"README.md"}