{"id":19024117,"url":"https://github.com/astrohelm/isolation","last_synced_at":"2026-04-09T18:25:01.306Z","repository":{"id":190877340,"uuid":"683202362","full_name":"astrohelm/isolation","owner":"astrohelm","description":"How often do you see libraries which mutates global variables. Or how often do you check libraries actions 🥸 ?This library prevents unexpected behavior and global pollution.","archived":false,"fork":false,"pushed_at":"2024-08-24T15:02:51.000Z","size":263,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-11T03:58:17.153Z","etag":null,"topics":["astrohelm","container","context","dependency-injection","isolation","javascript","loader","nodejs","pollution-control","realm","realms","runner","sandbox","script","script-loader","security","v8","vm","wrapper","zero-dependencies"],"latest_commit_sha":null,"homepage":"https://astrohelm.ru","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/astrohelm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-25T21:04:33.000Z","updated_at":"2024-08-24T15:02:54.000Z","dependencies_parsed_at":"2023-10-25T21:22:18.506Z","dependency_job_id":"387ccad0-ed73-4291-b137-a72b2859bacd","html_url":"https://github.com/astrohelm/isolation","commit_stats":null,"previous_names":["astrohelm/astroctx","astrohelm/isolation"],"tags_count":16,"template":false,"template_full_name":"astrohelm/node-workspace","purl":"pkg:github/astrohelm/isolation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astrohelm%2Fisolation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astrohelm%2Fisolation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astrohelm%2Fisolation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astrohelm%2Fisolation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astrohelm","download_url":"https://codeload.github.com/astrohelm/isolation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astrohelm%2Fisolation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29761981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T21:02:23.375Z","status":"ssl_error","status_checked_at":"2026-02-23T20:58:31.539Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astrohelm","container","context","dependency-injection","isolation","javascript","loader","nodejs","pollution-control","realm","realms","runner","sandbox","script","script-loader","security","v8","vm","wrapper","zero-dependencies"],"created_at":"2024-11-08T20:34:53.908Z","updated_at":"2026-02-24T00:05:37.179Z","avatar_url":"https://github.com/astrohelm.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n\n**Isolation**\n\n\u003c/h1\u003e\n\n**Why should i use it ?** How often do you see libraries which mutates global variables Or how often\ndo you check libraries actions ? Library provides script isolation in custom contexts to solve this\nkind of issues. Also, isolation prevents global scope and prototypes pollution.\n\n\u003e [!TIP]\n\u003e\n\u003e ## **Possible use case**\n\u003e\n\u003e May be useful as routing loader, if some loaded route makes an error while runtime, you may\n\u003e recreate it - to prevent memory leaks. Another worlds, with this library you can create\n\u003e multi-tenant applications;\n\n\u003ch2 align=\"center\"\u003e\n\n**Installation**\n\n\u003c/h2\u003e\n\n```bash\nnpm i isolation --save\n```\n\n\u003ch2 align=\"center\"\u003e\n\n**Basic Usage**\n\n\u003c/h2\u003e\n\n- **Prevent intentionally damage**\n\n  It will stop tricky users code, while you don't allow it.\n\n  ```javascript\n  // unchecked-dangerous-library index.js\n  const fs = require('fs');\n  fs.rm(process.cwd(), { recursive: true }); // Ha ha, no-code developer\n  ```\n\n  ```javascript\n  // routes/route/get.js\n  const dangerousLibrary = require('unchecked-dangerous-library'); // Point where dangerous library initialized\n  // ... other logic\n  ```\n\n  ```javascript\n  // index.js\n  const Isolation = require('isolation');\n  const routes = Isolation.read('./routes');\n  // ⚠️ Will throw an error because fs doesn't allowed\n  ```\n\n- **Prevent unintentionally damage**\n\n  This solves problem where libraries used to mutate global variables.\n\n  ```javascript\n  // unchecked-dangerous-library index.js\n  var console = msg =\u003e process.stdout.write(msg); // Someone just want different implementation for console\n  global.console = console;\n  console('Here it works fine');\n  String.prototype = {}; // Or just mutating prototypes\n  ```\n\n  ```javascript\n  // routes/route/get.js\n  const dangerousLibrary = require('unchecked-dangerous-library'); // Point where dangerous library initialized\n  // ... other logic\n  ```\n\n  ```javascript\n  // index.js\n  const Isolation = require('isolation');\n  Isolation.read('./routes');\n  console.log('All works fine');\n  console('Here it not works'); // Will throw an error\n  String.prototype; // Will be as default\n  ```\n\n\u003ch2 id=\"module-types\" align=\"center\"\u003e\n\n**Module types / Script syntax**\n\n\u003c/h2\u003e\n\n\u003e [!CAUTION]\n\u003e\n\u003e You can run any script from string, just like eval, but in custom VM container. But you\n\u003e **shouldn't use** it for unknown script evaluation, it may create **security issues**.\n\n### **Commonjs**\n\nBy default Isolation will use Standard Nodejs syntax. With this type of syntax it will provide to\nyour realms global variables such as:\n\n- **require** function, which is almost same as nodejs require, but with extra cup of isolation;\n- **module** \u0026 **exports** variables provided to manipulate with exports between modules;\n- **\\_\\_filename** \u0026 **\\_\\_dirname** are same as with default nodejs realm;\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e You always should use module.exports to export, otherwise you will see undefined as the result of\n\u003e realm execution.\n\n```javascript\nconst Isolation = require('isolation');\nconsole.log(new Isolation(`module.exports = { field: 'value' };`).execute()); // Output: { field: 'value' }\nconsole.log(Isolation.execute(`module.exports = (a, b) =\u003e a + b;`)(2 + 2)); // Output: 4\nconsole.log(Isolation.execute(`(a, b) =\u003e a + b;`)(2 + 2)); // Output: undefined\nIsolation.execute(`module.exports = async (a, b) =\u003e a + b;`)(2 + 2).then(console.log); // Output: 4\n```\n\n### **ISO**\n\nThis type of syntax will stand your script alone without any of extra global variables. That means\nthat you would not see \u003ccode\u003emodule\u003c/code\u003e or \u003ccode\u003eexports\u003c/code\u003e in your environment. But your\ncontext variables will still work well.\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e In this mode, your realms will export result of the last expression, that means that you should\n\u003e put a reference to your variable or expression at the end of the file / row;\n\n```javascript\nconst Isolation = require('isolation');\nconst options = { type: 'iso' };\nconsole.log(new Isolation(`{ field: 'value' };`, options).execute()); // Output: { field: 'value' }\nconsole.log(Isolation.execute(`(a, b) =\u003e a + b;`, options)(2 + 2)); // Output: 4\nIsolation.execute(`async (a, b) =\u003e a + b;`, options)(2 + 2).then(console.log); // Output: 4\n```\n\n### **ESM**\n\nIsolation doesn't yet support esm syntax. That's because currently \u003ccode\u003enode.vm\u003c/code\u003e ESM modules\nare experimental.\n\n\u003ch2 id=\"context-api\" align=\"center\"\u003e\n\n**Context API**\n\n\u003c/h2\u003e\n\nYou can create custom context or use default presets with **context api**. This will allow you to\nprovide your custom variables to the context without requiring any module.\n\n\u003e [!TIP]\n\u003e\n\u003e Remember to reuse your contexts. This will increase performance of your application. To help you\n\u003e with this we have default contexts:\n\n### **Context example**\n\n```javascript\nconst { contextify, execute } = require('isolation');\nconst custom = contextify({ console }); // ⚠️ Object will be mutated\nexecute(`console.log(123);`, { ctx: custom }); // STD Output: 123\nexecute(`console.log(123);`); // No STD output, because different stdout stream\n```\n\nAlso its allow you to change program behavior with something like:\n\n```js\nconst ctx = Isolation.contextify({ a: 1000, b: 10 });\nconst realm = new Isolation(`module.exports = a - b`, { ctx });\nrealm.execute(); // Output: 990\nrealm.execute({ ...ctx, a: 0 }); // Output: -10\nrealm.execute({ ...ctx, b: 7 }); // Output: 993\n```\n\n### **Default contexts**\n\nDefault contexts are accessible from Isolation.contextify, there you can find:\n\n- Isolation.contextify.**EMPTY**, that just empty context\n- Isolation.contextify.**COMMON**, timers, buffer, fetch etc...\n- Isolation.contextify.**NODE**, global, console, process \u0026 **COMMON** context You should'nt use\n  **NODE** context, it may create security issues, otherwise it may road to possible context\n  escaping.\n\n\u003ch2 id=\"reader-api\" align=\"center\"\u003e\n\n**Reader API**\n\n\u003c/h2\u003e\n\nReader allow you to run scripts from files and extends possible provided options with:\n\n- Option \u003ccode\u003eprepare:boolean\u003c/code\u003e reader will return non-executed scripts, **default false**\n- Option \u003ccode\u003edepth:number|boolean\u003c/code\u003e nested directories restrictions, **default true**\n- Option \u003ccode\u003eflat:boolean\u003c/code\u003e result with nested scripts will be flat, **default false**\n\n- \u003ccode\u003eread\u003c/code\u003e Allow you to read source codes from files and directories\n\n  ```javascript\n  const Isolation = require('isolation');\n  Isolation.read('./path/to/script.js').then(console.log); // Output: result of script execution\n  Isolation.read('./path/to').then(console.log); // Output: { script: any }\n  Isolation.read('./path/to', { prepare: true }).then(console.log); // Output: { script: Script {} }\n  ```\n\n  By default reader works with nested directories, to disable this behavior you can do:\n\n  ```js\n  const Isolation = require('isolation');\n  Isolation.read('./path/to', { depth: false });\n  // Or limit it:\n  Isolation.read('./path/to', { depth: 3 });\n  ```\n\n- \u003ccode\u003eread.file\u003c/code\u003e Allow you to execute script from single file\n\n  ```javascript\n  const Isolation = require('isolation');\n  Isolation.read.file('./path/to/script.js').then(console.log); // Output: result of script execution\n  Isolation.read.file('./path/to/script.js', { prepare: true }).then(console.log); // Output: Script {}\n  ```\n\n- \u003ccode\u003eread.dir\u003c/code\u003e Allow you to execute multiple scripts from directory\n\n  ```javascript\n  const Isolation = require('isolation');\n  Isolation.read.dir('./path/to').then(console.log); // Output: { script: any, deep: { script: any } }\n  Isolation.read.dir('./path/to', { prepare: true }).then(console.log); Output: { script: Script {} }\n  Isolation.read.dir('./path/to', { depth: false }).then(console.log); // Output: { script: any }\n  ```\n\n\u003ch2 id=\"access-control\" align=\"center\"\u003e\n\n**Access control**\n\n\u003c/h2\u003e\n\nYou may control access over realm submodules and reader api;\n\n\u003e [!NOTE]\n\u003e\n\u003e If access doesn't provided realm submodules would'nt be accessible and reader will read all files\n\u003e in directed repository.\n\n```js\nconst options = { access: pathOrModule =\u003e pathOrModule === 'fs' || pathOrModule.endsWith('.js') };\nIsolation.execute('module.exports = require(\"fs\")', options);\nIsolation.read('./path/to/script.js', options);\n// Or\nconst options2 = {\n  access: {\n    reader: path =\u003e true, // Directory reader\n    realm: module =\u003e {}, //  Realm submodules\n  },\n};\n```\n\n### **Library substitution**\n\nYou can replace result of require for specific libraries with anything what you want;\n\n```js\nconst Isolation = require('isolation');\nconst src = `\n  const fs = require('fs');\n  module.exports = fs.readFile('Isolation.js');\n`;\n\nconst sub = name =\u003e {\n  if (name !== 'fs') return true;\n  return {\n    readFile: filename =\u003e filename + ' Works !',\n  };\n};\n\nconst result = Isolation.execute(src, { access: { realm: sub } });\nconsole.log(result); // Output: Isolation.js Works !\n```\n\n\u003ch2 id=\"script-options\" align=\"center\"\u003e\n\n**Possible script options**\n\n\u003c/h2\u003e\n\n| Option           | Possible                                       | Default                          | Description                                                                                           |\n| ---------------- | ---------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------- |\n| **type**         | iso\u0026nbsp;\\|\u0026nbsp;cjs                           | cjs                              | Type\u0026nbsp;of\u0026nbsp;script\u0026nbsp;handling, see [syntax types](#module-types)                             |\n| **ctx**          | object                                         | -                                | Realm\u0026nbsp;context, see [Context API](#context-api)                                                   |\n| **filename**     | string                                         | ISO                              | Name\u0026nbsp;of\u0026nbsp;the\u0026nbsp;module\u0026nbsp;, also it is global variable **\\_\\_filename** for root realm   |\n| **dir**          | string                                         | process.cwd()                    | Module\u0026nbsp;directory\u0026nbsp;, also it is global variable **\\_\\_dirname** and realm require start point |\n| **npmIsolation** | boolean                                        | false                            | Controls\u0026nbsp;npm\u0026nbsp;modules\u0026nbsp;isolation                                                         |\n| **access**       | [Access](./types/options.d.ts#L51)             | -                                | Isolation\u0026nbsp;restrictions, see [Access API](#reader-api)                                            |\n| **prepare**      | boolean                                        | false                            | Reader\u0026nbsp;would'nt\u0026nbsp;execute script for you                                                      |\n| **flat**         | boolean                                        | false                            | Reader\u0026nbsp;will\u0026nbsp;flat\u0026nbsp;nested\u0026nbsp;scripts                                                   |\n| **depth**        | boolean\u0026nbsp;\\|\u0026nbsp;number                    | true                             | Restricts\u0026nbsp;dir\u0026nbsp;reading\u0026nbsp;depth                                                            |\n| **realmOpts**    | [ScriptOptions](./types/options.d.ts#L63)      | -                                | Configuration\u0026nbsp;for VM.Script initialization                                                       |\n| **runOpts**      | [RunningCodeOptions](./types/options.d.ts#L62) | {\u0026nbsp;timeout:\u0026nbsp;1000\u0026nbsp;} | Configuration\u0026nbsp;for VM.Script execution                                                            |\n\n\u003ch2 align=\"center\"\u003eCopyright \u0026 contributors\u003c/h2\u003e\n\n\u003cp align=\"center\"\u003e\nCopyright © 2023 \u003ca href=\"https://github.com/astrohelm/isolation/graphs/contributors\"\u003eAstrohelm contributors\u003c/a\u003e.\nThis library is \u003ca href=\"./LICENSE\"\u003eMIT licensed license\u003c/a\u003e.\u003cbr/\u003e\nAnd it is part of \u003ca href=\"https://github.com/astrohelm\"\u003eAstrohelm solutions\u003c/a\u003e.\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastrohelm%2Fisolation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastrohelm%2Fisolation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastrohelm%2Fisolation/lists"}