diff --git a/console/.oxfmtrc.json b/console/.oxfmtrc.json
deleted file mode 100644
index fce110d..0000000
--- a/console/.oxfmtrc.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "./node_modules/oxfmt/configuration_schema.json",
- "ignorePatterns": ["src/routeTree.gen.ts"]
-}
diff --git a/console/.oxlintrc.json b/console/.oxlintrc.json
deleted file mode 100644
index 5f58139..0000000
--- a/console/.oxlintrc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$schema": "./node_modules/oxlint/configuration_schema.json",
- "plugins": ["typescript", "unicorn", "oxc", "react", "jsx-a11y", "node"],
- "categories": {
- "correctness": "error"
- },
- "rules": {},
- "ignorePatterns": ["src/routeTree.gen.ts"],
- "env": {
- "builtin": true,
- "browser": true,
- "node": true
- }
-}
diff --git a/console/README.md b/console/README.md
deleted file mode 100644
index ffa25b5..0000000
--- a/console/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Wasmeld Console
-
-WebAssembly Runtime 的管理控制台,使用 TanStack Start、TanStack Router、
-React 和 srvx 构建,通过 Node.js 运行。页面只调用 `wasmeld-console` HTTP API,
-不直接访问数据库或 Wasmeld Runtime。
-
-运行概览可以启动、停止和重启整个 Runtime;服务版本与运行实例页面负责管理单个
-Wasm Actor。停止 Runtime 不会断开管理 API。
-
-## Development
-
-```bash
-npm install
-npm run dev
-```
-
-默认访问 `http://localhost:3000`。
-
-管理 API 默认使用 `http://127.0.0.1:8080`。可以在控制台的“运行设置”中修改,
-或在构建时设置 `VITE_WASMELD_API_URL`。
-
-## Validation
-
-```bash
-npm run format:check
-npm run lint
-npm test
-```
-
-生产构建完成后可以运行:
-
-```bash
-npm start
-```
-
-`npm test` 会生成 Node.js 生产构建,并验证 srvx 服务端渲染和静态资源。
diff --git a/console/package.json b/console/package.json
deleted file mode 100644
index 2482b22..0000000
--- a/console/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "wasmeld-console",
- "version": "0.1.0",
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "vite dev",
- "build": "vite build && tsc --noEmit",
- "start": "srvx serve --prod --entry dist/server/server.js --static ../client",
- "preview": "vite preview",
- "test": "npm run build && node --test tests/rendered-html.test.mjs",
- "lint": "oxlint . --deny-warnings",
- "format": "oxfmt .",
- "format:check": "oxfmt --check ."
- },
- "dependencies": {
- "@tanstack/react-router": "^1.170.18",
- "@tanstack/react-start": "^1.168.32",
- "lucide-react": "^1.27.0",
- "react": "19.2.6",
- "react-dom": "19.2.6",
- "srvx": "^0.12.4"
- },
- "devDependencies": {
- "@types/node": "22.19.19",
- "@types/react": "19.2.14",
- "@types/react-dom": "19.2.3",
- "@vitejs/plugin-react": "6.0.2",
- "oxfmt": "^0.60.0",
- "oxlint": "^1.75.0",
- "typescript": "5.9.3",
- "vite": "^8.1.5"
- },
- "engines": {
- "node": ">=22.13.0"
- }
-}
diff --git a/console/src/components/dialogs.tsx b/console/src/components/dialogs.tsx
deleted file mode 100644
index 65c79c6..0000000
--- a/console/src/components/dialogs.tsx
+++ /dev/null
@@ -1,379 +0,0 @@
-import {
- ArrowRight,
- Clock3,
- CloudUpload,
- FileCode2,
- Package,
- Play,
- RadioTower,
- RefreshCw,
- ShieldCheck,
- SquareTerminal,
- X,
-} from "lucide-react";
-import { FormEvent, ReactNode, useState } from "react";
-import { InvokeResult, RegisterComponentInput } from "../api";
-import {
- FormattedInvocationOutput,
- Service,
- formatInvocationOutput,
- invocationInputSize,
- parseInvocationInput,
-} from "../console-model";
-
-function DialogFrame({
- title,
- description,
- icon,
- onClose,
- closeDisabled = false,
- children,
-}: {
- title: string;
- description: string;
- icon: ReactNode;
- onClose: () => void;
- closeDisabled?: boolean;
- children: ReactNode;
-}) {
- return (
-
-
-
- );
-}
-
-export function ActivateDeploymentDialog({
- service,
- currentRevision,
- submitting,
- onClose,
- onConfirm,
-}: {
- service: Service;
- currentRevision: string | null;
- submitting: boolean;
- onClose: () => void;
- onConfirm: () => void;
-}) {
- return (
- }
- onClose={onClose}
- closeDisabled={submitting}
- >
-
-
-
- 当前版本
- {currentRevision ?? "尚未部署"}
-
-
-
- 目标版本
- {service.revision}
-
-
-
- Wasmeld 将先确认 {service.id}@{service.revision} 的 Actor 可用,再更新对外路由。
-
-
-
-
-
-
-
- );
-}
-
-export function DeployDialog({
- onClose,
- onRegister,
-}: {
- onClose: () => void;
- onRegister: (input: RegisterComponentInput) => Promise;
-}) {
- const [file, setFile] = useState(null);
- const [submitting, setSubmitting] = useState(false);
- const [error, setError] = useState("");
- const fileName = file?.name ?? "";
-
- async function submit(event: FormEvent) {
- event.preventDefault();
- if (!file) return;
- if (!file.name.toLowerCase().endsWith(".wasmpkg")) {
- setError("请选择 .wasmpkg 组件包");
- return;
- }
- setSubmitting(true);
- setError("");
- try {
- await onRegister({ file });
- } catch (submitError) {
- setError(submitError instanceof Error ? submitError.message : "组件注册失败");
- setSubmitting(false);
- }
- }
-
- return (
- }
- onClose={onClose}
- >
-
-
- );
-}
-
-export function WitPackageDialog({
- onClose,
- onPublish,
-}: {
- onClose: () => void;
- onPublish: (file: File) => Promise;
-}) {
- const [file, setFile] = useState(null);
- const [submitting, setSubmitting] = useState(false);
- const [error, setError] = useState("");
- const fileName = file?.name ?? "";
-
- async function submit(event: FormEvent) {
- event.preventDefault();
- if (!file) return;
- if (!file.name.toLowerCase().endsWith(".wasm")) {
- setError("请选择由 wasmeld wit build 生成的 .wasm 文件");
- return;
- }
- if (file.size > 4 * 1024 * 1024) {
- setError("WIT 包不能超过 4 MB");
- return;
- }
- setSubmitting(true);
- setError("");
- try {
- await onPublish(file);
- } catch (submitError) {
- setError(submitError instanceof Error ? submitError.message : "WIT 包发布失败");
- setSubmitting(false);
- }
- }
-
- return (
- }
- onClose={onClose}
- >
-
-
- );
-}
-
-export function InvokeDialog({
- service,
- onClose,
- onInvoke,
-}: {
- service: Service;
- onClose: () => void;
- onInvoke: (service: Service, input: Uint8Array) => Promise;
-}) {
- const [input, setInput] = useState(service.id === "echo" ? "hello wasm" : "");
- const [format, setFormat] = useState<"utf8" | "hex">("utf8");
- const [output, setOutput] = useState("");
- const [outputBytes, setOutputBytes] = useState(null);
- const [outputFormat, setOutputFormat] = useState(null);
- const [running, setRunning] = useState(false);
- const [failed, setFailed] = useState(false);
- const [latency, setLatency] = useState(null);
-
- async function invoke() {
- setRunning(true);
- setOutput("");
- setOutputBytes(null);
- setOutputFormat(null);
- setFailed(false);
- setLatency(null);
- try {
- const result = await onInvoke(service, parseInvocationInput(input, format));
- const formatted = formatInvocationOutput(service, result.output, format);
- setOutput(formatted.text);
- setOutputBytes(result.outputBytes);
- setOutputFormat(formatted);
- setLatency(result.latencyMs);
- } catch (invokeError) {
- setFailed(true);
- setOutput(invokeError instanceof Error ? invokeError.message : "组件调用失败");
- } finally {
- setRunning(false);
- }
- }
-
- return (
- }
- onClose={onClose}
- >
-
-
-
-
-
-
-
{invocationInputSize(input, format)} B
-
-
-
-
-
-
输出
- {output && latency !== null && outputBytes !== null && outputFormat && (
-
-
- {outputBytes} B · {outputFormat.format}
- {outputFormat.automatic ? " · 自动" : ""}
-
-
-
- {latency} ms
-
-
- )}
-
-
{running ? "invoking..." : output || "等待调用"}
-
-
-
-
-
-
-
- );
-}
diff --git a/console/src/components/views.tsx b/console/src/components/views.tsx
deleted file mode 100644
index 5609ef7..0000000
--- a/console/src/components/views.tsx
+++ /dev/null
@@ -1,986 +0,0 @@
-import {
- Activity,
- AlertTriangle,
- Archive,
- ArrowRight,
- Box,
- Braces,
- Check,
- CircleStop,
- CloudUpload,
- Cpu,
- Download,
- FileCode2,
- Package,
- Play,
- RadioTower,
- RefreshCw,
- RotateCcw,
- Search,
- Server,
- SquareTerminal,
- X,
- Zap,
-} from "lucide-react";
-import { ReactNode, useState } from "react";
-import {
- BackendCapability,
- BackendRuntime,
- BackendWitPackage,
- witPackageDownloadUrl,
-} from "../api";
-import {
- EventTone,
- RuntimeEvent,
- Service,
- ServiceStatus,
- STATUS_META,
- formatDuration,
- serviceKey,
-} from "../console-model";
-
-function PageHeading({
- eyebrow,
- title,
- description,
- actions,
-}: {
- eyebrow: string;
- title: string;
- description: string;
- actions?: ReactNode;
-}) {
- return (
-
-
-
{eyebrow}
-
{title}
-
{description}
-
- {actions &&
{actions}
}
-
- );
-}
-
-export function Overview({
- services,
- filteredServices,
- events,
- running,
- faulted,
- totalCalls,
- deploymentCount,
- runtime,
- selectedService,
- onSelect,
- onDeploy,
- onInvoke,
- onStatus,
- onActivate,
- onViewAll,
- onRefresh,
- onRuntimeAction,
- runtimeAction,
- deploymentAction,
-}: {
- services: Service[];
- filteredServices: Service[];
- events: RuntimeEvent[];
- running: number;
- faulted: number;
- totalCalls: number;
- deploymentCount: number;
- runtime: BackendRuntime | null;
- selectedService: Service | null;
- onSelect: (service: Service) => void;
- onDeploy: () => void;
- onInvoke: (service: Service) => void;
- onStatus: (service: Service, status: ServiceStatus) => void;
- onActivate: (service: Service) => void;
- onViewAll: () => void;
- onRefresh: () => void;
- onRuntimeAction: (action: "start" | "stop" | "restart") => void;
- runtimeAction: "start" | "stop" | "restart" | null;
- deploymentAction: string | null;
-}) {
- const errorCount = services.reduce((sum, service) => sum + service.errors, 0);
- const latencies = services
- .map((service) => service.latencyMs)
- .filter((latency): latency is number => latency !== null);
- const latestLatency = latencies.length ? Math.max(...latencies) : null;
-
- return (
- <>
-
-
-
- >
- }
- />
-
-
- }
- label="服务版本"
- value={services.length.toString()}
- note={`${deploymentCount} 个对外服务`}
- tone="cyan"
- />
- }
- label="运行实例"
- value={running.toString()}
- note={`${services.length - running} 个未运行`}
- tone="green"
- />
- }
- label="累计调用"
- value={totalCalls.toLocaleString("zh-CN")}
- note="持久化统计"
- tone="amber"
- />
- }
- label="异常"
- value={(faulted + errorCount).toString()}
- note={faulted + errorCount ? "需要检查" : "无异常"}
- tone="coral"
- />
-
-
-
-
-
-
-
-
- Wasmeld Runtime
-
- {runtime?.status === "running"
- ? "Engine 已启用 fuel 与 epoch interruption"
- : "Engine 与所有 Actor 已释放"}
-
-
-
- {runtime?.status === "stopped" ? (
-
- ) : (
- <>
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
服务状态
-
已注册版本及当前 Actor 状态
-
-
-
-
-
-
-
-
-
- {selectedService && (
-
-
-
-
-
-
- 当前选中
-
- {selectedService.id}
- @{selectedService.revision}
-
-
-
-
-
-
-
-
- {!selectedService.active && (
-
- )}
-
-
-
- )}
- >
- );
-}
-
-function Metric({
- icon,
- label,
- value,
- note,
- tone,
-}: {
- icon: ReactNode;
- label: string;
- value: string;
- note: string;
- tone: string;
-}) {
- return (
-
- {icon}
-
- {label}
- {value}
-
- {note}
-
- );
-}
-
-function RuntimeStat({ label, value, detail }: { label: string; value: string; detail: string }) {
- return (
-
- {label}
- {value}
- {detail}
-
- );
-}
-
-function DetailValue({ label, value }: { label: string; value: string }) {
- return (
-
- {label}
- {value}
-
- );
-}
-
-function StatusBadge({ status }: { status: ServiceStatus }) {
- const meta = STATUS_META[status];
- return (
-
-
- {meta.label}
-
- );
-}
-
-function CapabilitySummary({ capabilities }: { capabilities: BackendCapability[] }) {
- if (capabilities.length === 0) {
- return 无;
- }
-
- const [first, ...remaining] = capabilities;
- return (
- capability.interface).join("\n")}
- >
-
-
- {first.package}/{first.name} @{first.version}
-
- {remaining.length > 0 && +{remaining.length}}
-
- );
-}
-
-function ServiceTable({
- services,
- selectedKey,
- onSelect,
- onInvoke,
- onStatus,
- onActivate,
- canActivate,
- deploymentAction,
- compact = false,
-}: {
- services: Service[];
- selectedKey?: string;
- onSelect: (service: Service) => void;
- onInvoke: (service: Service) => void;
- onStatus: (service: Service, status: ServiceStatus) => void;
- onActivate: (service: Service) => void;
- canActivate: boolean;
- deploymentAction: string | null;
- compact?: boolean;
-}) {
- if (services.length === 0) {
- return (
-
-
- 没有匹配的服务
- 调整搜索关键词或状态筛选。
-
- );
- }
-
- return (
-
-
-
-
- | 服务 |
- 状态 |
- {!compact && 制品 | }
- {!compact && Host 能力 | }
- 调用 |
- 延迟 |
-
- 操作
- |
-
-
-
- {services.map((service) => (
-
- |
-
- |
-
-
- |
- {!compact && {service.artifact} | }
- {!compact && (
-
-
- |
- )}
- {service.calls.toLocaleString("zh-CN")} |
-
- {service.latencyMs ? `${service.latencyMs} ms` : "—"}
- |
-
-
-
- {service.status === "running" ? (
- <>
-
-
-
- >
- ) : (
-
- )}
-
- |
-
- ))}
-
-
-
- );
-}
-
-function EventList({ events }: { events: RuntimeEvent[] }) {
- const icons: Record = {
- success: ,
- warning: ,
- danger: ,
- neutral: ,
- };
-
- return (
-
- {events.map((event) => (
-
-
{icons[event.tone]}
-
- {event.title}
- {event.detail}
-
-
-
- ))}
-
- );
-}
-
-export function ServicesView({
- services,
- statusFilter,
- onFilter,
- onDeploy,
- onInvoke,
- onSelect,
- onStatus,
- onActivate,
- canActivate,
- deploymentAction,
-}: {
- services: Service[];
- statusFilter: "all" | ServiceStatus;
- onFilter: (status: "all" | ServiceStatus) => void;
- onDeploy: () => void;
- onInvoke: (service: Service) => void;
- onSelect: (service: Service) => void;
- onStatus: (service: Service, status: ServiceStatus) => void;
- onActivate: (service: Service) => void;
- canActivate: boolean;
- deploymentAction: string | null;
-}) {
- return (
- <>
-
-
- 注册组件
-
- }
- />
-
-
-
- {[
- ["all", "全部"],
- ["running", "运行中"],
- ["stopped", "已停止"],
- ["faulted", "故障"],
- ].map(([value, label]) => (
-
- ))}
-
-
{services.length} 个版本
-
-
-
- >
- );
-}
-
-export function WitPackagesView({
- apiBase,
- packages,
- onPublish,
-}: {
- apiBase: string;
- packages: BackendWitPackage[];
- onPublish: () => void;
-}) {
- function downloadPackage(packageMetadata: BackendWitPackage) {
- const anchor = document.createElement("a");
- anchor.href = witPackageDownloadUrl(apiBase, packageMetadata);
- anchor.download = `${packageMetadata.name.replace(":", "-")}-${packageMetadata.version}.wasm`;
- document.body.append(anchor);
- anchor.click();
- anchor.remove();
- }
-
- return (
- <>
-
-
- 发布 WIT 包
-
- }
- />
-
-
- 发布后不可覆盖;包名、版本与依赖由制品自动解析。
- {packages.length} 个包版本
-
- {packages.length === 0 ? (
-
-
- 没有匹配的 WIT 包
- 发布二进制 WIT Package,或调整搜索关键词。
-
- ) : (
-
-
-
-
- | Package |
- 依赖 |
- SHA-256 |
-
- 操作
- |
-
-
-
- {packages.map((packageMetadata) => {
- const dependencies = packageMetadata.dependencies
- .map((dependency) => `${dependency.name}@${dependency.version}`)
- .join(", ");
- return (
-
- |
-
-
-
-
-
- {packageMetadata.name}
- {packageMetadata.version}
-
-
- |
-
- {dependencies || "无直接依赖"}
- |
-
- {packageMetadata.sha256}
- |
-
-
-
-
- |
-
- );
- })}
-
-
-
- )}
-
- >
- );
-}
-
-export function InstancesView({
- services,
- onInvoke,
- onStatus,
- onRefresh,
-}: {
- services: Service[];
- onInvoke: (service: Service) => void;
- onStatus: (service: Service, status: ServiceStatus) => void;
- onRefresh: () => void;
-}) {
- const instances = services.filter(
- (service) => service.status === "running" || service.status === "faulted",
- );
-
- return (
- <>
-
-
-
- }
- />
-
- {instances.length === 0 ? (
-
- ) : (
- instances.map((service) => (
-
-
-
-
-
-
-
-
- {service.id}@{service.revision}
-
- actor/{service.id}-01
-
-
-
-
-
-
-
- {service.updatedAt}
-
-
-
-
-
-
-
- ))
- )}
-
- >
- );
-}
-
-export function ActivityView({
- events,
- services,
-}: {
- events: RuntimeEvent[];
- services: Service[];
-}) {
- const calls = services.reduce((sum, service) => sum + service.calls, 0);
- const errors = services.reduce((sum, service) => sum + service.errors, 0);
- const latencies = services
- .map((service) => service.latencyMs)
- .filter((latency): latency is number => latency !== null);
- const averageLatency = latencies.length
- ? latencies.reduce((sum, latency) => sum + latency, 0) / latencies.length
- : null;
-
- function exportEvents() {
- const blob = new Blob([JSON.stringify(events, null, 2)], {
- type: "application/json",
- });
- const url = URL.createObjectURL(blob);
- const anchor = document.createElement("a");
- anchor.href = url;
- anchor.download = "wasmeld-events.json";
- anchor.click();
- URL.revokeObjectURL(url);
- }
-
- return (
- <>
-
-
- 导出记录
-
- }
- />
-
-
-
- 时间范围
- 当前进程
-
-
- 成功率
- {calls ? `${(((calls - errors) / calls) * 100).toFixed(2)}%` : "—"}
-
-
- 平均延迟
- {averageLatency === null ? "—" : `${averageLatency.toFixed(1)} ms`}
-
-
- 记录数
- {events.length}
-
-
-
-
- >
- );
-}
-
-export function SettingsView({
- endpoint,
- onSaveEndpoint,
-}: {
- endpoint: string;
- onSaveEndpoint: (value: string) => void;
-}) {
- const [value, setValue] = useState(endpoint);
-
- return (
- <>
-
-
- >
- );
-}
diff --git a/console/src/routeTree.gen.ts b/console/src/routeTree.gen.ts
deleted file mode 100644
index ac3e6c2..0000000
--- a/console/src/routeTree.gen.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/* oxlint-disable */
-
-// @ts-nocheck
-
-// noinspection JSUnusedGlobalSymbols
-
-// This file was automatically generated by TanStack Router.
-// You should NOT make any changes in this file as it will be overwritten.
-// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
-
-import { Route as rootRouteImport } from './routes/__root'
-import { Route as IndexRouteImport } from './routes/index'
-
-const IndexRoute = IndexRouteImport.update({
- id: '/',
- path: '/',
- getParentRoute: () => rootRouteImport,
-} as any)
-
-export interface FileRoutesByFullPath {
- '/': typeof IndexRoute
-}
-export interface FileRoutesByTo {
- '/': typeof IndexRoute
-}
-export interface FileRoutesById {
- __root__: typeof rootRouteImport
- '/': typeof IndexRoute
-}
-export interface FileRouteTypes {
- fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/'
- fileRoutesByTo: FileRoutesByTo
- to: '/'
- id: '__root__' | '/'
- fileRoutesById: FileRoutesById
-}
-export interface RootRouteChildren {
- IndexRoute: typeof IndexRoute
-}
-
-declare module '@tanstack/react-router' {
- interface FileRoutesByPath {
- '/': {
- id: '/'
- path: '/'
- fullPath: '/'
- preLoaderRoute: typeof IndexRouteImport
- parentRoute: typeof rootRouteImport
- }
- }
-}
-
-const rootRouteChildren: RootRouteChildren = {
- IndexRoute: IndexRoute,
-}
-export const routeTree = rootRouteImport
- ._addFileChildren(rootRouteChildren)
- ._addFileTypes()
-
-import type { getRouter } from './router.tsx'
-import type { createStart } from '@tanstack/react-start'
-declare module '@tanstack/react-start' {
- interface Register {
- ssr: true
- router: Awaited>
- }
-}
diff --git a/console/src/router.tsx b/console/src/router.tsx
deleted file mode 100644
index f8bf919..0000000
--- a/console/src/router.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { createRouter } from "@tanstack/react-router";
-import { routeTree } from "./routeTree.gen";
-
-export function getRouter() {
- return createRouter({
- routeTree,
- defaultPreload: "intent",
- scrollRestoration: true,
- });
-}
-
-declare module "@tanstack/react-router" {
- interface Register {
- router: ReturnType;
- }
-}
diff --git a/console/src/routes/__root.tsx b/console/src/routes/__root.tsx
deleted file mode 100644
index 6354446..0000000
--- a/console/src/routes/__root.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-///
-
-import { HeadContent, Outlet, Scripts, createRootRoute } from "@tanstack/react-router";
-import type { ReactNode } from "react";
-import appCss from "../styles/app.css?url";
-
-export const Route = createRootRoute({
- head: () => ({
- meta: [
- { charSet: "utf-8" },
- {
- name: "viewport",
- content: "width=device-width, initial-scale=1",
- },
- { title: "Wasmeld Console" },
- {
- name: "description",
- content: "WebAssembly Runtime 管理控制台",
- },
- { property: "og:title", content: "Wasmeld Console" },
- {
- property: "og:description",
- content: "WebAssembly Runtime 管理控制台",
- },
- { property: "og:type", content: "website" },
- { property: "og:image", content: "/og.png" },
- { name: "twitter:card", content: "summary_large_image" },
- { name: "twitter:title", content: "Wasmeld Console" },
- {
- name: "twitter:description",
- content: "WebAssembly Runtime 管理控制台",
- },
- { name: "twitter:image", content: "/og.png" },
- ],
- links: [{ rel: "stylesheet", href: appCss }],
- }),
- component: RootComponent,
-});
-
-function RootComponent() {
- return (
-
-
-
- );
-}
-
-function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
- return (
-
-
-
-
-
- {children}
-
-
-
- );
-}
diff --git a/console/src/routes/index.tsx b/console/src/routes/index.tsx
deleted file mode 100644
index 5130a78..0000000
--- a/console/src/routes/index.tsx
+++ /dev/null
@@ -1,489 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { ArrowRight, Braces, CheckCircle2, Search, Server, ShieldCheck } from "lucide-react";
-import { useCallback, useEffect, useMemo, useState } from "react";
-import {
- BackendDeployment,
- BackendRuntime,
- BackendWitPackage,
- RegisterComponentInput,
- activateDeployment,
- changeRuntimeState,
- changeServiceState,
- fetchSnapshot,
- getApiBase,
- invokeComponent,
- publishWitPackage,
- registerComponent,
- saveApiBase,
-} from "../api";
-import {
- ConnectionState,
- NAV_ITEMS,
- RuntimeEvent,
- Service,
- ServiceStatus,
- View,
- formatApiHost,
- formatDuration,
- serviceKey,
- toEvent,
- toService,
-} from "../console-model";
-import {
- ActivateDeploymentDialog,
- DeployDialog,
- InvokeDialog,
- WitPackageDialog,
-} from "../components/dialogs";
-import {
- ActivityView,
- InstancesView,
- Overview,
- ServicesView,
- SettingsView,
- WitPackagesView,
-} from "../components/views";
-
-export const Route = createFileRoute("/")({
- component: Home,
-});
-
-function Home() {
- const [view, setView] = useState("overview");
- const [services, setServices] = useState([]);
- const [events, setEvents] = useState([]);
- const [deployments, setDeployments] = useState([]);
- const [witPackages, setWitPackages] = useState([]);
- const [runtime, setRuntime] = useState(null);
- const [runtimeAction, setRuntimeAction] = useState<"start" | "stop" | "restart" | null>(null);
- const [connection, setConnection] = useState("connecting");
- const [apiBase, setApiBase] = useState(getApiBase);
- const [query, setQuery] = useState("");
- const [statusFilter, setStatusFilter] = useState<"all" | ServiceStatus>("all");
- const [selectedKey, setSelectedKey] = useState("");
- const [deployOpen, setDeployOpen] = useState(false);
- const [witPublishOpen, setWitPublishOpen] = useState(false);
- const [invokeKey, setInvokeKey] = useState(null);
- const [activationKey, setActivationKey] = useState(null);
- const [deploymentAction, setDeploymentAction] = useState(null);
- const [toast, setToast] = useState(null);
-
- const selectedService =
- services.find((service) => serviceKey(service) === selectedKey) ?? services[0] ?? null;
- const invokeService = services.find((service) => serviceKey(service) === invokeKey) ?? null;
- const activationService =
- services.find((service) => serviceKey(service) === activationKey) ?? null;
-
- const filteredServices = useMemo(() => {
- const normalized = query.trim().toLowerCase();
- return services.filter((service) => {
- const matchesText =
- !normalized ||
- service.id.toLowerCase().includes(normalized) ||
- service.description.toLowerCase().includes(normalized) ||
- service.artifact.toLowerCase().includes(normalized);
- const matchesStatus = statusFilter === "all" || service.status === statusFilter;
- return matchesText && matchesStatus;
- });
- }, [query, services, statusFilter]);
-
- const filteredWitPackages = useMemo(() => {
- const normalized = query.trim().toLowerCase();
- return witPackages.filter(
- (packageMetadata) =>
- !normalized ||
- packageMetadata.name.toLowerCase().includes(normalized) ||
- packageMetadata.version.toLowerCase().includes(normalized) ||
- packageMetadata.sha256.toLowerCase().includes(normalized),
- );
- }, [query, witPackages]);
-
- const running = services.filter((service) => service.status === "running").length;
- const faulted = services.filter((service) => service.status === "faulted").length;
- const totalCalls = services.reduce((sum, service) => sum + service.calls, 0);
-
- const refreshSnapshot = useCallback(async () => {
- try {
- const snapshot = await fetchSnapshot(apiBase);
- const activeRevisions = new Map(
- snapshot.deployments.map((deployment) => [
- deployment.service_id,
- deployment.active_revision,
- ]),
- );
- const nextServices = snapshot.services.map((service) =>
- toService(service, activeRevisions.get(service.id)),
- );
- setServices(nextServices);
- setDeployments(snapshot.deployments);
- setEvents(snapshot.events.map(toEvent));
- setRuntime(snapshot.runtime);
- setWitPackages(snapshot.witPackages);
- // Preserve operator context when possible. Registrations and cleanup can
- // remove the selected revision between polls, in which case the first
- // remaining service becomes the deterministic fallback.
- setSelectedKey((current) =>
- nextServices.some((service) => serviceKey(service) === current)
- ? current
- : nextServices[0]
- ? serviceKey(nextServices[0])
- : "",
- );
- setConnection("online");
- } catch {
- // Clear the complete snapshot on any request failure. Mixing stale
- // services with live deployments or Runtime state would present actions
- // against identities that may no longer exist.
- setServices([]);
- setDeployments([]);
- setEvents([]);
- setRuntime(null);
- setWitPackages([]);
- setConnection("offline");
- }
- }, [apiBase]);
-
- useEffect(() => {
- void refreshSnapshot();
- const interval = window.setInterval(() => void refreshSnapshot(), 5000);
- return () => window.clearInterval(interval);
- }, [refreshSnapshot]);
-
- function notify(message: string) {
- setToast(message);
- window.setTimeout(() => setToast(null), 2600);
- }
-
- async function setServiceStatus(service: Service, status: ServiceStatus) {
- const action =
- status === "stopped" ? "stop" : service.status === "running" ? "restart" : "start";
- try {
- await changeServiceState(apiBase, service, action);
- await refreshSnapshot();
- notify(
- `${service.id} ${
- action === "stop" ? "已停止" : action === "restart" ? "已重启" : "已启动"
- }`,
- );
- } catch (error) {
- notify(error instanceof Error ? error.message : "运行时操作失败");
- }
- }
-
- async function setRuntimeStatus(action: "start" | "stop" | "restart") {
- setRuntimeAction(action);
- try {
- await changeRuntimeState(apiBase, action);
- await refreshSnapshot();
- notify(
- action === "start"
- ? "Runtime 已启动"
- : action === "stop"
- ? "Runtime 已停止"
- : "Runtime 已重启",
- );
- } catch (error) {
- notify(error instanceof Error ? error.message : "Runtime 操作失败");
- } finally {
- setRuntimeAction(null);
- }
- }
-
- async function activateService(service: Service) {
- const key = serviceKey(service);
- setDeploymentAction(key);
- try {
- await activateDeployment(apiBase, service);
- await refreshSnapshot();
- setActivationKey(null);
- notify(`${service.id}@${service.revision} 已设为对外版本`);
- } catch (error) {
- notify(error instanceof Error ? error.message : "Deployment 切换失败");
- } finally {
- setDeploymentAction(null);
- }
- }
-
- async function runInvocation(service: Service, input: Uint8Array) {
- const result = await invokeComponent(apiBase, service, input);
- await refreshSnapshot();
- return result;
- }
-
- async function registerService(input: RegisterComponentInput) {
- const registered = await registerComponent(apiBase, input);
- await refreshSnapshot();
- setSelectedKey(serviceKey(registered));
- setView("services");
- setDeployOpen(false);
- notify("组件注册成功");
- }
-
- async function publishWit(file: File) {
- const packageMetadata = await publishWitPackage(apiBase, file);
- await refreshSnapshot();
- setWitPublishOpen(false);
- notify(`${packageMetadata.name}@${packageMetadata.version} 已发布`);
- }
-
- function updateApiBase(value: string) {
- try {
- const nextBase = saveApiBase(value);
- setConnection("connecting");
- setApiBase(nextBase);
- notify("API 地址已保存");
- } catch (error) {
- notify(error instanceof Error ? error.message : "API 地址无效");
- }
- }
-
- const title = NAV_ITEMS.find((item) => item.id === view)?.label ?? "运行概览";
-
- return (
-
-
-
-
-
-
-
- {view === "overview" && (
- setSelectedKey(serviceKey(service))}
- onDeploy={() => setDeployOpen(true)}
- onInvoke={(service) => setInvokeKey(serviceKey(service))}
- onStatus={setServiceStatus}
- onActivate={(service) => setActivationKey(serviceKey(service))}
- onViewAll={() => setView("services")}
- onRefresh={() => void refreshSnapshot()}
- onRuntimeAction={(action) => void setRuntimeStatus(action)}
- runtimeAction={runtimeAction}
- deploymentAction={deploymentAction}
- />
- )}
-
- {view === "services" && (
- setDeployOpen(true)}
- onInvoke={(service) => setInvokeKey(serviceKey(service))}
- onSelect={(service) => setSelectedKey(serviceKey(service))}
- onStatus={setServiceStatus}
- onActivate={(service) => setActivationKey(serviceKey(service))}
- canActivate={runtime?.status === "running"}
- deploymentAction={deploymentAction}
- />
- )}
-
- {view === "instances" && (
- setInvokeKey(serviceKey(service))}
- onStatus={setServiceStatus}
- onRefresh={() => void refreshSnapshot()}
- />
- )}
-
- {view === "activity" && }
-
- {view === "wit-packages" && (
- setWitPublishOpen(true)}
- />
- )}
-
- {view === "settings" && (
-
- )}
-
-
-
-
-
- {deployOpen && (
-
setDeployOpen(false)} onRegister={registerService} />
- )}
-
- {witPublishOpen && (
- setWitPublishOpen(false)} onPublish={publishWit} />
- )}
-
- {invokeService && (
- setInvokeKey(null)}
- onInvoke={runInvocation}
- />
- )}
-
- {activationService && (
- service.id === activationService.id && service.active)
- ?.revision ?? null
- }
- submitting={deploymentAction === serviceKey(activationService)}
- onClose={() => setActivationKey(null)}
- onConfirm={() => void activateService(activationService)}
- />
- )}
-
- {toast && (
-
- )}
-
- );
-}
-
-function Sidebar({
- view,
- onChange,
- running,
- connection,
- apiBase,
- uptimeMs,
- runtimeStatus,
-}: {
- view: View;
- onChange: (view: View) => void;
- running: number;
- connection: ConnectionState;
- apiBase: string;
- uptimeMs: number | null;
- runtimeStatus: BackendRuntime["status"] | null;
-}) {
- const runtimeLabel =
- connection !== "online"
- ? "离线"
- : runtimeStatus === "running"
- ? "运行中"
- : runtimeStatus === "stopped"
- ? "已停止"
- : "连接中";
- const runtimeHealthClass =
- connection !== "online"
- ? "health-pulse health-offline"
- : runtimeStatus === "running"
- ? "health-pulse"
- : "health-pulse health-stopped";
-
- return (
-
- );
-}
diff --git a/console/src/styles/app.css b/console/src/styles/app.css
deleted file mode 100644
index 2a266f0..0000000
--- a/console/src/styles/app.css
+++ /dev/null
@@ -1,2110 +0,0 @@
-:root {
- --canvas: #f3f5f7;
- --surface: #ffffff;
- --surface-subtle: #f7f8fa;
- --surface-strong: #eef1f3;
- --ink: #182027;
- --ink-soft: #58636d;
- --ink-faint: #89939c;
- --line: #dfe4e8;
- --line-strong: #cdd4da;
- --sidebar: #172026;
- --sidebar-ink: #e9eef1;
- --sidebar-muted: #8f9ba3;
- --green: #16835b;
- --green-bg: #e8f5ef;
- --cyan: #13758a;
- --cyan-bg: #e5f3f6;
- --amber: #a2600c;
- --amber-bg: #fff1d9;
- --coral: #b74938;
- --coral-bg: #fcebe8;
- --shadow: 0 10px 28px rgba(24, 32, 39, 0.08);
-}
-
-* {
- box-sizing: border-box;
-}
-
-html,
-body {
- min-height: 100%;
-}
-
-body {
- margin: 0;
- background: var(--canvas);
- color: var(--ink);
- font-family: Arial, "PingFang SC", "Microsoft YaHei", Helvetica, sans-serif;
- letter-spacing: 0;
-}
-
-button,
-input,
-textarea,
-select {
- font: inherit;
- letter-spacing: 0;
-}
-
-button {
- color: inherit;
-}
-
-button:focus-visible,
-input:focus-visible,
-textarea:focus-visible {
- outline: 2px solid #2192a8;
- outline-offset: 2px;
-}
-
-button:disabled {
- cursor: not-allowed;
- opacity: 0.45;
-}
-
-.sr-only {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip: rect(0, 0, 0, 0);
- white-space: nowrap;
- border: 0;
-}
-
-.app-shell {
- min-height: 100vh;
- display: grid;
- grid-template-columns: 232px minmax(0, 1fr);
-}
-
-.sidebar {
- position: fixed;
- inset: 0 auto 0 0;
- z-index: 20;
- width: 232px;
- display: flex;
- flex-direction: column;
- padding: 22px 14px 16px;
- background: var(--sidebar);
- color: var(--sidebar-ink);
- border-right: 1px solid #263139;
-}
-
-.brand {
- min-height: 44px;
- display: flex;
- align-items: center;
- gap: 11px;
- padding: 0 8px;
-}
-
-.brand-mark {
- width: 34px;
- height: 34px;
- display: grid;
- place-items: center;
- color: #c9f1df;
- background: #20352f;
- border: 1px solid #315449;
- border-radius: 6px;
-}
-
-.brand strong,
-.brand span {
- display: block;
-}
-
-.brand strong {
- font-size: 14px;
- line-height: 18px;
-}
-
-.brand span {
- margin-top: 2px;
- color: var(--sidebar-muted);
- font-family: var(--font-geist-mono), monospace;
- font-size: 9px;
- line-height: 12px;
- text-transform: uppercase;
-}
-
-.environment-switcher {
- width: 100%;
- min-height: 52px;
- margin: 20px 0 22px;
- padding: 8px;
- display: grid;
- grid-template-columns: 30px 1fr 16px;
- align-items: center;
- gap: 8px;
- text-align: left;
- color: var(--sidebar-ink);
- background: #202a30;
- border: 1px solid #303b42;
- border-radius: 6px;
- cursor: pointer;
-}
-
-.environment-icon {
- width: 30px;
- height: 30px;
- display: grid;
- place-items: center;
- color: #aadfcc;
- background: #29383a;
- border-radius: 5px;
-}
-
-.environment-switcher small,
-.environment-switcher strong {
- display: block;
-}
-
-.environment-switcher small {
- margin-bottom: 2px;
- color: var(--sidebar-muted);
- font-size: 9px;
-}
-
-.environment-switcher strong {
- max-width: 118px;
- overflow: hidden;
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.primary-nav {
- display: flex;
- flex-direction: column;
- gap: 3px;
-}
-
-.nav-label {
- padding: 0 10px 7px;
- color: #6f7c84;
- font-size: 9px;
- font-weight: 700;
- text-transform: uppercase;
-}
-
-.nav-item {
- position: relative;
- width: 100%;
- min-height: 40px;
- padding: 0 10px;
- display: grid;
- grid-template-columns: 20px 1fr auto;
- align-items: center;
- gap: 8px;
- color: #aab4ba;
- background: transparent;
- border: 0;
- border-radius: 5px;
- text-align: left;
- font-size: 12px;
- cursor: pointer;
-}
-
-.nav-item::before {
- content: "";
- position: absolute;
- left: -14px;
- width: 3px;
- height: 22px;
- background: transparent;
- border-radius: 0 2px 2px 0;
-}
-
-.nav-item:hover {
- color: #edf3f5;
- background: #202a30;
-}
-
-.nav-item.active {
- color: #f8fbfc;
- background: #253138;
-}
-
-.nav-item.active::before {
- background: #52bc94;
-}
-
-.nav-count {
- min-width: 19px;
- height: 19px;
- padding: 0 5px;
- display: grid;
- place-items: center;
- color: #b8e8d6;
- background: #30483f;
- border-radius: 10px;
- font-size: 9px;
-}
-
-.sidebar-runtime {
- margin-top: auto;
- padding: 13px 10px 4px;
- border-top: 1px solid #2a353c;
-}
-
-.runtime-title {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 11px;
- font-weight: 700;
-}
-
-.health-pulse {
- width: 7px;
- height: 7px;
- background: #55c697;
- border-radius: 50%;
- box-shadow: 0 0 0 3px rgba(85, 198, 151, 0.14);
-}
-
-.health-stopped {
- background: #d79a38;
- box-shadow: 0 0 0 3px rgba(215, 154, 56, 0.14);
-}
-
-.runtime-meta {
- margin-top: 8px;
- display: flex;
- justify-content: space-between;
- color: #75828a;
- font-family: var(--font-geist-mono), monospace;
- font-size: 9px;
-}
-
-.app-main {
- min-width: 0;
- min-height: 100vh;
- grid-column: 2;
- display: grid;
- grid-template-rows: 56px 1fr 28px;
-}
-
-.topbar {
- position: sticky;
- top: 0;
- z-index: 15;
- min-width: 0;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 28px;
- background: rgba(255, 255, 255, 0.96);
- border-bottom: 1px solid var(--line);
-}
-
-.breadcrumb {
- display: flex;
- align-items: center;
- gap: 8px;
- color: var(--ink-faint);
- font-size: 11px;
-}
-
-.breadcrumb strong {
- color: var(--ink);
- font-weight: 600;
-}
-
-.topbar-actions {
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.global-search {
- width: 240px;
- height: 32px;
- padding: 0 10px;
- display: flex;
- align-items: center;
- gap: 8px;
- color: var(--ink-faint);
- background: #f4f6f7;
- border: 1px solid var(--line);
- border-radius: 5px;
-}
-
-.global-search:focus-within {
- background: #fff;
- border-color: #9bbec5;
-}
-
-.global-search input {
- width: 100%;
- min-width: 0;
- color: var(--ink);
- background: transparent;
- border: 0;
- outline: 0;
- font-size: 11px;
-}
-
-.global-search input::placeholder {
- color: #98a2aa;
-}
-
-.source-state {
- height: 28px;
- padding: 0 9px;
- display: flex;
- align-items: center;
- gap: 6px;
- color: #72501f;
- background: #fff7e9;
- border: 1px solid #f1dfbf;
- border-radius: 4px;
- font-size: 10px;
- white-space: nowrap;
-}
-
-.source-dot {
- width: 6px;
- height: 6px;
- background: #d18a28;
- border-radius: 50%;
-}
-
-.source-online {
- color: #146947;
- background: var(--green-bg);
- border-color: #b9dfcf;
-}
-
-.source-online .source-dot {
- background: var(--green);
-}
-
-.source-offline {
- color: #963c30;
- background: var(--coral-bg);
- border-color: #efc4bd;
-}
-
-.source-offline .source-dot,
-.health-offline {
- background: var(--coral);
- box-shadow: none;
-}
-
-.avatar-button {
- width: 30px;
- height: 30px;
- display: grid;
- place-items: center;
- color: #ecf7f2;
- background: #31584a;
- border: 0;
- border-radius: 50%;
- font-size: 9px;
- font-weight: 700;
- cursor: pointer;
-}
-
-.content {
- width: 100%;
- max-width: 1540px;
- margin: 0 auto;
- padding: 28px;
-}
-
-.page-heading {
- min-height: 62px;
- display: flex;
- align-items: flex-end;
- justify-content: space-between;
- gap: 24px;
- margin-bottom: 22px;
-}
-
-.eyebrow {
- display: block;
- margin-bottom: 5px;
- color: var(--cyan);
- font-family: var(--font-geist-mono), monospace;
- font-size: 9px;
- font-weight: 700;
-}
-
-.page-heading h1 {
- margin: 0;
- font-size: 23px;
- line-height: 30px;
- letter-spacing: 0;
-}
-
-.page-heading p {
- margin: 4px 0 0;
- color: var(--ink-soft);
- font-size: 11px;
- line-height: 18px;
-}
-
-.heading-actions {
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.primary-button,
-.secondary-button,
-.danger-button,
-.icon-button,
-.text-button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 7px;
- border-radius: 5px;
- font-size: 11px;
- font-weight: 600;
- cursor: pointer;
-}
-
-.primary-button,
-.secondary-button,
-.danger-button {
- min-height: 34px;
- padding: 0 13px;
-}
-
-.primary-button {
- color: #f6fffb;
- background: #1f7658;
- border: 1px solid #1f7658;
-}
-
-.primary-button:hover {
- background: #185f47;
-}
-
-.secondary-button {
- color: var(--ink);
- background: #fff;
- border: 1px solid var(--line-strong);
-}
-
-.secondary-button:hover,
-.icon-button:hover {
- background: var(--surface-subtle);
-}
-
-.danger-button {
- color: #9b3427;
- background: #fff;
- border: 1px solid #e7b9b2;
-}
-
-.danger-button:hover {
- background: #fff4f2;
-}
-
-.icon-button {
- width: 34px;
- height: 34px;
- padding: 0;
- color: var(--ink-soft);
- background: #fff;
- border: 1px solid var(--line-strong);
-}
-
-.text-button {
- padding: 4px 0;
- color: var(--cyan);
- background: transparent;
- border: 0;
-}
-
-.metric-grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
-}
-
-.metric {
- min-width: 0;
- height: 92px;
- padding: 15px;
- display: grid;
- grid-template-columns: 36px 1fr;
- grid-template-rows: 1fr auto;
- gap: 5px 11px;
- background: var(--surface);
- border: 1px solid var(--line);
- border-radius: 6px;
-}
-
-.metric-icon {
- width: 36px;
- height: 36px;
- display: grid;
- place-items: center;
- border-radius: 5px;
-}
-
-.metric-cyan {
- color: var(--cyan);
- background: var(--cyan-bg);
-}
-
-.metric-green {
- color: var(--green);
- background: var(--green-bg);
-}
-
-.metric-amber {
- color: var(--amber);
- background: var(--amber-bg);
-}
-
-.metric-coral {
- color: var(--coral);
- background: var(--coral-bg);
-}
-
-.metric-copy {
- min-width: 0;
-}
-
-.metric-copy span,
-.metric-copy strong {
- display: block;
-}
-
-.metric-copy span {
- margin-bottom: 1px;
- color: var(--ink-soft);
- font-size: 10px;
-}
-
-.metric-copy strong {
- overflow: hidden;
- font-family: var(--font-geist-mono), monospace;
- font-size: 21px;
- line-height: 27px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.metric > small {
- grid-column: 2;
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.runtime-band {
- min-height: 80px;
- margin: 12px 0;
- padding: 12px 16px;
- display: grid;
- grid-template-columns: minmax(280px, 1.8fr) repeat(4, minmax(95px, 0.6fr));
- align-items: center;
- gap: 16px;
- background: #eef4f3;
- border: 1px solid #d5e3df;
- border-left: 3px solid #3f9b78;
- border-radius: 4px;
-}
-
-.runtime-band-title {
- min-width: 0;
- display: flex;
- align-items: center;
- gap: 11px;
-}
-
-.runtime-band-title > div:nth-child(2) {
- min-width: 0;
- flex: 1;
-}
-
-.runtime-symbol {
- width: 36px;
- height: 36px;
- display: grid;
- place-items: center;
- color: #d8f4e8;
- background: #214b3c;
- border-radius: 5px;
-}
-
-.runtime-band-title strong,
-.runtime-band-title span {
- display: block;
-}
-
-.runtime-band-title strong {
- margin-bottom: 3px;
- font-size: 12px;
-}
-
-.runtime-band-title span {
- overflow: hidden;
- color: var(--ink-soft);
- font-size: 9px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.runtime-controls {
- display: flex;
- align-items: center;
- gap: 5px;
-}
-
-.runtime-controls .icon-button {
- width: 30px;
- height: 30px;
-}
-
-.runtime-controls .runtime-stop-button {
- color: #a34033;
- border-color: #e2b8b1;
-}
-
-.runtime-controls .runtime-stop-button:hover {
- background: #fff4f2;
-}
-
-.runtime-stat {
- min-width: 0;
- padding-left: 14px;
- border-left: 1px solid #d0ddd9;
-}
-
-.runtime-stat span,
-.runtime-stat strong,
-.runtime-stat small {
- display: block;
-}
-
-.runtime-stat span {
- color: var(--ink-soft);
- font-size: 9px;
-}
-
-.runtime-stat strong {
- margin: 3px 0 1px;
- font-family: var(--font-geist-mono), monospace;
- font-size: 13px;
-}
-
-.runtime-stat small {
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.overview-grid {
- display: grid;
- grid-template-columns: minmax(0, 1.8fr) minmax(280px, 0.8fr);
- gap: 12px;
-}
-
-.panel {
- min-width: 0;
- background: var(--surface);
- border: 1px solid var(--line);
- border-radius: 6px;
-}
-
-.panel-header {
- min-height: 60px;
- padding: 13px 15px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 16px;
- border-bottom: 1px solid var(--line);
-}
-
-.panel-header h2 {
- margin: 0;
- font-size: 13px;
-}
-
-.panel-header p {
- margin: 3px 0 0;
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.live-label {
- display: flex;
- align-items: center;
- gap: 5px;
- color: var(--green);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
- font-weight: 700;
-}
-
-.live-label span {
- width: 6px;
- height: 6px;
- background: #27a875;
- border-radius: 50%;
- box-shadow: 0 0 0 3px rgba(39, 168, 117, 0.12);
-}
-
-.table-scroll {
- width: 100%;
- overflow-x: auto;
-}
-
-.data-table {
- width: 100%;
- min-width: 620px;
- border-collapse: collapse;
- table-layout: fixed;
-}
-
-.service-table-full {
- min-width: 980px;
-}
-
-.data-table.service-table-full th:first-child {
- width: 24%;
-}
-
-.service-table-full th:nth-child(2) {
- width: 90px;
-}
-
-.service-table-full th:nth-child(3) {
- width: 150px;
-}
-
-.service-table-full th:nth-child(4) {
- width: 220px;
-}
-
-.service-table-full th:nth-child(5),
-.service-table-full th:nth-child(6) {
- width: 72px;
-}
-
-.data-table th {
- height: 34px;
- padding: 0 12px;
- color: var(--ink-faint);
- background: #fafbfc;
- border-bottom: 1px solid var(--line);
- text-align: left;
- font-size: 9px;
- font-weight: 600;
-}
-
-.data-table th:first-child {
- width: 37%;
- padding-left: 15px;
-}
-
-.data-table th:nth-last-child(1) {
- width: 150px;
-}
-
-.data-table td {
- height: 54px;
- padding: 7px 12px;
- border-bottom: 1px solid #edf0f2;
- font-size: 10px;
- vertical-align: middle;
-}
-
-.data-table tbody tr:hover,
-.data-table tbody tr.selected {
- background: #f5f9f8;
-}
-
-.data-table tbody tr:last-child td {
- border-bottom: 0;
-}
-
-.service-cell {
- min-width: 0;
- display: flex;
- align-items: center;
- gap: 9px;
-}
-
-.service-select {
- width: 100%;
- padding: 0;
- color: inherit;
- text-align: left;
- background: transparent;
- border: 0;
- cursor: pointer;
-}
-
-.service-glyph {
- flex: 0 0 auto;
- width: 28px;
- height: 28px;
- display: grid;
- place-items: center;
- color: #477164;
- background: #edf3f1;
- border-radius: 5px;
-}
-
-.service-cell > span:last-child {
- min-width: 0;
-}
-
-.service-cell strong,
-.service-cell small {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.service-cell strong {
- font-size: 11px;
-}
-
-.service-title {
- min-width: 0;
- display: flex;
- align-items: center;
- gap: 6px;
-}
-
-.service-title strong {
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.active-deployment-badge {
- flex: 0 0 auto;
- height: 17px;
- padding: 0 5px;
- display: inline-flex;
- align-items: center;
- gap: 3px;
- color: #176b4d;
- background: #e4f3ed;
- border: 1px solid #c5e4d8;
- border-radius: 9px;
- font-size: 7px;
- font-weight: 700;
-}
-
-.service-cell small {
- margin-top: 3px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.artifact-cell {
- overflow: hidden;
- color: var(--ink-soft);
- font-family: var(--font-geist-mono), monospace;
- font-size: 9px !important;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.capability-summary {
- max-width: 100%;
- height: 23px;
- padding: 0 7px;
- display: inline-flex;
- align-items: center;
- gap: 5px;
- color: #315f52;
- background: #edf5f2;
- border: 1px solid #d2e4de;
- border-radius: 4px;
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.capability-summary > span {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.capability-summary > small {
- flex: 0 0 auto;
- color: var(--ink-faint);
- font-size: 7px;
-}
-
-.capability-empty {
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.numeric-cell {
- color: var(--ink-soft);
- font-family: var(--font-geist-mono), monospace;
- white-space: nowrap;
-}
-
-.status-badge {
- width: fit-content;
- height: 22px;
- padding: 0 7px;
- display: inline-flex;
- align-items: center;
- gap: 5px;
- border-radius: 11px;
- font-size: 8px;
- font-weight: 600;
- white-space: nowrap;
-}
-
-.status-badge > span {
- width: 5px;
- height: 5px;
- border-radius: 50%;
-}
-
-.status-running {
- color: #126b4a;
- background: var(--green-bg);
-}
-
-.status-running > span {
- background: #20a675;
-}
-
-.status-stopped {
- color: #5e6870;
- background: #edf0f2;
-}
-
-.status-stopped > span {
- background: #87929a;
-}
-
-.status-faulted {
- color: #9e392b;
- background: var(--coral-bg);
-}
-
-.status-faulted > span {
- background: #c95645;
-}
-
-.row-actions {
- min-width: 128px;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 3px;
-}
-
-.row-actions button {
- width: 27px;
- height: 27px;
- padding: 0;
- display: grid;
- place-items: center;
- color: #68747d;
- background: transparent;
- border: 1px solid transparent;
- border-radius: 4px;
- cursor: pointer;
-}
-
-.row-actions button:hover:not(:disabled) {
- color: var(--ink);
- background: #fff;
- border-color: var(--line);
-}
-
-.row-actions .active-deployment-button:disabled {
- color: #197253;
- background: #e7f4ef;
- border-color: #c6e4d9;
- cursor: default;
- opacity: 1;
-}
-
-.event-list {
- padding: 4px 14px;
-}
-
-.event-row {
- min-height: 59px;
- padding: 10px 0;
- display: grid;
- grid-template-columns: 24px minmax(0, 1fr) auto;
- align-items: start;
- gap: 8px;
- border-bottom: 1px solid #edf0f2;
-}
-
-.event-row:last-child {
- border-bottom: 0;
-}
-
-.event-icon {
- width: 22px;
- height: 22px;
- display: grid;
- place-items: center;
- border-radius: 50%;
-}
-
-.event-success {
- color: var(--green);
- background: var(--green-bg);
-}
-
-.event-warning {
- color: var(--amber);
- background: var(--amber-bg);
-}
-
-.event-danger {
- color: var(--coral);
- background: var(--coral-bg);
-}
-
-.event-neutral {
- color: #69757e;
- background: #edf0f2;
-}
-
-.event-row strong,
-.event-row span {
- display: block;
-}
-
-.event-row strong {
- font-size: 9px;
- line-height: 14px;
-}
-
-.event-row div > span {
- margin-top: 3px;
- color: var(--ink-faint);
- font-size: 8px;
- line-height: 12px;
-}
-
-.event-row time {
- padding-top: 2px;
- color: var(--ink-faint);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.detail-strip {
- min-height: 72px;
- margin-top: 12px;
- padding: 11px 15px;
- display: grid;
- grid-template-columns: minmax(200px, 1.5fr) repeat(4, minmax(80px, 0.55fr)) auto;
- align-items: center;
- gap: 15px;
- background: var(--surface);
- border: 1px solid var(--line);
- border-radius: 6px;
-}
-
-.detail-identity,
-.instance-main {
- min-width: 0;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.artifact-icon {
- flex: 0 0 auto;
- width: 36px;
- height: 36px;
- display: grid;
- place-items: center;
- color: #356959;
- background: #e9f2ef;
- border-radius: 5px;
-}
-
-.detail-identity span,
-.detail-identity strong,
-.detail-value span,
-.detail-value strong {
- display: block;
-}
-
-.detail-identity > div:last-child {
- min-width: 0;
-}
-
-.detail-identity span,
-.detail-value span {
- margin-bottom: 4px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.detail-identity strong {
- overflow: hidden;
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.detail-identity small {
- margin-left: 3px;
- color: var(--ink-faint);
- font-family: var(--font-geist-mono), monospace;
- font-size: 9px;
-}
-
-.detail-value {
- min-width: 0;
- padding-left: 13px;
- border-left: 1px solid var(--line);
-}
-
-.detail-value strong {
- overflow: hidden;
- font-family: var(--font-geist-mono), monospace;
- font-size: 11px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.detail-actions {
- display: flex;
- justify-content: flex-end;
- gap: 7px;
-}
-
-.full-panel {
- min-height: 520px;
-}
-
-.filterbar {
- min-height: 56px;
- padding: 10px 14px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px solid var(--line);
-}
-
-.segmented {
- width: fit-content;
- display: inline-flex;
- padding: 2px;
- background: #eef1f3;
- border: 1px solid #e2e6e9;
- border-radius: 5px;
-}
-
-.segmented button {
- min-height: 26px;
- padding: 0 9px;
- color: var(--ink-soft);
- background: transparent;
- border: 0;
- border-radius: 3px;
- font-size: 9px;
- cursor: pointer;
-}
-
-.segmented button.active {
- color: var(--ink);
- background: #fff;
- box-shadow: 0 1px 3px rgba(24, 32, 39, 0.1);
-}
-
-.result-count {
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.registry-note {
- overflow: hidden;
- color: var(--ink-soft);
- font-size: 9px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.wit-package-table th:first-child {
- width: 28%;
-}
-
-.wit-package-table th:nth-child(2) {
- width: 34%;
-}
-
-.wit-package-table th:nth-child(3) {
- width: auto;
-}
-
-.wit-package-table th:last-child {
- width: 64px;
-}
-
-.wit-package-table .row-actions {
- min-width: 0;
-}
-
-.empty-state {
- min-height: 280px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- color: var(--ink-faint);
-}
-
-.empty-state strong {
- margin-top: 10px;
- color: var(--ink);
- font-size: 12px;
-}
-
-.empty-state span {
- margin-top: 4px;
- font-size: 9px;
-}
-
-.instance-list {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.instance-placeholder {
- min-height: clamp(280px, 48vh, 480px);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- color: var(--ink-faint);
- background: rgba(255, 255, 255, 0.36);
- border: 1px dashed #cfd8dd;
- border-radius: 6px;
-}
-
-.instance-placeholder-icon {
- width: 44px;
- height: 44px;
- display: grid;
- place-items: center;
- color: #71828b;
- background: #e9eef0;
- border: 1px solid #d9e1e5;
- border-radius: 6px;
-}
-
-.instance-placeholder strong {
- margin-top: 13px;
- color: var(--ink-soft);
- font-size: 12px;
-}
-
-.instance-placeholder span {
- margin-top: 5px;
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.instance-row {
- position: relative;
- min-height: 76px;
- padding: 13px 14px 13px 18px;
- display: grid;
- grid-template-columns: minmax(200px, 1.35fr) repeat(3, minmax(90px, 0.55fr)) minmax(
- 120px,
- 0.65fr
- ) 112px;
- align-items: center;
- gap: 14px;
- background: var(--surface);
- border: 1px solid var(--line);
- border-radius: 6px;
-}
-
-.instance-indicator {
- position: absolute;
- inset: 12px auto 12px 0;
- width: 3px;
- border-radius: 0 2px 2px 0;
-}
-
-.instance-indicator.running {
- background: #32a979;
-}
-
-.instance-indicator.faulted {
- background: #d25847;
-}
-
-.instance-main strong,
-.instance-main span,
-.instance-status > span:last-child {
- display: block;
-}
-
-.instance-main strong {
- font-size: 11px;
-}
-
-.instance-main span {
- margin-top: 4px;
- color: var(--ink-faint);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.instance-status > span:last-child {
- margin-top: 4px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.activity-summary {
- min-height: 78px;
- padding: 13px 18px;
- display: grid;
- grid-template-columns: repeat(4, 1fr);
- align-items: center;
- background: #fafbfc;
- border-bottom: 1px solid var(--line);
-}
-
-.activity-summary > div {
- padding-left: 18px;
- border-left: 1px solid var(--line);
-}
-
-.activity-summary > div:first-child {
- padding-left: 0;
- border-left: 0;
-}
-
-.activity-summary span,
-.activity-summary strong {
- display: block;
-}
-
-.activity-summary span {
- margin-bottom: 5px;
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.activity-summary strong {
- font-family: var(--font-geist-mono), monospace;
- font-size: 13px;
-}
-
-.settings-form {
- background: var(--surface);
- border: 1px solid var(--line);
- border-radius: 6px;
-}
-
-.settings-section {
- min-height: 126px;
- padding: 22px;
- display: grid;
- grid-template-columns: minmax(220px, 0.75fr) minmax(320px, 1.25fr);
- gap: 34px;
- border-bottom: 1px solid var(--line);
-}
-
-.settings-heading {
- display: flex;
- align-items: flex-start;
- gap: 10px;
- color: #41665a;
-}
-
-.settings-heading h2 {
- margin: 0;
- color: var(--ink);
- font-size: 12px;
-}
-
-.settings-heading p {
- margin: 4px 0 0;
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.settings-fields,
-.dialog-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 14px;
-}
-
-.form-field {
- min-width: 0;
-}
-
-.form-field label,
-.form-field > span {
- display: block;
-}
-
-.form-field label {
- margin-bottom: 6px;
- color: var(--ink-soft);
- font-size: 9px;
- font-weight: 600;
-}
-
-.form-field input,
-.code-field textarea {
- width: 100%;
- color: var(--ink);
- background: #fff;
- border: 1px solid var(--line-strong);
- border-radius: 4px;
-}
-
-.form-field input {
- height: 34px;
- padding: 0 10px;
- font-size: 10px;
-}
-
-.form-field input[readonly] {
- color: var(--ink-soft);
- background: #f6f7f8;
-}
-
-.form-field > span {
- margin-top: 5px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.wide-field {
- max-width: 520px;
-}
-
-.unit-input {
- display: grid;
- grid-template-columns: 1fr 42px;
-}
-
-.unit-input input {
- border-radius: 4px 0 0 4px;
-}
-
-.unit-input > span {
- display: grid;
- place-items: center;
- color: var(--ink-faint);
- background: #f3f5f6;
- border: 1px solid var(--line-strong);
- border-left: 0;
- border-radius: 0 4px 4px 0;
- font-size: 9px;
-}
-
-.danger-section .settings-heading {
- color: var(--coral);
-}
-
-.danger-section {
- align-items: center;
-}
-
-.danger-section .danger-button {
- width: fit-content;
-}
-
-.form-footer {
- min-height: 62px;
- padding: 14px 22px;
- display: flex;
- justify-content: flex-end;
-}
-
-.statusbar {
- min-width: 0;
- padding: 0 28px;
- display: flex;
- align-items: center;
- gap: 20px;
- color: #76828a;
- background: #eef1f3;
- border-top: 1px solid var(--line);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.statusbar span:first-child {
- display: flex;
- align-items: center;
- gap: 5px;
- color: #3c6b5b;
-}
-
-.dialog-backdrop {
- position: fixed;
- inset: 0;
- z-index: 50;
- display: grid;
- place-items: center;
- padding: 20px;
- background: rgba(13, 19, 23, 0.58);
-}
-
-.dialog {
- position: relative;
- width: min(620px, 100%);
- max-height: calc(100vh - 40px);
- margin: 0;
- padding: 0;
- overflow-y: auto;
- background: #fff;
- border: 1px solid #cfd6da;
- border-radius: 7px;
- box-shadow: var(--shadow);
-}
-
-.dialog-header {
- min-height: 72px;
- padding: 14px 16px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 20px;
- border-bottom: 1px solid var(--line);
-}
-
-.dialog-title {
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.dialog-title > span {
- width: 34px;
- height: 34px;
- display: grid;
- place-items: center;
- color: #316a57;
- background: #e9f3ef;
- border-radius: 5px;
-}
-
-.dialog-title h2 {
- margin: 0;
- font-size: 14px;
-}
-
-.dialog-title p {
- margin: 4px 0 0;
- color: var(--ink-faint);
- font-size: 9px;
-}
-
-.dialog-form {
- padding: 18px;
-}
-
-.form-error {
- margin-top: 12px;
- padding: 9px 10px;
- color: #963c30;
- background: var(--coral-bg);
- border: 1px solid #efc4bd;
- border-radius: 4px;
- font-size: 10px;
- line-height: 16px;
-}
-
-.upload-zone {
- height: 112px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- color: var(--ink-soft);
- background: #f8faf9;
- border: 1px dashed #aebdb7;
- border-radius: 5px;
- cursor: pointer;
-}
-
-.upload-zone:hover,
-.upload-zone.has-file {
- color: #286b54;
- background: #f1f8f5;
- border-color: #68a58f;
-}
-
-.upload-zone input {
- position: absolute;
- width: 1px;
- height: 1px;
- opacity: 0;
-}
-
-.upload-zone strong {
- margin-top: 8px;
- font-size: 10px;
-}
-
-.upload-zone span {
- margin-top: 3px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.dialog-grid {
- margin-top: 16px;
-}
-
-.dialog-footer {
- min-height: 60px;
- padding: 12px 16px;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 8px;
- background: #fafbfc;
- border-top: 1px solid var(--line);
-}
-
-.dialog-form .dialog-footer {
- margin: 18px -18px -18px;
-}
-
-.deployment-confirmation {
- padding: 18px;
-}
-
-.deployment-route {
- min-height: 72px;
- display: grid;
- grid-template-columns: minmax(0, 1fr) 24px minmax(0, 1fr);
- align-items: center;
- gap: 12px;
- border-top: 1px solid var(--line);
- border-bottom: 1px solid var(--line);
-}
-
-.deployment-route > svg {
- color: var(--ink-faint);
-}
-
-.deployment-route span,
-.deployment-route strong {
- display: block;
-}
-
-.deployment-route span {
- margin-bottom: 5px;
- color: var(--ink-faint);
- font-size: 8px;
-}
-
-.deployment-route strong {
- overflow: hidden;
- font-family: var(--font-geist-mono), monospace;
- font-size: 13px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.deployment-target {
- color: #176b4d;
-}
-
-.deployment-confirmation p {
- margin: 13px 0 0;
- color: var(--ink-soft);
- font-size: 9px;
- line-height: 16px;
-}
-
-.invoke-body {
- padding: 16px;
-}
-
-.invoke-toolbar {
- min-height: 36px;
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
-}
-
-.invoke-toolbar > span {
- color: var(--ink-faint);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.code-field > span,
-.invoke-output > div > span {
- display: block;
- margin-bottom: 6px;
- color: var(--ink-soft);
- font-size: 9px;
- font-weight: 600;
-}
-
-.code-field textarea {
- height: 116px;
- padding: 10px;
- resize: vertical;
- font-family: var(--font-geist-mono), monospace;
- font-size: 10px;
- line-height: 17px;
-}
-
-.invoke-output {
- margin-top: 14px;
-}
-
-.invoke-output > div {
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
-.invoke-output-meta {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.invoke-output-meta > span {
- color: var(--ink-faint);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.invoke-output small {
- display: flex;
- align-items: center;
- gap: 4px;
- color: var(--green);
- font-family: var(--font-geist-mono), monospace;
- font-size: 8px;
-}
-
-.invoke-output pre {
- min-height: 74px;
- margin: 0;
- padding: 10px;
- overflow: auto;
- color: #bdebd9;
- background: #182127;
- border: 1px solid #27353d;
- border-radius: 4px;
- font-family: var(--font-geist-mono), monospace;
- font-size: 10px;
- line-height: 17px;
- white-space: pre-wrap;
-}
-
-.invoke-output.failed pre {
- color: #ffd0c9;
- background: #2a1d1b;
- border-color: #57332e;
-}
-
-.toast {
- position: fixed;
- right: 22px;
- bottom: 42px;
- z-index: 70;
- min-width: 210px;
- min-height: 42px;
- padding: 10px 13px;
- display: flex;
- align-items: center;
- gap: 8px;
- color: #e9fff6;
- background: #1f3c32;
- border: 1px solid #426a5c;
- border-radius: 5px;
- box-shadow: var(--shadow);
- font-size: 10px;
-}
-
-.spin {
- animation: rotate 0.9s linear infinite;
-}
-
-@keyframes rotate {
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (max-width: 1180px) {
- .runtime-band {
- grid-template-columns: minmax(260px, 1.5fr) repeat(2, minmax(90px, 0.6fr));
- }
-
- .runtime-stat:nth-last-child(-n + 2) {
- display: none;
- }
-
- .overview-grid {
- grid-template-columns: 1fr;
- }
-
- .event-panel {
- min-height: 280px;
- }
-
- .detail-strip {
- grid-template-columns: minmax(190px, 1.4fr) repeat(2, 0.6fr) auto;
- }
-
- .detail-strip .detail-value:nth-of-type(3),
- .detail-strip .detail-value:nth-of-type(4) {
- display: none;
- }
-
- .instance-row {
- grid-template-columns: minmax(190px, 1.35fr) repeat(2, 0.6fr) minmax(110px, 0.65fr) 112px;
- }
-
- .instance-row > .detail-value:nth-of-type(3) {
- display: none;
- }
-}
-
-@media (max-width: 840px) {
- .app-shell {
- display: block;
- }
-
- .sidebar {
- position: sticky;
- top: 0;
- width: 100%;
- height: auto;
- padding: 9px 12px;
- display: grid;
- grid-template-columns: auto 1fr;
- align-items: center;
- border-right: 0;
- border-bottom: 1px solid #263139;
- }
-
- .brand {
- min-width: 158px;
- padding: 0;
- }
-
- .environment-switcher,
- .nav-label,
- .sidebar-runtime {
- display: none;
- }
-
- .primary-nav {
- min-width: 0;
- display: flex;
- flex-direction: row;
- justify-content: flex-end;
- overflow-x: auto;
- }
-
- .nav-item {
- width: 38px;
- min-width: 38px;
- height: 38px;
- padding: 0;
- display: grid;
- place-items: center;
- }
-
- .nav-item span {
- display: none;
- }
-
- .nav-item::before {
- inset: auto 8px -9px;
- width: auto;
- height: 2px;
- }
-
- .app-main {
- min-height: calc(100vh - 62px);
- display: grid;
- grid-template-rows: 50px 1fr 28px;
- }
-
- .topbar {
- padding: 0 16px;
- }
-
- .global-search {
- width: 190px;
- }
-
- .source-state {
- display: none;
- }
-
- .content {
- padding: 20px 16px;
- }
-
- .metric-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .runtime-band {
- grid-template-columns: 1fr 0.5fr;
- }
-
- .runtime-stat:nth-child(n + 3) {
- display: none;
- }
-
- .settings-section {
- grid-template-columns: 1fr;
- gap: 18px;
- }
-
- .instance-row {
- grid-template-columns: minmax(190px, 1fr) minmax(100px, 0.5fr) 104px;
- }
-
- .instance-row > .detail-value:nth-of-type(n + 2),
- .instance-status {
- display: none;
- }
-}
-
-@media (max-width: 560px) {
- .sidebar {
- grid-template-columns: 42px 1fr;
- }
-
- .brand {
- min-width: 0;
- }
-
- .brand > div:last-child {
- display: none;
- }
-
- .breadcrumb span,
- .breadcrumb svg {
- display: none;
- }
-
- .global-search {
- width: min(48vw, 190px);
- }
-
- .page-heading {
- align-items: flex-start;
- flex-direction: column;
- gap: 14px;
- }
-
- .heading-actions {
- width: 100%;
- }
-
- .heading-actions .primary-button {
- flex: 1;
- }
-
- .metric-grid {
- grid-template-columns: 1fr;
- }
-
- .metric {
- height: 78px;
- }
-
- .runtime-band {
- grid-template-columns: 1fr;
- }
-
- .runtime-stat {
- display: none !important;
- }
-
- .instance-placeholder {
- min-height: 260px;
- }
-
- .detail-strip {
- grid-template-columns: 1fr auto;
- }
-
- .detail-strip .detail-value {
- display: none;
- }
-
- .filterbar {
- align-items: flex-start;
- flex-direction: column;
- gap: 9px;
- }
-
- .segmented {
- max-width: 100%;
- overflow-x: auto;
- }
-
- .instance-row {
- grid-template-columns: minmax(150px, 1fr) 104px;
- }
-
- .instance-row > .detail-value {
- display: none;
- }
-
- .activity-summary {
- grid-template-columns: repeat(2, 1fr);
- gap: 14px 0;
- }
-
- .activity-summary > div:nth-child(3) {
- padding-left: 0;
- border-left: 0;
- }
-
- .settings-fields,
- .dialog-grid {
- grid-template-columns: 1fr;
- }
-
- .dialog-backdrop {
- padding: 10px;
- }
-
- .dialog {
- max-height: calc(100vh - 20px);
- }
-
- .statusbar {
- padding: 0 16px;
- }
-
- .statusbar span:not(:first-child) {
- display: none;
- }
-}
diff --git a/console/tests/rendered-html.test.mjs b/console/tests/rendered-html.test.mjs
deleted file mode 100644
index bd0fb0e..0000000
--- a/console/tests/rendered-html.test.mjs
+++ /dev/null
@@ -1,127 +0,0 @@
-import assert from "node:assert/strict";
-import { spawn } from "node:child_process";
-import { access, readFile } from "node:fs/promises";
-import { createServer } from "node:net";
-import { fileURLToPath } from "node:url";
-import test, { after, before } from "node:test";
-
-let serverProcess;
-let serverOrigin;
-
-async function reservePort() {
- const server = createServer();
- await new Promise((resolve, reject) => {
- server.once("error", reject);
- server.listen(0, "127.0.0.1", resolve);
- });
- const address = server.address();
- assert(address && typeof address === "object");
- await new Promise((resolve, reject) => {
- server.close((error) => (error ? reject(error) : resolve()));
- });
- return address.port;
-}
-
-before(async () => {
- const port = await reservePort();
- serverOrigin = `http://127.0.0.1:${port}`;
- serverProcess = spawn(
- process.execPath,
- [
- fileURLToPath(new URL("../node_modules/srvx/bin/srvx.mjs", import.meta.url)),
- "serve",
- "--prod",
- "--entry",
- "dist/server/server.js",
- "--static",
- "../client",
- ],
- {
- env: {
- ...process.env,
- HOST: "127.0.0.1",
- PORT: String(port),
- },
- stdio: ["ignore", "pipe", "pipe"],
- },
- );
-
- for (let attempt = 0; attempt < 50; attempt += 1) {
- if (serverProcess.exitCode !== null) {
- throw new Error(`Node server exited with code ${serverProcess.exitCode}`);
- }
- try {
- const response = await fetch(serverOrigin);
- if (response.ok) return;
- } catch {
- // The server is still starting.
- }
- await new Promise((resolve) => setTimeout(resolve, 100));
- }
- throw new Error("Node server did not become ready");
-});
-
-after(() => {
- serverProcess?.kill("SIGTERM");
-});
-
-test("server-renders the Wasm management console", async () => {
- const response = await fetch(serverOrigin, {
- headers: { accept: "text/html" },
- });
- assert.equal(response.status, 200);
- assert.match(response.headers.get("content-type") ?? "", /^text\/html\b/i);
-
- const html = await response.text();
- assert.match(html, /Wasmeld Console<\/title>/i);
- assert.match(html, /运行概览/);
- assert.match(html, /WIT 包/);
- assert.match(html, /连接中/);
- assert.match(html, /0 个对外服务/);
- assert.match(html, /Component Model/);
- assert.doesNotMatch(html, /本地演示|codex-preview|vinext|next\.js/i);
-});
-
-test("uses TanStack Start routing and produces Node artifacts", async () => {
- const [
- rootRoute,
- indexRoute,
- views,
- dialogs,
- consoleModel,
- apiClient,
- router,
- packageJson,
- viteConfig,
- ] = await Promise.all([
- readFile(new URL("../src/routes/__root.tsx", import.meta.url), "utf8"),
- readFile(new URL("../src/routes/index.tsx", import.meta.url), "utf8"),
- readFile(new URL("../src/components/views.tsx", import.meta.url), "utf8"),
- readFile(new URL("../src/components/dialogs.tsx", import.meta.url), "utf8"),
- readFile(new URL("../src/console-model.ts", import.meta.url), "utf8"),
- readFile(new URL("../src/api.ts", import.meta.url), "utf8"),
- readFile(new URL("../src/router.tsx", import.meta.url), "utf8"),
- readFile(new URL("../package.json", import.meta.url), "utf8"),
- readFile(new URL("../vite.config.ts", import.meta.url), "utf8"),
- ]);
-
- assert.match(rootRoute, /createRootRoute/);
- assert.match(rootRoute, //);
- assert.match(rootRoute, //);
- assert.match(indexRoute, /createFileRoute\("\/"\)/);
- assert.match(dialogs, /切换对外版本/);
- assert.match(views, /Host 能力/);
- assert.match(views, /service\.capabilities/);
- assert.match(consoleModel, /TextDecoder\("utf-8", \{ fatal: true \}\)/);
- assert.match(dialogs, /outputFormat\.automatic/);
- assert.match(apiClient, /\/api\/v1\/deployments/);
- assert.match(apiClient, /capabilities: BackendCapability\[\]/);
- assert.match(router, /createRouter/);
- assert.match(packageJson, /"@tanstack\/react-start"/);
- assert.match(packageJson, /"srvx"/);
- assert.doesNotMatch(packageJson, /"next"|"vinext"|"drizzle-orm"/);
- assert.match(viteConfig, /tanstackStart\(\{/);
-
- await access(new URL("../dist/server/server.js", import.meta.url));
- await access(new URL("../dist/client/og.png", import.meta.url));
-});
diff --git a/console/vite.config.ts b/console/vite.config.ts
deleted file mode 100644
index 7165a9c..0000000
--- a/console/vite.config.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { tanstackStart } from "@tanstack/react-start/plugin/vite";
-import viteReact from "@vitejs/plugin-react";
-import { defineConfig } from "vite";
-
-export default defineConfig({
- server: { port: 3000 },
- plugins: [
- tanstackStart({
- router: {
- routeTreeFileHeader: [
- "/* oxlint-disable */",
- "// @ts-nocheck",
- "// noinspection JSUnusedGlobalSymbols",
- ],
- },
- }),
- viteReact(),
- ],
-});
diff --git a/console/.gitignore b/crates/wasmeld-console/web/.gitignore
similarity index 85%
rename from console/.gitignore
rename to crates/wasmeld-console/web/.gitignore
index 1f5b167..1c019e8 100644
--- a/console/.gitignore
+++ b/crates/wasmeld-console/web/.gitignore
@@ -1,6 +1,5 @@
/node_modules/
/dist/
-/.tanstack/
*.tsbuildinfo
.env*
!.env.example
diff --git a/crates/wasmeld-console/web/.oxfmtrc.json b/crates/wasmeld-console/web/.oxfmtrc.json
new file mode 100644
index 0000000..04e09e4
--- /dev/null
+++ b/crates/wasmeld-console/web/.oxfmtrc.json
@@ -0,0 +1,8 @@
+{
+ "printWidth": 100,
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "singleQuote": false,
+ "trailingComma": "all"
+}
diff --git a/crates/wasmeld-console/web/.oxlintrc.json b/crates/wasmeld-console/web/.oxlintrc.json
new file mode 100644
index 0000000..ac5d4d9
--- /dev/null
+++ b/crates/wasmeld-console/web/.oxlintrc.json
@@ -0,0 +1,12 @@
+{
+ "plugins": ["typescript"],
+ "categories": {
+ "correctness": "error",
+ "suspicious": "warn"
+ },
+ "rules": {
+ "typescript/no-explicit-any": "error",
+ "no-console": "warn"
+ },
+ "ignorePatterns": ["dist/**", "node_modules/**"]
+}
diff --git a/crates/wasmeld-console/web/index.html b/crates/wasmeld-console/web/index.html
new file mode 100644
index 0000000..6606241
--- /dev/null
+++ b/crates/wasmeld-console/web/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+ Wasmeld Console
+
+
+
+
+
+
diff --git a/console/package-lock.json b/crates/wasmeld-console/web/package-lock.json
similarity index 58%
rename from console/package-lock.json
rename to crates/wasmeld-console/web/package-lock.json
index 53d08f2..4fccf20 100644
--- a/console/package-lock.json
+++ b/crates/wasmeld-console/web/package-lock.json
@@ -1,41 +1,38 @@
{
- "name": "wasmeld-console",
+ "name": "wasmeld-console-web",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "wasmeld-console",
+ "name": "wasmeld-console-web",
"version": "0.1.0",
"dependencies": {
- "@tanstack/react-router": "^1.170.18",
- "@tanstack/react-start": "^1.168.32",
- "lucide-react": "^1.27.0",
- "react": "19.2.6",
- "react-dom": "19.2.6",
- "srvx": "^0.12.4"
+ "lucide-solid": "1.27.0",
+ "solid-js": "1.9.14"
},
"devDependencies": {
- "@types/node": "22.19.19",
- "@types/react": "19.2.14",
- "@types/react-dom": "19.2.3",
- "@vitejs/plugin-react": "6.0.2",
- "oxfmt": "^0.60.0",
- "oxlint": "^1.75.0",
- "typescript": "5.9.3",
- "vite": "^8.1.5"
+ "@tailwindcss/vite": "4.3.3",
+ "@types/node": "24.10.1",
+ "oxfmt": "0.61.0",
+ "oxlint": "1.76.0",
+ "tailwindcss": "4.3.3",
+ "typescript": "7.0.2",
+ "vite": "8.1.5",
+ "vite-plugin-solid": "2.11.14"
},
"engines": {
"node": ">=22.13.0"
}
},
"node_modules/@babel/code-frame": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
- "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.29.7",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
@@ -47,6 +44,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -56,6 +54,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -82,24 +81,11 @@
"url": "https://opencollective.com/babel"
}
},
- "node_modules/@babel/core/node_modules/@babel/code-frame": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
- "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.29.7",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.1.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/generator": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.7",
@@ -116,6 +102,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.29.7",
@@ -132,6 +119,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -141,6 +129,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.29.7",
@@ -154,6 +143,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.29.7",
@@ -167,10 +157,21 @@
"@babel/core": "^7.0.0"
}
},
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -180,6 +181,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -189,6 +191,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -198,6 +201,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.29.7",
@@ -211,6 +215,7 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.7"
@@ -222,10 +227,27 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -236,24 +258,11 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/template/node_modules/@babel/code-frame": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
- "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.29.7",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.1.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/traverse": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.7",
@@ -268,24 +277,11 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/traverse/node_modules/@babel/code-frame": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
- "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.29.7",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.1.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/types": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.29.7",
@@ -296,21 +292,32 @@
}
},
"node_modules/@emnapi/core": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
- "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
+ "version": "2.0.0-alpha.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz",
+ "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "2.0.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz",
+ "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
- "@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
- "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
+ "version": "2.0.0-alpha.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz",
+ "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -333,6 +340,7 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
@@ -343,6 +351,7 @@
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -353,6 +362,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -362,12 +372,14 @@
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -375,86 +387,41 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
- "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.0.tgz",
+ "integrity": "sha512-kDoONqMa+VnZ4vvvu/ZUurpJ4gkZU57e7g69qpNgWhYcZFPUHZM2CEMKm+cG6ufDVALbjMvfmMjFVqaK7uEMnA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@tybys/wasm-util": "^0.10.3"
},
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=23.5.0"
+ },
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"peerDependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1"
- }
- },
- "node_modules/@oozcitak/dom": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz",
- "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==",
- "license": "MIT",
- "dependencies": {
- "@oozcitak/infra": "^2.0.2",
- "@oozcitak/url": "^3.0.0",
- "@oozcitak/util": "^10.0.0"
- },
- "engines": {
- "node": ">=20.0"
- }
- },
- "node_modules/@oozcitak/infra": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz",
- "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==",
- "license": "MIT",
- "dependencies": {
- "@oozcitak/util": "^10.0.0"
- },
- "engines": {
- "node": ">=20.0"
- }
- },
- "node_modules/@oozcitak/url": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz",
- "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==",
- "license": "MIT",
- "dependencies": {
- "@oozcitak/infra": "^2.0.2",
- "@oozcitak/util": "^10.0.0"
- },
- "engines": {
- "node": ">=20.0"
- }
- },
- "node_modules/@oozcitak/util": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz",
- "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==",
- "license": "MIT",
- "engines": {
- "node": ">=20.0"
+ "@emnapi/core": "^2.0.0-alpha.3",
+ "@emnapi/runtime": "^2.0.0-alpha.3"
}
},
"node_modules/@oxc-project/types": {
"version": "0.139.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz",
"integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Boshen"
}
},
"node_modules/@oxfmt/binding-android-arm-eabi": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.60.0.tgz",
- "integrity": "sha512-1q4q4Jc8FlOMVojEisyFAVyl8h1yawNv6phjgmhGVEDeyeOdsSnSr9x0+D4mOnEKvpO5L4mxKZ/DP9X6U3A/Mw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.61.0.tgz",
+ "integrity": "sha512-BaS+1OVvg9sr+Xav0+KdWedQRcAzrdoEcwMZeqoc2F6ieC1s/t5eM35YQoRPQ7vAqkZ+p3tbQb1r9I9mrV5oGA==",
"cpu": [
"arm"
],
@@ -469,9 +436,9 @@
}
},
"node_modules/@oxfmt/binding-android-arm64": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.60.0.tgz",
- "integrity": "sha512-tD41I6nCt9k8SQXft0CSjjU9jg6SwG7uMu7PxodSEHXl+GDW0868oy6tTtoJkyUze8YKFgTpz/k5LuPUnFiGLw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.61.0.tgz",
+ "integrity": "sha512-of8atAV0M1egGcVOMbgZCvc10sFOP3ayQBNQV5h5G3fNq8gACdEswfFk9bzGrdbM23rtg0Coxi7np7oPLcueNw==",
"cpu": [
"arm64"
],
@@ -486,9 +453,9 @@
}
},
"node_modules/@oxfmt/binding-darwin-arm64": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.60.0.tgz",
- "integrity": "sha512-TTpzPug96Zxdyb46KvTyIUQDdsqbumXh2TKG9C23PCT0kF7JkW56Z/quPuG9rqOFKQIi1gpRNZ7DX18LwxXPnw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.61.0.tgz",
+ "integrity": "sha512-7l8+5ov4BGwtAcmpzvEik/TG3bciwyw/S3e6j5GKH7pcQqcgCVxD3AuJeP6upto+SOTBKQ4wrrdbMt0gq8fHSQ==",
"cpu": [
"arm64"
],
@@ -503,9 +470,9 @@
}
},
"node_modules/@oxfmt/binding-darwin-x64": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.60.0.tgz",
- "integrity": "sha512-CnOoWgQ7L+JL/YQaRJ+NyATciSfcftncm7y3kqyte1cGtFEGnStaCd1TAyrinkfQ7nRBfHrTs1/vTwUJr3WF2Q==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.61.0.tgz",
+ "integrity": "sha512-Fnz4dDDXBb7udk+DmwelNjxbD6yptyxwCqwCH2ebo4RVLxVsRfFsn/AHJC49KIltPrVokamGv4SSOsiV50DTxQ==",
"cpu": [
"x64"
],
@@ -520,9 +487,9 @@
}
},
"node_modules/@oxfmt/binding-freebsd-x64": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.60.0.tgz",
- "integrity": "sha512-ychJo7S3hZxdO6eDZ9zM6F2lM9fpJS3EKS5CAUSWyprdLYxTu4gbaUKV/VBPTcMJwQa2Bpo+643y3OJ537pihA==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.61.0.tgz",
+ "integrity": "sha512-mddOebKNCP+AucmzfNsk3jgbr681qAUvgMqi865GW5gWLJ/AnzXbvjQRrny0e++NAN8aphav/aRSrfFxNsNjpA==",
"cpu": [
"x64"
],
@@ -537,9 +504,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm-gnueabihf": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.60.0.tgz",
- "integrity": "sha512-36IH5o55T2Fx7E0feDttt+mifxN6yk9pWv4KfhAIsP0dFnUq27331OwbpOsZdoXF9soOLWm7mQUz5+UUmyec4g==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.61.0.tgz",
+ "integrity": "sha512-svx59iYL+DbaZGZUIoice4W0CjRXGExnbz7Re+awIb60rVxBS2KrU7Hnlx+nZYanLGLpjneUEgo/VFEKkSZAyQ==",
"cpu": [
"arm"
],
@@ -554,9 +521,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm-musleabihf": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.60.0.tgz",
- "integrity": "sha512-G1Ve7lAa6sFBolVI2LWHfEAqy0YKh4vnioH8uYO9kAEdgM7mR40IksIx9/Zk4+vbYew/sGa4J9Q4tZ3n9gXDHA==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.61.0.tgz",
+ "integrity": "sha512-BYK9MPJPCf6d+fLKMTruThmEyCtHzQ1zLcsrTlUVkmnoXIaHAbfpeLYQwX1tkjs7W11dyzoi6HFvKcdnvX1zNg==",
"cpu": [
"arm"
],
@@ -571,13 +538,16 @@
}
},
"node_modules/@oxfmt/binding-linux-arm64-gnu": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.60.0.tgz",
- "integrity": "sha512-LTQdRBf6uzj/h7Xk6lKzbGD2hrF/fK4YI9LIN1c0509tPUn8wRa3mCmrFQpEWJPLYGFrLFFMTYW1Ljj6VqW2Hw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.61.0.tgz",
+ "integrity": "sha512-QUaCNLq2/EC6G5ljOuFanl9Lgw6ZWp4co7rs4+KOMUzbGfA4Lq58FHRjjF9sVIG+93XSbo343MxFATrOU1qctA==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -588,13 +558,16 @@
}
},
"node_modules/@oxfmt/binding-linux-arm64-musl": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.60.0.tgz",
- "integrity": "sha512-2JMo3XPxMPx3hiqddSZYyaH+fKJm6cz0u8n1naYjP/CdOQOZW34i8lKBUfmbWiuFvd6KoYXLmhAyBuvojsYS7Q==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.61.0.tgz",
+ "integrity": "sha512-S6uvJ6MXnRXl+zTs0CARNDvkE+cymj0EVWEKKsyKnlLlqTyQJBjw5s4D2pSIOZc+S46cy4STefzcr/sm0VzVPA==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -605,13 +578,16 @@
}
},
"node_modules/@oxfmt/binding-linux-ppc64-gnu": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.60.0.tgz",
- "integrity": "sha512-L3C+nBD13lr306tr/PjM3RMll+BVqgFrIgUyoeHuai5oueJrRLgO3j+GO5/Cbhtkf5PSlHYTI1JY7iqBd1qa6A==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.61.0.tgz",
+ "integrity": "sha512-6VDlRcytvZG6UlSIdAFKDLbppo9tvPxrWzle6vHldYFMeuDPQEfMKrkwezp7FaBq1wik9ra554ZZeRPsyIkFpg==",
"cpu": [
"ppc64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -622,13 +598,16 @@
}
},
"node_modules/@oxfmt/binding-linux-riscv64-gnu": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.60.0.tgz",
- "integrity": "sha512-M4MsmvqlxFiPtSRGyBYQSZxchEf463AOyd+Dh4/9xDpjWBsRtDUTDMFN5EdHinjVK1/eDJQ8MLpcYjpYayaCnA==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.61.0.tgz",
+ "integrity": "sha512-KkBTYbzExpbmn15XjKPLu2fRV2PVlq+KWt+brad5rwIa03vdYoaDRWiS7raHII/dCTR6Ro4UpYUCH4t6lif4WQ==",
"cpu": [
"riscv64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -639,13 +618,16 @@
}
},
"node_modules/@oxfmt/binding-linux-riscv64-musl": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.60.0.tgz",
- "integrity": "sha512-OH+9UskYuxRB+GxqdGkVN8f5UpwhqG8YscNo1wl8+KJ62cd7wZdGga6iGLJIf8kibF1WBwvlfDUx3cez/VXwFg==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.61.0.tgz",
+ "integrity": "sha512-69tzIq7sJLVB9dxYYtvMzcSSsnZHSO+U2U19O2RqDqgj6+Q4O7HjSXdaszbcgqzhsUwzSH7z5kWvk8nmf6BHTg==",
"cpu": [
"riscv64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -656,13 +638,16 @@
}
},
"node_modules/@oxfmt/binding-linux-s390x-gnu": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.60.0.tgz",
- "integrity": "sha512-y7AAFutt9wFWBFOAn6+BHaV39usZmcr3YYH2385f+NHgPNpIF9HpqKp0jgUxPaUOCyG3oaX5VhJduL1Nw164rw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.61.0.tgz",
+ "integrity": "sha512-Oqi/N0OvtOVXsPKAOOhKgGH3msRYF8BLJaNBbWiupRiKoKVyc8JRKPCfarkQJC+RgP9U8raUKLe+bNwd0HUMiA==",
"cpu": [
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -673,13 +658,16 @@
}
},
"node_modules/@oxfmt/binding-linux-x64-gnu": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.60.0.tgz",
- "integrity": "sha512-yKZ9+CXAI+1RO5nH/4Z/9M6DAsfOzd5bw/gtWk81KB4mpalMaRRSXfouc5/tHxazDmBek55HNPepNYBgaCew0Q==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.61.0.tgz",
+ "integrity": "sha512-3TKwv/ed4uwJSemAA8P9XcoqETpjQI4waquF9UilhA9Mn/dhr1PdUEXWlL74mtc6ZNfmKPA9+NEJm01nRF8CVA==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -690,13 +678,16 @@
}
},
"node_modules/@oxfmt/binding-linux-x64-musl": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.60.0.tgz",
- "integrity": "sha512-bCUGaF6hJOYnQzLJdHLZbvGsOd5oSvGAyJhPAKum2uyLYUuXmP8vqg690DWi2hqcnIoYpqSqCrjzE5aiUAgwQg==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.61.0.tgz",
+ "integrity": "sha512-uFso4u4nLkVSlMCpgjyvWV60Gt7GvDQHnk1mmRxHIkZTMB0ljpUKwCD9FYGgN9H97x2wYl0UwEjgRZaPIuhEhw==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -707,9 +698,9 @@
}
},
"node_modules/@oxfmt/binding-openharmony-arm64": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.60.0.tgz",
- "integrity": "sha512-GrUeZOvzP30ExxfCuQiyofuUGI+OmvAgFwOO5w5p9mGPlxcyuqI+6Sy9fAKFFfLQrqKYWFgc5sYA2Unj/29nPg==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.61.0.tgz",
+ "integrity": "sha512-keGLkzeOvkMpNmPp4hffXWpfoSsY6e1K8++KXD4mSSfxdvM8q9QUDsYY689TB1k6Co832DZn1MnaaVx6cIBMWQ==",
"cpu": [
"arm64"
],
@@ -724,9 +715,9 @@
}
},
"node_modules/@oxfmt/binding-win32-arm64-msvc": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.60.0.tgz",
- "integrity": "sha512-WD4Q954kUl2TDJV/6q7UnE2rlKk047kXLJsr4bJ2mXRaAqNXcmV3nwKUsGCc3mz/jYDBnXtJEaBErJEybK8iQQ==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.61.0.tgz",
+ "integrity": "sha512-VzsAISkFxmNhJ5LBDEL9VuH6tJsVJMtqYit2LyIUf/HLnsCe4Pg9SMOjjVQzGWt0bnpyfJ94CrqTqcpNZzK+ug==",
"cpu": [
"arm64"
],
@@ -741,9 +732,9 @@
}
},
"node_modules/@oxfmt/binding-win32-ia32-msvc": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.60.0.tgz",
- "integrity": "sha512-HqDekjr8JXzVDUP1YthDZ1Y3CBEcuZT4WX3B+1kaxj8CvZA8Y2YhcEsXqoSop3tVsgjACxjnFQFDkBo0r/jq1Q==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.61.0.tgz",
+ "integrity": "sha512-xv4t7yzwJoYaLB6Zv28B3W+j7brEjsyv50rLTAQgmxJzddce9fAMCxed8dSAkbWES0zz2J29nYK5FaTuD2YBHg==",
"cpu": [
"ia32"
],
@@ -758,9 +749,9 @@
}
},
"node_modules/@oxfmt/binding-win32-x64-msvc": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.60.0.tgz",
- "integrity": "sha512-tz78yhmGPKboTMHCHSaUqXK8JrmoSejgDcWeqAtg2s07ZGKQ3rH5Jn8NuXPGNG33CDbY2e9NoQWXIVEmKO21Rw==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.61.0.tgz",
+ "integrity": "sha512-6EZXFkqOwxdDYjIn3TSNnPk3ST5E5GiYd4FiM6UF/mCL/LZSfr6D6UygTfW3R1PCQP2quCKpCEGRlij8E3VYbg==",
"cpu": [
"x64"
],
@@ -775,9 +766,9 @@
}
},
"node_modules/@oxlint/binding-android-arm-eabi": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.75.0.tgz",
- "integrity": "sha512-lutovtFzJqlRaqpZrCqSSGaHZzl9nIxxpjLzhSRLunN6dCLylj0uzlCyQGaQDIys7rrv8kVXiFO+R4Zpn0bX7g==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.76.0.tgz",
+ "integrity": "sha512-ZHIE5Zt9AsPDcY4nOlofXt0YfneEeo+QrKMPcPzLf2Z6Q8VtV2W73d7SFJ920WUwyik783u/doKCs3KXdwG+7w==",
"cpu": [
"arm"
],
@@ -792,9 +783,9 @@
}
},
"node_modules/@oxlint/binding-android-arm64": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.75.0.tgz",
- "integrity": "sha512-hXI0hDgHkw4w5nfru72aG7y+2iQJmC4waH/KV6H/hbgA6yAP5jYNx0P9yug15Hs0tWl/+mda3Jjn/2gmDT48tw==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.76.0.tgz",
+ "integrity": "sha512-shm/ngQilHK6bs+ElJWa4oHfNj5vL1Gl/iVEJldTQjpr0/67oSgr0KUpbmcnLig5Fo0v/l6j2567A7TOL89ONA==",
"cpu": [
"arm64"
],
@@ -809,9 +800,9 @@
}
},
"node_modules/@oxlint/binding-darwin-arm64": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.75.0.tgz",
- "integrity": "sha512-D91BWbK/dMYfCcrghspPIuKs2D9LF4Z/OabVSQjw1AO6PWxArD7teDA48bm0ySFqWDaPVqmQRl5GMWNglTXyrQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.76.0.tgz",
+ "integrity": "sha512-rvJmrAPKSQ9aWJ6wIS6CK2tJjwzfW0ApQH9qokq6sfDvmHwoyIHxHFMq7z7i7GiV6fdE6s8qvBqWKPTu8RmT6Q==",
"cpu": [
"arm64"
],
@@ -826,9 +817,9 @@
}
},
"node_modules/@oxlint/binding-darwin-x64": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.75.0.tgz",
- "integrity": "sha512-02mpwzf12BonZ6PT0TuQoomvEh2kVl2WGBIKWezCyToIS+rYkQZ6GXnARBAl9A4Ovm2V+Xe7M4KretyqmmcnJQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.76.0.tgz",
+ "integrity": "sha512-U/zYdb7VYKGY6pA9Vd2rYl9O/HlCylcOlb5PGPvVLtg+oLGsk6H3XGKEMHKyqD3nmmtmlmwb/8SwU2vfSAtvMw==",
"cpu": [
"x64"
],
@@ -843,9 +834,9 @@
}
},
"node_modules/@oxlint/binding-freebsd-x64": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.75.0.tgz",
- "integrity": "sha512-qZJgLnDaBsiL5YESx2t/TZ8eXkL9fEkKoXEdzegROhlz9A0lgyGnZ0dAzJrh7LJAHQl2K9RdRueN2s/9N7+odg==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.76.0.tgz",
+ "integrity": "sha512-WvKG9CAriuo0XNiFzpXjDngUZcRGFNpaK2kLyMUsnJlShxkT96u+BpJQ3KqdQwGOrvI14L6V8bAwXwAYNNY6Jg==",
"cpu": [
"x64"
],
@@ -860,9 +851,9 @@
}
},
"node_modules/@oxlint/binding-linux-arm-gnueabihf": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.75.0.tgz",
- "integrity": "sha512-7XlaWA5BJD3XpCfrEqjEe6Zseeb14S7QGa304XfwKignRaKQ+eIj775BQ7nIslggWickl4IsPUFqJ+/gAyNHVg==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.76.0.tgz",
+ "integrity": "sha512-qJ5+RH99TqFRq3UCDxkW0zJJu9c+OAHFY72vGlxZLEpuO+MpKo3POgqb8sYipL9KYm8XY6ofb0HsOuvY6hQNqQ==",
"cpu": [
"arm"
],
@@ -877,9 +868,9 @@
}
},
"node_modules/@oxlint/binding-linux-arm-musleabihf": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.75.0.tgz",
- "integrity": "sha512-av6Tpv8yrcMMMOadOqENBhlsLRcGFXXwoQ0hzHhsmS9FJ4Wioy8we427GbcMe2XTxmL2e60T67H1Dyr3up+tAA==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.76.0.tgz",
+ "integrity": "sha512-PvPCVptkgVARsucgIqFQQcSmJ6xc6GtnVB5bRBekRahTc9eObMtjHfMjy5M+C2tHt5UCMttWM9RuSk/H9NqYeg==",
"cpu": [
"arm"
],
@@ -894,13 +885,16 @@
}
},
"node_modules/@oxlint/binding-linux-arm64-gnu": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.75.0.tgz",
- "integrity": "sha512-WcUhd8fHT5plrA14lANevl+hOl815mVI5t2hU21oFWrZKFXIVV/Sr4rWQV0NzSvzBupbMLNc5ErEA6Ehxh5jMg==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.76.0.tgz",
+ "integrity": "sha512-3KeFDx8Bu4HPAXbuHZOr/oHvN+QT+JQhMw/NYPz7Z071xLSsG27Jfh9PIQVEY7hk1I+jr43ExqRIeJ6VKk2yLw==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -911,13 +905,16 @@
}
},
"node_modules/@oxlint/binding-linux-arm64-musl": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.75.0.tgz",
- "integrity": "sha512-UWzp5wRHFe/ESO3+eEaxXsTkYTGLYjnTsi/I5neEacXSItQ6WNleapfOAeA4x2b8nyhJ4uQxqvtv9pHv8kWJtQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.76.0.tgz",
+ "integrity": "sha512-oPFkkKTgl0K/EIg9fQ8oA3IGcI05/Mq1en04iFa41mmNPT+6KEiByVazTOZZJiHMBBrbsns1YJ2e1Scqwzesjw==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -928,13 +925,16 @@
}
},
"node_modules/@oxlint/binding-linux-ppc64-gnu": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.75.0.tgz",
- "integrity": "sha512-XEVRwGMLKCUKrvhLAz4F6AIh8MJrQVdSZtAmPpRZt9tGPsUnamPOcl3dS/ZQzJnar/Ymgc//+xho0L60Emzuxg==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.76.0.tgz",
+ "integrity": "sha512-gN7yZ0eqflA5Fhf1wvHxGUltIV3FsvmB1zhNMDEK9vSHhc7E6qg9CuPeBgPZab66Tjzq6w6kHAtNEvnTHf4cyw==",
"cpu": [
"ppc64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -945,13 +945,16 @@
}
},
"node_modules/@oxlint/binding-linux-riscv64-gnu": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.75.0.tgz",
- "integrity": "sha512-mAG4DUXqfLC8cTjMD2kt3jDmVzFREYtDyeLNdLdsCcBc4Zbl2EMuiFektGBilQwkNjYnMvCqJs55U+Hyb+b+jw==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.76.0.tgz",
+ "integrity": "sha512-S/HqMbn22mQrjtErUxEoS/a55u8kIeXvreIxiJu5G7Le3UecEd6SQZxrDIpuhtgaFnsY/nVra3ytP+pRljDilA==",
"cpu": [
"riscv64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -962,13 +965,16 @@
}
},
"node_modules/@oxlint/binding-linux-riscv64-musl": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.75.0.tgz",
- "integrity": "sha512-95hrAvriAlI+pekSomTFIn0+bawMDlDwTNVmdjsFusTHyL2JWh7TWvRNG/Lkim72uN8OiCcO9wcaC6omLP5E3w==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.76.0.tgz",
+ "integrity": "sha512-ZIga3097VJZolGZk6SrIAUokIGfRkxRlhiHDUznZptGBfwrhD7pNfD1rzEzsCwvk/1DX0A1bLz+liuNh5QKIVQ==",
"cpu": [
"riscv64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -979,13 +985,16 @@
}
},
"node_modules/@oxlint/binding-linux-s390x-gnu": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.75.0.tgz",
- "integrity": "sha512-4b6f2+FrtruAESrCqIKcrarzfrSx+wk2QNcp+RT91/Prc+pMQMAfyZ1rG1c3tFQNl8Bc616tx40uNXyxNBRPbQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.76.0.tgz",
+ "integrity": "sha512-ZGiiA7pFzMJSyMWYZTVlPgbTsx+Vl8ihLGMIujPwaslUF7kIPPWAbVmAlTc+9lWDV+DCiB8Ikixu+lSHeOIIWQ==",
"cpu": [
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -996,13 +1005,16 @@
}
},
"node_modules/@oxlint/binding-linux-x64-gnu": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.75.0.tgz",
- "integrity": "sha512-nshAhrUvXFUWOvqQ2soIw7HFNWvpvEV4o0cYSqPtzLiPF5gKyYTDOOTJ6Rn8g8K/iGvPIrbDA4v8+5MvnjJrrg==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.76.0.tgz",
+ "integrity": "sha512-JLiy5WuvEBFTT6ErIFV35SLzi0R7Iri6MKU6dZbTxfIx8pndbbPs3Mj780nMipBFcPkti+okAPOJ9POKkHFEgg==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1013,13 +1025,16 @@
}
},
"node_modules/@oxlint/binding-linux-x64-musl": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.75.0.tgz",
- "integrity": "sha512-e4jNxLKnxLC6sYBQRxrI2pgIIxnmMtF8U/VwNYcjTT/CLS+spH624cYVnj07bTKwaEWT37/e025isOs6j/0xqA==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.76.0.tgz",
+ "integrity": "sha512-z7lgKQtbo/I1NIe8G5NHLesxJDv0tRSUWTpXKb9Pm3E9nKFKfO4IOSDtFroKgXtOYb0jQbcdH+0wzTyMXVes+A==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1030,9 +1045,9 @@
}
},
"node_modules/@oxlint/binding-openharmony-arm64": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.75.0.tgz",
- "integrity": "sha512-hZ2lH+1qLf/DiEP9UWuQTK2JWj/BgvMB4jhIV4SmNU1wfEiYYX4TynQyAZXx0j9X4qRYizAL042SKaV+8ynh4w==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.76.0.tgz",
+ "integrity": "sha512-JOjKymIpb9QcYfEhZsN6h4V9Ivd474W38cNIBRv6bg2TbIvogbMTH0Mg6YWW9TiRDqfcX+/Hyfsbo5vcSE5guQ==",
"cpu": [
"arm64"
],
@@ -1047,9 +1062,9 @@
}
},
"node_modules/@oxlint/binding-win32-arm64-msvc": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.75.0.tgz",
- "integrity": "sha512-Ilj6PNzGDS3bCU0MSJH7Msh0NhH+T/mRp2shwg+q+GHeVlPwP5LEboW96aW+3kVKFk6zYZy1Xi5pZkqZh6X8KQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.76.0.tgz",
+ "integrity": "sha512-pqDWZiwcmByWUEm1NFUBNiT6aentCcaoMWJv0HbXEmuYermJ4sg8ppVrshubYP2MZ6SHccJJcpr6x469PuDFIw==",
"cpu": [
"arm64"
],
@@ -1064,9 +1079,9 @@
}
},
"node_modules/@oxlint/binding-win32-ia32-msvc": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.75.0.tgz",
- "integrity": "sha512-QVit2nOEOiPhkmsrksPSkoGCdnZRNkspt8fwoYyP09te1VEbnSj4LAxua4rc8FKTmWkySVe05j8iz9GXYfF1AQ==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.76.0.tgz",
+ "integrity": "sha512-Ba0O659kgMv6pwO3z9PdO+K3aMxQRaw9HnG+e6AtOfgwcKFvYilciQYBoUBmxfQvOCKZe1SwjMkuB542NkuDMQ==",
"cpu": [
"ia32"
],
@@ -1081,9 +1096,9 @@
}
},
"node_modules/@oxlint/binding-win32-x64-msvc": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.75.0.tgz",
- "integrity": "sha512-DSxnNkBUAYARPwJtR12Ig3deWr8w0H997xP6jy33i+e0SyYJw8FKuz4+cZtpmPEhQmvlPJE3X/2vNxDmLkd/rA==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.76.0.tgz",
+ "integrity": "sha512-5qcirPHO8nKfkoowEVWtpAoVTcYDy6g0UT0NGic450Qv8J2NrOqg4uQ8QppRP4MDTC7Xx47lbZnmadTH03CGGA==",
"cpu": [
"x64"
],
@@ -1190,6 +1205,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1207,6 +1225,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1224,6 +1245,9 @@
"ppc64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1241,6 +1265,9 @@
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1258,6 +1285,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1275,6 +1305,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
@@ -1320,6 +1353,29 @@
"node": "^20.19.0 || >=22.12.0"
}
},
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
+ "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
+ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz",
@@ -1358,462 +1414,291 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
- "devOptional": true,
+ "dev": true,
"license": "MIT"
},
- "node_modules/@tanstack/history": {
- "version": "1.162.0",
- "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.162.0.tgz",
- "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==",
- "license": "MIT",
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/react-router": {
- "version": "1.170.18",
- "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.18.tgz",
- "integrity": "sha512-wpbGYZEp/fmz1q4bn7BD8VZ+/VZ7GBqSJv5V969pU+chP8y7dquWDmKTFMohvUegb9lg12m1uPVvD6kB2wORvQ==",
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@tanstack/history": "1.162.0",
- "@tanstack/react-store": "^0.9.3",
- "@tanstack/router-core": "1.171.15",
- "isbot": "^5.1.22"
- },
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=18.0.0 || >=19.0.0",
- "react-dom": ">=18.0.0 || >=19.0.0"
- }
- },
- "node_modules/@tanstack/react-start": {
- "version": "1.168.32",
- "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.168.32.tgz",
- "integrity": "sha512-y1WXHo+jPfHxiuuN1m+br06IcriiBQnEWryBdbKdEOS5vw2PmnOj+Cgf1/YcGOqtSougScWFeE2rL1FXWvsLLg==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/react-router": "1.170.18",
- "@tanstack/react-start-client": "1.168.16",
- "@tanstack/react-start-rsc": "0.1.31",
- "@tanstack/react-start-server": "1.167.22",
- "@tanstack/router-utils": "1.162.2",
- "@tanstack/start-client-core": "1.170.14",
- "@tanstack/start-plugin-core": "1.171.24",
- "@tanstack/start-server-core": "1.169.17",
- "pathe": "^2.0.3"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "@rsbuild/core": "^2.0.0",
- "react": ">=18.0.0 || >=19.0.0",
- "react-dom": ">=18.0.0 || >=19.0.0",
- "vite": ">=7.0.0"
- },
- "peerDependenciesMeta": {
- "@rsbuild/core": {
- "optional": true
- },
- "@vitejs/plugin-rsc": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
- }
- },
- "node_modules/@tanstack/react-start-client": {
- "version": "1.168.16",
- "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.168.16.tgz",
- "integrity": "sha512-1OfHgy0wpHwe2tlB3FxMeA+IMX6Il/QAMf+8UdXuimReIc2Lz3BkMLBL38k4GIxBguX9sI8EMLO5jlTZ4e1olw==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/react-router": "1.170.18",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/start-client-core": "1.170.14"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=18.0.0 || >=19.0.0",
- "react-dom": ">=18.0.0 || >=19.0.0"
- }
- },
- "node_modules/@tanstack/react-start-server": {
- "version": "1.167.22",
- "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.167.22.tgz",
- "integrity": "sha512-eH2PeHuLfL3R5YzE9+y2FfcE4Ld1LNV2ZfrCNVPJMMJFt+9nXDaRHg9BsEmc+JkTAGzz3FKLyQEoWwpbG6Ehqg==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/react-router": "1.170.18",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/start-server-core": "1.169.17"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=18.0.0 || >=19.0.0",
- "react-dom": ">=18.0.0 || >=19.0.0"
- }
- },
- "node_modules/@tanstack/react-start/node_modules/@tanstack/react-start-rsc": {
- "version": "0.1.31",
- "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.1.31.tgz",
- "integrity": "sha512-WxjkXYflq550vTNJpdPyMaPC+Vyh88L5wOL+SiDTjPMGne9ad7FZmoJxqfCFEv1e7HVKMH/mMoE8619TsTNVzQ==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/react-router": "1.170.18",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/router-utils": "1.162.2",
- "@tanstack/start-client-core": "1.170.14",
- "@tanstack/start-fn-stubs": "1.162.0",
- "@tanstack/start-plugin-core": "1.171.24",
- "@tanstack/start-server-core": "1.169.17",
- "@tanstack/start-storage-context": "1.167.17",
- "pathe": "^2.0.3"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "@rspack/core": ">=2.0.0-0",
- "@vitejs/plugin-rsc": ">=0.5.20",
- "react": ">=18.0.0 || >=19.0.0",
- "react-dom": ">=18.0.0 || >=19.0.0",
- "react-server-dom-rspack": ">=0.0.2"
- },
- "peerDependenciesMeta": {
- "@rspack/core": {
- "optional": true
- },
- "@vitejs/plugin-rsc": {
- "optional": true
- },
- "react-server-dom-rspack": {
- "optional": true
- }
- }
- },
- "node_modules/@tanstack/react-store": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.9.3.tgz",
- "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/store": "0.9.3",
- "use-sync-external-store": "^1.6.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
- "node_modules/@tanstack/router-core": {
- "version": "1.171.15",
- "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.15.tgz",
- "integrity": "sha512-IILCDcLaItMZQ2jEmCABHY1Nhjjn5XUvwpQp3e4Nmu+vfg0BgYFuu/QASz2SwE2ZNbVMrvt8X/wxa+Gg5aErxA==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/history": "1.162.0",
- "cookie-es": "^3.0.0",
- "seroval": "^1.5.4",
- "seroval-plugins": "^1.5.4"
- },
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/router-generator": {
- "version": "1.167.21",
- "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.21.tgz",
- "integrity": "sha512-m3oXZyienj8owialdyoZ0txHQrnEx/Ra+D9kWtar5fC2cWZr5Pvxl86VY2mX5RRLC5QLKLeRGT1x4HV95wHVDQ==",
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.28.5",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/router-utils": "1.162.2",
- "@tanstack/virtual-file-routes": "1.162.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
"jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
"magic-string": "^0.30.21",
- "prettier": "^3.5.0",
- "zod": "^4.4.3"
- },
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
}
},
- "node_modules/@tanstack/router-plugin": {
- "version": "1.168.23",
- "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.23.tgz",
- "integrity": "sha512-0+PIcvnaAimFwjoEIeV3h7LKjzC8zNnp7pH2UamdKwQ9QlY99WU9V0Xl0zbM0i9hrUa/mKgWPDAzELmPUu5fMA==",
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "dev": true,
"license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "@babel/core": "^7.28.5",
- "@babel/template": "^7.27.2",
- "@babel/types": "^7.28.5",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/router-generator": "1.167.21",
- "@tanstack/router-utils": "1.162.2",
- "chokidar": "^5.0.0",
- "unplugin": "^3.0.0",
- "zod": "^4.4.3"
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
},
"engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
+ "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "tailwindcss": "4.3.3"
},
"peerDependencies": {
- "@rsbuild/core": ">=1.0.2 || ^2.0.0",
- "@tanstack/react-router": "^1.170.18",
- "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0",
- "vite-plugin-solid": "^2.11.10 || ^3.0.0-0",
- "webpack": ">=5.92.0"
- },
- "peerDependenciesMeta": {
- "@rsbuild/core": {
- "optional": true
- },
- "@tanstack/react-router": {
- "optional": true
- },
- "vite": {
- "optional": true
- },
- "vite-plugin-solid": {
- "optional": true
- },
- "webpack": {
- "optional": true
- }
- }
- },
- "node_modules/@tanstack/router-utils": {
- "version": "1.162.2",
- "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.2.tgz",
- "integrity": "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==",
- "license": "MIT",
- "dependencies": {
- "@babel/generator": "^7.28.5",
- "@babel/parser": "^7.28.5",
- "@babel/types": "^7.28.5",
- "ansis": "^4.1.0",
- "babel-dead-code-elimination": "^1.0.12",
- "diff": "^8.0.2",
- "pathe": "^2.0.3",
- "tinyglobby": "^0.2.15"
- },
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/start-client-core": {
- "version": "1.170.14",
- "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.170.14.tgz",
- "integrity": "sha512-yasBgEIFSWysL4EiFIGwp638nCoXXKiTqkc48EP2oty4OyNsZPTC1yfJ82zjq2KGkTAYtIaeMl7otqqRl1n85Q==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/router-core": "1.171.15",
- "@tanstack/start-fn-stubs": "1.162.0",
- "@tanstack/start-storage-context": "1.167.17",
- "seroval": "^1.5.4"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/start-fn-stubs": {
- "version": "1.162.0",
- "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.162.0.tgz",
- "integrity": "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==",
- "license": "MIT",
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/start-plugin-core": {
- "version": "1.171.24",
- "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.171.24.tgz",
- "integrity": "sha512-l/tm+T0ntXHeIzr9kJDTJ2IDNZC0yFazjkvbEVeZsDOrJ8F+HiZmY+tXYqI5/nDYkwxY0DVQr+kGsTRVb6y2Jw==",
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "7.27.1",
- "@babel/core": "^7.28.5",
- "@babel/types": "^7.28.5",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/router-generator": "1.167.21",
- "@tanstack/router-plugin": "1.168.23",
- "@tanstack/router-utils": "1.162.2",
- "@tanstack/start-server-core": "1.169.17",
- "exsolve": "^1.0.7",
- "lightningcss": "^1.32.0",
- "pathe": "^2.0.3",
- "picomatch": "^4.0.3",
- "seroval": "^1.5.4",
- "source-map": "^0.7.6",
- "srvx": "^0.11.9",
- "tinyglobby": "^0.2.15",
- "ufo": "^1.5.4",
- "vitefu": "^1.1.1",
- "xmlbuilder2": "^4.0.3",
- "zod": "^4.4.3"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "@rsbuild/core": "^2.0.0",
- "vite": ">=7.0.0"
- },
- "peerDependenciesMeta": {
- "@rsbuild/core": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
- }
- },
- "node_modules/@tanstack/start-plugin-core/node_modules/source-map": {
- "version": "0.7.6",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
- "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">= 12"
- }
- },
- "node_modules/@tanstack/start-plugin-core/node_modules/srvx": {
- "version": "0.11.22",
- "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.22.tgz",
- "integrity": "sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==",
- "license": "MIT",
- "bin": {
- "srvx": "bin/srvx.mjs"
- },
- "engines": {
- "node": ">=20.16.0"
- }
- },
- "node_modules/@tanstack/start-server-core": {
- "version": "1.169.17",
- "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.169.17.tgz",
- "integrity": "sha512-u0N+PHJhMHnzfnlXYI9F+A/qweDe3E2X0mfkORPGIEkNQgvS548RA9fjwvixR2en5b848CfpEqUzwFhm/tQ40Q==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/history": "1.162.0",
- "@tanstack/router-core": "1.171.15",
- "@tanstack/start-client-core": "1.170.14",
- "@tanstack/start-storage-context": "1.167.17",
- "fetchdts": "^0.1.6",
- "h3-v2": "npm:h3@2.0.1-rc.20",
- "seroval": "^1.5.4"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/start-storage-context": {
- "version": "1.167.17",
- "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.167.17.tgz",
- "integrity": "sha512-ntkDyGx0PE0opIlWNAMpkMb8qkjR4uyCUOfC0CiT0STM25+EcwPuwYNfDXXeVObMrTAPgsQ4yOj3xdY0Xr4ptw==",
- "license": "MIT",
- "dependencies": {
- "@tanstack/router-core": "1.171.15"
- },
- "engines": {
- "node": ">=22.12.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/store": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz",
- "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==",
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/virtual-file-routes": {
- "version": "1.162.0",
- "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz",
- "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==",
- "license": "MIT",
- "engines": {
- "node": ">=20.19"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
}
},
"node_modules/@tybys/wasm-util": {
@@ -1827,93 +1712,455 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
"node_modules/@types/node": {
- "version": "22.19.19",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
- "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
+ "version": "24.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
+ "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.21.0"
+ "undici-types": "~7.16.0"
}
},
- "node_modules/@types/react": {
- "version": "19.2.14",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
- "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "node_modules/@typescript/typescript-aix-ppc64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
+ "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-darwin-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
+ "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-darwin-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
+ "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-freebsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-freebsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
+ "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-arm": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
+ "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
+ "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-loong64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
+ "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-mips64el": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
+ "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-ppc64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
+ "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-riscv64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
+ "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-s390x": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
+ "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
+ "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-netbsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-netbsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-openbsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-openbsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-sunos-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
+ "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-win32-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
+ "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-win32-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
+ "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/babel-plugin-jsx-dom-expressions": {
+ "version": "0.40.7",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.40.7.tgz",
+ "integrity": "sha512-/O6JWUmjv03OI9lL2ry9bUjpD5S3PclM55RRJEyCdcFZ5W2SEA/59d+l2hNsk3gI6kiWRdRPdOtqZmsQzFN1pQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "csstype": "^3.2.2"
- }
- },
- "node_modules/@types/react-dom": {
- "version": "19.2.3",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
- "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
- "dev": true,
- "license": "MIT",
+ "@babel/helper-module-imports": "7.18.6",
+ "@babel/plugin-syntax-jsx": "^7.18.6",
+ "@babel/types": "^7.20.7",
+ "html-entities": "2.3.3",
+ "parse5": "^7.1.2"
+ },
"peerDependencies": {
- "@types/react": "^19.2.0"
+ "@babel/core": "^7.20.12"
}
},
- "node_modules/@vitejs/plugin-react": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz",
- "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==",
+ "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@rolldown/pluginutils": "^1.0.0"
+ "@babel/types": "^7.18.6"
},
"engines": {
- "node": "^20.19.0 || >=22.12.0"
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/babel-preset-solid": {
+ "version": "1.9.12",
+ "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.9.12.tgz",
+ "integrity": "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "babel-plugin-jsx-dom-expressions": "^0.40.6"
},
"peerDependencies": {
- "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
- "babel-plugin-react-compiler": "^1.0.0",
- "vite": "^8.0.0"
+ "@babel/core": "^7.0.0",
+ "solid-js": "^1.9.12"
},
"peerDependenciesMeta": {
- "@rolldown/plugin-babel": {
- "optional": true
- },
- "babel-plugin-react-compiler": {
+ "solid-js": {
"optional": true
}
}
},
- "node_modules/ansis": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz",
- "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==",
- "license": "ISC",
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "license": "Python-2.0"
- },
- "node_modules/babel-dead-code-elimination": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz",
- "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==",
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.23.7",
- "@babel/parser": "^7.23.6",
- "@babel/traverse": "^7.23.7",
- "@babel/types": "^7.23.6"
- }
- },
"node_modules/baseline-browser-mapping": {
- "version": "2.11.3",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.3.tgz",
- "integrity": "sha512-sbT0Ui/CZwyAyy7icT1Gw5P1LKRlFaHwaF6tDCW5YHq2X5SeeZFphBuIagopSfwSSZq3sQcbmEL072yphxm7ew==",
+ "version": "2.11.7",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.7.tgz",
+ "integrity": "sha512-APw5YuIQAg6L9w4sHDI6j26DGFJI6RpYOhnkMPdC9lWbkKvsyPHzDsve1yd73lk21yz7Y09Kci8B2Pp9FonzWA==",
+ "dev": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.cjs"
@@ -1926,6 +2173,7 @@
"version": "4.28.7",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
"integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -1959,6 +2207,7 @@
"version": "1.0.30001806",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
"integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -1975,44 +2224,24 @@
],
"license": "CC-BY-4.0"
},
- "node_modules/chokidar": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
- "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
- "license": "MIT",
- "dependencies": {
- "readdirp": "^5.0.0"
- },
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "license": "MIT"
- },
- "node_modules/cookie-es": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz",
- "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2030,46 +2259,73 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
- "node_modules/diff": {
- "version": "8.0.4",
- "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
- "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
- "license": "BSD-3-Clause",
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.398",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz",
+ "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.24.4",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.4.tgz",
+ "integrity": "sha512-GVoi+ICHocoOIU7qVVM48wOJziRsqrsyqlI0Ce0LdowRn6v3bcH2zUa9kp85ncx0nwIb9/HOCOLS3fdThDG/XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
"engines": {
- "node": ">=0.3.1"
+ "node": ">=10.13.0"
}
},
- "node_modules/electron-to-chromium": {
- "version": "1.5.396",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.396.tgz",
- "integrity": "sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==",
- "license": "ISC"
+ "node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
- "node_modules/exsolve": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz",
- "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==",
- "license": "MIT"
- },
- "node_modules/fetchdts": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz",
- "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==",
- "license": "MIT"
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
},
"node_modules/fsevents": {
"version": "2.3.3",
@@ -2090,61 +2346,44 @@
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/h3-v2": {
- "name": "h3",
- "version": "2.0.1-rc.20",
- "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.20.tgz",
- "integrity": "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==",
- "license": "MIT",
- "dependencies": {
- "rou3": "^0.8.1",
- "srvx": "^0.11.13"
- },
- "bin": {
- "h3": "bin/h3.mjs"
- },
- "engines": {
- "node": ">=20.11.1"
- },
- "peerDependencies": {
- "crossws": "^0.4.1"
- },
- "peerDependenciesMeta": {
- "crossws": {
- "optional": true
- }
- }
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
},
- "node_modules/h3-v2/node_modules/srvx": {
- "version": "0.11.22",
- "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.22.tgz",
- "integrity": "sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==",
- "license": "MIT",
- "bin": {
- "srvx": "bin/srvx.mjs"
- },
- "engines": {
- "node": ">=20.16.0"
- }
+ "node_modules/html-entities": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz",
+ "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/isbot": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.2.1.tgz",
- "integrity": "sha512-dJ+LpKyClQZ7NG+j3OensC/mAZkGpukE9YUrgPYvAZj2doVL0edfDgywTUh5CXa0o+nW9a1V9e5+CJTX8+SxRw==",
- "license": "Unlicense",
+ "node_modules/is-what": {
+ "version": "4.1.16",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
+ "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=18"
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/jiti": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -2154,34 +2393,14 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
"license": "MIT"
},
- "node_modules/js-yaml": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
- "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/puzrin"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/nodeca"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -2194,6 +2413,7 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
@@ -2203,9 +2423,10 @@
}
},
"node_modules/lightningcss": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
- "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
@@ -2218,26 +2439,27 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
- "lightningcss-android-arm64": "1.33.0",
- "lightningcss-darwin-arm64": "1.33.0",
- "lightningcss-darwin-x64": "1.33.0",
- "lightningcss-freebsd-x64": "1.33.0",
- "lightningcss-linux-arm-gnueabihf": "1.33.0",
- "lightningcss-linux-arm64-gnu": "1.33.0",
- "lightningcss-linux-arm64-musl": "1.33.0",
- "lightningcss-linux-x64-gnu": "1.33.0",
- "lightningcss-linux-x64-musl": "1.33.0",
- "lightningcss-win32-arm64-msvc": "1.33.0",
- "lightningcss-win32-x64-msvc": "1.33.0"
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
}
},
"node_modules/lightningcss-android-arm64": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
- "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2252,12 +2474,13 @@
}
},
"node_modules/lightningcss-darwin-arm64": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
- "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2272,12 +2495,13 @@
}
},
"node_modules/lightningcss-darwin-x64": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
- "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2292,12 +2516,13 @@
}
},
"node_modules/lightningcss-freebsd-x64": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
- "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2312,12 +2537,13 @@
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
- "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
"cpu": [
"arm"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2332,12 +2558,16 @@
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
- "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
"cpu": [
"arm64"
],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2352,12 +2582,16 @@
}
},
"node_modules/lightningcss-linux-arm64-musl": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
- "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
"cpu": [
"arm64"
],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2372,12 +2606,16 @@
}
},
"node_modules/lightningcss-linux-x64-gnu": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
- "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
"cpu": [
"x64"
],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2392,12 +2630,16 @@
}
},
"node_modules/lightningcss-linux-x64-musl": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
- "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
"cpu": [
"x64"
],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2412,12 +2654,13 @@
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
- "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
"cpu": [
"arm64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2432,12 +2675,13 @@
}
},
"node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
- "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
"cpu": [
"x64"
],
+ "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2455,40 +2699,59 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
- "node_modules/lucide-react": {
+ "node_modules/lucide-solid": {
"version": "1.27.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.27.0.tgz",
- "integrity": "sha512-rJicGl/3Fly/E0rOH1YmPZ6e49JCnKknh1ox1vpHnkfjujAkKA6sqUZvH3MTAaXXjgexyUwgNwTJzTtYuAFYJw==",
+ "resolved": "https://registry.npmjs.org/lucide-solid/-/lucide-solid-1.27.0.tgz",
+ "integrity": "sha512-zbz//eLp8l3coLBkVj3kw/jOS2lP7UMsM7EYRvWhu1NF1buy1hvEUQ5maOLgWXNOCmhqfPP7Zmf1+KcdDwHoYg==",
"license": "ISC",
"peerDependencies": {
- "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ "solid-js": "^1.4.7"
}
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
+ "node_modules/merge-anything": {
+ "version": "5.1.7",
+ "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.7.tgz",
+ "integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-what": "^4.1.8"
+ },
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
- "devOptional": true,
+ "dev": true,
"funding": [
{
"type": "github",
@@ -2507,15 +2770,16 @@
"version": "2.0.51",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz",
"integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/oxfmt": {
- "version": "0.60.0",
- "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.60.0.tgz",
- "integrity": "sha512-fViX6i+gJuZWY+jI/fnR6WRbRj70GZ9RlCd30MygJrHTUNc4DxvKHWw8vBjMjffv3PgU5qWDR0AzmojQByqaZA==",
+ "version": "0.61.0",
+ "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.61.0.tgz",
+ "integrity": "sha512-DxdHBEMYpcEnHoUHjjOigUqV2TYKsvxLwUPXnVYBjgFdqrcQ/91OtwubtZ2PUodCs3sStI8R5Qw3fKNGK4e8wQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2531,25 +2795,25 @@
"url": "https://github.com/sponsors/Boshen"
},
"optionalDependencies": {
- "@oxfmt/binding-android-arm-eabi": "0.60.0",
- "@oxfmt/binding-android-arm64": "0.60.0",
- "@oxfmt/binding-darwin-arm64": "0.60.0",
- "@oxfmt/binding-darwin-x64": "0.60.0",
- "@oxfmt/binding-freebsd-x64": "0.60.0",
- "@oxfmt/binding-linux-arm-gnueabihf": "0.60.0",
- "@oxfmt/binding-linux-arm-musleabihf": "0.60.0",
- "@oxfmt/binding-linux-arm64-gnu": "0.60.0",
- "@oxfmt/binding-linux-arm64-musl": "0.60.0",
- "@oxfmt/binding-linux-ppc64-gnu": "0.60.0",
- "@oxfmt/binding-linux-riscv64-gnu": "0.60.0",
- "@oxfmt/binding-linux-riscv64-musl": "0.60.0",
- "@oxfmt/binding-linux-s390x-gnu": "0.60.0",
- "@oxfmt/binding-linux-x64-gnu": "0.60.0",
- "@oxfmt/binding-linux-x64-musl": "0.60.0",
- "@oxfmt/binding-openharmony-arm64": "0.60.0",
- "@oxfmt/binding-win32-arm64-msvc": "0.60.0",
- "@oxfmt/binding-win32-ia32-msvc": "0.60.0",
- "@oxfmt/binding-win32-x64-msvc": "0.60.0"
+ "@oxfmt/binding-android-arm-eabi": "0.61.0",
+ "@oxfmt/binding-android-arm64": "0.61.0",
+ "@oxfmt/binding-darwin-arm64": "0.61.0",
+ "@oxfmt/binding-darwin-x64": "0.61.0",
+ "@oxfmt/binding-freebsd-x64": "0.61.0",
+ "@oxfmt/binding-linux-arm-gnueabihf": "0.61.0",
+ "@oxfmt/binding-linux-arm-musleabihf": "0.61.0",
+ "@oxfmt/binding-linux-arm64-gnu": "0.61.0",
+ "@oxfmt/binding-linux-arm64-musl": "0.61.0",
+ "@oxfmt/binding-linux-ppc64-gnu": "0.61.0",
+ "@oxfmt/binding-linux-riscv64-gnu": "0.61.0",
+ "@oxfmt/binding-linux-riscv64-musl": "0.61.0",
+ "@oxfmt/binding-linux-s390x-gnu": "0.61.0",
+ "@oxfmt/binding-linux-x64-gnu": "0.61.0",
+ "@oxfmt/binding-linux-x64-musl": "0.61.0",
+ "@oxfmt/binding-openharmony-arm64": "0.61.0",
+ "@oxfmt/binding-win32-arm64-msvc": "0.61.0",
+ "@oxfmt/binding-win32-ia32-msvc": "0.61.0",
+ "@oxfmt/binding-win32-x64-msvc": "0.61.0"
},
"peerDependencies": {
"svelte": "^5.0.0",
@@ -2565,9 +2829,9 @@
}
},
"node_modules/oxlint": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.75.0.tgz",
- "integrity": "sha512-m9WzjRcRYA/uqIZDa9tclrieoPJ/ln1QYTKdFx6NUOs8uY5DiHlIwRQoCrHT6OM6O3ww3l2skY5gO7G7ZphE7g==",
+ "version": "1.76.0",
+ "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.76.0.tgz",
+ "integrity": "sha512-6QoFioEU4fNdiUx/2Eo6TRd6NG7H7njnRCz8rhB66cZmMHDTqcm1Rjvl8Wry+ZTQMBAmyb4Mlf62Mk5X+eHSOw==",
"dev": true,
"license": "MIT",
"bin": {
@@ -2580,25 +2844,25 @@
"url": "https://github.com/sponsors/Boshen"
},
"optionalDependencies": {
- "@oxlint/binding-android-arm-eabi": "1.75.0",
- "@oxlint/binding-android-arm64": "1.75.0",
- "@oxlint/binding-darwin-arm64": "1.75.0",
- "@oxlint/binding-darwin-x64": "1.75.0",
- "@oxlint/binding-freebsd-x64": "1.75.0",
- "@oxlint/binding-linux-arm-gnueabihf": "1.75.0",
- "@oxlint/binding-linux-arm-musleabihf": "1.75.0",
- "@oxlint/binding-linux-arm64-gnu": "1.75.0",
- "@oxlint/binding-linux-arm64-musl": "1.75.0",
- "@oxlint/binding-linux-ppc64-gnu": "1.75.0",
- "@oxlint/binding-linux-riscv64-gnu": "1.75.0",
- "@oxlint/binding-linux-riscv64-musl": "1.75.0",
- "@oxlint/binding-linux-s390x-gnu": "1.75.0",
- "@oxlint/binding-linux-x64-gnu": "1.75.0",
- "@oxlint/binding-linux-x64-musl": "1.75.0",
- "@oxlint/binding-openharmony-arm64": "1.75.0",
- "@oxlint/binding-win32-arm64-msvc": "1.75.0",
- "@oxlint/binding-win32-ia32-msvc": "1.75.0",
- "@oxlint/binding-win32-x64-msvc": "1.75.0"
+ "@oxlint/binding-android-arm-eabi": "1.76.0",
+ "@oxlint/binding-android-arm64": "1.76.0",
+ "@oxlint/binding-darwin-arm64": "1.76.0",
+ "@oxlint/binding-darwin-x64": "1.76.0",
+ "@oxlint/binding-freebsd-x64": "1.76.0",
+ "@oxlint/binding-linux-arm-gnueabihf": "1.76.0",
+ "@oxlint/binding-linux-arm-musleabihf": "1.76.0",
+ "@oxlint/binding-linux-arm64-gnu": "1.76.0",
+ "@oxlint/binding-linux-arm64-musl": "1.76.0",
+ "@oxlint/binding-linux-ppc64-gnu": "1.76.0",
+ "@oxlint/binding-linux-riscv64-gnu": "1.76.0",
+ "@oxlint/binding-linux-riscv64-musl": "1.76.0",
+ "@oxlint/binding-linux-s390x-gnu": "1.76.0",
+ "@oxlint/binding-linux-x64-gnu": "1.76.0",
+ "@oxlint/binding-linux-x64-musl": "1.76.0",
+ "@oxlint/binding-openharmony-arm64": "1.76.0",
+ "@oxlint/binding-win32-arm64-msvc": "1.76.0",
+ "@oxlint/binding-win32-ia32-msvc": "1.76.0",
+ "@oxlint/binding-win32-x64-msvc": "1.76.0"
},
"peerDependencies": {
"oxlint-tsgolint": ">=7.0.2001",
@@ -2613,22 +2877,31 @@
}
}
},
- "node_modules/pathe": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
- "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
- "license": "MIT"
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -2638,10 +2911,10 @@
}
},
"node_modules/postcss": {
- "version": "8.5.23",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
- "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
- "devOptional": true,
+ "version": "8.5.25",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
+ "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2666,60 +2939,11 @@
"node": "^10 || ^12 || >=14"
}
},
- "node_modules/prettier": {
- "version": "3.9.6",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz",
- "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==",
- "license": "MIT",
- "bin": {
- "prettier": "bin/prettier.cjs"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/react": {
- "version": "19.2.6",
- "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
- "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "19.2.6",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
- "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
- "license": "MIT",
- "dependencies": {
- "scheduler": "^0.27.0"
- },
- "peerDependencies": {
- "react": "^19.2.6"
- }
- },
- "node_modules/readdirp": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
- "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- },
"node_modules/rolldown": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz",
"integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.139.0",
@@ -2749,22 +2973,11 @@
"@rolldown/binding-win32-x64-msvc": "1.1.5"
}
},
- "node_modules/rou3": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz",
- "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==",
- "license": "MIT"
- },
- "node_modules/scheduler": {
- "version": "0.27.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
- "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
- "license": "MIT"
- },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2791,32 +3004,68 @@
"seroval": "^1.0"
}
},
+ "node_modules/solid-js": {
+ "version": "1.9.14",
+ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.14.tgz",
+ "integrity": "sha512-sAEXC0Kk0S1EDg+8ysEWJDbYhA3RRoEjwuySUGlKIemeo0I5YZfOyumNjNs9Sv3y2nmhD+0rW66ag2HsMuQiGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.1.0",
+ "seroval": "~1.5.4",
+ "seroval-plugins": "~1.5.4"
+ }
+ },
+ "node_modules/solid-refresh": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.6.3.tgz",
+ "integrity": "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/generator": "^7.23.6",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/types": "^7.23.6"
+ },
+ "peerDependencies": {
+ "solid-js": "^1.3"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "devOptional": true,
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/srvx": {
- "version": "0.12.4",
- "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.12.4.tgz",
- "integrity": "sha512-RixzFlMn3dvzDTpKIAXhXrqL4cy6vScNCP0VVwgVbUBU94o+DiXLsFnAZetbyKAEnK6Ox3hzHXWGsyv/Iibv7g==",
+ "node_modules/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
"license": "MIT",
- "bin": {
- "srvx": "bin/srvx.mjs"
- },
"engines": {
- "node": ">=20.16.0"
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
}
},
"node_modules/tinyglobby": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
@@ -2829,23 +3078,6 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
"node_modules/tinypool": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz",
@@ -2865,90 +3097,52 @@
"optional": true
},
"node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
+ "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
+ "tsc": "bin/tsc"
},
"engines": {
- "node": ">=14.17"
+ "node": ">=16.20.0"
+ },
+ "optionalDependencies": {
+ "@typescript/typescript-aix-ppc64": "7.0.2",
+ "@typescript/typescript-darwin-arm64": "7.0.2",
+ "@typescript/typescript-darwin-x64": "7.0.2",
+ "@typescript/typescript-freebsd-arm64": "7.0.2",
+ "@typescript/typescript-freebsd-x64": "7.0.2",
+ "@typescript/typescript-linux-arm": "7.0.2",
+ "@typescript/typescript-linux-arm64": "7.0.2",
+ "@typescript/typescript-linux-loong64": "7.0.2",
+ "@typescript/typescript-linux-mips64el": "7.0.2",
+ "@typescript/typescript-linux-ppc64": "7.0.2",
+ "@typescript/typescript-linux-riscv64": "7.0.2",
+ "@typescript/typescript-linux-s390x": "7.0.2",
+ "@typescript/typescript-linux-x64": "7.0.2",
+ "@typescript/typescript-netbsd-arm64": "7.0.2",
+ "@typescript/typescript-netbsd-x64": "7.0.2",
+ "@typescript/typescript-openbsd-arm64": "7.0.2",
+ "@typescript/typescript-openbsd-x64": "7.0.2",
+ "@typescript/typescript-sunos-x64": "7.0.2",
+ "@typescript/typescript-win32-arm64": "7.0.2",
+ "@typescript/typescript-win32-x64": "7.0.2"
}
},
- "node_modules/ufo": {
- "version": "1.6.4",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",
- "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
- "license": "MIT"
- },
"node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
- "node_modules/unplugin": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.3.0.tgz",
- "integrity": "sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==",
- "license": "MIT",
- "dependencies": {
- "@jridgewell/remapping": "^2.3.5",
- "picomatch": "^4.0.4",
- "webpack-virtual-modules": "^0.6.2"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- },
- "peerDependencies": {
- "@farmfe/core": "*",
- "@rspack/core": "*",
- "bun-types-no-globals": "*",
- "esbuild": "*",
- "rolldown": "*",
- "rollup": "*",
- "unloader": "*",
- "vite": "*",
- "webpack": "*"
- },
- "peerDependenciesMeta": {
- "@farmfe/core": {
- "optional": true
- },
- "@rspack/core": {
- "optional": true
- },
- "bun-types-no-globals": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- },
- "rolldown": {
- "optional": true
- },
- "rollup": {
- "optional": true
- },
- "unloader": {
- "optional": true
- },
- "vite": {
- "optional": true
- },
- "webpack": {
- "optional": true
- }
- }
- },
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2975,20 +3169,11 @@
"browserslist": ">= 4.21.0"
}
},
- "node_modules/use-sync-external-store": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
- "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
- "license": "MIT",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
"node_modules/vite": {
"version": "8.1.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz",
"integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.32.0",
@@ -3062,10 +3247,36 @@
}
}
},
+ "node_modules/vite-plugin-solid": {
+ "version": "2.11.14",
+ "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.11.14.tgz",
+ "integrity": "sha512-7ZVBt8rpoyqmlwin2kRIUveaHoF6/kulY7gsnD+qFh4nS29V4OPAnw+ojoAspXIjObiL9o1xh9a/nTuYHm02Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.23.3",
+ "@types/babel__core": "^7.20.4",
+ "babel-preset-solid": "^1.8.4",
+ "merge-anything": "^5.1.7",
+ "solid-refresh": "^0.6.3",
+ "vitefu": "^1.0.4"
+ },
+ "peerDependencies": {
+ "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.0.0 || ^7.0.0",
+ "solid-js": "^1.7.2",
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@testing-library/jest-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vitefu": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
"integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
+ "dev": true,
"license": "MIT",
"workspaces": [
"tests/deps/*",
@@ -3081,41 +3292,12 @@
}
}
},
- "node_modules/webpack-virtual-modules": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
- "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
- "license": "MIT"
- },
- "node_modules/xmlbuilder2": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz",
- "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==",
- "license": "MIT",
- "dependencies": {
- "@oozcitak/dom": "^2.0.2",
- "@oozcitak/infra": "^2.0.2",
- "@oozcitak/util": "^10.0.0",
- "js-yaml": "^4.1.1"
- },
- "engines": {
- "node": ">=20.0"
- }
- },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
"license": "ISC"
- },
- "node_modules/zod": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
- "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
}
}
}
diff --git a/crates/wasmeld-console/web/package.json b/crates/wasmeld-console/web/package.json
new file mode 100644
index 0000000..e136432
--- /dev/null
+++ b/crates/wasmeld-console/web/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "wasmeld-console-web",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build && tsc --noEmit",
+ "preview": "vite preview",
+ "test": "npm run build && node --test tests/build-output.test.mjs",
+ "lint": "oxlint . --deny-warnings",
+ "format": "oxfmt .",
+ "format:check": "oxfmt --check ."
+ },
+ "dependencies": {
+ "lucide-solid": "1.27.0",
+ "solid-js": "1.9.14"
+ },
+ "devDependencies": {
+ "@tailwindcss/vite": "4.3.3",
+ "@types/node": "24.10.1",
+ "oxfmt": "0.61.0",
+ "oxlint": "1.76.0",
+ "tailwindcss": "4.3.3",
+ "typescript": "7.0.2",
+ "vite": "8.1.5",
+ "vite-plugin-solid": "2.11.14"
+ },
+ "engines": {
+ "node": ">=22.13.0"
+ }
+}
diff --git a/crates/wasmeld-console/web/page.html b/crates/wasmeld-console/web/page.html
new file mode 100644
index 0000000..4719267
--- /dev/null
+++ b/crates/wasmeld-console/web/page.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Wasmeld Console Page
+
+
+
+
+
+
diff --git a/crates/wasmeld-console/web/public/icon.svg b/crates/wasmeld-console/web/public/icon.svg
new file mode 100644
index 0000000..3a22ac5
--- /dev/null
+++ b/crates/wasmeld-console/web/public/icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/crates/wasmeld-console/web/public/manifest.webmanifest b/crates/wasmeld-console/web/public/manifest.webmanifest
new file mode 100644
index 0000000..348e389
--- /dev/null
+++ b/crates/wasmeld-console/web/public/manifest.webmanifest
@@ -0,0 +1,18 @@
+{
+ "name": "Wasmeld Console",
+ "short_name": "Wasmeld",
+ "description": "WebAssembly Component Runtime management console",
+ "theme_color": "#173f35",
+ "background_color": "#f3f6f5",
+ "display": "standalone",
+ "start_url": "/",
+ "scope": "/",
+ "icons": [
+ {
+ "src": "/icon.svg",
+ "sizes": "any",
+ "type": "image/svg+xml",
+ "purpose": "any maskable"
+ }
+ ]
+}
diff --git a/console/public/og.png b/crates/wasmeld-console/web/public/og.png
similarity index 100%
rename from console/public/og.png
rename to crates/wasmeld-console/web/public/og.png
diff --git a/crates/wasmeld-console/web/src/components/ui/empty-state.tsx b/crates/wasmeld-console/web/src/components/ui/empty-state.tsx
new file mode 100644
index 0000000..a34e0df
--- /dev/null
+++ b/crates/wasmeld-console/web/src/components/ui/empty-state.tsx
@@ -0,0 +1,13 @@
+import type { Component } from "solid-js";
+import type { LucideProps } from "lucide-solid";
+
+export function EmptyState(props: { icon: Component; title: string; detail: string }) {
+ const Icon = props.icon;
+ return (
+
+
+ {props.title}
+ {props.detail}
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/components/ui/page-heading.tsx b/crates/wasmeld-console/web/src/components/ui/page-heading.tsx
new file mode 100644
index 0000000..1f47c0d
--- /dev/null
+++ b/crates/wasmeld-console/web/src/components/ui/page-heading.tsx
@@ -0,0 +1,19 @@
+import type { JSXElement } from "solid-js";
+
+export function PageHeading(props: {
+ eyebrow: string;
+ title: string;
+ description: string;
+ actions?: JSXElement;
+}) {
+ return (
+
+
+
{props.eyebrow}
+
{props.title}
+
{props.description}
+
+ {props.actions && {props.actions}
}
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/components/ui/service-table.tsx b/crates/wasmeld-console/web/src/components/ui/service-table.tsx
new file mode 100644
index 0000000..bd3e4b2
--- /dev/null
+++ b/crates/wasmeld-console/web/src/components/ui/service-table.tsx
@@ -0,0 +1,195 @@
+import {
+ Box,
+ Braces,
+ CircleStop,
+ Play,
+ RadioTower,
+ RefreshCw,
+ RotateCcw,
+ Search,
+ SquareTerminal,
+} from "lucide-solid";
+import { For, Show } from "solid-js";
+import { serviceKey, type Service } from "../../lib/model";
+import type { HostSharedState, PageCommand } from "../../sdk/protocol";
+import { EmptyState } from "./empty-state";
+import { StatusBadge } from "./status-badge";
+
+export function ServiceTable(props: {
+ services: Service[];
+ state: HostSharedState;
+ command: (command: PageCommand) => void;
+ compact?: boolean;
+}) {
+ return (
+ 0}
+ fallback={
+
+ }
+ >
+
+
+
+
+ | 服务 |
+ 状态 |
+
+ 制品 |
+ Host 能力 |
+
+ 调用 |
+ 延迟 |
+
+ 操作
+ |
+
+
+
+
+ {(service) => {
+ const key = serviceKey(service);
+ return (
+
+ |
+
+
+
+
+
+
+ {service.id}
+
+
+
+ 对外
+
+
+
+ {service.revision}
+
+
+ |
+
+
+ |
+
+
+ {service.artifact}
+ |
+
+ 0}
+ fallback={无}
+ >
+ capability.interface)
+ .join("\n")}
+ >
+
+
+ {service.capabilities[0]?.package}/{service.capabilities[0]?.name}
+
+ 1}>
+ +{service.capabilities.length - 1}
+
+
+
+ |
+
+ {service.calls.toLocaleString("zh-CN")} |
+
+ {service.latencyMs === null ? "—" : `${service.latencyMs} ms`}
+ |
+
+
+
+
+ props.command({
+ type: "service-action",
+ serviceKey: key,
+ action: "start",
+ })
+ }
+ >
+
+
+ }
+ >
+
+
+
+
+
+ |
+
+ );
+ }}
+
+
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/components/ui/status-badge.tsx b/crates/wasmeld-console/web/src/components/ui/status-badge.tsx
new file mode 100644
index 0000000..bab7c79
--- /dev/null
+++ b/crates/wasmeld-console/web/src/components/ui/status-badge.tsx
@@ -0,0 +1,6 @@
+import { STATUS_META, type ServiceStatus } from "../../lib/model";
+
+export function StatusBadge(props: { status: ServiceStatus }) {
+ const meta = () => STATUS_META[props.status];
+ return {meta().label};
+}
diff --git a/crates/wasmeld-console/web/src/host/app.tsx b/crates/wasmeld-console/web/src/host/app.tsx
new file mode 100644
index 0000000..fbf20f7
--- /dev/null
+++ b/crates/wasmeld-console/web/src/host/app.tsx
@@ -0,0 +1,444 @@
+import {
+ Boxes,
+ FileCode2,
+ History,
+ LayoutDashboard,
+ Package,
+ Search,
+ Server,
+ Settings,
+ ShieldCheck,
+ WifiOff,
+} from "lucide-solid";
+import {
+ createEffect,
+ createMemo,
+ createSignal,
+ For,
+ onCleanup,
+ onMount,
+ Show,
+ type Component,
+} from "solid-js";
+import type { LucideProps } from "lucide-solid";
+import {
+ activateDeployment,
+ changeRuntimeState,
+ changeServiceState,
+ fetchSnapshot,
+ getApiBase,
+ invokeComponent,
+ publishWitPackage,
+ registerComponent,
+ saveApiBase,
+ type BackendSnapshot,
+ type InvokeResult,
+} from "../lib/api";
+import { isView, serviceKey, type ConnectionState, type Service, type View } from "../lib/model";
+import { servicesFrom } from "../lib/view-state";
+import { disposePage, pageUrl, sendState } from "../sdk/host";
+import {
+ isPageMessage,
+ type HostSharedState,
+ type PageCommand,
+ type RuntimeAction,
+} from "../sdk/protocol";
+import { DialogLayer, type DialogState } from "./dialogs";
+
+const NAVIGATION: Array<{
+ id: View;
+ label: string;
+ icon: Component;
+}> = [
+ { id: "overview", label: "运行概览", icon: LayoutDashboard },
+ { id: "services", label: "服务版本", icon: Package },
+ { id: "instances", label: "运行实例", icon: Server },
+ { id: "wit-packages", label: "WIT 包", icon: FileCode2 },
+ { id: "activity", label: "调用记录", icon: History },
+ { id: "settings", label: "运行设置", icon: Settings },
+];
+
+export default function HostApp() {
+ // All backend ownership stays in this persistent document. Page iframes are
+ // disposable renderers and can only request typed commands through the SDK.
+ const [view, setView] = createSignal(initialView());
+ const [frameInstance, setFrameInstance] = createSignal(1);
+ const [frameReady, setFrameReady] = createSignal(false);
+ const [snapshot, setSnapshot] = createSignal(null);
+ const [connection, setConnection] = createSignal("connecting");
+ const [apiBase, setApiBase] = createSignal(getApiBase());
+ const [query, setQuery] = createSignal("");
+ const [runtimeAction, setRuntimeAction] = createSignal(null);
+ const [serviceAction, setServiceAction] = createSignal(null);
+ const [deploymentAction, setDeploymentAction] = createSignal(null);
+ const [dialog, setDialog] = createSignal(null);
+ const [dialogBusy, setDialogBusy] = createSignal(false);
+ const [toast, setToast] = createSignal(null);
+ let iframe: HTMLIFrameElement | undefined;
+ let toastTimer: number | undefined;
+ let refreshGeneration = 0;
+
+ const state = createMemo(() => ({
+ view: view(),
+ snapshot: snapshot(),
+ connection: connection(),
+ query: query(),
+ apiBase: apiBase(),
+ runtimeAction: runtimeAction(),
+ serviceAction: serviceAction(),
+ deploymentAction: deploymentAction(),
+ }));
+ const activeServices = createMemo(
+ () => servicesFrom(state()).filter((service) => service.status === "running").length,
+ );
+ const frameSource = createMemo(() => pageUrl(view(), frameInstance()));
+ const title = createMemo(
+ () => NAVIGATION.find((item) => item.id === view())?.label ?? "运行概览",
+ );
+
+ async function refresh() {
+ const generation = ++refreshGeneration;
+ try {
+ const next = await fetchSnapshot(apiBase());
+ if (generation !== refreshGeneration) return;
+ setSnapshot(next);
+ setConnection("online");
+ } catch {
+ if (generation !== refreshGeneration) return;
+ setSnapshot(null);
+ setConnection("offline");
+ }
+ }
+
+ function notify(message: string) {
+ if (toastTimer !== undefined) window.clearTimeout(toastTimer);
+ setToast(message);
+ toastTimer = window.setTimeout(() => setToast(null), 2800);
+ }
+
+ function navigate(next: View, pushHistory = true) {
+ if (next === view()) return;
+ // Give page-owned libraries a synchronous cleanup hook, then change the
+ // keyed URL so Solid removes the old iframe realm in the same transition.
+ const target = iframe?.contentWindow;
+ if (target) disposePage(target);
+ setFrameReady(false);
+ setView(next);
+ setFrameInstance((instance) => instance + 1);
+ setQuery("");
+ if (pushHistory) {
+ const url = new URL(window.location.href);
+ url.searchParams.set("view", next);
+ window.history.pushState({ view: next }, "", url);
+ }
+ }
+
+ function findService(key: string): Service | null {
+ return servicesFrom(state()).find((service) => serviceKey(service) === key) ?? null;
+ }
+
+ async function performRuntimeAction(action: RuntimeAction) {
+ setRuntimeAction(action);
+ try {
+ await changeRuntimeState(apiBase(), action);
+ await refresh();
+ notify(
+ action === "start"
+ ? "Runtime 已启动"
+ : action === "stop"
+ ? "Runtime 已停止"
+ : "Runtime 已重启",
+ );
+ } catch (error) {
+ notify(error instanceof Error ? error.message : "Runtime 操作失败");
+ } finally {
+ setRuntimeAction(null);
+ }
+ }
+
+ async function performServiceAction(key: string, action: "start" | "stop" | "restart") {
+ const service = findService(key);
+ if (!service) return;
+ setServiceAction(key);
+ try {
+ await changeServiceState(apiBase(), service, action);
+ await refresh();
+ notify(
+ `${service.id} ${action === "stop" ? "已停止" : action === "restart" ? "已重启" : "已启动"}`,
+ );
+ } catch (error) {
+ notify(error instanceof Error ? error.message : "Actor 操作失败");
+ } finally {
+ setServiceAction(null);
+ }
+ }
+
+ async function handleCommand(command: PageCommand) {
+ switch (command.type) {
+ case "refresh":
+ await refresh();
+ return;
+ case "navigate":
+ navigate(command.view);
+ return;
+ case "open-register":
+ setDialog({ type: "register" });
+ return;
+ case "open-wit-publish":
+ setDialog({ type: "wit-publish" });
+ return;
+ case "open-invoke": {
+ const service = findService(command.serviceKey);
+ if (service) setDialog({ type: "invoke", service });
+ return;
+ }
+ case "open-activate": {
+ const service = findService(command.serviceKey);
+ if (!service) return;
+ const currentRevision =
+ snapshot()?.deployments.find((item) => item.service_id === service.id)?.active_revision ??
+ null;
+ setDialog({ type: "activate", service, currentRevision });
+ return;
+ }
+ case "runtime-action":
+ await performRuntimeAction(command.action);
+ return;
+ case "service-action":
+ await performServiceAction(command.serviceKey, command.action);
+ return;
+ case "save-api-base":
+ try {
+ const next = saveApiBase(command.value);
+ setApiBase(next);
+ setSnapshot(null);
+ setConnection("connecting");
+ await refresh();
+ notify("API 地址已保存");
+ } catch (error) {
+ notify(error instanceof Error ? error.message : "API 地址无效");
+ }
+ }
+ }
+
+ const receive = (event: MessageEvent) => {
+ if (
+ event.origin !== window.location.origin ||
+ event.source !== iframe?.contentWindow ||
+ !isPageMessage(event.data) ||
+ event.data.view !== view()
+ ) {
+ return;
+ }
+ if (event.data.type === "ready") {
+ setFrameReady(true);
+ if (iframe?.contentWindow) sendState(iframe.contentWindow, state());
+ return;
+ }
+ void handleCommand(event.data.command);
+ };
+
+ const popState = () => {
+ const requested = new URLSearchParams(window.location.search).get("view");
+ navigate(isView(requested) ? requested : "overview", false);
+ };
+
+ onMount(() => {
+ window.addEventListener("message", receive);
+ window.addEventListener("popstate", popState);
+ void refresh();
+ const interval = window.setInterval(() => void refresh(), 5000);
+ onCleanup(() => window.clearInterval(interval));
+ });
+
+ onCleanup(() => {
+ window.removeEventListener("message", receive);
+ window.removeEventListener("popstate", popState);
+ if (toastTimer !== undefined) window.clearTimeout(toastTimer);
+ });
+
+ createEffect(() => {
+ const next = state();
+ if (frameReady() && iframe?.contentWindow) sendState(iframe.contentWindow, next);
+ });
+
+ async function register(file: File) {
+ setDialogBusy(true);
+ try {
+ const registered = await registerComponent(apiBase(), file);
+ await refresh();
+ setDialog(null);
+ notify(`${registered.id}@${registered.revision} 已注册`);
+ } finally {
+ setDialogBusy(false);
+ }
+ }
+
+ async function publishWit(file: File) {
+ setDialogBusy(true);
+ try {
+ const published = await publishWitPackage(apiBase(), file);
+ await refresh();
+ setDialog(null);
+ notify(`${published.name}@${published.version} 已发布`);
+ } finally {
+ setDialogBusy(false);
+ }
+ }
+
+ async function activate(service: Service) {
+ setDialogBusy(true);
+ setDeploymentAction(serviceKey(service));
+ try {
+ await activateDeployment(apiBase(), service);
+ await refresh();
+ setDialog(null);
+ notify(`${service.id}@${service.revision} 已设为对外版本`);
+ } finally {
+ setDialogBusy(false);
+ setDeploymentAction(null);
+ }
+ }
+
+ async function invoke(service: Service, input: Uint8Array): Promise {
+ const result = await invokeComponent(apiBase(), service, input);
+ await refresh();
+ return result;
+ }
+
+ return (
+
+
+
+
+
+
+
+ {(source) => (
+
+
+
+
+
+
+
+ 管理 API 不可用
+
+
+
+
+
+
+
+ {(activeDialog) => (
+ !dialogBusy() && setDialog(null)}
+ onRegister={register}
+ onPublishWit={publishWit}
+ onActivate={activate}
+ onInvoke={invoke}
+ />
+ )}
+
+
+
+ {(message) => (
+
+ {message()}
+
+ )}
+
+
+ );
+}
+
+function initialView(): View {
+ const requested = new URLSearchParams(window.location.search).get("view");
+ return isView(requested) ? requested : "overview";
+}
diff --git a/crates/wasmeld-console/web/src/host/dialogs.tsx b/crates/wasmeld-console/web/src/host/dialogs.tsx
new file mode 100644
index 0000000..a3bee76
--- /dev/null
+++ b/crates/wasmeld-console/web/src/host/dialogs.tsx
@@ -0,0 +1,357 @@
+import {
+ ArrowRight,
+ Clock3,
+ CloudUpload,
+ FileCode2,
+ Package,
+ Play,
+ RadioTower,
+ RefreshCw,
+ ShieldCheck,
+ SquareTerminal,
+ X,
+} from "lucide-solid";
+import { createMemo, createSignal, onCleanup, onMount, Show, type JSXElement } from "solid-js";
+import type { InvokeResult } from "../lib/api";
+import {
+ formatInvocationOutput,
+ invocationInputSize,
+ parseInvocationInput,
+ type Service,
+} from "../lib/model";
+
+export type DialogState =
+ | { type: "register" }
+ | { type: "wit-publish" }
+ | { type: "invoke"; service: Service }
+ | { type: "activate"; service: Service; currentRevision: string | null };
+
+export function DialogLayer(props: {
+ dialog: DialogState;
+ busy: boolean;
+ onClose: () => void;
+ onRegister: (file: File) => Promise;
+ onPublishWit: (file: File) => Promise;
+ onInvoke: (service: Service, input: Uint8Array) => Promise;
+ onActivate: (service: Service) => Promise;
+}) {
+ return (
+ <>
+
+
+
+
+
+
+
+ ).service}
+ onClose={props.onClose}
+ onInvoke={props.onInvoke}
+ />
+
+
+ }
+ busy={props.busy}
+ onClose={props.onClose}
+ onActivate={props.onActivate}
+ />
+
+ >
+ );
+}
+
+function DialogFrame(props: {
+ title: string;
+ description: string;
+ icon: JSXElement;
+ closeDisabled?: boolean;
+ onClose: () => void;
+ children: JSXElement;
+ footer: JSXElement;
+}) {
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (event.key === "Escape" && !props.closeDisabled) props.onClose();
+ };
+ onMount(() => window.addEventListener("keydown", onKeyDown));
+ onCleanup(() => window.removeEventListener("keydown", onKeyDown));
+
+ return (
+
+
+
+ );
+}
+
+function UploadDialog(props: {
+ kind: "component" | "wit";
+ busy: boolean;
+ onClose: () => void;
+ onSubmit: (file: File) => Promise;
+}) {
+ const [file, setFile] = createSignal(null);
+ const [error, setError] = createSignal("");
+ const isWit = () => props.kind === "wit";
+ const title = () => (isWit() ? "发布 WIT 包" : "注册组件包");
+
+ async function submit() {
+ const selected = file();
+ if (!selected || props.busy) return;
+ const extension = isWit() ? ".wasm" : ".wasmpkg";
+ const limit = isWit() ? 4 * 1024 * 1024 : 64 * 1024 * 1024;
+ if (!selected.name.toLowerCase().endsWith(extension)) {
+ setError(`请选择 ${extension} 文件`);
+ return;
+ }
+ if (selected.size > limit) {
+ setError(`文件不能超过 ${isWit() ? "4 MB" : "64 MB"}`);
+ return;
+ }
+ setError("");
+ await props.onSubmit(selected).catch((submitError: unknown) => {
+ setError(submitError instanceof Error ? submitError.message : `${title()}失败`);
+ });
+ }
+
+ return (
+ : }
+ closeDisabled={props.busy}
+ onClose={props.onClose}
+ footer={
+ <>
+
+
+ >
+ }
+ >
+
+
+ {error()}
+
+
+ );
+}
+
+function ActivateDialog(props: {
+ dialog: Extract;
+ busy: boolean;
+ onClose: () => void;
+ onActivate: (service: Service) => Promise;
+}) {
+ return (
+ }
+ closeDisabled={props.busy}
+ onClose={props.onClose}
+ footer={
+ <>
+
+
+ >
+ }
+ >
+
+
+ 当前版本
+ {props.dialog.currentRevision ?? "尚未部署"}
+
+
+
+ 目标版本
+ {props.dialog.service.revision}
+
+
+
+ Wasmeld 将先确认 {props.dialog.service.id}@{props.dialog.service.revision} 的 Actor
+ 可用,再更新对外路由。
+
+
+ );
+}
+
+function InvokeDialog(props: {
+ service: Service;
+ onClose: () => void;
+ onInvoke: (service: Service, input: Uint8Array) => Promise;
+}) {
+ const [input, setInput] = createSignal(props.service.id === "echo" ? "hello wasm" : "");
+ const [format, setFormat] = createSignal<"utf8" | "hex">("utf8");
+ const [output, setOutput] = createSignal("");
+ const [outputMeta, setOutputMeta] = createSignal("");
+ const [running, setRunning] = createSignal(false);
+ const [failed, setFailed] = createSignal(false);
+ const inputBytes = createMemo(() => invocationInputSize(input(), format()));
+
+ async function invoke() {
+ setRunning(true);
+ setOutput("");
+ setOutputMeta("");
+ setFailed(false);
+ try {
+ const result = await props.onInvoke(props.service, parseInvocationInput(input(), format()));
+ const formatted = formatInvocationOutput(props.service, result.output, format());
+ setOutput(formatted.text);
+ setOutputMeta(
+ `${result.outputBytes} B · ${formatted.format}${formatted.automatic ? " · 自动" : ""} · ${result.latencyMs} ms`,
+ );
+ } catch (error) {
+ setFailed(true);
+ setOutput(error instanceof Error ? error.message : "组件调用失败");
+ } finally {
+ setRunning(false);
+ }
+ }
+
+ return (
+ }
+ closeDisabled={running()}
+ onClose={props.onClose}
+ footer={
+ <>
+
+
+ >
+ }
+ >
+
+
+
+
+
+
{inputBytes()} B
+
+
+
+
+ 输出
+
+
+
+ {outputMeta()}
+
+
+
+
+ {running() ? "invoking..." : output() || "等待调用"}
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/host/main.tsx b/crates/wasmeld-console/web/src/host/main.tsx
new file mode 100644
index 0000000..bbe6cbf
--- /dev/null
+++ b/crates/wasmeld-console/web/src/host/main.tsx
@@ -0,0 +1,13 @@
+import { render } from "solid-js/web";
+import "../styles/app.css";
+import HostApp from "./app";
+
+const root = document.getElementById("app");
+if (!root) throw new Error("missing #app root");
+render(() => , root);
+
+if (import.meta.env.PROD && "serviceWorker" in navigator) {
+ window.addEventListener("load", () => {
+ void navigator.serviceWorker.register("/sw.js");
+ });
+}
diff --git a/console/src/api.ts b/crates/wasmeld-console/web/src/lib/api.ts
similarity index 66%
rename from console/src/api.ts
rename to crates/wasmeld-console/web/src/lib/api.ts
index 7f0215a..7d3dcab 100644
--- a/console/src/api.ts
+++ b/crates/wasmeld-console/web/src/lib/api.ts
@@ -1,13 +1,13 @@
/**
- * Typed management-plane client for `wasmeld-console`.
+ * Typed client for the Rust management API.
*
- * These DTOs intentionally preserve the Rust API's snake_case fields; view
- * formatting belongs in `console-model.ts`. Management invocation bytes use
- * base64 inside JSON for inspectability. Public clients should call the
- * gateway's `application/octet-stream` endpoint instead.
+ * Production uses a same-origin base so the embedded Console follows the
+ * address used to open it. Vite development keeps the existing local backend
+ * default and relies on Wasmeld's development CORS policy.
*/
-export const DEFAULT_API_BASE = import.meta.env.VITE_WASMELD_API_URL ?? "http://127.0.0.1:8080";
+export const DEFAULT_API_BASE =
+ import.meta.env.VITE_WASMELD_API_URL ?? (import.meta.env.DEV ? "http://127.0.0.1:8080" : "");
const API_BASE_STORAGE_KEY = "wasmeld-api-base";
@@ -78,8 +78,12 @@ export type BackendWitPackage = {
dependencies: BackendWitDependency[];
};
-export type RegisterComponentInput = {
- file: File;
+export type BackendSnapshot = {
+ services: BackendService[];
+ deployments: BackendDeployment[];
+ events: BackendEvent[];
+ runtime: BackendRuntime;
+ witPackages: BackendWitPackage[];
};
export type InvokeResult = {
@@ -89,14 +93,20 @@ export type InvokeResult = {
};
export function getApiBase(): string {
- // TanStack Start can evaluate modules during SSR, where localStorage does
- // not exist. The environment default keeps server rendering deterministic.
if (typeof window === "undefined") return DEFAULT_API_BASE;
return window.localStorage.getItem(API_BASE_STORAGE_KEY) ?? DEFAULT_API_BASE;
}
+export function displayApiBase(value: string): string {
+ return value || (typeof window === "undefined" ? "same origin" : window.location.origin);
+}
+
export function saveApiBase(value: string): string {
const normalized = value.trim().replace(/\/+$/, "");
+ if (!normalized) {
+ window.localStorage.removeItem(API_BASE_STORAGE_KEY);
+ return "";
+ }
const parsed = new URL(normalized);
if (!["http:", "https:"].includes(parsed.protocol)) {
throw new Error("API 地址必须使用 http 或 https");
@@ -105,10 +115,7 @@ export function saveApiBase(value: string): string {
return normalized;
}
-export async function fetchSnapshot(apiBase: string) {
- // Parallel reads minimize refresh latency but are not a database
- // transaction. A deployment can change between responses; the five-second
- // poll in the route reconciles that short-lived inconsistency.
+export async function fetchSnapshot(apiBase: string): Promise {
const [services, deployments, events, runtime, witPackages] = await Promise.all([
request<{ services: BackendService[] }>(apiBase, "/api/v1/services"),
request<{ deployments: BackendDeployment[] }>(apiBase, "/api/v1/deployments"),
@@ -125,30 +132,27 @@ export async function fetchSnapshot(apiBase: string) {
};
}
-export async function activateDeployment(
+export function activateDeployment(
apiBase: string,
service: Pick,
): Promise {
- return request(apiBase, `/api/v1/deployments/${encodeURIComponent(service.id)}/activate`, {
+ return request(apiBase, `/api/v1/deployments/${segment(service.id)}/activate`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ revision: service.revision }),
});
}
-export async function registerComponent(
- apiBase: string,
- input: RegisterComponentInput,
-): Promise {
+export function registerComponent(apiBase: string, file: File): Promise {
const form = new FormData();
- form.set("package", input.file, input.file.name);
+ form.set("package", file, file.name);
return request(apiBase, "/api/v1/services", {
method: "POST",
body: form,
});
}
-export async function publishWitPackage(apiBase: string, file: File): Promise {
+export function publishWitPackage(apiBase: string, file: File): Promise {
const form = new FormData();
form.set("package", file, file.name);
return request(apiBase, "/api/v1/wit/packages", {
@@ -162,17 +166,17 @@ export function witPackageDownloadUrl(
packageMetadata: Pick,
): string {
const [namespace, name] = packageMetadata.name.split(":");
- return `${apiBase}/api/v1/wit/packages/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}/${encodeURIComponent(packageMetadata.version)}/content`;
+ return `${apiBase}/api/v1/wit/packages/${segment(namespace)}/${segment(name)}/${segment(packageMetadata.version)}/content`;
}
-export async function changeServiceState(
+export function changeServiceState(
apiBase: string,
service: Pick,
action: "start" | "stop" | "restart",
): Promise {
return request(
apiBase,
- `/api/v1/services/${encodeURIComponent(service.id)}/${encodeURIComponent(service.revision)}/${action}`,
+ `/api/v1/services/${segment(service.id)}/${segment(service.revision)}/${action}`,
{
method: "POST",
headers: { "content-type": "application/json" },
@@ -181,13 +185,11 @@ export async function changeServiceState(
);
}
-export async function changeRuntimeState(
+export function changeRuntimeState(
apiBase: string,
action: "start" | "stop" | "restart",
): Promise {
- return request(apiBase, `/api/v1/runtime/${action}`, {
- method: "POST",
- });
+ return request(apiBase, `/api/v1/runtime/${action}`, { method: "POST" });
}
export async function invokeComponent(
@@ -195,22 +197,15 @@ export async function invokeComponent(
service: Pick,
input: Uint8Array,
): Promise {
- // Example: `invokeComponent(base, service, new TextEncoder().encode("ping"))`.
- // The management endpoint targets an exact revision and is intended for the
- // operator console, not public application traffic.
const response = await request<{
output_base64: string;
output_bytes: number;
latency_ms: number;
- }>(
- apiBase,
- `/api/v1/services/${encodeURIComponent(service.id)}/${encodeURIComponent(service.revision)}/invoke`,
- {
- method: "POST",
- headers: { "content-type": "application/json" },
- body: JSON.stringify({ input_base64: bytesToBase64(input) }),
- },
- );
+ }>(apiBase, `/api/v1/services/${segment(service.id)}/${segment(service.revision)}/invoke`, {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ input_base64: bytesToBase64(input) }),
+ });
return {
output: base64ToBytes(response.output_base64),
outputBytes: response.output_bytes,
@@ -229,13 +224,10 @@ async function request(apiBase: string, path: string, init?: RequestInit): Pr
},
});
} catch {
- throw new Error(`无法连接 Wasmeld:${apiBase}`);
+ throw new Error(`无法连接 Wasmeld:${displayApiBase(apiBase)}`);
}
if (!response.ok) {
- // Both management and gateway errors use `{ error: { code, message } }`.
- // The UI displays only the server-safe message and falls back to status
- // when a proxy returns HTML or an otherwise unrelated response.
const body = (await response.json().catch(() => null)) as {
error?: { message?: string };
} | null;
@@ -244,9 +236,11 @@ async function request(apiBase: string, path: string, init?: RequestInit): Pr
return (await response.json()) as T;
}
+function segment(value: string): string {
+ return encodeURIComponent(value);
+}
+
function bytesToBase64(bytes: Uint8Array): string {
- // Invocation input is bounded by the Runtime, so constructing this binary
- // string cannot grow beyond the configured management request limit.
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return window.btoa(binary);
diff --git a/console/src/console-model.ts b/crates/wasmeld-console/web/src/lib/model.ts
similarity index 65%
rename from console/src/console-model.ts
rename to crates/wasmeld-console/web/src/lib/model.ts
index e8ead6c..8ff853f 100644
--- a/console/src/console-model.ts
+++ b/crates/wasmeld-console/web/src/lib/model.ts
@@ -1,23 +1,24 @@
-/**
- * Pure conversion and presentation helpers for the management UI.
- *
- * No function in this module performs I/O or changes backend state. Keeping
- * byte decoding here prevents React views from silently treating arbitrary
- * Component output as readable text.
- */
+import type { BackendEvent, BackendService } from "./api";
-import { FileCode2, History, LayoutDashboard, Package, Server, Settings } from "lucide-react";
-import { BackendCapability, BackendEvent, BackendService } from "./api";
+export const VIEWS = [
+ "overview",
+ "services",
+ "instances",
+ "wit-packages",
+ "activity",
+ "settings",
+] as const;
-export type View = "overview" | "services" | "instances" | "wit-packages" | "activity" | "settings";
+export type View = (typeof VIEWS)[number];
+export type ConnectionState = "connecting" | "online" | "offline";
export type ServiceStatus = "running" | "stopped" | "faulted";
export type EventTone = "success" | "warning" | "danger" | "neutral";
export type Service = {
id: string;
revision: string;
- description: string;
artifact: string;
+ world: string;
status: ServiceStatus;
updatedAt: string;
memoryMb: number;
@@ -25,7 +26,7 @@ export type Service = {
deadlineMs: number;
mailbox: number;
maxInputKb: number;
- capabilities: BackendCapability[];
+ capabilities: BackendService["capabilities"];
calls: number;
errors: number;
latencyMs: number | null;
@@ -40,20 +41,11 @@ export type RuntimeEvent = {
tone: EventTone;
};
-export type ConnectionState = "connecting" | "online" | "offline";
-
-export const NAV_ITEMS: Array<{
- id: View;
- label: string;
- icon: typeof LayoutDashboard;
-}> = [
- { id: "overview", label: "运行概览", icon: LayoutDashboard },
- { id: "services", label: "服务版本", icon: Package },
- { id: "instances", label: "运行实例", icon: Server },
- { id: "wit-packages", label: "WIT 包", icon: FileCode2 },
- { id: "activity", label: "调用记录", icon: History },
- { id: "settings", label: "运行设置", icon: Settings },
-];
+export type FormattedInvocationOutput = {
+ text: string;
+ format: "UTF-8" | "HEX" | "U64 LE";
+ automatic: boolean;
+};
export const STATUS_META: Record = {
running: { label: "运行中", className: "status-running" },
@@ -61,7 +53,11 @@ export const STATUS_META: Record) {
+export function isView(value: string | null): value is View {
+ return VIEWS.includes(value as View);
+}
+
+export function serviceKey(service: Pick): string {
return `${service.id}@${service.revision}`;
}
@@ -69,12 +65,10 @@ export function toService(service: BackendService, activeRevision?: string): Ser
return {
id: service.id,
revision: service.revision,
- description: "Wasm Component",
artifact: service.artifact.split(/[\\/]/).pop() ?? service.artifact,
+ world: service.world,
status: service.status,
- updatedAt: new Date(service.updated_at_ms).toLocaleString("zh-CN", {
- hour12: false,
- }),
+ updatedAt: new Date(service.updated_at_ms).toLocaleString("zh-CN", { hour12: false }),
memoryMb: Math.round(service.limits.memory_bytes / 1024 / 1024),
fuel: compactNumber(service.limits.fuel_per_call),
deadlineMs: service.limits.deadline_ms,
@@ -102,22 +96,20 @@ export function toEvent(event: BackendEvent): RuntimeEvent {
};
return {
id: event.id,
- time: new Date(event.timestamp_ms).toLocaleTimeString("zh-CN", {
- hour12: false,
- }),
+ time: new Date(event.timestamp_ms).toLocaleTimeString("zh-CN", { hour12: false }),
title: `${identity} ${meta[event.kind].label}`,
detail: event.message,
tone: meta[event.kind].tone,
};
}
-export function compactNumber(value: number) {
+export function compactNumber(value: number): string {
if (value >= 1_000_000) return `${value / 1_000_000}M`;
if (value >= 1_000) return `${value / 1_000}K`;
return value.toString();
}
-export function formatDuration(milliseconds: number) {
+export function formatDuration(milliseconds: number): string {
const totalSeconds = Math.floor(milliseconds / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
@@ -125,15 +117,7 @@ export function formatDuration(milliseconds: number) {
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m ${seconds}s`;
}
-export function formatApiHost(value: string) {
- try {
- return new URL(value).host;
- } catch {
- return value;
- }
-}
-
-export function parseInvocationInput(value: string, format: "utf8" | "hex") {
+export function parseInvocationInput(value: string, format: "utf8" | "hex"): Uint8Array {
if (format === "utf8") return new TextEncoder().encode(value);
const compact = value.replace(/\s+/g, "");
if (compact.length % 2 !== 0 || /[^0-9a-f]/i.test(compact)) {
@@ -142,7 +126,7 @@ export function parseInvocationInput(value: string, format: "utf8" | "hex") {
return Uint8Array.from(compact.match(/.{2}/g)?.map((byte) => Number.parseInt(byte, 16)) ?? []);
}
-export function invocationInputSize(value: string, format: "utf8" | "hex") {
+export function invocationInputSize(value: string, format: "utf8" | "hex"): number {
try {
return parseInvocationInput(value, format).byteLength;
} catch {
@@ -150,45 +134,11 @@ export function invocationInputSize(value: string, format: "utf8" | "hex") {
}
}
-export type FormattedInvocationOutput = {
- text: string;
- format: "UTF-8" | "HEX" | "U64 LE";
- automatic: boolean;
-};
-
-export function formatHex(bytes: Uint8Array) {
- return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(" ");
-}
-
-export function decodeReadableUtf8(bytes: Uint8Array) {
- let text: string;
- try {
- text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
- } catch {
- return null;
- }
-
- // Valid UTF-8 can still contain terminal controls. Reject them so the output
- // panel cannot render invisible or misleading content; tab/newline/CR remain
- // useful for ordinary textual responses.
- for (const character of text) {
- const codePoint = character.codePointAt(0) ?? 0;
- const allowedWhitespace = codePoint === 0x09 || codePoint === 0x0a || codePoint === 0x0d;
- if ((codePoint < 0x20 && !allowedWhitespace) || codePoint === 0x7f) {
- return null;
- }
- }
- return text;
-}
-
export function formatInvocationOutput(
service: Service,
output: Uint8Array,
format: "utf8" | "hex",
-) {
- // Counter is the one built-in example with a documented numeric wire
- // format. Other eight-byte services remain generic bytes and are not
- // guessed as integers.
+): FormattedInvocationOutput {
if (service.id === "counter" && output.byteLength === 8) {
return {
text: new DataView(output.buffer, output.byteOffset, output.byteLength)
@@ -196,29 +146,33 @@ export function formatInvocationOutput(
.toString(),
format: "U64 LE",
automatic: false,
- } satisfies FormattedInvocationOutput;
+ };
}
if (format === "hex") {
- return {
- text: formatHex(output) || "(empty)",
- format: "HEX",
- automatic: false,
- } satisfies FormattedInvocationOutput;
+ return { text: formatHex(output) || "(empty)", format: "HEX", automatic: false };
}
-
- // UTF-8 decoding is fatal rather than replacement-based. If one byte is
- // invalid or contains a disallowed control, show the exact bytes as HEX.
const text = decodeReadableUtf8(output);
if (text !== null) {
- return {
- text: text || "(empty)",
- format: "UTF-8",
- automatic: false,
- } satisfies FormattedInvocationOutput;
+ return { text: text || "(empty)", format: "UTF-8", automatic: false };
}
- return {
- text: formatHex(output),
- format: "HEX",
- automatic: true,
- } satisfies FormattedInvocationOutput;
+ return { text: formatHex(output), format: "HEX", automatic: true };
+}
+
+function formatHex(bytes: Uint8Array): string {
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(" ");
+}
+
+function decodeReadableUtf8(bytes: Uint8Array): string | null {
+ let text: string;
+ try {
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
+ } catch {
+ return null;
+ }
+ for (const character of text) {
+ const codePoint = character.codePointAt(0) ?? 0;
+ const allowedWhitespace = codePoint === 0x09 || codePoint === 0x0a || codePoint === 0x0d;
+ if ((codePoint < 0x20 && !allowedWhitespace) || codePoint === 0x7f) return null;
+ }
+ return text;
}
diff --git a/crates/wasmeld-console/web/src/lib/view-state.ts b/crates/wasmeld-console/web/src/lib/view-state.ts
new file mode 100644
index 0000000..cde0c71
--- /dev/null
+++ b/crates/wasmeld-console/web/src/lib/view-state.ts
@@ -0,0 +1,17 @@
+import type { HostSharedState } from "../sdk/protocol";
+import { toEvent, toService, type RuntimeEvent, type Service } from "./model";
+
+export function servicesFrom(state: HostSharedState | null): Service[] {
+ if (!state?.snapshot) return [];
+ const deployments = new Map(
+ state.snapshot.deployments.map((deployment) => [
+ deployment.service_id,
+ deployment.active_revision,
+ ]),
+ );
+ return state.snapshot.services.map((service) => toService(service, deployments.get(service.id)));
+}
+
+export function eventsFrom(state: HostSharedState | null): RuntimeEvent[] {
+ return state?.snapshot?.events.map(toEvent) ?? [];
+}
diff --git a/crates/wasmeld-console/web/src/pages/activity/index.tsx b/crates/wasmeld-console/web/src/pages/activity/index.tsx
new file mode 100644
index 0000000..1db4ea0
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/activity/index.tsx
@@ -0,0 +1,61 @@
+import { History, RefreshCw } from "lucide-solid";
+import { createMemo, For, Show } from "solid-js";
+import { EmptyState } from "../../components/ui/empty-state";
+import { PageHeading } from "../../components/ui/page-heading";
+import { eventsFrom } from "../../lib/view-state";
+import type { PageProps } from "../types";
+
+const toneClass = {
+ success: "bg-brand",
+ warning: "bg-amber-strong",
+ danger: "bg-coral-strong",
+ neutral: "bg-muted",
+};
+
+export default function ActivityPage(props: PageProps) {
+ const events = createMemo(() => {
+ const query = props.state()?.query.trim().toLowerCase() ?? "";
+ return eventsFrom(props.state()).filter(
+ (event) =>
+ !query ||
+ event.title.toLowerCase().includes(query) ||
+ event.detail.toLowerCase().includes(query),
+ );
+ });
+
+ return (
+
+ props.command({ type: "refresh" })}>
+
+
+ }
+ />
+
+ 0}
+ fallback={
+
+ }
+ >
+
+
+ {(event) => (
+
+
+ {event.title}
+ {event.detail}
+
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/pages/instances/index.tsx b/crates/wasmeld-console/web/src/pages/instances/index.tsx
new file mode 100644
index 0000000..1d3e3dd
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/instances/index.tsx
@@ -0,0 +1,108 @@
+import { Cpu, RefreshCw, Server, SquareTerminal } from "lucide-solid";
+import { createMemo, For, Show } from "solid-js";
+import { EmptyState } from "../../components/ui/empty-state";
+import { PageHeading } from "../../components/ui/page-heading";
+import { StatusBadge } from "../../components/ui/status-badge";
+import { serviceKey } from "../../lib/model";
+import { servicesFrom } from "../../lib/view-state";
+import type { PageProps } from "../types";
+
+export default function InstancesPage(props: PageProps) {
+ const services = createMemo(() => servicesFrom(props.state()));
+ const running = createMemo(
+ () => services().filter((service) => service.status === "running").length,
+ );
+
+ return (
+
+ props.command({ type: "refresh" })}>
+
+
+ }
+ />
+ 0}
+ fallback={
+
+
+
+ }
+ >
+
+
+ {(service) => (
+
+
+
+
+
+
+
+ {service.id}
+ {service.revision}
+
+
+
+
+
+
+
- 内存上限
+ - {service.memoryMb} MB
+
+
+
- Mailbox
+ - {service.mailbox}
+
+
+
- Deadline
+ - {service.deadlineMs} ms
+
+
+
- 最近延迟
+ -
+ {service.latencyMs === null ? "—" : `${service.latencyMs} ms`}
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/pages/main.tsx b/crates/wasmeld-console/web/src/pages/main.tsx
new file mode 100644
index 0000000..da75390
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/main.tsx
@@ -0,0 +1,59 @@
+import { AlertTriangle, LoaderCircle } from "lucide-solid";
+import { lazy, Show, Suspense, type Component } from "solid-js";
+import { render } from "solid-js/web";
+import { isView, type View } from "../lib/model";
+import { createFrameBridge } from "../primitives/create-frame-bridge";
+import "../styles/app.css";
+import type { PageProps } from "./types";
+
+// Each view is a dynamic import so a freshly-created iframe evaluates only the
+// page it owns. Destroying that iframe releases the chunk's runtime objects.
+const pages: Record> = {
+ overview: lazy(() => import("./overview")),
+ services: lazy(() => import("./services")),
+ instances: lazy(() => import("./instances")),
+ "wit-packages": lazy(() => import("./wit-packages")),
+ activity: lazy(() => import("./activity")),
+ settings: lazy(() => import("./settings")),
+};
+
+function FramePage() {
+ const requested = new URLSearchParams(window.location.search).get("view");
+ const view = isView(requested) ? requested : null;
+
+ return (
+
+
+
+
未知页面
+
{requested ?? "(empty)"}
+
+
+ }
+ >
+ {(activeView) => {
+ const bridge = createFrameBridge(activeView());
+ const Page = pages[activeView()];
+ document.title = `${activeView()} · Wasmeld`;
+ return (
+
+
+
+ }
+ >
+
+
+ );
+ }}
+
+ );
+}
+
+const root = document.getElementById("app");
+if (!root) throw new Error("missing #app root");
+render(() => , root);
diff --git a/crates/wasmeld-console/web/src/pages/overview/index.tsx b/crates/wasmeld-console/web/src/pages/overview/index.tsx
new file mode 100644
index 0000000..5f1f36b
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/overview/index.tsx
@@ -0,0 +1,258 @@
+import {
+ Activity,
+ AlertTriangle,
+ CircleStop,
+ CloudUpload,
+ Cpu,
+ Package,
+ Play,
+ RefreshCw,
+ RotateCcw,
+ Zap,
+} from "lucide-solid";
+import { createMemo, For, Show, type JSXElement } from "solid-js";
+import { PageHeading } from "../../components/ui/page-heading";
+import { ServiceTable } from "../../components/ui/service-table";
+import { eventsFrom, servicesFrom } from "../../lib/view-state";
+import { formatDuration } from "../../lib/model";
+import type { PageProps } from "../types";
+
+export default function OverviewPage(props: PageProps) {
+ const services = createMemo(() => servicesFrom(props.state()));
+ const events = createMemo(() => eventsFrom(props.state()));
+ const running = createMemo(
+ () => services().filter((service) => service.status === "running").length,
+ );
+ const totalCalls = createMemo(() =>
+ services().reduce((total, service) => total + service.calls, 0),
+ );
+ const errors = createMemo(() => services().reduce((total, service) => total + service.errors, 0));
+
+ return (
+
+ }>
+ {(state) => (
+ <>
+
+
+
+ >
+ }
+ />
+
+
+ }
+ tone="bg-cyan-soft text-cyan-strong"
+ label="服务版本"
+ value={services().length.toString()}
+ note={`${state().snapshot?.deployments.length ?? 0} 个对外服务`}
+ />
+ }
+ tone="bg-brand-soft text-brand"
+ label="运行实例"
+ value={running().toString()}
+ note={`${services().length - running()} 个未运行`}
+ />
+ }
+ tone="bg-amber-soft text-amber-strong"
+ label="累计调用"
+ value={totalCalls().toLocaleString("zh-CN")}
+ note="持久化统计"
+ />
+ }
+ tone="bg-coral-soft text-coral-strong"
+ label="调用异常"
+ value={errors().toString()}
+ note={errors() > 0 ? "需要检查" : "无异常"}
+ />
+
+
+
+
+
+
+
+
+ Wasmeld Runtime
+
+ {state().snapshot?.runtime.status === "running"
+ ? "Wasmtime sandbox 正常"
+ : "Engine 与 Actor 已释放"}
+
+
+
+
props.command({ type: "runtime-action", action: "start" })}
+ >
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ );
+}
+
+function Metric(props: {
+ icon: JSXElement;
+ tone: string;
+ label: string;
+ value: string;
+ note: string;
+}) {
+ return (
+
+ {props.icon}
+
+ {props.label}
+ {props.value}
+
+ {props.note}
+
+ );
+}
+
+function RuntimeStat(props: { label: string; value: string; detail: string }) {
+ return (
+
+ {props.label}
+ {props.value}
+ {props.detail}
+
+ );
+}
+
+function OverviewSkeleton() {
+ return (
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/pages/services/index.tsx b/crates/wasmeld-console/web/src/pages/services/index.tsx
new file mode 100644
index 0000000..f6f8327
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/services/index.tsx
@@ -0,0 +1,76 @@
+import { CloudUpload, Filter, RefreshCw } from "lucide-solid";
+import { createMemo, createSignal, Show } from "solid-js";
+import { PageHeading } from "../../components/ui/page-heading";
+import { ServiceTable } from "../../components/ui/service-table";
+import { servicesFrom } from "../../lib/view-state";
+import type { ServiceStatus } from "../../lib/model";
+import type { PageProps } from "../types";
+
+export default function ServicesPage(props: PageProps) {
+ const [status, setStatus] = createSignal<"all" | ServiceStatus>("all");
+ const services = createMemo(() => servicesFrom(props.state()));
+ const filtered = createMemo(() => {
+ const query = props.state()?.query.trim().toLowerCase() ?? "";
+ return services().filter(
+ (service) =>
+ (status() === "all" || service.status === status()) &&
+ (!query ||
+ service.id.toLowerCase().includes(query) ||
+ service.revision.toLowerCase().includes(query) ||
+ service.artifact.toLowerCase().includes(query)),
+ );
+ });
+
+ return (
+
+
+
+
+ >
+ }
+ />
+
+
+
+ {(state) => (
+
+ )}
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/pages/settings/index.tsx b/crates/wasmeld-console/web/src/pages/settings/index.tsx
new file mode 100644
index 0000000..993dcdc
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/settings/index.tsx
@@ -0,0 +1,88 @@
+import { Database, Globe2, Save, ShieldCheck } from "lucide-solid";
+import { createEffect, createSignal } from "solid-js";
+import { displayApiBase } from "../../lib/api";
+import { PageHeading } from "../../components/ui/page-heading";
+import type { PageProps } from "../types";
+
+export default function SettingsPage(props: PageProps) {
+ const [endpoint, setEndpoint] = createSignal("");
+ let initialized = false;
+ createEffect(() => {
+ const state = props.state();
+ if (state && !initialized) {
+ setEndpoint(state.apiBase);
+ initialized = true;
+ }
+ });
+
+ return (
+
+
+
+
+ );
+}
+
+function Info(props: { icon: typeof ShieldCheck; title: string; detail: string }) {
+ const Icon = props.icon;
+ return (
+
+
+
+
+
+
{props.title}
+
{props.detail}
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/pages/types.ts b/crates/wasmeld-console/web/src/pages/types.ts
new file mode 100644
index 0000000..00e7cae
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/types.ts
@@ -0,0 +1,7 @@
+import type { Accessor } from "solid-js";
+import type { HostSharedState, PageCommand } from "../sdk/protocol";
+
+export type PageProps = {
+ state: Accessor;
+ command: (command: PageCommand) => void;
+};
diff --git a/crates/wasmeld-console/web/src/pages/wit-packages/index.tsx b/crates/wasmeld-console/web/src/pages/wit-packages/index.tsx
new file mode 100644
index 0000000..28f06c8
--- /dev/null
+++ b/crates/wasmeld-console/web/src/pages/wit-packages/index.tsx
@@ -0,0 +1,105 @@
+import { CloudUpload, Download, FileCode2, Search } from "lucide-solid";
+import { createMemo, For, Show } from "solid-js";
+import { EmptyState } from "../../components/ui/empty-state";
+import { PageHeading } from "../../components/ui/page-heading";
+import { witPackageDownloadUrl } from "../../lib/api";
+import type { PageProps } from "../types";
+
+export default function WitPackagesPage(props: PageProps) {
+ const packages = createMemo(() => {
+ const state = props.state();
+ const query = state?.query.trim().toLowerCase() ?? "";
+ return (
+ state?.snapshot?.witPackages.filter(
+ (item) =>
+ !query ||
+ item.name.toLowerCase().includes(query) ||
+ item.version.toLowerCase().includes(query) ||
+ item.sha256.toLowerCase().includes(query),
+ ) ?? []
+ );
+ });
+
+ return (
+
+ props.command({ type: "open-wit-publish" })}
+ >
+
+ 发布 WIT 包
+
+ }
+ />
+
+
+ 0}
+ fallback={
+
+ }
+ >
+
+
+
+
+ | 包 |
+ 版本 |
+ 直接依赖 |
+ SHA-256 |
+
+ 下载
+ |
+
+
+
+
+ {(item) => (
+
+ |
+
+
+ {item.name}
+
+ |
+ {item.version} |
+
+ {item.dependencies.length
+ ? item.dependencies
+ .map((dependency) => `${dependency.name}@${dependency.version}`)
+ .join(", ")
+ : "无"}
+ |
+
+ {item.sha256}
+ |
+
+
+
+
+ |
+
+ )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/crates/wasmeld-console/web/src/primitives/create-frame-bridge.ts b/crates/wasmeld-console/web/src/primitives/create-frame-bridge.ts
new file mode 100644
index 0000000..6e32ee5
--- /dev/null
+++ b/crates/wasmeld-console/web/src/primitives/create-frame-bridge.ts
@@ -0,0 +1,40 @@
+import { createSignal, onCleanup, onMount } from "solid-js";
+import type { View } from "../lib/model";
+import { isHostMessage, type HostSharedState, type PageCommand } from "../sdk/protocol";
+import { notifyReady, sendCommand } from "../sdk/page";
+
+/**
+ * Connects one iframe document to the persistent Host Shell.
+ *
+ * The listener and state belong to the iframe's Solid owner. Navigating or
+ * removing the iframe runs `onCleanup`, so the old document cannot continue to
+ * receive Host snapshots.
+ */
+export function createFrameBridge(view: View) {
+ const [state, setState] = createSignal(null);
+
+ const receive = (event: MessageEvent) => {
+ if (event.origin !== window.location.origin || event.source !== window.parent) return;
+ if (!isHostMessage(event.data)) return;
+ if (event.data.type === "state" && event.data.state.view === view) {
+ setState(event.data.state);
+ }
+ if (event.data.type === "dispose") {
+ window.dispatchEvent(new Event("wasmeld:dispose"));
+ }
+ };
+
+ onMount(() => {
+ window.addEventListener("message", receive);
+ notifyReady(view);
+ });
+
+ onCleanup(() => window.removeEventListener("message", receive));
+
+ return {
+ state,
+ command(command: PageCommand) {
+ sendCommand(view, command);
+ },
+ };
+}
diff --git a/crates/wasmeld-console/web/src/sdk/host.ts b/crates/wasmeld-console/web/src/sdk/host.ts
new file mode 100644
index 0000000..5e1f7ba
--- /dev/null
+++ b/crates/wasmeld-console/web/src/sdk/host.ts
@@ -0,0 +1,32 @@
+import type { View } from "../lib/model";
+import { SDK_CHANNEL, SDK_VERSION, type HostMessage, type HostSharedState } from "./protocol";
+
+export function sendState(target: Window, state: HostSharedState): void {
+ send(target, {
+ channel: SDK_CHANNEL,
+ version: SDK_VERSION,
+ source: "host",
+ type: "state",
+ state,
+ });
+}
+
+export function disposePage(target: Window): void {
+ send(target, {
+ channel: SDK_CHANNEL,
+ version: SDK_VERSION,
+ source: "host",
+ type: "dispose",
+ });
+}
+
+export function pageUrl(view: View, instance: number): string {
+ const url = new URL("/page.html", window.location.origin);
+ url.searchParams.set("view", view);
+ url.searchParams.set("instance", instance.toString());
+ return `${url.pathname}${url.search}`;
+}
+
+function send(target: Window, message: HostMessage): void {
+ target.postMessage(message, window.location.origin);
+}
diff --git a/crates/wasmeld-console/web/src/sdk/page.ts b/crates/wasmeld-console/web/src/sdk/page.ts
new file mode 100644
index 0000000..ff4cbd3
--- /dev/null
+++ b/crates/wasmeld-console/web/src/sdk/page.ts
@@ -0,0 +1,27 @@
+import type { View } from "../lib/model";
+import { SDK_CHANNEL, SDK_VERSION, type PageCommand, type PageMessage } from "./protocol";
+
+export function notifyReady(view: View): void {
+ send({
+ channel: SDK_CHANNEL,
+ version: SDK_VERSION,
+ source: "page",
+ type: "ready",
+ view,
+ });
+}
+
+export function sendCommand(view: View, command: PageCommand): void {
+ send({
+ channel: SDK_CHANNEL,
+ version: SDK_VERSION,
+ source: "page",
+ type: "command",
+ view,
+ command,
+ });
+}
+
+function send(message: PageMessage): void {
+ window.parent.postMessage(message, window.location.origin);
+}
diff --git a/crates/wasmeld-console/web/src/sdk/protocol.ts b/crates/wasmeld-console/web/src/sdk/protocol.ts
new file mode 100644
index 0000000..dd1ba48
--- /dev/null
+++ b/crates/wasmeld-console/web/src/sdk/protocol.ts
@@ -0,0 +1,95 @@
+import type { BackendSnapshot } from "../lib/api";
+import type { ConnectionState, View } from "../lib/model";
+
+export const SDK_CHANNEL = "wasmeld-console";
+
+/**
+ * Compatibility version for the same-origin Host/Page document protocol.
+ *
+ * Additive optional messages may keep the version. Removing a field or
+ * changing its meaning requires a version bump and an atomic Host/Page
+ * release, which is naturally provided by the embedded Console binary.
+ */
+export const SDK_VERSION = 1;
+
+export type RuntimeAction = "start" | "stop" | "restart";
+export type ServiceAction = "start" | "stop" | "restart";
+
+export type HostSharedState = {
+ // This is a serializable snapshot, never a Solid signal crossing realms.
+ view: View;
+ snapshot: BackendSnapshot | null;
+ connection: ConnectionState;
+ query: string;
+ apiBase: string;
+ runtimeAction: RuntimeAction | null;
+ serviceAction: string | null;
+ deploymentAction: string | null;
+};
+
+export type PageCommand =
+ | { type: "refresh" }
+ | { type: "navigate"; view: View }
+ | { type: "open-register" }
+ | { type: "open-wit-publish" }
+ | { type: "open-invoke"; serviceKey: string }
+ | { type: "open-activate"; serviceKey: string }
+ | { type: "runtime-action"; action: RuntimeAction }
+ | { type: "service-action"; serviceKey: string; action: ServiceAction }
+ | { type: "save-api-base"; value: string };
+
+export type PageMessage =
+ | {
+ channel: typeof SDK_CHANNEL;
+ version: typeof SDK_VERSION;
+ source: "page";
+ type: "ready";
+ view: View;
+ }
+ | {
+ channel: typeof SDK_CHANNEL;
+ version: typeof SDK_VERSION;
+ source: "page";
+ type: "command";
+ view: View;
+ command: PageCommand;
+ };
+
+export type HostMessage =
+ | {
+ channel: typeof SDK_CHANNEL;
+ version: typeof SDK_VERSION;
+ source: "host";
+ type: "state";
+ state: HostSharedState;
+ }
+ | {
+ channel: typeof SDK_CHANNEL;
+ version: typeof SDK_VERSION;
+ source: "host";
+ type: "dispose";
+ };
+
+export function isPageMessage(value: unknown): value is PageMessage {
+ if (!isRecord(value)) return false;
+ return (
+ value.channel === SDK_CHANNEL &&
+ value.version === SDK_VERSION &&
+ value.source === "page" &&
+ (value.type === "ready" || value.type === "command")
+ );
+}
+
+export function isHostMessage(value: unknown): value is HostMessage {
+ if (!isRecord(value)) return false;
+ return (
+ value.channel === SDK_CHANNEL &&
+ value.version === SDK_VERSION &&
+ value.source === "host" &&
+ (value.type === "state" || value.type === "dispose")
+ );
+}
+
+function isRecord(value: unknown): value is Record {
+ return typeof value === "object" && value !== null;
+}
diff --git a/crates/wasmeld-console/web/src/styles/app.css b/crates/wasmeld-console/web/src/styles/app.css
new file mode 100644
index 0000000..f52586d
--- /dev/null
+++ b/crates/wasmeld-console/web/src/styles/app.css
@@ -0,0 +1,329 @@
+@import "tailwindcss";
+
+@theme {
+ --color-canvas: #f3f6f5;
+ --color-surface: #ffffff;
+ --color-line: #d8e0de;
+ --color-ink: #17211f;
+ --color-muted: #64716e;
+ --color-brand: #1f775e;
+ --color-brand-strong: #155a46;
+ --color-brand-soft: #e7f3ef;
+ --color-cyan-soft: #e5f5f7;
+ --color-cyan-strong: #147386;
+ --color-amber-soft: #fff3d8;
+ --color-amber-strong: #9b6507;
+ --color-coral-soft: #ffebe5;
+ --color-coral-strong: #b9492f;
+ --font-sans:
+ Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans SC",
+ sans-serif;
+ --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
+}
+
+@layer base {
+ * {
+ box-sizing: border-box;
+ letter-spacing: 0;
+ }
+
+ html,
+ body,
+ #app {
+ min-height: 100%;
+ margin: 0;
+ }
+
+ body {
+ @apply bg-canvas font-sans text-ink antialiased;
+ }
+
+ button,
+ input,
+ select,
+ textarea {
+ font: inherit;
+ }
+
+ button,
+ a {
+ -webkit-tap-highlight-color: transparent;
+ }
+
+ button:focus-visible,
+ a:focus-visible,
+ input:focus-visible,
+ select:focus-visible,
+ textarea:focus-visible {
+ @apply outline-2 outline-offset-2 outline-brand;
+ }
+
+ .frame-root,
+ .frame-document {
+ @apply overflow-x-hidden bg-canvas;
+ }
+}
+
+@layer components {
+ .btn {
+ @apply inline-flex h-10 items-center justify-center gap-2 rounded-md border px-4 text-sm font-semibold transition-colors disabled:cursor-not-allowed disabled:opacity-45;
+ }
+
+ .btn-primary {
+ @apply border-brand bg-brand text-white hover:border-brand-strong hover:bg-brand-strong;
+ }
+
+ .btn-secondary {
+ @apply border-line bg-white text-ink hover:bg-canvas;
+ }
+
+ .btn-danger {
+ @apply border-coral-strong bg-white text-coral-strong hover:bg-coral-soft;
+ }
+
+ .icon-btn {
+ @apply inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-line bg-white text-muted transition-colors hover:bg-canvas hover:text-ink disabled:cursor-not-allowed disabled:opacity-45;
+ }
+
+ .panel {
+ @apply border-line bg-surface rounded-md border;
+ }
+
+ .panel-header {
+ @apply border-line flex min-h-16 items-center justify-between gap-4 border-b px-5 py-3;
+ }
+
+ .panel-header h2 {
+ @apply text-base font-semibold;
+ }
+
+ .panel-header p {
+ @apply mt-0.5 text-xs text-muted;
+ }
+
+ .page {
+ @apply mx-auto w-full max-w-[1480px] px-4 py-5 sm:px-6 lg:px-8 lg:py-7;
+ }
+
+ .page-heading {
+ @apply mb-5 flex flex-col justify-between gap-4 sm:flex-row sm:items-end;
+ }
+
+ .page-heading h1 {
+ @apply mt-1 text-2xl font-bold text-ink;
+ }
+
+ .page-heading p {
+ @apply mt-1 max-w-3xl text-sm text-muted;
+ }
+
+ .eyebrow {
+ @apply text-cyan-strong text-[11px] font-bold uppercase;
+ }
+
+ .heading-actions {
+ @apply flex shrink-0 items-center gap-2;
+ }
+
+ .metric-grid {
+ @apply mb-5 grid grid-cols-1 border-l border-t border-line sm:grid-cols-2 xl:grid-cols-4;
+ }
+
+ .metric {
+ @apply flex min-h-24 items-center gap-3 border-b border-r border-line bg-white px-4 py-3;
+ }
+
+ .metric-icon {
+ @apply flex size-10 shrink-0 items-center justify-center rounded-md;
+ }
+
+ .metric-copy {
+ @apply min-w-0 flex-1;
+ }
+
+ .metric-copy span {
+ @apply block text-xs text-muted;
+ }
+
+ .metric-copy strong {
+ @apply mt-1 block text-2xl font-bold;
+ }
+
+ .metric > small {
+ @apply self-end whitespace-nowrap pb-1 text-[11px] text-muted;
+ }
+
+ .table-wrap {
+ @apply w-full overflow-x-auto;
+ }
+
+ .data-table {
+ @apply w-full min-w-[760px] border-collapse text-left text-sm;
+ }
+
+ .data-table th {
+ @apply border-line bg-canvas border-b px-4 py-2.5 text-[11px] font-semibold uppercase text-muted;
+ }
+
+ .data-table td {
+ @apply border-line border-b px-4 py-3 align-middle;
+ }
+
+ .data-table tbody tr {
+ @apply transition-colors hover:bg-[#f8faf9];
+ }
+
+ .data-table tbody tr:last-child td {
+ @apply border-b-0;
+ }
+
+ .status-badge {
+ @apply inline-flex items-center gap-1.5 whitespace-nowrap text-xs font-semibold;
+ }
+
+ .status-badge::before {
+ content: "";
+ @apply size-1.5 rounded-full bg-current;
+ }
+
+ .status-running {
+ @apply text-brand;
+ }
+
+ .status-stopped {
+ @apply text-muted;
+ }
+
+ .status-faulted {
+ @apply text-coral-strong;
+ }
+
+ .row-actions {
+ @apply flex items-center justify-end gap-1;
+ }
+
+ .row-actions button {
+ @apply inline-flex size-8 items-center justify-center rounded-md text-muted hover:bg-canvas hover:text-ink disabled:cursor-not-allowed disabled:opacity-35;
+ }
+
+ .empty-state {
+ @apply flex min-h-56 flex-col items-center justify-center gap-2 px-6 text-center text-muted;
+ }
+
+ .empty-state strong {
+ @apply text-sm text-ink;
+ }
+
+ .empty-state span {
+ @apply text-xs;
+ }
+
+ .code {
+ @apply font-mono text-xs;
+ }
+
+ .field {
+ @apply block;
+ }
+
+ .field > span {
+ @apply mb-1.5 block text-xs font-semibold text-muted;
+ }
+
+ .input,
+ .select,
+ .textarea {
+ @apply border-line w-full rounded-md border bg-white px-3 text-sm text-ink outline-none transition-colors focus:border-brand;
+ }
+
+ .input,
+ .select {
+ @apply h-10;
+ }
+
+ .textarea {
+ @apply min-h-36 resize-y py-3 font-mono;
+ }
+
+ .dialog-backdrop {
+ @apply fixed inset-0 z-50 flex items-center justify-center bg-[#0d1715]/55 p-3 backdrop-blur-[1px];
+ }
+
+ .dialog {
+ @apply border-line max-h-[calc(100dvh-24px)] w-full max-w-3xl overflow-auto rounded-md border bg-white p-0 shadow-2xl;
+ }
+
+ .dialog-header {
+ @apply border-line flex items-start justify-between gap-4 border-b px-5 py-4 sm:px-7 sm:py-5;
+ }
+
+ .dialog-title {
+ @apply flex min-w-0 items-start gap-3;
+ }
+
+ .dialog-title > span {
+ @apply bg-brand-soft text-brand flex size-10 shrink-0 items-center justify-center rounded-md;
+ }
+
+ .dialog-title h2 {
+ @apply text-lg font-bold sm:text-xl;
+ }
+
+ .dialog-title p {
+ @apply mt-1 text-sm text-muted;
+ }
+
+ .dialog-body {
+ @apply px-5 py-5 sm:px-7;
+ }
+
+ .dialog-footer {
+ @apply border-line flex items-center justify-end gap-2 border-t bg-[#fafbfb] px-5 py-4 sm:px-7;
+ }
+
+ .upload-zone {
+ @apply border-line flex min-h-48 cursor-pointer flex-col items-center justify-center gap-2 rounded-md border border-dashed bg-[#fbfcfc] px-5 text-center text-muted transition-colors hover:border-brand hover:bg-brand-soft;
+ }
+
+ .upload-zone input {
+ @apply sr-only;
+ }
+
+ .upload-zone strong {
+ @apply text-sm text-ink;
+ }
+
+ .upload-zone span {
+ @apply text-xs;
+ }
+
+ .form-error {
+ @apply border-coral-strong/30 bg-coral-soft text-coral-strong mt-3 rounded-md border px-3 py-2 text-sm;
+ }
+
+ .segmented {
+ @apply border-line inline-flex rounded-md border bg-canvas p-1;
+ }
+
+ .segmented button {
+ @apply h-8 rounded-sm px-3 text-xs font-semibold text-muted;
+ }
+
+ .segmented button.active {
+ @apply bg-white text-ink shadow-sm;
+ }
+
+ .skeleton-line {
+ @apply h-3 animate-pulse rounded-sm bg-[#dfe6e4];
+ }
+
+ .spin {
+ animation: spin 0.8s linear infinite;
+ }
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/crates/wasmeld-console/web/tests/build-output.test.mjs b/crates/wasmeld-console/web/tests/build-output.test.mjs
new file mode 100644
index 0000000..b9e5d02
--- /dev/null
+++ b/crates/wasmeld-console/web/tests/build-output.test.mjs
@@ -0,0 +1,23 @@
+import assert from "node:assert/strict";
+import { readFile, stat } from "node:fs/promises";
+import test from "node:test";
+
+test("build emits independent host and iframe documents", async () => {
+ const [host, page] = await Promise.all([
+ readFile(new URL("../dist/index.html", import.meta.url), "utf8"),
+ readFile(new URL("../dist/page.html", import.meta.url), "utf8"),
+ ]);
+
+ assert.match(host, /Wasmeld Console/);
+ assert.match(page, /Wasmeld Console Page/);
+ assert.notEqual(host, page);
+});
+
+test("build emits an installable PWA worker and manifest", async () => {
+ const manifest = JSON.parse(
+ await readFile(new URL("../dist/manifest.webmanifest", import.meta.url), "utf8"),
+ );
+ assert.equal(manifest.short_name, "Wasmeld");
+ assert.equal(manifest.start_url, "/");
+ assert.ok((await stat(new URL("../dist/sw.js", import.meta.url))).size > 0);
+});
diff --git a/console/tsconfig.json b/crates/wasmeld-console/web/tsconfig.json
similarity index 53%
rename from console/tsconfig.json
rename to crates/wasmeld-console/web/tsconfig.json
index 3d49616..350ec99 100644
--- a/console/tsconfig.json
+++ b/crates/wasmeld-console/web/tsconfig.json
@@ -1,17 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
"skipLibCheck": true,
"strict": true,
"noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
"isolatedModules": true,
- "jsx": "react-jsx",
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js",
"types": ["vite/client"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"],
- "exclude": ["node_modules"]
+ "exclude": ["dist", "node_modules"]
}
diff --git a/crates/wasmeld-console/web/vite.config.ts b/crates/wasmeld-console/web/vite.config.ts
new file mode 100644
index 0000000..6f5eebe
--- /dev/null
+++ b/crates/wasmeld-console/web/vite.config.ts
@@ -0,0 +1,88 @@
+import tailwindcss from "@tailwindcss/vite";
+import { createHash } from "node:crypto";
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
+import { defineConfig, type Plugin } from "vite";
+import solid from "vite-plugin-solid";
+
+const outputDirectory = process.env.WASMELD_WEB_OUT_DIR ?? "dist";
+
+export default defineConfig({
+ server: {
+ port: 3000,
+ },
+ plugins: [solid(), tailwindcss(), pwaWorker()],
+ build: {
+ outDir: outputDirectory,
+ emptyOutDir: true,
+ rollupOptions: {
+ // Host and Page remain separate HTML documents. Dynamic page imports
+ // then create one lazy chunk per primary management view.
+ input: {
+ host: resolve(import.meta.dirname, "index.html"),
+ page: resolve(import.meta.dirname, "page.html"),
+ },
+ },
+ },
+});
+
+function pwaWorker(): Plugin {
+ return {
+ name: "wasmeld-pwa-worker",
+ apply: "build",
+ generateBundle(_, bundle) {
+ // Derive the cache name from emitted filenames and unhashed public
+ // assets. A changed build activates a new cache without another PWA
+ // dependency or a generated source file in the repository.
+ const publicFiles = ["icon.svg", "manifest.webmanifest", "og.png"];
+ const generatedFiles = Object.keys(bundle).filter((file) =>
+ /\.(?:html|js|css|svg|png|webmanifest)$/.test(file),
+ );
+ const files = [...new Set([...generatedFiles, ...publicFiles])].sort();
+ const digest = createHash("sha256");
+ for (const file of files) digest.update(file);
+ for (const file of publicFiles) {
+ digest.update(readFileSync(resolve(import.meta.dirname, "public", file)));
+ }
+ const cacheName = `wasmeld-${digest.digest("hex").slice(0, 16)}`;
+ const urls = files.map((file) => `/${file}`);
+ this.emitFile({
+ type: "asset",
+ fileName: "sw.js",
+ source: serviceWorkerSource(cacheName, urls),
+ });
+ },
+ };
+}
+
+function serviceWorkerSource(cacheName: string, urls: string[]): string {
+ // Runtime state must never be satisfied from an old cache. Only documents
+ // and build assets participate in offline behavior.
+ return `const CACHE = ${JSON.stringify(cacheName)};
+const PRECACHE = ${JSON.stringify(urls)};
+self.addEventListener("install", (event) => {
+ event.waitUntil(caches.open(CACHE).then((cache) => cache.addAll(PRECACHE)).then(() => self.skipWaiting()));
+});
+self.addEventListener("activate", (event) => {
+ event.waitUntil(caches.keys().then((keys) => Promise.all(keys.filter((key) => key.startsWith("wasmeld-") && key !== CACHE).map((key) => caches.delete(key)))).then(() => self.clients.claim()));
+});
+self.addEventListener("fetch", (event) => {
+ if (event.request.method !== "GET") return;
+ const url = new URL(event.request.url);
+ if (url.origin !== self.location.origin || url.pathname === "/healthz" || url.pathname.startsWith("/api/")) return;
+ if (event.request.mode === "navigate") {
+ event.respondWith(fetch(event.request).then((response) => {
+ const copy = response.clone();
+ caches.open(CACHE).then((cache) => cache.put(event.request, copy));
+ return response;
+ }).catch(async () => {
+ const cached = await caches.match(event.request);
+ if (cached) return cached;
+ return caches.match(url.pathname === "/page.html" ? "/page.html" : "/index.html");
+ }));
+ return;
+ }
+ event.respondWith(caches.match(event.request).then((cached) => cached || fetch(event.request)));
+});
+`;
+}