Fix waypoint loading in Edit in Planner flow
Three issues fixed: 1. GPX parser used browser DOMParser which doesn't exist in Node/Vite SSR. Added async parseGpxAsync() using linkedom for server-side parsing. 2. Server-side session initialization stored waypoints in a Yjs doc instance separate from the Vite WebSocket plugin's doc store. Moved waypoint initialization to client-side: API returns parsed waypoints, client adds them to Yjs after sync. 3. GPX was encoded in URL params causing HTTP 431. Now the Journal creates a Planner session via API (POST body), and only passes compact waypoint coordinates in URL params. Verified: Journal route → Edit in Planner → 4 waypoints loaded, route computed (79.3km), elevation profile, Save to Journal ready. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2e2dbe05c1
commit
14b179bb0c
9 changed files with 201 additions and 13 deletions
|
|
@ -33,9 +33,18 @@ export async function action({ params, request }: Route.ActionArgs) {
|
||||||
return data({ error: "Failed to create Planner session" }, { status: 502 });
|
return data({ error: "Failed to create Planner session" }, { status: 502 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = (await sessionResp.json()) as { url: string };
|
const session = (await sessionResp.json()) as {
|
||||||
|
url: string;
|
||||||
|
initialWaypoints?: Array<{ lat: number; lon: number; name?: string }>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encode waypoints in URL params (small — just coordinates, not full GPX)
|
||||||
|
const urlParams = new URLSearchParams({ returnUrl });
|
||||||
|
if (session.initialWaypoints?.length) {
|
||||||
|
urlParams.set("waypoints", JSON.stringify(session.initialWaypoints));
|
||||||
|
}
|
||||||
|
|
||||||
return data({
|
return data({
|
||||||
url: `${plannerUrl}${session.url}?returnUrl=${encodeURIComponent(returnUrl)}`,
|
url: `${plannerUrl}${session.url}?${urlParams}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,11 @@ interface SessionViewProps {
|
||||||
callbackUrl?: string;
|
callbackUrl?: string;
|
||||||
callbackToken?: string;
|
callbackToken?: string;
|
||||||
returnUrl?: string;
|
returnUrl?: string;
|
||||||
|
initialWaypoints?: Array<{ lat: number; lon: number; name?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl }: SessionViewProps) {
|
export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl, initialWaypoints }: SessionViewProps) {
|
||||||
const yjs = useYjs(sessionId);
|
const yjs = useYjs(sessionId, initialWaypoints);
|
||||||
const { isHost, computing, routeStats, requestRoute } = useRouting(yjs);
|
const { isHost, computing, routeStats, requestRoute } = useRouting(yjs);
|
||||||
const [highlightPosition, setHighlightPosition] = useState<[number, number] | null>(null);
|
const [highlightPosition, setHighlightPosition] = useState<[number, number] | null>(null);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,14 @@ export interface YjsState {
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useYjs(sessionId: string): YjsState | null {
|
export function useYjs(
|
||||||
|
sessionId: string,
|
||||||
|
initialWaypoints?: Array<{ lat: number; lon: number; name?: string }>,
|
||||||
|
): YjsState | null {
|
||||||
const [state, setState] = useState<YjsState | null>(null);
|
const [state, setState] = useState<YjsState | null>(null);
|
||||||
const providerRef = useRef<WebsocketProvider | null>(null);
|
const providerRef = useRef<WebsocketProvider | null>(null);
|
||||||
const docRef = useRef<Y.Doc | null>(null);
|
const docRef = useRef<Y.Doc | null>(null);
|
||||||
|
const initializedWaypoints = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const doc = new Y.Doc();
|
const doc = new Y.Doc();
|
||||||
|
|
@ -52,10 +56,28 @@ export function useYjs(sessionId: string): YjsState | null {
|
||||||
const waypoints = doc.getArray<Y.Map<unknown>>("waypoints");
|
const waypoints = doc.getArray<Y.Map<unknown>>("waypoints");
|
||||||
const routeData = doc.getMap("routeData");
|
const routeData = doc.getMap("routeData");
|
||||||
|
|
||||||
// Use persistent identity
|
|
||||||
const { color, name } = getOrCreateUserIdentity();
|
const { color, name } = getOrCreateUserIdentity();
|
||||||
provider.awareness.setLocalStateField("user", { color, name });
|
provider.awareness.setLocalStateField("user", { color, name });
|
||||||
|
|
||||||
|
// Initialize waypoints once after first sync
|
||||||
|
if (initialWaypoints?.length && !initializedWaypoints.current) {
|
||||||
|
(provider as unknown as { on(event: string, cb: () => void): void }).on("synced", () => {
|
||||||
|
// Only add if the doc is empty (avoid duplicating on reconnect)
|
||||||
|
if (waypoints.length === 0 && !initializedWaypoints.current) {
|
||||||
|
initializedWaypoints.current = true;
|
||||||
|
doc.transact(() => {
|
||||||
|
for (const wp of initialWaypoints) {
|
||||||
|
const yMap = new Y.Map();
|
||||||
|
yMap.set("lat", wp.lat);
|
||||||
|
yMap.set("lon", wp.lon);
|
||||||
|
if (wp.name) yMap.set("name", wp.name);
|
||||||
|
waypoints.push([yMap]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const updateState = (connected: boolean) => {
|
const updateState = (connected: boolean) => {
|
||||||
setState({
|
setState({
|
||||||
doc,
|
doc,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { data } from "react-router";
|
import { data } from "react-router";
|
||||||
import type { Route } from "./+types/api.sessions";
|
import type { Route } from "./+types/api.sessions";
|
||||||
import { createSession, initializeSessionWithWaypoints, listSessions } from "~/lib/sessions";
|
import { createSession, listSessions } from "~/lib/sessions";
|
||||||
import { parseGpx } from "@trails-cool/gpx";
|
import { parseGpxAsync } from "@trails-cool/gpx";
|
||||||
|
|
||||||
export async function action({ request }: Route.ActionArgs) {
|
export async function action({ request }: Route.ActionArgs) {
|
||||||
if (request.method !== "POST") {
|
if (request.method !== "POST") {
|
||||||
|
|
@ -17,10 +17,11 @@ export async function action({ request }: Route.ActionArgs) {
|
||||||
|
|
||||||
const session = await createSession({ callbackUrl, callbackToken });
|
const session = await createSession({ callbackUrl, callbackToken });
|
||||||
|
|
||||||
|
let initialWaypoints: Array<{ lat: number; lon: number; name?: string }> | undefined;
|
||||||
if (gpx) {
|
if (gpx) {
|
||||||
try {
|
try {
|
||||||
const gpxData = parseGpx(gpx);
|
const gpxData = await parseGpxAsync(gpx);
|
||||||
initializeSessionWithWaypoints(session.id, gpxData.waypoints);
|
initialWaypoints = gpxData.waypoints;
|
||||||
} catch (_e) {
|
} catch (_e) {
|
||||||
// Continue with empty session if GPX is invalid
|
// Continue with empty session if GPX is invalid
|
||||||
}
|
}
|
||||||
|
|
@ -30,6 +31,7 @@ export async function action({ request }: Route.ActionArgs) {
|
||||||
{
|
{
|
||||||
sessionId: session.id,
|
sessionId: session.id,
|
||||||
url: `/session/${session.id}`,
|
url: `/session/${session.id}`,
|
||||||
|
initialWaypoints,
|
||||||
},
|
},
|
||||||
{ status: 201 },
|
{ status: 201 },
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ export default function SessionPage({ loaderData }: Route.ComponentProps) {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const returnUrl = searchParams.get("returnUrl") ?? undefined;
|
const returnUrl = searchParams.get("returnUrl") ?? undefined;
|
||||||
|
const waypointsParam = searchParams.get("waypoints");
|
||||||
|
let initialWaypoints: Array<{ lat: number; lon: number; name?: string }> | undefined;
|
||||||
|
if (waypointsParam) {
|
||||||
|
try { initialWaypoints = JSON.parse(waypointsParam); } catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
|
|
@ -52,6 +57,7 @@ export default function SessionPage({ loaderData }: Route.ComponentProps) {
|
||||||
callbackUrl={loaderData.callbackUrl ?? undefined}
|
callbackUrl={loaderData.callbackUrl ?? undefined}
|
||||||
callbackToken={loaderData.callbackToken ?? undefined}
|
callbackToken={loaderData.callbackToken ?? undefined}
|
||||||
returnUrl={returnUrl}
|
returnUrl={returnUrl}
|
||||||
|
initialWaypoints={initialWaypoints}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
"i18next-browser-languagedetector": "^8.2.1",
|
"i18next-browser-languagedetector": "^8.2.1",
|
||||||
"jsdom": "^29.0.1",
|
"jsdom": "^29.0.1",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
|
"linkedom": "^0.18.12",
|
||||||
"playwright": "^1.58.2",
|
"playwright": "^1.58.2",
|
||||||
"postgres": "^3.4.8",
|
"postgres": "^3.4.8",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export { parseGpx } from "./parse";
|
export { parseGpx, parseGpxAsync } from "./parse";
|
||||||
export { generateGpx } from "./generate";
|
export { generateGpx } from "./generate";
|
||||||
export type { GpxData, TrackPoint, ElevationProfile } from "./types";
|
export type { GpxData, TrackPoint, ElevationProfile } from "./types";
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,39 @@ import type { GpxData, TrackPoint, ElevationProfile } from "./types";
|
||||||
/**
|
/**
|
||||||
* Parse a GPX XML string into structured data.
|
* Parse a GPX XML string into structured data.
|
||||||
*/
|
*/
|
||||||
|
let _LinkedDOMParser: typeof DOMParser | null = null;
|
||||||
|
|
||||||
|
async function getDOMParser(): Promise<typeof DOMParser> {
|
||||||
|
if (typeof DOMParser !== "undefined") return DOMParser;
|
||||||
|
if (!_LinkedDOMParser) {
|
||||||
|
const linkedom = await import("linkedom");
|
||||||
|
_LinkedDOMParser = linkedom.DOMParser as unknown as typeof DOMParser;
|
||||||
|
}
|
||||||
|
return _LinkedDOMParser;
|
||||||
|
}
|
||||||
|
|
||||||
export function parseGpx(xml: string): GpxData {
|
export function parseGpx(xml: string): GpxData {
|
||||||
const parser = new DOMParser();
|
// Synchronous path for browser
|
||||||
const doc = parser.parseFromString(xml, "application/xml");
|
if (typeof DOMParser !== "undefined") {
|
||||||
|
return parseGpxWithParser(new DOMParser(), xml);
|
||||||
|
}
|
||||||
|
// Fallback: try linkedom synchronously (works in Node with top-level await or CJS)
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const { DOMParser: LP } = require("linkedom");
|
||||||
|
return parseGpxWithParser(new LP() as unknown as DOMParser, xml);
|
||||||
|
} catch {
|
||||||
|
throw new Error("DOMParser not available — install linkedom for Node.js");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function parseGpxAsync(xml: string): Promise<GpxData> {
|
||||||
|
const Parser = await getDOMParser();
|
||||||
|
return parseGpxWithParser(new Parser(), xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseGpxWithParser(parser: DOMParser, xml: string): GpxData {
|
||||||
|
const doc = parser.parseFromString(xml, "application/xml") as unknown as Document;
|
||||||
|
|
||||||
const parserError = doc.querySelector("parsererror");
|
const parserError = doc.querySelector("parsererror");
|
||||||
if (parserError) {
|
if (parserError) {
|
||||||
|
|
|
||||||
117
pnpm-lock.yaml
generated
117
pnpm-lock.yaml
generated
|
|
@ -119,6 +119,9 @@ importers:
|
||||||
leaflet:
|
leaflet:
|
||||||
specifier: ^1.9.4
|
specifier: ^1.9.4
|
||||||
version: 1.9.4
|
version: 1.9.4
|
||||||
|
linkedom:
|
||||||
|
specifier: ^0.18.12
|
||||||
|
version: 0.18.12
|
||||||
playwright:
|
playwright:
|
||||||
specifier: ^1.58.2
|
specifier: ^1.58.2
|
||||||
version: 1.58.2
|
version: 1.58.2
|
||||||
|
|
@ -1545,6 +1548,9 @@ packages:
|
||||||
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==}
|
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==}
|
||||||
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||||
|
|
||||||
|
boolbase@1.0.0:
|
||||||
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
brace-expansion@5.0.4:
|
brace-expansion@5.0.4:
|
||||||
resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==}
|
resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==}
|
||||||
engines: {node: 18 || 20 || >=22}
|
engines: {node: 18 || 20 || >=22}
|
||||||
|
|
@ -1621,13 +1627,23 @@ packages:
|
||||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
css-select@5.2.2:
|
||||||
|
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
|
||||||
|
|
||||||
css-tree@3.2.1:
|
css-tree@3.2.1:
|
||||||
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
|
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
|
||||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||||
|
|
||||||
|
css-what@6.2.2:
|
||||||
|
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
css.escape@1.5.1:
|
css.escape@1.5.1:
|
||||||
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
||||||
|
|
||||||
|
cssom@0.5.0:
|
||||||
|
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
|
||||||
|
|
||||||
csstype@3.2.3:
|
csstype@3.2.3:
|
||||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||||
|
|
||||||
|
|
@ -1688,6 +1704,19 @@ packages:
|
||||||
dom-accessibility-api@0.6.3:
|
dom-accessibility-api@0.6.3:
|
||||||
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
|
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
|
||||||
|
|
||||||
|
dom-serializer@2.0.0:
|
||||||
|
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||||
|
|
||||||
|
domelementtype@2.3.0:
|
||||||
|
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||||
|
|
||||||
|
domhandler@5.0.3:
|
||||||
|
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
domutils@3.2.2:
|
||||||
|
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||||
|
|
||||||
drizzle-kit@0.31.10:
|
drizzle-kit@0.31.10:
|
||||||
resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==}
|
resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -1897,10 +1926,18 @@ packages:
|
||||||
resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
|
resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
entities@4.5.0:
|
||||||
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
entities@6.0.1:
|
entities@6.0.1:
|
||||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
entities@7.0.1:
|
||||||
|
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
es-define-property@1.0.1:
|
es-define-property@1.0.1:
|
||||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -2110,9 +2147,15 @@ packages:
|
||||||
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
|
|
||||||
|
html-escaper@3.0.3:
|
||||||
|
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
|
||||||
|
|
||||||
html-parse-stringify@3.0.1:
|
html-parse-stringify@3.0.1:
|
||||||
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
|
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
|
||||||
|
|
||||||
|
htmlparser2@10.1.0:
|
||||||
|
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
@ -2299,6 +2342,15 @@ packages:
|
||||||
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
|
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
|
linkedom@0.18.12:
|
||||||
|
resolution: {integrity: sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
peerDependencies:
|
||||||
|
canvas: '>= 2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
canvas:
|
||||||
|
optional: true
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2392,6 +2444,9 @@ packages:
|
||||||
node-releases@2.0.36:
|
node-releases@2.0.36:
|
||||||
resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
|
resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
|
||||||
|
|
||||||
|
nth-check@2.1.1:
|
||||||
|
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||||
|
|
||||||
object-inspect@1.13.4:
|
object-inspect@1.13.4:
|
||||||
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -2771,6 +2826,9 @@ packages:
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
uhyphen@0.2.0:
|
||||||
|
resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==}
|
||||||
|
|
||||||
undici-types@7.18.2:
|
undici-types@7.18.2:
|
||||||
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
||||||
|
|
||||||
|
|
@ -4132,6 +4190,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
brace-expansion@5.0.4:
|
brace-expansion@5.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 4.0.4
|
balanced-match: 4.0.4
|
||||||
|
|
@ -4206,13 +4266,25 @@ snapshots:
|
||||||
shebang-command: 2.0.0
|
shebang-command: 2.0.0
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
|
|
||||||
|
css-select@5.2.2:
|
||||||
|
dependencies:
|
||||||
|
boolbase: 1.0.0
|
||||||
|
css-what: 6.2.2
|
||||||
|
domhandler: 5.0.3
|
||||||
|
domutils: 3.2.2
|
||||||
|
nth-check: 2.1.1
|
||||||
|
|
||||||
css-tree@3.2.1:
|
css-tree@3.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
mdn-data: 2.27.1
|
mdn-data: 2.27.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
css-what@6.2.2: {}
|
||||||
|
|
||||||
css.escape@1.5.1: {}
|
css.escape@1.5.1: {}
|
||||||
|
|
||||||
|
cssom@0.5.0: {}
|
||||||
|
|
||||||
csstype@3.2.3: {}
|
csstype@3.2.3: {}
|
||||||
|
|
||||||
data-urls@7.0.0:
|
data-urls@7.0.0:
|
||||||
|
|
@ -4248,6 +4320,24 @@ snapshots:
|
||||||
|
|
||||||
dom-accessibility-api@0.6.3: {}
|
dom-accessibility-api@0.6.3: {}
|
||||||
|
|
||||||
|
dom-serializer@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
entities: 4.5.0
|
||||||
|
|
||||||
|
domelementtype@2.3.0: {}
|
||||||
|
|
||||||
|
domhandler@5.0.3:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
|
domutils@3.2.2:
|
||||||
|
dependencies:
|
||||||
|
dom-serializer: 2.0.0
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
|
||||||
drizzle-kit@0.31.10:
|
drizzle-kit@0.31.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@drizzle-team/brocli': 0.10.2
|
'@drizzle-team/brocli': 0.10.2
|
||||||
|
|
@ -4284,8 +4374,12 @@ snapshots:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
|
|
||||||
|
entities@4.5.0: {}
|
||||||
|
|
||||||
entities@6.0.1: {}
|
entities@6.0.1: {}
|
||||||
|
|
||||||
|
entities@7.0.1: {}
|
||||||
|
|
||||||
es-define-property@1.0.1: {}
|
es-define-property@1.0.1: {}
|
||||||
|
|
||||||
es-errors@1.3.0: {}
|
es-errors@1.3.0: {}
|
||||||
|
|
@ -4576,10 +4670,19 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@noble/hashes'
|
- '@noble/hashes'
|
||||||
|
|
||||||
|
html-escaper@3.0.3: {}
|
||||||
|
|
||||||
html-parse-stringify@3.0.1:
|
html-parse-stringify@3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
void-elements: 3.1.0
|
void-elements: 3.1.0
|
||||||
|
|
||||||
|
htmlparser2@10.1.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
domutils: 3.2.2
|
||||||
|
entities: 7.0.1
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
|
|
@ -4734,6 +4837,14 @@ snapshots:
|
||||||
lightningcss-win32-arm64-msvc: 1.32.0
|
lightningcss-win32-arm64-msvc: 1.32.0
|
||||||
lightningcss-win32-x64-msvc: 1.32.0
|
lightningcss-win32-x64-msvc: 1.32.0
|
||||||
|
|
||||||
|
linkedom@0.18.12:
|
||||||
|
dependencies:
|
||||||
|
css-select: 5.2.2
|
||||||
|
cssom: 0.5.0
|
||||||
|
html-escaper: 3.0.3
|
||||||
|
htmlparser2: 10.1.0
|
||||||
|
uhyphen: 0.2.0
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 5.0.0
|
p-locate: 5.0.0
|
||||||
|
|
@ -4802,6 +4913,10 @@ snapshots:
|
||||||
|
|
||||||
node-releases@2.0.36: {}
|
node-releases@2.0.36: {}
|
||||||
|
|
||||||
|
nth-check@2.1.1:
|
||||||
|
dependencies:
|
||||||
|
boolbase: 1.0.0
|
||||||
|
|
||||||
object-inspect@1.13.4: {}
|
object-inspect@1.13.4: {}
|
||||||
|
|
||||||
obug@2.1.1: {}
|
obug@2.1.1: {}
|
||||||
|
|
@ -5179,6 +5294,8 @@ snapshots:
|
||||||
|
|
||||||
typescript@5.9.3: {}
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
|
uhyphen@0.2.0: {}
|
||||||
|
|
||||||
undici-types@7.18.2: {}
|
undici-types@7.18.2: {}
|
||||||
|
|
||||||
undici@7.24.5: {}
|
undici@7.24.5: {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue