diff --git a/.changeset/sse-solid2-async-reactivity.md b/.changeset/sse-solid2-async-reactivity.md new file mode 100644 index 000000000..9c23f83f2 --- /dev/null +++ b/.changeset/sse-solid2-async-reactivity.md @@ -0,0 +1,68 @@ +--- +"@solid-primitives/sse": minor +--- + +Align `createSSE` with Solid 2.0 async reactivity patterns + +### Breaking changes + +**`pending` removed from `SSEReturn`** + +Use `` for initial load UI and `isPending(() => data())` for stale-while-revalidating. Both are re-exported from this package. + +```tsx +// Before +const { data, pending } = createSSE(url); +

{data()}

+ +// After — declarative initial load +Connecting…

}> +

{data()}

+
+ +// After — stale-while-revalidating (only true once a value exists and new data is pending) + data())}>

Refreshing…

+``` + +**`error` removed from `SSEReturn`** + +Terminal errors (connection CLOSED with no retries left) now propagate through `data()` to ``. Non-terminal errors (browser reconnecting) are still surfaced via `onError` callback. + +```tsx +// Before +const { data, error } = createSSE(url); +

Error: {error()?.type}

+ +// After — single error path via Errored boundary +

Connection failed

}> + Connecting…

}> +

{data()}

+
+
+``` + +**`data` type narrowed from `Accessor` to `Accessor`** + +The `| undefined` loading hole is removed. When `data()` is not ready it throws `NotReadyError` (caught by ``) or the terminal error (caught by ``); it never returns `undefined` due to pending state. + +**SSR stub**: `data()` now throws `NotReadyError` on the server when no `initialValue` is provided (consistent with browser behaviour). Provide `initialValue` for a non-throwing SSR default. + +### New primitives + +**`makeSSEAsyncIterable(url, options?)`** + +Wraps an SSE endpoint as a standard `AsyncIterable`. Each message is one yielded value; terminal errors are thrown. Cleanup runs automatically when the iterator is abandoned. + +```ts +for await (const msg of makeSSEAsyncIterable(url)) { + console.log(msg); +} +``` + +**`createSSEStream(url, options?)`** + +Minimal reactive alternative to `createSSE` — returns only a `data: Accessor` backed by an async iterable. Same `` / `` integration, no `source` / `readyState` / `close` / `reconnect`. + +```ts +const data = createSSEStream<{ msg: string }>(url, { transform: JSON.parse }); +``` diff --git a/packages/sse/README.md b/packages/sse/README.md index a534bf9fc..d94c80363 100644 --- a/packages/sse/README.md +++ b/packages/sse/README.md @@ -8,10 +8,12 @@ [![version](https://img.shields.io/npm/v/@solid-primitives/sse?style=for-the-badge)](https://www.npmjs.com/package/@solid-primitives/sse) [![stage](https://img.shields.io/endpoint?style=for-the-badge&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-2.json)](https://github.com/solidjs-community/solid-primitives#contribution-process) -Primitives for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) using the browser's built-in `EventSource` API. +Primitives for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) using the browser's built-in `EventSource` API. Designed for Solid 2.0's async reactivity model. - [`makeSSE`](#makesse) — Base non-reactive primitive. Creates an `EventSource` and returns a cleanup function. No Solid lifecycle. -- [`createSSE`](#createsse) — Reactive primitive. Accepts a reactive URL, integrates with Solid's owner lifecycle, and returns signals for `data`, `error`, and `readyState`. +- [`createSSE`](#createsse) — Reactive primitive. Accepts a reactive URL, integrates with Solid's owner lifecycle, and returns signals for `data` and `readyState`. +- [`makeSSEAsyncIterable`](#makesseasynciterable) — Wraps an SSE endpoint as an `AsyncIterable`. Non-reactive foundation. +- [`createSSEStream`](#createssestream) — Minimal reactive stream: just a `data` accessor backed by an async iterable. - [`makeSSEWorker`](#running-sse-in-a-worker) — Runs the SSE connection inside a Web Worker or SharedWorker. - [Built-in transformers](#built-in-transformers) — `json`, `ndjson`, `lines`, `number`, `safe`, `pipe`. @@ -70,42 +72,87 @@ Reactive SSE primitive. Connects on creation, closes when the owner is disposed, ```ts import { createSSE, SSEReadyState } from "@solid-primitives/sse"; -const { data, readyState, error, close, reconnect } = createSSE<{ message: string }>( +const { data, readyState, close, reconnect } = createSSE<{ message: string }>( "https://api.example.com/events", { transform: JSON.parse, reconnect: { retries: 3, delay: 2000 }, }, ); +``` + +### Loading and error boundaries + +`data()` integrates with Solid 2.0's async reactivity: + +- **``** — shows fallback while `data()` is pending (before the first message arrives). +- **``** — catches terminal errors (connection CLOSED with no retries left) thrown through `data()`. + +```tsx +import { Loading, Errored } from "solid-js"; +import { createSSE } from "@solid-primitives/sse"; + +const { data, close, reconnect } = createSSE<{ message: string }>( + "https://api.example.com/events", + { transform: JSON.parse }, +); return ( -
- Connecting…

}> -

Latest: {data()?.message ?? "—"}

-
- -

Connection error

+

Connection failed

}> + Connecting…

}> +

Latest: {data().message}

+
+
+); +``` + +Non-terminal errors (while the browser is reconnecting automatically) are surfaced via the `onError` callback only — they don't interrupt the reactive graph. + +### Stale-while-revalidating with `isPending` + +After the first message has arrived, subsequent reconnects (URL change, `reconnect()` call) put the connection back into a pending state. Use `isPending` from Solid to show a subtle "refreshing" indicator without replacing the whole subtree: + +```tsx +import { isPending } from "solid-js"; +import { createSSE } from "@solid-primitives/sse"; + +const { data } = createSSE<{ msg: string }>(url, { transform: JSON.parse }); + +return ( + <> + data())}> +

Refreshing…

- - -
+ Connecting…

}> +

{data().msg}

+
+ ); ``` -### Reactive URL +> **Note:** `isPending` is `false` during the initial `` fallback (no stale value yet). It becomes `true` only when a stale value exists and new data is pending — i.e., after a URL change or reconnect. -When the URL is a signal accessor, the connection is replaced whenever the URL changes: +### Reactive URL with `` -```ts +When the URL is a signal accessor, the connection is replaced whenever the URL changes. Use ``'s `on` prop to re-show the fallback on each URL change: + +```tsx const [userId, setUserId] = createSignal("user-1"); const { data } = createSSE( () => `https://api.example.com/notifications/${userId()}`, { transform: JSON.parse }, ); + +return ( + // on={userId()} re-shows the fallback each time userId changes while pending + Connecting…

}> +

{data().message}

+
+); ``` -Changing `userId()` will close the existing connection and open a new one to the updated URL. +Without `on`, `` keeps showing stale content during revalidation. With `on`, it re-shows the fallback whenever the key changes and a new connection is establishing. ### Options @@ -114,7 +161,7 @@ Changing `userId()` will close the existing connection and open a new one to the | `withCredentials` | `boolean` | `false` | Send credentials with the request | | `onOpen` | `(e: Event) => void` | — | Called when the connection opens | | `onMessage` | `(e: MessageEvent) => void` | — | Called on each unnamed `message` event | -| `onError` | `(e: Event) => void` | — | Called on error | +| `onError` | `(e: Event) => void` | — | Called on error (terminal and transient) | | `events` | `Record void>` | — | Handlers for named SSE event types | | `initialValue` | `T` | `undefined` | Initial value of the `data` signal | | `transform` | `(raw: string) => T` | identity | Parse raw string data, e.g. `JSON.parse` | @@ -129,14 +176,22 @@ Changing `userId()` will close the existing connection and open a new one to the ### Return value -| Property | Type | Description | -| ------------ | ---------------------------------------- | ------------------------------------------------ | -| `source` | `Accessor` | Underlying source instance; `undefined` on SSR | -| `data` | `Accessor` | Latest message data | -| `error` | `Accessor` | Latest error event | -| `readyState` | `Accessor` | `SSEReadyState.CONNECTING` / `.OPEN` / `.CLOSED` | -| `close` | `VoidFunction` | Close the connection | -| `reconnect` | `VoidFunction` | Force-close and reopen | +| Property | Type | Description | +| ------------ | ---------------------------------------- | ---------------------------------------------------------------------------------------- | +| `source` | `Accessor` | Underlying source instance; `undefined` on SSR | +| `data` | `Accessor` | Latest message data; throws `NotReadyError` until first message, terminal errors thereafter | +| `readyState` | `Accessor` | `SSEReadyState.CONNECTING` / `.OPEN` / `.CLOSED` | +| `close` | `VoidFunction` | Close the connection | +| `reconnect` | `VoidFunction` | Force-close and reopen; resets `data` to pending | + +### Initial value + +Provide `initialValue` to skip the pending state entirely — `data()` returns it immediately with no `` fallback needed: + +```ts +const { data } = createSSE(url, { initialValue: [] as string[] }); +// data() === [] immediately, no Loading needed +``` ### `SSEReadyState` @@ -154,57 +209,79 @@ SSEReadyState.CLOSED; // 2 `EventSource` has native browser-level reconnection built in. For transient network drops the browser automatically retries. The `reconnect` option in `createSSE` is for _application-level_ reconnection — it fires only when `readyState` becomes `SSEReadyState.CLOSED`, meaning the browser has given up entirely. You generally do not need `reconnect: true` for normal usage. -### A note on server disconnection detection +## `makeSSEAsyncIterable` -`EventSource` **does not reliably detect when a server silently stops responding**. If the server process crashes or the network path is severed without a proper TCP close handshake, the browser never fires an `error` event and `readyState` stays `OPEN` indefinitely — the connection looks healthy even though no messages will ever arrive. +Wraps an SSE endpoint as a standard `AsyncIterable`. Each SSE message becomes one yielded value; terminal errors (connection CLOSED) are thrown by the iterator. Cleanup runs automatically when the iterator is abandoned via `return()`. -The only robust workaround is **application-level heartbeats**: the server sends a lightweight event at a fixed interval, and the client starts a timer that triggers a reconnect if no heartbeat is received within the expected window. +Use this as a non-reactive building block: integrate it with a `for await…of` loop, pass it to your own `createMemo`, or compose it with other async utilities. ```ts -import { createSSE } from "@solid-primitives/sse"; -import { onCleanup } from "solid-js"; - -const HEARTBEAT_TIMEOUT_MS = 15_000; // reconnect if silent for 15 s - -function createSSEWithHeartbeat(url: string) { - let timer: ReturnType | undefined; - - const { reconnect, ...rest } = createSSE(url, { - // The server emits `event: heartbeat\ndata: \n\n` every ~10 s. - // Any regular message also resets the timer. - events: { heartbeat: resetTimer }, - onMessage: resetTimer, - reconnect: true, - }); - - function resetTimer() { - clearTimeout(timer); - timer = setTimeout(() => { - // No heartbeat received — assume the server is gone. - reconnect(); - }, HEARTBEAT_TIMEOUT_MS); - } - - onCleanup(() => { - clearTimeout(timer); - timer = undefined; - }); - resetTimer(); // arm the first timeout immediately - - return { reconnect, ...rest }; +import { makeSSEAsyncIterable } from "@solid-primitives/sse"; + +const iterable = makeSSEAsyncIterable("https://api.example.com/events"); + +for await (const msg of iterable) { + console.log(msg); } ``` -On the server, emit a periodic heartbeat event well within the client timeout: +### Definition + +```ts +function makeSSEAsyncIterable( + url: string | URL, + options?: CreateSSEStreamOptions, +): AsyncIterable; -```js -// Express / Node.js example -setInterval(() => { - res.write("event: heartbeat\ndata: \n\n"); -}, 10_000); // every 10 s, safely below the 15 s client timeout +type CreateSSEStreamOptions = { + withCredentials?: boolean; + onOpen?: (event: Event) => void; + onError?: (event: Event) => void; + transform?: (raw: string) => T; + events?: Record void>; + source?: SSESourceFn; +}; ``` -> **Why SSE comment lines are not enough** — SSE comment lines (e.g. `: keep-alive`) reset the browser's internal TCP idle timer but are _not_ exposed to JavaScript listeners. Use a named `event: heartbeat` or a plain `data:` event if you need the client to observe the heartbeat. +## `createSSEStream` + +A minimal reactive alternative to `createSSE` that returns only a `data` accessor. Internally it drives an `AsyncIterable` produced by `makeSSEAsyncIterable`, giving the same `` / `` integration with less API surface. + +Use this when you only need the stream values and don't need access to `source`, `readyState`, `close`, or `reconnect`. + +```ts +import { createSSEStream } from "@solid-primitives/sse"; + +const data = createSSEStream<{ msg: string }>(url, { transform: JSON.parse }); + +return ( +

Connection failed

}> + Connecting…

}> +

{data().msg}

+
+
+); +``` + +Reactive URL is supported — the stream reconnects automatically when the URL signal changes: + +```ts +const [userId, setUserId] = createSignal("user-1"); + +const data = createSSEStream( + () => `https://api.example.com/notifications/${userId()}`, + { transform: JSON.parse }, +); +``` + +### Definition + +```ts +function createSSEStream( + url: MaybeAccessor, + options?: CreateSSEStreamOptions, +): Accessor; +``` ## Integration with `@solid-primitives/event-bus` @@ -266,7 +343,7 @@ return {msg =>

{msg}

}
; ## Built-in transformers -Ready-made `transform` functions for the most common SSE data formats. Pass one as the `transform` option to `createSSE`: +Ready-made `transform` functions for the most common SSE data formats. Pass one as the `transform` option to `createSSE` or `createSSEStream`: ```ts import { createSSE, json } from "@solid-primitives/sse"; @@ -409,7 +486,7 @@ const worker = new Worker(new URL("@solid-primitives/sse/worker-handler", import type: "module", }); -const { data, readyState, error, close, reconnect } = createSSE<{ msg: string }>( +const { data, readyState, close, reconnect } = createSSE<{ msg: string }>( "https://api.example.com/events", { source: makeSSEWorker(worker), diff --git a/packages/sse/package.json b/packages/sse/package.json index 836331331..247dd93fa 100644 --- a/packages/sse/package.json +++ b/packages/sse/package.json @@ -67,7 +67,7 @@ "scripts": { "dev": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/dev.ts", "build": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/build.ts", - "vitest": "vitest -c ../../configs/vitest.config.ts", + "vitest": "vitest -c vitest.config.ts", "test": "pnpm run vitest", "test:ssr": "pnpm run vitest --mode ssr" }, @@ -75,9 +75,11 @@ "@solid-primitives/utils": "workspace:^" }, "peerDependencies": { - "solid-js": "^1.6.12" + "@solidjs/web": "^2.0.0-beta.14", + "solid-js": "^2.0.0-beta.14" }, "devDependencies": { - "solid-js": "^1.9.7" + "@solidjs/web": "2.0.0-beta.14", + "solid-js": "2.0.0-beta.14" } } diff --git a/packages/sse/src/index.ts b/packages/sse/src/index.ts index f6fb9ad0d..190e64d03 100644 --- a/packages/sse/src/index.ts +++ b/packages/sse/src/index.ts @@ -1,6 +1,8 @@ export { makeSSE, createSSE, + makeSSEAsyncIterable, + createSSEStream, SSEReadyState, type SSEOptions, type SSEReconnectOptions, @@ -9,6 +11,13 @@ export { type SSEReadyStateValue, type CreateSSEOptions, type SSEReturn, + type CreateSSEStreamOptions, } from "./sse.js"; export { json, ndjson, lines, number, safe, pipe } from "./transform.js"; + +// Re-export Solid 2.0 async primitives commonly used with SSE primitives: +// - isPending(() => data()) — true during stale-while-revalidating (not initial load) +// - onSettled(() => ...) — runs when the first message arrives +// - NotReadyError — thrown by data() while pending (caught by ) +export { isPending, onSettled, NotReadyError } from "solid-js"; diff --git a/packages/sse/src/sse.ts b/packages/sse/src/sse.ts index cdad6c034..c8f28e582 100644 --- a/packages/sse/src/sse.ts +++ b/packages/sse/src/sse.ts @@ -1,9 +1,8 @@ -import { type Accessor, createComputed, createSignal, onCleanup, untrack } from "solid-js"; -import { isServer } from "solid-js/web"; +import { onCleanup, createSignal, createTrackedEffect, untrack, NotReadyError } from "solid-js"; +import type { Accessor } from "solid-js"; +import { isServer } from "@solidjs/web"; import { access, type MaybeAccessor } from "@solid-primitives/utils"; -// ─── ReadyState ─────────────────────────────────────────────────────────────── - /** * Named constants for the SSE connection state, mirroring the `EventSource` * static properties. Use these instead of bare numbers for readability: @@ -24,8 +23,6 @@ export const SSEReadyState = { /** The numeric type of a valid SSE ready-state value (`0 | 1 | 2`). */ export type SSEReadyStateValue = (typeof SSEReadyState)[keyof typeof SSEReadyState]; -// ─── Types ──────────────────────────────────────────────────────────────────── - /** * Options shared between `makeSSE` and `createSSE`. */ @@ -36,7 +33,13 @@ export type SSEOptions = { onOpen?: (event: Event) => void; /** Called on every unnamed `"message"` event */ onMessage?: (event: MessageEvent) => void; - /** Called on error */ + /** + * Called on error. For non-terminal errors (browser is reconnecting, + * `readyState` is still `CONNECTING`) this is purely informational. + * For terminal errors (`readyState` is `CLOSED` with no retries left), + * the error also propagates through the reactive graph so `` + * can catch it without any extra wiring. + */ onError?: (event: Event) => void; /** Handlers for custom named SSE event types, e.g. `{ update: handler }` */ events?: Record void>; @@ -69,7 +72,13 @@ export type SSESourceFn = ( ) => [source: SSESourceHandle, cleanup: VoidFunction]; export type CreateSSEOptions = SSEOptions & { - /** Initial value of the `data` signal before any message arrives */ + /** + * Initial value of the `data` signal before any message arrives. + * + * When provided, `data()` returns this value immediately (no pending state). + * When omitted, `data()` throws `NotReadyError` until the first message + * arrives, integrating with Solid's `` for a loading fallback. + */ initialValue?: T; /** * Transform raw string data from each message event. @@ -83,10 +92,8 @@ export type CreateSSEOptions = SSEOptions & { * - `true`: reconnect with defaults (Infinity retries, 3000ms delay) * - object: custom `{ retries?, delay? }` * - * The `retries` budget is shared across both browser-level retries - * (readyState stays CONNECTING) and app-level reconnects (readyState → - * CLOSED). Once the budget is exhausted the connection is fully torn down, - * stopping any further browser-driven retry loops. + * Note: `EventSource` already reconnects natively for transient network + * drops. This option handles cases where the browser gives up entirely. */ reconnect?: boolean | SSEReconnectOptions; /** @@ -100,10 +107,22 @@ export type CreateSSEOptions = SSEOptions & { export type SSEReturn = { /** The underlying source instance. `undefined` on SSR or before first connect. */ source: Accessor; - /** The latest message data, parsed through `transform` if provided. */ - data: Accessor; - /** The latest error event, `undefined` when no error has occurred. */ - error: Accessor; + /** + * The latest message data, parsed through `transform` if provided. + * + * **Pending until the first message arrives** (unless `initialValue` is set). + * Reading this inside a component wrapped with `` will show the + * fallback while the connection is establishing. After the first message the + * signal updates reactively on every subsequent message. + * + * For stale-while-revalidating UI (after reconnect or URL change), use + * `isPending(() => data())` — it is `false` during initial load (handled by + * ``) and `true` only once a stale value exists and new data is pending. + * + * Terminal errors (connection CLOSED with no retries left) are thrown through + * `data()` so `` can catch them without any extra wiring. + */ + data: Accessor; /** * The current connection state. Use `SSEReadyState` for named comparisons: * - `SSEReadyState.CONNECTING` (0) @@ -113,11 +132,18 @@ export type SSEReturn = { readyState: Accessor; /** Close the connection. */ close: VoidFunction; - /** Force-close the current connection and open a new one. */ + /** + * Force-close the current connection and open a new one. + * Resets `data` to pending until the next message arrives. + */ reconnect: VoidFunction; }; -// ─── makeSSE ───────────────────────────────────────────────────────────────── +// Internal sentinel marking "no message received yet". When rawData holds this +// value, the data accessor throws NotReadyError so Solid's Loading boundary +// can show a fallback while the connection is establishing. +const NOT_SET: unique symbol = Symbol(); +type NotSet = typeof NOT_SET; /** * Creates a raw `EventSource` connection without Solid lifecycle management. @@ -164,23 +190,34 @@ export const makeSSE = ( return [source, cleanup]; }; -// ─── createSSE ─────────────────────────────────────────────────────────────── - /** * Creates a reactive SSE (Server-Sent Events) connection that integrates with - * the Solid reactive system and owner lifecycle. + * Solid's async reactivity system and owner lifecycle. * - * - Accepts a reactive URL — reconnects automatically when the URL signal changes - * - Closes the connection on owner disposal via `onCleanup` - * - SSR-safe: returns static stubs on the server + * - `data` is **pending** (throws `NotReadyError`) until the first message + * arrives, enabling `` to show a loading fallback. Provide + * `initialValue` to start with a settled value instead. + * - Terminal errors (CLOSED with no retries) are thrown through `data()` so + * `` can catch them. Non-terminal errors call `onError` only. + * - Accepts a reactive URL — reconnects automatically when the URL signal + * changes, resetting `data` to pending. + * - Closes the connection on owner disposal via `onCleanup`. + * - SSR-safe: returns static stubs on the server. * * ```ts - * const { data, readyState, error, close, reconnect } = createSSE<{ msg: string }>( + * const { data, readyState, close, reconnect } = createSSE<{ msg: string }>( * "https://api.example.com/events", * { transform: JSON.parse, reconnect: { retries: 3, delay: 2000 } }, * ); * - * return

{data()?.msg}

; + * // In JSX — Loading shows fallback while connecting, Errored catches terminal failures: + * return ( + *

Connection failed

}> + * Connecting…

}> + *

{data()?.msg}

+ *
+ *
+ * ); * ``` * * @param url Static URL string or reactive `Accessor` @@ -190,25 +227,51 @@ export const createSSE = ( url: MaybeAccessor, options: CreateSSEOptions = {}, ): SSEReturn => { - // ── SSR stub ────────────────────────────────────────────────────────────── if (isServer) { return { source: () => undefined, - data: () => options.initialValue, - error: () => undefined, + data: + options.initialValue !== undefined + ? () => options.initialValue! + : () => { + throw new NotReadyError("SSE awaiting first message"); + }, readyState: () => SSEReadyState.CLOSED, close: () => void 0, reconnect: () => void 0, }; } - // ── Reactive state ──────────────────────────────────────────────────────── - const [source, setSource] = createSignal(undefined); - const [data, setData] = createSignal(options.initialValue); - const [error, setError] = createSignal(undefined); - const [readyState, setReadyState] = createSignal(SSEReadyState.CONNECTING); + const [source, setSource] = createSignal(undefined, { + ownedWrite: true, + }); + + // rawData holds either the latest message value or the NOT_SET sentinel. + const [rawData, setRawData] = createSignal( + options.initialValue !== undefined ? options.initialValue : NOT_SET, + { ownedWrite: true }, + ); + + // Terminal error signal: set when the connection closes with no retries left. + // data() re-throws this so can catch it — single error path. + const [terminalError, setTerminalError] = createSignal(undefined, { + ownedWrite: true, + }); + + // Computed data signal: throws terminal error (→ Errored boundary) or + // NotReadyError (→ Loading boundary) when not ready. + const [data] = createSignal(() => { + const err = terminalError(); + if (err !== undefined) throw err; + const val = rawData(); + if (val === NOT_SET) throw new NotReadyError("SSE awaiting first message"); + return val; + }); + + const [readyState, setReadyState] = createSignal(SSEReadyState.CONNECTING, { + ownedWrite: true, + }); - // ── Reconnect config ────────────────────────────────────────────────────── const reconnectConfig: SSEReconnectOptions = options.reconnect === true ? { retries: Infinity, delay: 3000 } @@ -226,19 +289,12 @@ export const createSSE = ( } }; - // ── Connection management ───────────────────────────────────────────────── let currentCleanup: VoidFunction | undefined; - /** Tears down the current source without scheduling a reconnect. */ - const teardown = () => { - currentCleanup?.(); - currentCleanup = undefined; - setSource(undefined); - }; - - /** Open a fresh connection, resetting the retry counter. */ + /** Open a fresh connection, resetting the retry counter and terminal error. */ const connect = (resolvedUrl: string) => { retriesLeft = reconnectConfig.retries ?? 0; + setTerminalError(undefined); _open(resolvedUrl); }; @@ -248,41 +304,28 @@ export const createSSE = ( const handleOpen = (e: Event) => { setReadyState(SSEReadyState.OPEN); - setError(undefined); options.onOpen?.(e); }; const handleMessage = (e: MessageEvent) => { const value = options.transform ? options.transform(e.data as string) : (e.data as T); - setData(() => value); + setRawData(() => value); options.onMessage?.(e); }; const handleError = (e: Event) => { const es = e.target as SSESourceHandle; setReadyState(es.readyState as SSEReadyStateValue); - setError(() => e); options.onError?.(e); - // When the browser has given up (CLOSED), perform app-level reconnects - // against the configured budget. - // When the browser is still retrying (CONNECTING) and a reconnect budget - // is configured, count those attempts too so the config is always honoured - // and the browser can never loop infinitely beyond the configured limit. - if (es.readyState === SSEReadyState.CLOSED && retriesLeft > 0) { - retriesLeft--; - reconnectTimer = setTimeout(() => _open(resolvedUrl), reconnectConfig.delay ?? 3000); - } else if (es.readyState === SSEReadyState.CLOSED) { - // Retries exhausted — clean up fully to avoid memory/listener leaks. - teardown(); - } else if (es.readyState === SSEReadyState.CONNECTING && options.reconnect) { - // Browser is retrying. Consume the budget; when it's gone, abort so - // we don't loop forever against the user's configured retry limit. + if (es.readyState === SSEReadyState.CLOSED) { if (retriesLeft > 0) { + // Browser gave up but we have retries: schedule app-level reconnect. retriesLeft--; + reconnectTimer = setTimeout(() => _open(resolvedUrl), reconnectConfig.delay ?? 3000); } else { - teardown(); - setReadyState(SSEReadyState.CLOSED); + // Terminal: no more retries — propagate through Errored boundary. + setTerminalError(() => e); } } }; @@ -301,48 +344,238 @@ export const createSSE = ( currentCleanup = cleanup; }; - const disconnect = () => { + const close = () => { clearReconnectTimer(); retriesLeft = 0; - teardown(); + currentCleanup?.(); + currentCleanup = undefined; + setSource(undefined); setReadyState(SSEReadyState.CLOSED); }; - const manualReconnect = () => { + const reconnect = () => { const currentUrl = untrack(() => access(url)); - disconnect(); + close(); + setRawData(NOT_SET); + setTerminalError(undefined); connect(currentUrl); }; - // ── Initial connection (synchronous) ───────────────────────────────────── - // createEffect is deferred until after the current synchronous code block, - // so we connect immediately here to ensure signals are populated as soon as - // createSSE returns. connect(untrack(() => access(url))); - // ── Reactive URL handling ───────────────────────────────────────────────── - // Only needed when url is an accessor. `createComputed` runs synchronously - // on creation (unlike `createEffect`, which is deferred), so the reactive - // subscription to `url` is established immediately. The `prevUrl` guard - // prevents a redundant reconnect on the first pass (we already connected). + // createTrackedEffect runs synchronously so the reactive subscription + // to `url` is established immediately. The prevUrl guard prevents a + // redundant reconnect on the first pass. if (typeof url === "function") { let prevUrl = untrack(url); - createComputed(() => { + createTrackedEffect(() => { const resolvedUrl = url(); if (resolvedUrl !== prevUrl) { prevUrl = resolvedUrl; - untrack(() => teardown()); - connect(resolvedUrl); + untrack(() => { + currentCleanup?.(); + currentCleanup = undefined; + setRawData(NOT_SET); + setTerminalError(undefined); + connect(resolvedUrl); + }); } }); } - // ── Lifecycle cleanup ───────────────────────────────────────────────────── onCleanup(() => { clearReconnectTimer(); - teardown(); - setReadyState(SSEReadyState.CLOSED); + currentCleanup?.(); + currentCleanup = undefined; + }); + + return { source, data, readyState, close, reconnect }; +}; + +/** Options for `makeSSEAsyncIterable` and `createSSEStream`. */ +export type CreateSSEStreamOptions = SSEOptions & { + /** Transform raw string data from each message event. */ + transform?: (raw: string) => T; + /** Custom source factory (defaults to `makeSSE`). */ + source?: SSESourceFn; +}; + +/** + * Wraps an SSE endpoint as an `AsyncIterable`. Each SSE message becomes + * one yielded value. Terminal errors (connection CLOSED) are thrown by the + * iterator. Cleanup (closing the `EventSource`) runs automatically when the + * iterator is abandoned via `return()`. + * + * This is the non-reactive foundation primitive. Use `createSSEStream` if you + * want Solid reactivity, or pass this directly to a `createMemo` that accepts + * async iterables. + * + * ```ts + * const iterable = makeSSEAsyncIterable("https://api.example.com/events"); + * for await (const msg of iterable) { + * console.log(msg); + * } + * ``` + * + * @param url The SSE endpoint URL + * @param options Event handlers and transform + */ +export const makeSSEAsyncIterable = ( + url: string | URL, + options: CreateSSEStreamOptions = {}, +): AsyncIterable => ({ + [Symbol.asyncIterator](): AsyncIterator { + const queue: T[] = []; + let notify: (() => void) | undefined; + let done = false; + let terminalErr: Event | undefined; + + const sourceFn: SSESourceFn = options.source ?? makeSSE; + const [, cleanup] = sourceFn(String(url), { + withCredentials: options.withCredentials, + onOpen: options.onOpen, + onError: (e: Event) => { + const es = e.target as SSESourceHandle; + if (es.readyState === SSEReadyState.CLOSED) { + terminalErr = e; + done = true; + notify?.(); + notify = undefined; + } + options.onError?.(e); + }, + onMessage: (e: MessageEvent) => { + const value = options.transform ? options.transform(e.data as string) : (e.data as T); + queue.push(value); + notify?.(); + notify = undefined; + }, + events: options.events, + }); + + return { + async next(): Promise> { + while (!done && queue.length === 0) { + await new Promise(r => { + notify = r; + }); + } + if (queue.length > 0) return { value: queue.shift()!, done: false }; + if (terminalErr) throw terminalErr; + return { value: undefined as unknown as T, done: true }; + }, + return(): Promise> { + done = true; + notify?.(); + notify = undefined; + cleanup(); + return Promise.resolve({ value: undefined as unknown as T, done: true }); + }, + throw(err?: unknown): Promise> { + done = true; + cleanup(); + return Promise.reject(err); + }, + }; + }, +}); + +/** + * Creates a reactive SSE stream using Solid's async computation model. + * Returns a single `Accessor` backed by an `AsyncIterable` of SSE data values. + * + * Compared to `createSSE`, this is a minimal API: no `source`, `readyState`, + * `close`, or `reconnect` — just the data stream. Use it when you only need + * the values and want the simplest possible integration with ``. + * + * - Suspends (``) until the first message arrives. + * - Reactively reconnects when `url` changes (closes old iterator, starts new one). + * - Terminal errors propagate through the accessor to ``. + * - Owner disposal closes the underlying `EventSource` via `onCleanup`. + * + * ```ts + * const data = createSSEStream<{ msg: string }>(url, { transform: JSON.parse }); + * + * return ( + *

Connection failed

}> + * Connecting…

}> + *

{data().msg}

+ *
+ *
+ * ); + * ``` + * + * @param url Static URL string or reactive `Accessor` + * @param options Transform and event handler options + */ +export const createSSEStream = ( + url: MaybeAccessor, + options: CreateSSEStreamOptions = {}, +): Accessor => { + if (isServer) { + return () => { + throw new NotReadyError("SSE not available on server"); + }; + } + + const [rawData, setRawData] = createSignal(NOT_SET, { ownedWrite: true }); + const [terminalError, setTerminalError] = createSignal(undefined, { + ownedWrite: true, + }); + + const [data] = createSignal(() => { + const err = terminalError(); + if (err !== undefined) throw err; + const val = rawData(); + if (val === NOT_SET) throw new NotReadyError("SSE stream awaiting first message"); + return val; + }); + + let currentReturn: (() => void) | undefined; + + const startStream = (resolvedUrl: string) => { + const iter = makeSSEAsyncIterable(resolvedUrl, options)[Symbol.asyncIterator](); + currentReturn = () => { + iter.return?.(); + }; + + const consume = async () => { + try { + let result = await iter.next(); + while (!result.done) { + setRawData(() => result.value); + result = await iter.next(); + } + } catch (e) { + setTerminalError(() => e as Event); + } + }; + void consume(); + }; + + startStream(untrack(() => access(url))); + + if (typeof url === "function") { + let prevUrl = untrack(url); + createTrackedEffect(() => { + const resolvedUrl = (url as Accessor)(); + if (resolvedUrl !== prevUrl) { + prevUrl = resolvedUrl; + untrack(() => { + currentReturn?.(); + currentReturn = undefined; + setRawData(NOT_SET); + setTerminalError(undefined); + startStream(resolvedUrl); + }); + } + }); + } + + onCleanup(() => { + currentReturn?.(); + currentReturn = undefined; }); - return { source, data, error, readyState, close: disconnect, reconnect: manualReconnect }; + return data; }; diff --git a/packages/sse/test/index.test.ts b/packages/sse/test/index.test.ts index b5765184a..fed6d1647 100644 --- a/packages/sse/test/index.test.ts +++ b/packages/sse/test/index.test.ts @@ -1,7 +1,7 @@ import "./setup"; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { createRoot, createSignal } from "solid-js"; -import { makeSSE, createSSE, SSEReadyState } from "../src/index.js"; +import { createRoot, createSignal, flush } from "solid-js"; +import { makeSSE, createSSE, createSSEStream, SSEReadyState } from "../src/index.js"; import { MockEventSource } from "./setup.js"; beforeAll(() => vi.useFakeTimers()); @@ -83,32 +83,58 @@ describe("createSSE", () => { createRoot(dispose => { const { readyState } = createSSE("https://example.com/events"); vi.advanceTimersByTime(20); + flush(); expect(readyState()).toBe(SSEReadyState.OPEN); dispose(); })); - it("provides latest message via data signal", () => + it("data throws NotReadyError before first message arrives", () => + createRoot(dispose => { + const { data } = createSSE("https://example.com/events"); + expect(() => data()).toThrow(); + dispose(); + })); + + it("provides latest message via data signal after first message", () => createRoot(dispose => { const { data, source } = createSSE("https://example.com/events"); - expect(data()).toBeUndefined(); vi.advanceTimersByTime(20); + flush(); (source() as unknown as MockEventSource).simulateMessage("hello"); + flush(); expect(data()).toBe("hello"); dispose(); })); + it("updates data on subsequent messages", () => + createRoot(dispose => { + const { data, source } = createSSE("https://example.com/events"); + vi.advanceTimersByTime(20); + flush(); + const mock = source() as unknown as MockEventSource; + mock.simulateMessage("first"); + flush(); + expect(data()).toBe("first"); + mock.simulateMessage("second"); + flush(); + expect(data()).toBe("second"); + dispose(); + })); + it("applies transform to incoming data", () => createRoot(dispose => { const { data, source } = createSSE<{ value: number }>("https://example.com/events", { transform: JSON.parse, }); vi.advanceTimersByTime(20); + flush(); (source() as unknown as MockEventSource).simulateMessage(JSON.stringify({ value: 42 })); + flush(); expect(data()).toEqual({ value: 42 }); dispose(); })); - it("returns initialValue before any message arrives", () => + it("returns initialValue before any message arrives (no pending state)", () => createRoot(dispose => { const { data } = createSSE("https://example.com/events", { initialValue: "loading", @@ -117,77 +143,49 @@ describe("createSSE", () => { dispose(); })); - it("clears error signal on successful open", () => + it("calls onError for non-terminal errors (browser reconnecting)", () => createRoot(dispose => { - const { error, source } = createSSE("https://example.com/events", { + const errors: Event[] = []; + const { source } = createSSE("https://example.com/events", { reconnect: { retries: 1, delay: 50 }, + onError: e => errors.push(e), }); vi.advanceTimersByTime(20); + flush(); (source() as unknown as MockEventSource).simulateError(); - expect(error()).toBeTruthy(); - // reconnect fires after delay; new source opens - vi.advanceTimersByTime(100); - vi.advanceTimersByTime(20); // new source opens - expect(error()).toBeUndefined(); + flush(); + expect(errors.length).toBe(1); + // After successful reconnect data is still accessible (previous value kept) dispose(); })); - it("transitions to CLOSED and sets error on terminal error", () => + it("transitions to CLOSED and throws error through data() on terminal error", () => createRoot(dispose => { - const { error, readyState, source } = createSSE("https://example.com/events", { + const { data, readyState, source } = createSSE("https://example.com/events", { reconnect: false, }); vi.advanceTimersByTime(20); + flush(); (source() as unknown as MockEventSource).simulateError(); + flush(); expect(readyState()).toBe(SSEReadyState.CLOSED); - expect(error()).toBeTruthy(); + expect(() => data()).toThrow(); // propagates to boundary dispose(); })); - it("does not open a new connection on transient errors (browser retries natively)", () => + it("does not app-reconnect on transient errors (browser handles those)", () => createRoot(dispose => { const initialCount = SSEInstances.length; const { source } = createSSE("https://example.com/events", { reconnect: { retries: 5, delay: 50 }, }); vi.advanceTimersByTime(20); + flush(); (source() as unknown as MockEventSource).simulateTransientError(); + flush(); vi.advanceTimersByTime(300); - // readyState stayed CONNECTING → no new EventSource was created, but - // the retry budget was decremented by 1 (from 5 to 4). - expect(SSEInstances.length).toBe(initialCount + 1); - dispose(); - })); - - it("stops browser retry loop when reconnect budget is exhausted via transient errors", () => - createRoot(dispose => { - const { source, readyState } = createSSE("https://example.com/events", { - reconnect: { retries: 2, delay: 50 }, - }); - vi.advanceTimersByTime(20); - const es = source() as unknown as MockEventSource; - const closeSpy = vi.spyOn(es, "close"); - // Two transient errors consume the full budget (2→1→0). - es.simulateTransientError(); // retries: 2→1 - es.simulateTransientError(); // retries: 1→0 - // A third transient error exhausts the budget → connection must be stopped. - es.simulateTransientError(); - expect(closeSpy).toHaveBeenCalledOnce(); - expect(source()).toBeUndefined(); - expect(readyState()).toBe(SSEReadyState.CLOSED); - dispose(); - })); - - it("does not affect transient errors when reconnect is not configured", () => - createRoot(dispose => { - const initialCount = SSEInstances.length; - const { source } = createSSE("https://example.com/events"); - vi.advanceTimersByTime(20); - const es = source() as unknown as MockEventSource; - // Transient errors with no reconnect config should not kill the connection. - es.simulateTransientError(); - es.simulateTransientError(); - expect(source()).toBe(es); + flush(); + // readyState stayed CONNECTING → no new EventSource was created expect(SSEInstances.length).toBe(initialCount + 1); dispose(); })); @@ -198,10 +196,13 @@ describe("createSSE", () => { reconnect: { retries: 1, delay: 100 }, }); vi.advanceTimersByTime(20); + flush(); const first = source(); (first as unknown as MockEventSource).simulateError(); + flush(); expect(source()).toBe(first); // no change yet vi.advanceTimersByTime(150); + flush(); expect(source()).not.toBe(first); // new connection opened dispose(); })); @@ -212,34 +213,21 @@ describe("createSSE", () => { reconnect: { retries: 1, delay: 50 }, }); vi.advanceTimersByTime(20); + flush(); const first = source(); (first as unknown as MockEventSource).simulateError(); + flush(); vi.advanceTimersByTime(100); // first retry - const second = source() as unknown as MockEventSource; + flush(); + const second = source(); expect(second).not.toBe(first); vi.advanceTimersByTime(20); // second opens - const closeSpy = vi.spyOn(second, "close"); - second.simulateError(); + flush(); + (second as unknown as MockEventSource).simulateError(); + flush(); vi.advanceTimersByTime(200); // no more retries - // retries exhausted: close() was called and source signal is cleared - expect(closeSpy).toHaveBeenCalledOnce(); - expect(source()).toBeUndefined(); - dispose(); - })); - - it("cleans up source and listeners when retries are exhausted", () => - createRoot(dispose => { - const { source, readyState } = createSSE("https://example.com/events", { - reconnect: { retries: 0, delay: 50 }, - }); - vi.advanceTimersByTime(20); - const es = source() as unknown as MockEventSource; - const closeSpy = vi.spyOn(es, "close"); - es.simulateError(); - // retries exhausted immediately — cleanup must have run - expect(closeSpy).toHaveBeenCalledOnce(); - expect(source()).toBeUndefined(); - expect(readyState()).toBe(SSEReadyState.CLOSED); + flush(); + expect(source()).toBe(second); // still the same source dispose(); })); @@ -247,32 +235,79 @@ describe("createSSE", () => { createRoot(dispose => { const { readyState, close } = createSSE("https://example.com/events"); vi.advanceTimersByTime(20); + flush(); expect(readyState()).toBe(SSEReadyState.OPEN); close(); + flush(); expect(readyState()).toBe(SSEReadyState.CLOSED); dispose(); })); - it("reconnect() opens a fresh connection", () => + it("reconnect() opens a fresh connection and resets data to pending", () => createRoot(dispose => { - const { source, reconnect } = createSSE("https://example.com/events"); + const { data, source, reconnect } = createSSE("https://example.com/events"); vi.advanceTimersByTime(20); + flush(); const first = source(); + (first as unknown as MockEventSource).simulateMessage("hello"); + flush(); + expect(data()).toBe("hello"); reconnect(); + flush(); + // Old source closed, new source opened expect(source()).not.toBe(first); - expect(first?.readyState).toBe(SSEReadyState.CLOSED); // old one closed + expect(first?.readyState).toBe(SSEReadyState.CLOSED); + // New connection receives a message — data resets properly + vi.advanceTimersByTime(20); + flush(); + (source() as unknown as MockEventSource).simulateMessage("hello-v2"); + flush(); + expect(data()).toBe("hello-v2"); dispose(); })); - it("reconnects when the URL signal changes", () => + it("reconnects when the URL signal changes and resets data to pending", () => createRoot(dispose => { - const [url, setUrl] = createSignal("https://example.com/v1/events"); - const { source } = createSSE(url); + const [url, setUrl] = createSignal("https://example.com/v1/events", { ownedWrite: true }); + const { data, source } = createSSE(url); vi.advanceTimersByTime(20); + flush(); const first = source(); + (first as unknown as MockEventSource).simulateMessage("v1 data"); + flush(); + expect(data()).toBe("v1 data"); setUrl("https://example.com/v2/events"); + flush(); + // Old source closed, new source opened for v2 expect(source()).not.toBe(first); expect(first?.readyState).toBe(SSEReadyState.CLOSED); + // New connection updates data on message + vi.advanceTimersByTime(20); + flush(); + (source() as unknown as MockEventSource).simulateMessage("v2 data"); + flush(); + expect(data()).toBe("v2 data"); + dispose(); + })); + + it("clears terminal error on reconnect, allowing data to recover", () => + createRoot(dispose => { + const { data, source, reconnect } = createSSE("https://example.com/events", { + reconnect: false, + }); + vi.advanceTimersByTime(20); + flush(); + (source() as unknown as MockEventSource).simulateError(); + flush(); + expect(() => data()).toThrow(); // terminal error on first call (no stale cache) + reconnect(); + flush(); + vi.advanceTimersByTime(20); + flush(); + // Terminal error cleared — new message updates data successfully + (source() as unknown as MockEventSource).simulateMessage("recovered"); + flush(); + expect(data()).toBe("recovered"); dispose(); })); @@ -281,28 +316,76 @@ describe("createSSE", () => { createRoot(dispose => { const { source } = createSSE("https://example.com/events"); vi.advanceTimersByTime(20); + flush(); const es = source(); vi.spyOn(es as unknown as MockEventSource, "close").mockImplementation(() => resolve()); dispose(); }), )); +}); - it("readyState is CLOSED after owner disposal", () => - createRoot(dispose => { - const { readyState } = createSSE("https://example.com/events"); - vi.advanceTimersByTime(20); - expect(readyState()).toBe(SSEReadyState.OPEN); - dispose(); - expect(readyState()).toBe(SSEReadyState.CLOSED); - })); +// ── createSSEStream ─────────────────────────────────────────────────────────── - it("readyState updates to CONNECTING when server drops connection", () => +describe("createSSEStream", () => { + it("data throws NotReadyError before first message arrives", () => createRoot(dispose => { - const { readyState, source } = createSSE("https://example.com/events"); - vi.advanceTimersByTime(20); - expect(readyState()).toBe(SSEReadyState.OPEN); - (source() as unknown as MockEventSource).simulateTransientError(); - expect(readyState()).toBe(SSEReadyState.CONNECTING); + const data = createSSEStream("https://example.com/events"); + expect(() => data()).toThrow(); dispose(); })); + + it("provides latest message after first message resolves", async () => { + await new Promise(resolve => + createRoot(async dispose => { + const data = createSSEStream("https://example.com/events"); + vi.advanceTimersByTime(20); + // Locate the mock source via SSEInstances + const mock = SSEInstances[SSEInstances.length - 1]!; + mock.simulateMessage("stream-hello"); + // Let the async iterator microtask resolve + await Promise.resolve(); + await Promise.resolve(); + flush(); + expect(data()).toBe("stream-hello"); + dispose(); + resolve(); + }), + ); + }); + + it("applies transform to incoming data", async () => { + await new Promise(resolve => + createRoot(async dispose => { + const data = createSSEStream<{ v: number }>("https://example.com/events", { + transform: JSON.parse, + }); + vi.advanceTimersByTime(20); + const mock = SSEInstances[SSEInstances.length - 1]!; + mock.simulateMessage(JSON.stringify({ v: 7 })); + await Promise.resolve(); + await Promise.resolve(); + flush(); + expect(data()).toEqual({ v: 7 }); + dispose(); + resolve(); + }), + ); + }); + + it("propagates terminal error through data()", async () => { + await new Promise(resolve => + createRoot(async dispose => { + const data = createSSEStream("https://example.com/events"); + vi.advanceTimersByTime(20); + const mock = SSEInstances[SSEInstances.length - 1]!; + mock.simulateError(); // CLOSED → terminal + await Promise.resolve(); + await Promise.resolve(); + flush(); + expect(() => data()).toThrow(); + dispose(); + resolve(); + }), + ); + }); }); diff --git a/packages/sse/test/server.test.ts b/packages/sse/test/server.test.ts index ab7ea714f..d6a457234 100644 --- a/packages/sse/test/server.test.ts +++ b/packages/sse/test/server.test.ts @@ -1,14 +1,13 @@ import { describe, expect, it } from "vitest"; import { createRoot } from "solid-js"; -import { createSSE } from "../src/index.js"; +import { createSSE, createSSEStream } from "../src/index.js"; describe("SSR", () => { it("returns safe stubs without touching EventSource", () => createRoot(dispose => { const sse = createSSE("https://example.com/events"); expect(sse.source()).toBeUndefined(); - expect(sse.data()).toBeUndefined(); - expect(sse.error()).toBeUndefined(); + expect(() => sse.data()).toThrow(); // throws NotReadyError — no initialValue expect(sse.readyState()).toBe(2); expect(() => sse.close()).not.toThrow(); expect(() => sse.reconnect()).not.toThrow(); @@ -23,4 +22,11 @@ describe("SSR", () => { expect(data()).toBe("loading"); dispose(); })); + + it("createSSEStream throws NotReadyError on server", () => + createRoot(dispose => { + const data = createSSEStream("https://example.com/events"); + expect(() => data()).toThrow(); + dispose(); + })); }); diff --git a/packages/sse/test/worker.test.ts b/packages/sse/test/worker.test.ts index ee635674a..74c7f2851 100644 --- a/packages/sse/test/worker.test.ts +++ b/packages/sse/test/worker.test.ts @@ -1,6 +1,6 @@ import "./setup"; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { createRoot } from "solid-js"; +import { createRoot, flush } from "solid-js"; import { createSSE, SSEReadyState } from "../src/sse.js"; import { makeSSEWorker, type SSEWorkerMessage, type SSEWorkerTarget } from "../src/worker.js"; @@ -227,6 +227,7 @@ describe("createSSE with worker source", () => { }); const id = (target.sent[0] as Extract).id; target.respond({ type: "open", id }); + flush(); expect(readyState()).toBe(SSEReadyState.OPEN); dispose(); })); @@ -240,6 +241,7 @@ describe("createSSE with worker source", () => { const id = (target.sent[0] as Extract).id; target.respond({ type: "open", id }); target.respond({ type: "message", id, data: "world", eventType: "message" }); + flush(); expect(data()).toBe("world"); dispose(); })); @@ -254,6 +256,7 @@ describe("createSSE with worker source", () => { const id = (target.sent[0] as Extract).id; target.respond({ type: "open", id }); target.respond({ type: "message", id, data: JSON.stringify({ n: 7 }), eventType: "message" }); + flush(); expect(data()).toEqual({ n: 7 }); dispose(); })); @@ -288,12 +291,15 @@ describe("createSSE with worker source", () => { }); const id1 = (target.sent[0] as Extract).id; target.respond({ type: "open", id: id1 }); + flush(); target.respond({ type: "error", id: id1, readyState: SSEReadyState.CLOSED }); + flush(); // Before the reconnect timer fires, only 1 connect expect(target.sent.filter(m => m.type === "connect")).toHaveLength(1); vi.advanceTimersByTime(150); + flush(); // After the delay, a new connect should have been sent expect(target.sent.filter(m => m.type === "connect")).toHaveLength(2); @@ -308,8 +314,10 @@ describe("createSSE with worker source", () => { }); const id = (target.sent[0] as Extract).id; target.respond({ type: "open", id }); + flush(); expect(readyState()).toBe(SSEReadyState.OPEN); close(); + flush(); expect(readyState()).toBe(SSEReadyState.CLOSED); expect(target.sent.some(m => m.type === "disconnect")).toBe(true); dispose(); diff --git a/packages/sse/vitest.config.ts b/packages/sse/vitest.config.ts new file mode 100644 index 000000000..4679514b1 --- /dev/null +++ b/packages/sse/vitest.config.ts @@ -0,0 +1,46 @@ +import { defineConfig } from "vitest/config"; +import solidPlugin from "vite-plugin-solid"; + +export default defineConfig(({ mode }) => { + const testSSR = mode === "test:ssr" || mode === "ssr"; + return { + plugins: [ + solidPlugin({ + hot: false, + solid: { generate: testSSR ? "ssr" : "dom", omitNestedClosingTags: false }, + }), + ], + resolve: { + conditions: testSSR + ? ["@solid-primitives/source", "node"] + : ["@solid-primitives/source", "browser", "development"], + alias: { + "solid-js/web": new URL( + testSSR + ? "../../node_modules/@solidjs/web/dist/server.js" + : "../../node_modules/@solidjs/web/dist/web.js", + import.meta.url, + ).pathname, + "@solidjs/web": new URL( + testSSR + ? "../../node_modules/@solidjs/web/dist/server.js" + : "../../node_modules/@solidjs/web/dist/web.js", + import.meta.url, + ).pathname, + }, + }, + test: { + watch: false, + isolate: false, + passWithNoTests: true, + environment: testSSR ? "node" : "jsdom", + transformMode: { web: [/\.[jt]sx$/] }, + ...(testSSR + ? { include: ["test/server.test.{ts,tsx}"] } + : { + include: ["test/*.test.{ts,tsx}"], + exclude: ["test/server.test.{ts,tsx}"], + }), + }, + }; +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee1923c5f..d8ac6908b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,10 +152,10 @@ importers: version: link:../scheduled '@solidjs/web': specifier: ^2.0.0-beta.14 - version: 2.0.0-beta.14(solid-js@2.0.0-beta.14) + version: 2.0.0-beta.14(solid-js@2.0.0-experimental.16) solid-js: specifier: ^2.0.0-beta.14 - version: 2.0.0-beta.14 + version: 2.0.0-experimental.16 packages/broadcast-channel: devDependencies: @@ -773,7 +773,7 @@ importers: devDependencies: solid-js: specifier: ^2.0.0-beta.14 - version: 2.0.0-beta.14 + version: 2.0.0-experimental.16 packages/promise: dependencies: @@ -897,10 +897,10 @@ importers: devDependencies: '@solidjs/web': specifier: ^2.0.0-beta.14 - version: 2.0.0-beta.14(solid-js@2.0.0-beta.14) + version: 2.0.0-beta.14(solid-js@2.0.0-experimental.16) solid-js: specifier: ^2.0.0-beta.14 - version: 2.0.0-beta.14 + version: 2.0.0-experimental.16 packages/scroll: dependencies: @@ -968,9 +968,12 @@ importers: specifier: workspace:^ version: link:../utils devDependencies: + '@solidjs/web': + specifier: 2.0.0-beta.14 + version: 2.0.0-beta.14(solid-js@2.0.0-beta.14) solid-js: - specifier: ^1.9.7 - version: 1.9.7 + specifier: 2.0.0-beta.14 + version: 2.0.0-beta.14 packages/state-machine: devDependencies: @@ -1194,7 +1197,7 @@ importers: version: 2.0.0-beta.17(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14) '@tanstack/solid-start': specifier: ^2.0.0-beta.17 - version: 2.0.0-beta.18(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + version: 2.0.0-beta.18(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) clsx: specifier: ^2.0.0 version: 2.1.1 @@ -1252,10 +1255,10 @@ importers: version: 4.0.0 vite: specifier: ^8.0.8 - version: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + version: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) vite-plugin-solid: specifier: 3.0.0-next.5 - version: 3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + version: 3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) packages: @@ -1370,10 +1373,6 @@ packages: resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - '@babel/helper-replace-supers@7.27.1': resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} engines: {node: '>=6.9.0'} @@ -1455,12 +1454,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-object-rest-spread@7.8.3': resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: @@ -2381,8 +2374,8 @@ packages: resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} engines: {node: '>=20.0'} - '@oxc-project/types@0.130.0': - resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} '@peculiar/asn1-schema@2.3.13': resolution: {integrity: sha512-3Xq3a01WkHRZL8X04Zsfg//mGaA21xlL4tlVn4v2xGT0JStiztATRkMwa5b+f/HXmY2smsiLXYK46Gwgzvfg3g==} @@ -2413,97 +2406,97 @@ packages: '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} - '@rolldown/binding-android-arm64@1.0.1': - resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.1': - resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.1': - resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.1': - resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': - resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.1': - resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.1': - resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.1': - resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.1': - resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.1': - resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.1': - resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.1': - resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.1': - resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.1': - resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.1': - resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2719,6 +2712,9 @@ packages: peerDependencies: solid-js: '>=1.8.4' + '@solidjs/signals@0.11.3': + resolution: {integrity: sha512-udMfutYPOlcxKUmc5+n1QtarsxOiAlC6LJY2TqFyaMwdXgo+reiYUcYGDlOiAPXfCLE0lavZHQ/6GT5pJbXKBA==} + '@solidjs/signals@2.0.0-beta.14': resolution: {integrity: sha512-y72nYtD7ogwX/UR5g2Y+meyeO6Q/xbQGtmvVTQX6USkMwEGOMnytqDnHj5amUzD7Fzqg32svwtCSx/q8hsOXAA==} @@ -3184,13 +3180,8 @@ packages: babel-dead-code-elimination@1.0.12: resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - babel-plugin-jsx-dom-expressions@0.40.7: - resolution: {integrity: sha512-/O6JWUmjv03OI9lL2ry9bUjpD5S3PclM55RRJEyCdcFZ5W2SEA/59d+l2hNsk3gI6kiWRdRPdOtqZmsQzFN1pQ==} - peerDependencies: - '@babel/core': ^7.20.12 - - babel-plugin-jsx-dom-expressions@0.50.0-next.11: - resolution: {integrity: sha512-J9Z9T3khj0LxYMtcg1jNA5sdrZia/uWVLVUI0fuBgrjWfKju4+6wlzJSFnrGjFbydOaviykhpPB5FqZoufg+Vw==} + babel-plugin-jsx-dom-expressions@0.39.8: + resolution: {integrity: sha512-/MVOIIjonylDXnrWmG23ZX82m9mtKATsVHB7zYlPfDR9Vdd/NBE48if+wv27bSkBtyO7EPMUlcUc4J63QwuACQ==} peerDependencies: '@babel/core': ^7.20.12 @@ -3207,23 +3198,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - babel-preset-solid@1.9.12: - resolution: {integrity: sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==} + babel-preset-solid@1.9.6: + resolution: {integrity: sha512-HXTK9f93QxoH8dYn1M2mJdOlWgMsR88Lg/ul6QCZGkNTktjTE5HAf93YxQumHoCudLEtZrU1cFCMFOVho6GqFg==} peerDependencies: '@babel/core': ^7.0.0 - solid-js: ^1.9.12 - peerDependenciesMeta: - solid-js: - optional: true - - babel-preset-solid@2.0.0-beta.13: - resolution: {integrity: sha512-VX5fa4b6Sn92v+vFw3ITEvDv0f5vZZZhGgGcqYaAzjP7RF45+VZcZBoG0pHwCGA7UfXdYLUQuqXb4tG1uV3cQA==} - peerDependencies: - '@babel/core': ^7.0.0 - solid-js: ^2.0.0-beta.13 - peerDependenciesMeta: - solid-js: - optional: true babel-preset-solid@2.0.0-beta.14: resolution: {integrity: sha512-l0eX4t+vYmANQqEbRWz0d7b9zt2SybxX7/PfA5cyWGphSGiMtGahFT6XHXktDd8x16o5t1DyPIl7yfa/HAho3A==} @@ -4670,6 +4648,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4972,8 +4955,8 @@ packages: resolution: {integrity: sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==} engines: {node: '>=6.0.0'} - postcss@8.5.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} postcss@8.5.5: @@ -5197,8 +5180,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown@1.0.1: - resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -5268,12 +5251,6 @@ packages: peerDependencies: seroval: ^1.0 - seroval-plugins@1.5.4: - resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - seroval@1.3.2: resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} engines: {node: '>=10'} @@ -5282,10 +5259,6 @@ packages: resolution: {integrity: sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==} engines: {node: '>=10'} - seroval@1.5.4: - resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} - engines: {node: '>=10'} - set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -5344,6 +5317,9 @@ packages: solid-js@2.0.0-beta.14: resolution: {integrity: sha512-gbbvlxhs1GgL1IsnwHNtkTCRBBQcIDMwznBw3T05iYvP+fuUKMyIPku+ZLjeALyX4RaSLR99JSL6NttyHsYb8Q==} + solid-js@2.0.0-experimental.16: + resolution: {integrity: sha512-zZ1dU7cR0EnvLnrYiRLQbCFiDw5blLdlqmofgLzKUYE1TCMWDcisBlSwz0Ez8l4yXB4adbdhtaYCuynH4xSq9A==} + solid-refresh@0.8.0-next.7: resolution: {integrity: sha512-fqkPRAeiE0tqfo2ZljeQBIXwfYssU2w1FmaWFrXmnV33B/CfGfez7BjtOF0Y1/orUNRXI/DZcJlJThHllcCMsA==} peerDependencies: @@ -5363,6 +5339,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + source-map@0.7.6: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} @@ -5379,8 +5359,8 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - srvx@0.11.15: - resolution: {integrity: sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==} + srvx@0.11.16: + resolution: {integrity: sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw==} engines: {node: '>=20.16.0'} hasBin: true @@ -5663,8 +5643,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - validate-html-nesting@1.2.4: - resolution: {integrity: sha512-doQi7e8EJ2OWneSG1aZpJluS6A49aZM0+EICXWKm1i6WvqTLmq0tpUcImc4KTWG50mORO0C4YDBtOCSYvElftw==} + validate-html-nesting@1.2.2: + resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} value-or-promise@1.0.12: resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} @@ -5763,8 +5743,8 @@ packages: yaml: optional: true - vite@8.0.13: - resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5806,6 +5786,14 @@ packages: yaml: optional: true + vitefu@1.0.6: + resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + vite: + optional: true + vitefu@1.1.3: resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} peerDependencies: @@ -5993,13 +5981,13 @@ snapshots: '@ardatan/relay-compiler@12.0.0(graphql@16.9.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 + '@babel/core': 7.27.4 + '@babel/generator': 7.27.5 + '@babel/parser': 7.27.5 '@babel/runtime': 7.27.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - babel-preset-fbjs: 3.4.0(@babel/core@7.29.0) + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + babel-preset-fbjs: 3.4.0(@babel/core@7.27.4) chalk: 4.1.2 fb-watchman: 2.0.2 fbjs: 3.0.5 @@ -6103,7 +6091,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@babel/helper-compilation-targets@7.27.2': dependencies: @@ -6129,20 +6117,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.4) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.27.4 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -6151,14 +6126,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.27.1': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.18.6': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@babel/helper-module-imports@7.27.1': dependencies: @@ -6183,15 +6158,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.27.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -6203,34 +6169,23 @@ snapshots: '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.27.4 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color @@ -6260,57 +6215,52 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.29.0)': + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.4) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.29.0)': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.29.0) - - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/compat-data': 7.27.5 + '@babel/core': 7.27.4 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.27.4) - '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.27.4)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)': dependencies: @@ -6322,76 +6272,76 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-classes@7.25.0(@babel/core@7.29.0)': + '@babel/plugin-transform-classes@7.25.0(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.4) + '@babel/traverse': 7.27.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/template': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.29.0)': + '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.29.0)': + '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.29.0) + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.27.4) - '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.29.0)': + '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.27.4 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.27.4 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-literals@7.25.2(@babel/core@7.29.0)': + '@babel/plugin-transform-literals@7.25.2(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.27.4)': dependencies: @@ -6401,65 +6351,57 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.29.0) + '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.29.0)': + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-spread@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-spread@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.29.0)': + '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-typescript@7.27.1(@babel/core@7.27.4)': dependencies: @@ -7214,11 +7156,11 @@ snapshots: '@graphql-tools/graphql-tag-pluck@8.3.2(graphql@16.9.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/core': 7.27.4 + '@babel/parser': 7.27.5 + '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.27.4) + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 '@graphql-tools/utils': 10.3.4(graphql@16.9.0) graphql: 16.9.0 tslib: 2.8.1 @@ -7371,7 +7313,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/gen-mapping@0.3.8': dependencies: @@ -7381,8 +7323,8 @@ snapshots: '@jridgewell/remapping@2.3.5': dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} @@ -7458,7 +7400,7 @@ snapshots: '@oozcitak/util@10.0.0': {} - '@oxc-project/types@0.130.0': {} + '@oxc-project/types@0.132.0': {} '@peculiar/asn1-schema@2.3.13': dependencies: @@ -7490,53 +7432,53 @@ snapshots: '@repeaterjs/repeater@3.0.6': {} - '@rolldown/binding-android-arm64@1.0.1': + '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-arm64@1.0.1': + '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-x64@1.0.1': + '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rolldown/binding-freebsd-x64@1.0.1': + '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.1': + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.1': + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.1': + '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.1': + '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.1': + '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-musl@1.0.1': + '@rolldown/binding-linux-x64-musl@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.1': + '@rolldown/binding-openharmony-arm64@1.0.2': optional: true - '@rolldown/binding-wasm32-wasi@1.0.1': + '@rolldown/binding-wasm32-wasi@1.0.2': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.1': + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.1': + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true '@rolldown/pluginutils@1.0.0-beta.40': {} @@ -7734,6 +7676,8 @@ snapshots: dependencies: solid-js: 2.0.0-beta.14 + '@solidjs/signals@0.11.3': {} + '@solidjs/signals@2.0.0-beta.14': {} '@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14)': @@ -7744,10 +7688,16 @@ snapshots: '@solidjs/web@2.0.0-beta.14(solid-js@2.0.0-beta.14)': dependencies: - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) solid-js: 2.0.0-beta.14 + '@solidjs/web@2.0.0-beta.14(solid-js@2.0.0-experimental.16)': + dependencies: + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) + solid-js: 2.0.0-experimental.16 + '@supabase/auth-js@2.67.3': dependencies: '@supabase/node-fetch': 2.6.15 @@ -7808,8 +7758,8 @@ snapshots: dependencies: '@tanstack/history': 1.161.6 cookie-es: 2.0.0 - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) '@tanstack/router-generator@1.166.24': dependencies: @@ -7818,18 +7768,18 @@ snapshots: '@tanstack/virtual-file-routes': 1.161.7 prettier: 3.5.3 recast: 0.23.11 - source-map: 0.7.6 + source-map: 0.7.4 tsx: 4.20.2 zod: 3.25.63 transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.167.12(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': + '@tanstack/router-plugin@1.167.12(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': dependencies: '@babel/core': 7.29.0 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.0) - '@babel/template': 7.28.6 + '@babel/template': 7.27.2 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 '@tanstack/router-core': 1.168.9 @@ -7840,8 +7790,8 @@ snapshots: unplugin: 2.3.5 zod: 3.25.63 optionalDependencies: - vite: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) - vite-plugin-solid: 3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + vite-plugin-solid: 3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) transitivePeerDependencies: - supports-color @@ -7890,18 +7840,18 @@ snapshots: transitivePeerDependencies: - crossws - '@tanstack/solid-start@2.0.0-beta.18(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': + '@tanstack/solid-start@2.0.0-beta.18(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': dependencies: '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@tanstack/solid-router': 2.0.0-beta.17(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14) '@tanstack/solid-start-client': 2.0.0-beta.17(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14) '@tanstack/solid-start-server': 2.0.0-beta.17(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14) '@tanstack/start-client-core': 1.167.9 - '@tanstack/start-plugin-core': 1.167.17(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + '@tanstack/start-plugin-core': 1.167.17(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) '@tanstack/start-server-core': 1.167.9 pathe: 2.0.3 solid-js: 2.0.0-beta.14 - vite: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) transitivePeerDependencies: - '@rsbuild/core' - '@tanstack/react-router' @@ -7915,11 +7865,11 @@ snapshots: '@tanstack/router-core': 1.168.9 '@tanstack/start-fn-stubs': 1.161.6 '@tanstack/start-storage-context': 1.166.23 - seroval: 1.5.4 + seroval: 1.5.2 '@tanstack/start-fn-stubs@1.161.6': {} - '@tanstack/start-plugin-core@1.167.17(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': + '@tanstack/start-plugin-core@1.167.17(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.29.0 @@ -7927,7 +7877,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.40 '@tanstack/router-core': 1.168.9 '@tanstack/router-generator': 1.166.24 - '@tanstack/router-plugin': 1.167.12(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + '@tanstack/router-plugin': 1.167.12(vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)))(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) '@tanstack/router-utils': 1.161.6 '@tanstack/start-client-core': 1.167.9 '@tanstack/start-server-core': 1.167.9 @@ -7936,11 +7886,11 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.4 source-map: 0.7.6 - srvx: 0.11.15 + srvx: 0.11.16 tinyglobby: 0.2.16 ufo: 1.6.1 - vite: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) - vitefu: 1.1.3(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + vitefu: 1.1.3(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) xmlbuilder2: 4.0.3 zod: 3.25.63 transitivePeerDependencies: @@ -7958,7 +7908,7 @@ snapshots: '@tanstack/start-client-core': 1.167.9 '@tanstack/start-storage-context': 1.166.23 h3-v2: h3@2.0.1-rc.16 - seroval: 1.5.4 + seroval: 1.5.2 transitivePeerDependencies: - crossws @@ -7983,24 +7933,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.7 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 '@types/babel__traverse@7.20.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@types/debug@4.1.12': dependencies: @@ -8339,90 +8289,72 @@ snapshots: babel-dead-code-elimination@1.0.12: dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/core': 7.27.4 + '@babel/parser': 7.27.5 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color - babel-plugin-jsx-dom-expressions@0.40.7(@babel/core@7.27.4): + babel-plugin-jsx-dom-expressions@0.39.8(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.27.4) - '@babel/types': 7.29.0 - html-entities: 2.3.3 - parse5: 7.3.0 - - babel-plugin-jsx-dom-expressions@0.50.0-next.11(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/types': 7.27.6 html-entities: 2.3.3 parse5: 7.3.0 - validate-html-nesting: 1.2.4 + validate-html-nesting: 1.2.2 babel-plugin-jsx-dom-expressions@0.50.0-next.13(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.27.4) - '@babel/types': 7.29.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/types': 7.27.6 html-entities: 2.3.3 parse5: 7.3.0 - validate-html-nesting: 1.2.4 + validate-html-nesting: 1.2.2 babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} - babel-preset-fbjs@3.4.0(@babel/core@7.29.0): + babel-preset-fbjs@3.4.0(@babel/core@7.27.4): dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.29.0) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.29.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) - '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.29.0) - '@babel/plugin-transform-classes': 7.25.0(@babel/core@7.29.0) - '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.29.0) - '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.29.0) - '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.29.0) - '@babel/plugin-transform-literals': 7.25.2(@babel/core@7.29.0) - '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.29.0) - '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.29.0) - '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.29.0) + '@babel/core': 7.27.4 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.27.4) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.27.4) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.4) + '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.27.4) + '@babel/plugin-transform-classes': 7.25.0(@babel/core@7.27.4) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.27.4) + '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.27.4) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.27.4) + '@babel/plugin-transform-literals': 7.25.2(@babel/core@7.27.4) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.27.4) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.27.4) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.27.4) babel-plugin-syntax-trailing-function-commas: 7.0.0-beta.0 transitivePeerDependencies: - supports-color - babel-preset-solid@1.9.12(@babel/core@7.27.4)(solid-js@2.0.0-beta.14): + babel-preset-solid@1.9.6(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 - babel-plugin-jsx-dom-expressions: 0.40.7(@babel/core@7.27.4) - optionalDependencies: - solid-js: 2.0.0-beta.14 - - babel-preset-solid@2.0.0-beta.13(@babel/core@7.29.0)(solid-js@2.0.0-beta.14): - dependencies: - '@babel/core': 7.29.0 - babel-plugin-jsx-dom-expressions: 0.50.0-next.11(@babel/core@7.29.0) - optionalDependencies: - solid-js: 2.0.0-beta.14 + babel-plugin-jsx-dom-expressions: 0.39.8(@babel/core@7.27.4) babel-preset-solid@2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14): dependencies: @@ -8888,7 +8820,7 @@ snapshots: dependencies: '@babel/core': 7.27.4 '@babel/preset-typescript': 7.27.1(@babel/core@7.27.4) - babel-preset-solid: 1.9.12(@babel/core@7.27.4)(solid-js@2.0.0-beta.14) + babel-preset-solid: 1.9.6(@babel/core@7.27.4) esbuild: 0.25.5 solid-js: 2.0.0-beta.14 transitivePeerDependencies: @@ -9299,7 +9231,7 @@ snapshots: h3@2.0.1-rc.16: dependencies: rou3: 0.8.1 - srvx: 0.11.15 + srvx: 0.11.16 has-flag@3.0.0: {} @@ -10110,6 +10042,8 @@ snapshots: nanoid@3.3.11: {} + nanoid@3.3.12: {} + natural-compare@1.4.0: {} no-case@3.0.4: @@ -10254,7 +10188,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.27.1 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -10397,9 +10331,9 @@ snapshots: picocolors: 0.2.1 source-map: 0.6.1 - postcss@8.5.14: + postcss@8.5.15: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -10611,26 +10545,26 @@ snapshots: rfdc@1.4.1: {} - rolldown@1.0.1: + rolldown@1.0.2: dependencies: - '@oxc-project/types': 0.130.0 + '@oxc-project/types': 0.132.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.1 - '@rolldown/binding-darwin-arm64': 1.0.1 - '@rolldown/binding-darwin-x64': 1.0.1 - '@rolldown/binding-freebsd-x64': 1.0.1 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 - '@rolldown/binding-linux-arm64-gnu': 1.0.1 - '@rolldown/binding-linux-arm64-musl': 1.0.1 - '@rolldown/binding-linux-ppc64-gnu': 1.0.1 - '@rolldown/binding-linux-s390x-gnu': 1.0.1 - '@rolldown/binding-linux-x64-gnu': 1.0.1 - '@rolldown/binding-linux-x64-musl': 1.0.1 - '@rolldown/binding-openharmony-arm64': 1.0.1 - '@rolldown/binding-wasm32-wasi': 1.0.1 - '@rolldown/binding-win32-arm64-msvc': 1.0.1 - '@rolldown/binding-win32-x64-msvc': 1.0.1 + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 rollup@4.43.0: dependencies: @@ -10708,16 +10642,10 @@ snapshots: dependencies: seroval: 1.5.2 - seroval-plugins@1.5.4(seroval@1.5.4): - dependencies: - seroval: 1.5.4 - seroval@1.3.2: {} seroval@1.5.2: {} - seroval@1.5.4: {} - set-blocking@2.0.0: {} setimmediate@1.0.5: {} @@ -10775,8 +10703,15 @@ snapshots: dependencies: '@solidjs/signals': 2.0.0-beta.14 csstype: 3.1.3 - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) + + solid-js@2.0.0-experimental.16: + dependencies: + '@solidjs/signals': 0.11.3 + csstype: 3.1.3 + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) solid-refresh@0.8.0-next.7(solid-js@2.0.0-beta.14): dependencies: @@ -10800,6 +10735,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.4: {} + source-map@0.7.6: {} space-separated-tokens@2.0.2: {} @@ -10815,7 +10752,7 @@ snapshots: sprintf-js@1.0.3: {} - srvx@0.11.15: {} + srvx@0.11.16: {} stackback@0.0.2: {} @@ -11100,7 +11037,7 @@ snapshots: unplugin@2.3.5: dependencies: acorn: 8.15.0 - picomatch: 4.0.4 + picomatch: 4.0.2 webpack-virtual-modules: 0.6.2 update-browserslist-db@1.1.3(browserslist@4.25.0): @@ -11127,7 +11064,7 @@ snapshots: util-deprecate@1.0.2: {} - validate-html-nesting@1.2.4: {} + validate-html-nesting@1.2.2: {} value-or-promise@1.0.12: {} @@ -11159,31 +11096,31 @@ snapshots: - supports-color - terser - vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): + vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@types/babel__core': 7.20.5 - babel-preset-solid: 2.0.0-beta.13(@babel/core@7.29.0)(solid-js@2.0.0-beta.14) + babel-preset-solid: 2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14) merge-anything: 5.1.7 solid-js: 2.0.0-beta.14 solid-refresh: 0.8.0-next.7(solid-js@2.0.0-beta.14) - vite: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) - vitefu: 1.1.3(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + vitefu: 1.0.6(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) transitivePeerDependencies: - supports-color vite-plugin-solid@3.0.0-next.5(@solidjs/web@2.0.0-beta.14(solid-js@2.0.0-beta.14))(solid-js@2.0.0-beta.14)(vite@6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@solidjs/web': 2.0.0-beta.14(solid-js@2.0.0-beta.14) '@types/babel__core': 7.20.5 - babel-preset-solid: 2.0.0-beta.13(@babel/core@7.29.0)(solid-js@2.0.0-beta.14) + babel-preset-solid: 2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14) merge-anything: 5.1.7 solid-js: 2.0.0-beta.14 solid-refresh: 0.8.0-next.7(solid-js@2.0.0-beta.14) vite: 6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) - vitefu: 1.1.3(vite@6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) + vitefu: 1.0.6(vite@6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)) transitivePeerDependencies: - supports-color @@ -11215,12 +11152,12 @@ snapshots: tsx: 4.20.2 yaml: 2.5.0 - vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0): + vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.14 - rolldown: 1.0.1 + postcss: 8.5.15 + rolldown: 1.0.2 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 22.15.31 @@ -11231,13 +11168,17 @@ snapshots: tsx: 4.20.2 yaml: 2.5.0 - vitefu@1.1.3(vite@6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): + vitefu@1.0.6(vite@6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): optionalDependencies: vite: 6.3.5(@types/node@22.15.31)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) - vitefu@1.1.3(vite@8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): + vitefu@1.0.6(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): + optionalDependencies: + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + + vitefu@1.1.3(vite@8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0)): optionalDependencies: - vite: 8.0.13(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) + vite: 8.0.14(@types/node@22.15.31)(esbuild@0.25.5)(jiti@1.21.7)(sass@1.77.8)(tsx@4.20.2)(yaml@2.5.0) vitest@2.1.9(@types/node@22.15.31)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.77.8): dependencies: