diff --git a/.changeset/activate-multiplexing.md b/.changeset/activate-multiplexing.md deleted file mode 100644 index aaf2a7d..0000000 --- a/.changeset/activate-multiplexing.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: runs share connections, and a run's slot frees at its Result (#127) - -Concurrent runs are multiplexed onto shared connections (several per -socket, routed by run id) instead of opening one connection each, and a run -with pending `waitUntil` work no longer holds admission capacity during its -background grace phase. `maxConcurrentRuns` semantics are unchanged; -`SandboxStats.openConnections` now tracks roughly peak concurrency divided -by the per-connection share instead of peak concurrency. diff --git a/.changeset/bridge-attribution-lookup.md b/.changeset/bridge-attribution-lookup.md deleted file mode 100644 index cc8a3ea..0000000 --- a/.changeset/bridge-attribution-lookup.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -perf: cheaper per-call attribution for bridge calls and console output (#127) - -Native callbacks resolve the owning run in one table lookup and take a -reference-counted handle to the stub binding instead of cloning it per -invocation. Attribution semantics are unchanged. diff --git a/.changeset/bump-v8-147.md b/.changeset/bump-v8-147.md deleted file mode 100644 index dc6e375..0000000 --- a/.changeset/bump-v8-147.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -chore: bump the v8 crate 130 → 147 (V8 13.0 → 14.7) - -The serialization format is unchanged, so `@iso4/sandbox` and `@iso4/v8-*` -still pair exactly as before. Most native paths are 10–47 % faster. diff --git a/.changeset/capacity-manager.md b/.changeset/capacity-manager.md deleted file mode 100644 index d96172f..0000000 --- a/.changeset/capacity-manager.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: capacity manager — memory budget and `sandbox.stats()` (#65) - -New `memoryBudgetMb` decides how many isolates stay alive, container-aware by -default, while `maxIsolates` still caps concurrent runs. `sandbox.stats()` -returns a capacity snapshot over a control connection outside the run pool. diff --git a/.changeset/capacity-rails.md b/.changeset/capacity-rails.md deleted file mode 100644 index 12ea640..0000000 --- a/.changeset/capacity-rails.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: memory capacity rails — global-container metering, a hard admission line, and bounded queueing (#77) - -Memory watermarks now measure the whole container (cgroup working set, -Node host included) instead of the runtime child alone, the budget default -becomes 80% of the container limit minus a 256 MB host reserve, and a new -isolate is never created when measured usage plus the run's `memoryMb` -would cross 90% of that base — such runs fail with the new `ERR_CAPACITY` -code instead of queueing. `maxConcurrentRuns`' automatic default is now -memory-bounded, and the new `maxQueuedRuns` (default 100 × slots) sheds -callers past the queue bound with the new `ERR_QUEUE_FULL` code. diff --git a/.changeset/clone-independent-body.md b/.changeset/clone-independent-body.md deleted file mode 100644 index 7288a32..0000000 --- a/.changeset/clone-independent-body.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: Request/Response clone() no longer shares its body buffer - -A cloned Request or Response now gets its own copy of a buffer body, so -mutating one side's bytes no longer reaches through to the other. diff --git a/.changeset/codegen-prepare-time-only.md b/.changeset/codegen-prepare-time-only.md deleted file mode 100644 index 1212fa5..0000000 --- a/.changeset/codegen-prepare-time-only.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -feat: disable eval and new Function in run code - -Code generation from strings is now a prepare()-time capability: setup code can still compile functions from strings, but per-run code calling `eval` or `new Function` gets a catchable `EvalError` and the run continues. diff --git a/.changeset/connection-writer-thread.md b/.changeset/connection-writer-thread.md deleted file mode 100644 index 8b9d814..0000000 --- a/.changeset/connection-writer-thread.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -fix: a host that stops draining a connection can no longer stall sandbox execution (#127) - -Outbound frames now go through a bounded per-connection queue with a -dedicated writer thread; a peer that stops reading fails that connection's -runs cleanly after a bounded wait instead of freezing every instance that -shares it. diff --git a/.changeset/cross-run-desync.md b/.changeset/cross-run-desync.md deleted file mode 100644 index 44a1020..0000000 --- a/.changeset/cross-run-desync.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -fix: connection integrity and result correlation (#73) - -Every `Result` is matched against the run that asked for it, and a connection -whose frame alignment is in doubt is replaced rather than reused. `maxIsolates` -is now a capacity rather than a fixed set of connections, and there is a new -host-detected error code `ERR_PROTOCOL_DESYNC`. diff --git a/.changeset/dns-after-authorize.md b/.changeset/dns-after-authorize.md deleted file mode 100644 index b36f615..0000000 --- a/.changeset/dns-after-authorize.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: resolve DNS only for authorized requests - -DNS is no longer resolved before the allow/deny check, so a denied host is -never looked up — closing a covert-lookup channel and an internal-network -oracle. The private/reserved-IP block now runs at connection time (for allowed -requests only) and `SafeFetchRequest.resolvedIp` is always `null`. diff --git a/.changeset/embed-icu-data.md b/.changeset/embed-icu-data.md deleted file mode 100644 index 0bf9dd6..0000000 --- a/.changeset/embed-icu-data.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-x64-gnu": patch -"@iso4/v8-linux-arm64-gnu": patch ---- - -Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. diff --git a/.changeset/eviction-scoring.md b/.changeset/eviction-scoring.md deleted file mode 100644 index 4e5df7d..0000000 --- a/.changeset/eviction-scoring.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: RSS watermark + scored eviction — `heapUsed × idleTime` (#66) - -The memory budget is enforced against the runtime's own process RSS: at the -mark, idle warm instances are evicted by score and new warm admissions stop -until RSS falls back to 80 % of it. `sandbox.stats()` gains `budgetBytes`, -`rssBytes` and `underPressure`; the instance-count cap is gone. diff --git a/.changeset/fetch-ipv6-origins.md b/.changeset/fetch-ipv6-origins.md deleted file mode 100644 index a58095d..0000000 --- a/.changeset/fetch-ipv6-origins.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: reach origins that resolve to IPv6 - -DNS pinning forced IPv4, so an IPv6-only host was unreachable and could end -the host process. Literal IPv6 URLs now resolve too, and `::` is treated as -reserved. diff --git a/.changeset/flat-read-ceiling.md b/.changeset/flat-read-ceiling.md deleted file mode 100644 index 0b27295..0000000 --- a/.changeset/flat-read-ceiling.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -fix: inbound frames are read against the flat protocol ceiling (#127) - -Per-run frame allowances are still enforced per run, but the connection's -read ceiling is now a constant — it can no longer shrink under an in-flight -frame, so a large late frame for a just-completed run is discarded instead -of costing the connection. diff --git a/.changeset/frame-reader-chunk-list.md b/.changeset/frame-reader-chunk-list.md deleted file mode 100644 index 122250c..0000000 --- a/.changeset/frame-reader-chunk-list.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -perf: receive large results without stalling the host - -Incoming chunks are joined once per frame instead of re-concatenated per -chunk. A 15 MB result now takes ~19 ms rather than ~1.2 s. diff --git a/.changeset/frozen-clock-cache.md b/.changeset/frozen-clock-cache.md deleted file mode 100644 index 6e2ca11..0000000 --- a/.changeset/frozen-clock-cache.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -perf: the frozen-clock advance no longer allocates V8 state per turn (#127) - -Clock handles are cached per isolate at install time; a turn within the -same wall millisecond now skips V8 entirely. Clock semantics are unchanged. diff --git a/.changeset/frozen-clock.md b/.changeset/frozen-clock.md deleted file mode 100644 index d46f295..0000000 --- a/.changeset/frozen-clock.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": minor -"@iso4/v8-darwin-arm64": minor -"@iso4/v8-darwin-x64": minor -"@iso4/v8-linux-x64-gnu": minor -"@iso4/v8-linux-arm64-gnu": minor ---- - -Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. diff --git a/.changeset/global-override-malformed.md b/.changeset/global-override-malformed.md deleted file mode 100644 index 8698b9c..0000000 --- a/.changeset/global-override-malformed.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: reject a supplied-but-malformed per-run global override - -A per-run `globals` override that is present but not a function (e.g. a tenant -handler that resolves to `undefined`) now throws instead of silently falling -back to the precompile-time default, matching the imports side. diff --git a/.changeset/global-watchdog.md b/.changeset/global-watchdog.md deleted file mode 100644 index a14876d..0000000 --- a/.changeset/global-watchdog.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) - -Warm instances hold one OS thread instead of two, so deployments with hard -per-container thread limits can keep roughly twice as many instances warm. -Budget and timeout semantics are unchanged. diff --git a/.changeset/host-claims-origin.md b/.changeset/host-claims-origin.md deleted file mode 100644 index a3ee339..0000000 --- a/.changeset/host-claims-origin.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: a matched host claims the origin for scheme and port - -A request whose host matches a rule but uses a disallowed scheme or port is now -denied, matching the route behaviour, instead of falling through to the -`policy` callback. diff --git a/.changeset/host-to-sandbox-call.md b/.changeset/host-to-sandbox-call.md deleted file mode 100644 index ae8acdf..0000000 --- a/.changeset/host-to-sandbox-call.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: host → sandbox function calls — `prefix.call({ export, args })` and `run({ code, call })` (#58) - -Call a function that already lives in the sandbox, addressed by export path, -with arguments crossing as one V8 blob. An export that cannot cross no longer -fails a plain run — it is reported in the new `skippedExports` instead. diff --git a/.changeset/instance-event-channel.md b/.changeset/instance-event-channel.md deleted file mode 100644 index 1dc83f4..0000000 --- a/.changeset/instance-event-channel.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -perf: instance turn loops route run events through one channel and a deadline heap (#127) - -Frame routing on a busy instance no longer scales with the number of -in-flight runs, and boundary deadlines fire in arrival order: co-resident -frame traffic can neither starve a run's wall timeout nor turn a run whose -answer arrived in time into one. diff --git a/.changeset/internals-dont-enum.md b/.changeset/internals-dont-enum.md deleted file mode 100644 index d531775..0000000 --- a/.changeset/internals-dont-enum.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: install runtime-internal globals non-enumerable - -The `__iso4_*` plumbing no longer appears in `Object.keys(globalThis)` or `for...in`; host-declared globals stay enumerable like browser globals. Sandbox code that enumerates its environment no longer trips over runtime internals. diff --git a/.changeset/kill-runtime-on-host-exit.md b/.changeset/kill-runtime-on-host-exit.md deleted file mode 100644 index c75656a..0000000 --- a/.changeset/kill-runtime-on-host-exit.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: stop the runtime when the host exits without `dispose()` - -A last-resort `exit` hook now ends it. `dispose()` is still the only complete -answer, since a host killed by a signal runs no JavaScript. diff --git a/.changeset/late-handler-stream-release.md b/.changeset/late-handler-stream-release.md deleted file mode 100644 index b490d5b..0000000 --- a/.changeset/late-handler-stream-release.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: a bridge handler settling after its run completed releases its streams (#127) - -A streamed body returned by a handler whose run already finished no longer -leaves its host-side reader locked; the source is released since nothing -will ever pump it. diff --git a/.changeset/literal-path-matching.md b/.changeset/literal-path-matching.md deleted file mode 100644 index 5e82558..0000000 --- a/.changeset/literal-path-matching.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: match request paths literally instead of decoding them - -The route allowlist now matches the path exactly as it is sent, with no -percent-decoding, so an encoded slash can no longer make the matched path differ -from the path on the wire. `.`/`..` are still normalised by the URL parser. diff --git a/.changeset/native-timers.md b/.changeset/native-timers.md deleted file mode 100644 index 2ed07e3..0000000 --- a/.changeset/native-timers.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: native `setTimeout`/`clearTimeout` in run code (#79) - -Timers run natively in the runtime's event loop: a sleep costs no CPU budget but counts against the wall budget, `Date.now()` advances by exactly the requested delay, and a run's pending timers die with it. Both names are now reserved global names; `setInterval` is deliberately not provided. diff --git a/.changeset/native-url-ada.md b/.changeset/native-url-ada.md deleted file mode 100644 index 1dcfd79..0000000 --- a/.changeset/native-url-ada.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: WHATWG-compliant URL in the sandbox - -The sandbox `URL` is now backed natively by the ada parser (the one Node.js -uses) and passes the WPT URL test suite, including IDNA, relative resolution -and non-special schemes. `URL.parse`, `URL.canParse` and the previously -missing component setters are now available. diff --git a/.changeset/oom-victim-preference.md b/.changeset/oom-victim-preference.md deleted file mode 100644 index c4dd335..0000000 --- a/.changeset/oom-victim-preference.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -feat: the runtime child marks itself as the preferred OOM victim (#77) - -On Linux the spawned runtime raises its own `oom_score_adj` at startup, so -a container out-of-memory kill takes the sandbox child (failed runs, a -respawnable sandbox) instead of the Node host. diff --git a/.changeset/outbox-inline-fast-path.md b/.changeset/outbox-inline-fast-path.md deleted file mode 100644 index 08d7038..0000000 --- a/.changeset/outbox-inline-fast-path.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -perf: outbound frames skip the writer thread when the socket is free (#127) - -Removes the flat per-call overhead the bounded outbound queue introduced -for short, frequent calls; the writer thread still takes over whenever the -socket backs up, so stall isolation is unchanged. diff --git a/.changeset/per-global-enumerable.md b/.changeset/per-global-enumerable.md deleted file mode 100644 index 1b79625..0000000 --- a/.changeset/per-global-enumerable.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -feat: per-global opt-out of enumerability - -The object global forms accept `enumerable: false` to keep an injected global out of `for...in` / `Object.keys` while staying callable, and new `{ kind: 'bridge', handler }` / `{ kind: 'string', expr }` object forms carry the option for what the shorthands declare. Shorthand globals stay enumerable. diff --git a/.changeset/per-workload-heap-caps.md b/.changeset/per-workload-heap-caps.md deleted file mode 100644 index df97e86..0000000 --- a/.changeset/per-workload-heap-caps.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: per-prefix and per-one-off heap caps (#77) - -`prepare({ memoryMb })` caps every isolate serving that prefix, and one-off -`run()` accepts `limits.memoryMb` again for its fresh isolate — the -sandbox-level `memoryMb` becomes the default for both. Prefix -`execute()`/`call()` still reject a per-run value: warm isolates are shared -and their cap is fixed at creation. diff --git a/.changeset/pre-dispatch-abort.md b/.changeset/pre-dispatch-abort.md deleted file mode 100644 index ea033d3..0000000 --- a/.changeset/pre-dispatch-abort.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -fix: an abort that arrives before its run starts still lands gracefully (#127) - -A Terminate (or connection loss) racing ahead of the run's dispatch is now -remembered and answered when the run arrives, instead of falling back to -the host-side teardown timeout. diff --git a/.changeset/prefix-aware-acquire.md b/.changeset/prefix-aware-acquire.md deleted file mode 100644 index 6cefbe8..0000000 --- a/.changeset/prefix-aware-acquire.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: prefix runs join busy instances; instances scale with measured CPU demand (#77) - -A prefix run with no idle instance now joins a busy one (the engine -interleaves runs) instead of always cold-starting, and another isolate is -opened only when the prefix's measured CPU demand justifies it — so -waiting-heavy traffic stops piling up isolates while compute-heavy traffic -still scales out for response time. `SandboxStats.activeRuns` now counts -runs (several can share one instance); `warmInstances` counts instances as -before. diff --git a/.changeset/prefix-top-level-await.md b/.changeset/prefix-top-level-await.md deleted file mode 100644 index bded163..0000000 --- a/.changeset/prefix-top-level-await.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: top-level `await` in prefix code no longer fails `prepare()` (#55) - -The runtime now drains the microtask queue until the prefix's evaluation -promise settles. Two new error codes state the remaining limits: -`ERR_PREFIX_BRIDGE_CALL` and `ERR_PREFIX_DID_NOT_SETTLE`. diff --git a/.changeset/private-symbol-type-tag.md b/.changeset/private-symbol-type-tag.md deleted file mode 100644 index be7c5df..0000000 --- a/.changeset/private-symbol-type-tag.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: identify runtime web types by an internal construction-time tag - -Serializing a `Headers`, `Request` or `Response` no longer depends on the classes being intact on `globalThis`, and overriding `Symbol.hasInstance` can no longer change how an instance crosses the boundary. diff --git a/.changeset/proto-own-key.md b/.changeset/proto-own-key.md deleted file mode 100644 index 2b83987..0000000 --- a/.changeset/proto-own-key.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: preserve an own `__proto__` key crossing into the sandbox - -Rebuilding a host-supplied plain object no longer triggers the prototype setter, -so an own-enumerable `__proto__` key (e.g. from `JSON.parse`) crosses as data -instead of being silently dropped. diff --git a/.changeset/redirect-credential-stripping.md b/.changeset/redirect-credential-stripping.md deleted file mode 100644 index 0fd39f2..0000000 --- a/.changeset/redirect-credential-stripping.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: strip credentials on cross-origin redirects - -Following a redirect to a different origin now drops `authorization`, `cookie` -and `proxy-authorization`, and a method-changing redirect drops `content-*` -headers, matching undici's redirect handling. diff --git a/.changeset/reduce-per-run-tax.md b/.changeset/reduce-per-run-tax.md deleted file mode 100644 index 07c2ac1..0000000 --- a/.changeset/reduce-per-run-tax.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@iso4/sandbox': patch ---- - -perf: cut fixed per-run overhead — ~4 % hot-run latency, ~6 % throughput - -Per-run trace logs are off by default; set `ISO4_V8_TRACE=1` to restore them. -Prefix snapshots are shared by handle instead of copied twice per run. diff --git a/.changeset/remove-runtime-snapshots.md b/.changeset/remove-runtime-snapshots.md deleted file mode 100644 index 11eccff..0000000 --- a/.changeset/remove-runtime-snapshots.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -refactor: remove runtime V8 snapshot creation — prefixes are validated source, re-evaluated per run (#60, #61, #62) - -The public API and the wire protocol are unchanged, but per-run latency now -includes prefix evaluation, and a nondeterministic prefix produces per-run -values. Closes the intermittent child-process crash under concurrent -`prepare()`. diff --git a/.changeset/run-router-slot-pool.md b/.changeset/run-router-slot-pool.md deleted file mode 100644 index 45b2f37..0000000 --- a/.changeset/run-router-slot-pool.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: run-slot admission, lazy connections, and a per-run frame router (#126) - -Breaking: `maxIsolates` is replaced by `maxConcurrentRuns` (same default) — it caps runs executing at once, the rest queue FIFO, and `AbortSignal.timeout()` bounds the wait. Connections to the runtime now open on demand instead of all at `createSandbox()`, and `stats()` gains `openConnections`. diff --git a/.changeset/sandbox-request-validation.md b/.changeset/sandbox-request-validation.md deleted file mode 100644 index 82257c4..0000000 --- a/.changeset/sandbox-request-validation.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: reject URL credentials and control-char statusText in the sandbox - -`new Request(url)` now throws when the URL includes credentials (fetch spec), -and `new Response` rejects a `statusText` containing control characters -(mirroring workerd) — so these fail on the user's line rather than host-side. diff --git a/.changeset/serialization-under-budget.md b/.changeset/serialization-under-budget.md deleted file mode 100644 index 091a53c..0000000 --- a/.changeset/serialization-under-budget.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: keep resource limits armed through result serialization - -Serializing a run's result executes guest getters, so it now stays under the -run's CPU, wall and memory budgets; serialization time counts against -`cpuTimeMs`/`wallTimeMs`. diff --git a/.changeset/session-demux-turn-loop.md b/.changeset/session-demux-turn-loop.md deleted file mode 100644 index a10ed5c..0000000 --- a/.changeset/session-demux-turn-loop.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@iso4/sandbox": minor -"@iso4/v8-darwin-arm64": minor -"@iso4/v8-darwin-x64": minor -"@iso4/v8-linux-arm64-gnu": minor -"@iso4/v8-linux-x64-gnu": minor ---- - -feat: session demux and per-instance turn loop (#125) - -Runs no longer hold a thread while suspended on host calls, and a waiting -run's abort or timeout now fails that run alone instead of evicting its -warm instance. New error code -`ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) -reports runs that were in flight on a shared instance when a co-resident run -had to be terminated mid-execution. diff --git a/.changeset/session-stamped-descriptors.md b/.changeset/session-stamped-descriptors.md deleted file mode 100644 index 774edcd..0000000 --- a/.changeset/session-stamped-descriptors.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: rehydrate only host-emitted host-type descriptors, stamped per session - -Host-to-sandbox `Headers`/`Request`/`Response` descriptors now carry a random per-sandbox stamp negotiated at connection setup, and the runtime rebuilds only stamped descriptors. Structured data passed into a run can no longer be reinterpreted as a host type, and no property name is reserved anymore. diff --git a/.changeset/setbody-detached.md b/.changeset/setbody-detached.md deleted file mode 100644 index f6ce92b..0000000 --- a/.changeset/setbody-detached.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: `setBody` no longer depends on `this` - -`ctx.req.setBody` can now be destructured or passed as a callback without -throwing; it writes the request body through a closure like `header` and -`setUrl`. diff --git a/.changeset/socket-private-dir.md b/.changeset/socket-private-dir.md deleted file mode 100644 index 359be58..0000000 --- a/.changeset/socket-private-dir.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: replace the argv auth token with a kernel-enforced private socket directory - -The runtime socket now lives in a fresh owner-only (0700) per-sandbox directory, so access is enforced by the kernel at connect time. The token is gone from the spawn args and the wire handshake (`@iso4/sandbox` and `@iso4/v8-*` are released in lockstep). diff --git a/.changeset/spawn-failure-contained.md b/.changeset/spawn-failure-contained.md deleted file mode 100644 index 9aeb11e..0000000 --- a/.changeset/spawn-failure-contained.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@iso4/sandbox": patch -"@iso4/v8-darwin-arm64": patch -"@iso4/v8-darwin-x64": patch -"@iso4/v8-linux-arm64-gnu": patch -"@iso4/v8-linux-x64-gnu": patch ---- - -fix: an instance thread that fails to spawn fails only its own run (#127) - -Under process resource exhaustion the affected run now reports -ERR_INTERNAL and the connection keeps serving, instead of the runtime -panicking the connection's demux. diff --git a/.changeset/startup-failure-cleanup.md b/.changeset/startup-failure-cleanup.md deleted file mode 100644 index 699c098..0000000 --- a/.changeset/startup-failure-cleanup.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: clean up the runtime process when `createSandbox()` fails - -A failed startup left the runtime running with no `Sandbox` to dispose it. A -runtime that exits during startup is now reported with its exit code instead -of a socket timeout. diff --git a/.changeset/stream-frame-run-validation.md b/.changeset/stream-frame-run-validation.md deleted file mode 100644 index 9cdabfe..0000000 --- a/.changeset/stream-frame-run-validation.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: stream frames must carry a real run id (#127) - -An unattributed stream frame (run id 0) now tears the connection down as a -protocol desync instead of being matched to a run by stream id — with -several runs on one connection that guess could credit or cancel the wrong -run's body stream. The production runtime always tags stream frames. diff --git a/.changeset/streaming-bodies.md b/.changeset/streaming-bodies.md deleted file mode 100644 index 3a865c0..0000000 --- a/.changeset/streaming-bodies.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -feat: stream large Request/Response bodies into the sandbox - -A host body that outgrows a 64 KiB probe now crosses as a stream pumped under flow control instead of being buffered whole: lower memory, and the sandbox starts reading on the first chunk via `.body` or the body helpers. Small bodies keep the buffered path unchanged; returning a streamed body to the host still requires reading it first. diff --git a/.changeset/tag-lookup-continue.md b/.changeset/tag-lookup-continue.md deleted file mode 100644 index 31b0843..0000000 --- a/.changeset/tag-lookup-continue.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -fix: identify runtime web types independently of one another during serialization - -Serializing a `Headers`, `Request` or `Response` no longer fails just because sandbox code removed or shadowed one of the other classes on `globalThis`. diff --git a/.changeset/tidy-pugs-shave.md b/.changeset/tidy-pugs-shave.md deleted file mode 100644 index 1e7ad7a..0000000 --- a/.changeset/tidy-pugs-shave.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: sandbox web runtime — `Headers`, `Request`, `Response`, `URL`, `TextEncoder` and friends - -`Request`, `Response` and `Headers` cross the boundary as real instances rather -than flattening to plain objects. New error code `ERR_TYPE_NOT_SERIALIZABLE` -for values that cannot cross; streams are deliberately unsupported. diff --git a/.changeset/timeout-whole-request.md b/.changeset/timeout-whole-request.md deleted file mode 100644 index 73a4764..0000000 --- a/.changeset/timeout-whole-request.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@iso4/fetch": patch ---- - -fix: `timeoutMs` bounds the whole request, not each redirect hop - -A single deadline now spans the entire redirect chain, so a redirecting request -can no longer run for `(maxRedirects + 1)` times the configured timeout. diff --git a/.changeset/v8-152-node-range.md b/.changeset/v8-152-node-range.md deleted file mode 100644 index 4e3ae99..0000000 --- a/.changeset/v8-152-node-range.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@iso4/sandbox": minor -"@iso4/v8-darwin-arm64": minor -"@iso4/v8-darwin-x64": minor -"@iso4/v8-linux-arm64-gnu": minor -"@iso4/v8-linux-x64-gnu": minor ---- - -feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) - -The runtime picks up five V8 release lines of security fixes and performance -work. Serialized values keep the format every shipping Node reads, while the -handshake now also accepts hosts on newer Node lines that write V8's -next serialization format — so Node 22 through 27 pair with the same binary. diff --git a/.changeset/v8-blob-wire-codec.md b/.changeset/v8-blob-wire-codec.md deleted file mode 100644 index 88956fd..0000000 --- a/.changeset/v8-blob-wire-codec.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat!: replace the WireValue codec with V8 serialization blobs - -Protocol version 1 → 2, so `@iso4/sandbox` and `@iso4/v8-*` must be updated -together and a mismatch now fails at `createSandbox()`. `Date`, `Map`, `Set`, -`RegExp`, `Error`, typed arrays and cycles round-trip as real instances, and -dense payloads are ~5.9× faster. diff --git a/.changeset/wait-until-grace-phase.md b/.changeset/wait-until-grace-phase.md deleted file mode 100644 index ba16cdb..0000000 --- a/.changeset/wait-until-grace-phase.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@iso4/sandbox": patch ---- - -feat: `waitUntil()` lets a run finish background work after its result - -Sandbox code can register background work with the new `waitUntil(promise)` global (also importable from `iso4:runtime`); the caller gets the result immediately and the work keeps running up to a configurable grace budget (`limits.graceMs`, default 30 s). The outcome arrives as `result.waitUntil`, a never-rejecting promise with status and telemetry. diff --git a/.changeset/warm-isolate-registry.md b/.changeset/warm-isolate-registry.md deleted file mode 100644 index a0c389e..0000000 --- a/.changeset/warm-isolate-registry.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: warm isolate registry — prefix runs reuse resident isolates (#64) - -Warmth is a cache and never a guarantee: module-scope state may survive between -runs on an instance and may be evicted at any time. Breaking — `limits.memoryMb` -moves to `createSandbox({ memoryMb })` with the default raised to 128 MB; new -`ERR_WARMUP_LIMIT` and a new `heapUsedBytes` result field. diff --git a/.changeset/widen-host-export-data.md b/.changeset/widen-host-export-data.md deleted file mode 100644 index 815f7f2..0000000 --- a/.changeset/widen-host-export-data.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@iso4/sandbox": minor ---- - -feat: widen `HostExportData` to everything V8 serialization carries - -`Date`, `RegExp`, `Error`, `Map`, `Set`, `ArrayBuffer`, typed arrays, `DataView` -and cycles now cross as real instances. Host-module data leaves are no longer -inspected at registration, so an unsupported value fails with the serializer's -own error rather than one naming the exact leaf path. diff --git a/packages/iso4-fetch/CHANGELOG.md b/packages/iso4-fetch/CHANGELOG.md index b486eef..62cbdd5 100644 --- a/packages/iso4-fetch/CHANGELOG.md +++ b/packages/iso4-fetch/CHANGELOG.md @@ -1,5 +1,51 @@ # @iso4/fetch +## 0.0.2 + +### Patch Changes + +- 7fb2cde: fix: resolve DNS only for authorized requests + + DNS is no longer resolved before the allow/deny check, so a denied host is + never looked up — closing a covert-lookup channel and an internal-network + oracle. The private/reserved-IP block now runs at connection time (for allowed + requests only) and `SafeFetchRequest.resolvedIp` is always `null`. + +- 5ca5ab9: fix: reach origins that resolve to IPv6 + + DNS pinning forced IPv4, so an IPv6-only host was unreachable and could end + the host process. Literal IPv6 URLs now resolve too, and `::` is treated as + reserved. + +- 939afdd: fix: a matched host claims the origin for scheme and port + + A request whose host matches a rule but uses a disallowed scheme or port is now + denied, matching the route behaviour, instead of falling through to the + `policy` callback. + +- 1c8cc0a: fix: match request paths literally instead of decoding them + + The route allowlist now matches the path exactly as it is sent, with no + percent-decoding, so an encoded slash can no longer make the matched path differ + from the path on the wire. `.`/`..` are still normalised by the URL parser. + +- fd0cd30: fix: strip credentials on cross-origin redirects + + Following a redirect to a different origin now drops `authorization`, `cookie` + and `proxy-authorization`, and a method-changing redirect drops `content-*` + headers, matching undici's redirect handling. + +- c501131: fix: `setBody` no longer depends on `this` + + `ctx.req.setBody` can now be destructured or passed as a callback without + throwing; it writes the request body through a closure like `header` and + `setUrl`. + +- d544d5b: fix: `timeoutMs` bounds the whole request, not each redirect hop + + A single deadline now spans the entire redirect chain, so a redirecting request + can no longer run for `(maxRedirects + 1)` times the configured timeout. + ## 0.0.1 ### Patch Changes diff --git a/packages/iso4-fetch/package.json b/packages/iso4-fetch/package.json index 3070f35..67da737 100644 --- a/packages/iso4-fetch/package.json +++ b/packages/iso4-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/fetch", - "version": "0.0.1", + "version": "0.0.2", "type": "module", "description": "Hardened FetchHandler for the @iso4/sandbox runtime: DNS pinning, host allowlist, private-IP blocking, no auto-redirect", "keywords": [ diff --git a/packages/iso4-sandbox/CHANGELOG.md b/packages/iso4-sandbox/CHANGELOG.md index 905a078..13d9851 100644 --- a/packages/iso4-sandbox/CHANGELOG.md +++ b/packages/iso4-sandbox/CHANGELOG.md @@ -1,5 +1,314 @@ # @iso4/sandbox +## 0.5.0 + +### Minor Changes + +- 2f90212: feat: runs share connections, and a run's slot frees at its Result (#127) + + Concurrent runs are multiplexed onto shared connections (several per + socket, routed by run id) instead of opening one connection each, and a run + with pending `waitUntil` work no longer holds admission capacity during its + background grace phase. `maxConcurrentRuns` semantics are unchanged; + `SandboxStats.openConnections` now tracks roughly peak concurrency divided + by the per-connection share instead of peak concurrency. + +- c6c7d13: chore: bump the v8 crate 130 → 147 (V8 13.0 → 14.7) + + The serialization format is unchanged, so `@iso4/sandbox` and `@iso4/v8-*` + still pair exactly as before. Most native paths are 10–47 % faster. + +- 344d259: feat: capacity manager — memory budget and `sandbox.stats()` (#65) + + New `memoryBudgetMb` decides how many isolates stay alive, container-aware by + default, while `maxIsolates` still caps concurrent runs. `sandbox.stats()` + returns a capacity snapshot over a control connection outside the run pool. + +- 16cce13: feat: memory capacity rails — global-container metering, a hard admission line, and bounded queueing (#77) + + Memory watermarks now measure the whole container (cgroup working set, + Node host included) instead of the runtime child alone, the budget default + becomes 80% of the container limit minus a 256 MB host reserve, and a new + isolate is never created when measured usage plus the run's `memoryMb` + would cross 90% of that base — such runs fail with the new `ERR_CAPACITY` + code instead of queueing. `maxConcurrentRuns`' automatic default is now + memory-bounded, and the new `maxQueuedRuns` (default 100 × slots) sheds + callers past the queue bound with the new `ERR_QUEUE_FULL` code. + +- a5a6739: fix: connection integrity and result correlation (#73) + + Every `Result` is matched against the run that asked for it, and a connection + whose frame alignment is in doubt is replaced rather than reused. `maxIsolates` + is now a capacity rather than a fixed set of connections, and there is a new + host-detected error code `ERR_PROTOCOL_DESYNC`. + +- e074119: feat: RSS watermark + scored eviction — `heapUsed × idleTime` (#66) + + The memory budget is enforced against the runtime's own process RSS: at the + mark, idle warm instances are evicted by score and new warm admissions stop + until RSS falls back to 80 % of it. `sandbox.stats()` gains `budgetBytes`, + `rssBytes` and `underPressure`; the instance-count cap is gone. + +- f962a14: Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. +- b45658c: feat: host → sandbox function calls — `prefix.call({ export, args })` and `run({ code, call })` (#58) + + Call a function that already lives in the sandbox, addressed by export path, + with arguments crossing as one V8 blob. An export that cannot cross no longer + fails a plain run — it is reported in the new `skippedExports` instead. + +- 71b3f26: feat: native `setTimeout`/`clearTimeout` in run code (#79) + + Timers run natively in the runtime's event loop: a sleep costs no CPU budget but counts against the wall budget, `Date.now()` advances by exactly the requested delay, and a run's pending timers die with it. Both names are now reserved global names; `setInterval` is deliberately not provided. + +- ec9e042: feat: per-prefix and per-one-off heap caps (#77) + + `prepare({ memoryMb })` caps every isolate serving that prefix, and one-off + `run()` accepts `limits.memoryMb` again for its fresh isolate — the + sandbox-level `memoryMb` becomes the default for both. Prefix + `execute()`/`call()` still reject a per-run value: warm isolates are shared + and their cap is fixed at creation. + +- f49f2b2: feat: prefix runs join busy instances; instances scale with measured CPU demand (#77) + + A prefix run with no idle instance now joins a busy one (the engine + interleaves runs) instead of always cold-starting, and another isolate is + opened only when the prefix's measured CPU demand justifies it — so + waiting-heavy traffic stops piling up isolates while compute-heavy traffic + still scales out for response time. `SandboxStats.activeRuns` now counts + runs (several can share one instance); `warmInstances` counts instances as + before. + +- 911a82d: refactor: remove runtime V8 snapshot creation — prefixes are validated source, re-evaluated per run (#60, #61, #62) + + The public API and the wire protocol are unchanged, but per-run latency now + includes prefix evaluation, and a nondeterministic prefix produces per-run + values. Closes the intermittent child-process crash under concurrent + `prepare()`. + +- bbcd205: feat: run-slot admission, lazy connections, and a per-run frame router (#126) + + Breaking: `maxIsolates` is replaced by `maxConcurrentRuns` (same default) — it caps runs executing at once, the rest queue FIFO, and `AbortSignal.timeout()` bounds the wait. Connections to the runtime now open on demand instead of all at `createSandbox()`, and `stats()` gains `openConnections`. + +- 139386b: feat: session demux and per-instance turn loop (#125) + + Runs no longer hold a thread while suspended on host calls, and a waiting + run's abort or timeout now fails that run alone instead of evicting its + warm instance. New error code + `ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) + reports runs that were in flight on a shared instance when a co-resident run + had to be terminated mid-execution. + +- cf851bf: feat: sandbox web runtime — `Headers`, `Request`, `Response`, `URL`, `TextEncoder` and friends + + `Request`, `Response` and `Headers` cross the boundary as real instances rather + than flattening to plain objects. New error code `ERR_TYPE_NOT_SERIALIZABLE` + for values that cannot cross; streams are deliberately unsupported. + +- e1b10fc: feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) + + The runtime picks up five V8 release lines of security fixes and performance + work. Serialized values keep the format every shipping Node reads, while the + handshake now also accepts hosts on newer Node lines that write V8's + next serialization format — so Node 22 through 27 pair with the same binary. + +- 467479f: feat!: replace the WireValue codec with V8 serialization blobs + + Protocol version 1 → 2, so `@iso4/sandbox` and `@iso4/v8-*` must be updated + together and a mismatch now fails at `createSandbox()`. `Date`, `Map`, `Set`, + `RegExp`, `Error`, typed arrays and cycles round-trip as real instances, and + dense payloads are ~5.9× faster. + +- b2a19f8: feat: warm isolate registry — prefix runs reuse resident isolates (#64) + + Warmth is a cache and never a guarantee: module-scope state may survive between + runs on an instance and may be evicted at any time. Breaking — `limits.memoryMb` + moves to `createSandbox({ memoryMb })` with the default raised to 128 MB; new + `ERR_WARMUP_LIMIT` and a new `heapUsedBytes` result field. + +- ea8937f: feat: widen `HostExportData` to everything V8 serialization carries + + `Date`, `RegExp`, `Error`, `Map`, `Set`, `ArrayBuffer`, typed arrays, `DataView` + and cycles now cross as real instances. Host-module data leaves are no longer + inspected at registration, so an unsupported value fails with the serializer's + own error rather than one naming the exact leaf path. + +### Patch Changes + +- fd462aa: perf: cheaper per-call attribution for bridge calls and console output (#127) + + Native callbacks resolve the owning run in one table lookup and take a + reference-counted handle to the stub binding instead of cloning it per + invocation. Attribution semantics are unchanged. + +- f1a2e24: fix: Request/Response clone() no longer shares its body buffer + + A cloned Request or Response now gets its own copy of a buffer body, so + mutating one side's bytes no longer reaches through to the other. + +- 17a87e7: feat: disable eval and new Function in run code + + Code generation from strings is now a prepare()-time capability: setup code can still compile functions from strings, but per-run code calling `eval` or `new Function` gets a catchable `EvalError` and the run continues. + +- f6cddb7: fix: a host that stops draining a connection can no longer stall sandbox execution (#127) + + Outbound frames now go through a bounded per-connection queue with a + dedicated writer thread; a peer that stops reading fails that connection's + runs cleanly after a bounded wait instead of freezing every instance that + shares it. + +- 61e420c: Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. +- 8871645: fix: inbound frames are read against the flat protocol ceiling (#127) + + Per-run frame allowances are still enforced per run, but the connection's + read ceiling is now a constant — it can no longer shrink under an in-flight + frame, so a large late frame for a just-completed run is discarded instead + of costing the connection. + +- 5ca5ab9: perf: receive large results without stalling the host + + Incoming chunks are joined once per frame instead of re-concatenated per + chunk. A 15 MB result now takes ~19 ms rather than ~1.2 s. + +- f186aec: perf: the frozen-clock advance no longer allocates V8 state per turn (#127) + + Clock handles are cached per isolate at install time; a turn within the + same wall millisecond now skips V8 entirely. Clock semantics are unchanged. + +- 5a5cfbe: fix: reject a supplied-but-malformed per-run global override + + A per-run `globals` override that is present but not a function (e.g. a tenant + handler that resolves to `undefined`) now throws instead of silently falling + back to the precompile-time default, matching the imports side. + +- 03b9e46: perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) + + Warm instances hold one OS thread instead of two, so deployments with hard + per-container thread limits can keep roughly twice as many instances warm. + Budget and timeout semantics are unchanged. + +- dbd1caf: perf: instance turn loops route run events through one channel and a deadline heap (#127) + + Frame routing on a busy instance no longer scales with the number of + in-flight runs, and boundary deadlines fire in arrival order: co-resident + frame traffic can neither starve a run's wall timeout nor turn a run whose + answer arrived in time into one. + +- 768d839: fix: install runtime-internal globals non-enumerable + + The `__iso4_*` plumbing no longer appears in `Object.keys(globalThis)` or `for...in`; host-declared globals stay enumerable like browser globals. Sandbox code that enumerates its environment no longer trips over runtime internals. + +- 5ca5ab9: fix: stop the runtime when the host exits without `dispose()` + + A last-resort `exit` hook now ends it. `dispose()` is still the only complete + answer, since a host killed by a signal runs no JavaScript. + +- f6b13f8: fix: a bridge handler settling after its run completed releases its streams (#127) + + A streamed body returned by a handler whose run already finished no longer + leaves its host-side reader locked; the source is released since nothing + will ever pump it. + +- 3637971: fix: WHATWG-compliant URL in the sandbox + + The sandbox `URL` is now backed natively by the ada parser (the one Node.js + uses) and passes the WPT URL test suite, including IDNA, relative resolution + and non-special schemes. `URL.parse`, `URL.canParse` and the previously + missing component setters are now available. + +- 926a690: feat: the runtime child marks itself as the preferred OOM victim (#77) + + On Linux the spawned runtime raises its own `oom_score_adj` at startup, so + a container out-of-memory kill takes the sandbox child (failed runs, a + respawnable sandbox) instead of the Node host. + +- 7aec3d4: perf: outbound frames skip the writer thread when the socket is free (#127) + + Removes the flat per-call overhead the bounded outbound queue introduced + for short, frequent calls; the writer thread still takes over whenever the + socket backs up, so stall isolation is unchanged. + +- a1f6e4a: feat: per-global opt-out of enumerability + + The object global forms accept `enumerable: false` to keep an injected global out of `for...in` / `Object.keys` while staying callable, and new `{ kind: 'bridge', handler }` / `{ kind: 'string', expr }` object forms carry the option for what the shorthands declare. Shorthand globals stay enumerable. + +- 2e6fb0f: fix: an abort that arrives before its run starts still lands gracefully (#127) + + A Terminate (or connection loss) racing ahead of the run's dispatch is now + remembered and answered when the run arrives, instead of falling back to + the host-side teardown timeout. + +- 1925209: fix: top-level `await` in prefix code no longer fails `prepare()` (#55) + + The runtime now drains the microtask queue until the prefix's evaluation + promise settles. Two new error codes state the remaining limits: + `ERR_PREFIX_BRIDGE_CALL` and `ERR_PREFIX_DID_NOT_SETTLE`. + +- 1ed87b3: fix: identify runtime web types by an internal construction-time tag + + Serializing a `Headers`, `Request` or `Response` no longer depends on the classes being intact on `globalThis`, and overriding `Symbol.hasInstance` can no longer change how an instance crosses the boundary. + +- c0de1ab: fix: preserve an own `__proto__` key crossing into the sandbox + + Rebuilding a host-supplied plain object no longer triggers the prototype setter, + so an own-enumerable `__proto__` key (e.g. from `JSON.parse`) crosses as data + instead of being silently dropped. + +- cf037f8: perf: cut fixed per-run overhead — ~4 % hot-run latency, ~6 % throughput + + Per-run trace logs are off by default; set `ISO4_V8_TRACE=1` to restore them. + Prefix snapshots are shared by handle instead of copied twice per run. + +- 9819e84: fix: reject URL credentials and control-char statusText in the sandbox + + `new Request(url)` now throws when the URL includes credentials (fetch spec), + and `new Response` rejects a `statusText` containing control characters + (mirroring workerd) — so these fail on the user's line rather than host-side. + +- 51e824d: fix: keep resource limits armed through result serialization + + Serializing a run's result executes guest getters, so it now stays under the + run's CPU, wall and memory budgets; serialization time counts against + `cpuTimeMs`/`wallTimeMs`. + +- 6c8c0da: fix: rehydrate only host-emitted host-type descriptors, stamped per session + + Host-to-sandbox `Headers`/`Request`/`Response` descriptors now carry a random per-sandbox stamp negotiated at connection setup, and the runtime rebuilds only stamped descriptors. Structured data passed into a run can no longer be reinterpreted as a host type, and no property name is reserved anymore. + +- 343da7a: fix: replace the argv auth token with a kernel-enforced private socket directory + + The runtime socket now lives in a fresh owner-only (0700) per-sandbox directory, so access is enforced by the kernel at connect time. The token is gone from the spawn args and the wire handshake (`@iso4/sandbox` and `@iso4/v8-*` are released in lockstep). + +- 3504569: fix: an instance thread that fails to spawn fails only its own run (#127) + + Under process resource exhaustion the affected run now reports + ERR_INTERNAL and the connection keeps serving, instead of the runtime + panicking the connection's demux. + +- 5ca5ab9: fix: clean up the runtime process when `createSandbox()` fails + + A failed startup left the runtime running with no `Sandbox` to dispose it. A + runtime that exits during startup is now reported with its exit code instead + of a socket timeout. + +- 985e9b6: fix: stream frames must carry a real run id (#127) + + An unattributed stream frame (run id 0) now tears the connection down as a + protocol desync instead of being matched to a run by stream id — with + several runs on one connection that guess could credit or cancel the wrong + run's body stream. The production runtime always tags stream frames. + +- 6cb167b: feat: stream large Request/Response bodies into the sandbox + + A host body that outgrows a 64 KiB probe now crosses as a stream pumped under flow control instead of being buffered whole: lower memory, and the sandbox starts reading on the first chunk via `.body` or the body helpers. Small bodies keep the buffered path unchanged; returning a streamed body to the host still requires reading it first. + +- ba357d0: fix: identify runtime web types independently of one another during serialization + + Serializing a `Headers`, `Request` or `Response` no longer fails just because sandbox code removed or shadowed one of the other classes on `globalThis`. + +- 3586fcd: feat: `waitUntil()` lets a run finish background work after its result + + Sandbox code can register background work with the new `waitUntil(promise)` global (also importable from `iso4:runtime`); the caller gets the result immediately and the work keeps running up to a configurable grace budget (`limits.graceMs`, default 30 s). The outcome arrives as `result.waitUntil`, a never-rejecting promise with status and telemetry. + ## 0.4.1 ### Patch Changes diff --git a/packages/iso4-sandbox/package.json b/packages/iso4-sandbox/package.json index bbb8895..e723baa 100644 --- a/packages/iso4-sandbox/package.json +++ b/packages/iso4-sandbox/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/sandbox", - "version": "0.4.1", + "version": "0.5.0", "type": "module", "description": "Fast, sandboxed V8 isolate runtime for agent-generated JavaScript. Two-process architecture for crash isolation.", "keywords": [ diff --git a/packages/iso4-v8-darwin-arm64/CHANGELOG.md b/packages/iso4-v8-darwin-arm64/CHANGELOG.md index 7f9e6d2..9751db1 100644 --- a/packages/iso4-v8-darwin-arm64/CHANGELOG.md +++ b/packages/iso4-v8-darwin-arm64/CHANGELOG.md @@ -1,5 +1,85 @@ # @iso4/v8-darwin-arm64 +## 0.5.0 + +### Minor Changes + +- f962a14: Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. +- 139386b: feat: session demux and per-instance turn loop (#125) + + Runs no longer hold a thread while suspended on host calls, and a waiting + run's abort or timeout now fails that run alone instead of evicting its + warm instance. New error code + `ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) + reports runs that were in flight on a shared instance when a co-resident run + had to be terminated mid-execution. + +- e1b10fc: feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) + + The runtime picks up five V8 release lines of security fixes and performance + work. Serialized values keep the format every shipping Node reads, while the + handshake now also accepts hosts on newer Node lines that write V8's + next serialization format — so Node 22 through 27 pair with the same binary. + +### Patch Changes + +- fd462aa: perf: cheaper per-call attribution for bridge calls and console output (#127) + + Native callbacks resolve the owning run in one table lookup and take a + reference-counted handle to the stub binding instead of cloning it per + invocation. Attribution semantics are unchanged. + +- f6cddb7: fix: a host that stops draining a connection can no longer stall sandbox execution (#127) + + Outbound frames now go through a bounded per-connection queue with a + dedicated writer thread; a peer that stops reading fails that connection's + runs cleanly after a bounded wait instead of freezing every instance that + shares it. + +- 61e420c: Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. +- 8871645: fix: inbound frames are read against the flat protocol ceiling (#127) + + Per-run frame allowances are still enforced per run, but the connection's + read ceiling is now a constant — it can no longer shrink under an in-flight + frame, so a large late frame for a just-completed run is discarded instead + of costing the connection. + +- f186aec: perf: the frozen-clock advance no longer allocates V8 state per turn (#127) + + Clock handles are cached per isolate at install time; a turn within the + same wall millisecond now skips V8 entirely. Clock semantics are unchanged. + +- 03b9e46: perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) + + Warm instances hold one OS thread instead of two, so deployments with hard + per-container thread limits can keep roughly twice as many instances warm. + Budget and timeout semantics are unchanged. + +- dbd1caf: perf: instance turn loops route run events through one channel and a deadline heap (#127) + + Frame routing on a busy instance no longer scales with the number of + in-flight runs, and boundary deadlines fire in arrival order: co-resident + frame traffic can neither starve a run's wall timeout nor turn a run whose + answer arrived in time into one. + +- 7aec3d4: perf: outbound frames skip the writer thread when the socket is free (#127) + + Removes the flat per-call overhead the bounded outbound queue introduced + for short, frequent calls; the writer thread still takes over whenever the + socket backs up, so stall isolation is unchanged. + +- 2e6fb0f: fix: an abort that arrives before its run starts still lands gracefully (#127) + + A Terminate (or connection loss) racing ahead of the run's dispatch is now + remembered and answered when the run arrives, instead of falling back to + the host-side teardown timeout. + +- 3504569: fix: an instance thread that fails to spawn fails only its own run (#127) + + Under process resource exhaustion the affected run now reports + ERR_INTERNAL and the connection keeps serving, instead of the runtime + panicking the connection's demux. + ## 0.4.1 ## 0.4.0 diff --git a/packages/iso4-v8-darwin-arm64/package.json b/packages/iso4-v8-darwin-arm64/package.json index 469d4cd..fc855d8 100644 --- a/packages/iso4-v8-darwin-arm64/package.json +++ b/packages/iso4-v8-darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/v8-darwin-arm64", - "version": "0.4.1", + "version": "0.5.0", "type": "module", "description": "Native iso4 V8 runtime binary for darwin-arm64", "license": "MIT", diff --git a/packages/iso4-v8-darwin-x64/CHANGELOG.md b/packages/iso4-v8-darwin-x64/CHANGELOG.md index 03d65f5..2b30093 100644 --- a/packages/iso4-v8-darwin-x64/CHANGELOG.md +++ b/packages/iso4-v8-darwin-x64/CHANGELOG.md @@ -1,5 +1,85 @@ # @iso4/v8-darwin-x64 +## 0.5.0 + +### Minor Changes + +- f962a14: Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. +- 139386b: feat: session demux and per-instance turn loop (#125) + + Runs no longer hold a thread while suspended on host calls, and a waiting + run's abort or timeout now fails that run alone instead of evicting its + warm instance. New error code + `ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) + reports runs that were in flight on a shared instance when a co-resident run + had to be terminated mid-execution. + +- e1b10fc: feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) + + The runtime picks up five V8 release lines of security fixes and performance + work. Serialized values keep the format every shipping Node reads, while the + handshake now also accepts hosts on newer Node lines that write V8's + next serialization format — so Node 22 through 27 pair with the same binary. + +### Patch Changes + +- fd462aa: perf: cheaper per-call attribution for bridge calls and console output (#127) + + Native callbacks resolve the owning run in one table lookup and take a + reference-counted handle to the stub binding instead of cloning it per + invocation. Attribution semantics are unchanged. + +- f6cddb7: fix: a host that stops draining a connection can no longer stall sandbox execution (#127) + + Outbound frames now go through a bounded per-connection queue with a + dedicated writer thread; a peer that stops reading fails that connection's + runs cleanly after a bounded wait instead of freezing every instance that + shares it. + +- 61e420c: Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. +- 8871645: fix: inbound frames are read against the flat protocol ceiling (#127) + + Per-run frame allowances are still enforced per run, but the connection's + read ceiling is now a constant — it can no longer shrink under an in-flight + frame, so a large late frame for a just-completed run is discarded instead + of costing the connection. + +- f186aec: perf: the frozen-clock advance no longer allocates V8 state per turn (#127) + + Clock handles are cached per isolate at install time; a turn within the + same wall millisecond now skips V8 entirely. Clock semantics are unchanged. + +- 03b9e46: perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) + + Warm instances hold one OS thread instead of two, so deployments with hard + per-container thread limits can keep roughly twice as many instances warm. + Budget and timeout semantics are unchanged. + +- dbd1caf: perf: instance turn loops route run events through one channel and a deadline heap (#127) + + Frame routing on a busy instance no longer scales with the number of + in-flight runs, and boundary deadlines fire in arrival order: co-resident + frame traffic can neither starve a run's wall timeout nor turn a run whose + answer arrived in time into one. + +- 7aec3d4: perf: outbound frames skip the writer thread when the socket is free (#127) + + Removes the flat per-call overhead the bounded outbound queue introduced + for short, frequent calls; the writer thread still takes over whenever the + socket backs up, so stall isolation is unchanged. + +- 2e6fb0f: fix: an abort that arrives before its run starts still lands gracefully (#127) + + A Terminate (or connection loss) racing ahead of the run's dispatch is now + remembered and answered when the run arrives, instead of falling back to + the host-side teardown timeout. + +- 3504569: fix: an instance thread that fails to spawn fails only its own run (#127) + + Under process resource exhaustion the affected run now reports + ERR_INTERNAL and the connection keeps serving, instead of the runtime + panicking the connection's demux. + ## 0.4.1 ## 0.4.0 diff --git a/packages/iso4-v8-darwin-x64/package.json b/packages/iso4-v8-darwin-x64/package.json index 3b20dd6..b37ba14 100644 --- a/packages/iso4-v8-darwin-x64/package.json +++ b/packages/iso4-v8-darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/v8-darwin-x64", - "version": "0.4.1", + "version": "0.5.0", "type": "module", "description": "Native iso4 V8 runtime binary for darwin-x64", "license": "MIT", diff --git a/packages/iso4-v8-linux-arm64-gnu/CHANGELOG.md b/packages/iso4-v8-linux-arm64-gnu/CHANGELOG.md index e5a89a1..04c5d14 100644 --- a/packages/iso4-v8-linux-arm64-gnu/CHANGELOG.md +++ b/packages/iso4-v8-linux-arm64-gnu/CHANGELOG.md @@ -1,5 +1,85 @@ # @iso4/v8-linux-arm64-gnu +## 0.5.0 + +### Minor Changes + +- f962a14: Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. +- 139386b: feat: session demux and per-instance turn loop (#125) + + Runs no longer hold a thread while suspended on host calls, and a waiting + run's abort or timeout now fails that run alone instead of evicting its + warm instance. New error code + `ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) + reports runs that were in flight on a shared instance when a co-resident run + had to be terminated mid-execution. + +- e1b10fc: feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) + + The runtime picks up five V8 release lines of security fixes and performance + work. Serialized values keep the format every shipping Node reads, while the + handshake now also accepts hosts on newer Node lines that write V8's + next serialization format — so Node 22 through 27 pair with the same binary. + +### Patch Changes + +- fd462aa: perf: cheaper per-call attribution for bridge calls and console output (#127) + + Native callbacks resolve the owning run in one table lookup and take a + reference-counted handle to the stub binding instead of cloning it per + invocation. Attribution semantics are unchanged. + +- f6cddb7: fix: a host that stops draining a connection can no longer stall sandbox execution (#127) + + Outbound frames now go through a bounded per-connection queue with a + dedicated writer thread; a peer that stops reading fails that connection's + runs cleanly after a bounded wait instead of freezing every instance that + shares it. + +- 61e420c: Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. +- 8871645: fix: inbound frames are read against the flat protocol ceiling (#127) + + Per-run frame allowances are still enforced per run, but the connection's + read ceiling is now a constant — it can no longer shrink under an in-flight + frame, so a large late frame for a just-completed run is discarded instead + of costing the connection. + +- f186aec: perf: the frozen-clock advance no longer allocates V8 state per turn (#127) + + Clock handles are cached per isolate at install time; a turn within the + same wall millisecond now skips V8 entirely. Clock semantics are unchanged. + +- 03b9e46: perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) + + Warm instances hold one OS thread instead of two, so deployments with hard + per-container thread limits can keep roughly twice as many instances warm. + Budget and timeout semantics are unchanged. + +- dbd1caf: perf: instance turn loops route run events through one channel and a deadline heap (#127) + + Frame routing on a busy instance no longer scales with the number of + in-flight runs, and boundary deadlines fire in arrival order: co-resident + frame traffic can neither starve a run's wall timeout nor turn a run whose + answer arrived in time into one. + +- 7aec3d4: perf: outbound frames skip the writer thread when the socket is free (#127) + + Removes the flat per-call overhead the bounded outbound queue introduced + for short, frequent calls; the writer thread still takes over whenever the + socket backs up, so stall isolation is unchanged. + +- 2e6fb0f: fix: an abort that arrives before its run starts still lands gracefully (#127) + + A Terminate (or connection loss) racing ahead of the run's dispatch is now + remembered and answered when the run arrives, instead of falling back to + the host-side teardown timeout. + +- 3504569: fix: an instance thread that fails to spawn fails only its own run (#127) + + Under process resource exhaustion the affected run now reports + ERR_INTERNAL and the connection keeps serving, instead of the runtime + panicking the connection's demux. + ## 0.4.1 ## 0.4.0 diff --git a/packages/iso4-v8-linux-arm64-gnu/package.json b/packages/iso4-v8-linux-arm64-gnu/package.json index 6dc7782..0e90aec 100644 --- a/packages/iso4-v8-linux-arm64-gnu/package.json +++ b/packages/iso4-v8-linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/v8-linux-arm64-gnu", - "version": "0.4.1", + "version": "0.5.0", "type": "module", "description": "Native iso4 V8 runtime binary for linux-arm64-gnu", "license": "MIT", diff --git a/packages/iso4-v8-linux-x64-gnu/CHANGELOG.md b/packages/iso4-v8-linux-x64-gnu/CHANGELOG.md index 8650e5d..be91e9e 100644 --- a/packages/iso4-v8-linux-x64-gnu/CHANGELOG.md +++ b/packages/iso4-v8-linux-x64-gnu/CHANGELOG.md @@ -1,5 +1,85 @@ # @iso4/v8-linux-x64-gnu +## 0.5.0 + +### Minor Changes + +- f962a14: Freeze the sandbox clock during execution, workerd-style. `Date.now()`, no-arg `new Date()`/`Date()`, no-arg `Intl.DateTimeFormat` formatting, and `Temporal.Now.*` all read one per-context value that advances — monotone, whole milliseconds — only when the runtime regains control at run entry, a bridge response, or a stream frame. Sandboxed code can no longer observe its own elapsed execution time, closing the timing side-channel between co-resident isolates. Explicit-argument `Date`/`Temporal`/`Intl` computation is untouched. Alongside it, `SharedArrayBuffer` is removed from the sandbox global (as in non-cross-origin-isolated browsers; `Atomics` on plain buffers keeps working) and `Atomics.wait` now throws, matching workerd. +- 139386b: feat: session demux and per-instance turn loop (#125) + + Runs no longer hold a thread while suspended on host calls, and a waiting + run's abort or timeout now fails that run alone instead of evicting its + warm instance. New error code + `ERR_INSTANCE_RESET` (with `resetCause` and `culpritRunId` on the error) + reports runs that were in flight on a shared instance when a co-resident run + had to be terminated mid-execution. + +- e1b10fc: feat: upgrade to V8 15.2 and span Node 22–27 with one binary (#80) + + The runtime picks up five V8 release lines of security fixes and performance + work. Serialized values keep the format every shipping Node reads, while the + handshake now also accepts hosts on newer Node lines that write V8's + next serialization format — so Node 22 through 27 pair with the same binary. + +### Patch Changes + +- fd462aa: perf: cheaper per-call attribution for bridge calls and console output (#127) + + Native callbacks resolve the owning run in one table lookup and take a + reference-counted handle to the stub binding instead of cloning it per + invocation. Attribution semantics are unchanged. + +- f6cddb7: fix: a host that stops draining a connection can no longer stall sandbox execution (#127) + + Outbound frames now go through a bounded per-connection queue with a + dedicated writer thread; a peer that stops reading fails that connection's + runs cleanly after a bounded wait instead of freezing every instance that + shares it. + +- 61e420c: Embed ICU data in the runtime binary. Locale-aware calls in sandboxed code (`toLocaleString`, `Intl.*`, `localeCompare`) previously aborted the whole V8 runtime process with "Fatal process out of memory: DateTimePatternGeneratorCache::CreateGenerator", leaving the sandbox unreachable for every subsequent run. They now return correctly localized output. +- 8871645: fix: inbound frames are read against the flat protocol ceiling (#127) + + Per-run frame allowances are still enforced per run, but the connection's + read ceiling is now a constant — it can no longer shrink under an in-flight + frame, so a large late frame for a just-completed run is discarded instead + of costing the connection. + +- f186aec: perf: the frozen-clock advance no longer allocates V8 state per turn (#127) + + Clock handles are cached per isolate at install time; a turn within the + same wall millisecond now skips V8 entirely. Clock semantics are unchanged. + +- 03b9e46: perf: one shared watchdog thread now enforces all CPU/wall budgets (#145) + + Warm instances hold one OS thread instead of two, so deployments with hard + per-container thread limits can keep roughly twice as many instances warm. + Budget and timeout semantics are unchanged. + +- dbd1caf: perf: instance turn loops route run events through one channel and a deadline heap (#127) + + Frame routing on a busy instance no longer scales with the number of + in-flight runs, and boundary deadlines fire in arrival order: co-resident + frame traffic can neither starve a run's wall timeout nor turn a run whose + answer arrived in time into one. + +- 7aec3d4: perf: outbound frames skip the writer thread when the socket is free (#127) + + Removes the flat per-call overhead the bounded outbound queue introduced + for short, frequent calls; the writer thread still takes over whenever the + socket backs up, so stall isolation is unchanged. + +- 2e6fb0f: fix: an abort that arrives before its run starts still lands gracefully (#127) + + A Terminate (or connection loss) racing ahead of the run's dispatch is now + remembered and answered when the run arrives, instead of falling back to + the host-side teardown timeout. + +- 3504569: fix: an instance thread that fails to spawn fails only its own run (#127) + + Under process resource exhaustion the affected run now reports + ERR_INTERNAL and the connection keeps serving, instead of the runtime + panicking the connection's demux. + ## 0.4.1 ## 0.4.0 diff --git a/packages/iso4-v8-linux-x64-gnu/package.json b/packages/iso4-v8-linux-x64-gnu/package.json index 6d631b6..cc38b97 100644 --- a/packages/iso4-v8-linux-x64-gnu/package.json +++ b/packages/iso4-v8-linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@iso4/v8-linux-x64-gnu", - "version": "0.4.1", + "version": "0.5.0", "type": "module", "description": "Native iso4 V8 runtime binary for linux-x64-gnu", "license": "MIT",