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:
jake committed 2026-05-27 16:07:49 -04:00
1 parent 7554ae92eb
commit 2de4b24fc9
21 files changed
+530 -303

No files matched your search

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