diff --git a/app/components/filter-sphere/filter.tsx b/app/components/filter-sphere/filter.tsx new file mode 100644 index 0000000..5a8fad3 --- /dev/null +++ b/app/components/filter-sphere/filter.tsx @@ -0,0 +1,37 @@ +import { + FilterSphereProvider, + FilterBuilder, + useFilterSphere, + FilterGroup, +} from "@fn-sphere/filter"; +import { filterFnList, filterSchema, getLocaleText } from "./schema"; +import { filterTheme } from "./theme"; +import { filterRuleToQueryString } from "./transform"; +import { cacheFilterRule, getCachedFilterRule } from "./utils"; + +export interface Props { + value?: string; + onChange?: (value: string) => void; +} + +const AdvancedFilterBuilder = (props: Props) => { + const defaultRule = getCachedFilterRule(props.value ?? "") ?? undefined; + const { context } = useFilterSphere({ + schema: filterSchema, + defaultRule, + filterFnList, + getLocaleText, + onRuleChange: ({ filterRule }) => { + const query = filterRuleToQueryString(filterRule); + props.onChange?.(query); + cacheFilterRule(query, filterRule); + }, + }); + return ( + + + + ); +}; + +export default AdvancedFilterBuilder; diff --git a/app/components/filter-sphere/index.ts b/app/components/filter-sphere/index.ts new file mode 100644 index 0000000..ad3d29c --- /dev/null +++ b/app/components/filter-sphere/index.ts @@ -0,0 +1,4 @@ +import AdvancedFilterBuilder from "./filter"; +export { getCachedFilterRule } from "./utils"; + +export default AdvancedFilterBuilder; diff --git a/app/components/filter-sphere/schema.ts b/app/components/filter-sphere/schema.ts new file mode 100644 index 0000000..ee7a96e --- /dev/null +++ b/app/components/filter-sphere/schema.ts @@ -0,0 +1,51 @@ +import { defineTypedFn, FnSchema, presetFilter } from "@fn-sphere/filter"; +import { z } from "zod"; +import { zhCN } from "@fn-sphere/filter/locales"; + +export const filterSchema = z.object({ + title: z.string().describe("文章标题"), + author: z.array(z.string()).describe("文章作者"), + tags: z.array(z.string()).describe("文章标签"), + content: z.string().describe("文章内容"), + date: z.date().describe("发布时间"), + link: z.string().describe("文章链接"), + content_length: z.number().describe("文章字数"), + id: z.string().describe("ID"), + id_feed: z.number().describe("Feed ID"), +}); + +const notStartsWithFilter = defineTypedFn({ + name: "notStartsWith", + define: z.function().args(z.string(), z.coerce.string()).returns(z.boolean()), + // Just a placeholder since we don't need filter data at frontend. + implement: () => false, +}); + +const filterPriority = [ + "contains", + "notContains", + "startsWith", + "notStartsWith", +]; + +export const filterFnList: FnSchema[] = [ + ...presetFilter.filter((fn) => fn.name !== "endsWith"), + notStartsWithFilter, +].sort((a, b) => { + const indexA = filterPriority.indexOf(a.name); + const indexB = filterPriority.indexOf(b.name); + return ( + (indexA === -1 ? Infinity : indexA) - (indexB === -1 ? Infinity : indexB) + ); +}); + +const locale: Record = { + ...zhCN, + startsWith: "以...开始", + notStartsWith: "不以...开始", +}; + +export const getLocaleText = (key: string): string => { + if (!(key in locale)) return key; + return locale[key]; +}; diff --git a/app/components/filter-sphere/theme.tsx b/app/components/filter-sphere/theme.tsx new file mode 100644 index 0000000..df424cc --- /dev/null +++ b/app/components/filter-sphere/theme.tsx @@ -0,0 +1,135 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { cn } from "@/lib/utils"; +import { + type FilterTheme, + createFilterTheme, + presetTheme, + useFilterGroup, + useRootRule, + useView, +} from "@fn-sphere/filter"; +import { type ChangeEvent, useCallback } from "react"; + +// See http://www.waterwater.moe/fn-sphere/customization/theme/ + +const componentsSpec = { + Button: (props) => { + return + + {depth < 3 && ( + + )} + {!isRoot && ( + + )} + + {children} + + ); + }, + FilterSelect: (props) => { + const PresetFilterSelect = presetTheme.templates.FilterSelect; + return ; + }, +} satisfies Partial; + +export const filterTheme = createFilterTheme({ + components: componentsSpec, + templates: templatesSpec, +}); diff --git a/app/components/filter-sphere/transform.test.ts b/app/components/filter-sphere/transform.test.ts new file mode 100644 index 0000000..34290f8 --- /dev/null +++ b/app/components/filter-sphere/transform.test.ts @@ -0,0 +1,229 @@ +import { describe, it, expect } from "vitest"; +import { + deserializeFilterGroup, + filterRuleToQueryString, + serializeFilterGroup, +} from "./transform"; +import type { FilterGroup } from "@fn-sphere/filter"; + +describe("filterRuleToQueryString", () => { + it("should transform simple equals filter", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "equals", + args: ["hello world"], + }, + ], + }; + expect(filterRuleToQueryString(filter)).toBe('(title = "hello world")'); + }); + + it("should handle multiple conditions with AND", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "startsWith", + args: ["2025"], + }, + { + id: "2" as FilterGroup["id"], + type: "Filter", + path: ["content_length"], + name: "lessThan", + args: [10], + }, + ], + }; + expect(filterRuleToQueryString(filter)).toBe( + '(title STARTS WITH "2025" AND content_length < 10)' + ); + }); + + it("should handle nested filter groups", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "or", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "startsWith", + args: ["2025"], + }, + { + id: "2" as FilterGroup["id"], + type: "Filter", + path: ["content_length"], + name: "lessThan", + args: [10], + }, + ], + }, + { + id: "4" as FilterGroup["id"], + type: "Filter", + path: ["id"], + name: "equals", + args: ["1726778286371046"], + }, + ], + }; + expect(filterRuleToQueryString(filter)).toBe( + '((title STARTS WITH "2025" AND content_length < 10) OR id = "1726778286371046")' + ); + }); + + it("should handle tag for CONTAINS operator", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["tags"], + name: "contains", + args: ["ctf"], + }, + ], + }; + expect(filterRuleToQueryString(filter)).toBe(`(tags CONTAINS "ctf")`); + }); + + it("should handle date values", () => { + const date = new Date(2024, 0, 1); // January 1, 2024 + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["createdAt"], + name: "before", + args: [date], + }, + ], + }; + expect(filterRuleToQueryString(filter)).toBe("(createdAt < sec(2024-1-1))"); + }); + + it("should handle unary filter cases", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "isEmpty", + args: [], + }, + ], + }; + + expect(filterRuleToQueryString(filter)).toBe("(title IS EMPTY)"); + }); + + it("should return empty string for empty filter", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "equals", + args: [], + }, + ], + }; + + expect(filterRuleToQueryString(filter)).toBe(""); + }); + + it("should return empty string for empty filter group", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [], + }; + expect(filterRuleToQueryString(filter)).toBe(""); + }); +}); + +describe("FilterGroup Serialization", () => { + it("should serialize and deserialize a basic FilterGroup", () => { + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["title"], + name: "equals", + args: ["test"], + }, + ], + }; + + const serialized = serializeFilterGroup(filter); + const deserialized = deserializeFilterGroup(serialized); + expect(deserialized).toEqual(filter); + }); + + it("should handle Date objects in args correctly", () => { + const date = new Date("2024-03-15T12:00:00Z"); + const filter: FilterGroup = { + id: "0" as FilterGroup["id"], + type: "FilterGroup", + op: "and", + conditions: [ + { + id: "1" as FilterGroup["id"], + type: "Filter", + path: ["createdAt"], + name: "equals", + args: [date], + }, + ], + }; + + const serialized = serializeFilterGroup(filter); + const deserialized = deserializeFilterGroup(serialized); + console.log(serialized, deserialized) + expect((deserialized.conditions[0] as any).args[0]).toBeInstanceOf(Date); + expect((deserialized.conditions[0] as any).args[0].toISOString()).toBe( + date.toISOString() + ); + }); +}); diff --git a/app/components/filter-sphere/transform.ts b/app/components/filter-sphere/transform.ts new file mode 100644 index 0000000..dd5ba3f --- /dev/null +++ b/app/components/filter-sphere/transform.ts @@ -0,0 +1,173 @@ +import { FilterGroup, SingleFilter } from "@fn-sphere/filter"; +import { filterFnList } from "./schema"; +import { z } from "zod"; + +// Define operator mapping +const FILTER_OPERATORS: Record = { + equals: "=", + notEquals: "!=", + greaterThan: ">", + greaterThanOrEqual: ">=", + lessThan: "<", + lessThanOrEqual: "<=", + contains: "CONTAINS", + notContains: "NOT CONTAINS", + startsWith: "STARTS WITH", + notStartsWith: "NOT STARTS WITH", + in: "IN", + notIn: "NOT IN", + isNull: "IS NULL", + isNotNull: "IS NOT NULL", + isEmpty: "IS EMPTY", + isNotEmpty: "IS NOT EMPTY", + before: "<", + after: ">", +}; + +/** + * Checks if a filter is unary (takes 0 or 1 parameters) + * + * Unary filters include operations like isNull, isEmpty, isNotNull etc. + */ +const checkUnaryFilter = (filterName: string) => { + // use `validateRule` from @fn-sphere/core in the future + const filterSchema = filterFnList.find((fn) => fn.name === filterName); + if (!filterSchema) throw new Error("Unknown filter! " + filterName); + const filterDefine = + typeof filterSchema.define === "function" + ? filterSchema.define(z.any()) + : filterSchema.define; + const parameters = filterDefine.parameters(); + return parameters.items.length <= 1; +}; + +function transformSingleFilter(filter: SingleFilter): string | null { + const path = filter.path?.[0]; + const operator = filter.name ? FILTER_OPERATORS[filter.name] : undefined; + const value = filter.args[0]; + + if (!filter.name || path === undefined || operator === undefined) { + return null; + } + const isUnaryFilter = checkUnaryFilter(filter.name); + if (value === undefined && !isUnaryFilter) { + return null; + } + + // Handle array values for IN/NOT IN operators + if (Array.isArray(value)) { + return `${path} ${operator} [${value + .map((v) => (typeof v === "string" ? `${v}` : v)) + .join(", ")}]`; + } + + if (value === undefined) { + return `${path} ${operator}`; + } + + // Handle string values + if (typeof value === "string") { + return `${path} ${operator} "${value}"`; + } + // Handle date values + if (value instanceof Date) { + const dateStr = `sec(${value.getFullYear()}-${ + value.getMonth() + 1 + }-${value.getDate()})`; + return `${path} ${operator} ${dateStr}`; + } + + return `${path} ${operator} ${value}`; +} + +function transformFilterGroup(filterGroup: FilterGroup): string | null { + if (!filterGroup.conditions.length) return ""; + + const conditions = filterGroup.conditions.map((condition) => { + if (condition.type === "Filter") { + return transformSingleFilter(condition); + } else { + return transformFilterGroup(condition); + } + }); + + const operator = filterGroup.op.toUpperCase() as Uppercase; + const result = conditions.filter((i) => i !== null).join(` ${operator} `); + if (!result) { + return null; + } + + return `(${result})`; +} + +/** + * Transforms a FilterGroup object into a query string format for advanced search. + * + * @example + * ```ts + * filterRuleToQueryString({ + * type: "FilterGroup", + * op: "and", + * conditions: [{ + * type: "Filter", + * path: ["title"], + * name: "equals", + * args: ["hello world"] + * }] + * }) + * // "(title = "hello world")" + * ``` + */ +export const filterRuleToQueryString = (filterGroup: FilterGroup) => { + return transformFilterGroup(filterGroup) ?? ""; +}; + +/** + * Serializes a FilterGroup object to JSON string with special date handling + */ +export function serializeFilterGroup(filterGroup: FilterGroup): string { + const replacer = function (this: any, key: string, value: any) { + // Special handling for Date objects in args + return this[key] instanceof Date + ? { + __type: "Date", + value: this[key].toISOString(), + } + : this[key]; + }; + const serialized = JSON.stringify(filterGroup, replacer); + return serialized; +} + +/** + * deserializes a JSON string back to FilterGroup object + */ +export function deserializeFilterGroup(serialized: string): FilterGroup { + const deserialized = JSON.parse(serialized, (key, value) => { + // Revive Date objects from special format + if (value && typeof value === "object" && value.__type === "Date") { + return new Date(value.value); + } + return value; + }); + + // Type guard to ensure we have a valid FilterGroup + if (!isValidFilterGroup(deserialized)) { + throw new Error("Invalid FilterGroup structure"); + } + return deserialized; +} + +/** + * Type guard to validate FilterGroup structure + */ +function isValidFilterGroup(obj: any): obj is FilterGroup { + return ( + obj && + typeof obj === "object" && + typeof obj.id === "string" && + obj.type === "FilterGroup" && + (obj.op === "and" || obj.op === "or") && + Array.isArray(obj.conditions) + ); +} diff --git a/app/components/filter-sphere/utils.ts b/app/components/filter-sphere/utils.ts new file mode 100644 index 0000000..f5cb205 --- /dev/null +++ b/app/components/filter-sphere/utils.ts @@ -0,0 +1,30 @@ +import { FilterGroup } from "@fn-sphere/filter"; +import { deserializeFilterGroup, serializeFilterGroup } from "./transform"; + +const STORAGE_KEY = "filter-rule-cache"; + +export const cacheFilterRule = (query: string, rule: FilterGroup) => { + if (!("localStorage" in globalThis)) return; + + const obj = { + key: query, + value: serializeFilterGroup(rule), + }; + localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); +}; + +export const getCachedFilterRule = (query: string) => { + if (!("localStorage" in globalThis)) return; + + const str = localStorage.getItem(STORAGE_KEY); + if (!str) return null; + + try { + const obj = JSON.parse(str); + if (obj.key !== query) return null; + return deserializeFilterGroup(obj.value); + } catch (error) { + console.error("Failed to parse cached filter rule!", str); + return null; + } +}; diff --git a/app/components/search-box.tsx b/app/components/search-box.tsx index d228fba..1413dbf 100644 --- a/app/components/search-box.tsx +++ b/app/components/search-box.tsx @@ -14,6 +14,7 @@ import { SelectValue, } from "@/components/ui/select"; import ManualDialog from "./manual-dialog"; +import AdvancedFilterBuilder, { getCachedFilterRule } from "./filter-sphere"; export interface Props { query: string; @@ -34,6 +35,9 @@ export default function Search(props: Props) { const [useAdvancedSearch, setUseAdvancedSearch] = React.useState( props.initAdvancedSearch ); + const [isExpertMode, setIsExpertMode] = React.useState( + props.initAdvancedSearch && !getCachedFilterRule(props.query) + ); const [sort, setSort] = React.useState(Sort.Relevance); useEffect(() => { props.onSortChange(sort); @@ -45,6 +49,19 @@ export default function Search(props: Props) {
+ {useAdvancedSearch && ( + <> + + setIsExpertMode(prev)} + /> + + )} @@ -93,7 +110,14 @@ export default function Search(props: Props) { {useAdvancedSearch ? ( - + isExpertMode ? ( + + ) : ( + + ) ) : ( )} diff --git a/app/components/search.tsx b/app/components/search.tsx index ceba84a..7770b47 100644 --- a/app/components/search.tsx +++ b/app/components/search.tsx @@ -2,7 +2,6 @@ import { useState, useEffect, useCallback } from "react"; import { useRouter, useSearchParams } from "next/navigation"; -import { Button } from "@/components/ui/button"; import SearchResults from "./search-results"; import debounce from "lodash.debounce"; import SearchBox, { Sort } from "./search-box"; @@ -49,11 +48,13 @@ export default function Search() { const handleSearch = (e: React.FormEvent) => { e.preventDefault(); + if (!query.length) return const encodedQuery = encodeURIComponent(query); router.push(`/search?q=${encodedQuery}&sort=${sort}`, { scroll: false }); }; const handleInputChange = (s: string) => { + if (s === query) return; setQuery(s); debouncedUpdateURL(s); }; diff --git a/app/page.tsx b/app/page.tsx index a817029..93c97a7 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -66,7 +66,7 @@ export default function Home() {
-

+


[AD] 正在进行中的项目: @@ -82,7 +82,7 @@ export default function Home() { GitHub {" "} via MIT License. -

+
); } diff --git a/components/ui/input.tsx b/components/ui/input.tsx index 27af00b..d321ed6 100644 --- a/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -21,7 +21,16 @@ const Input = React.forwardRef< if (inputRef.current) { inputRef.current.focus(); const length = inputRef.current.value.length; - inputRef.current.setSelectionRange(length, length); + // HTMLInputElement: setSelectionRange() method + // The element must be of one of the following input types: password, search, tel, text, or url. + // Otherwise the browser throws an InvalidStateError exception. + if ( + ["password", "search", "tel", "text", "url"].includes( + inputRef.current.type + ) + ) { + inputRef.current.setSelectionRange(length, length); + } } }, []); @@ -40,7 +49,7 @@ const Input = React.forwardRef< className )} ref={inputRef} - defaultValue={value} + value={value} {...inputProps} {...props} /> diff --git a/package.json b/package.json index 2168eaa..efd1953 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,16 @@ }, "license": "MIT", "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "test": "vitest" }, "dependencies": { "@codemirror/lang-sql": "^6.8.0", "@codemirror/view": "^6.36.2", + "@fn-sphere/filter": "^0.7.1", "@mantine/core": "^7.15.3", "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-select": "^2.1.4", @@ -34,7 +36,8 @@ "react-dom": "^19.0.0", "react-intersection-observer": "^9.14.1", "tailwind-merge": "^2.6.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zod": "^3.24.1" }, "devDependencies": { "@types/lodash.debounce": "^4.0.9", @@ -43,6 +46,7 @@ "@types/react-dom": "^19.0.2", "postcss": "^8.4.49", "tailwindcss": "^3.4.17", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "vitest": "^3.0.4" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c7abc1..0947202 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@codemirror/view': specifier: ^6.36.2 version: 6.36.2 + '@fn-sphere/filter': + specifier: ^0.7.1 + version: 0.7.1(@types/react@19.0.4)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.24.1) '@mantine/core': specifier: ^7.15.3 version: 7.15.3(@mantine/hooks@7.15.2(react@19.0.0))(@types/react@19.0.4)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -74,6 +77,9 @@ importers: tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@3.4.17) + zod: + specifier: ^3.24.1 + version: 3.24.1 devDependencies: '@types/lodash.debounce': specifier: ^4.0.9 @@ -96,6 +102,9 @@ importers: typescript: specifier: ^5.7.3 version: 5.7.3 + vitest: + specifier: ^3.0.4 + version: 3.0.4(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0) packages: @@ -137,6 +146,156 @@ packages: '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@floating-ui/core@1.6.9': resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} @@ -158,6 +317,22 @@ packages: '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@fn-sphere/core@0.6.0': + resolution: {integrity: sha512-3XvDjG5Qw54qFrzMtL4znL/S7ZhWN3jQJEJ0sqZnEe/xjSc0+6PCxdCULyXgjy/LxEIMjYbSorE26EeQVLcqAw==} + peerDependencies: + zod: ^3.0.0 + + '@fn-sphere/filter@0.7.1': + resolution: {integrity: sha512-pt8v6sWci0GJfXVx+PnPy9E/jhDKekERraNUFP4E5BPG/Q5z33L0tFTZ2PEP3bqYiDdSvfTtJKhoHtbmwsLDuA==} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + zod: ^3.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -658,6 +833,101 @@ packages: '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + '@rollup/rollup-android-arm-eabi@4.34.0': + resolution: {integrity: sha512-Eeao7ewDq79jVEsrtWIj5RNqB8p2knlm9fhR6uJ2gqP7UfbLrTrxevudVrEPDM7Wkpn/HpRC2QfazH7MXLz3vQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.34.0': + resolution: {integrity: sha512-yVh0Kf1f0Fq4tWNf6mWcbQBCLDpDrDEl88lzPgKhrgTcDrTtlmun92ywEF9dCjmYO3EFiSuJeeo9cYRxl2FswA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.34.0': + resolution: {integrity: sha512-gCs0ErAZ9s0Osejpc3qahTsqIPUDjSKIyxK/0BGKvL+Tn0n3Kwvj8BrCv7Y5sR1Ypz1K2qz9Ny0VvkVyoXBVUQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.34.0': + resolution: {integrity: sha512-aIB5Anc8hngk15t3GUkiO4pv42ykXHfmpXGS+CzM9CTyiWyT8HIS5ygRAy7KcFb/wiw4Br+vh1byqcHRTfq2tQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.34.0': + resolution: {integrity: sha512-kpdsUdMlVJMRMaOf/tIvxk8TQdzHhY47imwmASOuMajg/GXpw8GKNd8LNwIHE5Yd1onehNpcUB9jHY6wgw9nHQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.34.0': + resolution: {integrity: sha512-D0RDyHygOBCQiqookcPevrvgEarN0CttBecG4chOeIYCNtlKHmf5oi5kAVpXV7qs0Xh/WO2RnxeicZPtT50V0g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.34.0': + resolution: {integrity: sha512-mCIw8j5LPDXmCOW8mfMZwT6F/Kza03EnSr4wGYEswrEfjTfVsFOxvgYfuRMxTuUF/XmRb9WSMD5GhCWDe2iNrg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.34.0': + resolution: {integrity: sha512-AwwldAu4aCJPob7zmjuDUMvvuatgs8B/QiVB0KwkUarAcPB3W+ToOT+18TQwY4z09Al7G0BvCcmLRop5zBLTag==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.34.0': + resolution: {integrity: sha512-e7kDUGVP+xw05pV65ZKb0zulRploU3gTu6qH1qL58PrULDGxULIS0OSDQJLH7WiFnpd3ZKUU4VM3u/Z7Zw+e7Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.34.0': + resolution: {integrity: sha512-SXYJw3zpwHgaBqTXeAZ31qfW/v50wq4HhNVvKFhRr5MnptRX2Af4KebLWR1wpxGJtLgfS2hEPuALRIY3LPAAcA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.34.0': + resolution: {integrity: sha512-e5XiCinINCI4RdyU3sFyBH4zzz7LiQRvHqDtRe9Dt8o/8hTBaYpdPimayF00eY2qy5j4PaaWK0azRgUench6WQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.0': + resolution: {integrity: sha512-3SWN3e0bAsm9ToprLFBSro8nJe6YN+5xmB11N4FfNf92wvLye/+Rh5JGQtKOpwLKt6e61R1RBc9g+luLJsc23A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.34.0': + resolution: {integrity: sha512-B1Oqt3GLh7qmhvfnc2WQla4NuHlcxAD5LyueUi5WtMc76ZWY+6qDtQYqnxARx9r+7mDGfamD+8kTJO0pKUJeJA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.34.0': + resolution: {integrity: sha512-UfUCo0h/uj48Jq2lnhX0AOhZPSTAq3Eostas+XZ+GGk22pI+Op1Y6cxQ1JkUuKYu2iU+mXj1QjPrZm9nNWV9rg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.34.0': + resolution: {integrity: sha512-chZLTUIPbgcpm+Z7ALmomXW8Zh+wE2icrG+K6nt/HenPLmtwCajhQC5flNSk1Xy5EDMt/QAOz2MhzfOfJOLSiA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.34.0': + resolution: {integrity: sha512-jo0UolK70O28BifvEsFD/8r25shFezl0aUk2t0VJzREWHkq19e+pcLu4kX5HiVXNz5qqkD+aAq04Ct8rkxgbyQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.34.0': + resolution: {integrity: sha512-Vmg0NhAap2S54JojJchiu5An54qa6t/oKT7LmDaWggpIcaiL8WcWHEN6OQrfTdL6mQ2GFyH7j2T5/3YPEDOOGA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.34.0': + resolution: {integrity: sha512-CV2aqhDDOsABKHKhNcs1SZFryffQf8vK2XrxP6lxC99ELZAdvsDgPklIBfd65R8R+qvOm1SmLaZ/Fdq961+m7A==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.34.0': + resolution: {integrity: sha512-g2ASy1QwHP88y5KWvblUolJz9rN+i4ZOsYzkEwcNfaNooxNUXG+ON6F5xFo0NIItpHqxcdAyls05VXpBnludGw==} + cpu: [x64] + os: [win32] + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -672,6 +942,9 @@ packages: peerDependencies: react: ^18 || ^19 + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/lodash.debounce@4.0.9': resolution: {integrity: sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==} @@ -711,6 +984,35 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' + '@vitest/expect@3.0.4': + resolution: {integrity: sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==} + + '@vitest/mocker@3.0.4': + resolution: {integrity: sha512-gEef35vKafJlfQbnyOXZ0Gcr9IBUsMTyTLXsEQwuyYAerpHqvXhzdBnDFuHLpFqth3F7b6BaFr4qV/Cs1ULx5A==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.0.4': + resolution: {integrity: sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==} + + '@vitest/runner@3.0.4': + resolution: {integrity: sha512-dKHzTQ7n9sExAcWH/0sh1elVgwc7OJ2lMOBrAm73J7AH6Pf9T12Zh3lNE1TETZaqrWFXtLlx3NVrLRb5hCK+iw==} + + '@vitest/snapshot@3.0.4': + resolution: {integrity: sha512-+p5knMLwIk7lTQkM3NonZ9zBewzVp9EVkVpvNta0/PlFWpiqLaRcF4+33L1it3uRUCh0BGLOaXPPGEjNKfWb4w==} + + '@vitest/spy@3.0.4': + resolution: {integrity: sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==} + + '@vitest/utils@3.0.4': + resolution: {integrity: sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -741,6 +1043,10 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -759,6 +1065,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} @@ -766,6 +1076,14 @@ packages: caniuse-lite@1.0.30001692: resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -816,6 +1134,19 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -838,6 +1169,21 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -945,6 +1291,9 @@ packages: lottie-web@5.12.2: resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==} + loupe@3.1.3: + resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -953,6 +1302,9 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -969,6 +1321,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -1031,6 +1386,13 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + pathe@2.0.2: + resolution: {integrity: sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1173,6 +1535,11 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.34.0: + resolution: {integrity: sha512-+4C/cgJ9w6sudisA0nZz0+O7lTP9a3CzNLsoDwaRumM8QHwghUsu6tqHXiTmNUp/rqNiM14++7dkzHDyCRs0Jg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1199,6 +1566,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1210,6 +1580,12 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -1278,6 +1654,24 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1350,6 +1744,79 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite-node@3.0.4: + resolution: {integrity: sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@6.0.11: + resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.0.4: + resolution: {integrity: sha512-6XG8oTKy2gnJIFTHP6LD7ExFeNLxiTkK3CfMvT7IfR8IN+BYICCf0lXUQmX7i7JoxUP8QmeP4mTnWXgflu4yjw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.0.4 + '@vitest/ui': 3.0.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -1358,6 +1825,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1371,6 +1843,15 @@ packages: engines: {node: '>= 14'} hasBin: true + zod-compare@0.3.1: + resolution: {integrity: sha512-e05e3zgEgDAGGCDSW3Td5aQXNBCEm1MvCyWgRHHLUT3YWAKI2F7aZ4DPXCXDFkCLCvbJbnY2KLxlXssnlOA/Tg==} + engines: {node: '>=20'} + peerDependencies: + zod: ^3.22.4 + + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -1445,6 +1926,81 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + '@floating-ui/core@1.6.9': dependencies: '@floating-ui/utils': 0.2.9 @@ -1470,6 +2026,20 @@ snapshots: '@floating-ui/utils@0.2.9': {} + '@fn-sphere/core@0.6.0(zod@3.24.1)': + dependencies: + zod: 3.24.1 + zod-compare: 0.3.1(zod@3.24.1) + + '@fn-sphere/filter@0.7.1(@types/react@19.0.4)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(zod@3.24.1)': + dependencies: + '@fn-sphere/core': 0.6.0(zod@3.24.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + zod: 3.24.1 + optionalDependencies: + '@types/react': 19.0.4 + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -1899,6 +2469,63 @@ snapshots: '@radix-ui/rect@1.1.0': {} + '@rollup/rollup-android-arm-eabi@4.34.0': + optional: true + + '@rollup/rollup-android-arm64@4.34.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.34.0': + optional: true + + '@rollup/rollup-darwin-x64@4.34.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.34.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.34.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.34.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.34.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.34.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.34.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.34.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.34.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.34.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.34.0': + optional: true + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -1912,6 +2539,8 @@ snapshots: '@tanstack/query-core': 5.64.0 react: 19.0.0 + '@types/estree@1.0.6': {} + '@types/lodash.debounce@4.0.9': dependencies: '@types/lodash': 4.17.14 @@ -1957,6 +2586,46 @@ snapshots: - '@codemirror/lint' - '@codemirror/search' + '@vitest/expect@3.0.4': + dependencies: + '@vitest/spy': 3.0.4 + '@vitest/utils': 3.0.4 + chai: 5.1.2 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.0.4(vite@6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0))': + dependencies: + '@vitest/spy': 3.0.4 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0) + + '@vitest/pretty-format@3.0.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.0.4': + dependencies: + '@vitest/utils': 3.0.4 + pathe: 2.0.2 + + '@vitest/snapshot@3.0.4': + dependencies: + '@vitest/pretty-format': 3.0.4 + magic-string: 0.30.17 + pathe: 2.0.2 + + '@vitest/spy@3.0.4': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@3.0.4': + dependencies: + '@vitest/pretty-format': 3.0.4 + loupe: 3.1.3 + tinyrainbow: 2.0.0 + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -1980,6 +2649,8 @@ snapshots: dependencies: tslib: 2.8.1 + assertion-error@2.0.1: {} + balanced-match@1.0.2: {} binary-extensions@2.3.0: {} @@ -1996,10 +2667,22 @@ snapshots: dependencies: streamsearch: 1.1.0 + cac@6.7.14: {} + camelcase-css@2.0.1: {} caniuse-lite@1.0.30001692: {} + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.3 + pathval: 2.0.0 + + check-error@2.1.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -2062,6 +2745,12 @@ snapshots: csstype@3.1.3: {} + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + detect-libc@2.0.3: optional: true @@ -2077,6 +2766,42 @@ snapshots: emoji-regex@9.2.2: {} + es-module-lexer@1.6.0: {} + + esbuild@0.24.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + expect-type@1.1.0: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2178,12 +2903,18 @@ snapshots: lottie-web@5.12.2: {} + loupe@3.1.3: {} + lru-cache@10.4.3: {} lucide-react@0.471.0(react@19.0.0): dependencies: react: 19.0.0 + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + merge2@1.4.1: {} micromatch@4.0.8: @@ -2197,6 +2928,8 @@ snapshots: minipass@7.1.2: {} + ms@2.1.3: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -2253,6 +2986,10 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + pathe@2.0.2: {} + + pathval@2.0.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -2378,6 +3115,31 @@ snapshots: reusify@1.0.4: {} + rollup@4.34.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.34.0 + '@rollup/rollup-android-arm64': 4.34.0 + '@rollup/rollup-darwin-arm64': 4.34.0 + '@rollup/rollup-darwin-x64': 4.34.0 + '@rollup/rollup-freebsd-arm64': 4.34.0 + '@rollup/rollup-freebsd-x64': 4.34.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.0 + '@rollup/rollup-linux-arm-musleabihf': 4.34.0 + '@rollup/rollup-linux-arm64-gnu': 4.34.0 + '@rollup/rollup-linux-arm64-musl': 4.34.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.0 + '@rollup/rollup-linux-riscv64-gnu': 4.34.0 + '@rollup/rollup-linux-s390x-gnu': 4.34.0 + '@rollup/rollup-linux-x64-gnu': 4.34.0 + '@rollup/rollup-linux-x64-musl': 4.34.0 + '@rollup/rollup-win32-arm64-msvc': 4.34.0 + '@rollup/rollup-win32-ia32-msvc': 4.34.0 + '@rollup/rollup-win32-x64-msvc': 4.34.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -2422,6 +3184,8 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + signal-exit@4.1.0: {} simple-swizzle@0.2.2: @@ -2431,6 +3195,10 @@ snapshots: source-map-js@1.2.1: {} + stackback@0.0.2: {} + + std-env@3.8.0: {} + streamsearch@1.1.0: {} string-width@4.2.3: @@ -2515,6 +3283,16 @@ snapshots: dependencies: any-promise: 1.3.0 + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinypool@1.0.2: {} + + tinyrainbow@2.0.0: {} + + tinyspy@3.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -2565,12 +3343,87 @@ snapshots: util-deprecate@1.0.2: {} + vite-node@3.0.4(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.6.0 + pathe: 2.0.2 + vite: 6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0): + dependencies: + esbuild: 0.24.2 + postcss: 8.4.49 + rollup: 4.34.0 + optionalDependencies: + '@types/node': 20.17.12 + fsevents: 2.3.3 + jiti: 1.21.7 + yaml: 2.7.0 + + vitest@3.0.4(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0): + dependencies: + '@vitest/expect': 3.0.4 + '@vitest/mocker': 3.0.4(vite@6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/pretty-format': 3.0.4 + '@vitest/runner': 3.0.4 + '@vitest/snapshot': 3.0.4 + '@vitest/spy': 3.0.4 + '@vitest/utils': 3.0.4 + chai: 5.1.2 + debug: 4.4.0 + expect-type: 1.1.0 + magic-string: 0.30.17 + pathe: 2.0.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.0.11(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0) + vite-node: 3.0.4(@types/node@20.17.12)(jiti@1.21.7)(yaml@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.17.12 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + w3c-keyname@2.2.8: {} which@2.0.2: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -2584,3 +3437,9 @@ snapshots: strip-ansi: 7.1.0 yaml@2.7.0: {} + + zod-compare@0.3.1(zod@3.24.1): + dependencies: + zod: 3.24.1 + + zod@3.24.1: {}