fix: stop shipping full Module registry to the frontend — serve ModuleMetadata only

- Extract a new `ModuleMetadata` type (rename of `ModuleSummary`) containing only the display/resolution fields needed client-side; the full `Module` graph (templates, codemods, file lists, etc.) stays server-side
- Replace the dual `modules: Record<string, Module>` + `summaries: ModuleSummary[]` props on `Builder` and `ModuleCards` with a single `metadata: ModuleMetadata[]`; category bucketing and `${cat}:${id}` keyed lookup are derived once via `useMemo` inside `ModuleCards`
- Teach `resolveAdapter` (and its call sites in `module-cards.tsx`, `selection.ts`, `resolver.ts`) to accept `ModuleMetadata` directly so adapter-compatibility checks no longer require a full `Module` lookup
- Update `builder-state.functions.ts` and the index route to project only metadata before the server function returns, removing the `state.modules` record from the serialized payload
This commit is contained in:
2026-05-27 16:07:49 -04:00
parent 7554ae92eb
commit 2de4b24fc9
21 changed files with 530 additions and 303 deletions
+4 -4
View File
@@ -20,7 +20,7 @@
"@stanza/registry": "workspace:*",
"@tabler/icons-react": "^3.44.0",
"@tailwindcss/vite": "^4.3.0",
"@takumi-rs/image-response": "^1.5.1",
"@takumi-rs/image-response": "^1.6.0",
"@tanstack/react-devtools": "^0.10.5",
"@tanstack/react-hotkeys": "^0.10.0",
"@tanstack/react-pacer": "^0.22.1",
@@ -34,15 +34,15 @@
"fumadocs-core": "^16.9.1",
"fumadocs-mdx": "^15.0.9",
"fumadocs-ui": "npm:@fumadocs/base-ui@^16.9.1",
"lru-cache": "^11.5.0",
"lru-cache": "^11.5.1",
"motion": "^12.40.0",
"nitro": "^3.0.260522-beta",
"posthog-node": "^5.35.4",
"posthog-node": "^5.35.5",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"react-resizable-panels": "^4.11.2",
"recharts": "^3.8.1",
"shadcn": "^4.8.1",
"shadcn": "^4.8.2",
"shiki": "^4.1.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
+16 -13
View File
@@ -1,4 +1,4 @@
import type { CategoryId } from "@stanza/registry";
import type { CategoryId, ModuleMetadata } from "@stanza/registry";
import { isMulti } from "@stanza/registry";
import { useNavigate, useRouterState } from "@tanstack/react-router";
import { track } from "@vercel/analytics";
@@ -19,7 +19,15 @@ import {
} from "@/lib/selection";
import type { BuilderState } from "@/server/builder-state.functions";
export function Builder({ state, search }: { state: BuilderState; search: BuilderSearch }) {
export function Builder({
state,
search,
metadata,
}: {
state: BuilderState;
search: BuilderSearch;
metadata: ModuleMetadata[];
}) {
const navigate = useNavigate({ from: "/" });
// Same-pathname gate so navigations *away* from this route don't flash the
// overlay before the page unmounts. `useRouterState` is the documented
@@ -33,16 +41,16 @@ export function Builder({ state, search }: { state: BuilderState; search: Builde
// Drop orphaned dependents from a shared link (e.g. `?orm=drizzle` with no
// `db`) so cards + command don't render an unresolvable selection.
const selections = useMemo(
() => pruneUnresolved(state.modules, parsed.selections),
[state.modules, parsed.selections],
() => pruneUnresolved(metadata, parsed.selections),
[metadata, parsed.selections],
);
const [optimistic, setOptimistic] = useOptimistic(selections, (_prev, next: Selections) => next);
// Latest-value snapshot so setName/setPm/toggle keep stable identities and
// downstream memoization (`ModuleCard(s)`) actually pays off.
const latest = useRef({ name, pm, optimistic, modules: state.modules });
latest.current = { name, pm, optimistic, modules: state.modules };
const latest = useRef({ name, pm, optimistic, metadata });
latest.current = { name, pm, optimistic, metadata };
const setName = useCallback(
(next: string) => {
@@ -99,7 +107,7 @@ export function Builder({ state, search }: { state: BuilderState; search: Builde
track("builder_module_selected", { category, module: id });
}
// Dropping a peer can strand its dependents (e.g. `db` → `orm`); prune.
const next = pruneUnresolved(snapshot.modules, draft);
const next = pruneUnresolved(snapshot.metadata, draft);
startTransition(async () => {
setOptimistic(next);
await navigate({
@@ -121,12 +129,7 @@ export function Builder({ state, search }: { state: BuilderState; search: Builde
them to reach it). On lg the right column owns it instead. */}
<div className="min-w-0 lg:hidden">{commandBar}</div>
<section className="min-w-0 space-y-8">
<ModuleCards
modules={state.modules}
summaries={state.index.modules}
selections={optimistic}
onToggle={toggle}
/>
<ModuleCards metadata={metadata} selections={optimistic} onToggle={toggle} />
</section>
<section className="flex min-w-0 flex-col gap-6 lg:sticky lg:top-20 lg:h-[calc(100vh-6rem)] lg:self-start">
<div className="hidden lg:block">{commandBar}</div>
@@ -1,4 +1,4 @@
import type { CategoryId, Module, ModuleSummary, ResolveError } from "@stanza/registry";
import type { CategoryId, ModuleMetadata, ResolveError } from "@stanza/registry";
import {
categoryLabel,
emptyManifest,
@@ -21,37 +21,40 @@ import { cn } from "@/lib/utils";
const RESOLVER_MANIFEST = emptyManifest({ name: "t" });
export function ModuleCards({
modules,
summaries,
metadata,
selections,
onToggle,
}: {
modules: Record<string, Module>;
summaries: ModuleSummary[];
metadata: ModuleMetadata[];
selections: Selections;
onToggle: (category: CategoryId, id: string) => void;
}) {
// Bucket metadata by category once, and also build a flat `${cat}:${id}`
// lookup the peer-context memo reuses.
const { byCategory, byKey } = useMemo(() => {
const buckets = new Map<CategoryId, ModuleMetadata[]>();
const keyed = new Map<string, ModuleMetadata>();
for (const m of metadata) {
const list = buckets.get(m.category);
if (list) list.push(m);
else buckets.set(m.category, [m]);
keyed.set(`${m.category}:${m.id}`, m);
}
return { byCategory: buckets, byKey: keyed };
}, [metadata]);
// Shared peer context: the chosen one-cardinality modules. Every card resolves
// compatibility against this.
const pending = useMemo<Partial<Record<CategoryId, Module>>>(() => {
const out: Partial<Record<CategoryId, Module>> = {};
const pending = useMemo<Partial<Record<CategoryId, ModuleMetadata>>>(() => {
const out: Partial<Record<CategoryId, ModuleMetadata>> = {};
for (const c of PEER_CATEGORIES) {
const id = selections[c]?.[0];
if (id && modules[`${c}:${id}`]) out[c] = modules[`${c}:${id}`];
if (!id) continue;
const mod = byKey.get(`${c}:${id}`);
if (mod) out[c] = mod;
}
return out;
}, [modules, selections]);
// Bucket summaries by category once instead of filtering per-section.
const byCategory = useMemo(() => {
const map = new Map<CategoryId, ModuleSummary[]>();
for (const m of summaries) {
const list = map.get(m.category);
if (list) list.push(m);
else map.set(m.category, [m]);
}
return map;
}, [summaries]);
}, [byKey, selections]);
// Only render categories that actually have modules in the registry.
const categories = useMemo(() => KNOWN_CATEGORIES.filter((c) => byCategory.has(c)), [byCategory]);
@@ -62,8 +65,7 @@ export function ModuleCards({
<ModuleSection
key={category}
group={category}
summaries={byCategory.get(category) ?? []}
modulesById={modules}
metadata={byCategory.get(category) ?? []}
pending={pending}
selections={selections}
index={index + 1}
@@ -77,8 +79,7 @@ export function ModuleCards({
function ModuleSection({
group,
summaries,
modulesById,
metadata,
pending,
selections,
index,
@@ -86,15 +87,14 @@ function ModuleSection({
onToggle,
}: {
group: CategoryId;
summaries: ModuleSummary[];
modulesById: Record<string, Module>;
pending: Partial<Record<CategoryId, Module>>;
metadata: ModuleMetadata[];
pending: Partial<Record<CategoryId, ModuleMetadata>>;
selections: Selections;
index: number;
multi: boolean;
onToggle: (category: CategoryId, id: string) => void;
}) {
if (summaries.length === 0) return null;
if (metadata.length === 0) return null;
const selectedIds = selections[group];
return (
@@ -106,14 +106,11 @@ function ModuleSection({
<h2 className="text-lg font-medium tracking-tight">{categoryLabel(group)}</h2>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
{summaries.map((m) => {
const full = modulesById[`${m.category}:${m.id}`];
const result = full
? resolveAdapter(full, { manifest: RESOLVER_MANIFEST, pending })
: undefined;
const disabled = !result?.ok;
{metadata.map((m) => {
const result = resolveAdapter(m, { manifest: RESOLVER_MANIFEST, pending });
const disabled = !result.ok;
const selected = Boolean(selectedIds?.includes(m.id));
const reason = result && !result.ok ? describeError(result.error) : undefined;
const reason = !result.ok ? describeError(result.error) : undefined;
return (
<ModuleCard
key={m.id}
@@ -139,7 +136,7 @@ const ModuleCard = memo(function ModuleCard({
reason,
onToggle,
}: {
module: ModuleSummary;
module: ModuleMetadata;
category: CategoryId;
selected: boolean;
disabled: boolean;
@@ -1,10 +1,10 @@
import type { CategoryId, ModuleSummary, RegistryIndex } from "@stanza/registry";
import type { CategoryId, ModuleMetadata, RegistryIndex } from "@stanza/registry";
import { categoryLabel, KNOWN_CATEGORIES } from "@stanza/registry";
import { useMemo } from "react";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
function summaryKey(slot: CategoryId, id: string): string {
function metaKey(slot: CategoryId, id: string): string {
return `${slot}:${id}`;
}
@@ -33,11 +33,11 @@ export function AdapterSwitcher({
[peerOptions],
);
// Pre-index summaries so the option-label lookup is O(1) instead of scanning
// Pre-index metadata so the option-label lookup is O(1) instead of scanning
// `index.modules` per option per slot per render.
const summaryIndex = useMemo(() => {
const map = new Map<string, ModuleSummary>();
for (const m of index.modules) map.set(summaryKey(m.category, m.id), m);
const metaIndex = useMemo(() => {
const map = new Map<string, ModuleMetadata>();
for (const m of index.modules) map.set(metaKey(m.category, m.id), m);
return map;
}, [index.modules]);
@@ -63,7 +63,7 @@ export function AdapterSwitcher({
}}
>
{options.map((id) => {
const label = summaryIndex.get(summaryKey(slot, id))?.label ?? id;
const label = metaIndex.get(metaKey(slot, id))?.label ?? id;
return (
<ToggleGroupItem
key={id}
@@ -1,6 +1,6 @@
"use client";
import type { ModuleSummary, RegistryIndex } from "@stanza/registry";
import type { ModuleMetadata, RegistryIndex } from "@stanza/registry";
import { categoryLabel } from "@stanza/registry";
import { IconBookmark, IconSearch } from "@tabler/icons-react";
import { formatForDisplay, useHotkey } from "@tanstack/react-hotkeys";
@@ -46,7 +46,7 @@ type DocItem = {
description?: string;
};
type Hit = { kind: "doc"; item: DocItem } | { kind: "module"; module: ModuleSummary };
type Hit = { kind: "doc"; item: DocItem } | { kind: "module"; module: ModuleMetadata };
type Group = { key: string; label: string; hits: Hit[] };
@@ -80,7 +80,7 @@ export function SiteSearch({ registry, docs }: { registry: RegistryIndex; docs:
// Modules: debounce the query, then fetch with an abort signal for any
// request that's still in-flight when the debounced value changes again.
const [moduleResults, setModuleResults] = useState<ModuleSummary[] | null>(null);
const [moduleResults, setModuleResults] = useState<ModuleMetadata[] | null>(null);
const moduleFetchRef = useRef<AbortController | null>(null);
const fetchModules = useDebouncedCallback(
(q: string) => {
@@ -308,13 +308,13 @@ function dedupeDocsByPage(hits: SortedResult[], pageTitlesByUrl: Map<string, str
return [...byPage.values()];
}
function parseModuleResults(data: unknown): ModuleSummary[] {
function parseModuleResults(data: unknown): ModuleMetadata[] {
if (!data || typeof data !== "object") return [];
const results = (data as { results?: unknown }).results;
if (!Array.isArray(results)) return [];
// First-party endpoint: we control the response shape in api.search.modules.ts.
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
return results as ModuleSummary[];
return results as ModuleMetadata[];
}
function hitKey(hit: Hit, index: number): string {
+4 -4
View File
@@ -1,9 +1,9 @@
import type { CategoryId, ModuleSummary } from "@stanza/registry";
import type { CategoryId, ModuleMetadata } from "@stanza/registry";
export function groupByCategory(
modules: ModuleSummary[],
): Array<{ group: CategoryId; modules: ModuleSummary[] }> {
const groups = new Map<CategoryId, ModuleSummary[]>();
modules: ModuleMetadata[],
): Array<{ group: CategoryId; modules: ModuleMetadata[] }> {
const groups = new Map<CategoryId, ModuleMetadata[]>();
for (const m of modules) {
const list = groups.get(m.category) ?? [];
list.push(m);
+39 -13
View File
@@ -1,4 +1,11 @@
import type { AppSpec, CategoryId, Module, Resolved, ResolvedEntry } from "@stanza/registry";
import type {
AppSpec,
CategoryId,
Module,
ModuleMetadata,
Resolved,
ResolvedEntry,
} from "@stanza/registry";
import {
categoryOrder,
defaultWebApp,
@@ -89,11 +96,11 @@ export function toSearchParams(input: {
}
/** Build the peer context — only one-cardinality categories can be peers. */
function pendingPeers(
modules: Record<string, Module>,
function pendingPeers<M extends { id: string }>(
modules: Record<string, M>,
selections: Selections,
): Partial<Record<CategoryId, Module>> {
const pending: Partial<Record<CategoryId, Module>> = {};
): Partial<Record<CategoryId, M>> {
const pending: Partial<Record<CategoryId, M>> = {};
for (const category of PEER_CATEGORIES) {
const id = selections[category]?.[0];
if (!id) continue;
@@ -146,22 +153,41 @@ export function resolveSelected(modules: Record<string, Module>, selections: Sel
* landing on a shared URL like `?orm=drizzle` with no `db`) would otherwise
* leave the orphaned dependent selected-but-unresolvable. Pruning to a fixpoint
* keeps selections in lockstep with what the resolver — and the CLI — accepts.
*
* Takes `ModuleMetadata[]` rather than full `Module`s — the resolver only reads
* `id`/`peers`/`adapters[].match`, all of which the index metadata already
* carries. That lets the home route avoid shipping the ~400 KB hydrated
* catalog down to the client.
*/
export function pruneUnresolved(
modules: Record<string, Module>,
selections: Selections,
): Selections {
export function pruneUnresolved(metadata: ModuleMetadata[], selections: Selections): Selections {
const byKey = new Map<string, ModuleMetadata>();
for (const m of metadata) byKey.set(`${m.category}:${m.id}`, m);
const manifest = emptyManifest({ name: "t" });
let current: Selections = { ...selections };
for (;;) {
const resolved = resolveSelected(modules, current);
const pending: Partial<Record<CategoryId, ModuleMetadata>> = {};
for (const c of PEER_CATEGORIES) {
const id = current[c]?.[0];
if (!id) continue;
const mod = byKey.get(`${c}:${id}`);
if (mod) pending[c] = mod;
}
let removed = false;
const next: Selections = {};
for (const category of KNOWN_CATEGORIES) {
const ids = current[category];
if (!ids?.length) continue;
const okIds = new Set((resolved[category] ?? []).map((e) => e.module.id));
const kept = ids.filter((id) => okIds.has(id));
if (kept.length !== ids.length) removed = true;
const kept: string[] = [];
for (const id of ids) {
const mod = byKey.get(`${category}:${id}`);
if (!mod) {
removed = true;
continue;
}
if (resolveAdapter(mod, { manifest, pending }).ok) kept.push(id);
else removed = true;
}
if (kept.length > 0) next[category] = kept;
}
current = next;
+23 -25
View File
@@ -1,5 +1,5 @@
import { create, insert, search } from "@orama/orama";
import type { Module, ModuleSummary, RegistryIndex } from "@stanza/registry";
import type { Module, ModuleMetadata, RegistryIndex } from "@stanza/registry";
import { createFileRoute } from "@tanstack/react-router";
import { cache } from "react";
@@ -11,7 +11,7 @@ const moduleSchema = {
label: "string",
description: "string",
// Joined text for full-text matching. These fields never travel back to the
// client — only `summaries[hit.id]` does, which is `ModuleSummary`-shaped.
// client — only `metadata[hit.id]` does, which is `ModuleMetadata`-shaped.
deps: "string",
envNames: "string",
envDescriptions: "string",
@@ -19,7 +19,7 @@ const moduleSchema = {
type ModuleIndex = {
db: ReturnType<typeof create<typeof moduleSchema>>;
summaries: Map<string, ModuleSummary>;
metadata: Map<string, ModuleMetadata>;
};
// React `cache()` dedupes the (async) build across any concurrent callers
@@ -30,25 +30,23 @@ const getModuleIndex = cache((): Promise<ModuleIndex> => buildIndex());
async function buildIndex(): Promise<ModuleIndex> {
const index = await loadRegistryFile<RegistryIndex>("index.json");
const db = create({ schema: moduleSchema });
const summaries = new Map<string, ModuleSummary>();
const metadata = new Map<string, ModuleMetadata>();
// Per-module file missing (shouldn't happen for first-party modules, but
// be tolerant): fall back to summary-only indexing via `mod: null`.
// be tolerant): fall back to metadata-only indexing via `mod: null`.
const loaded = await Promise.all(
index.modules.map(async (summary) => {
index.modules.map(async (meta) => {
try {
const mod = await loadRegistryFile<Module>(
`modules/${summary.category}-${summary.id}.json`,
);
return { summary, mod };
const mod = await loadRegistryFile<Module>(`modules/${meta.category}-${meta.id}.json`);
return { meta, mod };
} catch {
return { summary, mod: null as Module | null };
return { meta, mod: null as Module | null };
}
}),
);
const inserted = await Promise.all(
loaded.map(async ({ summary, mod }) => {
loaded.map(async ({ meta, mod }) => {
const deps = new Set<string>();
const envNames = new Set<string>();
const envDescriptions: string[] = [];
@@ -70,31 +68,31 @@ async function buildIndex(): Promise<ModuleIndex> {
}
const id = await insert(db, {
category: summary.category,
moduleId: summary.id,
label: summary.label,
description: summary.description,
category: meta.category,
moduleId: meta.id,
label: meta.label,
description: meta.description,
deps: [...deps].join(" "),
envNames: [...envNames].join(" "),
envDescriptions: envDescriptions.join(" "),
});
return { id, summary };
return { id, meta };
}),
);
for (const { id, summary } of inserted) summaries.set(id, summary);
for (const { id, meta } of inserted) metadata.set(id, meta);
return { db, summaries };
return { db, metadata };
}
/**
* `GET /api/search/modules?q=…` — server-side module search. Builds an Orama
* index from the full module data (deps, env vars, descriptions) so we can
* match on richer fields than the client ever sees. Only `ModuleSummary`-
* match on richer fields than the client ever sees. Only `ModuleMetadata`-
* shaped hits travel back, which means we can index README bodies later
* without bloating any client payload.
*
* Empty query returns an empty array — the client renders all modules from
* the registry summary it already has from the root loader.
* the registry metadata it already has from the root loader.
*/
export const Route = createFileRoute("/api/search/modules")({
server: {
@@ -105,13 +103,13 @@ export const Route = createFileRoute("/api/search/modules")({
const q = url.searchParams.get("q") ?? "";
if (!q) return Response.json({ results: [] });
const { db, summaries } = await getModuleIndex();
const { db, metadata } = await getModuleIndex();
const hits = await search(db, { term: q, limit: 50 });
const results: ModuleSummary[] = [];
const results: ModuleMetadata[] = [];
for (const hit of hits.hits) {
const summary = summaries.get(hit.id);
if (summary) results.push(summary);
const meta = metadata.get(hit.id);
if (meta) results.push(meta);
}
return Response.json({ results });
} catch (error) {
+5 -2
View File
@@ -1,4 +1,4 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { createFileRoute, Link, useLoaderData } from "@tanstack/react-router";
import { Builder } from "@/components/builder";
import { validateBuilderSearch } from "@/lib/selection";
@@ -24,6 +24,9 @@ export const Route = createFileRoute("/")({
function Page() {
const state = Route.useLoaderData();
const search = Route.useSearch();
// Registry index is loaded once by the root route — read it here instead of
// re-shipping it in our own loader data.
const { registry } = useLoaderData({ from: "__root__" });
return (
<div className="mx-auto max-w-7xl px-4 py-10 sm:px-6">
<header className="mb-10 max-w-2xl">
@@ -44,7 +47,7 @@ function Page() {
</Link>
</p>
</header>
<Builder state={state} search={search} />
<Builder state={state} search={search} metadata={registry.modules} />
</div>
);
}
@@ -27,12 +27,12 @@ export const Route = createFileRoute("/og/registry/$category/$id")({
return new Response("Registry unavailable", { status: 502 });
}
const summary = index.modules.find((m) => m.category === category && m.id === id);
if (!summary) {
const meta = index.modules.find((m) => m.category === category && m.id === id);
if (!meta) {
return new Response("Not found", { status: 404 });
}
return new ImageResponse(OgCard({ summary }), {
return new ImageResponse(OgCard({ meta }), {
width: 1200,
height: 630,
format: "webp",
+6 -6
View File
@@ -1,4 +1,4 @@
import type { CategoryId, ModuleSummary } from "@stanza/registry";
import type { CategoryId, ModuleMetadata } from "@stanza/registry";
import { categoryLabel, KNOWN_CATEGORIES } from "@stanza/registry";
import { createFileRoute, Link, useLoaderData } from "@tanstack/react-router";
import { lazy, Suspense, useEffect, useState } from "react";
@@ -91,8 +91,8 @@ function StatsPage() {
const isLoading = stats === null;
const findModule = (category: CategoryId, id: string): ModuleSummary | undefined =>
registry.modules.find((m: ModuleSummary) => m.category === category && m.id === id);
const findModule = (category: CategoryId, id: string): ModuleMetadata | undefined =>
registry.modules.find((m) => m.category === category && m.id === id);
const activitySum = stats?.activity30d.reduce((acc, day) => acc + day.count, 0) ?? 0;
@@ -188,12 +188,12 @@ function StatsPage() {
<BarList
emptyMessage={isLoading ? "Loading…" : "No data yet."}
data={entries.map((entry) => {
const summary = findModule(category, entry.id);
const label = summary?.label ?? entry.id;
const meta = findModule(category, entry.id);
const label = meta?.label ?? entry.id;
return {
name: label,
value: entry.count,
leading: <ModuleLogo logo={summary?.logo} label={label} size="sm" />,
leading: <ModuleLogo logo={meta?.logo} label={label} size="sm" />,
trailingSecondary: numberFormatter.format(entry.count),
trailing: percentFormatter.format(entry.share),
href: `/registry/${category}/${entry.id}`,
+7 -13
View File
@@ -1,4 +1,3 @@
import type { Module, RegistryIndex } from "@stanza/registry";
import {
synthesizeEnvExample,
synthesizeManifest,
@@ -17,13 +16,9 @@ import {
} from "@/lib/selection";
import type { Preview } from "@/server/highlighter";
import { getHighlighter, renderPreview } from "@/server/highlighter.server";
import { loadRegistryFile } from "@/server/registry-base.server";
import { getAllModules } from "@/server/registry-modules.server";
export type BuilderState = {
index: RegistryIndex;
/** Keyed by `${category}:${id}` for direct lookup. */
modules: Record<string, Module>;
/** Pre-rendered Shiki HTML, keyed by file path (relative to repo root). */
previews: Record<string, Preview>;
/** Ordered list of file paths derived from current selections. */
@@ -34,6 +29,10 @@ export type BuilderState = {
* Server function that powers the builder. Runs on every search-param change
* via the route's `loaderDeps`. Pulls the registry, derives the selected file
* list, and pre-renders Shiki HTML for each — keeping shiki off the client.
*
* The full hydrated module catalog stays server-side: the client reads
* `ModuleMetadata[]` from the root route's loader for card rendering + peer
* resolution, which is all it needs.
*/
export const getBuilderState = createServerFn({ method: "GET" })
// Server functions are HTTP-reachable; share the route's allow-list so a
@@ -47,12 +46,9 @@ export const getBuilderState = createServerFn({ method: "GET" })
// warm highlighter instead of paying ~hundreds of ms of cold-start.
void getHighlighter();
// Module catalog is cached per-process; `getAllModules` reads `index.json`
// internally, we still load it here for the BuilderState response.
const [index, modules] = await Promise.all([
loadRegistryFile<RegistryIndex>("index.json"),
getAllModules(),
]);
// Full module records are needed server-side for synth, but never shipped
// to the client — that's the point of this server function.
const modules = await getAllModules();
const { name, pm, selections } = parseSelections(data);
const resolved = resolveSelected(modules, selections);
@@ -102,8 +98,6 @@ export const getBuilderState = createServerFn({ method: "GET" })
);
return {
index,
modules,
previews: Object.fromEntries(previewEntries),
filePaths: previewFiles.map((f) => f.path),
};
@@ -3,7 +3,7 @@ import type {
EnvVar,
Module,
ModuleAdapter,
ModuleSummary,
ModuleMetadata,
PeerRequirement,
RegistryIndex,
} from "@stanza/registry";
@@ -81,8 +81,8 @@ export const getModuleDetail = createServerFn({ method: "GET" })
.handler(async ({ data }): Promise<ModuleDetail | null> => {
const index = await loadRegistryFile<RegistryIndex>("index.json");
const summary = index.modules.find((m) => m.category === data.category && m.id === data.id);
if (!summary) return null;
const meta = index.modules.find((m) => m.category === data.category && m.id === data.id);
if (!meta) return null;
const module = await loadRegistryFile<Module>(`modules/${data.category}-${data.id}.json`);
@@ -236,4 +236,4 @@ function effectiveInstallFields(module: Module, adapter: ModuleAdapter): Effecti
};
}
export type { ModuleSummary };
export type { ModuleMetadata };
+8 -8
View File
@@ -1,4 +1,4 @@
import type { ModuleSummary } from "@stanza/registry";
import type { ModuleMetadata } from "@stanza/registry";
import { categoryLabel } from "@stanza/registry";
import type { CSSProperties, ReactElement } from "react";
@@ -102,8 +102,8 @@ const TAGLINE: CSSProperties = {
};
const DEFAULT_FOOTER: CSSProperties = { color: "#52525b", fontSize: "22px" };
export function OgCard({ summary }: { summary: ModuleSummary }): ReactElement {
const logo = summary.logo;
export function OgCard({ meta }: { meta: ModuleMetadata }): ReactElement {
const logo = meta.logo;
// The OG card is always dark-background. For a theme pair, use the `dark`
// variant (designed for dark surfaces); for a single theme-agnostic mark,
// use it as-is. Either way we render it untouched — inverting mangles
@@ -114,7 +114,7 @@ export function OgCard({ summary }: { summary: ModuleSummary }): ReactElement {
<div style={HEADER_ROW}>
<img src={svgToDataUri(BRAND_LOGO_SVG)} width={32} height={32} alt="Stanza" />
<span style={DOT}>·</span>
<span style={SLOT}>{categoryLabel(summary.category)}</span>
<span style={SLOT}>{categoryLabel(meta.category)}</span>
</div>
<div style={BODY}>
@@ -125,16 +125,16 @@ export function OgCard({ summary }: { summary: ModuleSummary }): ReactElement {
<img src={svgToDataUri(logoSrc)} width={64} height={64} alt="" />
</div>
) : (
<div style={LETTER_BOX}>{summary.label.slice(0, 1)}</div>
<div style={LETTER_BOX}>{meta.label.slice(0, 1)}</div>
)}
<div style={TITLE}>{summary.label}</div>
<div style={TITLE}>{meta.label}</div>
</div>
<div style={DESCRIPTION}>{summary.description}</div>
<div style={DESCRIPTION}>{meta.description}</div>
</div>
<div style={FOOTER}>
<span>
stanza.tools/registry/{summary.category}/{summary.id}
stanza.tools/registry/{meta.category}/{meta.id}
</span>
</div>
</div>
@@ -18,17 +18,15 @@ export function getAllModules(): Promise<Record<string, Module>> {
async function loadAll(): Promise<Record<string, Module>> {
const index = await loadRegistryFile<RegistryIndex>("index.json");
const settled = await Promise.all(
index.modules.map(async (summary): Promise<readonly [string, Module] | null> => {
index.modules.map(async (meta): Promise<readonly [string, Module] | null> => {
try {
const mod = await loadRegistryFile<Module>(
`modules/${summary.category}-${summary.id}.json`,
);
const mod = await loadRegistryFile<Module>(`modules/${meta.category}-${meta.id}.json`);
return [`${mod.category}:${mod.id}`, mod] as const;
} catch (cause) {
console.error("[server-error]", cause, {
source: "getAllModules/loadModule",
category: summary.category,
moduleId: summary.id,
category: meta.category,
moduleId: meta.id,
});
return null;
}
+9 -9
View File
@@ -1,7 +1,7 @@
/**
* Static registry build. Scans `registry/modules/*`, imports each module's
* default export, writes:
* - <out>/registry/index.json — registry index (slot/module summaries)
* - <out>/registry/index.json — registry index (per-module metadata)
* - <out>/registry/modules/<slot>-<id>.json — per-module full manifests
* - <out>/schema.json — JSON Schema for stanza.json (served at the web root)
*
@@ -40,7 +40,7 @@ async function main() {
.filter((d) => d.isDirectory())
.map((d) => d.name);
const summaries = [];
const metadata = [];
for (const dir of dirs) {
const entry = path.join(modulesDir, dir, "module.ts");
const imported: { default: Module } = await import(entry);
@@ -74,11 +74,11 @@ async function main() {
JSON.stringify(inlined, null, 2),
);
// The index keeps a lightweight summary — no `content`, no per-adapter
// payloads — but it DOES carry top-level metadata like `logo` so the
// wizard / web builder can render module cards without fetching the
// full per-module JSON.
summaries.push({
// The index keeps lightweight metadata — no template `content`, no
// per-adapter payloads — but it DOES carry top-level fields like `logo`
// so the wizard / web builder can render module cards without fetching
// the full per-module JSON.
metadata.push({
...inlined,
adapters: inlined.adapters.map((a) => ({ key: a.key, match: a.match })),
});
@@ -88,7 +88,7 @@ async function main() {
generatedAt: new Date().toISOString(),
schemaVersion: 1,
categories: [...CATEGORIES],
modules: summaries,
modules: metadata,
};
fs.writeFileSync(path.join(registryDir, "index.json"), JSON.stringify(index, null, 2));
@@ -100,7 +100,7 @@ async function main() {
JSON.stringify(manifestJsonSchema(), null, 2),
);
console.log(`Wrote ${summaries.length} modules to ${outBase}`);
console.log(`Wrote ${metadata.length} modules to ${outBase}`);
}
/**
+2 -2
View File
@@ -8,7 +8,7 @@ export type {
PeerRequirement,
Module,
ModuleAdapter,
ModuleSummary,
ModuleMetadata,
RegistryIndex,
TemplateRef,
EnvVar,
@@ -29,7 +29,7 @@ export {
categoryCardinality,
isMulti,
ModuleSchema,
ModuleSummarySchema,
ModuleMetadataSchema,
RegistryIndexSchema,
} from "./module";
+10 -9
View File
@@ -339,10 +339,11 @@ export type Module = ModuleInstallFields & {
};
/**
* Lightweight summary for the registry index — strips codemod implementations
* but keeps everything the wizard / search UI needs.
* Lightweight per-module metadata for the registry index — strips template
* bodies and codemod implementations but keeps everything the wizard, search,
* and web builder need for display + peer resolution.
*/
export type ModuleSummary = Omit<Module, "adapters"> & {
export type ModuleMetadata = Omit<Module, "adapters"> & {
adapters: Pick<ModuleAdapter, "key" | "match">[];
};
@@ -350,7 +351,7 @@ export type RegistryIndex = {
generatedAt: string;
schemaVersion: 1;
categories: Category[];
modules: ModuleSummary[];
modules: ModuleMetadata[];
};
/**
@@ -451,7 +452,7 @@ const adapterSchema = z.object({
...installFieldsSchema,
});
/** Shape shared by a full `Module` and its index `ModuleSummary` (all but `adapters`). */
/** Shape shared by a full `Module` and its index `ModuleMetadata` (all but `adapters`). */
const moduleBaseShape = {
category: z.enum(KNOWN_CATEGORIES),
id: z.string(),
@@ -507,8 +508,8 @@ const categorySchema = z.object({
]),
}) satisfies z.ZodType<Category>;
/** Index summary: full module metadata with adapters reduced to `key` + `match`. */
export const ModuleSummarySchema = z.object({
/** Per-module index entry: full metadata with adapters reduced to `key` + `match`. */
export const ModuleMetadataSchema = z.object({
...moduleBaseShape,
adapters: z.array(
z.object({
@@ -516,12 +517,12 @@ export const ModuleSummarySchema = z.object({
match: z.partialRecord(z.enum(KNOWN_CATEGORIES), z.string()),
}),
),
}) satisfies z.ZodType<ModuleSummary>;
}) satisfies z.ZodType<ModuleMetadata>;
/** Runtime-validatable schema for the registry `index.json` payload. */
export const RegistryIndexSchema = z.object({
generatedAt: z.string(),
schemaVersion: z.literal(1),
categories: z.array(categorySchema),
modules: z.array(ModuleSummarySchema),
modules: z.array(ModuleMetadataSchema),
}) satisfies z.ZodType<RegistryIndex>;
+23
View File
@@ -79,6 +79,29 @@ describe("resolveAdapter", () => {
expect(result.error.kind).toBe("incompatible-peer");
});
it("accepts a narrow metadata shape and returns the narrow adapter", () => {
// ModuleMetadata strips adapter templates/codemods/install fields — the
// web builder ships only this shape to the client. The generic must
// preserve the input's adapter type end-to-end.
const meta = {
id: "drizzle",
peers: { db: ["postgres", "sqlite"] },
adapters: [
{ key: "postgres", match: { db: "postgres" } },
{ key: "sqlite", match: { db: "sqlite" } },
],
};
const result = resolveAdapter(meta, {
manifest: emptyManifest({ name: "t" }),
pending: { db: { id: "postgres" } },
});
assert(result.ok);
expect(result.adapter.key).toBe("postgres");
// @ts-expect-error — adapter type narrows to the input's adapter shape;
// the input had no `templates`, so accessing it is a type error.
void result.adapter.templates;
});
it("falls back to a default (empty-match) adapter when no peers are required", () => {
const tailwind: Module = defineModule({
id: "tailwind",
+31 -13
View File
@@ -2,9 +2,9 @@ import { type StanzaManifest, selectedOne } from "./manifest";
import {
type CategoryId,
KNOWN_CATEGORIES,
type Module,
type ModuleAdapter,
PEER_CATEGORIES,
type PeerRequirement,
} from "./module";
/**
@@ -14,11 +14,23 @@ import {
*/
export const categoryOrder: readonly CategoryId[] = KNOWN_CATEGORIES;
/**
* Minimum shape `resolveAdapter` reads. Both full `Module` and the lighter
* `ModuleMetadata` satisfy this — the web builder ships only metadata to the
* client, the CLI passes full Modules. The generic preserves the adapter type
* end-to-end so each caller gets back the same shape it put in.
*/
export type Resolvable<A extends Pick<ModuleAdapter, "key" | "match">> = {
id: string;
peers?: PeerRequirement;
adapters: A[];
};
export type ResolveContext = {
/** Manifest state at the moment of resolution (post any pending picks). */
manifest: StanzaManifest;
/** Modules the user has already chosen this run but not yet committed. */
pending: Partial<Record<CategoryId, Module>>;
pending: Partial<Record<CategoryId, { id: string }>>;
/**
* App being targeted by this resolution. When set, peer lookups for
* single-cardinality categories scope to records whose `apps` include this
@@ -30,12 +42,12 @@ export type ResolveContext = {
};
export type ResolveError =
| { kind: "no-adapter"; module: Module; peers: Partial<Record<CategoryId, string>> }
| { kind: "missing-peer"; module: Module; category: CategoryId }
| { kind: "incompatible-peer"; module: Module; category: CategoryId; peer: string };
| { kind: "no-adapter"; peers: Partial<Record<CategoryId, string>> }
| { kind: "missing-peer"; category: CategoryId }
| { kind: "incompatible-peer"; category: CategoryId; peer: string };
export type ResolveResult =
| { ok: true; adapter: ModuleAdapter }
export type ResolveResult<A extends Pick<ModuleAdapter, "key" | "match">> =
| { ok: true; adapter: A }
| { ok: false; error: ResolveError };
/**
@@ -44,7 +56,10 @@ export type ResolveResult =
* Specificity = number of `match` keys satisfied. The default (empty `match`)
* always wins on tiebreak when no peers are required.
*/
export function resolveAdapter(module: Module, context: ResolveContext): ResolveResult {
export function resolveAdapter<A extends Pick<ModuleAdapter, "key" | "match">>(
module: Resolvable<A>,
context: ResolveContext,
): ResolveResult<A> {
const activePeers = activePeerIdsForContext(context);
// Check declared peers are satisfied (id present + on allow-list if specified).
@@ -53,12 +68,12 @@ export function resolveAdapter(module: Module, context: ResolveContext): Resolve
if (allowed === undefined) continue;
const chosen = activePeers[category];
if (!chosen) {
return { ok: false, error: { kind: "missing-peer", module, category } };
return { ok: false, error: { kind: "missing-peer", category } };
}
if (allowed !== "any" && !allowed.includes(chosen)) {
return {
ok: false,
error: { kind: "incompatible-peer", module, category, peer: chosen },
error: { kind: "incompatible-peer", category, peer: chosen },
};
}
}
@@ -73,7 +88,7 @@ export function resolveAdapter(module: Module, context: ResolveContext): Resolve
if (candidates.length === 0) {
return {
ok: false,
error: { kind: "no-adapter", module, peers: activePeers },
error: { kind: "no-adapter", peers: activePeers },
};
}
@@ -82,7 +97,10 @@ export function resolveAdapter(module: Module, context: ResolveContext): Resolve
return { ok: true, adapter: candidates[0]!.adapter };
}
export function isCompatible(module: Module, context: ResolveContext): boolean {
export function isCompatible<A extends Pick<ModuleAdapter, "key" | "match">>(
module: Resolvable<A>,
context: ResolveContext,
): boolean {
return resolveAdapter(module, context).ok;
}
@@ -130,7 +148,7 @@ function activePeerIdsForContext(context: ResolveContext): Partial<Record<Catego
* an empty `match` are universally applicable (specificity 0).
*/
function matchSpecificity(
adapter: ModuleAdapter,
adapter: Pick<ModuleAdapter, "match">,
peers: Partial<Record<CategoryId, string>>,
): number {
let score = 0;
+287 -121
View File
@@ -36,7 +36,7 @@ importers:
version: 6.0.3
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
apps/cli:
dependencies:
@@ -82,10 +82,10 @@ importers:
version: 6.0.3
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
vitest:
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
version: '@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
apps/web:
dependencies:
@@ -114,8 +114,8 @@ importers:
specifier: ^4.3.0
version: 4.3.0(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))
'@takumi-rs/image-response':
specifier: ^1.5.1
version: 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
specifier: ^1.6.0
version: 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/react-devtools':
specifier: ^0.10.5
version: 0.10.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(solid-js@1.9.13)
@@ -151,22 +151,22 @@ importers:
version: 16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3)
fumadocs-mdx:
specifier: ^15.0.9
version: 15.0.9(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react@19.2.6)(rolldown@1.0.2)
version: 15.0.9(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react@19.2.6)(rolldown@1.0.3)
fumadocs-ui:
specifier: npm:@fumadocs/base-ui@^16.9.1
version: '@fumadocs/base-ui@16.9.1(@tailwindcss/oxide@4.3.0)(@takumi-rs/image-response@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0)'
version: '@fumadocs/base-ui@16.9.1(@tailwindcss/oxide@4.3.0)(@takumi-rs/image-response@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0)'
lru-cache:
specifier: ^11.5.0
version: 11.5.0
specifier: ^11.5.1
version: 11.5.1
motion:
specifier: ^12.40.0
version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
nitro:
specifier: ^3.0.260522-beta
version: 3.0.260522-beta(@vercel/functions@3.6.0)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0)
version: 3.0.260522-beta(@vercel/functions@3.6.0)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.1)
posthog-node:
specifier: ^5.35.4
version: 5.35.4
specifier: ^5.35.5
version: 5.35.5
react:
specifier: ^19.2.6
version: 19.2.6
@@ -180,8 +180,8 @@ importers:
specifier: ^3.8.1
version: 3.8.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react-is@17.0.2)(react@19.2.6)(redux@5.0.1)
shadcn:
specifier: ^4.8.1
version: 4.8.1(@types/node@25.9.1)(typescript@6.0.3)
specifier: ^4.8.2
version: 4.8.2(@types/node@25.9.1)(typescript@6.0.3)
shiki:
specifier: ^4.1.0
version: 4.1.0
@@ -242,10 +242,10 @@ importers:
version: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
version: 0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
vitest:
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
version: '@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)'
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)'
packages/codemods:
dependencies:
@@ -267,10 +267,10 @@ importers:
version: 6.0.3
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
vitest:
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
version: '@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
packages/create-stanza:
dependencies:
@@ -286,7 +286,7 @@ importers:
version: 6.0.3
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
packages/registry:
dependencies:
@@ -311,10 +311,10 @@ importers:
version: 6.0.3
vite-plus:
specifier: 'catalog:'
version: 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
version: 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
vitest:
specifier: npm:@voidzero-dev/vite-plus-test@^0.1.22
version: '@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
version: '@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))'
registry/modules/ai-tanstack-ai:
dependencies:
@@ -1182,10 +1182,6 @@ packages:
'@open-draft/until@2.1.0':
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
'@opentelemetry/api@1.9.1':
resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==}
engines: {node: '>=8.0.0'}
'@orama/orama@3.1.18':
resolution: {integrity: sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==}
engines: {node: '>= 20.0.0'}
@@ -1330,6 +1326,9 @@ packages:
'@oxc-project/types@0.132.0':
resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==}
'@oxc-project/types@0.133.0':
resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==}
'@oxfmt/binding-android-arm-eabi@0.48.0':
resolution: {integrity: sha512-uwqk+/KhQvBIpULD8SMM/zAafMRC/+DV/xsEQjkkIsJ/kLmEI/2bxonVowcYTiXqqZ/a0FEW8DPkZY3VvwELDA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1617,11 +1616,11 @@ packages:
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
'@posthog/core@1.29.11':
resolution: {integrity: sha512-/4EF7oxAFSWJgaXxppT8bdYp7MGAnWFnKz994+MetTz/T6CKbYpjqIXHCofQXtcOXjEclTYj91igA+IkVFKiSg==}
'@posthog/core@1.29.12':
resolution: {integrity: sha512-r/2RUa4zbN0XdBp6d+Yk8Jw1rPWXHxyXIgSm/wJf9yDLIouZbH0Pdkgbc1RIuhwL6BIHCFrOqK5jy8TFKTI6iw==}
'@posthog/types@1.376.2':
resolution: {integrity: sha512-Y3ROpAxNqgcy2G0w6JoG5Gt+P6WNY2lkHTPMPzWqexRwemYbFegDi5AifDyD9/tstKTlOYKTTExtaJ5EBcghyQ==}
'@posthog/types@1.376.3':
resolution: {integrity: sha512-w21lBoz3/ZGw7BZT7t2lJq1mpJwMvWpZijW7vEwBFNAQlq0KfKf2mj5KKUYZMXM1GdIQ0jHnn931uXPB1Ae60w==}
'@reduxjs/toolkit@2.12.0':
resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==}
@@ -1640,30 +1639,60 @@ packages:
cpu: [arm64]
os: [android]
'@rolldown/binding-android-arm64@1.0.3':
resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@rolldown/binding-darwin-arm64@1.0.2':
resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-arm64@1.0.3':
resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.0.2':
resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.0.3':
resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@rolldown/binding-freebsd-x64@1.0.2':
resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-freebsd-x64@1.0.3':
resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.0.2':
resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm-gnueabihf@1.0.3':
resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.0.2':
resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1671,6 +1700,13 @@ packages:
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-gnu@1.0.3':
resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.2':
resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1678,6 +1714,13 @@ packages:
os: [linux]
libc: [musl]
'@rolldown/binding-linux-arm64-musl@1.0.3':
resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.0.2':
resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1685,6 +1728,13 @@ packages:
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-ppc64-gnu@1.0.3':
resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.2':
resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1692,6 +1742,13 @@ packages:
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.3':
resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.2':
resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1699,6 +1756,13 @@ packages:
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.3':
resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.2':
resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1706,29 +1770,59 @@ packages:
os: [linux]
libc: [musl]
'@rolldown/binding-linux-x64-musl@1.0.3':
resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.2':
resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-openharmony-arm64@1.0.3':
resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-wasm32-wasi@1.0.2':
resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [wasm32]
'@rolldown/binding-wasm32-wasi@1.0.3':
resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [wasm32]
'@rolldown/binding-win32-arm64-msvc@1.0.2':
resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-arm64-msvc@1.0.3':
resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.2':
resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.3':
resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@rolldown/pluginutils@1.0.0-rc.18':
resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==}
@@ -1916,64 +2010,64 @@ packages:
peerDependencies:
vite: ^5.2.0 || ^6 || ^7 || ^8
'@takumi-rs/core-darwin-arm64@1.5.1':
resolution: {integrity: sha512-b7gZxZFX+64Gip6ypY/9oLf9qhw0+s1MZavnt+mggXjzSAJiBmIqVmlpuB8HolYyYwuR3+bclG0/Ma1W63qdRA==}
'@takumi-rs/core-darwin-arm64@1.6.0':
resolution: {integrity: sha512-Ib5W+lE3M8kN6oJixDozVHBSp9wZVm64z3yHGqPO3hdnCoaozAsM8YfQbZL61ESWrnLzutBJtwFHD3jSZ+3ilA==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [arm64]
os: [darwin]
'@takumi-rs/core-darwin-x64@1.5.1':
resolution: {integrity: sha512-r65+N+Ttkf5xvKRzPnXXPZ4opDK6HnM/pHs/PZaEIE7HqKxscYeiUpwIwXaIwLsXT7OPSlTrBeQjkExfnlmj4Q==}
'@takumi-rs/core-darwin-x64@1.6.0':
resolution: {integrity: sha512-CmvPOafon70xNcbmocDEJK18ONCeck3oBENdVriP8hQxPVJA8qwtObFxLBzbkEFtQIW3PzeFM24UYmUnba9OVg==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [x64]
os: [darwin]
'@takumi-rs/core-linux-arm64-gnu@1.5.1':
resolution: {integrity: sha512-UyNajYHAEcMFA/DtAeX1zrWzajwUwFXo+hHuTUAjgbBCIFUAXNHkh92L0XMelyr7Yaj0uogdscvKWA/wGlKliw==}
'@takumi-rs/core-linux-arm64-gnu@1.6.0':
resolution: {integrity: sha512-sMcAiBPMnuECsxyUP3xF89yC7WCatUTcMYuAJ1nWgkY1QZ86oimuitlukCV2a6Wi011aOou02ALgf6SucDn8Rw==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@takumi-rs/core-linux-arm64-musl@1.5.1':
resolution: {integrity: sha512-+G7Qin3Wu1sDycdOYHA4hJiZeCTUSW6+gx9ZZnkFY3wYCFAteJacKoJq5f4OfxcNrnaXIsTOHdObEQwiid7raw==}
'@takumi-rs/core-linux-arm64-musl@1.6.0':
resolution: {integrity: sha512-G1llacEnQ37XXz4a8/CIzXCczp+s9Cz2diOEOTPUlID4/wWwNL8DRel3lP4NA7y7H7lsWB+C8KLz0by3T/icgg==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@takumi-rs/core-linux-x64-gnu@1.5.1':
resolution: {integrity: sha512-KqcKcOpxN4dm8kusKQmZ1lHrYExYchorjZ8911DWOFv4MCdv/LB3A5bM5othPeFeWo8EaSiWprIhQeTLUc2iZQ==}
'@takumi-rs/core-linux-x64-gnu@1.6.0':
resolution: {integrity: sha512-e6LQXzHii9RIWbQGLlDilLzyrTo4UrPAAA+/MVTcrgH3LE2AXlCMSRddFDQoPzlrElNSK7afS0OqOU3ZlF3biQ==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@takumi-rs/core-linux-x64-musl@1.5.1':
resolution: {integrity: sha512-WvxQcHXzHEsraDKtxn7K8LPBQlVrKPOn5IA7R7fKR4pT1jO3v5HKttFaH+Prt4HhGKKq63eggOh1lbFAQqj84w==}
'@takumi-rs/core-linux-x64-musl@1.6.0':
resolution: {integrity: sha512-pDGU7dBdYvhYlS1BGd+AIHs18EklT+jHMvWoOq0Qcm0SYbejYkuzj3H8iQyzAhnWhjWWwK3DPLHArNWNTsQYLw==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@takumi-rs/core-win32-arm64-msvc@1.5.1':
resolution: {integrity: sha512-MXB0xRg3gmSdVzoMVzDLg+RpFe+aaNRq3GadNvlxuPbG/f5LVCu5J5PQK6vEFLvQqGOKntX+9NvUvg1/dVMHhg==}
'@takumi-rs/core-win32-arm64-msvc@1.6.0':
resolution: {integrity: sha512-WCtl6+fKM0jqojm5Q+UjGBg9Kk5kdDwNYLrW4p1TU/H73XJ73h7fNNe46EnwBarnV5VIG2ReLGusm6tDq1xwXw==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [arm64]
os: [win32]
'@takumi-rs/core-win32-x64-msvc@1.5.1':
resolution: {integrity: sha512-b0qb1+z4l98DxufvvETCV177BRfoPGwuoVtFuCaKCgvQgg5xzCTMWlMLNUZwSOEG/qqUR9yWJbngupBD+djJGA==}
'@takumi-rs/core-win32-x64-msvc@1.6.0':
resolution: {integrity: sha512-fOmQrTz8MtcNA85zJpwFEzag5Iej9Q/VFIQcOyTxFGfE1Oyl2rwBQE0XGYU2JVD8h00d6RWZdllgRfvlJwalzg==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
cpu: [x64]
os: [win32]
'@takumi-rs/core@1.5.1':
resolution: {integrity: sha512-h3qKkTz+c7938kZIv/Vpt8dWDaZtMvNYFMSMU0miQpgXFYWQalRfqW+fzUb0SxAm33N4t+Mh3H3p+Bpvmpz/JQ==}
'@takumi-rs/core@1.6.0':
resolution: {integrity: sha512-U98BRuHhDtAojGP+NBZYWL53Fkt9rBAK9bOgh8MkbR5QKOQ6bObgoZj1TnwFePc57nLOU33DCgzBncse6RLPUA==}
engines: {node: '>= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0'}
'@takumi-rs/helpers@1.5.1':
resolution: {integrity: sha512-t0UcUoqwJciEFVEgVh0eSp8KQog/fzviFcGFp2Yy91oUCDcs8hFGzH/lw7oGpt6Ipsdp0XyOUtmyP+M/JSLAUw==}
'@takumi-rs/helpers@1.6.0':
resolution: {integrity: sha512-pjNmUhh1sfqWoyCHRAd0eMciFaDCUYis7FTAb8+XZgNGC3FNJ0b+6hWpnj5zMuP8xrAUoq61FNgj2kGt+B5TRg==}
peerDependencies:
react: ^19.2.5
react-dom: ^18.0.0 || ^19.0.0
@@ -1983,11 +2077,11 @@ packages:
react-dom:
optional: true
'@takumi-rs/image-response@1.5.1':
resolution: {integrity: sha512-K5dQc5cIm6+A1HJQdMYJLQHMxHHQlwv66nrgcyaQ3FDwhnkX/LLeKjgnr+S28qjXnrDncmKdHr3CXd19ZC1fxA==}
'@takumi-rs/image-response@1.6.0':
resolution: {integrity: sha512-dz1gviOqH1BE3X0RdCfsms33tp/X+PGI0bmNgEwRP0okJgkWKcO42OfzJyljqQ34bhYwx98aOcke1DpyD02n5w==}
'@takumi-rs/wasm@1.5.1':
resolution: {integrity: sha512-uOWjizXOYsM8n6cRngyw7oqvYBrkCvB1CHKEKC6069OSi/D/iCoo8gf23S7QnDN6A8H9QSbrS4RlnVVflZgCfA==}
'@takumi-rs/wasm@1.6.0':
resolution: {integrity: sha512-3VFzUth3+vht8LtjdXRIdVB4vzTJHa0vEypjL149mbq+A7mXRHNCMqeQl4hqHK3lk2H2VElzmxilwzuwtGZf/g==}
'@tanstack/devtools-client@0.0.6':
resolution: {integrity: sha512-f85ZJXJnDIFOoykG/BFIixuAevJovCvJF391LPs6YjBAPhGYC50NWlx1y4iF/UmK5/cCMx+/JqI5SBOz7FanQQ==}
@@ -3048,8 +3142,8 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
electron-to-chromium@1.5.361:
resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==}
electron-to-chromium@1.5.362:
resolution: {integrity: sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==}
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@@ -3878,8 +3972,8 @@ packages:
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
lru-cache@11.5.0:
resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==}
lru-cache@11.5.1:
resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==}
engines: {node: 20 || >=22}
lru-cache@5.1.1:
@@ -4436,8 +4530,8 @@ packages:
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
posthog-node@5.35.4:
resolution: {integrity: sha512-X4OCh3Lr4tfyUc/67ssDhe5cD3fwFVq4QBdNpQwpjtuOCGWZ4wDONc6zSkE1i6FVUkTc884GvwphorKC6To/BQ==}
posthog-node@5.35.5:
resolution: {integrity: sha512-zPLpjK0uAxVTVmV2TH/hNAq0JN0vUjZdJ8KOBErQS58lIJRHTkMMofNmpolkGq9pijpFITcpLsMYMsFMWvjBmg==}
engines: {node: ^20.20.0 || >=22.22.0}
peerDependencies:
rxjs: ^7.0.0
@@ -4681,6 +4775,11 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
rolldown@1.0.3:
resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
rou3@0.8.1:
resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==}
@@ -4745,8 +4844,8 @@ packages:
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
shadcn@4.8.1:
resolution: {integrity: sha512-B2J63uYwqfLJPNzZk2AAlonXG1aJhwv8xmXlUag8OZdV61CQB6570nkXLjU1u9XN1qXm0LpJhSFQ0ZhlOruA4Q==}
shadcn@4.8.2:
resolution: {integrity: sha512-pt3KneOg6LGYKNAdoTVf/lpVcf7t2MlV+Ll2Xc3lIIYN3ph4ajrjU+CcG6OVSgO5ubbLZj+9j5oMA9Lqg7o8KA==}
hasBin: true
shebang-command@2.0.0:
@@ -4910,8 +5009,8 @@ packages:
tailwindcss@4.3.0:
resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==}
takumi-js@1.5.1:
resolution: {integrity: sha512-t/AcU5AjMgigfmSn3BvkZrLGnLPn7/2AkhnUrhqSlQntUfrSYOBks1EqpSGgEPUAKHjQxNH+lptiZAHnUVu/5Q==}
takumi-js@1.6.0:
resolution: {integrity: sha512-1+Vd0c7Z2YykJx2BkRK2iMbyPLTWzVtlSt+Kb7fMQGO2UOUmNijthr7uHx5CZTyLt3EDjuqepjlUlr6WwmtwuA==}
tapable@2.3.3:
resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
@@ -5950,7 +6049,7 @@ snapshots:
'@fontsource-variable/geist@5.2.9': {}
'@fumadocs/base-ui@16.9.1(@tailwindcss/oxide@4.3.0)(@takumi-rs/image-response@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0)':
'@fumadocs/base-ui@16.9.1(@tailwindcss/oxide@4.3.0)(@takumi-rs/image-response@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0)':
dependencies:
'@base-ui/react': 1.5.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@fumadocs/tailwind': 0.0.5(@tailwindcss/oxide@4.3.0)(tailwindcss@4.3.0)
@@ -5968,7 +6067,7 @@ snapshots:
tailwind-merge: 3.6.0
unist-util-visit: 5.1.0
optionalDependencies:
'@takumi-rs/image-response': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/image-response': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@types/mdx': 2.0.13
'@types/react': 19.2.15
transitivePeerDependencies:
@@ -6172,9 +6271,6 @@ snapshots:
'@open-draft/until@2.1.0': {}
'@opentelemetry/api@1.9.1':
optional: true
'@orama/orama@3.1.18': {}
'@oxc-parser/binding-android-arm-eabi@0.120.0':
@@ -6250,6 +6346,8 @@ snapshots:
'@oxc-project/types@0.132.0': {}
'@oxc-project/types@0.133.0': {}
'@oxfmt/binding-android-arm-eabi@0.48.0':
optional: true
@@ -6393,11 +6491,11 @@ snapshots:
'@polka/url@1.0.0-next.29': {}
'@posthog/core@1.29.11':
'@posthog/core@1.29.12':
dependencies:
'@posthog/types': 1.376.2
'@posthog/types': 1.376.3
'@posthog/types@1.376.2': {}
'@posthog/types@1.376.3': {}
'@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)':
dependencies:
@@ -6406,7 +6504,7 @@ snapshots:
immer: 11.1.8
redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.2.0
reselect: 5.1.1
optionalDependencies:
react: 19.2.6
react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1)
@@ -6414,39 +6512,75 @@ snapshots:
'@rolldown/binding-android-arm64@1.0.2':
optional: true
'@rolldown/binding-android-arm64@1.0.3':
optional: true
'@rolldown/binding-darwin-arm64@1.0.2':
optional: true
'@rolldown/binding-darwin-arm64@1.0.3':
optional: true
'@rolldown/binding-darwin-x64@1.0.2':
optional: true
'@rolldown/binding-darwin-x64@1.0.3':
optional: true
'@rolldown/binding-freebsd-x64@1.0.2':
optional: true
'@rolldown/binding-freebsd-x64@1.0.3':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.2':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.3':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.2':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.3':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.2':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.3':
optional: true
'@rolldown/binding-linux-ppc64-gnu@1.0.2':
optional: true
'@rolldown/binding-linux-ppc64-gnu@1.0.3':
optional: true
'@rolldown/binding-linux-s390x-gnu@1.0.2':
optional: true
'@rolldown/binding-linux-s390x-gnu@1.0.3':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.2':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.3':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.2':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.3':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.2':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.3':
optional: true
'@rolldown/binding-wasm32-wasi@1.0.2':
dependencies:
'@emnapi/core': 1.10.0
@@ -6454,12 +6588,25 @@ snapshots:
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
optional: true
'@rolldown/binding-wasm32-wasi@1.0.3':
dependencies:
'@emnapi/core': 1.10.0
'@emnapi/runtime': 1.10.0
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.2':
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.3':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.2':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.3':
optional: true
'@rolldown/pluginutils@1.0.0-rc.18': {}
'@rolldown/pluginutils@1.0.1': {}
@@ -6626,61 +6773,61 @@ snapshots:
tailwindcss: 4.3.0
vite: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
'@takumi-rs/core-darwin-arm64@1.5.1':
'@takumi-rs/core-darwin-arm64@1.6.0':
optional: true
'@takumi-rs/core-darwin-x64@1.5.1':
'@takumi-rs/core-darwin-x64@1.6.0':
optional: true
'@takumi-rs/core-linux-arm64-gnu@1.5.1':
'@takumi-rs/core-linux-arm64-gnu@1.6.0':
optional: true
'@takumi-rs/core-linux-arm64-musl@1.5.1':
'@takumi-rs/core-linux-arm64-musl@1.6.0':
optional: true
'@takumi-rs/core-linux-x64-gnu@1.5.1':
'@takumi-rs/core-linux-x64-gnu@1.6.0':
optional: true
'@takumi-rs/core-linux-x64-musl@1.5.1':
'@takumi-rs/core-linux-x64-musl@1.6.0':
optional: true
'@takumi-rs/core-win32-arm64-msvc@1.5.1':
'@takumi-rs/core-win32-arm64-msvc@1.6.0':
optional: true
'@takumi-rs/core-win32-x64-msvc@1.5.1':
'@takumi-rs/core-win32-x64-msvc@1.6.0':
optional: true
'@takumi-rs/core@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
'@takumi-rs/core@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@takumi-rs/helpers': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/helpers': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
optionalDependencies:
'@takumi-rs/core-darwin-arm64': 1.5.1
'@takumi-rs/core-darwin-x64': 1.5.1
'@takumi-rs/core-linux-arm64-gnu': 1.5.1
'@takumi-rs/core-linux-arm64-musl': 1.5.1
'@takumi-rs/core-linux-x64-gnu': 1.5.1
'@takumi-rs/core-linux-x64-musl': 1.5.1
'@takumi-rs/core-win32-arm64-msvc': 1.5.1
'@takumi-rs/core-win32-x64-msvc': 1.5.1
'@takumi-rs/core-darwin-arm64': 1.6.0
'@takumi-rs/core-darwin-x64': 1.6.0
'@takumi-rs/core-linux-arm64-gnu': 1.6.0
'@takumi-rs/core-linux-arm64-musl': 1.6.0
'@takumi-rs/core-linux-x64-gnu': 1.6.0
'@takumi-rs/core-linux-x64-musl': 1.6.0
'@takumi-rs/core-win32-arm64-msvc': 1.6.0
'@takumi-rs/core-win32-x64-msvc': 1.6.0
transitivePeerDependencies:
- react
- react-dom
'@takumi-rs/helpers@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
'@takumi-rs/helpers@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
optionalDependencies:
react: 19.2.6
react-dom: 19.2.6(react@19.2.6)
'@takumi-rs/image-response@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
'@takumi-rs/image-response@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
takumi-js: 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
takumi-js: 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
transitivePeerDependencies:
- react
- react-dom
'@takumi-rs/wasm@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
'@takumi-rs/wasm@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@takumi-rs/helpers': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/helpers': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
transitivePeerDependencies:
- react
- react-dom
@@ -7191,7 +7338,7 @@ snapshots:
'@voidzero-dev/vite-plus-linux-x64-musl@0.1.22':
optional: true
'@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)':
'@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
@@ -7208,7 +7355,6 @@ snapshots:
vite: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
ws: 8.21.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@types/node': 25.9.1
jsdom: 29.1.1(@noble/hashes@1.8.0)
transitivePeerDependencies:
@@ -7233,7 +7379,7 @@ snapshots:
- utf-8-validate
- yaml
'@voidzero-dev/vite-plus-test@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))':
'@voidzero-dev/vite-plus-test@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
@@ -7250,7 +7396,6 @@ snapshots:
vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)
ws: 8.21.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@types/node': 25.9.1
jsdom: 29.1.1(@noble/hashes@1.8.0)
transitivePeerDependencies:
@@ -7390,7 +7535,7 @@ snapshots:
dependencies:
baseline-browser-mapping: 2.10.32
caniuse-lite: 1.0.30001793
electron-to-chromium: 1.5.361
electron-to-chromium: 1.5.362
node-releases: 2.0.46
update-browserslist-db: 1.2.3(browserslist@4.28.2)
@@ -7679,7 +7824,7 @@ snapshots:
ee-first@1.1.1: {}
electron-to-chromium@1.5.361: {}
electron-to-chromium@1.5.362: {}
emoji-regex@10.6.0: {}
@@ -8031,7 +8176,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
fumadocs-mdx@15.0.9(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react@19.2.6)(rolldown@1.0.2):
fumadocs-mdx@15.0.9(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.15)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(fumadocs-core@16.9.1(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react@19.2.6)(rolldown@1.0.3):
dependencies:
'@mdx-js/mdx': 3.1.1
'@standard-schema/spec': 1.1.0
@@ -8055,7 +8200,7 @@ snapshots:
'@types/mdx': 2.0.13
'@types/react': 19.2.15
react: 19.2.6
rolldown: 1.0.2
rolldown: 1.0.3
vite: '@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)'
transitivePeerDependencies:
- supports-color
@@ -8424,7 +8569,7 @@ snapshots:
decimal.js: 10.6.0
html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0)
is-potential-custom-element-name: 1.0.1
lru-cache: 11.5.0
lru-cache: 11.5.1
parse5: 8.0.1
saxes: 6.0.0
symbol-tree: 3.2.4
@@ -8533,7 +8678,7 @@ snapshots:
longest-streak@3.1.0: {}
lru-cache@11.5.0: {}
lru-cache@11.5.1: {}
lru-cache@5.1.1:
dependencies:
@@ -9075,7 +9220,7 @@ snapshots:
nf3@0.3.17: {}
nitro@3.0.260522-beta(@vercel/functions@3.6.0)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0):
nitro@3.0.260522-beta(@vercel/functions@3.6.0)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.1):
dependencies:
consola: 3.4.2
crossws: 0.4.5(srvx@0.11.16)
@@ -9087,10 +9232,10 @@ snapshots:
ocache: 0.1.4
ofetch: 2.0.0-alpha.3
ohash: 2.0.11
rolldown: 1.0.2
rolldown: 1.0.3
srvx: 0.11.16
unenv: 2.0.0-rc.24
unstorage: 2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3)
unstorage: 2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3)
optionalDependencies:
dotenv: 17.4.2
jiti: 2.7.0
@@ -9403,9 +9548,9 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
posthog-node@5.35.4:
posthog-node@5.35.5:
dependencies:
'@posthog/core': 1.29.11
'@posthog/core': 1.29.12
powershell-utils@0.1.0: {}
@@ -9698,6 +9843,27 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.0.2
'@rolldown/binding-win32-x64-msvc': 1.0.2
rolldown@1.0.3:
dependencies:
'@oxc-project/types': 0.133.0
'@rolldown/pluginutils': 1.0.1
optionalDependencies:
'@rolldown/binding-android-arm64': 1.0.3
'@rolldown/binding-darwin-arm64': 1.0.3
'@rolldown/binding-darwin-x64': 1.0.3
'@rolldown/binding-freebsd-x64': 1.0.3
'@rolldown/binding-linux-arm-gnueabihf': 1.0.3
'@rolldown/binding-linux-arm64-gnu': 1.0.3
'@rolldown/binding-linux-arm64-musl': 1.0.3
'@rolldown/binding-linux-ppc64-gnu': 1.0.3
'@rolldown/binding-linux-s390x-gnu': 1.0.3
'@rolldown/binding-linux-x64-gnu': 1.0.3
'@rolldown/binding-linux-x64-musl': 1.0.3
'@rolldown/binding-openharmony-arm64': 1.0.3
'@rolldown/binding-wasm32-wasi': 1.0.3
'@rolldown/binding-win32-arm64-msvc': 1.0.3
'@rolldown/binding-win32-x64-msvc': 1.0.3
rou3@0.8.1: {}
router@2.2.0:
@@ -9769,7 +9935,7 @@ snapshots:
setprototypeof@1.2.0: {}
shadcn@4.8.1(@types/node@25.9.1)(typescript@6.0.3):
shadcn@4.8.2(@types/node@25.9.1)(typescript@6.0.3):
dependencies:
'@babel/core': 7.29.7
'@babel/parser': 7.29.7
@@ -9976,11 +10142,11 @@ snapshots:
tailwindcss@4.3.0: {}
takumi-js@1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
takumi-js@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
'@takumi-rs/core': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/helpers': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/wasm': 1.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/core': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/helpers': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@takumi-rs/wasm': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
transitivePeerDependencies:
- react
- react-dom
@@ -10133,12 +10299,12 @@ snapshots:
picomatch: 4.0.4
webpack-virtual-modules: 0.6.2
unstorage@2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3):
unstorage@2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
optionalDependencies:
'@vercel/functions': 3.6.0
chokidar: 5.0.0
db0: 0.3.4
lru-cache: 11.5.0
lru-cache: 11.5.1
ofetch: 2.0.0-alpha.3
until-async@3.0.2: {}
@@ -10208,12 +10374,12 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
vite-plus@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3):
vite-plus@0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3):
dependencies:
'@oxc-project/types': 0.129.0
'@oxlint/plugins': 1.61.0
'@voidzero-dev/vite-plus-core': 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)
'@voidzero-dev/vite-plus-test': 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
'@voidzero-dev/vite-plus-test': 0.1.22(@types/node@25.9.1)(@voidzero-dev/vite-plus-core@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3))(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)
oxfmt: 0.48.0
oxlint: 1.63.0(oxlint-tsgolint@0.22.1)
oxlint-tsgolint: 0.22.1
@@ -10257,12 +10423,12 @@ snapshots:
- vite
- yaml
vite-plus@0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)):
vite-plus@0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)):
dependencies:
'@oxc-project/types': 0.129.0
'@oxlint/plugins': 1.61.0
'@voidzero-dev/vite-plus-core': 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(typescript@6.0.3)
'@voidzero-dev/vite-plus-test': 0.1.22(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
'@voidzero-dev/vite-plus-test': 0.1.22(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(jsdom@29.1.1(@noble/hashes@1.8.0))(typescript@6.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0))
oxfmt: 0.48.0
oxlint: 1.63.0(oxlint-tsgolint@0.22.1)
oxlint-tsgolint: 0.22.1