Changelog
Follow the changes included in each SER release.4.2.4
Reactive runs release their scoped children
Each top-level reactive SER execution now owns a child Effect scope. When
Svelte invalidates the statement, SER closes that run scope, interrupting work
started with Effect.forkScoped and running its finalizers before the next
execution takes over. Completed setup effects can still leave scoped work
running until invalidation, while typed setup failures and defects close their
run immediately. Component destruction remains the final backstop.
This prevents reactive subscriptions, fibers, latches, closures, and finalizers from accumulating in long-lived components as their inputs change.
4.2.3
Superseded value cells are released immediately
When a markup yield's dependencies change, its cache entry re-keys. The cell
stored under the superseded key was previously released only while still
pending, so a settled cell survived until the owning component unmounted. In
long-lived components whose yields re-key on rapidly changing state — a
streaming conversation view, for example — every change permanently retained
one settled cell along with its cached value, reactive source, and the fiber
records its production chain pinned, and invalidation of those orphaned cells
surfaced as Svelte derived_inert errors once their components were destroyed.
Superseded cells are now released as soon as the dependencies re-key, matching how promise caching already behaved. Dependencies that flip back to a prior value re-run the effect instead of resurfacing the stale cached result.
Scoped value reads publish their results
A value read started inside a component scope could fail to track its fiber, leaving the read stuck on its fallback. Scope-bound value work is now tracked and published correctly, and a value fiber whose launch is superseded before it starts is interrupted instead of running detached until the scope closes.
4.2.2
Compiler correctness fixes found by fuzzing
Top-level yield-star declarations now retain their export modifiers after lowering. Dependency collection now ignores declaration names, handles computed property names and parameter defaults, and respects block and loop scope, so reactive effects keep the dependencies they actually use without generating reads of undeclared names. Event callback extraction now parses the callback syntax instead of searching for the first arrow, so nested arrows no longer hide an invalid yield-star or truncate the generated handler.
The compiler and runtime now have property-based fuzz suites covering transform composition, dependency collection, source scanning, dispatcher lifecycles, yieldable boundaries, and remote failure transport. The fuzz workload runs from its own dispatch-only workflow.
Strict SER guidance
The SER skill has been rebuilt around strict Effect execution rules and focused references for component syntax, Effect discipline, remote functions, runtime and environment setup, tooling, and the error catalog.
4.2.1
Remote functions no longer read the request event
4.2.0 built a diagnostic context before running every remote handler, reading event.route and event.url to describe requests that might later fail. SvelteKit derives a restricted event for remote functions and, inside a query, defines url, params, and route as getters that throw, so a query's cache can only depend on its arguments. Every query therefore failed before its handler ran, answering with an internal error while the HTTP status stayed 200.
The context is now resolved only when a failure is actually reported, so a successful call never touches the request event, and each detail is read defensively because which properties a remote function may observe has changed across SvelteKit releases.
Bare yield* statements survive leading comments
A comment directly above a bare yield* statement was captured as part of the lowered expression, which defeated the anchored strip that removes the original yield* and left a second one nested inside the generated ToEffect argument.
4.2.0
Environment variables are declared with Effect Schema
DefineEnvVars describes SvelteKit's explicit environment variables with Effect Schema validators. Effect Schemas are converted to the Standard Schema interface SvelteKit validates at startup, so a declared variable reaches your application already decoded to its target type. Standard Schema validators and schema-less declarations pass through unchanged, and SvelteKit remains responsible for loading, visibility, and validation. Schemas must decode synchronously from the raw string value.
// src/env.ts
import { DefineEnvVars } from "svelte-effect-runtime/environment";
import { Schema } from "effect";
export const variables = DefineEnvVars({
PORT: { schema: Schema.NumberFromString, description: "Server port." },
PUBLIC_ORIGIN: { public: true, schema: Schema.URLFromString },
});Unencodable remote failures explain themselves
A remote handler whose failure SER cannot send to the client used to produce a bare 500 with nothing on the server to explain it. SER now reports why the failure was replaced, the request it happened in, the failure itself with its stack, and the full Effect cause, along with the change that would make it transportable.
This covers failures without a tagged error, failures that cannot be serialized, causes carrying only a defect, and handlers interrupted mid-request — the last of which commonly appears when a dev server restart disposes the runtime while a request is still in flight. What reaches the browser is unchanged.
Fixes
- Event handler work is bound to its component scope again, so destroying a component interrupts the effects its handlers started.
- A scoped promise failure no longer reaches callers twice, once as a rejection and once as an uncaught error.
- Disposing a component scope releases values cached under dependency keys that had since been superseded.
{@html}no longer renders a server fallback in place of its raw output.- Server transforms no longer import
onDestroy, which they never referenced.
Supported SvelteKit versions
SvelteKit 3 prereleases are supported through 3.0.0-next.8. Later prereleases change how an application is laid out rather than how SER integrates with it: 3.0.0-next.9 removed the $lib alias in favour of package subpath imports, and 3.0.0-next.12 moved SvelteKit's generated tsconfig and environment types. SER's own SvelteKit surface is unchanged across these releases and its peer range already admits them, but the conformance suite does not yet pass against them.
4.1.1
Editor scope diagnostics are fixed
Effect scripts that combine top-level work with effectful markup no longer report that SER's generated component scope is used before its declaration. Scope wiring is now inserted before the first transformed Effect statement, including when the language server has already added markup helpers.
Stale language-server installs are cleaned up
The VS Code extension now recognizes version-prefixed staging directories created by older SER releases. Abandoned language-server installs are removed instead of being retained with an invalid owner-metadata warning.
4.1.0
Effects now follow component lifetime
Effects started by SER syntax now run inside an Effect scope owned by their Svelte component. Destroying the component interrupts its in-flight work, runs registered finalizers, and clears component-local cached values instead of leaving that work attached to the application runtime.
This applies across script and markup effects, including event handlers and reactive reruns. Work owned by another live component remains isolated and continues normally.
Updated SvelteKit compatibility
The minimum supported SvelteKit 2 release is now 2.69.0. SvelteKit 3 prereleases remain supported.
4.0.1
Live queries preserve their first value
Live queries now retain an initial value supplied by SvelteKit while the remote Stream connects. Stream operators also preserve SER's transport controls, so Live.status(...) and Live.reconnect(...) continue to work after composing a live query.
Request cancellation reaches handlers
Effects run through Handler(...) are now interrupted when the request's abort signal fires. This lets scoped resources release promptly when a client disconnects or cancels a request.
Remote commands keep native updates
Command results now preserve SvelteKit's native update behavior instead of replacing it while SER decodes the Effect result.
Compiler and prerender fixes
- Compiler diagnostics are loaded only for source that may need them, keeping TypeScript and diagnostic machinery out of ordinary runtime chunks.
- Prerender bindings are retained and bridged correctly in generated remote modules.
- Diagnostics for tokenless
yieldexpressions now point at the correct source position.
Supported SvelteKit versions
The SvelteKit 2 peer dependency now starts at 2.61.0, the first compatible release for the remote-function integration used by SER. SvelteKit 3 prereleases remain supported.
4.0.0
Query.live is stream-native
Query.live now returns Effect's Stream data type directly. It no longer resolves to the old live-resource object with current, loading, ready, connected, and reconnect properties.
const clock = Clock();
yield * clock.pipe(Stream.runForEach((time) => Effect.sync(() => update_clock(time))));Live-query handlers must return a Stream as well. Native iterables and async generators remain usable, although they first need a Stream constructor such as Stream.fromIterable(...) or Stream.fromAsyncIterable(...). Returning an ordinary value, Promise, iterable, or an effect that later produces a Stream raises InvalidLiveQueryReturnError.
Transport controls have moved to the new Live helpers:
Live.status(stream)returns a Stream of connection states.Live.reconnect(stream)returns an effect that requests a reconnect.
Stream operators preserve SER's hidden transport metadata through pipe(...), so a derived remote Stream can still be passed to both helpers. A direct yield* stream reads its first element; if the Stream completes before emitting, it fails with EmptyStreamYieldError.
See Query.live for the complete API and migration table.
Native SvelteKit handlers can run effects
The new Handler(...) adapter runs native SvelteKit server callbacks through ServerRuntime. This covers route handlers such as GET and POST while leaving method selection, request arguments, and response validation with SvelteKit.
import type { RequestHandler } from "./$types";
import { Handler } from "svelte-effect-runtime";
export const GET = Handler<RequestHandler>(function* ({ params }) {
const post = yield* Posts.Get(params.slug);
return Response.json(post);
});The active RequestEvent is available as an effect service throughout the handler call. Native HTTP handlers do not expose a typed effect error channel, however, so domain failures must be recovered or translated into SvelteKit control flow before returning.
See Handler for request scope and error-boundary details.
Compiler entrypoint renamed
The Vite plugin entrypoint moved from svelte-effect-runtime/vite to svelte-effect-runtime/compiler.
import { effect } from "svelte-effect-runtime/vite";
import { effect } from "svelte-effect-runtime/compiler";The root svelte-effect-runtime export remains available. Projects that import the compiler subpath directly must update that import when moving to 4.0.0.
Compiler and markup changes
Script, markup, diagnostics, and language-server transforms now share one bounded Svelte source scanner. Apart from removing duplicated parsing logic, this changes a few observable edges:
- Event attributes follow Svelte's conventions instead of relying on a loose name check. Current
onclickattributes and legacyon:clickdirectives are both recognized at the AST boundary. - Script effects are split into independent runtime blocks, which keeps unrelated effect work from being coupled to one generated block.
- Server import rewriting parses imports structurally, including supported server and remote module forms, instead of depending on textual matches.
- Markup and editor diagnostics use the same source ranges as the compiler, reducing disagreements between the editor and the build.
Forms preserve array indices
Nested array values now use indexed FormData paths such as items[0] and items[1]. Previously, repeated items[] paths lost the original index, which made nested validation paths ambiguous once an array contained structured values.
Runtime and error behavior
ClientRuntime.make(...) and ServerRuntime.make(...) now reject a second initialization with RuntimeAlreadyInitializedError. Vite development SSR remains the exception: HMR disposes the previous server runtime before installing its replacement.
SER's public errors now use one documented hierarchy for compiler, runtime, remote-handler, factory, and transport failures. Dead exports that could no longer be reached, including UnknownRuntimeError and VitePreTransformPluginConflictError, have been removed. The old in-package documentation module has also been removed.
Documentation
SER 4.0.0 ships with documentation redesigned from scratch.