diff --git a/package.json b/package.json index c51af9d..5c3a988 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scrolloop", - "version": "0.4.0", + "version": "0.5.0", "repository": { "type": "git", "url": "git+https://github.com/976520/scrolloop.git" diff --git a/packages/core/src/virtualizer/Virtualizer.ts b/packages/core/src/virtualizer/Virtualizer.ts index 93bf51e..2daecaa 100644 --- a/packages/core/src/virtualizer/Virtualizer.ts +++ b/packages/core/src/virtualizer/Virtualizer.ts @@ -11,16 +11,16 @@ export class Virtualizer { #count: number; readonly #overscan: number; #plugins: Plugin[]; - readonly #onChange?: (state: VirtualizerState) => void; + readonly #onChange: ((state: VirtualizerState) => void) | undefined; readonly #layoutStrategy: LayoutStrategy; readonly #scrollSource: ScrollSource; #state: VirtualizerState; - readonly #unsubscribe?: () => void; + readonly #unsubscribe: (() => void) | undefined; - #prevRenderRange?: { startIndex: number; endIndex: number }; - #prevVirtualItems?: VirtualItem[]; + #prevRenderRange: { startIndex: number; endIndex: number } | undefined; + #prevVirtualItems: VirtualItem[] | undefined; constructor( layoutStrategy: LayoutStrategy, diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 9342ef0..04870e0 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,7 +4,10 @@ "outDir": "./dist", "declaration": true, "declarationMap": true, - "types": ["vitest/globals"] + "types": ["vitest/globals"], + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noImplicitOverride": true }, "include": ["src/**/*", "tsup.config.ts"], "exclude": ["node_modules", "dist", "**/*.test.ts"] diff --git a/packages/react-native/src/components/InfiniteList.tsx b/packages/react-native/src/components/InfiniteList.tsx index 6661ac6..905f975 100644 --- a/packages/react-native/src/components/InfiniteList.tsx +++ b/packages/react-native/src/components/InfiniteList.tsx @@ -57,19 +57,20 @@ function InfiniteListInner(props: InfiniteListProps) { ]); const handleRangeChange = (range: Range) => { - const prefetchStart = Math.max( - 0, - Math.floor(range.startIndex / pageSize) - - Math.floor(range.endIndex / pageSize) - ); + const prefetchStart = Math.floor(range.startIndex / pageSize); const prefetchEnd = Math.floor(range.endIndex / pageSize) + prefetchThreshold + Math.ceil(overscan / pageSize); - findMissingPages(prefetchStart, prefetchEnd, pages, loadingPages); + const missingPages = findMissingPages( + prefetchStart, + prefetchEnd, + pages, + loadingPages + ); - for (let page = prefetchStart; page <= prefetchEnd; page++) { + for (const page of missingPages) { loadPage(page); } }; diff --git a/packages/react/src/components/InfiniteList.tsx b/packages/react/src/components/InfiniteList.tsx index 977d6ef..f4c3beb 100644 --- a/packages/react/src/components/InfiniteList.tsx +++ b/packages/react/src/components/InfiniteList.tsx @@ -130,16 +130,13 @@ function InfiniteListInner(props: InfiniteListProps) { scrollTopRef.current = containerRef.current?.scrollTop ?? 0; return; } - const ps = Math.max( - 0, - ((range.startIndex / pageSize) | 0) - ((range.endIndex / pageSize) | 0) - ); + const ps = (range.startIndex / pageSize) | 0; const pe = ((range.endIndex / pageSize) | 0) + prefetchThreshold + Math.ceil(overscan / pageSize); - findMissingPages(ps, pe, mergedPages, loadingPages); - for (let p = ps; p <= pe; p++) loadPage(p); + const missingPages = findMissingPages(ps, pe, mergedPages, loadingPages); + for (const p of missingPages) loadPage(p); }, [ isServerSide, diff --git a/packages/react/src/hooks/useInfinitePages.ts b/packages/react/src/hooks/useInfinitePages.ts deleted file mode 100644 index 8ac4443..0000000 --- a/packages/react/src/hooks/useInfinitePages.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { useState, useCallback, useRef, useMemo } from "react"; -import type { PageResponse } from "../types"; -import { canLoadPage } from "../utils/canLoadPage"; - -interface UseInfinitePagesOptions { - fetchPage: (page: number, size: number) => Promise>; - pageSize: number; - initialPage: number; - onPageLoad?: (page: number, items: T[]) => void; - onError?: (error: Error) => void; -} - -export function useInfinitePages({ - fetchPage, - pageSize, - initialPage, - onPageLoad, - onError, -}: UseInfinitePagesOptions) { - const [pages, setPages] = useState>(new Map()); - const [loadingPages, setLoadingPages] = useState>(new Set()); - const [total, setTotal] = useState(0); - const [hasMore, setHasMore] = useState(true); - const [error, setError] = useState(null); - const abortControllersRef = useRef>(new Map()); - - const allItems = useMemo(() => { - const items: (T | undefined)[] = new Array(total); - pages.forEach((pageItems, pageNum) => { - const startIndex = pageNum * pageSize; - pageItems.forEach((item, i) => { - items[startIndex + i] = item; - }); - }); - return items; - }, [pages, total, pageSize]); - - const loadPage = useCallback( - async (page: number) => { - if (!canLoadPage(page, pages, loadingPages, total, pageSize, hasMore)) return; - - setLoadingPages((prev) => new Set(prev).add(page)); - setError(null); - - const controller = new AbortController(); - abortControllersRef.current.set(page, controller); - - try { - const response = await fetchPage(page, pageSize); - - if (controller.signal.aborted) return; - - setPages((prev) => new Map(prev).set(page, response.items)); - setTotal(response.total); - setHasMore(response.hasMore); - onPageLoad?.(page, response.items); - } catch (err) { - if (controller.signal.aborted) return; - - const error = err instanceof Error ? err : new Error(String(err)); - setError(error); - onError?.(error); - } finally { - setLoadingPages((prev) => { - const next = new Set(prev); - next.delete(page); - return next; - }); - abortControllersRef.current.delete(page); - } - }, - [pages, loadingPages, hasMore, total, pageSize, fetchPage, onPageLoad, onError] - ); - - const retry = useCallback(() => { - setError(null); - loadPage(initialPage); - }, [loadPage, initialPage]); - - const reset = useCallback(() => { - abortControllersRef.current.forEach((controller) => controller.abort()); - abortControllersRef.current.clear(); - - setPages(new Map()); - setLoadingPages(new Set()); - setTotal(0); - setHasMore(true); - setError(null); - }, []); - - return { - allItems, - pages, - loadingPages, - total, - hasMore, - error, - loadPage, - retry, - reset, - }; -} - diff --git a/packages/react/src/utils/canLoadPage.ts b/packages/react/src/utils/canLoadPage.ts deleted file mode 100644 index 8c1890c..0000000 --- a/packages/react/src/utils/canLoadPage.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function canLoadPage( - page: number, - pages: Map, - loadingPages: Set, - total: number, - pageSize: number, - hasMore: boolean -): boolean { - if (pages.has(page) || loadingPages.has(page)) return false; - - if (total > 0 && page * pageSize >= total) return false; - - if (!hasMore && page > Math.floor(total / pageSize)) return false; - - return true; -} - diff --git a/packages/react/src/utils/findMissingPages.ts b/packages/react/src/utils/findMissingPages.ts deleted file mode 100644 index 4008c00..0000000 --- a/packages/react/src/utils/findMissingPages.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function findMissingPages( - prefetchStart: number, - prefetchEnd: number, - pages: Map, - loadingPages: Set -): number[] { - const missingPages: number[] = []; - for (let p = prefetchStart; p <= prefetchEnd; p++) { - if (!pages.has(p) && !loadingPages.has(p)) missingPages.push(p); - } - return missingPages; -} - diff --git a/packages/shared/package.json b/packages/shared/package.json index 5fa038e..b9c21f5 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -34,6 +34,9 @@ "react": ">=18.0.0" }, "devDependencies": { + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^14.3.1", + "jsdom": "^24.1.3", "react": "^18.2.0", "tsup": "^8.0.0", "typescript": "^5.0.0", diff --git a/packages/shared/src/InfiniteSource.test.ts b/packages/shared/src/InfiniteSource.test.ts new file mode 100644 index 0000000..0a8a35a --- /dev/null +++ b/packages/shared/src/InfiniteSource.test.ts @@ -0,0 +1,361 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { InfiniteSource } from "./InfiniteSource"; +import type { InfiniteSourceOptions } from "./InfiniteSource"; +import type { PageResponse } from "./types"; + +describe("InfiniteSource", () => { + const mockFetchPage = + vi.fn< + (page: number, size: number) => Promise> + >(); + + beforeEach(() => { + mockFetchPage.mockClear(); + }); + + function makeManager( + overrides?: Partial> + ) { + return new InfiniteSource({ + fetchPage: mockFetchPage, + pageSize: 20, + initialPage: 0, + ...overrides, + }); + } + + it("initializes with empty state", () => { + const manager = makeManager(); + const state = manager.getState(); + + expect(state.pages.size).toBe(0); + expect(state.loadingPages.size).toBe(0); + expect(state.total).toBe(0); + expect(state.hasMore).toBe(true); + expect(state.error).toBeNull(); + expect(state.allItems).toEqual([]); + }); + + it("loads page successfully", async () => { + const mockData = Array(20) + .fill(0) + .map((_, i) => ({ id: i })); + + mockFetchPage.mockResolvedValue({ + items: mockData, + total: 100, + hasMore: true, + }); + + const manager = makeManager(); + await manager.loadPage(0); + + const state = manager.getState(); + expect(state.pages.size).toBe(1); + expect(state.pages.get(0)).toEqual(mockData); + expect(state.total).toBe(100); + expect(state.hasMore).toBe(true); + expect(mockFetchPage).toHaveBeenCalledWith(0, 20); + }); + + it("prevents duplicate page loads", async () => { + mockFetchPage.mockResolvedValue({ + items: Array(20).fill({ id: 0 }), + total: 100, + hasMore: true, + }); + + const manager = makeManager(); + await manager.loadPage(0); + + mockFetchPage.mockClear(); + await manager.loadPage(0); + + expect(mockFetchPage).not.toHaveBeenCalled(); + }); + + it("handles fetch error", async () => { + const error = new Error("Failed to fetch"); + mockFetchPage.mockRejectedValue(error); + + const manager = makeManager(); + await manager.loadPage(0); + + const state = manager.getState(); + expect(state.error?.message).toBe("Failed to fetch"); + expect(state.pages.size).toBe(0); + }); + + it("calls onPageLoad callback", async () => { + const onPageLoad = vi.fn(); + const mockData = Array(20) + .fill(0) + .map((_, i) => ({ id: i })); + + mockFetchPage.mockResolvedValue({ + items: mockData, + total: 100, + hasMore: true, + }); + + const manager = makeManager({ onPageLoad }); + await manager.loadPage(0); + + expect(onPageLoad).toHaveBeenCalledWith(0, mockData); + }); + + it("calls onError callback", async () => { + const onError = vi.fn(); + mockFetchPage.mockRejectedValue(new Error("Failed")); + + const manager = makeManager({ onError }); + await manager.loadPage(0); + + expect(onError).toHaveBeenCalledWith(expect.any(Error)); + }); + + it("merges multiple pages into allItems", async () => { + mockFetchPage.mockImplementation((page) => + Promise.resolve({ + items: Array(20) + .fill(0) + .map((_, i) => ({ id: page * 20 + i })), + total: 100, + hasMore: true, + }) + ); + + const manager = makeManager(); + await manager.loadPage(0); + await manager.loadPage(1); + + const state = manager.getState(); + expect(state.allItems.length).toBe(100); + expect(state.allItems[0]).toEqual({ id: 0 }); + expect(state.allItems[20]).toEqual({ id: 20 }); + }); + + it("retry reloads initial page", async () => { + const error = new Error("Failed"); + mockFetchPage.mockRejectedValueOnce(error).mockResolvedValueOnce({ + items: Array(20).fill({ id: 0 }), + total: 100, + hasMore: true, + }); + + const manager = makeManager(); + await manager.loadPage(0); + + expect(manager.getState().error).toBeTruthy(); + + await manager.retry(); + + const state = manager.getState(); + expect(state.error).toBeNull(); + expect(state.pages.size).toBe(1); + }); + + it("reset clears all state", async () => { + mockFetchPage.mockResolvedValue({ + items: Array(20).fill({ id: 0 }), + total: 100, + hasMore: true, + }); + + const manager = makeManager(); + await manager.loadPage(0); + + expect(manager.getState().pages.size).toBe(1); + + manager.reset(); + + const state = manager.getState(); + expect(state.pages.size).toBe(0); + expect(state.loadingPages.size).toBe(0); + expect(state.total).toBe(0); + expect(state.hasMore).toBe(true); + expect(state.error).toBeNull(); + }); + + it("does not load page beyond total", async () => { + mockFetchPage.mockResolvedValue({ + items: Array(20).fill({ id: 0 }), + total: 50, + hasMore: false, + }); + + const manager = makeManager(); + await manager.loadPage(0); + + mockFetchPage.mockClear(); + await manager.loadPage(3); + + expect(mockFetchPage).not.toHaveBeenCalled(); + }); + + it("tracks loading pages during fetch", async () => { + let resolvePromise!: (value: PageResponse<{ id: number }>) => void; + mockFetchPage.mockImplementation( + () => + new Promise((resolve) => { + resolvePromise = resolve; + }) + ); + + const manager = makeManager(); + const loadPromise = manager.loadPage(0); + + expect(manager.getState().loadingPages.has(0)).toBe(true); + + resolvePromise({ items: [], total: 0, hasMore: false }); + await loadPromise; + + expect(manager.getState().loadingPages.has(0)).toBe(false); + }); + + it("handles non-Error exceptions", async () => { + mockFetchPage.mockRejectedValue("String error"); + + const manager = makeManager(); + await manager.loadPage(0); + + expect(manager.getState().error?.message).toBe("String error"); + }); + + it("does not update state when reset is called before fetch resolves", async () => { + let resolvePromise!: (value: PageResponse<{ id: number }>) => void; + mockFetchPage.mockImplementation( + () => + new Promise((resolve) => { + resolvePromise = resolve; + }) + ); + + const manager = makeManager(); + const loadPromise = manager.loadPage(0); + + expect(manager.getState().loadingPages.has(0)).toBe(true); + + manager.reset(); + + expect(manager.getState().loadingPages.size).toBe(0); + + resolvePromise({ items: [{ id: 1 }], total: 100, hasMore: true }); + await loadPromise; + + expect(manager.getState().pages.size).toBe(0); + expect(manager.getState().total).toBe(0); + }); + + it("does not set error when reset is called before fetch rejects", async () => { + let rejectPromise!: (reason?: unknown) => void; + mockFetchPage.mockImplementation( + () => + new Promise((_, reject) => { + rejectPromise = reject; + }) + ); + + const manager = makeManager(); + const loadPromise = manager.loadPage(0); + + expect(manager.getState().loadingPages.has(0)).toBe(true); + + manager.reset(); + + rejectPromise(new Error("network error")); + await loadPromise; + + expect(manager.getState().error).toBeNull(); + expect(manager.getState().pages.size).toBe(0); + }); + + it("notifies subscribers on state change", async () => { + mockFetchPage.mockResolvedValue({ + items: [{ id: 0 }], + total: 1, + hasMore: false, + }); + + const manager = makeManager(); + const subscriber = vi.fn(); + const unsubscribe = manager.subscribe(subscriber); + + await manager.loadPage(0); + + expect(subscriber).toHaveBeenCalled(); + const lastState = + subscriber.mock.calls[subscriber.mock.calls.length - 1][0]; + expect(lastState.pages.size).toBe(1); + + unsubscribe(); + }); + + it("unsubscribe stops receiving notifications", async () => { + mockFetchPage.mockResolvedValue({ + items: [{ id: 0 }], + total: 1, + hasMore: false, + }); + + const manager = makeManager(); + const subscriber = vi.fn(); + const unsubscribe = manager.subscribe(subscriber); + + unsubscribe(); + await manager.loadPage(0); + + expect(subscriber).not.toHaveBeenCalled(); + }); + + it("updateCallbacks uses latest fetchPage", async () => { + const originalFetch = vi.fn().mockResolvedValue({ + items: [{ id: 0 }], + total: 1, + hasMore: false, + }); + const updatedFetch = vi.fn().mockResolvedValue({ + items: [{ id: 99 }], + total: 1, + hasMore: false, + }); + + const manager = new InfiniteSource({ + fetchPage: originalFetch, + pageSize: 20, + initialPage: 0, + }); + + manager.updateCallbacks({ fetchPage: updatedFetch }); + await manager.loadPage(0); + + expect(originalFetch).not.toHaveBeenCalled(); + expect(updatedFetch).toHaveBeenCalled(); + expect(manager.getState().pages.get(0)).toEqual([{ id: 99 }]); + }); + + it("destroy aborts in-flight requests and clears subscribers", async () => { + let resolvePromise!: (value: PageResponse<{ id: number }>) => void; + mockFetchPage.mockImplementation( + () => + new Promise((resolve) => { + resolvePromise = resolve; + }) + ); + + const manager = makeManager(); + const subscriber = vi.fn(); + manager.subscribe(subscriber); + + const loadPromise = manager.loadPage(0); + manager.destroy(); + + resolvePromise({ items: [{ id: 1 }], total: 100, hasMore: true }); + await loadPromise; + + // After destroy, subscribers are cleared — no new notifications after destroy + const callsAfterDestroy = subscriber.mock.calls.length; + manager.reset(); + expect(subscriber.mock.calls.length).toBe(callsAfterDestroy); + }); +}); diff --git a/packages/shared/src/InfiniteSource.ts b/packages/shared/src/InfiniteSource.ts new file mode 100644 index 0000000..beb30b6 --- /dev/null +++ b/packages/shared/src/InfiniteSource.ts @@ -0,0 +1,164 @@ +import type { PageResponse } from "./types"; +import { canLoadPage } from "./utils/canLoadPage"; + +export interface InfiniteSourceState { + pages: Map; + loadingPages: Set; + total: number; + hasMore: boolean; + error: Error | null; + allItems: (T | undefined)[]; +} + +export interface InfiniteSourceOptions { + fetchPage: (page: number, size: number) => Promise>; + pageSize: number; + initialPage: number; + onPageLoad?: (page: number, items: T[]) => void; + onError?: (error: Error) => void; +} + +export class InfiniteSource { + private fetchPage: (page: number, size: number) => Promise>; + private onPageLoad?: (page: number, items: T[]) => void; + private onError?: (error: Error) => void; + + readonly pageSize: number; + readonly initialPage: number; + + private _state: Omit, "allItems"> = { + pages: new Map(), + loadingPages: new Set(), + total: 0, + hasMore: true, + error: null, + }; + + private abortControllers = new Map(); + private subscribers = new Set<(state: InfiniteSourceState) => void>(); + + constructor({ + fetchPage, + pageSize, + initialPage, + onPageLoad, + onError, + }: InfiniteSourceOptions) { + this.fetchPage = fetchPage; + this.pageSize = pageSize; + this.initialPage = initialPage; + this.onPageLoad = onPageLoad; + this.onError = onError; + } + + getState(): InfiniteSourceState { + return { + ...this._state, + allItems: this.computeAllItems(), + }; + } + + subscribe(callback: (state: InfiniteSourceState) => void): () => void { + this.subscribers.add(callback); + return () => this.subscribers.delete(callback); + } + + updateCallbacks( + callbacks: Pick< + InfiniteSourceOptions, + "fetchPage" | "onPageLoad" | "onError" + > + ): void { + this.fetchPage = callbacks.fetchPage; + this.onPageLoad = callbacks.onPageLoad; + this.onError = callbacks.onError; + } + + async loadPage(page: number): Promise { + const { pages, loadingPages, total, hasMore } = this._state; + + if (!canLoadPage(page, pages, loadingPages, total, this.pageSize, hasMore)) + return; + + this.setState({ + loadingPages: new Set(loadingPages).add(page), + error: null, + }); + + const controller = new AbortController(); + this.abortControllers.set(page, controller); + + try { + const response = await this.fetchPage(page, this.pageSize); + + if (controller.signal.aborted) return; + + this.setState({ + pages: new Map(this._state.pages).set(page, response.items), + total: response.total, + hasMore: response.hasMore, + }); + this.onPageLoad?.(page, response.items); + } catch (err) { + if (controller.signal.aborted) return; + + const error = err instanceof Error ? err : new Error(String(err)); + this.setState({ error }); + this.onError?.(error); + } finally { + const next = new Set(this._state.loadingPages); + next.delete(page); + this.setState({ loadingPages: next }); + this.abortControllers.delete(page); + } + } + + retry(): void { + this.setState({ error: null }); + this.loadPage(this.initialPage); + } + + reset(): void { + this.abortControllers.forEach((c) => c.abort()); + this.abortControllers.clear(); + + this._state = { + pages: new Map(), + loadingPages: new Set(), + total: 0, + hasMore: true, + error: null, + }; + this.notify(); + } + + destroy(): void { + this.abortControllers.forEach((c) => c.abort()); + this.abortControllers.clear(); + this.subscribers.clear(); + } + + private setState( + partial: Partial, "allItems">> + ): void { + this._state = { ...this._state, ...partial }; + this.notify(); + } + + private notify(): void { + const state = this.getState(); + this.subscribers.forEach((cb) => cb(state)); + } + + private computeAllItems(): (T | undefined)[] { + const { pages, total } = this._state; + const items: (T | undefined)[] = new Array(total); + pages.forEach((pageItems, pageNum) => { + const startIndex = pageNum * this.pageSize; + pageItems.forEach((item, i) => { + items[startIndex + i] = item; + }); + }); + return items; + } +} diff --git a/packages/react/src/hooks/useInfinitePages.test.ts b/packages/shared/src/hooks/useInfinitePages.test.ts similarity index 81% rename from packages/react/src/hooks/useInfinitePages.test.ts rename to packages/shared/src/hooks/useInfinitePages.test.ts index 5db014f..3da0ee9 100644 --- a/packages/react/src/hooks/useInfinitePages.test.ts +++ b/packages/shared/src/hooks/useInfinitePages.test.ts @@ -365,4 +365,90 @@ describe("useInfinitePages", () => { expect(result.current.error?.message).toBe("String error"); }); + + it("does not update state when reset is called before fetch resolves", async () => { + let resolvePromise!: (value: PageResponse<{ id: number }>) => void; + mockFetchPage.mockImplementation( + () => + new Promise((resolve) => { + resolvePromise = resolve; + }) + ); + + const { result } = renderHook(() => + useInfinitePages({ + fetchPage: mockFetchPage, + pageSize: 20, + initialPage: 0, + }) + ); + + act(() => { + result.current.loadPage(0); + }); + + await waitFor(() => { + expect(result.current.loadingPages.has(0)).toBe(true); + }); + + act(() => { + result.current.reset(); + }); + + await waitFor(() => { + expect(result.current.loadingPages.size).toBe(0); + }); + + act(() => { + resolvePromise({ items: [{ id: 1 }], total: 100, hasMore: true }); + }); + + await waitFor(() => { + expect(result.current.pages.size).toBe(0); + expect(result.current.total).toBe(0); + }); + }); + + it("does not set error when reset is called before fetch rejects", async () => { + let rejectPromise!: (reason?: unknown) => void; + mockFetchPage.mockImplementation( + () => + new Promise((_, reject) => { + rejectPromise = reject; + }) + ); + + const { result } = renderHook(() => + useInfinitePages({ + fetchPage: mockFetchPage, + pageSize: 20, + initialPage: 0, + }) + ); + + act(() => { + result.current.loadPage(0); + }); + + await waitFor(() => { + expect(result.current.loadingPages.has(0)).toBe(true); + }); + + act(() => { + result.current.reset(); + }); + + await waitFor(() => { + expect(result.current.loadingPages.size).toBe(0); + }); + + act(() => { + rejectPromise(new Error("network error")); + }); + + await waitFor(() => { + expect(result.current.error).toBeNull(); + expect(result.current.pages.size).toBe(0); + }); + }); }); diff --git a/packages/shared/src/hooks/useInfinitePages.ts b/packages/shared/src/hooks/useInfinitePages.ts index 39b30bd..ae488c5 100644 --- a/packages/shared/src/hooks/useInfinitePages.ts +++ b/packages/shared/src/hooks/useInfinitePages.ts @@ -1,112 +1,52 @@ -import { useState, useCallback, useRef, useMemo } from "react"; -import type { PageResponse } from "../types"; -import { canLoadPage } from "../utils/canLoadPage"; +import { useState, useCallback, useEffect } from "react"; +import { InfiniteSource } from "../InfiniteSource"; +import type { + InfiniteSourceState, + InfiniteSourceOptions, +} from "../InfiniteSource"; + +export function useInfinitePages( + options: InfiniteSourceOptions +): InfiniteSourceState & { + loadPage: (page: number) => Promise; + retry: () => void; + reset: () => void; +} { + const { fetchPage, pageSize, initialPage, onPageLoad, onError } = options; + + const [manager] = useState>( + () => + new InfiniteSource({ + fetchPage, + pageSize, + initialPage, + onPageLoad, + onError, + }) + ); -interface UseInfinitePagesOptions { - fetchPage: (page: number, size: number) => Promise>; - pageSize: number; - initialPage: number; - onPageLoad?: (page: number, items: T[]) => void; - onError?: (error: Error) => void; -} + const [state, setState] = useState>(() => + manager.getState() + ); -export function useInfinitePages({ - fetchPage, - pageSize, - initialPage, - onPageLoad, - onError, -}: UseInfinitePagesOptions) { - const [pages, setPages] = useState>(new Map()); - const [loadingPages, setLoadingPages] = useState>(new Set()); - const [total, setTotal] = useState(0); - const [hasMore, setHasMore] = useState(true); - const [error, setError] = useState(null); - const abortControllersRef = useRef>(new Map()); + useEffect(() => { + const unsubscribe = manager.subscribe(setState); + return () => { + unsubscribe(); + manager.destroy(); + }; + }, [manager]); - const allItems = useMemo(() => { - const items: (T | undefined)[] = new Array(total); - pages.forEach((pageItems, pageNum) => { - const startIndex = pageNum * pageSize; - pageItems.forEach((item, i) => { - items[startIndex + i] = item; - }); - }); - return items; - }, [pages, total, pageSize]); + useEffect(() => { + manager.updateCallbacks({ fetchPage, onPageLoad, onError }); + }, [manager, fetchPage, onPageLoad, onError]); const loadPage = useCallback( - async (page: number) => { - if (!canLoadPage(page, pages, loadingPages, total, pageSize, hasMore)) - return; - - setLoadingPages((prev) => new Set(prev).add(page)); - setError(null); - - const controller = new AbortController(); - abortControllersRef.current.set(page, controller); - - try { - const response = await fetchPage(page, pageSize); - - if (controller.signal.aborted) return; - - setPages((prev) => new Map(prev).set(page, response.items)); - setTotal(response.total); - setHasMore(response.hasMore); - onPageLoad?.(page, response.items); - } catch (err) { - if (controller.signal.aborted) return; - - const error = err instanceof Error ? err : new Error(String(err)); - setError(error); - onError?.(error); - } finally { - setLoadingPages((prev) => { - const next = new Set(prev); - next.delete(page); - return next; - }); - abortControllersRef.current.delete(page); - } - }, - [ - pages, - loadingPages, - hasMore, - total, - pageSize, - fetchPage, - onPageLoad, - onError, - ] + (page: number) => manager.loadPage(page), + [manager] ); + const retry = useCallback(() => manager.retry(), [manager]); + const reset = useCallback(() => manager.reset(), [manager]); - const retry = useCallback(() => { - setError(null); - loadPage(initialPage); - }, [loadPage, initialPage]); - - const reset = useCallback(() => { - abortControllersRef.current.forEach((controller) => controller.abort()); - abortControllersRef.current.clear(); - - setPages(new Map()); - setLoadingPages(new Set()); - setTotal(0); - setHasMore(true); - setError(null); - }, []); - - return { - allItems, - pages, - loadingPages, - total, - hasMore, - error, - loadPage, - retry, - reset, - }; + return { ...state, loadPage, retry, reset }; } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 167643a..c4366ac 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,4 @@ export * from "./types"; export * from "./utils"; export * from "./hooks"; +export * from "./InfiniteSource"; diff --git a/packages/shared/src/utils/canLoadPage.test.ts b/packages/shared/src/utils/canLoadPage.test.ts new file mode 100644 index 0000000..b070e94 --- /dev/null +++ b/packages/shared/src/utils/canLoadPage.test.ts @@ -0,0 +1,62 @@ +import { describe, it, expect } from "vitest"; +import { canLoadPage } from "./canLoadPage"; + +describe("canLoadPage", () => { + const emptyPages = new Map(); + const emptyLoading = new Set(); + + it("returns true for first page in empty state", () => { + expect(canLoadPage(0, emptyPages, emptyLoading, 0, 20, true)).toBe(true); + }); + + it("returns false when page is already loaded", () => { + const pages = new Map([[0, [1, 2, 3]]]); + expect(canLoadPage(0, pages, emptyLoading, 100, 20, true)).toBe(false); + }); + + it("returns false when page is currently loading", () => { + const loadingPages = new Set([2]); + expect(canLoadPage(2, emptyPages, loadingPages, 100, 20, true)).toBe(false); + }); + + it("returns false when page is both loaded and loading", () => { + const pages = new Map([[1, [1]]]); + const loadingPages = new Set([1]); + expect(canLoadPage(1, pages, loadingPages, 100, 20, true)).toBe(false); + }); + + it("returns false when page * pageSize >= total", () => { + // total=50, pageSize=20: page 3 → 3*20=60 >= 50 + expect(canLoadPage(3, emptyPages, emptyLoading, 50, 20, true)).toBe(false); + }); + + it("returns false when page * pageSize exactly equals total", () => { + // total=40, pageSize=20: page 2 → 2*20=40 >= 40 + expect(canLoadPage(2, emptyPages, emptyLoading, 40, 20, true)).toBe(false); + }); + + it("returns true when page * pageSize is within total", () => { + // total=50, pageSize=20: page 2 → 2*20=40 < 50 + expect(canLoadPage(2, emptyPages, emptyLoading, 50, 20, true)).toBe(true); + }); + + it("skips total check when total is 0", () => { + expect(canLoadPage(0, emptyPages, emptyLoading, 0, 20, true)).toBe(true); + }); + + it("returns false when !hasMore and page exceeds last page index (total=0)", () => { + // total=0, hasMore=false: Math.floor(0/20)=0, page=1 > 0 → false + expect(canLoadPage(1, emptyPages, emptyLoading, 0, 20, false)).toBe(false); + }); + + it("returns true for page 0 when !hasMore and total is 0", () => { + // Math.floor(0/20)=0, page=0 is NOT > 0 + expect(canLoadPage(0, emptyPages, emptyLoading, 0, 20, false)).toBe(true); + }); + + it("returns true when hasMore is true even if page is beyond floor(total/pageSize)", () => { + // total=50, pageSize=20: floor(50/20)=2, page=2 → NOT > 2, but line 11 catches it (2*20=40<50 → ok) + // Use total=0 so line 11 is skipped: page=5, hasMore=true → line 13 not triggered → true + expect(canLoadPage(5, emptyPages, emptyLoading, 0, 20, true)).toBe(true); + }); +}); diff --git a/packages/shared/src/utils/findMissingPages.test.ts b/packages/shared/src/utils/findMissingPages.test.ts new file mode 100644 index 0000000..ba545ad --- /dev/null +++ b/packages/shared/src/utils/findMissingPages.test.ts @@ -0,0 +1,72 @@ +import { describe, it, expect } from "vitest"; +import { findMissingPages } from "./findMissingPages"; + +describe("findMissingPages", () => { + const emptyPages = new Map(); + const emptyLoading = new Set(); + + it("returns all pages in range when nothing is loaded or loading", () => { + const result = findMissingPages(0, 2, emptyPages, emptyLoading); + expect(result).toEqual([0, 1, 2]); + }); + + it("returns empty array when start > end", () => { + const result = findMissingPages(5, 3, emptyPages, emptyLoading); + expect(result).toEqual([]); + }); + + it("returns empty array when start === end and page is loaded", () => { + const pages = new Map([[1, [1, 2]]]); + const result = findMissingPages(1, 1, pages, emptyLoading); + expect(result).toEqual([]); + }); + + it("excludes pages that are already loaded", () => { + const pages = new Map([[1, [1, 2]]]); + const result = findMissingPages(0, 3, pages, emptyLoading); + expect(result).toEqual([0, 2, 3]); + }); + + it("excludes pages that are currently loading", () => { + const loadingPages = new Set([2]); + const result = findMissingPages(0, 3, emptyPages, loadingPages); + expect(result).toEqual([0, 1, 3]); + }); + + it("excludes pages that are both loaded and loading", () => { + const pages = new Map([[0, [1]]]); + const loadingPages = new Set([2]); + const result = findMissingPages(0, 3, pages, loadingPages); + expect(result).toEqual([1, 3]); + }); + + it("returns empty array when all pages are loaded", () => { + const pages = new Map([ + [0, [1]], + [1, [2]], + [2, [3]], + ]); + const result = findMissingPages(0, 2, pages, emptyLoading); + expect(result).toEqual([]); + }); + + it("returns empty array when all pages are loading", () => { + const loadingPages = new Set([0, 1, 2]); + const result = findMissingPages(0, 2, emptyPages, loadingPages); + expect(result).toEqual([]); + }); + + it("handles single-page range that is missing", () => { + const result = findMissingPages(3, 3, emptyPages, emptyLoading); + expect(result).toEqual([3]); + }); + + it("handles large range with sparse loaded pages", () => { + const pages = new Map([ + [2, []], + [5, []], + ]); + const result = findMissingPages(0, 6, pages, emptyLoading); + expect(result).toEqual([0, 1, 3, 4, 6]); + }); +}); diff --git a/packages/shared/vitest.config.ts b/packages/shared/vitest.config.ts index 1dd8712..45d1d8f 100644 --- a/packages/shared/vitest.config.ts +++ b/packages/shared/vitest.config.ts @@ -3,9 +3,18 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { globals: true, + environment: "jsdom", coverage: { provider: "v8", reporter: ["text", "json", "html", "json-summary"], + exclude: [ + "node_modules/", + "dist/", + "**/*.d.ts", + "**/*.config.*", + "**/index.ts", + "**/*.test.{ts,tsx}", + ], }, }, }); diff --git a/packages/svelte/package.json b/packages/svelte/package.json new file mode 100644 index 0000000..739ba0c --- /dev/null +++ b/packages/svelte/package.json @@ -0,0 +1,40 @@ +{ + "name": "@scrolloop/svelte", + "version": "0.1.0", + "description": "Svelte 5 adapter for @scrolloop/core", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + }, + "sideEffects": false, + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "vite build", + "dev": "vite build --watch" + }, + "peerDependencies": { + "svelte": ">=5.0.0" + }, + "dependencies": { + "@scrolloop/core": "workspace:*", + "@scrolloop/shared": "workspace:*" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^4.0.0", + "svelte": "^5.0.0", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vite-plugin-dts": "^4.0.0" + }, + "license": "MIT" +} diff --git a/packages/svelte/src/InfiniteList.svelte b/packages/svelte/src/InfiniteList.svelte new file mode 100644 index 0000000..7094abc --- /dev/null +++ b/packages/svelte/src/InfiniteList.svelte @@ -0,0 +1,135 @@ + + +{#if errorState && total === 0} + {#if errorSnippet} + {@render errorSnippet(errorState, source.retry)} + {:else} +
+
+

Error.

+

{errorState.message}

+ +
+
+ {/if} +{:else if total === 0 && loadingPages.size > 0} + {#if loadingSnippet} +
{@render loadingSnippet()}
+ {:else} +
+

Loading...

+
+ {/if} +{:else if total === 0 && !hasMore} + {#if emptySnippet} +
{@render emptySnippet()}
+ {:else} +
+

No data.

+
+ {/if} +{:else} + + {#snippet children(index, style)} + {@render children(index, pages.get(Math.floor(index / pageSize))?.[index % pageSize], style)} + {/snippet} + +{/if} + + diff --git a/packages/svelte/src/VirtualList.svelte b/packages/svelte/src/VirtualList.svelte new file mode 100644 index 0000000..f2101d2 --- /dev/null +++ b/packages/svelte/src/VirtualList.svelte @@ -0,0 +1,86 @@ + + +
+
+ {#each virtualItems as item (item.index)} +
+ {@render children(item.index, item.style)} +
+ {/each} +
+
diff --git a/packages/svelte/src/index.ts b/packages/svelte/src/index.ts new file mode 100644 index 0000000..80d84d5 --- /dev/null +++ b/packages/svelte/src/index.ts @@ -0,0 +1,3 @@ +export { default as VirtualList } from "./VirtualList.svelte"; +export { default as InfiniteList } from "./InfiniteList.svelte"; +export { createInfinitePages } from "./stores/createInfinitePages"; diff --git a/packages/svelte/src/stores/createInfinitePages.ts b/packages/svelte/src/stores/createInfinitePages.ts new file mode 100644 index 0000000..6b7b3cd --- /dev/null +++ b/packages/svelte/src/stores/createInfinitePages.ts @@ -0,0 +1,25 @@ +import { readable } from "svelte/store"; +import { InfiniteSource } from "@scrolloop/shared"; +import type { + InfiniteSourceOptions, + InfiniteSourceState, +} from "@scrolloop/shared"; + +export function createInfinitePages(options: InfiniteSourceOptions) { + const source = new InfiniteSource(options); + + const store = readable>(source.getState(), (set) => { + const unsubscribe = source.subscribe(set); + return () => { + unsubscribe(); + source.destroy(); + }; + }); + + return { + subscribe: store.subscribe, + loadPage: (page: number) => source.loadPage(page), + retry: () => source.retry(), + reset: () => source.reset(), + }; +} diff --git a/packages/svelte/tsconfig.json b/packages/svelte/tsconfig.json new file mode 100644 index 0000000..1110b74 --- /dev/null +++ b/packages/svelte/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "declaration": true, + "declarationMap": true + }, + "include": ["src/**/*.ts", "vite.config.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/svelte/vite.config.ts b/packages/svelte/vite.config.ts new file mode 100644 index 0000000..cadbfa7 --- /dev/null +++ b/packages/svelte/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import dts from "vite-plugin-dts"; + +export default defineConfig({ + plugins: [svelte(), dts({ include: ["src/**/*.ts"] })], + build: { + lib: { + entry: "src/index.ts", + formats: ["es", "cjs"], + fileName: (format) => `index.${format === "es" ? "mjs" : "cjs"}`, + }, + rollupOptions: { + external: [ + "svelte", + "svelte/store", + "@scrolloop/core", + "@scrolloop/shared", + ], + }, + }, +}); diff --git a/packages/svelte/vitest.config.ts b/packages/svelte/vitest.config.ts new file mode 100644 index 0000000..803bebe --- /dev/null +++ b/packages/svelte/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + coverage: { + reporter: ["text", "json", "html"], + include: ["src/**/*.{ts,svelte}"], + }, + }, +}); diff --git a/packages/vue/package.json b/packages/vue/package.json new file mode 100644 index 0000000..d602d0a --- /dev/null +++ b/packages/vue/package.json @@ -0,0 +1,40 @@ +{ + "name": "@scrolloop/vue", + "version": "0.1.0", + "description": "Vue 3 adapter for @scrolloop/core", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + }, + "sideEffects": false, + "files": [ + "dist" + ], + "scripts": { + "build": "vite build", + "dev": "vite build --watch" + }, + "peerDependencies": { + "vue": ">=3.3.0" + }, + "dependencies": { + "@scrolloop/core": "workspace:*", + "@scrolloop/shared": "workspace:*" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vite-plugin-dts": "^4.0.0", + "vue": "^3.3.0", + "vue-tsc": "^2.0.0" + }, + "license": "MIT" +} diff --git a/packages/vue/src/components/InfiniteList.vue b/packages/vue/src/components/InfiniteList.vue new file mode 100644 index 0000000..f47f758 --- /dev/null +++ b/packages/vue/src/components/InfiniteList.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/packages/vue/src/components/VirtualList.vue b/packages/vue/src/components/VirtualList.vue new file mode 100644 index 0000000..4ae91f8 --- /dev/null +++ b/packages/vue/src/components/VirtualList.vue @@ -0,0 +1,96 @@ + + + diff --git a/packages/vue/src/composables/useInfinitePages.ts b/packages/vue/src/composables/useInfinitePages.ts new file mode 100644 index 0000000..7287841 --- /dev/null +++ b/packages/vue/src/composables/useInfinitePages.ts @@ -0,0 +1,42 @@ +import { ref, computed, watch, toValue, onUnmounted } from "vue"; +import type { MaybeRefOrGetter } from "vue"; +import { InfiniteSource } from "@scrolloop/shared"; +import type { InfiniteSourceOptions } from "@scrolloop/shared"; + +export function useInfinitePages( + options: MaybeRefOrGetter> +) { + const resolved = toValue(options); + const source = new InfiniteSource(resolved); + const state = ref(source.getState()); + + const unsubscribe = source.subscribe((s) => { + state.value = s; + }); + + watch( + () => { + const { fetchPage, onPageLoad, onError } = toValue(options); + return { fetchPage, onPageLoad, onError }; + }, + ({ fetchPage, onPageLoad, onError }) => { + source.updateCallbacks({ fetchPage, onPageLoad, onError }); + } + ); + + onUnmounted(() => { + unsubscribe(); + source.destroy(); + }); + + return { + pages: computed(() => state.value.pages), + loadingPages: computed(() => state.value.loadingPages), + total: computed(() => state.value.total), + hasMore: computed(() => state.value.hasMore), + error: computed(() => state.value.error), + loadPage: (page: number) => source.loadPage(page), + retry: () => source.retry(), + reset: () => source.reset(), + }; +} diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts new file mode 100644 index 0000000..dca73cb --- /dev/null +++ b/packages/vue/src/index.ts @@ -0,0 +1,4 @@ +export { default as VirtualList } from "./components/VirtualList.vue"; +export { default as InfiniteList } from "./components/InfiniteList.vue"; +export { useInfinitePages } from "./composables/useInfinitePages"; +export type { VirtualListProps, InfiniteListProps, ItemStyle } from "./types"; diff --git a/packages/vue/src/types.ts b/packages/vue/src/types.ts new file mode 100644 index 0000000..d6df753 --- /dev/null +++ b/packages/vue/src/types.ts @@ -0,0 +1,24 @@ +import type { PageResponse, Range } from "@scrolloop/shared"; + +export type { PageResponse, Range }; + +export interface VirtualListProps { + count: number; + itemSize: number; + height?: number; + overscan?: number; + class?: string; +} + +export interface InfiniteListProps { + fetchPage: (page: number, size: number) => Promise>; + itemSize: number; + pageSize?: number; + initialPage?: number; + prefetchThreshold?: number; + height?: number; + overscan?: number; + class?: string; +} + +export type ItemStyle = Record; diff --git a/packages/vue/tsconfig.json b/packages/vue/tsconfig.json new file mode 100644 index 0000000..91503bb --- /dev/null +++ b/packages/vue/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "jsx": "preserve" + }, + "include": ["src/**/*", "vite.config.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/vue/vite.config.ts b/packages/vue/vite.config.ts new file mode 100644 index 0000000..db44058 --- /dev/null +++ b/packages/vue/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import dts from "vite-plugin-dts"; + +export default defineConfig({ + plugins: [vue(), dts({ include: ["src/**/*"] })], + build: { + lib: { + entry: "src/index.ts", + formats: ["es", "cjs"], + fileName: (format) => `index.${format === "es" ? "mjs" : "cjs"}`, + }, + rollupOptions: { + external: ["vue", "@scrolloop/core", "@scrolloop/shared"], + }, + }, +}); diff --git a/packages/vue/vitest.config.ts b/packages/vue/vitest.config.ts new file mode 100644 index 0000000..3a00bd3 --- /dev/null +++ b/packages/vue/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + coverage: { + reporter: ["text", "json", "html"], + include: ["src/**/*.{ts,tsx}"], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe63fa6..84b5a6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,7 +55,7 @@ importers: version: 5.44.0 tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) turbo: specifier: ^2.0.0 version: 2.6.0 @@ -79,7 +79,7 @@ importers: version: 2.1.9(vitest@2.1.9(@types/node@24.10.0)(jsdom@24.1.3)(terser@5.44.0)) tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) typescript: specifier: ^5.0.0 version: 5.9.3 @@ -137,7 +137,7 @@ importers: version: 18.3.1(react@18.3.1) tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) tsx: specifier: ^4.7.0 version: 4.20.6 @@ -171,7 +171,7 @@ importers: version: 0.72.17(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) typescript: specifier: ^5.0.0 version: 5.9.3 @@ -181,12 +181,21 @@ importers: packages/shared: devDependencies: + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^14.3.1 + version: 14.3.1(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + jsdom: + specifier: ^24.1.3 + version: 24.1.3 react: specifier: ^18.2.0 version: 18.3.1 tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) typescript: specifier: ^5.0.0 version: 5.9.3 @@ -194,6 +203,59 @@ importers: specifier: ^2.0.0 version: 2.1.9(@types/node@24.10.0)(jsdom@24.1.3)(terser@5.44.0) + packages/svelte: + dependencies: + '@scrolloop/core': + specifier: workspace:* + version: link:../core + '@scrolloop/shared': + specifier: workspace:* + version: link:../shared + devDependencies: + '@sveltejs/vite-plugin-svelte': + specifier: ^4.0.0 + version: 4.0.4(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + svelte: + specifier: ^5.0.0 + version: 5.55.1 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vite: + specifier: ^5.0.0 + version: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + vite-plugin-dts: + specifier: ^4.0.0 + version: 4.5.4(@types/node@24.10.0)(rollup@4.52.5)(typescript@5.9.3)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + + packages/vue: + dependencies: + '@scrolloop/core': + specifier: workspace:* + version: link:../core + '@scrolloop/shared': + specifier: workspace:* + version: link:../shared + devDependencies: + '@vitejs/plugin-vue': + specifier: ^5.0.0 + version: 5.2.4(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0))(vue@3.5.26(typescript@5.9.3)) + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vite: + specifier: ^5.0.0 + version: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + vite-plugin-dts: + specifier: ^4.0.0 + version: 4.5.4(@types/node@24.10.0)(rollup@4.52.5)(typescript@5.9.3)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + vue: + specifier: ^3.3.0 + version: 3.5.26(typescript@5.9.3) + vue-tsc: + specifier: ^2.0.0 + version: 2.2.12(typescript@5.9.3) + packages: '@adobe/css-tools@4.4.4': @@ -1531,6 +1593,19 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@microsoft/api-extractor-model@7.33.4': + resolution: {integrity: sha512-u1LTaNTikZAQ9uK6KG1Ms7nvNedsnODnspq/gH2dcyETWvH4hVNGNDvRAEutH66kAmxA4/necElqGNs1FggC8w==} + + '@microsoft/api-extractor@7.57.7': + resolution: {integrity: sha512-kmnmVs32MFWbV5X6BInC1/TfCs7y1ugwxv1xHsAIj/DyUfoe7vtO0alRUgbQa57+yRGHBBjlNcEk33SCAt5/dA==} + hasBin: true + + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1600,6 +1675,15 @@ packages: peerDependencies: react-native: '*' + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.52.5': resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] @@ -1710,6 +1794,36 @@ packages: cpu: [x64] os: [win32] + '@rushstack/node-core-library@5.20.3': + resolution: {integrity: sha512-95JgEPq2k7tHxhF9/OJnnyHDXfC9cLhhta0An/6MlkDsX2A6dTzDrTUG18vx4vjc280V0fi0xDH9iQczpSuWsw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.2.1': + resolution: {integrity: sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.7.2': + resolution: {integrity: sha512-9XbFWuqMYcHUso4mnETfhGVUSaADBRj6HUAAEYk50nMPn8WRICmBuCphycQGNB3duIR6EEZX3Xj3SYc2XiP+9A==} + + '@rushstack/terminal@0.22.3': + resolution: {integrity: sha512-gHC9pIMrUPzAbBiI4VZMU7Q+rsCzb8hJl36lFIulIzoceKotyKL3Rd76AZ2CryCTKEg+0bnTj406HE5YY5OQvw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@5.3.3': + resolution: {integrity: sha512-c+ltdcvC7ym+10lhwR/vWiOhsrm/bP3By2VsFcs5qTKv+6tTmxgbVrtJ5NdNjANiV5TcmOZgUN+5KYQ4llsvEw==} + '@shikijs/core@2.5.0': resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==} @@ -1752,6 +1866,26 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@sveltejs/acorn-typescript@1.0.9': + resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/vite-plugin-svelte-inspector@3.0.1': + resolution: {integrity: sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^4.0.0-next.0||^4.0.0 + svelte: ^5.0.0-next.96 || ^5.0.0 + vite: ^5.0.0 + + '@sveltejs/vite-plugin-svelte@4.0.4': + resolution: {integrity: sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + svelte: ^5.0.0-next.96 || ^5.0.0 + vite: ^5.0.0 + '@testing-library/dom@9.3.4': resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} engines: {node: '>=14'} @@ -1773,6 +1907,9 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1856,6 +1993,9 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -1874,6 +2014,10 @@ packages: '@types/yargs@17.0.34': resolution: {integrity: sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==} + '@typescript-eslint/types@8.57.2': + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -1922,6 +2066,24 @@ packages: '@vitest/utils@2.1.9': resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + '@volar/language-core@2.4.15': + resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.15': + resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.15': + resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + '@vue/compiler-core@3.5.26': resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} @@ -1934,6 +2096,9 @@ packages: '@vue/compiler-ssr@3.5.26': resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==} + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + '@vue/devtools-api@7.7.9': resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} @@ -1943,6 +2108,22 @@ packages: '@vue/devtools-shared@7.7.9': resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@2.2.12': + resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@vue/reactivity@3.5.26': resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} @@ -2027,10 +2208,35 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + algoliasearch@5.46.1: resolution: {integrity: sha512-39ol8Ulqb3MntofkXHlrcXKyU8BU0PXvQrXPBIX6eXj/EO4VT7651mhGVORI2oF8ydya9nFzT3fYDoqme/KL6w==} engines: {node: '>= 14.0.0'} + alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + + alien-signals@1.0.13: + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -2096,6 +2302,10 @@ packages: aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + aria-query@5.3.1: + resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} + engines: {node: '>= 0.4'} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -2141,6 +2351,10 @@ packages: axios@1.6.0: resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: @@ -2175,6 +2389,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -2198,6 +2416,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -2346,6 +2568,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + code-point-at@1.1.0: resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} engines: {node: '>=0.10.0'} @@ -2400,6 +2626,9 @@ packages: commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -2414,6 +2643,9 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} @@ -2481,6 +2713,9 @@ packages: dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -2566,9 +2801,16 @@ packages: engines: {node: '>=0.10'} hasBin: true + devalue@5.6.4: + resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -2693,11 +2935,17 @@ packages: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + esrap@2.2.4: + resolution: {integrity: sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -2735,6 +2983,15 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-xml-parser@4.5.3: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true @@ -2824,6 +3081,10 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} + fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -2886,11 +3147,12 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} @@ -2939,6 +3201,10 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + hermes-estree@0.12.0: resolution: {integrity: sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw==} @@ -3007,6 +3273,10 @@ packages: resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} engines: {node: '>=4'} + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3110,6 +3380,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -3222,6 +3495,9 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} @@ -3265,6 +3541,9 @@ packages: json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3273,6 +3552,9 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -3281,6 +3563,13 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3305,6 +3594,13 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -3326,6 +3622,9 @@ packages: lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -3351,6 +3650,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -3532,6 +3835,10 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.2.3: + resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3568,6 +3875,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -3751,6 +4061,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -3825,6 +4138,9 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + playwright-core@1.57.0: resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} engines: {node: '>=18'} @@ -3926,6 +4242,9 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -4041,6 +4360,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} @@ -4129,6 +4452,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} @@ -4350,6 +4678,10 @@ packages: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} @@ -4382,6 +4714,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svelte@5.55.1: + resolution: {integrity: sha512-QjvU7EFemf6mRzdMGlAFttMWtAAVXrax61SZYHdkD6yoVGQ89VeyKfZD4H1JrV1WLmJBxWhFch9H6ig/87VGjw==} + engines: {node: '>=18'} + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -4554,6 +4890,11 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -4610,6 +4951,10 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -4650,6 +4995,15 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + vite-plugin-dts@4.5.4: + resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + vite@5.4.21: resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -4681,6 +5035,14 @@ packages: terser: optional: true + vitefu@1.1.2: + resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + vitepress@1.6.4: resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==} hasBin: true @@ -4721,6 +5083,15 @@ packages: vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-tsc@2.2.12: + resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + vue@3.5.26: resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==} peerDependencies: @@ -4752,6 +5123,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} @@ -4880,6 +5252,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.1: resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} @@ -4905,6 +5280,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -6266,6 +6644,42 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@microsoft/api-extractor-model@7.33.4(@types/node@24.10.0)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.20.3(@types/node@24.10.0) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.57.7(@types/node@24.10.0)': + dependencies: + '@microsoft/api-extractor-model': 7.33.4(@types/node@24.10.0) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.20.3(@types/node@24.10.0) + '@rushstack/rig-package': 0.7.2 + '@rushstack/terminal': 0.22.3(@types/node@24.10.0) + '@rushstack/ts-command-line': 5.3.3(@types/node@24.10.0) + diff: 8.0.4 + lodash: 4.17.23 + minimatch: 10.2.3 + resolve: 1.22.11 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.11 + + '@microsoft/tsdoc@0.16.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -6459,6 +6873,14 @@ snapshots: nullthrows: 1.1.1 react-native: 0.72.17(@babel/core@7.28.5)(@babel/preset-env@7.28.5(@babel/core@7.28.5))(react@18.3.1) + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -6525,6 +6947,45 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true + '@rushstack/node-core-library@5.20.3(@types/node@24.10.0)': + dependencies: + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.5.4 + optionalDependencies: + '@types/node': 24.10.0 + + '@rushstack/problem-matcher@0.2.1(@types/node@24.10.0)': + optionalDependencies: + '@types/node': 24.10.0 + + '@rushstack/rig-package@0.7.2': + dependencies: + resolve: 1.22.11 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.22.3(@types/node@24.10.0)': + dependencies: + '@rushstack/node-core-library': 5.20.3(@types/node@24.10.0) + '@rushstack/problem-matcher': 0.2.1(@types/node@24.10.0) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 24.10.0 + + '@rushstack/ts-command-line@5.3.3(@types/node@24.10.0)': + dependencies: + '@rushstack/terminal': 0.22.3(@types/node@24.10.0) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + '@shikijs/core@2.5.0': dependencies: '@shikijs/engine-javascript': 2.5.0 @@ -6583,6 +7044,32 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@sveltejs/acorn-typescript@1.0.9(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)))(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + debug: 4.4.3 + svelte: 5.55.1 + vite: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)))(svelte@5.55.1)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + debug: 4.4.3 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.21 + svelte: 5.55.1 + vite: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + vitefu: 1.1.2(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)) + transitivePeerDependencies: + - supports-color + '@testing-library/dom@9.3.4': dependencies: '@babel/code-frame': 7.27.1 @@ -6617,6 +7104,8 @@ snapshots: dependencies: '@testing-library/dom': 9.3.4 + '@types/argparse@1.0.38': {} + '@types/aria-query@5.0.4': {} '@types/body-parser@1.19.6': @@ -6718,6 +7207,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/trusted-types@2.0.7': {} + '@types/unist@3.0.3': {} '@types/web-bluetooth@0.0.21': {} @@ -6736,6 +7227,8 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@typescript-eslint/types@8.57.2': {} + '@ungap/structured-clone@1.3.0': {} '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0))(vue@3.5.26(typescript@5.9.3))': @@ -6801,6 +7294,30 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 + '@volar/language-core@2.4.15': + dependencies: + '@volar/source-map': 2.4.15 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.15': {} + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.15': + dependencies: + '@volar/language-core': 2.4.15 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + '@vue/compiler-core@3.5.26': dependencies: '@babel/parser': 7.28.5 @@ -6831,6 +7348,11 @@ snapshots: '@vue/compiler-dom': 3.5.26 '@vue/shared': 3.5.26 + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + '@vue/devtools-api@7.7.9': dependencies: '@vue/devtools-kit': 7.7.9 @@ -6849,6 +7371,32 @@ snapshots: dependencies: rfdc: 1.4.1 + '@vue/language-core@2.2.0(typescript@5.9.3)': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.26 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.9.3 + + '@vue/language-core@2.2.12(typescript@5.9.3)': + dependencies: + '@volar/language-core': 2.4.15 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.26 + alien-signals: 1.0.13 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.9.3 + '@vue/reactivity@3.5.26': dependencies: '@vue/shared': 3.5.26 @@ -6914,6 +7462,21 @@ snapshots: agent-base@7.1.4: {} + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + algoliasearch@5.46.1: dependencies: '@algolia/abtesting': 1.12.1 @@ -6931,6 +7494,10 @@ snapshots: '@algolia/requester-fetch': 5.46.1 '@algolia/requester-node-http': 5.46.1 + alien-signals@0.4.14: {} + + alien-signals@1.0.13: {} + anser@1.4.10: {} ansi-escapes@7.2.0: @@ -6987,6 +7554,8 @@ snapshots: dependencies: deep-equal: 2.2.3 + aria-query@5.3.1: {} + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -7032,6 +7601,8 @@ snapshots: transitivePeerDependencies: - debug + axobject-query@4.1.0: {} + babel-core@7.0.0-bridge.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 @@ -7103,6 +7674,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.5.1: {} baseline-browser-mapping@2.8.24: {} @@ -7141,6 +7714,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -7300,6 +7877,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + code-point-at@1.1.0: {} color-convert@1.9.3: @@ -7338,6 +7917,8 @@ snapshots: commondir@1.0.1: {} + compare-versions@6.1.1: {} + compressible@2.0.18: dependencies: mime-db: 1.52.0 @@ -7358,6 +7939,8 @@ snapshots: confbox@0.1.8: {} + confbox@0.2.4: {} + connect@3.7.0: dependencies: debug: 2.6.9 @@ -7424,6 +8007,8 @@ snapshots: dayjs@1.11.19: {} + de-indent@1.0.2: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -7503,10 +8088,14 @@ snapshots: detect-libc@1.0.3: {} + devalue@5.6.4: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 + diff@8.0.4: {} + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -7683,8 +8272,15 @@ snapshots: escape-string-regexp@2.0.0: {} + esm-env@1.2.2: {} + esprima@4.0.1: {} + esrap@2.2.4: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@typescript-eslint/types': 8.57.2 + estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -7751,6 +8347,12 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.0.8: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + fast-xml-parser@4.5.3: dependencies: strnum: 1.1.2 @@ -7850,6 +8452,12 @@ snapshots: fs-constants@1.0.0: {} + fs-extra@11.3.4: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 @@ -7984,6 +8592,8 @@ snapshots: dependencies: '@types/hast': 3.0.4 + he@1.2.0: {} + hermes-estree@0.12.0: {} hermes-parser@0.12.0: @@ -8057,6 +8667,8 @@ snapshots: caller-path: 2.0.0 resolve-from: 3.0.0 + import-lazy@4.0.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -8146,6 +8758,10 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -8284,6 +8900,8 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jju@1.4.0: {} + joi@17.13.3: dependencies: '@hapi/hoek': 9.3.0 @@ -8362,16 +8980,28 @@ snapshots: json-parse-better-errors@1.0.2: {} + json-schema-traverse@1.0.0: {} + json5@2.2.3: {} jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + kind-of@6.0.3: {} kleur@3.0.3: {} + kleur@4.1.5: {} + + kolorist@1.8.0: {} + leven@3.1.0: {} lilconfig@3.1.3: {} @@ -8399,6 +9029,14 @@ snapshots: load-tsconfig@0.2.5: {} + local-pkg@1.1.2: + dependencies: + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 + + locate-character@3.0.0: {} + locate-path@3.0.0: dependencies: p-locate: 3.0.0 @@ -8418,6 +9056,8 @@ snapshots: lodash.throttle@4.1.1: {} + lodash@4.17.23: {} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -8449,6 +9089,10 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + lz-string@1.5.0: {} magic-string@0.30.21: @@ -8786,6 +9430,10 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.2.3: + dependencies: + brace-expansion: 5.0.5 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -8819,6 +9467,8 @@ snapshots: ms@2.1.3: {} + muggle-string@0.4.1: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -8983,6 +9633,8 @@ snapshots: parseurl@1.3.3: {} + path-browserify@1.0.1: {} + path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -9032,6 +9684,12 @@ snapshots: mlly: 1.8.0 pathe: 2.0.3 + pkg-types@2.3.0: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + playwright-core@1.57.0: {} playwright@1.57.0: @@ -9142,6 +9800,8 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@0.2.11: {} + querystringify@2.2.0: {} queue@6.0.2: @@ -9320,6 +9980,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} requires-port@1.0.0: {} @@ -9418,6 +10080,10 @@ snapshots: semver@6.3.1: {} + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + semver@7.7.3: {} send@0.19.0: @@ -9663,6 +10329,8 @@ snapshots: strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} + strnum@1.1.2: {} sucrase@3.35.0: @@ -9695,6 +10363,25 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svelte@5.55.1: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.9(acorn@8.15.0) + '@types/estree': 1.0.8 + '@types/trusted-types': 2.0.7 + acorn: 8.15.0 + aria-query: 5.3.1 + axobject-query: 4.1.0 + clsx: 2.1.1 + devalue: 5.6.4 + esm-env: 1.2.2 + esrap: 2.2.4 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.21 + zimmerframe: 1.1.4 + symbol-tree@3.2.4: {} tabbable@6.3.0: {} @@ -9794,7 +10481,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): + tsup@8.5.0(@microsoft/api-extractor@7.57.7(@types/node@24.10.0))(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.12) cac: 6.7.14 @@ -9814,6 +10501,7 @@ snapshots: tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: + '@microsoft/api-extractor': 7.57.7(@types/node@24.10.0) postcss: 8.5.6 typescript: 5.9.3 transitivePeerDependencies: @@ -9869,6 +10557,8 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + typescript@5.8.2: {} + typescript@5.9.3: {} ufo@1.6.1: {} @@ -9918,6 +10608,8 @@ snapshots: universalify@0.2.0: {} + universalify@2.0.1: {} + unpipe@1.0.0: {} update-browserslist-db@1.1.4(browserslist@4.27.0): @@ -9969,6 +10661,25 @@ snapshots: - supports-color - terser + vite-plugin-dts@4.5.4(@types/node@24.10.0)(rollup@4.52.5)(typescript@5.9.3)(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)): + dependencies: + '@microsoft/api-extractor': 7.57.7(@types/node@24.10.0) + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@volar/typescript': 2.4.28 + '@vue/language-core': 2.2.0(typescript@5.9.3) + compare-versions: 6.1.1 + debug: 4.4.3 + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + typescript: 5.9.3 + optionalDependencies: + vite: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + vite@5.4.21(@types/node@24.10.0)(terser@5.44.0): dependencies: esbuild: 0.21.5 @@ -9979,6 +10690,10 @@ snapshots: fsevents: 2.3.3 terser: 5.44.0 + vitefu@1.1.2(vite@5.4.21(@types/node@24.10.0)(terser@5.44.0)): + optionalDependencies: + vite: 5.4.21(@types/node@24.10.0)(terser@5.44.0) + vitepress@1.6.4(@algolia/client-search@5.46.1)(@types/node@24.10.0)(@types/react@18.3.26)(axios@1.13.2)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(terser@5.44.0)(typescript@5.9.3): dependencies: '@docsearch/css': 3.8.2 @@ -10066,6 +10781,14 @@ snapshots: vlq@1.0.1: {} + vscode-uri@3.1.0: {} + + vue-tsc@2.2.12(typescript@5.9.3): + dependencies: + '@volar/typescript': 2.4.15 + '@vue/language-core': 2.2.12(typescript@5.9.3) + typescript: 5.9.3 + vue@3.5.26(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.26 @@ -10212,6 +10935,8 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yaml@2.8.1: {} yargs-parser@18.1.3: @@ -10247,4 +10972,6 @@ snapshots: yocto-queue@0.1.0: {} + zimmerframe@1.1.4: {} + zwitch@2.0.4: {}