From cf35a22568be2e767c419a6b8ac36fe73c270eb3 Mon Sep 17 00:00:00 2001
From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com>
Date: Tue, 23 Sep 2025 03:04:45 -0700
Subject: [PATCH 01/80] fix: allow `{@html await ...}` and async snippets on
the server (#16817)
Fixes #16816
Fixes #16811
---------
Co-authored-by: Simon Holthausen
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
---
.changeset/long-spies-hope.md | 5 +++++
.../compiler/phases/3-transform/server/visitors/HtmlTag.js | 7 ++++++-
.../phases/3-transform/server/visitors/SnippetBlock.js | 5 +++++
.../samples/async-html-tag/_expected.html | 1 +
.../samples/async-html-tag/main.svelte | 1 +
.../samples/async-snippet/_expected.html | 1 +
.../samples/async-snippet/main.svelte | 6 ++++++
7 files changed, 25 insertions(+), 1 deletion(-)
create mode 100644 .changeset/long-spies-hope.md
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-html-tag/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-html-tag/main.svelte
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-snippet/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-snippet/main.svelte
diff --git a/.changeset/long-spies-hope.md b/.changeset/long-spies-hope.md
new file mode 100644
index 0000000000..6bb8184c64
--- /dev/null
+++ b/.changeset/long-spies-hope.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: allow `{@html await ...}` and snippets with async content on the server
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/HtmlTag.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/HtmlTag.js
index 9e857a9308..9a3d2830ac 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/HtmlTag.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/HtmlTag.js
@@ -9,5 +9,10 @@ import * as b from '#compiler/builders';
*/
export function HtmlTag(node, context) {
const expression = /** @type {Expression} */ (context.visit(node.expression));
- context.state.template.push(b.call('$.html', expression));
+ const call = b.call('$.html', expression);
+ context.state.template.push(
+ node.metadata.expression.has_await
+ ? b.stmt(b.call('$$renderer.push', b.thunk(call, true)))
+ : call
+ );
}
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js
index 7ae2a8e037..5fc865ec58 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js
@@ -3,6 +3,7 @@
/** @import { ComponentContext } from '../types.js' */
import { dev } from '../../../../state.js';
import * as b from '#compiler/builders';
+import { create_async_block } from './shared/utils.js';
/**
* @param {AST.SnippetBlock} node
@@ -15,6 +16,10 @@ export function SnippetBlock(node, context) {
/** @type {BlockStatement} */ (context.visit(node.body))
);
+ if (node.body.metadata.has_await) {
+ fn.body = b.block([create_async_block(fn.body)]);
+ }
+
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
fn.___snippet = true;
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-html-tag/_expected.html b/packages/svelte/tests/server-side-rendering/samples/async-html-tag/_expected.html
new file mode 100644
index 0000000000..5be0be37f2
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-html-tag/_expected.html
@@ -0,0 +1 @@
+this should work
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-html-tag/main.svelte b/packages/svelte/tests/server-side-rendering/samples/async-html-tag/main.svelte
new file mode 100644
index 0000000000..2d556e4d5b
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-html-tag/main.svelte
@@ -0,0 +1 @@
+{@html await 'this should work'}
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-snippet/_expected.html b/packages/svelte/tests/server-side-rendering/samples/async-snippet/_expected.html
new file mode 100644
index 0000000000..5be0be37f2
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-snippet/_expected.html
@@ -0,0 +1 @@
+this should work
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-snippet/main.svelte b/packages/svelte/tests/server-side-rendering/samples/async-snippet/main.svelte
new file mode 100644
index 0000000000..a6f2ac7b09
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-snippet/main.svelte
@@ -0,0 +1,6 @@
+{#snippet foo()}
+ {@const x = await 'this should work'}
+ {x}
+{/snippet}
+
+{@render foo()}
From 562623d536e9e2c3473d13a5cccce8d14ce98870 Mon Sep 17 00:00:00 2001
From: Brittany Harris <6003769+brittharr@users.noreply.github.com>
Date: Tue, 23 Sep 2025 13:55:46 +0100
Subject: [PATCH 02/80] fix: use SSR format compatible with nginx SSI for
props.id (#16820)
* fix: use SSR format compatible with nginx SSI for props.id
* changeset
---------
Co-authored-by: Rich Harris
---
.changeset/silly-schools-divide.md | 5 +++++
packages/svelte/src/internal/client/dom/template.js | 2 +-
packages/svelte/src/internal/server/index.js | 2 +-
3 files changed, 7 insertions(+), 2 deletions(-)
create mode 100644 .changeset/silly-schools-divide.md
diff --git a/.changeset/silly-schools-divide.md b/.changeset/silly-schools-divide.md
new file mode 100644
index 0000000000..ff36717063
--- /dev/null
+++ b/.changeset/silly-schools-divide.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: use nginx SSI-compatible comments for `$props.id()`
diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js
index 135ca86610..c2443fda7a 100644
--- a/packages/svelte/src/internal/client/dom/template.js
+++ b/packages/svelte/src/internal/client/dom/template.js
@@ -365,7 +365,7 @@ export function props_id() {
hydrating &&
hydrate_node &&
hydrate_node.nodeType === COMMENT_NODE &&
- hydrate_node.textContent?.startsWith(`#`)
+ hydrate_node.textContent?.startsWith(`$`)
) {
const id = hydrate_node.textContent.substring(1);
hydrate_next();
diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js
index 3ff44f8030..50bb629c4d 100644
--- a/packages/svelte/src/internal/server/index.js
+++ b/packages/svelte/src/internal/server/index.js
@@ -448,7 +448,7 @@ export function once(get_value) {
*/
export function props_id(renderer) {
const uid = renderer.global.uid();
- renderer.push('');
+ renderer.push('');
return uid;
}
From 8680c29a0a7bdb7993c40e8a34394d95c23d19c8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 23 Sep 2025 08:57:46 -0400
Subject: [PATCH 03/80] Version Packages (#16818)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.changeset/long-spies-hope.md | 5 -----
.changeset/silly-schools-divide.md | 5 -----
packages/svelte/CHANGELOG.md | 8 ++++++++
packages/svelte/package.json | 2 +-
packages/svelte/src/version.js | 2 +-
5 files changed, 10 insertions(+), 12 deletions(-)
delete mode 100644 .changeset/long-spies-hope.md
delete mode 100644 .changeset/silly-schools-divide.md
diff --git a/.changeset/long-spies-hope.md b/.changeset/long-spies-hope.md
deleted file mode 100644
index 6bb8184c64..0000000000
--- a/.changeset/long-spies-hope.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: allow `{@html await ...}` and snippets with async content on the server
diff --git a/.changeset/silly-schools-divide.md b/.changeset/silly-schools-divide.md
deleted file mode 100644
index ff36717063..0000000000
--- a/.changeset/silly-schools-divide.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"svelte": patch
----
-
-fix: use nginx SSI-compatible comments for `$props.id()`
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index fe6e44ffbe..2cf08ae409 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,13 @@
# svelte
+## 5.39.5
+
+### Patch Changes
+
+- fix: allow `{@html await ...}` and snippets with async content on the server ([#16817](https://github.com/sveltejs/svelte/pull/16817))
+
+- fix: use nginx SSI-compatible comments for `$props.id()` ([#16820](https://github.com/sveltejs/svelte/pull/16820))
+
## 5.39.4
### Patch Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 0be1242ffe..a4865da75f 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.39.4",
+ "version": "5.39.5",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index 1ebbbb95dd..55796a2083 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.39.4';
+export const VERSION = '5.39.5';
export const PUBLIC_VERSION = '5';
From 7d9962a57268fbe02b6f5a6327e488e2b189f8ca Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Tue, 23 Sep 2025 14:56:08 -0400
Subject: [PATCH 04/80] docs: update await expressions documentation (#16822)
* docs: update await expressions documentation
* Update documentation/docs/03-template-syntax/19-await-expressions.md
Co-authored-by: Tee Ming
* Update documentation/docs/03-template-syntax/19-await-expressions.md
Co-authored-by: Elliott Johnson
* Update documentation/docs/03-template-syntax/19-await-expressions.md
Co-authored-by: Tee Ming
* Update documentation/docs/03-template-syntax/19-await-expressions.md
---------
Co-authored-by: Elliott Johnson
Co-authored-by: Tee Ming
---
.../19-await-expressions.md | 40 ++++++++++---------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/documentation/docs/03-template-syntax/19-await-expressions.md b/documentation/docs/03-template-syntax/19-await-expressions.md
index 4e5ec28b26..e43d6c81d1 100644
--- a/documentation/docs/03-template-syntax/19-await-expressions.md
+++ b/documentation/docs/03-template-syntax/19-await-expressions.md
@@ -23,24 +23,6 @@ export default {
The experimental flag will be removed in Svelte 6.
-## Boundaries
-
-Currently, you can only use `await` inside a [``](svelte-boundary) with a `pending` snippet:
-
-```svelte
-
-
-
- {#snippet pending()}
- loading...
- {/snippet}
-
-```
-
-This restriction will be lifted once Svelte supports asynchronous server-side rendering (see [caveats](#Caveats)).
-
-> [!NOTE] In the [playground](/playground), your app is rendered inside a boundary with an empty pending snippet, so that you can use `await` without having to create one.
-
## Synchronized updates
When an `await` expression depends on a particular piece of state, changes to that state will not be reflected in the UI until the asynchronous work has completed, so that the UI is not left in an inconsistent state. In other words, in an example like [this](/playground/untitled#H4sIAAAAAAAAE42QsWrDQBBEf2VZUkhYRE4gjSwJ0qVMkS6XYk9awcFpJe5Wdoy4fw-ycdykSPt2dpiZFYVGxgrf2PsJTlPwPWTcO-U-xwIH5zli9bminudNtwEsbl-v8_wYj-x1Y5Yi_8W7SZRFI1ZYxy64WVsjRj0rEDTwEJWUs6f8cKP2Tp8vVIxSPEsHwyKdukmA-j6jAmwO63Y1SidyCsIneA_T6CJn2ZBD00Jk_XAjT4tmQwEv-32eH6AsgYK6wXWOPPTs6Xy1CaxLECDYgb3kSUbq8p5aaifzorCt0RiUZbQcDIJ10ldH8gs3K6X2Xzqbro5zu1KCHaw2QQPrtclvwVSXc2sEC1T-Vqw0LJy-ClRy_uSkx2ogHzn9ADZ1CubKAQAA)...
@@ -99,7 +81,9 @@ let b = $derived(await two());
## Indicating loading states
-In addition to the nearest boundary's [`pending`](svelte-boundary#Properties-pending) snippet, you can indicate that asynchronous work is ongoing with [`$effect.pending()`]($effect#$effect.pending).
+To render placeholder UI, you can wrap content in a `` with a [`pending`](svelte-boundary#Properties-pending) snippet. This will be shown when the boundary is first created, but not for subsequent updates, which are globally coordinated.
+
+After the contents of a boundary have resolved for the first time and replaced the `pending` snippet, you can detect subsequent async work with [`$effect.pending()`]($effect#$effect.pending). This is what you would use display a "we're asynchronously validating your input" spinner next to a form field, for example.
You can also use [`settled()`](svelte#settled) to get a promise that resolves when the current update is complete:
@@ -133,6 +117,24 @@ async function onclick() {
Errors in `await` expressions will bubble to the nearest [error boundary](svelte-boundary).
+## Server-side rendering
+
+Svelte supports asynchronous server-side rendering (SSR) with the `render(...)` API. To use it, simply await the return value:
+
+```js
+/// file: server.js
+import { render } from 'svelte/server';
+import App from './App.svelte';
+
+const { head, body } = +++await+++ render(App);
+```
+
+> [!NOTE] If you're using a framework like SvelteKit, this is done on your behalf.
+
+If a `` with a `pending` snippet is encountered during SSR, that snippet will be rendered while the rest of the content is ignored. All `await` expressions encountered outside boundaries with `pending` snippets will resolve and render their contents prior to `await render(...)` returning.
+
+> [!NOTE] In the future, we plan to add a streaming implementation that renders the content in the background.
+
## Caveats
As an experimental feature, the details of how `await` is handled (and related APIs like `$effect.pending()`) are subject to breaking changes outside of a semver major release, though we intend to keep such changes to a bare minimum.
From 5e6fed6bab2423f7469f29ee9cd002dd698b91a2 Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Tue, 23 Sep 2025 23:13:16 +0200
Subject: [PATCH 05/80] fix: depend on reads of deriveds created within
reaction (async mode) (#16823)
* fix: depend on reads of deriveds created within reaction (async mode)
As part of https://github.com/sveltejs/kit/pull/14481 we discovered that deriveds created within reactions and reading from them in that same reaction is actually useful in some cases, as such a use case we couldn't imagine yet in #15564 has appeared.
We think it's ultimately better to rerun on those cases, so we're going to make this change in async mode (that way the behavior doesn't change unless you have enabled the experimental flag)
* fix tests
---
.changeset/gold-eels-lay.md | 5 ++
.../internal/client/reactivity/deriveds.js | 4 +-
.../samples/derived-in-expression/_config.js | 74 +++++++++++++++++++
.../samples/derived-in-expression/main.svelte | 30 ++++++++
.../samples/untrack-own-deriveds/_config.js | 5 +-
.../samples/untrack-own-deriveds/main.svelte | 6 +-
6 files changed, 119 insertions(+), 5 deletions(-)
create mode 100644 .changeset/gold-eels-lay.md
create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-in-expression/_config.js
create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-in-expression/main.svelte
diff --git a/.changeset/gold-eels-lay.md b/.changeset/gold-eels-lay.md
new file mode 100644
index 0000000000..ef6ceb4dab
--- /dev/null
+++ b/.changeset/gold-eels-lay.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: depend on reads of deriveds created within reaction (async mode)
diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js
index 299251a2dc..11405a8e66 100644
--- a/packages/svelte/src/internal/client/reactivity/deriveds.js
+++ b/packages/svelte/src/internal/client/reactivity/deriveds.js
@@ -29,7 +29,7 @@ import * as w from '../warnings.js';
import { async_effect, destroy_effect } from './effects.js';
import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js';
import { get_stack } from '../dev/tracing.js';
-import { tracing_mode_flag } from '../../flags/index.js';
+import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { Boundary } from '../dom/blocks/boundary.js';
import { component_context } from '../context.js';
import { UNINITIALIZED } from '../../../constants.js';
@@ -231,7 +231,7 @@ export function async_derived(fn, location) {
export function user_derived(fn) {
const d = derived(fn);
- push_reaction_value(d);
+ if (!async_mode_flag) push_reaction_value(d);
return d;
}
diff --git a/packages/svelte/tests/runtime-runes/samples/derived-in-expression/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-in-expression/_config.js
new file mode 100644
index 0000000000..73428e0ff2
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/derived-in-expression/_config.js
@@ -0,0 +1,74 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ // In non-async mode we're not reacting to deriveds read in the same context they're defined in
+ skip_no_async: true,
+ test({ assert, target, logs }) {
+ const [a, b] = target.querySelectorAll('button');
+
+ flushSync(() => a?.click());
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+ a
+ b
+ 1/0
a?.click());
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+ a
+ b
+ 2/0
b?.click());
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+ a
+ b
+ 2/1
b?.click());
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+ a
+ b
+ 2/2
+ let object = $state.raw({ a: 0, b: 0 });
+
+ function a() {
+ console.log('a');
+ return object.a;
+ }
+
+ function b() {
+ console.log('b');
+ let double = $derived(object.b)
+ return double;
+ }
+
+ $effect(() => {
+ object.a;
+ console.log('effect a');
+ })
+
+ $effect(() => {
+ const b = $derived(object.b);
+ b;
+ console.log('effect b');
+ })
+
+
+ object = { ...object, a: object.a + 1 }}>a
+ object = { ...object, b: object.b + 1 }}>b
+
+{a()}/{b()}
diff --git a/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/_config.js b/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/_config.js
index b728c3c0be..b5233b01e8 100644
--- a/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/_config.js
@@ -13,10 +13,11 @@ export default test({
target.innerHTML,
`
increment
- 1/2
1/2
+ 1/2
`
);
- assert.deepEqual(logs, [0, 0]);
+ assert.deepEqual(logs, [0, 0, 0, 0]);
}
});
diff --git a/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/main.svelte b/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/main.svelte
index bbad2cdf4a..c0dd86993a 100644
--- a/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/main.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/main.svelte
@@ -17,10 +17,14 @@
$effect(() => {
foo = new Foo();
});
+
+ let bar = $derived(new Foo());
- foo.increment()}>increment
+ {foo.increment(); bar.increment()}}>increment
{#if foo}
{foo.value}/{foo.double}
{/if}
+
+{bar.value}/{bar.double}
From 1ef297f25de64f220bce8ff020f38d399b69a647 Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Tue, 23 Sep 2025 23:47:50 +0200
Subject: [PATCH 06/80] fix: ensure tick resolves within a macrotask (#16825)
Race them against each other - in almost all cases requestAnimationFrame will fire first, but e.g. in case the window is not focused or a view transition happens, requestAnimationFrame will be delayed and setTimeout helps us resolve fast enough in that case
Fixes #16429
Fixes https://github.com/sveltejs/kit/issues/14220
---
.changeset/wise-bottles-explode.md | 5 +++++
packages/svelte/src/internal/client/runtime.js | 8 +++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 .changeset/wise-bottles-explode.md
diff --git a/.changeset/wise-bottles-explode.md b/.changeset/wise-bottles-explode.md
new file mode 100644
index 0000000000..d3b2931272
--- /dev/null
+++ b/.changeset/wise-bottles-explode.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure tick resolves within a macrotask
diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js
index 22a1890e0f..b8f5f5ffc9 100644
--- a/packages/svelte/src/internal/client/runtime.js
+++ b/packages/svelte/src/internal/client/runtime.js
@@ -500,7 +500,13 @@ export function update_effect(effect) {
*/
export async function tick() {
if (async_mode_flag) {
- return new Promise((f) => requestAnimationFrame(() => f()));
+ return new Promise((f) => {
+ // Race them against each other - in almost all cases requestAnimationFrame will fire first,
+ // but e.g. in case the window is not focused or a view transition happens, requestAnimationFrame
+ // will be delayed and setTimeout helps us resolve fast enough in that case
+ requestAnimationFrame(() => f());
+ setTimeout(() => f());
+ });
}
await Promise.resolve();
From 0ed0f1ef69a67324ef411b61c6cf088e4abcd57b Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Wed, 24 Sep 2025 11:08:06 -0400
Subject: [PATCH 07/80] chore: disable inspector in playground (#16836)
---
playgrounds/sandbox/package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/playgrounds/sandbox/package.json b/playgrounds/sandbox/package.json
index 641f91ddfe..84aeab586b 100644
--- a/playgrounds/sandbox/package.json
+++ b/playgrounds/sandbox/package.json
@@ -5,8 +5,8 @@
"type": "module",
"scripts": {
"prepare": "node scripts/create-app-svelte.js",
- "dev": "vite --host",
- "ssr": "node --conditions=development ./ssr-dev.js",
+ "dev": "SVELTE_INSPECTOR_OPTIONS=false vite --host",
+ "ssr": "SVELTE_INSPECTOR_OPTIONS=false node --conditions=development ./ssr-dev.js",
"build": "vite build --outDir dist/client && vite build --outDir dist/server --ssr ssr-prod.js",
"prod": "npm run build && node dist/server/ssr-prod",
"preview": "vite preview",
From 7b2113e1bfb6da2078abe532b0530e25f8f85285 Mon Sep 17 00:00:00 2001
From: Aaron Ajose
Date: Wed, 24 Sep 2025 18:32:59 +0300
Subject: [PATCH 08/80] chore: fix typos (#16830)
* chore: fix typos
* revert bad change
---------
Co-authored-by: Rich Harris
---
packages/svelte/src/internal/client/render.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js
index f5e32a2196..b1165a6e7a 100644
--- a/packages/svelte/src/internal/client/render.js
+++ b/packages/svelte/src/internal/client/render.js
@@ -143,7 +143,7 @@ export function hydrate(component, options) {
e.hydration_failed();
}
- // If an error occured above, the operations might not yet have been initialised.
+ // If an error occurred above, the operations might not yet have been initialised.
init_operations();
clear_text_content(target);
From c75e86267758a534c76c3d02eae6026171792704 Mon Sep 17 00:00:00 2001
From: Tee Ming
Date: Wed, 24 Sep 2025 23:34:05 +0800
Subject: [PATCH 09/80] Update 19-await-expressions.md (#16827)
---
documentation/docs/03-template-syntax/19-await-expressions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/documentation/docs/03-template-syntax/19-await-expressions.md b/documentation/docs/03-template-syntax/19-await-expressions.md
index e43d6c81d1..d3896a5c4e 100644
--- a/documentation/docs/03-template-syntax/19-await-expressions.md
+++ b/documentation/docs/03-template-syntax/19-await-expressions.md
@@ -83,7 +83,7 @@ let b = $derived(await two());
To render placeholder UI, you can wrap content in a `` with a [`pending`](svelte-boundary#Properties-pending) snippet. This will be shown when the boundary is first created, but not for subsequent updates, which are globally coordinated.
-After the contents of a boundary have resolved for the first time and replaced the `pending` snippet, you can detect subsequent async work with [`$effect.pending()`]($effect#$effect.pending). This is what you would use display a "we're asynchronously validating your input" spinner next to a form field, for example.
+After the contents of a boundary have resolved for the first time and have replaced the `pending` snippet, you can detect subsequent async work with [`$effect.pending()`]($effect#$effect.pending). This is what you would use to display a "we're asynchronously validating your input" spinner next to a form field, for example.
You can also use [`settled()`](svelte#settled) to get a promise that resolves when the current update is complete:
From 24944e61f5ef5aebf00aa6f86f86edaf3ad70986 Mon Sep 17 00:00:00 2001
From: 7nik
Date: Wed, 24 Sep 2025 18:35:24 +0300
Subject: [PATCH 10/80] fix: async `class:` + spread attributes were compiled
into sync server-side code (#16834)
---
.changeset/tasty-snails-dress.md | 5 +++++
.../phases/3-transform/server/visitors/shared/element.js | 5 ++++-
.../samples/async-directive-with-spreading/_expected.html | 1 +
.../samples/async-directive-with-spreading/main.svelte | 2 ++
4 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 .changeset/tasty-snails-dress.md
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/main.svelte
diff --git a/.changeset/tasty-snails-dress.md b/.changeset/tasty-snails-dress.md
new file mode 100644
index 0000000000..0fb847c1ff
--- /dev/null
+++ b/.changeset/tasty-snails-dress.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: async `class:` + spread attributes were compiled into sync server-side code
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
index da90011259..3b5f2423a3 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
@@ -372,7 +372,10 @@ function build_element_spread_attributes(
directive.name,
directive.expression.type === 'Identifier' && directive.expression.name === directive.name
? b.id(directive.name)
- : /** @type {Expression} */ (context.visit(directive.expression))
+ : transform(
+ /** @type {Expression} */ (context.visit(directive.expression)),
+ directive.metadata.expression
+ )
);
});
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/_expected.html b/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/_expected.html
new file mode 100644
index 0000000000..d46a957bdf
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/_expected.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/main.svelte b/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/main.svelte
new file mode 100644
index 0000000000..ed4270b754
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-directive-with-spreading/main.svelte
@@ -0,0 +1,2 @@
+
+
From ac7e16002939f627bd961a9194e497f53ff466f9 Mon Sep 17 00:00:00 2001
From: LeeWxx <99359120+LeeWxx@users.noreply.github.com>
Date: Thu, 25 Sep 2025 01:35:51 +0900
Subject: [PATCH 11/80] fix: SSR scoped classes for elements
(#16821)
* fix: preserve scoped classes on select during ssr
* test: cover select scoped class regression
* chore: changeset
* chore: format files after lint
* fix: unify attribute handling and prevent double-await
* test: update renderer.select call order
* fix: restore scoped classes on
* test: cover scoped class for
* dry
* de-diff
* tweak changeset
---------
Co-authored-by: 7nik
Co-authored-by: Rich Harris
---
.changeset/nasty-comics-play.md | 5 +
.../server/visitors/RegularElement.js | 71 +++++-------
.../server/visitors/shared/element.js | 103 ++++++++++++++----
.../svelte/src/internal/server/renderer.js | 19 +++-
.../src/internal/server/renderer.test.ts | 18 +++
.../option-scoped-class/_expected.html | 2 +
.../samples/option-scoped-class/main.svelte | 10 ++
.../select-value-scoped-class/_expected.html | 1 +
.../select-value-scoped-class/main.svelte | 9 ++
9 files changed, 172 insertions(+), 66 deletions(-)
create mode 100644 .changeset/nasty-comics-play.md
create mode 100644 packages/svelte/tests/server-side-rendering/samples/option-scoped-class/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/option-scoped-class/main.svelte
create mode 100644 packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/main.svelte
diff --git a/.changeset/nasty-comics-play.md b/.changeset/nasty-comics-play.md
new file mode 100644
index 0000000000..b75c82c493
--- /dev/null
+++ b/.changeset/nasty-comics-play.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: SSR regression of processing attributes of `` and ``
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
index 14f48d1ce7..df3e2fc37f 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js
@@ -7,11 +7,10 @@ import { is_void } from '../../../../../utils.js';
import { dev, locator } from '../../../../state.js';
import * as b from '#compiler/builders';
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
-import { build_element_attributes, build_spread_object } from './shared/element.js';
+import { build_element_attributes, prepare_element_spread_object } from './shared/element.js';
import {
process_children,
build_template,
- build_attribute_value,
create_child_block,
PromiseOptimiser
} from './shared/utils.js';
@@ -37,9 +36,27 @@ export function RegularElement(node, context) {
const optimiser = new PromiseOptimiser();
- state.template.push(b.literal(`<${node.name}`));
- const body = build_element_attributes(node, { ...context, state }, optimiser.transform);
- state.template.push(b.literal(node_is_void ? '/>' : '>')); // add `/>` for XHTML compliance
+ // If this element needs special handling (like / ),
+ // avoid calling build_element_attributes here to prevent evaluating/awaiting
+ // attribute expressions twice. We'll handle attributes in the special branch.
+ const is_select_special =
+ node.name === 'select' &&
+ node.attributes.some(
+ (attribute) =>
+ ((attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
+ attribute.name === 'value') ||
+ attribute.type === 'SpreadAttribute'
+ );
+ const is_option_special = node.name === 'option';
+ const is_special = is_select_special || is_option_special;
+
+ let body = /** @type {Expression | null} */ (null);
+ if (!is_special) {
+ // only open the tag in the non-special path
+ state.template.push(b.literal(`<${node.name}`));
+ body = build_element_attributes(node, { ...context, state }, optimiser.transform);
+ state.template.push(b.literal(node_is_void ? '/>' : '>')); // add `/>` for XHTML compliance
+ }
if ((node.name === 'script' || node.name === 'style') && node.fragment.nodes.length === 1) {
state.template.push(
@@ -95,27 +112,7 @@ export function RegularElement(node, context) {
);
}
- if (
- node.name === 'select' &&
- node.attributes.some(
- (attribute) =>
- ((attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
- attribute.name === 'value') ||
- attribute.type === 'SpreadAttribute'
- )
- ) {
- const attributes = build_spread_object(
- node,
- node.attributes.filter(
- (attribute) =>
- attribute.type === 'Attribute' ||
- attribute.type === 'BindDirective' ||
- attribute.type === 'SpreadAttribute'
- ),
- context,
- optimiser.transform
- );
-
+ if (is_select_special) {
const inner_state = { ...state, template: [], init: [] };
process_children(trimmed, { ...context, state: inner_state });
@@ -124,7 +121,9 @@ export function RegularElement(node, context) {
b.block([...state.init, ...build_template(inner_state.template)])
);
- const statement = b.stmt(b.call('$$renderer.select', attributes, fn));
+ const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
+
+ const statement = b.stmt(b.call('$$renderer.select', attributes, fn, ...rest));
if (optimiser.expressions.length > 0) {
context.state.template.push(
@@ -137,19 +136,7 @@ export function RegularElement(node, context) {
return;
}
- if (node.name === 'option') {
- const attributes = build_spread_object(
- node,
- node.attributes.filter(
- (attribute) =>
- attribute.type === 'Attribute' ||
- attribute.type === 'BindDirective' ||
- attribute.type === 'SpreadAttribute'
- ),
- context,
- optimiser.transform
- );
-
+ if (is_option_special) {
let body;
if (node.metadata.synthetic_value_node) {
@@ -167,7 +154,9 @@ export function RegularElement(node, context) {
);
}
- const statement = b.stmt(b.call('$$renderer.option', attributes, body));
+ const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
+
+ const statement = b.stmt(b.call('$$renderer.option', attributes, body, ...rest));
if (optimiser.expressions.length > 0) {
context.state.template.push(
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
index 3b5f2423a3..cfb87b0ce7 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js
@@ -358,17 +358,86 @@ function build_element_spread_attributes(
context,
transform
) {
+ const args = prepare_element_spread(
+ element,
+ /** @type {Array} */ (attributes),
+ style_directives,
+ class_directives,
+ context,
+ transform
+ );
+
+ let call = b.call('$.attributes', ...args);
+
+ context.state.template.push(call);
+}
+
+/**
+ * Prepare args for $.attributes(...): compute object, css_hash, classes, styles and flags.
+ * @param {AST.RegularElement | AST.SvelteElement} element
+ * @param {ComponentContext} context
+ * @param {(expression: Expression, metadata: ExpressionMetadata) => Expression} transform
+ * @returns {[ObjectExpression,Literal | undefined, ObjectExpression | undefined, ObjectExpression | undefined, Literal | undefined]}
+ */
+export function prepare_element_spread_object(element, context, transform) {
+ /** @type {Array} */
+ const select_attributes = [];
+ /** @type {AST.ClassDirective[]} */
+ const class_directives = [];
+ /** @type {AST.StyleDirective[]} */
+ const style_directives = [];
+
+ for (const attribute of element.attributes) {
+ if (
+ attribute.type === 'Attribute' ||
+ attribute.type === 'BindDirective' ||
+ attribute.type === 'SpreadAttribute'
+ ) {
+ select_attributes.push(attribute);
+ } else if (attribute.type === 'ClassDirective') {
+ class_directives.push(attribute);
+ } else if (attribute.type === 'StyleDirective') {
+ style_directives.push(attribute);
+ }
+ }
+
+ return prepare_element_spread(
+ element,
+ select_attributes,
+ style_directives,
+ class_directives,
+ context,
+ transform
+ );
+}
+
+/**
+ * Prepare args for $.attributes(...): compute object, css_hash, classes, styles and flags.
+ * @param {AST.RegularElement | AST.SvelteElement} element
+ * @param {Array} attributes
+ * @param {AST.StyleDirective[]} style_directives
+ * @param {AST.ClassDirective[]} class_directives
+ * @param {ComponentContext} context
+ * @param {(expression: Expression, metadata: ExpressionMetadata) => Expression} transform
+ * @returns {[ObjectExpression,Literal | undefined, ObjectExpression | undefined, ObjectExpression | undefined, Literal | undefined]}
+ */
+export function prepare_element_spread(
+ element,
+ attributes,
+ style_directives,
+ class_directives,
+ context,
+ transform
+) {
+ /** @type {ObjectExpression | undefined} */
let classes;
+ /** @type {ObjectExpression | undefined} */
let styles;
let flags = 0;
- let has_await = false;
-
if (class_directives.length) {
- const properties = class_directives.map((directive) => {
- has_await ||= directive.metadata.expression.has_await;
-
- return b.init(
+ const properties = class_directives.map((directive) =>
+ b.init(
directive.name,
directive.expression.type === 'Identifier' && directive.expression.name === directive.name
? b.id(directive.name)
@@ -376,24 +445,21 @@ function build_element_spread_attributes(
/** @type {Expression} */ (context.visit(directive.expression)),
directive.metadata.expression
)
- );
- });
+ )
+ );
classes = b.object(properties);
}
if (style_directives.length > 0) {
- const properties = style_directives.map((directive) => {
- has_await ||= directive.metadata.expression.has_await;
-
- return b.init(
+ const properties = style_directives.map((directive) =>
+ b.init(
directive.name,
directive.value === true
? b.id(directive.name)
: build_attribute_value(directive.value, context, transform, true)
- );
- });
-
+ )
+ );
styles = b.object(properties);
}
@@ -406,17 +472,12 @@ function build_element_spread_attributes(
}
const object = build_spread_object(element, attributes, context, transform);
-
const css_hash =
element.metadata.scoped && context.state.analysis.css.hash
? b.literal(context.state.analysis.css.hash)
: undefined;
- const args = [object, css_hash, classes, styles, flags ? b.literal(flags) : undefined];
-
- let call = b.call('$.attributes', ...args);
-
- context.state.template.push(call);
+ return [object, css_hash, classes, styles, flags ? b.literal(flags) : undefined];
}
/**
diff --git a/packages/svelte/src/internal/server/renderer.js b/packages/svelte/src/internal/server/renderer.js
index 6971f200a0..bbb43a6f3b 100644
--- a/packages/svelte/src/internal/server/renderer.js
+++ b/packages/svelte/src/internal/server/renderer.js
@@ -160,9 +160,16 @@ export class Renderer {
/**
* @param {Record} attrs
* @param {(renderer: Renderer) => void} fn
+ * @param {string | undefined} [css_hash]
+ * @param {Record | undefined} [classes]
+ * @param {Record | undefined} [styles]
+ * @param {number | undefined} [flags]
+ * @returns {void}
*/
- select({ value, ...attrs }, fn) {
- this.push(``);
+ select(attrs, fn, css_hash, classes, styles, flags) {
+ const { value, ...select_attrs } = attrs;
+
+ this.push(``);
this.child((renderer) => {
renderer.local.select_value = value;
fn(renderer);
@@ -173,9 +180,13 @@ export class Renderer {
/**
* @param {Record} attrs
* @param {string | number | boolean | ((renderer: Renderer) => void)} body
+ * @param {string | undefined} [css_hash]
+ * @param {Record | undefined} [classes]
+ * @param {Record | undefined} [styles]
+ * @param {number | undefined} [flags]
*/
- option(attrs, body) {
- this.#out.push(` {
);
});
+test('select merges scoped css hash with static class', () => {
+ const component = (renderer: Renderer) => {
+ renderer.select(
+ { class: 'foo', value: 'foo' },
+ (renderer) => {
+ renderer.option({ value: 'foo' }, (renderer) => renderer.push('foo'));
+ },
+ 'svelte-hash'
+ );
+ };
+
+ const { head, body } = Renderer.render(component as unknown as Component);
+ expect(head).toBe('');
+ expect(body).toBe(
+ 'foo '
+ );
+});
+
describe('async', () => {
beforeAll(() => {
enable_async_mode_flag();
diff --git a/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/_expected.html b/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/_expected.html
new file mode 100644
index 0000000000..b30e5ff4a1
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/_expected.html
@@ -0,0 +1,2 @@
+foo
+
diff --git a/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/main.svelte b/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/main.svelte
new file mode 100644
index 0000000000..657f1e949d
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/option-scoped-class/main.svelte
@@ -0,0 +1,10 @@
+
+ foo
+
+
+
+
diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/_expected.html b/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/_expected.html
new file mode 100644
index 0000000000..d74fc96d9c
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/_expected.html
@@ -0,0 +1 @@
+foo
diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/main.svelte b/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/main.svelte
new file mode 100644
index 0000000000..9ad3a6b4d2
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/select-value-scoped-class/main.svelte
@@ -0,0 +1,9 @@
+
+ foo
+
+
+
From b92a55994b7349e5c681df97a571481488020bc4 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 24 Sep 2025 13:00:20 -0400
Subject: [PATCH 12/80] Version Packages (#16824)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.changeset/gold-eels-lay.md | 5 -----
.changeset/nasty-comics-play.md | 5 -----
.changeset/tasty-snails-dress.md | 5 -----
.changeset/wise-bottles-explode.md | 5 -----
packages/svelte/CHANGELOG.md | 12 ++++++++++++
packages/svelte/package.json | 2 +-
packages/svelte/src/version.js | 2 +-
7 files changed, 14 insertions(+), 22 deletions(-)
delete mode 100644 .changeset/gold-eels-lay.md
delete mode 100644 .changeset/nasty-comics-play.md
delete mode 100644 .changeset/tasty-snails-dress.md
delete mode 100644 .changeset/wise-bottles-explode.md
diff --git a/.changeset/gold-eels-lay.md b/.changeset/gold-eels-lay.md
deleted file mode 100644
index ef6ceb4dab..0000000000
--- a/.changeset/gold-eels-lay.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: depend on reads of deriveds created within reaction (async mode)
diff --git a/.changeset/nasty-comics-play.md b/.changeset/nasty-comics-play.md
deleted file mode 100644
index b75c82c493..0000000000
--- a/.changeset/nasty-comics-play.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: SSR regression of processing attributes of `` and ``
diff --git a/.changeset/tasty-snails-dress.md b/.changeset/tasty-snails-dress.md
deleted file mode 100644
index 0fb847c1ff..0000000000
--- a/.changeset/tasty-snails-dress.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: async `class:` + spread attributes were compiled into sync server-side code
diff --git a/.changeset/wise-bottles-explode.md b/.changeset/wise-bottles-explode.md
deleted file mode 100644
index d3b2931272..0000000000
--- a/.changeset/wise-bottles-explode.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: ensure tick resolves within a macrotask
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 2cf08ae409..83bd1d043f 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,17 @@
# svelte
+## 5.39.6
+
+### Patch Changes
+
+- fix: depend on reads of deriveds created within reaction (async mode) ([#16823](https://github.com/sveltejs/svelte/pull/16823))
+
+- fix: SSR regression of processing attributes of `` and `` ([#16821](https://github.com/sveltejs/svelte/pull/16821))
+
+- fix: async `class:` + spread attributes were compiled into sync server-side code ([#16834](https://github.com/sveltejs/svelte/pull/16834))
+
+- fix: ensure tick resolves within a macrotask ([#16825](https://github.com/sveltejs/svelte/pull/16825))
+
## 5.39.5
### Patch Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index a4865da75f..51c6a4f12e 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.39.5",
+ "version": "5.39.6",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index 55796a2083..a0271de08b 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.39.5';
+export const VERSION = '5.39.6';
export const PUBLIC_VERSION = '5';
From f0cede678200a3da2fbed6e84245dbef9ec0ecec Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Thu, 25 Sep 2025 13:45:31 -0400
Subject: [PATCH 13/80] chore: replace queue_idle_task with queue_micro_task
(#16844)
---
.../client/dom/elements/attributes.js | 4 +--
.../svelte/src/internal/client/dom/task.js | 32 +------------------
2 files changed, 3 insertions(+), 33 deletions(-)
diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js
index fb6a92cc82..a5f63359c9 100644
--- a/packages/svelte/src/internal/client/dom/elements/attributes.js
+++ b/packages/svelte/src/internal/client/dom/elements/attributes.js
@@ -6,7 +6,7 @@ import { create_event, delegate } from './events.js';
import { add_form_reset_listener, autofocus } from './misc.js';
import * as w from '../../warnings.js';
import { LOADING_ATTR_SYMBOL } from '#client/constants';
-import { queue_idle_task } from '../task.js';
+import { queue_micro_task } from '../task.js';
import { is_capture_event, is_delegated, normalize_attribute } from '../../../../utils.js';
import {
active_effect,
@@ -65,7 +65,7 @@ export function remove_input_defaults(input) {
// @ts-expect-error
input.__on_r = remove_defaults;
- queue_idle_task(remove_defaults);
+ queue_micro_task(remove_defaults);
add_form_reset_listener();
}
diff --git a/packages/svelte/src/internal/client/dom/task.js b/packages/svelte/src/internal/client/dom/task.js
index 938f3ccda2..1a47eee6cf 100644
--- a/packages/svelte/src/internal/client/dom/task.js
+++ b/packages/svelte/src/internal/client/dom/task.js
@@ -1,32 +1,17 @@
import { run_all } from '../../shared/utils.js';
import { is_flushing_sync } from '../reactivity/batch.js';
-// Fallback for when requestIdleCallback is not available
-const request_idle_callback =
- typeof requestIdleCallback === 'undefined'
- ? (/** @type {() => void} */ cb) => setTimeout(cb, 1)
- : requestIdleCallback;
-
/** @type {Array<() => void>} */
let micro_tasks = [];
-/** @type {Array<() => void>} */
-let idle_tasks = [];
-
function run_micro_tasks() {
var tasks = micro_tasks;
micro_tasks = [];
run_all(tasks);
}
-function run_idle_tasks() {
- var tasks = idle_tasks;
- idle_tasks = [];
- run_all(tasks);
-}
-
export function has_pending_tasks() {
- return micro_tasks.length > 0 || idle_tasks.length > 0;
+ return micro_tasks.length > 0;
}
/**
@@ -51,17 +36,6 @@ export function queue_micro_task(fn) {
micro_tasks.push(fn);
}
-/**
- * @param {() => void} fn
- */
-export function queue_idle_task(fn) {
- if (idle_tasks.length === 0) {
- request_idle_callback(run_idle_tasks);
- }
-
- idle_tasks.push(fn);
-}
-
/**
* Synchronously run any queued tasks.
*/
@@ -69,8 +43,4 @@ export function flush_tasks() {
if (micro_tasks.length > 0) {
run_micro_tasks();
}
-
- if (idle_tasks.length > 0) {
- run_idle_tasks();
- }
}
From ed0a39345b5e453abfdd5b4d921f3c5675dddea7 Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Thu, 25 Sep 2025 14:36:47 -0400
Subject: [PATCH 14/80] chore: simplify batch logic (#16838)
* always delete a batch once committed
* activate inside flush
* centralise logic
* chore: simplify batch logic a bit more (#16845)
* more
* remove unnecessary flushSync
* simplify
---
.../src/internal/client/dom/blocks/await.js | 4 +-
.../svelte/src/internal/client/dom/task.js | 6 +--
.../src/internal/client/reactivity/async.js | 1 -
.../src/internal/client/reactivity/batch.js | 37 +++++++------------
4 files changed, 17 insertions(+), 31 deletions(-)
diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js
index 8605812f1e..e7917fbd9e 100644
--- a/packages/svelte/src/internal/client/dom/blocks/await.js
+++ b/packages/svelte/src/internal/client/dom/blocks/await.js
@@ -22,7 +22,7 @@ import {
set_dev_current_component_function,
set_dev_stack
} from '../../context.js';
-import { flushSync } from '../../reactivity/batch.js';
+import { flushSync, is_flushing_sync } from '../../reactivity/batch.js';
const PENDING = 0;
const THEN = 1;
@@ -126,7 +126,7 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) {
// without this, the DOM does not update until two ticks after the promise
// resolves, which is unexpected behaviour (and somewhat irksome to test)
- flushSync();
+ if (!is_flushing_sync) flushSync();
}
}
}
diff --git a/packages/svelte/src/internal/client/dom/task.js b/packages/svelte/src/internal/client/dom/task.js
index 1a47eee6cf..8c51361467 100644
--- a/packages/svelte/src/internal/client/dom/task.js
+++ b/packages/svelte/src/internal/client/dom/task.js
@@ -10,10 +10,6 @@ function run_micro_tasks() {
run_all(tasks);
}
-export function has_pending_tasks() {
- return micro_tasks.length > 0;
-}
-
/**
* @param {() => void} fn
*/
@@ -40,7 +36,7 @@ export function queue_micro_task(fn) {
* Synchronously run any queued tasks.
*/
export function flush_tasks() {
- if (micro_tasks.length > 0) {
+ while (micro_tasks.length > 0) {
run_micro_tasks();
}
}
diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js
index a9126f1a5c..4d572281b7 100644
--- a/packages/svelte/src/internal/client/reactivity/async.js
+++ b/packages/svelte/src/internal/client/reactivity/async.js
@@ -244,7 +244,6 @@ export async function async_body(fn) {
if (pending) {
batch.flush();
} else {
- batch.activate();
batch.decrement();
}
diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js
index 35aff7d4c9..8cf0e4bd9d 100644
--- a/packages/svelte/src/internal/client/reactivity/batch.js
+++ b/packages/svelte/src/internal/client/reactivity/batch.js
@@ -23,7 +23,7 @@ import {
update_effect
} from '../runtime.js';
import * as e from '../errors.js';
-import { flush_tasks, has_pending_tasks, queue_micro_task } from '../dom/task.js';
+import { flush_tasks, queue_micro_task } from '../dom/task.js';
import { DEV } from 'esm-env';
import { invoke_error_boundary } from '../error-handling.js';
import { old_values } from './sources.js';
@@ -216,15 +216,6 @@ export class Batch {
flush_queued_effects(render_effects);
flush_queued_effects(effects);
- // Reinstate the current batch if there was no new one created, as `process()` runs in a loop in `flush_effects()`.
- // That method expects `current_batch` to be set, and could run the loop again if effects result in new effects
- // being scheduled but without writes happening in which case no new batch is created.
- if (current_batch === null) {
- current_batch = this;
- } else {
- batches.delete(this);
- }
-
this.#deferred?.resolve();
} else {
this.#defer_effects(this.#render_effects);
@@ -365,19 +356,15 @@ export class Batch {
flush() {
if (queued_root_effects.length > 0) {
+ this.activate();
flush_effects();
- } else {
- this.#commit();
- }
-
- if (current_batch !== this) {
- // this can happen if a `flushSync` occurred during `flush_effects()`,
- // which is permitted in legacy mode despite being a terrible idea
- return;
- }
- if (this.#pending === 0) {
- batches.delete(this);
+ if (current_batch !== null && current_batch !== this) {
+ // this can happen if a new batch was created during `flush_effects()`
+ return;
+ }
+ } else if (this.#pending === 0) {
+ this.#commit();
}
this.deactivate();
@@ -394,6 +381,7 @@ export class Batch {
}
this.#callbacks.clear();
+ batches.delete(this);
}
increment() {
@@ -478,14 +466,17 @@ export function flushSync(fn) {
var result;
if (fn) {
- flush_effects();
+ if (current_batch !== null) {
+ flush_effects();
+ }
+
result = fn();
}
while (true) {
flush_tasks();
- if (queued_root_effects.length === 0 && !has_pending_tasks()) {
+ if (queued_root_effects.length === 0) {
current_batch?.flush();
// we need to check again, in case we just updated an `$effect.pending()`
From 12e1c81fe64c2754484e6ca2b89399258154e12c Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Thu, 25 Sep 2025 14:38:48 -0400
Subject: [PATCH 15/80] chore: add missing changeset for #16838 and #16845
(#16847)
---
.changeset/clever-turtles-wink.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/clever-turtles-wink.md
diff --git a/.changeset/clever-turtles-wink.md b/.changeset/clever-turtles-wink.md
new file mode 100644
index 0000000000..6ff21f4d91
--- /dev/null
+++ b/.changeset/clever-turtles-wink.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+chore: simplify batch logic
From bb33c555b49b27ecd01afc742a7cf257b494b0b5 Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Fri, 26 Sep 2025 20:46:26 +0200
Subject: [PATCH 16/80] chore: bump some dev deps, harden github actions
(#16851)
---
.github/workflows/ecosystem-ci-trigger.yml | 2 +
.github/workflows/pkg.pr.new.yml | 2 +
package.json | 2 +-
packages/svelte/package.json | 2 +-
pnpm-lock.yaml | 442 +++++++++------------
5 files changed, 194 insertions(+), 256 deletions(-)
diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml
index 7753b606e1..aa08df2f84 100644
--- a/.github/workflows/ecosystem-ci-trigger.yml
+++ b/.github/workflows/ecosystem-ci-trigger.yml
@@ -4,6 +4,8 @@ on:
issue_comment:
types: [created]
+permissions: {}
+
jobs:
trigger:
runs-on: ubuntu-latest
diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml
index b1ba217e5a..49303f1684 100644
--- a/.github/workflows/pkg.pr.new.yml
+++ b/.github/workflows/pkg.pr.new.yml
@@ -1,6 +1,8 @@
name: Publish Any Commit
on: [push, pull_request]
+permissions: {}
+
jobs:
build:
permissions: {}
diff --git a/package.json b/package.json
index df882141ac..ad60494bf2 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"bench:debug": "node --allow-natives-syntax --inspect-brk ./benchmarking/run.js"
},
"devDependencies": {
- "@changesets/cli": "^2.27.8",
+ "@changesets/cli": "^2.29.7",
"@sveltejs/eslint-config": "^8.3.3",
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"@types/node": "^20.11.5",
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 51c6a4f12e..41a32f4a79 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -158,7 +158,7 @@
"@types/aria-query": "^5.0.4",
"@types/node": "^20.11.5",
"dts-buddy": "^0.5.5",
- "esbuild": "^0.21.5",
+ "esbuild": "^0.25.10",
"rollup": "^4.22.4",
"source-map": "^0.7.4",
"tinyglobby": "^0.2.12",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 39a504e504..f585619252 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
devDependencies:
'@changesets/cli':
- specifier: ^2.27.8
- version: 2.27.8
+ specifier: ^2.29.7
+ version: 2.29.7(@types/node@20.19.17)
'@sveltejs/eslint-config':
specifier: ^8.3.3
version: 8.3.3(@stylistic/eslint-plugin-js@1.8.0(eslint@9.9.1))(eslint-config-prettier@9.1.0(eslint@9.9.1))(eslint-plugin-n@17.16.1(eslint@9.9.1)(typescript@5.5.4))(eslint-plugin-svelte@3.11.0(eslint@9.9.1)(svelte@packages+svelte))(eslint@9.9.1)(typescript-eslint@8.26.0(eslint@9.9.1)(typescript@5.5.4))(typescript@5.5.4)
@@ -19,13 +19,13 @@ importers:
version: 1.1.0
'@types/node':
specifier: ^20.11.5
- version: 20.12.7
+ version: 20.19.17
'@types/picomatch':
specifier: ^4.0.2
version: 4.0.2
'@vitest/coverage-v8':
specifier: ^2.1.9
- version: 2.1.9(vitest@2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
+ version: 2.1.9(vitest@2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
eslint:
specifier: ^9.9.1
version: 9.9.1
@@ -61,7 +61,7 @@ importers:
version: 1.2.5
vitest:
specifier: ^2.1.9
- version: 2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ version: 2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
packages/svelte:
dependencies:
@@ -110,7 +110,7 @@ importers:
devDependencies:
'@jridgewell/trace-mapping':
specifier: ^0.3.25
- version: 0.3.25
+ version: 0.3.31
'@playwright/test':
specifier: ^1.46.1
version: 1.46.1
@@ -131,13 +131,13 @@ importers:
version: 5.0.4
'@types/node':
specifier: ^20.11.5
- version: 20.12.7
+ version: 20.19.17
dts-buddy:
specifier: ^0.5.5
version: 0.5.5(typescript@5.5.4)
esbuild:
- specifier: ^0.21.5
- version: 0.21.5
+ specifier: ^0.25.10
+ version: 0.25.10
rollup:
specifier: ^4.22.4
version: 4.50.1
@@ -152,7 +152,7 @@ importers:
version: 5.5.4
vitest:
specifier: ^2.1.9
- version: 2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ version: 2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
playgrounds/sandbox:
devDependencies:
@@ -215,63 +215,63 @@ packages:
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
- '@changesets/apply-release-plan@7.0.5':
- resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==}
+ '@changesets/apply-release-plan@7.0.13':
+ resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==}
- '@changesets/assemble-release-plan@6.0.4':
- resolution: {integrity: sha512-nqICnvmrwWj4w2x0fOhVj2QEGdlUuwVAwESrUo5HLzWMI1rE5SWfsr9ln+rDqWB6RQ2ZyaMZHUcU7/IRaUJS+Q==}
+ '@changesets/assemble-release-plan@6.0.9':
+ resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==}
- '@changesets/changelog-git@0.2.0':
- resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==}
+ '@changesets/changelog-git@0.2.1':
+ resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==}
- '@changesets/cli@2.27.8':
- resolution: {integrity: sha512-gZNyh+LdSsI82wBSHLQ3QN5J30P4uHKJ4fXgoGwQxfXwYFTJzDdvIJasZn8rYQtmKhyQuiBj4SSnLuKlxKWq4w==}
+ '@changesets/cli@2.29.7':
+ resolution: {integrity: sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ==}
hasBin: true
- '@changesets/config@3.0.3':
- resolution: {integrity: sha512-vqgQZMyIcuIpw9nqFIpTSNyc/wgm/Lu1zKN5vECy74u95Qx/Wa9g27HdgO4NkVAaq+BGA8wUc/qvbvVNs93n6A==}
+ '@changesets/config@3.1.1':
+ resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==}
'@changesets/errors@0.2.0':
resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==}
- '@changesets/get-dependents-graph@2.1.2':
- resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==}
+ '@changesets/get-dependents-graph@2.1.3':
+ resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==}
'@changesets/get-github-info@0.5.2':
resolution: {integrity: sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==}
- '@changesets/get-release-plan@4.0.4':
- resolution: {integrity: sha512-SicG/S67JmPTrdcc9Vpu0wSQt7IiuN0dc8iR5VScnnTVPfIaLvKmEGRvIaF0kcn8u5ZqLbormZNTO77bCEvyWw==}
+ '@changesets/get-release-plan@4.0.13':
+ resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==}
'@changesets/get-version-range-type@0.4.0':
resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==}
- '@changesets/git@3.0.1':
- resolution: {integrity: sha512-pdgHcYBLCPcLd82aRcuO0kxCDbw/yISlOtkmwmE8Odo1L6hSiZrBOsRl84eYG7DRCab/iHnOkWqExqc4wxk2LQ==}
+ '@changesets/git@3.0.4':
+ resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==}
'@changesets/logger@0.1.1':
resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==}
- '@changesets/parse@0.4.0':
- resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==}
+ '@changesets/parse@0.4.1':
+ resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==}
- '@changesets/pre@2.0.1':
- resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==}
+ '@changesets/pre@2.0.2':
+ resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==}
- '@changesets/read@0.6.1':
- resolution: {integrity: sha512-jYMbyXQk3nwP25nRzQQGa1nKLY0KfoOV7VLgwucI0bUO8t8ZLCr6LZmgjXsiKuRDc+5A6doKPr9w2d+FEJ55zQ==}
+ '@changesets/read@0.6.5':
+ resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==}
- '@changesets/should-skip-package@0.1.1':
- resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==}
+ '@changesets/should-skip-package@0.1.2':
+ resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==}
'@changesets/types@4.1.0':
resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==}
- '@changesets/types@6.0.0':
- resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==}
+ '@changesets/types@6.1.0':
+ resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==}
- '@changesets/write@0.3.2':
- resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==}
+ '@changesets/write@0.4.0':
+ resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
@@ -601,6 +601,15 @@ packages:
resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
engines: {node: '>=18.18'}
+ '@inquirer/external-editor@1.0.2':
+ resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@@ -630,8 +639,8 @@ packages:
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
- '@jridgewell/trace-mapping@0.3.25':
- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -869,8 +878,8 @@ packages:
'@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
- '@types/node@20.12.7':
- resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
+ '@types/node@20.19.17':
+ resolution: {integrity: sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==}
'@types/node@24.5.2':
resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==}
@@ -881,9 +890,6 @@ packages:
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
- '@types/semver@7.5.6':
- resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==}
-
'@typescript-eslint/eslint-plugin@8.26.0':
resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1115,16 +1121,16 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
- chai@5.1.2:
- resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==}
- engines: {node: '>=12'}
+ chai@5.3.3:
+ resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ engines: {node: '>=18'}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
- chardet@0.7.0:
- resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
+ chardet@2.1.0:
+ resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==}
check-error@2.1.1:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
@@ -1162,11 +1168,8 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- cross-spawn@5.1.0:
- resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
-
- cross-spawn@7.0.3:
- resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
cssesc@3.0.0:
@@ -1271,8 +1274,8 @@ packages:
error-stack-parser-es@1.0.5:
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
- es-module-lexer@1.6.0:
- resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
@@ -1388,17 +1391,13 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
- expect-type@1.1.0:
- resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
+ expect-type@1.2.2:
+ resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==}
engines: {node: '>=12.0.0'}
extendable-error@0.1.7:
resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==}
- external-editor@3.1.0:
- resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
- engines: {node: '>=4'}
-
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1536,17 +1535,18 @@ packages:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
- human-id@1.0.2:
- resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
-
- iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
+ human-id@4.1.1:
+ resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==}
+ hasBin: true
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
+ iconv-lite@0.7.0:
+ resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
+ engines: {node: '>=0.10.0'}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1767,15 +1767,12 @@ packages:
lodash.startcase@4.4.0:
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
- loupe@3.1.3:
- resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
+ loupe@3.2.1:
+ resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@4.1.5:
- resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
-
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
@@ -1859,10 +1856,6 @@ packages:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
- os-tmpdir@1.0.2:
- resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
- engines: {node: '>=0.10.0'}
-
outdent@0.5.0:
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
@@ -2020,9 +2013,6 @@ packages:
engines: {node: '>=14'}
hasBin: true
- pseudomap@1.0.2:
- resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
-
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -2109,18 +2099,10 @@ packages:
serialize-javascript@6.0.2:
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
- shebang-command@1.2.0:
- resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
- engines: {node: '>=0.10.0'}
-
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
- shebang-regex@1.0.0:
- resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
- engines: {node: '>=0.10.0'}
-
shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
@@ -2128,9 +2110,6 @@ packages:
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
- signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
-
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@@ -2161,8 +2140,8 @@ packages:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
- spawndamnit@2.0.0:
- resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
+ spawndamnit@3.0.1:
+ resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==}
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
@@ -2170,8 +2149,8 @@ packages:
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
- std-env@3.8.0:
- resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
+ std-env@3.9.0:
+ resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
@@ -2247,8 +2226,8 @@ packages:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
- tinypool@1.0.2:
- resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@1.2.0:
@@ -2266,10 +2245,6 @@ packages:
resolution: {integrity: sha512-ph4AE5BXWIOsSy9stpoeo7bYe/Cy7VfpciIH4RhVZUPItCJmhqWCN0EVzxd8BOHiyNb42vuJc6NWTjJkg91Tuw==}
hasBin: true
- tmp@0.0.33:
- resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
- engines: {node: '>=0.6.0'}
-
to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
@@ -2330,8 +2305,8 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
- undici-types@5.26.5:
- resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@7.12.0:
resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==}
@@ -2518,10 +2493,6 @@ packages:
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
- which@1.3.1:
- resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
- hasBin: true
-
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -2563,9 +2534,6 @@ packages:
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
- yallist@2.1.2:
- resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
-
yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
@@ -2584,7 +2552,7 @@ snapshots:
'@ampproject/remapping@2.3.0':
dependencies:
'@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/trace-mapping': 0.3.31
'@babel/helper-string-parser@7.24.8': {}
@@ -2606,13 +2574,13 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
- '@changesets/apply-release-plan@7.0.5':
+ '@changesets/apply-release-plan@7.0.13':
dependencies:
- '@changesets/config': 3.0.3
+ '@changesets/config': 3.1.1
'@changesets/get-version-range-type': 0.4.0
- '@changesets/git': 3.0.1
- '@changesets/should-skip-package': 0.1.1
- '@changesets/types': 6.0.0
+ '@changesets/git': 3.0.4
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
detect-indent: 6.1.0
fs-extra: 7.0.1
@@ -2622,58 +2590,58 @@ snapshots:
resolve-from: 5.0.0
semver: 7.7.2
- '@changesets/assemble-release-plan@6.0.4':
+ '@changesets/assemble-release-plan@6.0.9':
dependencies:
'@changesets/errors': 0.2.0
- '@changesets/get-dependents-graph': 2.1.2
- '@changesets/should-skip-package': 0.1.1
- '@changesets/types': 6.0.0
+ '@changesets/get-dependents-graph': 2.1.3
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
semver: 7.7.2
- '@changesets/changelog-git@0.2.0':
+ '@changesets/changelog-git@0.2.1':
dependencies:
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
- '@changesets/cli@2.27.8':
+ '@changesets/cli@2.29.7(@types/node@20.19.17)':
dependencies:
- '@changesets/apply-release-plan': 7.0.5
- '@changesets/assemble-release-plan': 6.0.4
- '@changesets/changelog-git': 0.2.0
- '@changesets/config': 3.0.3
+ '@changesets/apply-release-plan': 7.0.13
+ '@changesets/assemble-release-plan': 6.0.9
+ '@changesets/changelog-git': 0.2.1
+ '@changesets/config': 3.1.1
'@changesets/errors': 0.2.0
- '@changesets/get-dependents-graph': 2.1.2
- '@changesets/get-release-plan': 4.0.4
- '@changesets/git': 3.0.1
+ '@changesets/get-dependents-graph': 2.1.3
+ '@changesets/get-release-plan': 4.0.13
+ '@changesets/git': 3.0.4
'@changesets/logger': 0.1.1
- '@changesets/pre': 2.0.1
- '@changesets/read': 0.6.1
- '@changesets/should-skip-package': 0.1.1
- '@changesets/types': 6.0.0
- '@changesets/write': 0.3.2
+ '@changesets/pre': 2.0.2
+ '@changesets/read': 0.6.5
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
+ '@changesets/write': 0.4.0
+ '@inquirer/external-editor': 1.0.2(@types/node@20.19.17)
'@manypkg/get-packages': 1.1.3
- '@types/semver': 7.5.6
ansi-colors: 4.1.3
ci-info: 3.9.0
enquirer: 2.4.1
- external-editor: 3.1.0
fs-extra: 7.0.1
mri: 1.2.0
- outdent: 0.5.0
p-limit: 2.3.0
package-manager-detector: 0.2.0
picocolors: 1.1.1
resolve-from: 5.0.0
semver: 7.7.2
- spawndamnit: 2.0.0
+ spawndamnit: 3.0.1
term-size: 2.2.1
+ transitivePeerDependencies:
+ - '@types/node'
- '@changesets/config@3.0.3':
+ '@changesets/config@3.1.1':
dependencies:
'@changesets/errors': 0.2.0
- '@changesets/get-dependents-graph': 2.1.2
+ '@changesets/get-dependents-graph': 2.1.3
'@changesets/logger': 0.1.1
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
fs-extra: 7.0.1
micromatch: 4.0.8
@@ -2682,9 +2650,9 @@ snapshots:
dependencies:
extendable-error: 0.1.7
- '@changesets/get-dependents-graph@2.1.2':
+ '@changesets/get-dependents-graph@2.1.3':
dependencies:
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
picocolors: 1.1.1
semver: 7.7.2
@@ -2696,65 +2664,65 @@ snapshots:
transitivePeerDependencies:
- encoding
- '@changesets/get-release-plan@4.0.4':
+ '@changesets/get-release-plan@4.0.13':
dependencies:
- '@changesets/assemble-release-plan': 6.0.4
- '@changesets/config': 3.0.3
- '@changesets/pre': 2.0.1
- '@changesets/read': 0.6.1
- '@changesets/types': 6.0.0
+ '@changesets/assemble-release-plan': 6.0.9
+ '@changesets/config': 3.1.1
+ '@changesets/pre': 2.0.2
+ '@changesets/read': 0.6.5
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
'@changesets/get-version-range-type@0.4.0': {}
- '@changesets/git@3.0.1':
+ '@changesets/git@3.0.4':
dependencies:
'@changesets/errors': 0.2.0
'@manypkg/get-packages': 1.1.3
is-subdir: 1.2.0
micromatch: 4.0.8
- spawndamnit: 2.0.0
+ spawndamnit: 3.0.1
'@changesets/logger@0.1.1':
dependencies:
picocolors: 1.1.1
- '@changesets/parse@0.4.0':
+ '@changesets/parse@0.4.1':
dependencies:
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
js-yaml: 3.14.1
- '@changesets/pre@2.0.1':
+ '@changesets/pre@2.0.2':
dependencies:
'@changesets/errors': 0.2.0
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
fs-extra: 7.0.1
- '@changesets/read@0.6.1':
+ '@changesets/read@0.6.5':
dependencies:
- '@changesets/git': 3.0.1
+ '@changesets/git': 3.0.4
'@changesets/logger': 0.1.1
- '@changesets/parse': 0.4.0
- '@changesets/types': 6.0.0
+ '@changesets/parse': 0.4.1
+ '@changesets/types': 6.1.0
fs-extra: 7.0.1
p-filter: 2.1.0
picocolors: 1.1.1
- '@changesets/should-skip-package@0.1.1':
+ '@changesets/should-skip-package@0.1.2':
dependencies:
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
'@changesets/types@4.1.0': {}
- '@changesets/types@6.0.0': {}
+ '@changesets/types@6.1.0': {}
- '@changesets/write@0.3.2':
+ '@changesets/write@0.4.0':
dependencies:
- '@changesets/types': 6.0.0
+ '@changesets/types': 6.1.0
fs-extra: 7.0.1
- human-id: 1.0.2
+ human-id: 4.1.1
prettier: 2.8.8
'@esbuild/aix-ppc64@0.21.5':
@@ -2941,6 +2909,13 @@ snapshots:
'@humanwhocodes/retry@0.3.0': {}
+ '@inquirer/external-editor@1.0.2(@types/node@20.19.17)':
+ dependencies:
+ chardet: 2.1.0
+ iconv-lite: 0.7.0
+ optionalDependencies:
+ '@types/node': 20.19.17
+
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@@ -2956,12 +2931,12 @@ snapshots:
dependencies:
'@jridgewell/set-array': 1.2.1
'@jridgewell/sourcemap-codec': 1.5.0
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/trace-mapping': 0.3.31
'@jridgewell/remapping@2.3.4':
dependencies:
'@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.1': {}
@@ -2970,11 +2945,11 @@ snapshots:
'@jridgewell/source-map@0.3.6':
dependencies:
'@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/trace-mapping': 0.3.31
'@jridgewell/sourcemap-codec@1.5.0': {}
- '@jridgewell/trace-mapping@0.3.25':
+ '@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.5.0
@@ -3186,9 +3161,9 @@ snapshots:
'@types/node@12.20.55': {}
- '@types/node@20.12.7':
+ '@types/node@20.19.17':
dependencies:
- undici-types: 5.26.5
+ undici-types: 6.21.0
'@types/node@24.5.2':
dependencies:
@@ -3198,8 +3173,6 @@ snapshots:
'@types/resolve@1.20.2': {}
- '@types/semver@7.5.6': {}
-
'@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)':
dependencies:
'@eslint-community/regexpp': 4.12.1
@@ -3329,7 +3302,7 @@ snapshots:
'@typescript-eslint/types': 8.43.0
eslint-visitor-keys: 4.2.1
- '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
+ '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
@@ -3340,10 +3313,10 @@ snapshots:
istanbul-reports: 3.1.7
magic-string: 0.30.17
magicast: 0.3.5
- std-env: 3.8.0
+ std-env: 3.9.0
test-exclude: 7.0.1
tinyrainbow: 1.2.0
- vitest: 2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ vitest: 2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
transitivePeerDependencies:
- supports-color
@@ -3351,16 +3324,16 @@ snapshots:
dependencies:
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
- chai: 5.1.2
+ chai: 5.3.3
tinyrainbow: 1.2.0
- '@vitest/mocker@2.1.9(vite@5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
+ '@vitest/mocker@2.1.9(vite@5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
dependencies:
'@vitest/spy': 2.1.9
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- vite: 5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ vite: 5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
'@vitest/pretty-format@2.1.9':
dependencies:
@@ -3384,7 +3357,7 @@ snapshots:
'@vitest/utils@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
- loupe: 3.1.3
+ loupe: 3.2.1
tinyrainbow: 1.2.0
acorn-jsx@5.3.2(acorn@8.15.0):
@@ -3476,12 +3449,12 @@ snapshots:
callsites@3.1.0: {}
- chai@5.1.2:
+ chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
- loupe: 3.1.3
+ loupe: 3.2.1
pathval: 2.0.0
chalk@4.1.2:
@@ -3489,7 +3462,7 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
- chardet@0.7.0: {}
+ chardet@2.1.0: {}
check-error@2.1.1: {}
@@ -3526,13 +3499,7 @@ snapshots:
concat-map@0.0.1: {}
- cross-spawn@5.1.0:
- dependencies:
- lru-cache: 4.1.5
- shebang-command: 1.2.0
- which: 1.3.1
-
- cross-spawn@7.0.3:
+ cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
@@ -3617,7 +3584,7 @@ snapshots:
error-stack-parser-es@1.0.5: {}
- es-module-lexer@1.6.0: {}
+ es-module-lexer@1.7.0: {}
esbuild@0.21.5:
optionalDependencies:
@@ -3750,7 +3717,7 @@ snapshots:
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
chalk: 4.1.2
- cross-spawn: 7.0.3
+ cross-spawn: 7.0.6
debug: 4.4.1
escape-string-regexp: 4.0.0
eslint-scope: 8.4.0
@@ -3815,16 +3782,10 @@ snapshots:
esutils@2.0.3: {}
- expect-type@1.1.0: {}
+ expect-type@1.2.2: {}
extendable-error@0.1.7: {}
- external-editor@3.1.0:
- dependencies:
- chardet: 0.7.0
- iconv-lite: 0.4.24
- tmp: 0.0.33
-
fast-deep-equal@3.1.3: {}
fast-glob@3.3.3:
@@ -3874,7 +3835,7 @@ snapshots:
foreground-child@3.3.0:
dependencies:
- cross-spawn: 7.0.3
+ cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.0:
@@ -3969,13 +3930,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- human-id@1.0.2: {}
+ human-id@4.1.1: {}
- iconv-lite@0.4.24:
+ iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
- iconv-lite@0.6.3:
+ iconv-lite@0.7.0:
dependencies:
safer-buffer: 2.1.2
@@ -4052,7 +4013,7 @@ snapshots:
istanbul-lib-source-maps@5.0.6:
dependencies:
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/trace-mapping': 0.3.31
debug: 4.4.1
istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
@@ -4187,15 +4148,10 @@ snapshots:
lodash.startcase@4.4.0: {}
- loupe@3.1.3: {}
+ loupe@3.2.1: {}
lru-cache@10.4.3: {}
- lru-cache@4.1.5:
- dependencies:
- pseudomap: 1.0.2
- yallist: 2.1.2
-
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
@@ -4270,8 +4226,6 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- os-tmpdir@1.0.2: {}
-
outdent@0.5.0: {}
p-filter@2.1.0:
@@ -4389,8 +4343,6 @@ snapshots:
prettier@3.2.4: {}
- pseudomap@1.0.2: {}
-
punycode@2.3.1: {}
queue-microtask@1.2.3: {}
@@ -4489,22 +4441,14 @@ snapshots:
dependencies:
randombytes: 2.1.0
- shebang-command@1.2.0:
- dependencies:
- shebang-regex: 1.0.0
-
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
- shebang-regex@1.0.0: {}
-
shebang-regex@3.0.0: {}
siginfo@2.0.0: {}
- signal-exit@3.0.7: {}
-
signal-exit@4.1.0: {}
sirv@3.0.2:
@@ -4528,16 +4472,16 @@ snapshots:
source-map@0.7.4: {}
- spawndamnit@2.0.0:
+ spawndamnit@3.0.1:
dependencies:
- cross-spawn: 5.1.0
- signal-exit: 3.0.7
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
sprintf-js@1.0.3: {}
stackback@0.0.2: {}
- std-env@3.8.0: {}
+ std-env@3.9.0: {}
string-width@4.2.3:
dependencies:
@@ -4610,7 +4554,7 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
- tinypool@1.0.2: {}
+ tinypool@1.1.1: {}
tinyrainbow@1.2.0: {}
@@ -4622,10 +4566,6 @@ snapshots:
dependencies:
tldts-core: 6.1.64
- tmp@0.0.33:
- dependencies:
- os-tmpdir: 1.0.2
-
to-fast-properties@2.0.0: {}
to-regex-range@5.0.1:
@@ -4677,7 +4617,7 @@ snapshots:
typescript@5.5.4: {}
- undici-types@5.26.5: {}
+ undici-types@6.21.0: {}
undici-types@7.12.0: {}
@@ -4708,13 +4648,13 @@ snapshots:
dependencies:
vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
- vite-node@2.1.9(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
+ vite-node@2.1.9(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
dependencies:
cac: 6.7.14
debug: 4.4.1
- es-module-lexer: 1.6.0
+ es-module-lexer: 1.7.0
pathe: 1.1.2
- vite: 5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ vite: 5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
transitivePeerDependencies:
- '@types/node'
- less
@@ -4746,13 +4686,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- vite@5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
+ vite@5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.6
rollup: 4.50.1
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.19.17
fsevents: 2.3.3
lightningcss: 1.23.0
sass: 1.70.0
@@ -4777,30 +4717,30 @@ snapshots:
optionalDependencies:
vite: 7.1.5(@types/node@24.5.2)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
- vitest@2.1.9(@types/node@20.12.7)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
+ vitest@2.1.9(@types/node@20.19.17)(jsdom@25.0.1)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0):
dependencies:
'@vitest/expect': 2.1.9
- '@vitest/mocker': 2.1.9(vite@5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
+ '@vitest/mocker': 2.1.9(vite@5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
'@vitest/pretty-format': 2.1.9
'@vitest/runner': 2.1.9
'@vitest/snapshot': 2.1.9
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
- chai: 5.1.2
+ chai: 5.3.3
debug: 4.4.1
- expect-type: 1.1.0
+ expect-type: 1.2.2
magic-string: 0.30.17
pathe: 1.1.2
- std-env: 3.8.0
+ std-env: 3.9.0
tinybench: 2.9.0
tinyexec: 0.3.2
- tinypool: 1.0.2
+ tinypool: 1.1.1
tinyrainbow: 1.2.0
- vite: 5.4.20(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
- vite-node: 2.1.9(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ vite: 5.4.20(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
+ vite-node: 2.1.9(@types/node@20.19.17)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)
why-is-node-running: 2.3.0
optionalDependencies:
- '@types/node': 20.12.7
+ '@types/node': 20.19.17
jsdom: 25.0.1
transitivePeerDependencies:
- less
@@ -4837,10 +4777,6 @@ snapshots:
tr46: 0.0.3
webidl-conversions: 3.0.1
- which@1.3.1:
- dependencies:
- isexe: 2.0.0
-
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -4872,8 +4808,6 @@ snapshots:
xmlchars@2.2.0: {}
- yallist@2.1.2: {}
-
yaml@1.10.2: {}
yocto-queue@0.1.0: {}
From e0dba165b49d4489a1e622dd5bdededd32fa3d1a Mon Sep 17 00:00:00 2001
From: Conduitry
Date: Sun, 28 Sep 2025 17:38:18 -0400
Subject: [PATCH 17/80] docs: remove reference to SSR being synchronous
(#16861)
---
documentation/docs/03-template-syntax/19-await-expressions.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/documentation/docs/03-template-syntax/19-await-expressions.md b/documentation/docs/03-template-syntax/19-await-expressions.md
index d3896a5c4e..1c613af870 100644
--- a/documentation/docs/03-template-syntax/19-await-expressions.md
+++ b/documentation/docs/03-template-syntax/19-await-expressions.md
@@ -139,8 +139,6 @@ If a `` with a `pending` snippet is encountered during SSR, tha
As an experimental feature, the details of how `await` is handled (and related APIs like `$effect.pending()`) are subject to breaking changes outside of a semver major release, though we intend to keep such changes to a bare minimum.
-Currently, server-side rendering is synchronous. If a `` with a `pending` snippet is encountered during SSR, only the `pending` snippet will be rendered.
-
## Breaking changes
Effects run in a slightly different order when the `experimental.async` option is `true`. Specifically, _block_ effects like `{#if ...}` and `{#each ...}` now run before an `$effect.pre` or `beforeUpdate` in the same component, which means that in [very rare situations](/playground/untitled?#H4sIAAAAAAAAE22R3VLDIBCFX2WLvUhnTHsf0zre-Q7WmfwtFV2BgU1rJ5N3F0jaOuoVcPbw7VkYhK4_URTiGYkMnIyjDjLsFGO3EvdCKkIvipdB8NlGXxSCPt96snbtj0gctab2-J_eGs2oOWBE6VunLO_2es-EDKZ5x5ZhC0vPNWM2gHXGouNzAex6hHH1cPHil_Lsb95YT9VQX6KUAbS2DrNsBdsdDFHe8_XSYjH1SrhELTe3MLpsemajweiWVPuxHSbKNd-8eQTdE0EBf4OOaSg2hwNhhE_ABB_ulJzjj9FULvIcqgm5vnAqUB7wWFMfhuugQWkcAr8hVD-mq8D12kOep24J_IszToOXdveGDsuNnZwbJUNlXsKnhJdhUcTo42s41YpOSneikDV5HL8BktM6yRcCAAA=) it is possible to update a block that should no longer exist, but only if you update state inside an effect, [which you should avoid]($effect#When-not-to-use-$effect).
From 8895bd44f5297c0c69b8bc081155fbf9bac9c00e Mon Sep 17 00:00:00 2001
From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com>
Date: Mon, 29 Sep 2025 08:04:57 -0700
Subject: [PATCH 18/80] fix: coerce nullish `` to empty string (#16863)
---
.changeset/silly-walls-fail.md | 5 +++++
.../3-transform/client/visitors/TitleElement.js | 13 ++++++++++++-
.../runtime-runes/samples/title-nullish/_config.js | 7 +++++++
.../runtime-runes/samples/title-nullish/main.svelte | 6 ++++++
4 files changed, 30 insertions(+), 1 deletion(-)
create mode 100644 .changeset/silly-walls-fail.md
create mode 100644 packages/svelte/tests/runtime-runes/samples/title-nullish/_config.js
create mode 100644 packages/svelte/tests/runtime-runes/samples/title-nullish/main.svelte
diff --git a/.changeset/silly-walls-fail.md b/.changeset/silly-walls-fail.md
new file mode 100644
index 0000000000..6f364e7f8a
--- /dev/null
+++ b/.changeset/silly-walls-fail.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: coerce nullish `` to empty string
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/TitleElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/TitleElement.js
index e6f4202a01..98d7880b25 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/TitleElement.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/TitleElement.js
@@ -12,8 +12,19 @@ export function TitleElement(node, context) {
/** @type {any} */ (node.fragment.nodes),
context
);
+ const evaluated = context.state.scope.evaluate(value);
- const statement = b.stmt(b.assignment('=', b.id('$.document.title'), value));
+ const statement = b.stmt(
+ b.assignment(
+ '=',
+ b.id('$.document.title'),
+ evaluated.is_known
+ ? b.literal(evaluated.value)
+ : evaluated.is_defined
+ ? value
+ : b.logical('??', value, b.literal(''))
+ )
+ );
if (has_state) {
context.state.update.push(statement);
diff --git a/packages/svelte/tests/runtime-runes/samples/title-nullish/_config.js b/packages/svelte/tests/runtime-runes/samples/title-nullish/_config.js
new file mode 100644
index 0000000000..819d6b620e
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/title-nullish/_config.js
@@ -0,0 +1,7 @@
+import { test } from '../../test';
+
+export default test({
+ test({ assert, target }) {
+ assert.equal(target.ownerDocument.title, '');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/title-nullish/main.svelte b/packages/svelte/tests/runtime-runes/samples/title-nullish/main.svelte
new file mode 100644
index 0000000000..f1fa7e7b84
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/title-nullish/main.svelte
@@ -0,0 +1,6 @@
+
+
+ {thing.thing}
+
\ No newline at end of file
From 87f7e979635baa46acb594ecc7f2822920cb7aaf Mon Sep 17 00:00:00 2001
From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com>
Date: Mon, 29 Sep 2025 08:05:13 -0700
Subject: [PATCH 19/80] fix: wrap async `children` in `$$renderer.async`
(#16862)
---
.changeset/rude-terms-confess.md | 5 +++++
.../phases/3-transform/server/visitors/shared/component.js | 7 ++++++-
.../samples/async-children/_expected.html | 1 +
.../samples/async-children/component.svelte | 4 ++++
.../samples/async-children/main.svelte | 7 +++++++
5 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 .changeset/rude-terms-confess.md
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-children/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-children/component.svelte
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-children/main.svelte
diff --git a/.changeset/rude-terms-confess.md b/.changeset/rude-terms-confess.md
new file mode 100644
index 0000000000..a24774952e
--- /dev/null
+++ b/.changeset/rude-terms-confess.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: wrap async `children` in `$$renderer.async`
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/component.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/component.js
index d0de750c0e..e463ea785a 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/component.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/component.js
@@ -242,7 +242,12 @@ export function build_inline_component(node, expression, context) {
params.push(pattern);
}
- const slot_fn = b.arrow(params, b.block(block.body));
+ const slot_fn = b.arrow(
+ params,
+ node.fragment.metadata.has_await
+ ? b.block([create_async_block(b.block(block.body))])
+ : b.block(block.body)
+ );
if (slot_name === 'default' && !has_children_prop) {
if (
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-children/_expected.html b/packages/svelte/tests/server-side-rendering/samples/async-children/_expected.html
new file mode 100644
index 0000000000..04d9709792
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-children/_expected.html
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-children/component.svelte b/packages/svelte/tests/server-side-rendering/samples/async-children/component.svelte
new file mode 100644
index 0000000000..73b5a2f823
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-children/component.svelte
@@ -0,0 +1,4 @@
+
+{@render children()}
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-children/main.svelte b/packages/svelte/tests/server-side-rendering/samples/async-children/main.svelte
new file mode 100644
index 0000000000..ae0fc571b3
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-children/main.svelte
@@ -0,0 +1,7 @@
+
+
+ {@const one = await 1}
+ {one}
+
\ No newline at end of file
From 25cbdc8cb1c672cfa0ce506e9d432cf5d86863e6 Mon Sep 17 00:00:00 2001
From: Rich Harris
Date: Tue, 30 Sep 2025 09:57:22 -0400
Subject: [PATCH 20/80] fix: merge batches (#16866)
whenever a batch is committed, we essentially 'rebase' other pending batches on top of the newly applied state
---
.changeset/lemon-cars-count.md | 5 +
.../src/internal/client/reactivity/batch.js | 206 +++++++++++-------
.../internal/client/reactivity/deriveds.js | 46 ++--
.../samples/async-derived-module/_config.js | 11 -
.../runtime-runes/samples/async-if/_config.js | 30 ++-
.../samples/async-if/main.svelte | 21 +-
.../_config.js | 12 +-
.../main.svelte | 21 +-
8 files changed, 208 insertions(+), 144 deletions(-)
create mode 100644 .changeset/lemon-cars-count.md
diff --git a/.changeset/lemon-cars-count.md b/.changeset/lemon-cars-count.md
new file mode 100644
index 0000000000..5724e48460
--- /dev/null
+++ b/.changeset/lemon-cars-count.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: rebase pending batches when other batches are committed
diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js
index 8cf0e4bd9d..fb704edb13 100644
--- a/packages/svelte/src/internal/client/reactivity/batch.js
+++ b/packages/svelte/src/internal/client/reactivity/batch.js
@@ -1,4 +1,4 @@
-/** @import { Derived, Effect, Source } from '#client' */
+/** @import { Derived, Effect, Source, Value } from '#client' */
import {
BLOCK_EFFECT,
BRANCH_EFFECT,
@@ -10,10 +10,11 @@ import {
INERT,
RENDER_EFFECT,
ROOT_EFFECT,
- MAYBE_DIRTY
+ MAYBE_DIRTY,
+ DERIVED
} from '#client/constants';
import { async_mode_flag } from '../../flags/index.js';
-import { deferred, define_property } from '../../shared/utils.js';
+import { deferred, define_property, noop } from '../../shared/utils.js';
import {
active_effect,
is_dirty,
@@ -97,22 +98,8 @@ export class Batch {
#deferred = null;
/**
- * True if an async effect inside this batch resolved and
- * its parent branch was already deleted
- */
- #neutered = false;
-
- /**
- * Async effects (created inside `async_derived`) encountered during processing.
- * These run after the rest of the batch has updated, since they should
- * always have the latest values
- * @type {Effect[]}
- */
- #async_effects = [];
-
- /**
- * The same as `#async_effects`, but for effects inside a newly-created
- * `` — these do not prevent the batch from committing
+ * Async effects inside a newly-created ``
+ * — these do not prevent the batch from committing
* @type {Effect[]}
*/
#boundary_async_effects = [];
@@ -165,32 +152,7 @@ export class Batch {
previous_batch = null;
- /** @type {Map | null} */
- var current_values = null;
-
- // if there are multiple batches, we are 'time travelling' —
- // we need to undo the changes belonging to any batch
- // other than the current one
- if (async_mode_flag && batches.size > 1) {
- current_values = new Map();
- batch_deriveds = new Map();
-
- for (const [source, current] of this.current) {
- current_values.set(source, { v: source.v, wv: source.wv });
- source.v = current;
- }
-
- for (const batch of batches) {
- if (batch === this) continue;
-
- for (const [source, previous] of batch.#previous) {
- if (!current_values.has(source)) {
- current_values.set(source, { v: source.v, wv: source.wv });
- source.v = previous;
- }
- }
- }
- }
+ var revert = Batch.apply(this);
for (const root of root_effects) {
this.#traverse_effect_tree(root);
@@ -198,7 +160,7 @@ export class Batch {
// if we didn't start any new async work, and no async work
// is outstanding from a previous flush, commit
- if (this.#async_effects.length === 0 && this.#pending === 0) {
+ if (this.#pending === 0) {
this.#commit();
var render_effects = this.#render_effects;
@@ -210,7 +172,7 @@ export class Batch {
// If sources are written to, then work needs to happen in a separate batch, else prior sources would be mixed with
// newly updated sources, which could lead to infinite loops when effects run over and over again.
- previous_batch = current_batch;
+ previous_batch = this;
current_batch = null;
flush_queued_effects(render_effects);
@@ -223,27 +185,12 @@ export class Batch {
this.#defer_effects(this.#block_effects);
}
- if (current_values) {
- for (const [source, { v, wv }] of current_values) {
- // reset the source to the current value (unless
- // it got a newer value as a result of effects running)
- if (source.wv <= wv) {
- source.v = v;
- }
- }
-
- batch_deriveds = null;
- }
-
- for (const effect of this.#async_effects) {
- update_effect(effect);
- }
+ revert();
for (const effect of this.#boundary_async_effects) {
update_effect(effect);
}
- this.#async_effects = [];
this.#boundary_async_effects = [];
}
@@ -272,12 +219,8 @@ export class Batch {
} else if (async_mode_flag && (flags & RENDER_EFFECT) !== 0) {
this.#render_effects.push(effect);
} else if ((flags & CLEAN) === 0) {
- if ((flags & ASYNC) !== 0) {
- var effects = effect.b?.is_pending()
- ? this.#boundary_async_effects
- : this.#async_effects;
-
- effects.push(effect);
+ if ((flags & ASYNC) !== 0 && effect.b?.is_pending()) {
+ this.#boundary_async_effects.push(effect);
} else if (is_dirty(effect)) {
if ((effect.f & BLOCK_EFFECT) !== 0) this.#block_effects.push(effect);
update_effect(effect);
@@ -350,10 +293,6 @@ export class Batch {
}
}
- neuter() {
- this.#neutered = true;
- }
-
flush() {
if (queued_root_effects.length > 0) {
this.activate();
@@ -374,13 +313,58 @@ export class Batch {
* Append and remove branches to/from the DOM
*/
#commit() {
- if (!this.#neutered) {
- for (const fn of this.#callbacks) {
- fn();
- }
+ for (const fn of this.#callbacks) {
+ fn();
}
this.#callbacks.clear();
+
+ // If there are other pending batches, they now need to be 'rebased' —
+ // in other words, we re-run block/async effects with the newly
+ // committed state, unless the batch in question has a more
+ // recent value for a given source
+ if (batches.size > 1) {
+ this.#previous.clear();
+
+ let is_earlier = true;
+
+ for (const batch of batches) {
+ if (batch === this) {
+ is_earlier = false;
+ continue;
+ }
+
+ for (const [source, value] of this.current) {
+ if (batch.current.has(source)) {
+ if (is_earlier) {
+ // bring the value up to date
+ batch.current.set(source, value);
+ } else {
+ // later batch has more recent value,
+ // no need to re-run these effects
+ continue;
+ }
+ }
+
+ mark_effects(source);
+ }
+
+ if (queued_root_effects.length > 0) {
+ current_batch = batch;
+ const revert = Batch.apply(batch);
+
+ for (const root of queued_root_effects) {
+ batch.#traverse_effect_tree(root);
+ }
+
+ queued_root_effects = [];
+ revert();
+ }
+ }
+
+ current_batch = null;
+ }
+
batches.delete(this);
}
@@ -402,9 +386,6 @@ export class Batch {
schedule_effect(e);
}
- this.#render_effects = [];
- this.#effects = [];
-
this.flush();
} else {
this.deactivate();
@@ -444,6 +425,51 @@ export class Batch {
static enqueue(task) {
queue_micro_task(task);
}
+
+ /**
+ * @param {Batch} current_batch
+ */
+ static apply(current_batch) {
+ if (!async_mode_flag || batches.size === 1) {
+ return noop;
+ }
+
+ // if there are multiple batches, we are 'time travelling' —
+ // we need to undo the changes belonging to any batch
+ // other than the current one
+
+ /** @type {Map} */
+ var current_values = new Map();
+ batch_deriveds = new Map();
+
+ for (const [source, current] of current_batch.current) {
+ current_values.set(source, { v: source.v, wv: source.wv });
+ source.v = current;
+ }
+
+ for (const batch of batches) {
+ if (batch === current_batch) continue;
+
+ for (const [source, previous] of batch.#previous) {
+ if (!current_values.has(source)) {
+ current_values.set(source, { v: source.v, wv: source.wv });
+ source.v = previous;
+ }
+ }
+ }
+
+ return () => {
+ for (const [source, { v, wv }] of current_values) {
+ // reset the source to the current value (unless
+ // it got a newer value as a result of effects running)
+ if (source.wv <= wv) {
+ source.v = v;
+ }
+ }
+
+ batch_deriveds = null;
+ };
+ }
}
/**
@@ -615,6 +641,26 @@ function flush_queued_effects(effects) {
eager_block_effects = null;
}
+/**
+ * This is similar to `mark_reactions`, but it only marks async/block effects
+ * so that these can re-run after another batch has been committed
+ * @param {Value} value
+ */
+function mark_effects(value) {
+ if (value.reactions !== null) {
+ for (const reaction of value.reactions) {
+ const flags = reaction.f;
+
+ if ((flags & DERIVED) !== 0) {
+ mark_effects(/** @type {Derived} */ (reaction));
+ } else if ((flags & (ASYNC | BLOCK_EFFECT)) !== 0) {
+ set_signal_status(reaction, DIRTY);
+ schedule_effect(/** @type {Effect} */ (reaction));
+ }
+ }
+ }
+}
+
/**
* @param {Effect} signal
* @returns {void}
diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js
index 11405a8e66..5d5976a6c1 100644
--- a/packages/svelte/src/internal/client/reactivity/deriveds.js
+++ b/packages/svelte/src/internal/client/reactivity/deriveds.js
@@ -26,7 +26,7 @@ import {
import { equals, safe_equals } from './equality.js';
import * as e from '../errors.js';
import * as w from '../warnings.js';
-import { async_effect, destroy_effect } from './effects.js';
+import { async_effect, destroy_effect, teardown } from './effects.js';
import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js';
import { get_stack } from '../dev/tracing.js';
import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
@@ -35,6 +35,7 @@ import { component_context } from '../context.js';
import { UNINITIALIZED } from '../../../constants.js';
import { batch_deriveds, current_batch } from './batch.js';
import { unset_context } from './async.js';
+import { deferred } from '../../shared/utils.js';
/** @type {Effect | null} */
export let current_async_effect = null;
@@ -109,37 +110,40 @@ export function async_derived(fn, location) {
var promise = /** @type {Promise} */ (/** @type {unknown} */ (undefined));
var signal = source(/** @type {V} */ (UNINITIALIZED));
- /** @type {Promise | null} */
- var prev = null;
-
// only suspend in async deriveds created on initialisation
var should_suspend = !active_reaction;
+ /** @type {Map>>} */
+ var deferreds = new Map();
+
async_effect(() => {
if (DEV) current_async_effect = active_effect;
+ /** @type {ReturnType>} */
+ var d = deferred();
+ promise = d.promise;
+
try {
- var p = fn();
- // Make sure to always access the then property to read any signals
- // it might access, so that we track them as dependencies.
- if (prev) Promise.resolve(p).catch(() => {}); // avoid unhandled rejection
+ // If this code is changed at some point, make sure to still access the then property
+ // of fn() to read any signals it might access, so that we track them as dependencies.
+ Promise.resolve(fn()).then(d.resolve, d.reject);
} catch (error) {
- p = Promise.reject(error);
+ d.reject(error);
}
if (DEV) current_async_effect = null;
- var r = () => p;
- promise = prev?.then(r, r) ?? Promise.resolve(p);
-
- prev = promise;
-
var batch = /** @type {Batch} */ (current_batch);
var pending = boundary.is_pending();
if (should_suspend) {
boundary.update_pending_count(1);
- if (!pending) batch.increment();
+ if (!pending) {
+ batch.increment();
+
+ deferreds.get(batch)?.reject(STALE_REACTION);
+ deferreds.set(batch, d);
+ }
}
/**
@@ -147,8 +151,6 @@ export function async_derived(fn, location) {
* @param {unknown} error
*/
const handler = (value, error = undefined) => {
- prev = null;
-
current_async_effect = null;
if (!pending) batch.activate();
@@ -187,12 +189,12 @@ export function async_derived(fn, location) {
unset_context();
};
- promise.then(handler, (e) => handler(null, e || 'unknown'));
+ d.promise.then(handler, (e) => handler(null, e || 'unknown'));
+ });
- if (batch) {
- return () => {
- queueMicrotask(() => batch.neuter());
- };
+ teardown(() => {
+ for (const d of deferreds.values()) {
+ d.reject(STALE_REACTION);
}
});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-module/_config.js b/packages/svelte/tests/runtime-runes/samples/async-derived-module/_config.js
index f7d1d28fde..318f88bcc9 100644
--- a/packages/svelte/tests/runtime-runes/samples/async-derived-module/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/async-derived-module/_config.js
@@ -14,17 +14,6 @@ export default test({
const [reset, a, b, increment] = target.querySelectorAll('button');
a.click();
-
- // TODO why is this necessary? why isn't `await tick()` enough?
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- await Promise.resolve();
- flushSync();
await tick();
assert.htmlEqual(
target.innerHTML,
diff --git a/packages/svelte/tests/runtime-runes/samples/async-if/_config.js b/packages/svelte/tests/runtime-runes/samples/async-if/_config.js
index 3cd67952c3..ef119d601d 100644
--- a/packages/svelte/tests/runtime-runes/samples/async-if/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/async-if/_config.js
@@ -2,30 +2,46 @@ import { tick } from 'svelte';
import { test } from '../../test';
export default test({
- html: `reset true false pending
`,
+ html: `shift true false pending
`,
async test({ assert, target }) {
- const [reset, t, f] = target.querySelectorAll('button');
+ const [shift, t, f] = target.querySelectorAll('button');
+
+ shift.click();
+ await tick();
+ assert.htmlEqual(
+ target.innerHTML,
+ 'shift true false yes '
+ );
+
+ f.click();
+ await tick();
t.click();
await tick();
+
+ f.click();
+ await tick();
+
+ shift.click();
+ await tick();
assert.htmlEqual(
target.innerHTML,
- 'reset true false yes '
+ 'shift true false no '
);
- reset.click();
+ shift.click();
await tick();
assert.htmlEqual(
target.innerHTML,
- 'reset true false yes '
+ 'shift true false yes '
);
- f.click();
+ shift.click();
await tick();
assert.htmlEqual(
target.innerHTML,
- 'reset true false no '
+ 'shift true false no '
);
}
});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-if/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-if/main.svelte
index 21a4cbef97..ed708354a4 100644
--- a/packages/svelte/tests/runtime-runes/samples/async-if/main.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/async-if/main.svelte
@@ -1,13 +1,24 @@
- deferred = Promise.withResolvers()}>reset
- deferred.resolve(true)}>true
- deferred.resolve(false)}>false
+ {
+ const d = deferreds.shift();
+ d?.deferred.resolve(d.value);
+}}>shift
+ condition = true}>true
+ condition = false}>false
- {#if await deferred.promise}
+ {#if await push(condition)}
yes
{:else}
no
diff --git a/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/_config.js
index 5e522ebdb5..cc7b2756fa 100644
--- a/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/_config.js
@@ -3,26 +3,24 @@ import { test } from '../../test';
export default test({
async test({ assert, target }) {
- const [a, b, reset1, reset2, resolve1, resolve2] = target.querySelectorAll('button');
+ const [a, b, shift, pop] = target.querySelectorAll('button');
- resolve1.click();
+ shift.click();
await tick();
const p = /** @type {HTMLElement} */ (target.querySelector('#test'));
assert.htmlEqual(p.innerHTML, '1 + 2 = 3');
- flushSync(() => reset1.click());
flushSync(() => a.click());
- flushSync(() => reset2.click());
flushSync(() => b.click());
- resolve2.click();
+ pop.click();
await tick();
- assert.htmlEqual(p.innerHTML, '1 + 2 = 3');
+ assert.htmlEqual(p.innerHTML, '1 + 3 = 4');
- resolve1.click();
+ pop.click();
await tick();
assert.htmlEqual(p.innerHTML, '2 + 3 = 5');
diff --git a/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/main.svelte
index cc82db0d75..48ff06fece 100644
--- a/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/main.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/async-linear-order-same-derived/main.svelte
@@ -1,14 +1,14 @@
@@ -16,14 +16,11 @@
a++}>a++
b++}>b++
- deferred = d1 = Promise.withResolvers()}>reset 1
- deferred = d2 = Promise.withResolvers()}>reset 2
-
- d1.resolve()}>resolve 1
- d2.resolve()}>resolve 2
+ deferreds.shift()?.resolve()}>shift
+ deferreds.pop()?.resolve()}>pop
- {a} + {b} = {await add(a, b)}
+ {a} + {b} = {await push(a, b)}
{#snippet pending()}
loading...
From 46c10d0476c38fae9dff28b812fa476d3202a21a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Koles=C3=A1r?=
<34346635+jakubkolesar@users.noreply.github.com>
Date: Tue, 30 Sep 2025 17:46:58 +0200
Subject: [PATCH 21/80] fix: missing title warning for buttons and anchor tags
(#16872)
* fix(a11y): title warning for buttons and anchor tags
* chore(changeset): added changeset
* Update playgrounds/sandbox/index.html
* Update .changeset/shiny-chicken-occur.md
---------
Co-authored-by: 7nik
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
---
.changeset/shiny-chicken-occur.md | 5 +++++
.../docs/98-reference/.generated/compile-warnings.md | 2 +-
packages/svelte/messages/compile-warnings/a11y.md | 2 +-
.../compiler/phases/2-analyze/visitors/shared/a11y/index.js | 5 ++++-
packages/svelte/src/compiler/warnings.js | 4 ++--
.../validator/samples/a11y-anchor-has-content/warnings.json | 2 +-
.../samples/a11y-consider-explicit-label/input.svelte | 3 +++
.../samples/a11y-consider-explicit-label/warnings.json | 4 ++--
8 files changed, 19 insertions(+), 8 deletions(-)
create mode 100644 .changeset/shiny-chicken-occur.md
diff --git a/.changeset/shiny-chicken-occur.md b/.changeset/shiny-chicken-occur.md
new file mode 100644
index 0000000000..45a560480b
--- /dev/null
+++ b/.changeset/shiny-chicken-occur.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: silence label warning for buttons and anchor tags with title attributes
diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md
index 17841b863c..7dfbe75888 100644
--- a/documentation/docs/98-reference/.generated/compile-warnings.md
+++ b/documentation/docs/98-reference/.generated/compile-warnings.md
@@ -81,7 +81,7 @@ Coding for the keyboard is important for users with physical disabilities who ca
### a11y_consider_explicit_label
```
-Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute
+Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute
```
### a11y_distracting_elements
diff --git a/packages/svelte/messages/compile-warnings/a11y.md b/packages/svelte/messages/compile-warnings/a11y.md
index a299fa53bc..bc34829ce9 100644
--- a/packages/svelte/messages/compile-warnings/a11y.md
+++ b/packages/svelte/messages/compile-warnings/a11y.md
@@ -66,7 +66,7 @@ Coding for the keyboard is important for users with physical disabilities who ca
## a11y_consider_explicit_label
-> Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute
+> Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute
## a11y_distracting_elements
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
index e2f84290e5..8c5bf55e5f 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
@@ -382,7 +382,10 @@ export function check_element(node, context) {
}
// element-specific checks
- const is_labelled = attribute_map.has('aria-label') || attribute_map.has('aria-labelledby');
+ const is_labelled =
+ attribute_map.has('aria-label') ||
+ attribute_map.has('aria-labelledby') ||
+ attribute_map.has('title');
switch (node.name) {
case 'a':
diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js
index 8c03e12e71..089cb1e118 100644
--- a/packages/svelte/src/compiler/warnings.js
+++ b/packages/svelte/src/compiler/warnings.js
@@ -174,11 +174,11 @@ export function a11y_click_events_have_key_events(node) {
}
/**
- * Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute
+ * Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute
* @param {null | NodeLike} node
*/
export function a11y_consider_explicit_label(node) {
- w(node, 'a11y_consider_explicit_label', `Buttons and links should either contain text or have an \`aria-label\` or \`aria-labelledby\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`);
+ w(node, 'a11y_consider_explicit_label', `Buttons and links should either contain text or have an \`aria-label\`, \`aria-labelledby\` or \`title\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`);
}
/**
diff --git a/packages/svelte/tests/validator/samples/a11y-anchor-has-content/warnings.json b/packages/svelte/tests/validator/samples/a11y-anchor-has-content/warnings.json
index cd3778a443..3d9adc1cde 100644
--- a/packages/svelte/tests/validator/samples/a11y-anchor-has-content/warnings.json
+++ b/packages/svelte/tests/validator/samples/a11y-anchor-has-content/warnings.json
@@ -1,7 +1,7 @@
[
{
"code": "a11y_consider_explicit_label",
- "message": "Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute",
+ "message": "Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute",
"start": {
"line": 1,
"column": 0
diff --git a/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/input.svelte b/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/input.svelte
index e97951065d..463889dc4f 100644
--- a/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/input.svelte
+++ b/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/input.svelte
@@ -4,6 +4,9 @@
+
+
+
diff --git a/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/warnings.json b/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/warnings.json
index 2dcecf08b3..bc29076184 100644
--- a/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/warnings.json
+++ b/packages/svelte/tests/validator/samples/a11y-consider-explicit-label/warnings.json
@@ -1,7 +1,7 @@
[
{
"code": "a11y_consider_explicit_label",
- "message": "Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute",
+ "message": "Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute",
"start": {
"line": 1,
"column": 0
@@ -13,7 +13,7 @@
},
{
"code": "a11y_consider_explicit_label",
- "message": "Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute",
+ "message": "Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute",
"start": {
"line": 2,
"column": 0
From e9cd45a2daf2de2a62077b1e68019e3cc6f658c8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 30 Sep 2025 17:55:29 +0200
Subject: [PATCH 22/80] Version Packages (#16848)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.changeset/clever-turtles-wink.md | 5 -----
.changeset/lemon-cars-count.md | 5 -----
.changeset/rude-terms-confess.md | 5 -----
.changeset/shiny-chicken-occur.md | 5 -----
.changeset/silly-walls-fail.md | 5 -----
packages/svelte/CHANGELOG.md | 14 ++++++++++++++
packages/svelte/package.json | 2 +-
packages/svelte/src/version.js | 2 +-
8 files changed, 16 insertions(+), 27 deletions(-)
delete mode 100644 .changeset/clever-turtles-wink.md
delete mode 100644 .changeset/lemon-cars-count.md
delete mode 100644 .changeset/rude-terms-confess.md
delete mode 100644 .changeset/shiny-chicken-occur.md
delete mode 100644 .changeset/silly-walls-fail.md
diff --git a/.changeset/clever-turtles-wink.md b/.changeset/clever-turtles-wink.md
deleted file mode 100644
index 6ff21f4d91..0000000000
--- a/.changeset/clever-turtles-wink.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-chore: simplify batch logic
diff --git a/.changeset/lemon-cars-count.md b/.changeset/lemon-cars-count.md
deleted file mode 100644
index 5724e48460..0000000000
--- a/.changeset/lemon-cars-count.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: rebase pending batches when other batches are committed
diff --git a/.changeset/rude-terms-confess.md b/.changeset/rude-terms-confess.md
deleted file mode 100644
index a24774952e..0000000000
--- a/.changeset/rude-terms-confess.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: wrap async `children` in `$$renderer.async`
diff --git a/.changeset/shiny-chicken-occur.md b/.changeset/shiny-chicken-occur.md
deleted file mode 100644
index 45a560480b..0000000000
--- a/.changeset/shiny-chicken-occur.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: silence label warning for buttons and anchor tags with title attributes
diff --git a/.changeset/silly-walls-fail.md b/.changeset/silly-walls-fail.md
deleted file mode 100644
index 6f364e7f8a..0000000000
--- a/.changeset/silly-walls-fail.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'svelte': patch
----
-
-fix: coerce nullish `` to empty string
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 83bd1d043f..58cc215e9d 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,19 @@
# svelte
+## 5.39.7
+
+### Patch Changes
+
+- chore: simplify batch logic ([#16847](https://github.com/sveltejs/svelte/pull/16847))
+
+- fix: rebase pending batches when other batches are committed ([#16866](https://github.com/sveltejs/svelte/pull/16866))
+
+- fix: wrap async `children` in `$$renderer.async` ([#16862](https://github.com/sveltejs/svelte/pull/16862))
+
+- fix: silence label warning for buttons and anchor tags with title attributes ([#16872](https://github.com/sveltejs/svelte/pull/16872))
+
+- fix: coerce nullish `` to empty string ([#16863](https://github.com/sveltejs/svelte/pull/16863))
+
## 5.39.6
### Patch Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 41a32f4a79..e5ed8c5aaf 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.39.6",
+ "version": "5.39.7",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index a0271de08b..aa515b600d 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.39.6';
+export const VERSION = '5.39.7';
export const PUBLIC_VERSION = '5';
From 31541c88496d58850656005eb58570ff85b1d9ef Mon Sep 17 00:00:00 2001
From: Yuki Ishii
Date: Wed, 1 Oct 2025 19:26:14 +0900
Subject: [PATCH 23/80] fix: allow await in svelte boundary without pending
(#16857)
Fix: #16856
---
.changeset/poor-flies-serve.md | 5 +++++
.../3-transform/server/visitors/SvelteBoundary.js | 13 +++++++++++--
.../samples/async-svelte-boundary/_expected.html | 1 +
.../samples/async-svelte-boundary/main.svelte | 4 ++++
4 files changed, 21 insertions(+), 2 deletions(-)
create mode 100644 .changeset/poor-flies-serve.md
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/_expected.html
create mode 100644 packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/main.svelte
diff --git a/.changeset/poor-flies-serve.md b/.changeset/poor-flies-serve.md
new file mode 100644
index 0000000000..1ac13a88ab
--- /dev/null
+++ b/.changeset/poor-flies-serve.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: allow await in svelte:boundary without pending
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js
index b914c96f4e..39e6912be0 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js
@@ -2,7 +2,13 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import * as b from '#compiler/builders';
-import { block_close, block_open, block_open_else, build_attribute_value } from './shared/utils.js';
+import {
+ block_close,
+ block_open,
+ block_open_else,
+ build_attribute_value,
+ create_async_block
+} from './shared/utils.js';
/**
* @param {AST.SvelteBoundary} node
@@ -37,6 +43,9 @@ export function SvelteBoundary(node, context) {
context.state.template.push(block_open_else, pending, block_close);
} else {
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
- context.state.template.push(block_open, block, block_close);
+ const statement = node.fragment.metadata.has_await
+ ? create_async_block(b.block([block]))
+ : block;
+ context.state.template.push(block_open, statement, block_close);
}
}
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/_expected.html b/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/_expected.html
new file mode 100644
index 0000000000..5be0be37f2
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/_expected.html
@@ -0,0 +1 @@
+this should work
\ No newline at end of file
diff --git a/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/main.svelte b/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/main.svelte
new file mode 100644
index 0000000000..c4cde60119
--- /dev/null
+++ b/packages/svelte/tests/server-side-rendering/samples/async-svelte-boundary/main.svelte
@@ -0,0 +1,4 @@
+
+ {@const x = await 'this should work'}
+ {x}
+
\ No newline at end of file
From 4f653ddceac466302b587830089c4cd5ffd7eff6 Mon Sep 17 00:00:00 2001
From: Yuki Ishii
Date: Thu, 2 Oct 2025 00:56:32 +0900
Subject: [PATCH 24/80] fix: update error message to clarify usage with radio
inputs (#16874)
* fix: update error message to clarify usage with radio inputs
* show an extra bind checked error when a radio type
* typo
* replace 'group' binding with , drive-by fix some other messages
---------
Co-authored-by: Rich Harris
---
.changeset/slow-nails-push.md | 5 +++++
documentation/docs/03-template-syntax/12-bind.md | 4 +++-
.../phases/2-analyze/visitors/BindDirective.js | 12 ++++++++----
.../dynamic-element-binding-invalid/_config.js | 2 +-
.../samples/binding-dimensions-svg/errors.json | 2 +-
.../samples/binding-input-checked/errors.json | 2 +-
.../binding-invalid-on-element-2/errors.json | 2 +-
.../samples/binding-invalid-on-element/errors.json | 2 +-
.../binding-radio-input-checked/errors.json | 14 ++++++++++++++
.../binding-radio-input-checked/input.svelte | 5 +++++
10 files changed, 40 insertions(+), 10 deletions(-)
create mode 100644 .changeset/slow-nails-push.md
create mode 100644 packages/svelte/tests/validator/samples/binding-radio-input-checked/errors.json
create mode 100644 packages/svelte/tests/validator/samples/binding-radio-input-checked/input.svelte
diff --git a/.changeset/slow-nails-push.md b/.changeset/slow-nails-push.md
new file mode 100644
index 0000000000..8dedf35593
--- /dev/null
+++ b/.changeset/slow-nails-push.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: update `bind:checked` error message to clarify usage with radio inputs
diff --git a/documentation/docs/03-template-syntax/12-bind.md b/documentation/docs/03-template-syntax/12-bind.md
index de57815687..c21ed35919 100644
--- a/documentation/docs/03-template-syntax/12-bind.md
+++ b/documentation/docs/03-template-syntax/12-bind.md
@@ -95,7 +95,7 @@ Since 5.6.0, if an ` ` has a `defaultValue` and is part of a form, it will
## ` `
-Checkbox and radio inputs can be bound with `bind:checked`:
+Checkbox inputs can be bound with `bind:checked`:
```svelte
@@ -117,6 +117,8 @@ Since 5.6.0, if an ` ` has a `defaultChecked` attribute and is part of a f
```
+> [!NOTE] Use `bind:group` for radio inputs instead of `bind:checked`.
+
## ` `
Checkboxes can be in an [indeterminate](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/indeterminate) state, independently of whether they are checked or unchecked:
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js
index 9f02e7fa5a..995d251a2e 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js
@@ -33,7 +33,7 @@ export function BindDirective(node, context) {
e.bind_invalid_target(
node,
node.name,
- property.valid_elements.map((valid_element) => `<${valid_element}>`).join(', ')
+ property.valid_elements.map((valid_element) => `\`<${valid_element}>\``).join(', ')
);
}
@@ -67,11 +67,15 @@ export function BindDirective(node, context) {
}
} else {
if (node.name === 'checked' && type?.value[0].data !== 'checkbox') {
- e.bind_invalid_target(node, node.name, ' ');
+ e.bind_invalid_target(
+ node,
+ node.name,
+ `\` \`${type?.value[0].data === 'radio' ? ` — for \` \`, use \`bind:group\`` : ''}`
+ );
}
if (node.name === 'files' && type?.value[0].data !== 'file') {
- e.bind_invalid_target(node, node.name, ' ');
+ e.bind_invalid_target(node, node.name, '` `');
}
}
}
@@ -94,7 +98,7 @@ export function BindDirective(node, context) {
e.bind_invalid_target(
node,
node.name,
- `non- elements. Use 'clientWidth' for instead`
+ `non-\`\` elements. Use \`bind:clientWidth\` for \`\` instead`
);
}
diff --git a/packages/svelte/tests/compiler-errors/samples/dynamic-element-binding-invalid/_config.js b/packages/svelte/tests/compiler-errors/samples/dynamic-element-binding-invalid/_config.js
index 4bb3edc27b..25b0827765 100644
--- a/packages/svelte/tests/compiler-errors/samples/dynamic-element-binding-invalid/_config.js
+++ b/packages/svelte/tests/compiler-errors/samples/dynamic-element-binding-invalid/_config.js
@@ -3,6 +3,6 @@ import { test } from '../../test';
export default test({
error: {
code: 'bind_invalid_target',
- message: '`bind:value` can only be used with ,