feat: add presentation route shell
This commit is contained in:
@@ -15,8 +15,10 @@
|
||||
"@fontsource/barlow-condensed": "5.2.8",
|
||||
"@fontsource/ibm-plex-mono": "5.2.7",
|
||||
"@xyflow/react": "12.11.1",
|
||||
"motion": "^12.42.2",
|
||||
"react": "19.2.7",
|
||||
"react-dom": "19.2.7",
|
||||
"react-router-dom": "^7.18.1",
|
||||
"valibot": "1.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { App } from "./App.js";
|
||||
import { AppRoutes } from "./AppRoutes.js";
|
||||
import { callOperation, connectToServer } from "../connection/api.js";
|
||||
import type { RpcResponse } from "../connection/contracts.js";
|
||||
|
||||
@@ -183,4 +185,15 @@ describe("App", () => {
|
||||
await userEvent.click(screen.getByRole("button", { name: "Replay" }));
|
||||
expect(screen.getByRole("button", { name: /start presentation/i })).toBeEnabled();
|
||||
});
|
||||
|
||||
it("routes to presentation mode separately from the console", () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={["/present"]}>
|
||||
<AppRoutes />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("main", { name: /lda.chat presentation/i })).toBeInTheDocument();
|
||||
expect(screen.queryByLabelText("Lifecycle Explorer")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,184 +1,8 @@
|
||||
import { useReducer, useEffect, useCallback, useRef } from "react";
|
||||
import {
|
||||
connectionReducer,
|
||||
initialState,
|
||||
type EvidenceRecord,
|
||||
type SourceRecord,
|
||||
} from "./state.js";
|
||||
import { connectToServer, callOperation } from "../connection/api.js";
|
||||
import { ConnectionHeader } from "../components/ConnectionHeader.js";
|
||||
import { SourceInventory } from "../components/SourceInventory.js";
|
||||
import { LifecycleExplorer } from "../lifecycle/LifecycleExplorer.js";
|
||||
import { useLifecycleExplorer } from "../lifecycle/useLifecycleExplorer.js";
|
||||
import { LdaReportDemoPanel } from "../demo/LdaReportDemoPanel.js";
|
||||
import { useDemoTimeline } from "../demo/useDemoTimeline.js";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { AppRoutes } from "./AppRoutes.js";
|
||||
|
||||
const parseSources = (
|
||||
data: unknown,
|
||||
): SourceRecord[] => {
|
||||
if (!data || typeof data !== "object") return [];
|
||||
const obj = data as Record<string, unknown>;
|
||||
if (!Array.isArray(obj.sources)) return [];
|
||||
|
||||
return obj.sources.map((entry: unknown, i: number) => {
|
||||
const s = entry as Record<string, unknown>;
|
||||
const id = typeof s.id === "string" ? s.id : `source-${i}`;
|
||||
const kind = typeof s.kind === "string" ? s.kind : "unknown";
|
||||
const enabled = s.enabled !== false;
|
||||
const description =
|
||||
typeof s.description === "string" ? s.description : null;
|
||||
const counts = (s.counts ?? {}) as Record<string, number>;
|
||||
return {
|
||||
id,
|
||||
kind,
|
||||
enabled,
|
||||
description,
|
||||
toolCount: typeof counts.tools === "number" ? counts.tools : 0,
|
||||
nodeSpecCount: typeof counts.nodeSpecs === "number" ? counts.nodeSpecs : 0,
|
||||
reducerCount: typeof counts.reducers === "number" ? counts.reducers : 0,
|
||||
promptCount: typeof counts.prompts === "number" ? counts.prompts : 0,
|
||||
resourceCount:
|
||||
typeof counts.resources === "number" ? counts.resources : 0,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const App = () => {
|
||||
const [state, dispatch] = useReducer(connectionReducer, null, initialState);
|
||||
const connectGeneration = useRef(0);
|
||||
const sourcesGeneration = useRef(0);
|
||||
|
||||
const connectedTarget = state.phase === "connected" ? state.connectedTarget : null;
|
||||
|
||||
const recordEvidence = useCallback(
|
||||
(record: EvidenceRecord) => dispatch({ type: "evidence_recorded", record }),
|
||||
[],
|
||||
);
|
||||
|
||||
const lifecycleController = useLifecycleExplorer(connectedTarget, recordEvidence);
|
||||
const demoController = useDemoTimeline(connectedTarget, recordEvidence);
|
||||
|
||||
const loadSources = useCallback(
|
||||
async (target: string) => {
|
||||
const generation = ++sourcesGeneration.current;
|
||||
dispatch({ type: "sources_loading" });
|
||||
try {
|
||||
const result = await callOperation(
|
||||
"workflow.sources.list",
|
||||
target,
|
||||
{ limit: 50 },
|
||||
);
|
||||
if (sourcesGeneration.current !== generation) return;
|
||||
if (result.ok) {
|
||||
const sources = parseSources(result.interpreted);
|
||||
dispatch({
|
||||
type: "sources_loaded",
|
||||
sources,
|
||||
evidence: {
|
||||
id: `sources-${Date.now()}`,
|
||||
operation: "workflow.sources.list",
|
||||
label: "Source inventory",
|
||||
equivalentCli: result.equivalentCli,
|
||||
request: result.exchange.request,
|
||||
response: result.exchange.response,
|
||||
durationMs: result.durationMs,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "sources_error",
|
||||
message: result.error.message,
|
||||
evidence: {
|
||||
id: `sources-${Date.now()}`,
|
||||
operation: "workflow.sources.list",
|
||||
label: "Source inventory",
|
||||
equivalentCli: "uv run wf source list --limit 50",
|
||||
request: result.exchange.request,
|
||||
response: result.exchange.response,
|
||||
durationMs: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (sourcesGeneration.current !== generation) return;
|
||||
dispatch({
|
||||
type: "sources_error",
|
||||
message: e instanceof Error ? e.message : "unknown error",
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.phase === "connected" && state.connectedTarget) {
|
||||
void loadSources(state.connectedTarget);
|
||||
}
|
||||
}, [state.phase, state.connectedTarget, loadSources]);
|
||||
|
||||
const onSubmit = (target: string) => {
|
||||
const generation = ++connectGeneration.current;
|
||||
sourcesGeneration.current++;
|
||||
dispatch({ type: "submit", target });
|
||||
void connectToServer(target).then(
|
||||
(response) => {
|
||||
if (connectGeneration.current !== generation) return;
|
||||
if (response.ok) {
|
||||
dispatch({ type: "success", data: response });
|
||||
dispatch({
|
||||
type: "evidence_recorded",
|
||||
record: {
|
||||
id: `health-${Date.now()}`,
|
||||
operation: "workflow.health",
|
||||
label: "Health check",
|
||||
equivalentCli: "uv run wf status",
|
||||
request: response.exchange.request,
|
||||
response: response.exchange.response,
|
||||
durationMs: response.connection.durationMs,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "failure",
|
||||
code: response.error.code,
|
||||
message: response.error.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
(e: unknown) => {
|
||||
if (connectGeneration.current !== generation) return;
|
||||
dispatch({
|
||||
type: "failure",
|
||||
code: errorCodeFromThrown(e),
|
||||
message: e instanceof Error ? e.message : "unknown error",
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app-layout">
|
||||
<ConnectionHeader
|
||||
state={state}
|
||||
onSubmit={onSubmit}
|
||||
onDraftChange={(value) => dispatch({ type: "draft_changed", value })}
|
||||
/>
|
||||
<LdaReportDemoPanel controller={demoController} />
|
||||
<SourceInventory
|
||||
sources={state.sources}
|
||||
loading={state.sourcesLoading}
|
||||
error={state.sourceError}
|
||||
/>
|
||||
<section aria-label="Lifecycle Explorer" data-testid="lifecycle-explorer">
|
||||
<LifecycleExplorer controller={lifecycleController} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const errorCodeFromThrown = (error: unknown): string => {
|
||||
if (!(error instanceof Error)) return "rpc_protocol_error";
|
||||
return error.message.toLowerCase().includes("malformed")
|
||||
? "malformed_response"
|
||||
: "rpc_protocol_error";
|
||||
};
|
||||
export const App = () => (
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Navigate, Route, Routes } from "react-router-dom";
|
||||
import { ConsoleHome } from "./ConsoleHome.js";
|
||||
import { PresentationRoute } from "../presentation/PresentationRoute.js";
|
||||
|
||||
export const AppRoutes = () => (
|
||||
<Routes>
|
||||
<Route path="/" element={<ConsoleHome />} />
|
||||
<Route path="/console" element={<ConsoleHome />} />
|
||||
<Route path="/present" element={<PresentationRoute />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
);
|
||||
@@ -0,0 +1,184 @@
|
||||
import { useReducer, useEffect, useCallback, useRef } from "react";
|
||||
import {
|
||||
connectionReducer,
|
||||
initialState,
|
||||
type EvidenceRecord,
|
||||
type SourceRecord,
|
||||
} from "./state.js";
|
||||
import { connectToServer, callOperation } from "../connection/api.js";
|
||||
import { ConnectionHeader } from "../components/ConnectionHeader.js";
|
||||
import { SourceInventory } from "../components/SourceInventory.js";
|
||||
import { LifecycleExplorer } from "../lifecycle/LifecycleExplorer.js";
|
||||
import { useLifecycleExplorer } from "../lifecycle/useLifecycleExplorer.js";
|
||||
import { LdaReportDemoPanel } from "../demo/LdaReportDemoPanel.js";
|
||||
import { useDemoTimeline } from "../demo/useDemoTimeline.js";
|
||||
|
||||
const parseSources = (
|
||||
data: unknown,
|
||||
): SourceRecord[] => {
|
||||
if (!data || typeof data !== "object") return [];
|
||||
const obj = data as Record<string, unknown>;
|
||||
if (!Array.isArray(obj.sources)) return [];
|
||||
|
||||
return obj.sources.map((entry: unknown, i: number) => {
|
||||
const s = entry as Record<string, unknown>;
|
||||
const id = typeof s.id === "string" ? s.id : `source-${i}`;
|
||||
const kind = typeof s.kind === "string" ? s.kind : "unknown";
|
||||
const enabled = s.enabled !== false;
|
||||
const description =
|
||||
typeof s.description === "string" ? s.description : null;
|
||||
const counts = (s.counts ?? {}) as Record<string, number>;
|
||||
return {
|
||||
id,
|
||||
kind,
|
||||
enabled,
|
||||
description,
|
||||
toolCount: typeof counts.tools === "number" ? counts.tools : 0,
|
||||
nodeSpecCount: typeof counts.nodeSpecs === "number" ? counts.nodeSpecs : 0,
|
||||
reducerCount: typeof counts.reducers === "number" ? counts.reducers : 0,
|
||||
promptCount: typeof counts.prompts === "number" ? counts.prompts : 0,
|
||||
resourceCount:
|
||||
typeof counts.resources === "number" ? counts.resources : 0,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const ConsoleHome = () => {
|
||||
const [state, dispatch] = useReducer(connectionReducer, null, initialState);
|
||||
const connectGeneration = useRef(0);
|
||||
const sourcesGeneration = useRef(0);
|
||||
|
||||
const connectedTarget = state.phase === "connected" ? state.connectedTarget : null;
|
||||
|
||||
const recordEvidence = useCallback(
|
||||
(record: EvidenceRecord) => dispatch({ type: "evidence_recorded", record }),
|
||||
[],
|
||||
);
|
||||
|
||||
const lifecycleController = useLifecycleExplorer(connectedTarget, recordEvidence);
|
||||
const demoController = useDemoTimeline(connectedTarget, recordEvidence);
|
||||
|
||||
const loadSources = useCallback(
|
||||
async (target: string) => {
|
||||
const generation = ++sourcesGeneration.current;
|
||||
dispatch({ type: "sources_loading" });
|
||||
try {
|
||||
const result = await callOperation(
|
||||
"workflow.sources.list",
|
||||
target,
|
||||
{ limit: 50 },
|
||||
);
|
||||
if (sourcesGeneration.current !== generation) return;
|
||||
if (result.ok) {
|
||||
const sources = parseSources(result.interpreted);
|
||||
dispatch({
|
||||
type: "sources_loaded",
|
||||
sources,
|
||||
evidence: {
|
||||
id: `sources-${Date.now()}`,
|
||||
operation: "workflow.sources.list",
|
||||
label: "Source inventory",
|
||||
equivalentCli: result.equivalentCli,
|
||||
request: result.exchange.request,
|
||||
response: result.exchange.response,
|
||||
durationMs: result.durationMs,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "sources_error",
|
||||
message: result.error.message,
|
||||
evidence: {
|
||||
id: `sources-${Date.now()}`,
|
||||
operation: "workflow.sources.list",
|
||||
label: "Source inventory",
|
||||
equivalentCli: "uv run wf source list --limit 50",
|
||||
request: result.exchange.request,
|
||||
response: result.exchange.response,
|
||||
durationMs: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (sourcesGeneration.current !== generation) return;
|
||||
dispatch({
|
||||
type: "sources_error",
|
||||
message: e instanceof Error ? e.message : "unknown error",
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.phase === "connected" && state.connectedTarget) {
|
||||
void loadSources(state.connectedTarget);
|
||||
}
|
||||
}, [state.phase, state.connectedTarget, loadSources]);
|
||||
|
||||
const onSubmit = (target: string) => {
|
||||
const generation = ++connectGeneration.current;
|
||||
sourcesGeneration.current++;
|
||||
dispatch({ type: "submit", target });
|
||||
void connectToServer(target).then(
|
||||
(response) => {
|
||||
if (connectGeneration.current !== generation) return;
|
||||
if (response.ok) {
|
||||
dispatch({ type: "success", data: response });
|
||||
dispatch({
|
||||
type: "evidence_recorded",
|
||||
record: {
|
||||
id: `health-${Date.now()}`,
|
||||
operation: "workflow.health",
|
||||
label: "Health check",
|
||||
equivalentCli: "uv run wf status",
|
||||
request: response.exchange.request,
|
||||
response: response.exchange.response,
|
||||
durationMs: response.connection.durationMs,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "failure",
|
||||
code: response.error.code,
|
||||
message: response.error.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
(e: unknown) => {
|
||||
if (connectGeneration.current !== generation) return;
|
||||
dispatch({
|
||||
type: "failure",
|
||||
code: errorCodeFromThrown(e),
|
||||
message: e instanceof Error ? e.message : "unknown error",
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app-layout">
|
||||
<ConnectionHeader
|
||||
state={state}
|
||||
onSubmit={onSubmit}
|
||||
onDraftChange={(value) => dispatch({ type: "draft_changed", value })}
|
||||
/>
|
||||
<LdaReportDemoPanel controller={demoController} />
|
||||
<SourceInventory
|
||||
sources={state.sources}
|
||||
loading={state.sourcesLoading}
|
||||
error={state.sourceError}
|
||||
/>
|
||||
<section aria-label="Lifecycle Explorer" data-testid="lifecycle-explorer">
|
||||
<LifecycleExplorer controller={lifecycleController} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const errorCodeFromThrown = (error: unknown): string => {
|
||||
if (!(error instanceof Error)) return "rpc_protocol_error";
|
||||
return error.message.toLowerCase().includes("malformed")
|
||||
? "malformed_response"
|
||||
: "rpc_protocol_error";
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { PresentationRoute } from "./PresentationRoute.js";
|
||||
|
||||
afterEach(() => cleanup());
|
||||
|
||||
describe("PresentationRoute", () => {
|
||||
it("renders the presentation stage entry point", () => {
|
||||
render(<PresentationRoute />);
|
||||
|
||||
expect(screen.getByRole("main", { name: /lda.chat presentation/i })).toBeInTheDocument();
|
||||
expect(screen.getByText(/planner decisions/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
export const PresentationRoute = () => (
|
||||
<main className="presentation-route" aria-label="lda.chat presentation">
|
||||
<p>Planner decisions are separated from deterministic runtime execution.</p>
|
||||
</main>
|
||||
);
|
||||
Generated
+105
@@ -32,12 +32,18 @@ importers:
|
||||
'@xyflow/react':
|
||||
specifier: 12.11.1
|
||||
version: 12.11.1(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
|
||||
motion:
|
||||
specifier: ^12.42.2
|
||||
version: 12.42.2([email protected]([email protected]))([email protected])
|
||||
react:
|
||||
specifier: 19.2.7
|
||||
version: 19.2.7
|
||||
react-dom:
|
||||
specifier: 19.2.7
|
||||
version: 19.2.7([email protected])
|
||||
react-router-dom:
|
||||
specifier: ^7.18.1
|
||||
version: 7.18.1([email protected]([email protected]))([email protected])
|
||||
valibot:
|
||||
specifier: 1.4.2
|
||||
version: 1.4.2([email protected])
|
||||
@@ -719,6 +725,10 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
@@ -833,6 +843,20 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -965,6 +989,26 @@ packages:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-Atvv11yUKIid41cVrRBDVX5m8tF8kNpExRSlbpt6APClhDjtwQssgFHhQzejxw7/7YYbjHSPKBVbHo05BuJT5Q==}
|
||||
peerDependencies:
|
||||
'@emotion/is-prop-valid': '*'
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/is-prop-valid':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==}
|
||||
hasBin: true
|
||||
@@ -1024,6 +1068,23 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
peerDependencies:
|
||||
react: '>=18'
|
||||
react-dom: '>=18'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1051,6 +1112,9 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1763,6 +1827,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
mdn-data: 2.27.1
|
||||
@@ -1883,6 +1949,15 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
motion-dom: 12.42.2
|
||||
motion-utils: 12.39.0
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7([email protected])
|
||||
|
||||
[email protected]:
|
||||
optional: true
|
||||
|
||||
@@ -1991,6 +2066,20 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
motion-utils: 12.39.0
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
framer-motion: 12.42.2([email protected]([email protected]))([email protected])
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7([email protected])
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
node-gyp-build-optional-packages: 5.2.2
|
||||
@@ -2051,6 +2140,20 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
react: 19.2.7
|
||||
react-dom: 19.2.7([email protected])
|
||||
react-router: 7.18.1([email protected]([email protected]))([email protected])
|
||||
|
||||
[email protected]([email protected]([email protected]))([email protected]):
|
||||
dependencies:
|
||||
cookie: 1.1.1
|
||||
react: 19.2.7
|
||||
set-cookie-parser: 2.7.2
|
||||
optionalDependencies:
|
||||
react-dom: 19.2.7([email protected])
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
@@ -2091,6 +2194,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
Reference in New Issue
Block a user