Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ading2210/sandstone/llms.txt

Use this file to discover all available pages before exploring further.

The context module creates a sandboxed global scope, exposed as ctx, that intercepts access to specific global variables inside proxied JavaScript. When Sandstone rewrites a proxied script, references to globals such as window, location, and document are redirected through ctx rather than going directly to the real browser globals. This lets Sandstone substitute its own implementations — fake URLs, intercepted storage, patched history — without modifying the host page. This page documents the internals. You need it only if you are extending Sandstone or adding new interception behaviour. If you are embedding Sandstone, use ProxyFrame instead.
This is an internals reference. The exports described here are implementation details of the frame-side runtime and are not part of the public embedding API.

ctx

// CustomCTX instance — the sandboxed global scope
export const ctx
The single shared instance of CustomCTX. This is the execution environment for all proxied scripts. The rewriter injects references to ctx via the helper globals __ctx__, __get_this__, and __get_var__ that are installed on globalThis by update_ctx().

CustomCTX

CustomCTX is the class whose instance becomes the sandboxed global. Its prototype methods define all the intercepted globals. On construction, it reads the names of all prototype keys (excluding those prefixed with __) and pushes them into ctx_vars, then wraps globalThis in a Proxy stored as ctx.__proxy__.

Intercepted globals

The following properties are defined on CustomCTX and therefore intercepted when proxied scripts access them:
PropertyBehaviour
locationReturns a FakeLocation instance. Setting it calls FakeLocation.assign(value).
selfReturns ctx.__proxy__ (the proxied global).
globalThisReturns ctx.__proxy__.
windowReturns ctx.__proxy__.
originReturns ctx.location.origin.
documentReturns intercept.document.__proxy__ (or undefined in a worker).
parentReturns globalThis.parent when running inside an iframe; otherwise returns ctx.__proxy__.
topSame logic as parent.
fetchDelegates to polyfill.fetch.
URLReturns polyfill.FakeURL.
WorkerReturns polyfill.FakeWorker.
XMLHttpRequestReturns polyfill.FakeXMLHttpRequest.
historyReturns the current FakeHistory instance.
localStorageReturns the current FakeStorage("local") instance.
sessionStorageReturns the current FakeStorage("session") instance.
WebSocketReturns the network-layer WebSocket implementation.
evalCalls run_script(String(js)) so that dynamic eval inside proxied code is also rewritten.

Internal helper methods

These methods are installed on globalThis by update_ctx() and are called by rewritten code at runtime. You should not call them directly.
MethodSignatureDescription
__get_this__(this_obj)(any) → anyIf this_obj is globalThis, return ctx.__proxy__ instead. Used to intercept bare this references at global scope.
__get_var__(var_value, var_name)(any, string) → anyIf var_value is the same object as globalThis[var_name], return ctx.__proxy__[var_name] instead. Used to intercept identifier reads for ctx_vars.

ctx_vars

// string[] — variable names intercepted by ctx
export const ctx_vars
An array of variable names that are intercepted and redirected through ctx. It is populated automatically from the prototype keys of CustomCTX when the first instance is created. Any global whose name appears in ctx_vars will have its reads wrapped with __get_var__ by the JavaScript rewriter.

unreadable_vars

// string[] — variables always read via __ctx__ rather than __get_var__
export const unreadable_vars
A subset of intercepted variables that are always read directly from ctx rather than going through the __get_var__ fallback logic. The default members are "localStorage", "sessionStorage", and "importScripts". In a worker context, "document" is added as well. When the rewriter encounters one of these identifiers, it produces __ctx__.varName rather than (__get_var__(varName, "varName")).

update_ctx

function update_ctx()
Initialise or reset all internal context state. Call this once per page load, before executing any proxied scripts. It performs the following work:
  • Creates a new FakeLocation and stores it in the internal state.
  • Sets internal.self and internal.globalThis to ctx.__proxy__.
  • Creates a new FakeHistory, FakeStorage("local"), and FakeStorage("session").
  • Deletes globalThis.caches to prevent direct cache access from proxied code.
  • Installs __ctx__, __get_this__, and __get_var__ on globalThis so that rewritten scripts can call them.
// In loader.mjs, called once per navigation:
update_ctx();

run_script

function run_script(js): any
Rewrite js with parser.rewrite_js and then evaluate it using an indirect eval call. The indirect form (eval?.()) preserves the global scope binding so that variable declarations inside the script become globals rather than local variables.
run_script("console.log(window.location.href)");

run_script_safe

function run_script_safe(js)
The same as run_script, but catches and logs any exception rather than propagating it. Use this for fire-and-forget script execution where an error should not interrupt the surrounding code.

convert_url

function convert_url(url, base): string
Resolve url against base using the standard URL constructor and return the resulting absolute href. This is a thin wrapper used throughout the frame runtime whenever a relative URL must be made absolute using the current proxied page origin.
const absolute = convert_url("/path/to/resource", ctx.location.href);

intercept_property

function intercept_property(target, key, handler)
Override a property descriptor on target using Object.defineProperty. The original descriptor is retrieved from the target’s prototype before being replaced.
ParameterTypeDescription
targetobjectThe object whose property will be overridden.
keystringThe property name to intercept.
handlerPropertyDescriptorThe replacement descriptor (e.g. { get, set }).
Returns the original descriptor so you can restore it if needed.

The Proxy chain

When a proxied script reads a variable such as window, the rewriter emits a call to __get_var__(window, "window"). That helper checks whether window (the real browser global) is still the same object as globalThis.window. If it is, it returns ctx.__proxy__.window instead, which is the value defined on CustomCTX — namely, ctx.__proxy__ itself. ctx.__proxy__ is produced by create_obj_proxy(ctx, ctx_vars, globalThis). Its get trap checks ctx first; if the key is defined there, it returns ctx[key]. Otherwise it falls back to globalThis[key], proxying arrow functions to preserve the correct this binding. Its set trap routes writes through ctx when the key is a ctx_var and through globalThis otherwise. This two-layer design means:
  • Reads of intercepted globals return Sandstone’s fake implementations.
  • Reads of unintercepted globals (e.g. Math, JSON) pass through transparently.
  • Writes to intercepted globals update ctx, not the real window.
  • Writes to unintercepted globals update the real window.

Build docs developers (and LLMs) love