Skip to main content

Extension sandbox

Extension UI code runs in a dedicated Web Worker inside a sandboxed runtime iframe. Every extension shares the runtime's origin, so any browser API scoped to that origin would let one extension read or overwrite another extension's data. The platform therefore removes these APIs before your bundle is evaluated.

Blocked APIs​

Behaviour change

indexedDB, caches, BroadcastChannel and the other Worker-global APIs listed below are blocked in the extension Worker. Code or third-party libraries that use them throw a SecurityError on first access. Move that state to useExtensionStorage.

Worker global​

Reading or assigning any of these throws a SecurityError ("<name> is not available in the Lumio extension sandbox"). Even typeof indexedDB throws, because it reads the property.

APIWhy it is blocked
indexedDBOrigin-scoped database, shared by all extensions
caches (CacheStorage)Origin-scoped cache, shared by all extensions
BroadcastChannelMessages reach every context on the shared origin
navigator.storageQuota, persistence and the origin-private file system
navigator.locksWeb Locks are shared by every context on the origin
navigator.serviceWorkerService workers are registered per origin
navigator.storageBucketsEach Storage Bucket opens its own indexedDB, caches and file system, shared across the origin
Worker, SharedWorkerA nested worker would start with an unrestricted global
webkitRequestFileSystem*, webkitResolveLocalFileSystem*URLLegacy origin-scoped file systems

The blocks cannot be undone: the properties are non-configurable, and the original accessors on the prototypes are replaced too.

Network​

The Worker's Content Security Policy blocks network requests from extension UI code: fetch, XMLHttpRequest, WebSocket, EventSource and importScripts from other origins all fail. Read data through server functions, which can call declared egress hosts with ctx.fetch().

Runtime frame​

The runtime iframe that hosts the Worker also blocks localStorage, sessionStorage, indexedDB, caches and BroadcastChannel, and document.cookie always reads as "" (writes are dropped). Extension code does not run in that frame, but the restriction is listed here for completeness.

What to use instead​

You needUse
State that survives a reload, shared by all surfaces of your extensionuseExtensionStorage
Data your server functions ownServer functions (query() / mutation())
Values configured by the streameruseLumioConfig
Short-lived state in one surfaceReact state (useState, useReducer) or module variables

Detecting the sandbox in libraries​

A library that probes for storage with typeof indexedDB !== "undefined" throws instead of falling back. Wrap the probe:

function hasIndexedDb(): boolean {
try {
return typeof indexedDB !== "undefined";
} catch {
return false;
}
}

If you cannot change the library, configure it for in-memory storage or pick one without a persistence layer.