near-membrane

A DOM membrane library for creating fast, secure sandboxed JavaScript environments in the browser.

Library
npm
v0.19.0
133stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
72/100Good
Development Activity64
Maintenance68
Community76
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
81/100Excellent
Architecture88
Code Quality85
Innovation85
Learning Curve65

@locker/near-membrane-dom implements Salesforce’s near-membrane sandboxing technique for browsers, using a detached iframe to create an isolated Red Realm that mirrors the capabilities of the host Blue Realm. It powers Lightning Locker Service, letting untrusted or third-party code run inside a same-origin sandbox with distortions controlling exactly which globals, methods, and properties are exposed.

Unlike heavier VM-based isolation, near-membrane relies on lazily-initialized Proxies so sandbox creation stays fast and memory-light, activating only the portion of the global object graph that the sandboxed code actually touches. It has no runtime dependencies beyond its sibling @locker/near-membrane-* packages and ships pre-built ESM/CJS bundles alongside full TypeScript types.

What You Get

  • Detached-iframe sandboxing - Creates a hidden, same-origin iframe as an isolated Red Realm without leaking references back to the opener window.
  • Distortion-based capability control - A distortionCallback lets you swap, hide, or wrap any global before it crosses the membrane.
  • Lazy Proxy activation - Red Proxies initialize only on first trap invocation, keeping sandbox creation overhead minimal.
  • Full TypeScript types - Ships .d.ts declarations generated straight from the TypeScript source for createIframeVirtualEnvironment and related APIs.

Common Use Cases

  • Third-party script isolation - Run ads, widgets, or plugin code without letting it observe or mutate the host page’s real globals.
  • Multi-tenant component sandboxes - Salesforce’s Lightning Locker Service uses it to isolate each Lightning component’s execution context.
  • Polyfill/environment testing - Evaluate code against a distinct set of polyfills or timers without touching the host environment.
  • Capability-limited plugin systems - Grant plugins only the DOM APIs and globals you explicitly endow, blocking the rest by default.

Under The Hood

Architecture near-membrane-dom’s createIframeVirtualEnvironment (in src/browser-realm.ts) creates a hidden, detached <iframe> via createDetachableIframe, then wires its contentWindow (the Red Realm) to the host window (the Blue Realm) through @locker/near-membrane-base’s VirtualEnvironment class, createBlueConnector, and createRedConnector. Each side runs an init()-style membrane marshall (membrane.ts) that exchanges opaque Pointer references and a large set of Callable* hook functions (get/set/apply/construct/ownKeys, etc.) so that Proxy traps on one realm’s objects forward through to the other without ever exposing raw cross-realm identities. browser-realm.ts layers DOM-specific concerns on top of that generic protocol: filtering window’s own keys, special-casing unforgeable descriptors on Window/WindowProperties/EventTarget prototypes that cannot be proxied away, and registering a custom devtools formatter so proxied values remain inspectable. If the core connector/environment abstraction in near-membrane-base changed its pointer/callable protocol, every consuming package (-dom, -node) would need to update in lockstep, since they share the exact same marshalling wire format.

Tech Stack The project is a Lerna/Yarn-workspaces monorepo written in strict TypeScript ("strict": true, noUnusedLocals, noImplicitReturns) targeting es2020, compiled with Babel (@babel/preset-typescript, @babel/preset-env) and bundled per-package with Rollup (@rollup/plugin-babel, @rollup/plugin-node-resolve, @rollup/plugin-replace) into both CJS (dist/index.cjs.js) and ESM (dist/index.mjs.js) outputs, with .d.ts types emitted separately via tsc --emitDeclarationOnly. near-membrane-dom itself depends only on its sibling packages @locker/near-membrane-base, @locker/near-membrane-shared, and @locker/near-membrane-shared-dom — no third-party runtime dependencies. Node-side tests run under Jest with jsdom, while actual browser/DOM behavior is verified through Karma against headless Chrome via Puppeteer, with istanbul merging coverage from both runners into one report.

Code Quality The repo shows extensive test coverage - roughly 88 spec files across the near-membrane-base, near-membrane-node, near-membrane-shared, and near-membrane-shared-dom packages (the DOM-specific package is instead covered by the Karma/browser suite under test/). ESLint is configured with eslint-config-airbnb-base/airbnb-typescript plus eslint-plugin-import and Prettier integration, enforced in CI via a dedicated Run-linter job. Husky + commitlint (@commitlint/config-conventional) enforce Conventional Commits at the git-hook level. Error handling favors explicit TypeError throws on invalid inputs (e.g. missing global object) rather than silent fallbacks. GitHub Actions CI runs the linter, Jest suite, and Karma suite with merged coverage reporting published to a pages branch on every push/PR.

What Makes It Unique Rather than isolating code via a full JS engine sandbox (Web Workers, VMs, or a real ShadowRealm), near-membrane achieves isolation with same-origin detached iframes plus a lazily-initialized Proxy membrane - Red Proxies are only materialized the first time a trap actually fires, which keeps sandbox-creation cost low even though browser global objects expose an enormous API surface. The library explicitly documents its own boundaries (it is not a security boundary on its own - that’s left to the distortion mechanism) and handles browser-specific edge cases most membrane implementations ignore, like unforgeable Window prototype descriptors and the WindowProxy identity/GC quirks that arise when trying to sandbox cross-iframe references.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search