diff --git a/.changeset/video-initial.md b/.changeset/video-initial.md new file mode 100644 index 000000000..2a7e4f22c --- /dev/null +++ b/.changeset/video-initial.md @@ -0,0 +1,27 @@ +--- +"@solid-primitives/video": minor +--- + +New package: `@solid-primitives/video` + +Layered primitives for managing HTML video playback, built for Solid 2.0 (beta.14). + +### `makeVideo` + +Non-reactive base. Creates an `HTMLVideoElement` with optional event handlers and initial configuration (`autoPlay`, `loop`, `muted`, `preload`). Returns a `[player, cleanup]` tuple. No Solid owner required. + +### `makeVideoPlayer` + +Wraps `makeVideo` with imperative controls: `play`, `pause`, `seek`, `setVolume`, `setMuted`, `setPlaybackRate`, and `setLoop`. + +### `createVideo` + +Reactive primitive covering essential playback state: `playing`/`setPlaying`, `currentTime`/`seek`, `ended`, `seeking`, `error` (`MediaError | null`), and `duration` (throws `NotReadyError` until metadata loads — integrates with ``). Accepts a static or reactive `VideoSource` and optional `VideoOptions`. + +### `createVideoPlayer` + +Extends `createVideo` with the full control surface: `volume`/`setVolume`, `muted`/`setMuted`, `playbackRate`/`setPlaybackRate`, `loop`/`setLoop`, `buffered`, `readyState`, `videoWidth`, and `videoHeight`. Accepts `VideoControlsOptions` which adds `volume` and `playbackRate` initial values to `VideoOptions`. + +### Design notes + +`createVideo` and `createVideoPlayer` are composable — `createVideoPlayer` calls `createVideo` internally and layers additional `createEventListenerMap` bindings on the same player element. Choose the primitive that matches your needs; the non-reactive `make*` layer remains available when no Solid owner is present. diff --git a/.storybook/main.ts b/.storybook/main.ts index 0453258d1..1cb6eb661 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -6,6 +6,7 @@ const config: StorybookConfig = { staticDirs: [ { from: "../packages/audio/stories/assets", to: "/audio" }, { from: "../assets/img", to: "/img" }, + { from: "../assets/video", to: "/video" }, { from: "../node_modules/geist/dist/fonts", to: "/geist-fonts" }, ], addons: ["@storybook/addon-docs"], diff --git a/assets/video/big_buck_bunny_sall.mp4 b/assets/video/big_buck_bunny_sall.mp4 new file mode 100644 index 000000000..57f72e53d Binary files /dev/null and b/assets/video/big_buck_bunny_sall.mp4 differ diff --git a/packages/video/LICENSE b/packages/video/LICENSE new file mode 100644 index 000000000..38b41d975 --- /dev/null +++ b/packages/video/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Solid Primitives Working Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/video/README.md b/packages/video/README.md new file mode 100644 index 000000000..3e7192142 --- /dev/null +++ b/packages/video/README.md @@ -0,0 +1,178 @@ +

+ Solid Primitives Video +

+ +# @solid-primitives/video + +[![size](https://img.shields.io/bundlephobia/minzip/@solid-primitives/video?style=for-the-badge&label=size)](https://bundlephobia.com/package/@solid-primitives/video) +[![version](https://img.shields.io/npm/v/@solid-primitives/video?style=for-the-badge)](https://www.npmjs.com/package/@solid-primitives/video) +[![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-0.json)](https://github.com/solidjs-community/solid-primitives#contribution-process) + +Layered primitives for managing HTML video playback. The `make*` variants are non-reactive and require no Solid owner. The `create*` variants integrate with Solid's reactive system — `createVideo` covers essential playback state, and `createVideoPlayer` extends it with the full control surface. + +## Installation + +```bash +npm install @solid-primitives/video +# or +pnpm add @solid-primitives/video +``` + +## How to use it + +### `makeVideo` + +Creates a raw `HTMLVideoElement` with optional event handlers and initial configuration. No Solid owner required. + +```ts +const [player, cleanup] = makeVideo('clip.mp4', {}, { muted: true, loop: true }); +cleanup(); +``` + +```ts +function makeVideo( + src: VideoSource | HTMLVideoElement, + handlers?: VideoEventHandlers, + options?: VideoOptions, +): [player: HTMLVideoElement, cleanup: VoidFunction]; +``` + +### `makeVideoPlayer` + +Wraps `makeVideo` with imperative playback controls. No Solid owner required. + +```ts +const [{ play, pause, seek, setVolume, setMuted, setPlaybackRate, setLoop }, cleanup] = + makeVideoPlayer('clip.mp4'); + +await play(); +seek(30); +setPlaybackRate(1.5); +setLoop(true); +cleanup(); +``` + +```ts +function makeVideoPlayer( + src: VideoSource | HTMLVideoElement, + handlers?: VideoEventHandlers, + options?: VideoOptions, +): [controls: VideoControls, cleanup: VoidFunction]; +``` + +### `createVideo` + +Essential reactive playback state: `playing`, `currentTime`, `ended`, `seeking`, `error`, and an async `duration` that suspends until metadata is loaded. + +```ts +const video = createVideo('clip.mp4'); +// or with a reactive source: +const video = createVideo(() => selectedUrl()); + +video.playing() // boolean — true while actively playing +video.setPlaying(true) // plays +video.currentTime() // seconds +video.seek(30) +video.ended() // boolean +video.seeking() // boolean — true while scrubbing +video.error() // MediaError | null +``` + +The `duration` accessor throws `NotReadyError` until video metadata has loaded, integrating with Solid 2.0's `` boundary: + +```tsx + + {video.duration()}s + +``` + +```ts +function createVideo( + src: VideoSource | Accessor, + options?: VideoOptions, +): VideoReturn; +``` + +### `createVideoPlayer` + +Extends `createVideo` with the full control surface: volume, muted, playback rate, loop, buffering state, and dimensions. Accepts all `VideoOptions` plus `volume` and `playbackRate` initial values. + +```ts +const video = createVideoPlayer('clip.mp4', { + muted: true, + volume: 0.8, + playbackRate: 1, +}); + +// All fields from createVideo, plus: +video.volume() // 0–1 +video.setVolume(0.5) +video.muted() // boolean +video.setMuted(true) +video.playbackRate() // number +video.setPlaybackRate(1.5) +video.loop() // boolean +video.setLoop(true) +video.buffered() // TimeRanges | undefined +video.readyState() // 0–4 +video.videoWidth() // intrinsic pixel width +video.videoHeight() // intrinsic pixel height +``` + +> **Fullscreen** is intentionally omitted — use the dedicated `@solid-primitives/fullscreen` primitive to manage fullscreen state and attach it to `video.player`. + +```ts +function createVideoPlayer( + src: VideoSource | Accessor, + options?: VideoControlsOptions, +): VideoControlsReturn; +``` + +## Types + +```ts +type VideoSource = string | undefined | MediaProvider; + +type VideoOptions = { + autoPlay?: boolean; + loop?: boolean; + muted?: boolean; + preload?: "" | "none" | "metadata" | "auto"; +}; + +type VideoControlsOptions = VideoOptions & { + volume?: number; + playbackRate?: number; +}; + +type VideoReturn = { + player: HTMLVideoElement; + playing: Accessor; + setPlaying: (v: boolean) => void; + currentTime: Accessor; + seek: (time: number) => void; + ended: Accessor; + seeking: Accessor; + error: Accessor; + duration: Accessor; // throws NotReadyError until loaded +}; + +type VideoControlsReturn = VideoReturn & { + volume: Accessor; + setVolume: (v: number) => void; + muted: Accessor; + setMuted: (v: boolean) => void; + playbackRate: Accessor; + setPlaybackRate: (rate: number) => void; + loop: Accessor; + setLoop: (v: boolean) => void; + buffered: Accessor; + readyState: Accessor; + videoWidth: Accessor; + videoHeight: Accessor; +}; +``` + +## Changelog + +See [CHANGELOG.md](./CHANGELOG.md) diff --git a/packages/video/dev/index.tsx b/packages/video/dev/index.tsx new file mode 100644 index 000000000..09f525954 --- /dev/null +++ b/packages/video/dev/index.tsx @@ -0,0 +1,78 @@ +import { type Component, createSignal } from "solid-js"; +import { createVideoPlayer } from "../src/index.js"; + +const DEMO_URL = + "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; + +const App: Component = () => { + const [src, setSrc] = createSignal(DEMO_URL); + const video = createVideoPlayer(src); + + return ( +
+
+

Video Primitive Demo

+
+
+ ); +}; + +export default App; diff --git a/packages/video/package.json b/packages/video/package.json new file mode 100644 index 000000000..747e6912c --- /dev/null +++ b/packages/video/package.json @@ -0,0 +1,69 @@ +{ + "name": "@solid-primitives/video", + "version": "0.0.100", + "description": "Primitives to manage HTML video playback.", + "author": "David Di Biase ", + "contributors": [], + "license": "MIT", + "homepage": "https://primitives.solidjs.community/package/video", + "repository": { + "type": "git", + "url": "git+https://github.com/solidjs-community/solid-primitives.git" + }, + "bugs": { + "url": "https://github.com/solidjs-community/solid-primitives/issues" + }, + "primitive": { + "name": "video", + "stage": 0, + "list": [ + "makeVideo", + "makeVideoPlayer", + "createVideo", + "createVideoPlayer" + ], + "category": "Display & Media" + }, + "keywords": [ + "solid", + "primitives", + "video", + "media" + ], + "private": false, + "sideEffects": false, + "files": [ + "dist" + ], + "type": "module", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "browser": {}, + "exports": { + "import": { + "@solid-primitives/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "typesVersions": {}, + "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", + "test": "pnpm run vitest", + "test:ssr": "pnpm run vitest --mode ssr" + }, + "dependencies": { + "@solid-primitives/event-listener": "workspace:^", + "@solid-primitives/utils": "workspace:^" + }, + "devDependencies": { + "@solidjs/web": "2.0.0-beta.14", + "solid-js": "2.0.0-beta.14" + }, + "peerDependencies": { + "@solidjs/web": "^2.0.0-beta.14", + "solid-js": "^2.0.0-beta.14" + } +} diff --git a/packages/video/src/createVideo.ts b/packages/video/src/createVideo.ts new file mode 100644 index 000000000..db6152972 --- /dev/null +++ b/packages/video/src/createVideo.ts @@ -0,0 +1,171 @@ +import { type Accessor, createEffect, createSignal, NotReadyError, onCleanup } from "solid-js"; +import { isServer } from "@solidjs/web"; +import { access, INTERNAL_OPTIONS, noop } from "@solid-primitives/utils"; +import { createEventListenerMap } from "@solid-primitives/event-listener"; +import type { VideoEventHandlers, VideoOptions, VideoReturn, VideoSource } from "./types.js"; + +const NOT_SET: unique symbol = Symbol(); + +export function setVideoSrc(el: HTMLVideoElement, src: VideoSource): void { + if (typeof src === "string") { + el.srcObject = null; + el.src = src; + } else { + el.src = ""; + el.srcObject = (src as MediaProvider | null) ?? null; + } +} + +function unwrapSource(src: VideoSource | HTMLVideoElement): HTMLVideoElement { + if (src instanceof HTMLVideoElement) return src; + const player = document.createElement("video"); + setVideoSrc(player, src); + return player; +} + +function applyOptions(player: HTMLVideoElement, options: VideoOptions): void { + if (options.autoPlay !== undefined) player.autoplay = options.autoPlay; + if (options.loop !== undefined) player.loop = options.loop; + if (options.muted !== undefined) player.muted = options.muted; + if (options.preload !== undefined) player.preload = options.preload; +} + +/** + * Creates a raw `HTMLVideoElement` with optional event handlers and initial options. + * Non-reactive — no Solid owner required. Returns a cleanup function. + * + * @param src Video URL, MediaProvider, or existing HTMLVideoElement + * @param handlers Event handlers to bind against the player + * @param options Initial element configuration (autoPlay, loop, muted, preload) + * @returns Tuple of `[player, cleanup]` + * + * @example + * ```ts + * const [player, cleanup] = makeVideo('clip.mp4', {}, { muted: true }); + * ``` + */ +export const makeVideo = ( + src: VideoSource | HTMLVideoElement, + handlers: VideoEventHandlers = {}, + options?: VideoOptions, +): [player: HTMLVideoElement, cleanup: VoidFunction] => { + if (isServer) return [{} as HTMLVideoElement, noop]; + + const player = unwrapSource(src); + if (options) applyOptions(player, options); + + for (const [name, handler] of Object.entries(handlers)) { + player.addEventListener(name, handler as EventListener); + } + + const cleanup = () => { + player.pause(); + for (const [name, handler] of Object.entries(handlers)) { + player.removeEventListener(name, handler as EventListener); + } + }; + + return [player, cleanup]; +}; + +/** + * A reactive video primitive with essential playback state. + * + * Returns `playing`, `currentTime`, `ended`, `seeking`, `error`, and a `duration` + * that throws `NotReadyError` until metadata loads (integrates with ``). + * + * For volume, muted, playback rate, buffering, and dimensions use + * `createVideoPlayer`. + * + * @param src Video URL, MediaProvider, or a reactive accessor returning either + * @param options Initial element configuration + * + * @example + * ```ts + * const video = createVideo('clip.mp4'); + * video.playing() // boolean + * video.setPlaying(true) // plays + * video.seek(30) + * video.seeking() // boolean — true while scrubbing + * video.error() // MediaError | null + * + * // duration() throws NotReadyError until metadata loads: + * Loading…

}> + *

{video.duration()}s

+ *
+ * ``` + */ +export const createVideo = ( + src: VideoSource | Accessor, + options?: VideoOptions, +): VideoReturn => { + if (isServer) { + return { + player: {} as HTMLVideoElement, + playing: () => false, + setPlaying: noop, + currentTime: () => 0, + seek: noop, + ended: () => false, + seeking: () => false, + error: () => null, + duration: () => { + throw new NotReadyError("Video duration not available on the server"); + }, + }; + } + + const [player, cleanup] = makeVideo(access(src), {}, options); + onCleanup(cleanup); + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const seek = player.fastSeek + ? (time: number) => player.fastSeek(time) + : (time: number) => { player.currentTime = time; }; + + const [playing, setPlayingSignal] = createSignal(!player.paused, INTERNAL_OPTIONS); + const setPlaying = (v: boolean) => (v ? player.play() : player.pause()); + + const [currentTime, setCurrentTime] = createSignal(0, INTERNAL_OPTIONS); + const [ended, setEnded] = createSignal(false, INTERNAL_OPTIONS); + const [seeking, setSeeking] = createSignal(false, INTERNAL_OPTIONS); + const [error, setError] = createSignal(null, INTERNAL_OPTIONS); + const [rawDuration, setRawDuration] = createSignal( + NOT_SET, + INTERNAL_OPTIONS, + ); + + createEventListenerMap(player, { + playing: () => setPlayingSignal(true), + pause: () => setPlayingSignal(false), + ended: () => { + setPlayingSignal(false); + setEnded(true); + }, + play: () => setEnded(false), + timeupdate: () => setCurrentTime(player.currentTime), + seeking: () => setSeeking(true), + seeked: () => setSeeking(false), + error: () => setError(player.error), + loadstart: () => { + setRawDuration(NOT_SET); + setError(null); + }, + loadedmetadata: () => setRawDuration(player.duration), + }); + + const duration = (): number => { + const val = rawDuration(); + if (val === NOT_SET) throw new NotReadyError("Video duration not yet available"); + return val; + }; + + if (src instanceof Function) { + createEffect(src, (newSrc: VideoSource) => { + setVideoSrc(player, newSrc); + seek(0); + }); + } + + return { player, playing, setPlaying, currentTime, seek, ended, seeking, error, duration }; +}; diff --git a/packages/video/src/createVideoPlayer.ts b/packages/video/src/createVideoPlayer.ts new file mode 100644 index 000000000..394ce7f4b --- /dev/null +++ b/packages/video/src/createVideoPlayer.ts @@ -0,0 +1,214 @@ +import { createSignal, NotReadyError } from "solid-js"; +import { isServer } from "@solidjs/web"; +import { INTERNAL_OPTIONS, noop } from "@solid-primitives/utils"; +import { createEventListenerMap } from "@solid-primitives/event-listener"; +import { createVideo, makeVideo } from "./createVideo.js"; +import type { + VideoControls, + VideoControlsOptions, + VideoControlsReturn, + VideoEventHandlers, + VideoOptions, + VideoSource, +} from "./types.js"; +import type { Accessor } from "solid-js"; + +/** + * Wraps `makeVideo` with playback controls and exposes `player` for external + * fullscreen handling. Fullscreen must be implemented by the consumer (e.g. via + * `@solid-primitives/fullscreen`). Non-reactive — no Solid owner required. + * Returns a cleanup function. + * + * @param src Video URL, MediaProvider, or existing HTMLVideoElement + * @param handlers Event handlers to bind against the player + * @param options Initial element configuration + * @returns Tuple of `[controls, cleanup]` + * + * @example + * ```ts + * const [{ play, pause, seek }, cleanup] = makeVideoPlayer('clip.mp4'); + * ``` + */ +export const makeVideoPlayer = ( + src: VideoSource | HTMLVideoElement, + handlers: VideoEventHandlers = {}, + options?: VideoOptions, +): [controls: VideoControls, cleanup: VoidFunction] => { + if (isServer) { + return [ + { + play: async () => noop(), + pause: noop, + seek: noop, + setVolume: noop, + setMuted: noop, + setPlaybackRate: noop, + setLoop: noop, + player: {} as HTMLVideoElement, + }, + noop, + ]; + } + + const [player, cleanup] = makeVideo(src, handlers, options); + + const controls: VideoControls = { + player, + play: () => player.play(), + pause: () => player.pause(), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + seek: player.fastSeek + ? (time: number) => player.fastSeek(time) + : (time: number) => { + player.currentTime = time; + }, + setVolume: (volume: number) => { + player.volume = volume; + }, + setMuted: (muted: boolean) => { + player.muted = muted; + }, + setPlaybackRate: (rate: number) => { + player.playbackRate = rate; + }, + setLoop: (loop: boolean) => { + player.loop = loop; + }, + }; + + return [controls, cleanup]; +}; + +/** + * A reactive video primitive with full media controls. + * + * Extends `createVideo` with `volume`, `muted`, `playbackRate`, `loop`, + * `buffered`, `readyState`, `videoWidth`, and `videoHeight`. + * + * @param src Video URL, MediaProvider, or a reactive accessor returning either + * @param options Initial element configuration including volume and playback rate + * + * @example + * ```ts + * const video = createVideoPlayer('clip.mp4', { muted: true, volume: 0.8 }); + * video.playing() // boolean + * video.volume() // 0–1 + * video.setVolume(0.5) + * video.muted() // boolean + * video.setMuted(true) + * video.playbackRate() // number + * video.setPlaybackRate(1.5) + * video.loop() // boolean + * video.setLoop(true) + * video.buffered() // TimeRanges | undefined + * video.readyState() // 0–4 + * video.videoWidth() // number + * video.videoHeight() // number + * ``` + */ +export const createVideoPlayer = ( + src: VideoSource | Accessor, + options?: VideoControlsOptions, +): VideoControlsReturn => { + if (isServer) { + return { + player: {} as HTMLVideoElement, + playing: () => false, + setPlaying: noop, + currentTime: () => 0, + seek: noop, + ended: () => false, + seeking: () => false, + error: () => null, + duration: () => { + throw new NotReadyError("Video duration not available on the server"); + }, + volume: () => 1, + setVolume: noop, + muted: () => false, + setMuted: noop, + playbackRate: () => 1, + setPlaybackRate: noop, + loop: () => false, + setLoop: noop, + buffered: () => undefined, + readyState: () => 0, + videoWidth: () => 0, + videoHeight: () => 0, + }; + } + + const base = createVideo(src, options); + const { player } = base; + + // Apply controls-level initial values before reading signal initial state. + if (options?.volume !== undefined) player.volume = options.volume; + if (options?.playbackRate !== undefined) player.playbackRate = options.playbackRate; + + const [volume, setVolumeSignal] = createSignal(player.volume, INTERNAL_OPTIONS); + const setVolume = (v: number) => { + player.volume = v; + }; + + const [muted, setMutedSignal] = createSignal(player.muted, INTERNAL_OPTIONS); + const setMuted = (v: boolean) => { + player.muted = v; + }; + + const [playbackRate, setPlaybackRateSignal] = createSignal(player.playbackRate, INTERNAL_OPTIONS); + const setPlaybackRate = (v: number) => { + player.playbackRate = v; + }; + + // loop has no DOM event — setLoop must update both DOM and signal directly. + const [loop, setLoopSignal] = createSignal(player.loop, INTERNAL_OPTIONS); + const setLoop = (v: boolean) => { + player.loop = v; + setLoopSignal(v); + }; + + const [buffered, setBuffered] = createSignal(undefined, INTERNAL_OPTIONS); + const [readyState, setReadyState] = createSignal(player.readyState, INTERNAL_OPTIONS); + const [videoWidth, setVideoWidth] = createSignal(player.videoWidth, INTERNAL_OPTIONS); + const [videoHeight, setVideoHeight] = createSignal(player.videoHeight, INTERNAL_OPTIONS); + + const syncReadyState = () => setReadyState(player.readyState); + const syncVideoDimensions = () => { + setVideoWidth(player.videoWidth); + setVideoHeight(player.videoHeight); + }; + + createEventListenerMap(player, { + volumechange: () => { + setVolumeSignal(player.volume); + setMutedSignal(player.muted); + }, + ratechange: () => setPlaybackRateSignal(player.playbackRate), + progress: () => setBuffered(player.buffered), + loadedmetadata: () => { + syncReadyState(); + syncVideoDimensions(); + }, + loadeddata: syncReadyState, + canplay: syncReadyState, + canplaythrough: syncReadyState, + emptied: syncReadyState, + resize: syncVideoDimensions, + }); + + return { + ...base, + volume, + setVolume, + muted, + setMuted, + playbackRate, + setPlaybackRate, + loop, + setLoop, + buffered, + readyState, + videoWidth, + videoHeight, + }; +}; diff --git a/packages/video/src/index.ts b/packages/video/src/index.ts new file mode 100644 index 000000000..9ea7e54aa --- /dev/null +++ b/packages/video/src/index.ts @@ -0,0 +1,12 @@ +export type { + VideoSource, + VideoEventHandlers, + VideoOptions, + VideoControlsOptions, + VideoControls, + VideoReturn, + VideoControlsReturn, +} from "./types.js"; + +export { makeVideo, setVideoSrc, createVideo } from "./createVideo.js"; +export { makeVideoPlayer, createVideoPlayer } from "./createVideoPlayer.js"; diff --git a/packages/video/src/types.ts b/packages/video/src/types.ts new file mode 100644 index 000000000..10685583f --- /dev/null +++ b/packages/video/src/types.ts @@ -0,0 +1,74 @@ +import type { Accessor } from "solid-js"; + +export type VideoSource = string | undefined | MediaProvider; + +export type VideoEventHandlers = { + [K in keyof HTMLVideoElementEventMap]?: (event: HTMLVideoElementEventMap[K]) => void; +}; + +/** Initial configuration applied to the video element on creation. */ +export type VideoOptions = { + autoPlay?: boolean; + loop?: boolean; + muted?: boolean; + preload?: "" | "none" | "metadata" | "auto"; +}; + +/** Extends `VideoOptions` with initial values for controls-level properties. */ +export type VideoControlsOptions = VideoOptions & { + /** Initial volume (0–1). Defaults to the browser default (1). */ + volume?: number; + /** Initial playback rate. Defaults to the browser default (1). */ + playbackRate?: number; +}; + +export type VideoControls = { + play: () => Promise; + pause: VoidFunction; + seek: (time: number) => void; + setVolume: (volume: number) => void; + setMuted: (muted: boolean) => void; + setPlaybackRate: (rate: number) => void; + setLoop: (loop: boolean) => void; + player: HTMLVideoElement; +}; + +/** Return type of `createVideo` — essential playback state. */ +export type VideoReturn = { + player: HTMLVideoElement; + /** `true` while the video is actively playing. */ + playing: Accessor; + setPlaying: (v: boolean) => void; + currentTime: Accessor; + seek: (time: number) => void; + /** `true` once playback has reached the end of the media. */ + ended: Accessor; + /** `true` while the player is seeking to a new position. */ + seeking: Accessor; + /** `MediaError` if the element has encountered a media error, otherwise `null`. */ + error: Accessor; + /** + * Throws `NotReadyError` until metadata has loaded (integrates with + * ``). After `loadedmetadata` fires, returns the duration in + * seconds reactively. Resets to pending whenever the source changes. + */ + duration: Accessor; +}; + +/** Return type of `createVideoPlayer` — extends `VideoReturn` with full media controls. */ +export type VideoControlsReturn = VideoReturn & { + volume: Accessor; + setVolume: (v: number) => void; + muted: Accessor; + setMuted: (v: boolean) => void; + playbackRate: Accessor; + setPlaybackRate: (rate: number) => void; + loop: Accessor; + setLoop: (v: boolean) => void; + /** The current `TimeRanges` of buffered media, or `undefined` before first progress. */ + buffered: Accessor; + /** `HTMLMediaElement.readyState` — 0 (HAVE_NOTHING) through 4 (HAVE_ENOUGH_DATA). */ + readyState: Accessor; + videoWidth: Accessor; + videoHeight: Accessor; +}; diff --git a/packages/video/stories/createVideo.stories.tsx b/packages/video/stories/createVideo.stories.tsx new file mode 100644 index 000000000..8ca9b2689 --- /dev/null +++ b/packages/video/stories/createVideo.stories.tsx @@ -0,0 +1,281 @@ +import { createSignal, For, Show } from "solid-js"; +import preview from "../../../.storybook/preview.js"; +import { createVideo, createVideoPlayer } from "@solid-primitives/video"; +import readme from "../README.md?raw"; +import { + Button, + ButtonRow, + Container, + Section, + BoolRow, + StatRow, + colors, + font, + radii, +} from "../../../.storybook/ui/index.js"; + +const meta = preview.meta({ + title: "Display & Media/Video", + tags: ["autodocs"], + parameters: { + layout: "centered", + docs: { + description: { + component: readme, + }, + }, + }, +}); + +export default meta; + +const VIDEO = "/video/big_buck_bunny_sall.mp4"; + +const fmt = (s: number) => + `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`; + +// duration() throws NotReadyError until metadata loads. Storybook's React-hosted +// docs page intercepts that throw before Solid's boundary can catch it, +// crashing the story. Try-catch here keeps the error contained in solid's reactive +// graph so Show can gate on readiness instead. +const safeDur = (dur: () => number): number | undefined => { + try { return dur(); } catch { return undefined; } +}; + +const SPEEDS = [0.5, 1, 1.5, 2] as const; + +export const PlaySeek = meta.story({ + name: "Play & seek", + parameters: { + docs: { + description: { + story: + "`createVideo` tracks `playing`, `currentTime`, `ended`, and `seeking` reactively. `duration` throws `NotReadyError` until metadata loads — use it with `` or a guarded accessor.", + }, + }, + }, + render: () => { + const video = createVideo(VIDEO, { preload: "metadata", muted: true }); + const dur = () => safeDur(video.duration); + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + +
+ + Loading… + } + > + video.seek(Number(e.currentTarget.value))} + style={{ flex: "1", "min-width": "0" }} + /> + + {fmt(video.currentTime())} / {fmt(dur()!)} + + +
+ +
+ + + +
+ + ); + }, +}); + +export const FullControls = meta.story({ + name: "Full control surface", + parameters: { + docs: { + description: { + story: + "`createVideoPlayer` exposes the full control surface: seek, `volume`, `muted`, `playbackRate`, and `loop`. All signals update reactively as you interact.", + }, + }, + }, + render: () => { + const video = createVideoPlayer(VIDEO, { preload: "metadata", muted: true }); + const dur = () => safeDur(video.duration); + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + + + + + + +
+ Loading…} + > + video.seek(Number(e.currentTarget.value))} + style={{ flex: "1", "min-width": "0" }} + /> + + {fmt(video.currentTime())} / {fmt(dur()!)} + + +
+ +
+ + video.setVolume(Number(e.currentTarget.value))} + disabled={video.muted()} + style={{ flex: "1" }} + /> + + {(video.volume() * 100).toFixed(0)}% + +
+ +
+ Speed +
+ + {s => ( + + )} + +
+
+ +
+ + + + + +
+ + ); + }, +}); + +const CLIPS = [ + { label: "Clip A", url: VIDEO }, + { label: "Clip B", url: `${VIDEO}?2` }, +]; + +export const ReactiveSource = meta.story({ + name: "Reactive source", + parameters: { + docs: { + description: { + story: + "Pass an accessor as `src` — when the signal changes, `createVideo` reconnects the player and resets `duration` to pending. Both clips use the same file; the distinct URL triggers the reactive reconnect.", + }, + }, + }, + render: () => { + const [idx, setIdx] = createSignal(0); + const video = createVideo(() => CLIPS[idx()]!.url, { preload: "metadata", muted: true }); + const dur = () => safeDur(video.duration); + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + + + + {(c, i) => ( + + )} + + + +
+ + + ⏳ Loading… + + } + > + + {fmt(video.currentTime())} / {fmt(dur()!)} + + +
+ + ); + }, +}); diff --git a/packages/video/stories/createVideoPlayer.stories.tsx b/packages/video/stories/createVideoPlayer.stories.tsx new file mode 100644 index 000000000..4ab74582f --- /dev/null +++ b/packages/video/stories/createVideoPlayer.stories.tsx @@ -0,0 +1,226 @@ +import { For } from "solid-js"; +import preview from "../../../.storybook/preview.js"; +import { createVideoPlayer } from "@solid-primitives/video"; +import { + Button, + ButtonRow, + Container, + Section, + BoolRow, + StatRow, + Progress, + colors, + font, + radii, +} from "../../../.storybook/ui/index.js"; + +const meta = preview.meta({ + title: "Display & Media/Video", + parameters: { + layout: "centered", + }, +}); + +export default meta; + +const VIDEO = "/video/big_buck_bunny_sall.mp4"; + +const fmt = (s: number) => + `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`; + +const SPEEDS = [0.5, 1, 1.5, 2] as const; + +export const VolumeAndMuted = meta.story({ + name: "Volume & muted", + parameters: { + docs: { + description: { + story: + "`createVideoPlayer` adds reactive `volume` and `muted` signals on top of `createVideo`. The slider and mute toggle update each other independently — muting preserves the volume level.", + }, + }, + }, + render: () => { + const video = createVideoPlayer(VIDEO, { preload: "metadata", muted: true }); + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + + + + + + +
+ + Volume + + video.setVolume(Number(e.currentTarget.value))} + disabled={video.muted()} + style={{ flex: "1" }} + /> + + {(video.volume() * 100).toFixed(0)}% + +
+ +
+ + +
+ + ); + }, +}); + +export const SpeedAndLoop = meta.story({ + name: "Speed & loop", + parameters: { + docs: { + description: { + story: + "`playbackRate` and `loop` are reactive signals on `createVideoPlayer`. Selecting a speed or toggling loop reflects back to the video element immediately.", + }, + }, + }, + render: () => { + const video = createVideoPlayer(VIDEO, { preload: "metadata", muted: true }); + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + + + + + + +
+ Speed +
+ + {s => ( + + )} + +
+
+ +
+ + +
+ + ); + }, +}); + +const READY_STATE = ["NOTHING", "METADATA", "CURRENT", "FUTURE", "ENOUGH"] as const; + +export const BufferAndDimensions = meta.story({ + name: "Buffer & dimensions", + parameters: { + docs: { + description: { + story: + "`createVideoPlayer` exposes `readyState`, `buffered`, and intrinsic `videoWidth`/`videoHeight`. Hit play to start buffering — `readyState` increments as data arrives.", + }, + }, + }, + render: () => { + const video = createVideoPlayer(VIDEO, { preload: "auto", muted: true }); + + const bufferedPct = () => { + const b = video.buffered(); + const d = video.player.duration; + if (!b || b.length === 0 || !d || !isFinite(d)) return 0; + return (b.end(b.length - 1) / d) * 100; + }; + + const bufferedLabel = () => { + const b = video.buffered(); + if (!b || b.length === 0) return "none"; + return `${b.start(0).toFixed(1)}–${b.end(b.length - 1).toFixed(1)}s`; + }; + + return ( + +
{ + video.player.style.cssText = "width:100%;display:block"; + el.appendChild(video.player); + }} + /> + + + + + +
+ Buffered + + + {bufferedLabel()} + +
+ +
+ + 0 ? `${video.videoWidth()} × ${video.videoHeight()}` : "—"} + /> +
+ + ); + }, +}); diff --git a/packages/video/stories/makeVideoPlayer.stories.tsx b/packages/video/stories/makeVideoPlayer.stories.tsx new file mode 100644 index 000000000..ea23e66ba --- /dev/null +++ b/packages/video/stories/makeVideoPlayer.stories.tsx @@ -0,0 +1,107 @@ +import { createSignal, Show } from "solid-js"; +import preview from "../../../.storybook/preview.js"; +import { makeVideoPlayer } from "@solid-primitives/video"; +import { + Button, + Container, + Section, + BoolRow, + StatRow, + colors, + font, + radii, +} from "../../../.storybook/ui/index.js"; + +const meta = preview.meta({ + title: "Display & Media/Video", + parameters: { + layout: "centered", + }, +}); + +export default meta; + +const VIDEO = "/video/big_buck_bunny_sall.mp4"; + +const fmt = (s: number) => + `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`; + +export const ImperativeControls = meta.story({ + name: "Imperative controls", + parameters: { + docs: { + description: { + story: + "`makeVideoPlayer` is non-reactive — it returns a plain controls object with no Solid owner required. Wire event handlers to pull state into signals only when needed.", + }, + }, + }, + render: () => { + const [playing, setPlaying] = createSignal(false); + const [currentTime, setCurrentTime] = createSignal(0); + const [duration, setDuration] = createSignal(0); + + const [controls] = makeVideoPlayer( + VIDEO, + { + playing: () => setPlaying(true), + pause: () => setPlaying(false), + ended: () => setPlaying(false), + timeupdate: () => setCurrentTime(controls.player.currentTime), + loadeddata: () => setDuration(controls.player.duration), + }, + { preload: "metadata", muted: true }, + ); + + return ( + +
{ + controls.player.style.cssText = "width:100%;display:block"; + el.appendChild(controls.player); + }} + /> + +
+ + + 0} + fallback={ + Loading… + } + > + controls.seek(Number(e.currentTarget.value))} + style={{ flex: "1", "min-width": "0" }} + /> + + {fmt(currentTime())} / {fmt(duration())} + + +
+ +
+ + +
+ + ); + }, +}); diff --git a/packages/video/test/index.test.ts b/packages/video/test/index.test.ts new file mode 100644 index 000000000..fcd555650 --- /dev/null +++ b/packages/video/test/index.test.ts @@ -0,0 +1,449 @@ +import "./setup"; +import { createRoot, createSignal, flush } from "solid-js"; +import { describe, expect, it } from "vitest"; +import { makeVideo, makeVideoPlayer, createVideo, createVideoPlayer, setVideoSrc } from "../src/index.js"; + +const testUrl = "https://example.com/clip.mp4"; + +/** Yield to the microtask queue — used alongside flush() to drain Solid 2.0 effects. */ +const tick = () => Promise.resolve(); + +// ── setVideoSrc ─────────────────────────────────────────────────────────────── + +describe("setVideoSrc", () => { + it("sets src and nulls srcObject when given a string", () => { + const el = document.createElement("video") as HTMLVideoElement; + el.srcObject = {} as MediaProvider; + setVideoSrc(el, "clip.mp4"); + expect(el.srcObject).toBeNull(); + expect(el.src).toMatch(/clip\.mp4$/); + }); + + it("sets srcObject and clears src when given a MediaProvider", () => { + const el = document.createElement("video") as HTMLVideoElement; + el.src = "clip.mp4"; + const provider = {} as MediaProvider; + setVideoSrc(el, provider); + expect(el.srcObject).toBe(provider); + expect(el.src).not.toMatch(/clip\.mp4$/); + }); +}); + +// ── makeVideo ───────────────────────────────────────────────────────────────── + +describe("makeVideo", () => { + it("returns a player and cleanup tuple", () => { + const [player, cleanup] = makeVideo(testUrl); + expect(player.src).toBe(testUrl); + expect(player._mock.paused).toBe(true); + cleanup(); + }); + + it("cleanup pauses the player and removes listeners", () => { + let fired = false; + const [player, cleanup] = makeVideo(testUrl, { play: () => (fired = true) }); + cleanup(); + player.dispatchEvent(new Event("play")); + expect(fired).toBe(false); + }); + + it("can be called outside a Solid owner", () => { + expect(() => { + const [, cleanup] = makeVideo(testUrl); + cleanup(); + }).not.toThrow(); + }); + + it("accepts MediaProvider as source", () => { + const [player, cleanup] = makeVideo({} as MediaProvider); + expect(typeof player.srcObject).toBe("object"); + cleanup(); + }); + + it("accepts an existing HTMLVideoElement", () => { + const el = document.createElement("video"); + el.src = testUrl; + const [player, cleanup] = makeVideo(el); + expect(player).toBe(el); + cleanup(); + }); + + it("applies VideoOptions to the player", () => { + const [player, cleanup] = makeVideo(testUrl, {}, { muted: true, loop: true }); + expect(player.muted).toBe(true); + expect(player.loop).toBe(true); + cleanup(); + }); +}); + +// ── makeVideoPlayer ─────────────────────────────────────────────────────────── + +describe("makeVideoPlayer", () => { + it("returns controls and cleanup tuple", () => { + const [controls, cleanup] = makeVideoPlayer(testUrl); + expect(controls.player.src).toBe(testUrl); + cleanup(); + }); + + it("play and pause work", async () => { + const [{ player, play, pause }, cleanup] = makeVideoPlayer(testUrl); + expect(player._mock.paused).toBe(true); + await play(); + expect(player._mock.paused).toBe(false); + pause(); + expect(player.paused).toBe(true); + cleanup(); + }); + + it("seek updates currentTime", () => { + const [{ player, seek }, cleanup] = makeVideoPlayer(testUrl); + seek(42); + expect(player.currentTime).toBe(42); + cleanup(); + }); + + it("setVolume updates volume", () => { + const [{ player, setVolume }, cleanup] = makeVideoPlayer(testUrl); + setVolume(0.5); + expect(player.volume).toBe(0.5); + cleanup(); + }); + + it("setMuted toggles muted", () => { + const [{ player, setMuted }, cleanup] = makeVideoPlayer(testUrl); + setMuted(true); + expect(player.muted).toBe(true); + setMuted(false); + expect(player.muted).toBe(false); + cleanup(); + }); + + it("setPlaybackRate changes rate", () => { + const [{ player, setPlaybackRate }, cleanup] = makeVideoPlayer(testUrl); + setPlaybackRate(1.5); + expect(player.playbackRate).toBe(1.5); + cleanup(); + }); + + it("setLoop changes loop", () => { + const [{ player, setLoop }, cleanup] = makeVideoPlayer(testUrl); + setLoop(true); + expect(player.loop).toBe(true); + cleanup(); + }); +}); + +// ── createVideo ─────────────────────────────────────────────────────────────── + +describe("createVideo", () => { + it("returns the expected shape", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(typeof video.playing).toBe("function"); + expect(typeof video.setPlaying).toBe("function"); + expect(typeof video.currentTime).toBe("function"); + expect(typeof video.seek).toBe("function"); + expect(typeof video.ended).toBe("function"); + expect(typeof video.seeking).toBe("function"); + expect(typeof video.error).toBe("function"); + expect(typeof video.duration).toBe("function"); + expect(video.player).toBeInstanceOf(HTMLVideoElement); + dispose(); + })); + + it("initial playing is false", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(video.playing()).toBe(false); + dispose(); + })); + + it("setPlaying(true) plays the video", () => + createRoot(async dispose => { + const video = createVideo(testUrl); + video.setPlaying(true); + await tick(); + flush(); + expect(video.player._mock.paused).toBe(false); + expect(video.playing()).toBe(true); + dispose(); + })); + + it("setPlaying(false) pauses the video", () => + createRoot(async dispose => { + const video = createVideo(testUrl); + video.setPlaying(true); + await tick(); + video.setPlaying(false); + await tick(); + expect(video.player.paused).toBe(true); + expect(video.playing()).toBe(false); + dispose(); + })); + + it("ended is false initially and true after ended event", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(video.ended()).toBe(false); + video.player.dispatchEvent(new Event("ended")); + flush(); + expect(video.ended()).toBe(true); + dispose(); + })); + + it("ended resets to false on play", () => + createRoot(async dispose => { + const video = createVideo(testUrl); + video.player.dispatchEvent(new Event("ended")); + flush(); + expect(video.ended()).toBe(true); + video.setPlaying(true); + await tick(); + flush(); + expect(video.ended()).toBe(false); + dispose(); + })); + + it("seeking is false initially, true during seek, false after seeked", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(video.seeking()).toBe(false); + video.player.dispatchEvent(new Event("seeking")); + flush(); + expect(video.seeking()).toBe(true); + video.player.dispatchEvent(new Event("seeked")); + flush(); + expect(video.seeking()).toBe(false); + dispose(); + })); + + it("error is null initially, set on error event, cleared on loadstart", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(video.error()).toBeNull(); + const mediaError = { code: 2, message: "MEDIA_ERR_NETWORK" } as MediaError; + video.player._mock.error = mediaError; + video.player.dispatchEvent(new Event("error")); + flush(); + expect(video.error()).toBe(mediaError); + video.player.dispatchEvent(new Event("loadstart")); + flush(); + expect(video.error()).toBeNull(); + dispose(); + })); + + it("duration throws before load, returns number after", () => + createRoot(dispose => { + const video = createVideo(testUrl); + expect(() => video.duration()).toThrow(); + video.player._mock._load(video.player); + flush(); + expect(typeof video.duration()).toBe("number"); + dispose(); + })); + + it("applies options to the player element", () => + createRoot(dispose => { + const video = createVideo(testUrl, { muted: true, loop: true }); + expect(video.player.muted).toBe(true); + expect(video.player.loop).toBe(true); + dispose(); + })); + + it("src accessor change updates player source", () => + createRoot(async dispose => { + const [src, setSrc] = createSignal("track1.mp4", { ownedWrite: true }); + const video = createVideo(src); + expect(video.player.src).toMatch(/track1\.mp4$/); + setSrc("track2.mp4"); + await tick(); + flush(); + expect(video.player.src).toMatch(/track2\.mp4$/); + dispose(); + })); + + it("dispose pauses the player", () => + createRoot(dispose => { + const video = createVideo(testUrl); + dispose(); + expect(video.player._mock.paused).toBe(true); + })); +}); + +// ── createVideoPlayer ─────────────────────────────────────────────────────── + +describe("createVideoPlayer", () => { + it("includes all VideoReturn fields plus controls fields", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + // base fields + expect(typeof video.playing).toBe("function"); + expect(typeof video.setPlaying).toBe("function"); + expect(typeof video.currentTime).toBe("function"); + expect(typeof video.seek).toBe("function"); + expect(typeof video.ended).toBe("function"); + expect(typeof video.seeking).toBe("function"); + expect(typeof video.error).toBe("function"); + expect(typeof video.duration).toBe("function"); + // controls fields + expect(typeof video.volume).toBe("function"); + expect(typeof video.setVolume).toBe("function"); + expect(typeof video.muted).toBe("function"); + expect(typeof video.setMuted).toBe("function"); + expect(typeof video.playbackRate).toBe("function"); + expect(typeof video.setPlaybackRate).toBe("function"); + expect(typeof video.loop).toBe("function"); + expect(typeof video.setLoop).toBe("function"); + expect(typeof video.buffered).toBe("function"); + expect(typeof video.readyState).toBe("function"); + expect(typeof video.videoWidth).toBe("function"); + expect(typeof video.videoHeight).toBe("function"); + expect(video.player).toBeInstanceOf(HTMLVideoElement); + dispose(); + })); + + it("initial volume is 1", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.volume()).toBe(1); + dispose(); + })); + + it("setVolume updates signal via volumechange event", () => + createRoot(async dispose => { + const video = createVideoPlayer(testUrl); + video.setVolume(0.4); + flush(); + await tick(); + expect(video.volume()).toBe(0.4); + dispose(); + })); + + it("initial muted is false", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.muted()).toBe(false); + dispose(); + })); + + it("setMuted updates signal via volumechange event", () => + createRoot(async dispose => { + const video = createVideoPlayer(testUrl); + video.setMuted(true); + flush(); + await tick(); + expect(video.muted()).toBe(true); + dispose(); + })); + + it("initial playbackRate is 1", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.playbackRate()).toBe(1); + dispose(); + })); + + it("setPlaybackRate updates signal via ratechange event", () => + createRoot(async dispose => { + const video = createVideoPlayer(testUrl); + video.setPlaybackRate(2); + flush(); + await tick(); + expect(video.playbackRate()).toBe(2); + dispose(); + })); + + it("initial loop is false", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.loop()).toBe(false); + dispose(); + })); + + it("setLoop updates both player.loop and signal (no DOM event)", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + video.setLoop(true); + expect(video.player.loop).toBe(true); // DOM update is synchronous + flush(); + expect(video.loop()).toBe(true); // signal update needs flush + dispose(); + })); + + it("readyState updates when video loads", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.readyState()).toBe(0); + video.player._mock._load(video.player); + flush(); + expect(video.readyState()).toBe(4); + dispose(); + })); + + it("videoWidth and videoHeight update after metadata loads", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.videoWidth()).toBe(0); + expect(video.videoHeight()).toBe(0); + video.player._mock._load(video.player); + flush(); + expect(video.videoWidth()).toBe(1280); + expect(video.videoHeight()).toBe(720); + dispose(); + })); + + it("buffered is undefined initially, defined after progress event", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.buffered()).toBeUndefined(); + video.player.dispatchEvent(new Event("progress")); + flush(); + expect(video.buffered()).toBeDefined(); + dispose(); + })); + + it("VideoControlsOptions sets initial volume and playbackRate", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl, { volume: 0.3, playbackRate: 1.5 }); + expect(video.volume()).toBe(0.3); + expect(video.playbackRate()).toBe(1.5); + dispose(); + })); + + it("VideoControlsOptions sets initial muted and loop via VideoOptions", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl, { muted: true, loop: true }); + expect(video.muted()).toBe(true); + expect(video.loop()).toBe(true); + dispose(); + })); + + it("inherits seeking state from createVideo", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.seeking()).toBe(false); + video.player.dispatchEvent(new Event("seeking")); + flush(); + expect(video.seeking()).toBe(true); + dispose(); + })); + + it("inherits error state from createVideo", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + expect(video.error()).toBeNull(); + const mediaError = { code: 2, message: "MEDIA_ERR_NETWORK" } as MediaError; + video.player._mock.error = mediaError; + video.player.dispatchEvent(new Event("error")); + flush(); + expect(video.error()).toBe(mediaError); + dispose(); + })); + + it("dispose pauses the player", () => + createRoot(dispose => { + const video = createVideoPlayer(testUrl); + dispose(); + expect(video.player._mock.paused).toBe(true); + })); +}); diff --git a/packages/video/test/server.test.ts b/packages/video/test/server.test.ts new file mode 100644 index 000000000..7edb09639 --- /dev/null +++ b/packages/video/test/server.test.ts @@ -0,0 +1,67 @@ +import { NotReadyError } from "solid-js"; +import { describe, expect, it } from "vitest"; +import { makeVideo, makeVideoPlayer, createVideo, createVideoPlayer } from "../src/index.js"; + +describe("API works in SSR", () => { + it("makeVideo() returns stub player and noop cleanup", () => { + const [player, cleanup] = makeVideo("https://example.com/clip.mp4"); + expect(player).toBeDefined(); + expect(cleanup).toBeInstanceOf(Function); + expect(() => cleanup()).not.toThrow(); + }); + + it("makeVideoPlayer() returns stub controls and noop cleanup", () => { + const [controls, cleanup] = makeVideoPlayer("https://example.com/clip.mp4"); + expect(controls.play).toBeInstanceOf(Function); + expect(controls.pause).toBeInstanceOf(Function); + expect(controls.seek).toBeInstanceOf(Function); + expect(controls.setVolume).toBeInstanceOf(Function); + expect(controls.setMuted).toBeInstanceOf(Function); + expect(controls.setPlaybackRate).toBeInstanceOf(Function); + expect(controls.setLoop).toBeInstanceOf(Function); + expect(() => cleanup()).not.toThrow(); + }); + + it("createVideo() returns safe stubs with correct initial values", () => { + const video = createVideo("https://example.com/clip.mp4"); + expect(video.playing()).toBe(false); + expect(video.currentTime()).toBe(0); + expect(video.ended()).toBe(false); + expect(video.seeking()).toBe(false); + expect(video.error()).toBeNull(); + expect(video.setPlaying).toBeInstanceOf(Function); + expect(video.seek).toBeInstanceOf(Function); + }); + + it("createVideo() duration throws NotReadyError on server", () => { + const video = createVideo("https://example.com/clip.mp4"); + expect(() => video.duration()).toThrow(NotReadyError); + }); + + it("createVideoPlayer() returns safe stubs with correct initial values", () => { + const video = createVideoPlayer("https://example.com/clip.mp4"); + expect(video.playing()).toBe(false); + expect(video.currentTime()).toBe(0); + expect(video.ended()).toBe(false); + expect(video.seeking()).toBe(false); + expect(video.error()).toBeNull(); + expect(video.volume()).toBe(1); + expect(video.muted()).toBe(false); + expect(video.playbackRate()).toBe(1); + expect(video.loop()).toBe(false); + expect(video.buffered()).toBeUndefined(); + expect(video.readyState()).toBe(0); + expect(video.videoWidth()).toBe(0); + expect(video.videoHeight()).toBe(0); + expect(video.setPlaying).toBeInstanceOf(Function); + expect(video.setVolume).toBeInstanceOf(Function); + expect(video.setMuted).toBeInstanceOf(Function); + expect(video.setPlaybackRate).toBeInstanceOf(Function); + expect(video.setLoop).toBeInstanceOf(Function); + }); + + it("createVideoPlayer() duration throws NotReadyError on server", () => { + const video = createVideoPlayer("https://example.com/clip.mp4"); + expect(() => video.duration()).toThrow(NotReadyError); + }); +}); diff --git a/packages/video/test/setup.ts b/packages/video/test/setup.ts new file mode 100644 index 000000000..3b83e6f55 --- /dev/null +++ b/packages/video/test/setup.ts @@ -0,0 +1,184 @@ +declare global { + interface HTMLVideoElement { + _mock: VideoMock; + } +} + +interface VideoMock { + paused: boolean; + currentTime: number; + duration: number; + src: string; + srcObject: MediaProvider | null; + buffered: TimeRanges; + volume: number; + muted: boolean; + playbackRate: number; + loop: boolean; + readyState: number; + videoWidth: number; + videoHeight: number; + error: MediaError | null; + _loaded: boolean; + _load: (video: HTMLVideoElement) => void; + _resetMock: (video: HTMLVideoElement) => void; +} + +// Each HTMLVideoElement instance gets its own mock state lazily on first access. +// This prevents prototype-level mutations from leaking between tests. + +const createMockState = (): VideoMock => ({ + paused: true, + currentTime: 0, + duration: NaN, + src: "", + srcObject: null, + buffered: { length: 0, start: () => 0, end: () => 0 } as unknown as TimeRanges, + volume: 1, + muted: false, + playbackRate: 1, + loop: false, + readyState: 0, + videoWidth: 0, + videoHeight: 0, + error: null, + _loaded: false, + _load(video: HTMLVideoElement) { + // Update mock values before dispatching events so listeners read correct state. + video._mock.duration = 120; + video._mock.readyState = 4; + video._mock.videoWidth = 1280; + video._mock.videoHeight = 720; + video._mock._loaded = true; + video.dispatchEvent(new Event("loadedmetadata")); + video.dispatchEvent(new Event("loadeddata")); + video.dispatchEvent(new Event("canplaythrough")); + }, + _resetMock(video: HTMLVideoElement) { + const fresh = createMockState(); + Object.assign(video._mock, fresh); + }, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "_mock", { + get(this: HTMLVideoElement) { + if (!Object.prototype.hasOwnProperty.call(this, "__video_mock__")) { + Object.defineProperty(this, "__video_mock__", { + value: createMockState(), + writable: true, + configurable: true, + }); + } + return (this as any).__video_mock__; + }, + set(this: HTMLVideoElement, v: VideoMock) { + Object.defineProperty(this, "__video_mock__", { + value: v, + writable: true, + configurable: true, + }); + }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "paused", { + get(this: HTMLVideoElement) { return this._mock.paused; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "duration", { + get(this: HTMLVideoElement) { return this._mock.duration; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "volume", { + get(this: HTMLVideoElement) { return this._mock.volume; }, + set(this: HTMLVideoElement, value: number) { + this._mock.volume = value; + this.dispatchEvent(new Event("volumechange")); + }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "muted", { + get(this: HTMLVideoElement) { return this._mock.muted; }, + set(this: HTMLVideoElement, value: boolean) { + this._mock.muted = value; + this.dispatchEvent(new Event("volumechange")); + }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "playbackRate", { + get(this: HTMLVideoElement) { return this._mock.playbackRate; }, + set(this: HTMLVideoElement, value: number) { + this._mock.playbackRate = value; + this.dispatchEvent(new Event("ratechange")); + }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "loop", { + get(this: HTMLVideoElement) { return this._mock.loop; }, + set(this: HTMLVideoElement, value: boolean) { this._mock.loop = value; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "readyState", { + get(this: HTMLVideoElement) { return this._mock.readyState; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "videoWidth", { + get(this: HTMLVideoElement) { return this._mock.videoWidth; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "videoHeight", { + get(this: HTMLVideoElement) { return this._mock.videoHeight; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "error", { + get(this: HTMLVideoElement) { return this._mock.error; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "currentTime", { + get(this: HTMLVideoElement) { return this._mock.currentTime; }, + set(this: HTMLVideoElement, value: number) { this._mock.currentTime = value; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "src", { + get(this: HTMLVideoElement) { return this._mock.src; }, + set(this: HTMLVideoElement, value: string) { this._mock.src = value; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "srcObject", { + get(this: HTMLVideoElement) { return this._mock.srcObject; }, + set(this: HTMLVideoElement, value: MediaProvider | null) { this._mock.srcObject = value; }, + configurable: true, +}); + +Object.defineProperty(global.HTMLVideoElement.prototype, "buffered", { + get(this: HTMLVideoElement) { return this._mock.buffered; }, + configurable: true, +}); + +global.HTMLVideoElement.prototype.play = async function playMock(this: HTMLVideoElement) { + if (!this._mock._loaded) { + this._mock._load(this); + } + this.dispatchEvent(new Event("play")); + this._mock.paused = false; + this.dispatchEvent(new Event("playing")); +}; + +global.HTMLVideoElement.prototype.pause = function pauseMock(this: HTMLVideoElement) { + this.dispatchEvent(new Event("pause")); + this._mock.paused = true; +}; + +export {}; diff --git a/packages/video/tsconfig.json b/packages/video/tsconfig.json new file mode 100644 index 000000000..b9b2b6782 --- /dev/null +++ b/packages/video/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "composite": true, + "outDir": "dist", + "rootDir": "src" + }, + "references": [ + { + "path": "../event-listener" + }, + { + "path": "../utils" + } + ], + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f21129fcd..404dea36f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@babel/core': specifier: ^7.27.0 - version: 7.29.0 + version: 7.27.4 '@changesets/cli': specifier: ^2.29.4 version: 2.29.4 @@ -43,7 +43,7 @@ importers: version: 8.34.0(eslint@9.28.0(jiti@1.21.7))(typescript@5.8.3) babel-preset-solid: specifier: 2.0.0-beta.14 - version: 2.0.0-beta.14(@babel/core@7.29.0)(solid-js@2.0.0-beta.14) + version: 2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14) esbuild: specifier: ^0.25.5 version: 0.25.5 @@ -61,7 +61,7 @@ importers: version: 3.3.0 geist: specifier: ^1.7.1 - version: 1.7.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8)) + version: 1.7.1(next@16.2.6(@babel/core@7.27.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8)) jsdom: specifier: ^25.0.1 version: 25.0.1 @@ -1133,6 +1133,22 @@ importers: specifier: 2.0.0-beta.14 version: 2.0.0-beta.14 + packages/video: + dependencies: + '@solid-primitives/event-listener': + specifier: workspace:^ + version: link:../event-listener + '@solid-primitives/utils': + 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: 2.0.0-beta.14 + version: 2.0.0-beta.14 + packages/virtual: dependencies: '@solid-primitives/utils': @@ -1141,13 +1157,13 @@ importers: devDependencies: '@babel/core': specifier: ^7.27.0 - version: 7.29.0 + version: 7.27.4 '@solidjs/web': specifier: 2.0.0-beta.14 version: 2.0.0-beta.14(solid-js@2.0.0-beta.14) babel-preset-solid: specifier: 2.0.0-beta.14 - version: 2.0.0-beta.14(@babel/core@7.29.0)(solid-js@2.0.0-beta.14) + version: 2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14) solid-js: specifier: 2.0.0-beta.14 version: 2.0.0-beta.14 @@ -1222,10 +1238,10 @@ importers: version: 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@tanstack/solid-router': 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) + 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.19(@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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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)) clsx: specifier: ^2.0.0 version: 2.1.1 @@ -1283,10 +1299,10 @@ importers: version: 4.0.0 vite: specifier: ^8.0.8 - version: 8.0.10(@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.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: 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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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))(@testing-library/jest-dom@6.9.1)(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)) packages: @@ -1297,6 +1313,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@ardatan/relay-compiler@12.0.0': resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==} hasBin: true @@ -1326,6 +1346,10 @@ packages: resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} engines: {node: '>=6.9.0'} + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} + engines: {node: '>=6.9.0'} + '@babel/core@7.29.0': resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} @@ -1342,6 +1366,10 @@ packages: resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.28.6': resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} @@ -1364,10 +1392,20 @@ packages: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.28.6': resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.28.6': resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} @@ -1382,6 +1420,10 @@ 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'} @@ -1408,6 +1450,10 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.29.2': resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} @@ -1459,6 +1505,12 @@ 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: @@ -1614,6 +1666,10 @@ packages: resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.27.4': + resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} @@ -2487,9 +2543,6 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -2737,6 +2790,9 @@ packages: '@oxc-project/types@0.127.0': resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + '@oxc-project/types@0.130.0': + resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} + '@oxc-resolver/binding-android-arm-eabi@11.19.1': resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} cpu: [arm] @@ -2874,97 +2930,97 @@ packages: '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} - '@rolldown/binding-android-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} + '@rolldown/binding-android-arm64@1.0.1': + resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} + '@rolldown/binding-darwin-arm64@1.0.1': + resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.17': - resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} + '@rolldown/binding-darwin-x64@1.0.1': + resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': - resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} + '@rolldown/binding-freebsd-x64@1.0.1': + resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': - resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} + '@rolldown/binding-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.1': + resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} + '@rolldown/binding-linux-s390x-gnu@1.0.1': + resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} + '@rolldown/binding-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} + '@rolldown/binding-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} + '@rolldown/binding-openharmony-arm64@1.0.1': + resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': - resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + '@rolldown/binding-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} + '@rolldown/binding-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} + '@rolldown/binding-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2972,8 +3028,8 @@ packages: '@rolldown/pluginutils@1.0.0-beta.40': resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} - '@rolldown/pluginutils@1.0.0-rc.17': - resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@rollup/rollup-android-arm-eabi@4.43.0': resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} @@ -3323,30 +3379,30 @@ packages: resolution: {integrity: sha512-nRcYw+w2OEgK6VfjirYvGyPLOK+tZQz1jkYcmH5AjMamQ9PycnlxZF2aEZtPpNoUsaceX2bHptn6Ub5hGXqNvw==} engines: {node: '>=20.19'} - '@tanstack/solid-router@2.0.0-beta.18': - resolution: {integrity: sha512-ASAazTBbX1LPp3Dm5LxhUAi02uzY3Ya7xzskEiqNEs85ArpQf5Q1PTECXT+vNydhdB6Ih3IN+Ylqhw9a+KhFOg==} + '@tanstack/solid-router@2.0.0-beta.17': + resolution: {integrity: sha512-NJyYMv/NNnsm4N93wi1E7WMHtf+194fpQAQzFlguyK66fHQQ9gbif0stFh2WK9tOAtD5uZjRUGTlRPrnTLzd1w==} engines: {node: '>=20.19'} hasBin: true peerDependencies: '@solidjs/web': '>=2.0.0-0 <3.0.0' solid-js: '>=2.0.0-0 <3.0.0' - '@tanstack/solid-start-client@2.0.0-beta.18': - resolution: {integrity: sha512-FACxOIdFAisLNnSUFX3yL3DixM3Us8cwRv12LnApPsw4YHxpDhR0zEjDLwWYpWX4Dm7xHchddRMFEmR4elFXGQ==} + '@tanstack/solid-start-client@2.0.0-beta.17': + resolution: {integrity: sha512-DwJ9PBN1zo0NbMy4k21hmahtkwc9sAy8UNd358SwjZj3X94OIsJR9NFOtzQgoEu+i0IkPZPvjqIvww66HFfFIw==} engines: {node: '>=22.12.0'} peerDependencies: '@solidjs/web': '>=2.0.0-0 <3.0.0' solid-js: '>=2.0.0-0 <3.0.0' - '@tanstack/solid-start-server@2.0.0-beta.18': - resolution: {integrity: sha512-CbGvWrg1tCq0WVrCCU5HoSi65N4o6K/lz+xJXr5xSh7BSKdeKlQifLs104bYM8wo9sTPMIegpa7F2HPR4bSMww==} + '@tanstack/solid-start-server@2.0.0-beta.17': + resolution: {integrity: sha512-4Lx04PiZ+LRJzEKQM+vNtK3D3uj1fhKbY+bb1VblVHMSdj5bLkUE1Yh63y2/9fL2uLCdmPKUTD4z6Ne8msUA6w==} engines: {node: '>=22.12.0'} peerDependencies: '@solidjs/web': '>=2.0.0-0 <3.0.0' solid-js: '>=2.0.0-0 <3.0.0' - '@tanstack/solid-start@2.0.0-beta.19': - resolution: {integrity: sha512-rZQnsAa3bmgGsUoaCf4whplAIDv85x1SeQKRAqF9k/NNhJ92gj1lu6JVsu6RHxeY1+6Z8NA9nF5Tj5Ef6R2+OA==} + '@tanstack/solid-start@2.0.0-beta.18': + resolution: {integrity: sha512-jQ1KzEoQFmU+wJ7btJ6QHVIDkeihXaW8kOJUq88AiBsPPrafDd+BfdrTQHH4XFLmRS6WEMtwmcUaSBx5BHhIWQ==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: @@ -3407,8 +3463,8 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -3759,8 +3815,13 @@ packages: babel-dead-code-elimination@1.0.12: resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - babel-plugin-jsx-dom-expressions@0.39.8: - resolution: {integrity: sha512-/MVOIIjonylDXnrWmG23ZX82m9mtKATsVHB7zYlPfDR9Vdd/NBE48if+wv27bSkBtyO7EPMUlcUc4J63QwuACQ==} + 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==} peerDependencies: '@babel/core': ^7.20.12 @@ -3777,10 +3838,23 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - babel-preset-solid@1.9.6: - resolution: {integrity: sha512-HXTK9f93QxoH8dYn1M2mJdOlWgMsR88Lg/ul6QCZGkNTktjTE5HAf93YxQumHoCudLEtZrU1cFCMFOVho6GqFg==} + babel-preset-solid@1.9.12: + resolution: {integrity: sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==} 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==} @@ -4854,8 +4928,8 @@ packages: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} - isbot@5.1.39: - resolution: {integrity: sha512-obH0yYahGXdzNxo+djmHhBYThUKDkz565cxkIlt2L9hXfv1NlaLKoDBHo6KxXsYrIXx2RK3x5vY36CfZcobxEw==} + isbot@5.1.40: + resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} engines: {node: '>=18'} isexe@2.0.0: @@ -5663,8 +5737,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.13: - resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} postcss@8.5.5: @@ -5791,10 +5865,6 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -5913,8 +5983,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown@1.0.0-rc.17: - resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} + rolldown@1.0.1: + resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -5990,8 +6060,8 @@ packages: peerDependencies: seroval: ^1.0 - seroval-plugins@1.5.2: - resolution: {integrity: sha512-qpY0Cl+fKYFn4GOf3cMiq6l72CpuVaawb6ILjubOQ+diJ54LfOWaSSPsaswN8DRPIPW4Yq+tE1k5aKd7ILyaFg==} + seroval-plugins@1.5.4: + resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 @@ -6000,8 +6070,8 @@ packages: resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} engines: {node: '>=10'} - seroval@1.5.2: - resolution: {integrity: sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==} + seroval@1.5.4: + resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} engines: {node: '>=10'} set-blocking@2.0.0: @@ -6455,8 +6525,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - validate-html-nesting@1.2.2: - resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} + validate-html-nesting@1.2.4: + resolution: {integrity: sha512-doQi7e8EJ2OWneSG1aZpJluS6A49aZM0+EICXWKm1i6WvqTLmq0tpUcImc4KTWG50mORO0C4YDBtOCSYvElftw==} value-or-promise@1.0.12: resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} @@ -6555,13 +6625,13 @@ packages: yaml: optional: true - vite@8.0.10: - resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} + vite@8.0.13: + resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -6784,6 +6854,11 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + '@ardatan/relay-compiler@12.0.0(graphql@16.9.0)': dependencies: '@babel/core': 7.29.0 @@ -6838,6 +6913,26 @@ snapshots: '@babel/compat-data@7.29.3': {} + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/core@7.29.0': dependencies: '@babel/code-frame': 7.29.0 @@ -6878,6 +6973,14 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.27.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.0 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-compilation-targets@7.28.6': dependencies: '@babel/compat-data': 7.29.3 @@ -6886,6 +6989,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@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.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 @@ -6912,6 +7028,13 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.28.6': dependencies: '@babel/traverse': 7.29.0 @@ -6919,6 +7042,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@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.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 @@ -6934,6 +7075,17 @@ snapshots: '@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 @@ -6958,6 +7110,11 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} + '@babel/helpers@7.27.6': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + '@babel/helpers@7.29.2': dependencies: '@babel/template': 7.28.6 @@ -6965,7 +7122,7 @@ snapshots: '@babel/parser@7.27.5': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.27.6 '@babel/parser@7.29.3': dependencies: @@ -6975,42 +7132,57 @@ snapshots: 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.27.1 + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.29.0)': dependencies: - '@babel/compat-data': 7.27.5 + '@babel/compat-data': 7.29.3 '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@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)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.27.1(@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.28.6(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.29.0)': @@ -7021,24 +7193,24 @@ snapshots: '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-classes@7.25.0(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-compilation-targets': 7.28.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.29.0) '@babel/traverse': 7.29.0 globals: 11.12.0 @@ -7048,24 +7220,24 @@ snapshots: '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/template': 7.28.6 '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.29.0) '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color @@ -7074,7 +7246,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -7082,17 +7254,25 @@ snapshots: '@babel/plugin-transform-literals@7.25.2(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -7100,7 +7280,7 @@ snapshots: '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.29.0) transitivePeerDependencies: - supports-color @@ -7108,25 +7288,25 @@ snapshots: '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -7134,12 +7314,12 @@ snapshots: '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-transform-spread@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color @@ -7147,27 +7327,27 @@ snapshots: '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-typescript@7.27.1(@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-create-class-features-plugin': 7.27.1(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.27.1(@babel/core@7.29.0)': + '@babel/preset-typescript@7.27.1(@babel/core@7.27.4)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.4) transitivePeerDependencies: - supports-color @@ -7185,6 +7365,18 @@ snapshots: '@babel/parser': 7.29.3 '@babel/types': 7.29.0 + '@babel/traverse@7.27.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + debug: 4.4.1 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + '@babel/traverse@7.29.0': dependencies: '@babel/code-frame': 7.29.0 @@ -8162,7 +8354,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/gen-mapping@0.3.8': @@ -8182,8 +8374,6 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -8192,7 +8382,7 @@ snapshots: '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.5.0 '@kamilkisiela/fast-url-parser@1.1.4': {} @@ -8212,24 +8402,24 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@mdx-js/react@3.1.1(@types/react@19.2.15)(react@19.2.5)': + '@mdx-js/react@3.1.1(@types/react@19.2.15)(react@19.2.6)': dependencies: '@types/mdx': 2.0.13 '@types/react': 19.2.15 - react: 19.2.5 + react: 19.2.6 '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.2 optional: true '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.2 optional: true '@next/env@16.2.6': {} @@ -8357,6 +8547,8 @@ snapshots: '@oxc-project/types@0.127.0': {} + '@oxc-project/types@0.130.0': {} + '@oxc-resolver/binding-android-arm-eabi@11.19.1': optional: true @@ -8454,58 +8646,58 @@ snapshots: '@repeaterjs/repeater@3.0.6': {} - '@rolldown/binding-android-arm64@1.0.0-rc.17': + '@rolldown/binding-android-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + '@rolldown/binding-darwin-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.17': + '@rolldown/binding-darwin-x64@1.0.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + '@rolldown/binding-freebsd-x64@1.0.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-musl@1.0.1': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-ppc64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-s390x-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-x64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-x64-musl@1.0.1': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + '@rolldown/binding-openharmony-arm64@1.0.1': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + '@rolldown/binding-wasm32-wasi@1.0.1': 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.0-rc.17': + '@rolldown/binding-win32-arm64-msvc@1.0.1': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + '@rolldown/binding-win32-x64-msvc@1.0.1': optional: true '@rolldown/pluginutils@1.0.0-beta.40': {} - '@rolldown/pluginutils@1.0.0-rc.17': {} + '@rolldown/pluginutils@1.0.1': {} '@rollup/rollup-android-arm-eabi@4.43.0': optional: true @@ -8702,30 +8894,30 @@ snapshots: '@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.13)': dependencies: - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-js: 2.0.0-beta.13 '@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14)': dependencies: - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-js: 2.0.0-beta.14 '@solidjs/web@2.0.0-beta.14(solid-js@2.0.0-beta.14)': dependencies: - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-js: 2.0.0-beta.14 '@storybook/addon-docs@10.4.1(@types/react@19.2.15)(esbuild@0.25.5)(rollup@4.43.0)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.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))': dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.15)(react@19.2.5) + '@mdx-js/react': 3.1.1(@types/react@19.2.15)(react@19.2.6) '@storybook/csf-plugin': 10.4.1(esbuild@0.25.5)(rollup@4.43.0)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.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)) - '@storybook/icons': 2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.5) - '@storybook/react-dom-shim': 10.4.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.5)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) + '@storybook/icons': 2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@storybook/react-dom-shim': 10.4.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) storybook: 10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) ts-dedent: 2.2.0 optionalDependencies: @@ -8759,19 +8951,14 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.5)': - dependencies: - react: 19.2.5 - react-dom: 19.2.6(react@19.2.6) - '@storybook/icons@2.0.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - '@storybook/react-dom-shim@10.4.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.5)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))': + '@storybook/react-dom-shim@10.4.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))': dependencies: - react: 19.2.5 + react: 19.2.6 react-dom: 19.2.6(react@19.2.6) storybook: 10.4.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@testing-library/dom@10.4.1)(@types/react@19.2.15)(prettier@3.5.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: @@ -8841,8 +9028,8 @@ snapshots: dependencies: '@tanstack/history': 1.161.6 cookie-es: 2.0.0 - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) '@tanstack/router-generator@1.166.24': dependencies: @@ -8857,10 +9044,10 @@ snapshots: 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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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))': dependencies: '@babel/core': 7.29.0 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.0) '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 @@ -8873,8 +9060,8 @@ snapshots: unplugin: 2.3.5 zod: 3.25.63 optionalDependencies: - vite: 8.0.10(@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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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) + vite-plugin-solid: 3.0.0-next.5(@solidjs/web@2.0.0-beta.13(solid-js@2.0.0-beta.14))(@testing-library/jest-dom@6.9.1)(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)) transitivePeerDependencies: - supports-color @@ -8892,49 +9079,49 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/solid-router@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)': + '@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)': dependencies: '@solid-devtools/logger': 0.9.11(solid-js@2.0.0-beta.14) '@solidjs/meta': 0.29.4(solid-js@2.0.0-beta.14) '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@tanstack/history': 1.161.6 '@tanstack/router-core': 1.168.9 - isbot: 5.1.39 + isbot: 5.1.40 solid-js: 2.0.0-beta.14 - '@tanstack/solid-start-client@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)': + '@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)': dependencies: '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@tanstack/router-core': 1.168.9 - '@tanstack/solid-router': 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) + '@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/start-client-core': 1.167.9 solid-js: 2.0.0-beta.14 - '@tanstack/solid-start-server@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)': + '@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)': dependencies: '@solidjs/meta': 0.29.4(solid-js@2.0.0-beta.14) '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) '@tanstack/history': 1.161.6 '@tanstack/router-core': 1.168.9 - '@tanstack/solid-router': 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) + '@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/start-client-core': 1.167.9 '@tanstack/start-server-core': 1.167.9 solid-js: 2.0.0-beta.14 transitivePeerDependencies: - crossws - '@tanstack/solid-start@2.0.0-beta.19(@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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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))': dependencies: '@solidjs/web': 2.0.0-beta.13(solid-js@2.0.0-beta.14) - '@tanstack/solid-router': 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) - '@tanstack/solid-start-client': 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) - '@tanstack/solid-start-server': 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) + '@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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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-server-core': 1.167.9 pathe: 2.0.3 solid-js: 2.0.0-beta.14 - vite: 8.0.10(@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) transitivePeerDependencies: - '@rsbuild/core' - '@tanstack/react-router' @@ -8948,11 +9135,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.2 + seroval: 1.5.4 '@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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.29.0 @@ -8960,7 +9147,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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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.10(@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))(@testing-library/jest-dom@6.9.1)(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-utils': 1.161.6 '@tanstack/start-client-core': 1.167.9 '@tanstack/start-server-core': 1.167.9 @@ -8972,8 +9159,8 @@ snapshots: srvx: 0.11.15 tinyglobby: 0.2.16 ufo: 1.6.1 - vite: 8.0.10(@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.10(@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) + 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)) xmlbuilder2: 4.0.3 zod: 3.25.63 transitivePeerDependencies: @@ -8991,7 +9178,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.2 + seroval: 1.5.4 transitivePeerDependencies: - crossws @@ -9033,7 +9220,7 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true @@ -9450,25 +9637,34 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-jsx-dom-expressions@0.39.8(@babel/core@7.29.0): + babel-plugin-jsx-dom-expressions@0.40.7(@babel/core@7.27.4): dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) + '@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 - validate-html-nesting: 1.2.2 - babel-plugin-jsx-dom-expressions@0.50.0-next.13(@babel/core@7.29.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.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + html-entities: 2.3.3 + parse5: 7.3.0 + validate-html-nesting: 1.2.4 + + 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 html-entities: 2.3.3 parse5: 7.3.0 - validate-html-nesting: 1.2.2 + validate-html-nesting: 1.2.4 babel-plugin-jsx-dom-expressions@0.50.0-next.13(@babel/core@7.29.0): dependencies: @@ -9489,7 +9685,7 @@ snapshots: '@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.27.1(@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) @@ -9515,15 +9711,24 @@ snapshots: transitivePeerDependencies: - supports-color - babel-preset-solid@1.9.6(@babel/core@7.29.0): + babel-preset-solid@1.9.12(@babel/core@7.27.4)(solid-js@2.0.0-beta.14): dependencies: - '@babel/core': 7.29.0 - babel-plugin-jsx-dom-expressions: 0.39.8(@babel/core@7.29.0) + '@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.14(@babel/core@7.29.0)(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.13(@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-preset-solid@2.0.0-beta.14(@babel/core@7.27.4)(solid-js@2.0.0-beta.14): + dependencies: + '@babel/core': 7.27.4 + babel-plugin-jsx-dom-expressions: 0.50.0-next.13(@babel/core@7.27.4) optionalDependencies: solid-js: 2.0.0-beta.14 @@ -10023,9 +10228,9 @@ snapshots: esbuild-plugin-solid@0.6.0(esbuild@0.25.5)(solid-js@2.0.0-beta.14): dependencies: - '@babel/core': 7.29.0 - '@babel/preset-typescript': 7.27.1(@babel/core@7.29.0) - babel-preset-solid: 1.9.6(@babel/core@7.29.0) + '@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) esbuild: 0.25.5 solid-js: 2.0.0-beta.14 transitivePeerDependencies: @@ -10320,9 +10525,9 @@ snapshots: fuse.js@7.0.0: {} - geist@1.7.1(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8)): + geist@1.7.1(next@16.2.6(@babel/core@7.27.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8)): dependencies: - next: 16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8) + next: 16.2.6(@babel/core@7.27.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8) gensync@1.0.0-beta.2: {} @@ -10674,7 +10879,7 @@ snapshots: dependencies: is-inside-container: 1.0.0 - isbot@5.1.39: {} + isbot@5.1.40: {} isexe@2.0.0: {} @@ -11283,7 +11488,7 @@ snapshots: natural-compare@1.4.0: {} - next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8): + next@16.2.6(@babel/core@7.27.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.8): dependencies: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 @@ -11292,7 +11497,7 @@ snapshots: postcss: 8.4.31 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.6) + styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.2.6) optionalDependencies: '@next/swc-darwin-arm64': 16.2.6 '@next/swc-darwin-x64': 16.2.6 @@ -11662,7 +11867,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.13: + postcss@8.5.14: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -11723,11 +11928,6 @@ snapshots: dependencies: typescript: 5.8.3 - react-dom@19.2.6(react@19.2.5): - dependencies: - react: 19.2.5 - scheduler: 0.27.0 - react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 @@ -11735,8 +11935,6 @@ snapshots: react-is@17.0.2: {} - react@19.2.5: {} - react@19.2.6: {} read-cache@1.0.0: @@ -11905,26 +12103,26 @@ snapshots: rfdc@1.4.1: {} - rolldown@1.0.0-rc.17: + rolldown@1.0.1: dependencies: - '@oxc-project/types': 0.127.0 - '@rolldown/pluginutils': 1.0.0-rc.17 + '@oxc-project/types': 0.130.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-x64': 1.0.0-rc.17 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 + '@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 rollup@4.43.0: dependencies: @@ -12004,13 +12202,13 @@ snapshots: dependencies: seroval: 1.3.2 - seroval-plugins@1.5.2(seroval@1.5.2): + seroval-plugins@1.5.4(seroval@1.5.4): dependencies: - seroval: 1.5.2 + seroval: 1.5.4 seroval@1.3.2: {} - seroval@1.5.2: {} + seroval@1.5.4: {} set-blocking@2.0.0: {} @@ -12101,22 +12299,22 @@ snapshots: dependencies: '@solidjs/signals': 2.0.0-beta.14 csstype: 3.1.3 - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-js@2.0.0-beta.13: dependencies: '@solidjs/signals': 2.0.0-beta.14 csstype: 3.1.3 - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-js@2.0.0-beta.14: dependencies: '@solidjs/signals': 2.0.0-beta.14 csstype: 3.1.3 - seroval: 1.5.2 - seroval-plugins: 1.5.2(seroval@1.5.2) + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) solid-refresh@0.8.0-next.7(solid-js@2.0.0-beta.14): dependencies: @@ -12249,12 +12447,12 @@ snapshots: strip-json-comments@3.1.1: {} - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.6): + styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.2.6): dependencies: client-only: 0.0.1 react: 19.2.6 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.27.4 sucrase@3.35.0: dependencies: @@ -12535,7 +12733,7 @@ snapshots: util-deprecate@1.0.2: {} - validate-html-nesting@1.2.2: {} + validate-html-nesting@1.2.4: {} value-or-promise@1.0.12: {} @@ -12567,17 +12765,17 @@ 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))(@testing-library/jest-dom@6.9.1)(solid-js@2.0.0-beta.14)(vite@8.0.10(@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))(@testing-library/jest-dom@6.9.1)(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)): dependencies: '@babel/core': 7.29.0 '@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.14(@babel/core@7.29.0)(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) 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.10(@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.10(@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) + 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)) optionalDependencies: '@testing-library/jest-dom': 6.9.1 transitivePeerDependencies: @@ -12588,7 +12786,7 @@ snapshots: '@babel/core': 7.29.0 '@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.14(@babel/core@7.29.0)(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) 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) @@ -12627,12 +12825,12 @@ snapshots: tsx: 4.20.2 yaml: 2.5.0 - vite@8.0.10(@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): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.13 - rolldown: 1.0.0-rc.17 + postcss: 8.5.14 + rolldown: 1.0.1 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 22.15.31 @@ -12647,9 +12845,9 @@ snapshots: 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.10(@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)): optionalDependencies: - vite: 8.0.10(@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) vitest@2.1.9(@types/node@22.15.31)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.77.8): dependencies: