Deterministic substitution for the sandbox's global whitelist.
This is the hinge the whole replay story turns on.
Avenx evaluates every template expression, computed property and action body
as source text under with(sandbox), and the sandbox proxy's has trap
claims every key. So every identifier those expressions resolve — Date,
Math, state, anything — passes through one get trap, and that trap
hands out globals from a single line. Substituting a recording clock there
costs nothing and cannot be bypassed from inside a template. Substituting a
replaying clock in the same place is what makes a recorded session
reproducible.
Frameworks that compile expressions to closures have no equivalent point:
by the time the code runs, Date is a free variable resolved against the
real global scope, and the only way back in is to rewrite the program.
What this does not cover
Bridge modules and anything they import are ordinary ES modules. They are
not sandboxed, so a Date.now() in a bridge action reaches the real clock
and is invisible here. That is a genuine hole, and it is why recording does
not get the final say on whether a trace is deterministic — replay verifies
the claim by comparing observations. See replay.js.
- Source:
Members
(inner, constant) markedReads :Set:.<string:>
Causal parents that have already been marked as reading a given
non-deterministic global, so a loop reading Date.now() a thousand times
produces one marker rather than a thousand.
Type:
- Source:
(inner, constant) overrides :Map:.<string:, any:>
Globals currently substituted for sandbox lookups, keyed by identifier.
Empty in normal operation, so resolveSandboxGlobal degenerates to a
Map.size check and a property read.
Type:
- Source:
Methods
(static) clearGlobalOverrides()
Removes every substitution, restoring the real globals.
- Source:
(static) hasGlobalOverrides() → {boolean}
Whether any global is currently substituted.
- Source:
Returns:
- Type
- boolean
(static) installRecordingGlobals(recorder)
Substitutes globals that log every non-deterministic value they hand out.
The values themselves are real — a recording session must behave exactly as an untraced one would — but each is appended to the recorder's global log so replay can hand the same sequence back.
Parameters:
| Name | Type | Description |
|---|---|---|
recorder |
object | The recorder to log into. |
- Source:
(static) installReplayGlobals(globals, onExhausted) → {Object}
Substitutes globals that replay a recorded sequence of values.
When the recorded sequence is exhausted the replay has consumed more
non-determinism than the recording produced, which means it has already
diverged. That is reported through onExhausted rather than papered over by
looping or by falling back to the real clock, either of which would let a
diverged replay finish looking successful.
Parameters:
- Source:
Returns:
Live read cursors, for assertions.
- Type
- Object
(static) resolveSandboxGlobal(key) → {any}
Resolves a whitelisted global for the expression sandbox.
The sandbox calls this instead of reading globalThis[key] directly, so a
recording or replaying session can substitute a deterministic implementation
without patching the page's real globals — which would leak into unrelated
scripts and outlive the recording.
Parameters:
| Name | Type | Description |
|---|---|---|
key |
string | The whitelisted global identifier. |
- Source:
Returns:
The value template code should see.
- Type
- any
(inner) buildDate(readClock) → {function}
Builds a Date stand-in that reports a caller-supplied clock.
prototype is aliased to the real Date.prototype and construction
delegates to the real constructor, so instances are genuine Date objects
and x instanceof Date keeps working in application code.
Parameters:
| Name | Type | Description |
|---|---|---|
readClock |
function | Supplies the epoch milliseconds for a "now" reading. |
- Source:
Returns:
A drop-in replacement for Date.
- Type
- function
(inner) buildMath(readRandom) → {object}
Builds a Math stand-in whose random is supplied by the trace.
Created with Object.create(Math) so every other member — max, floor,
PI — resolves through the prototype chain to the real implementation
rather than being copied, which would silently drop anything a future engine
adds.
Parameters:
| Name | Type | Description |
|---|---|---|
readRandom |
function | Supplies the next random value. |
- Source:
Returns:
A drop-in replacement for Math.
- Type
- object
(inner) markGlobalRead(kind)
Records that application code observed a non-deterministic global.
The values themselves go into the recorder's compact log; this marker exists
so the causal graph knows where the read happened. Contract analysis then
asks whether any ancestor of that point declared itself deterministic —
which is how a build-time contract becomes a claim checked against what the
code actually did. See trace/contracts.js.
Parameters:
| Name | Type | Description |
|---|---|---|
kind |
'now' | 'random' | Which source was read. |
- Source: