feat(stammbaum): server-clamped initial view from ?cx&cy&z (#692)

The server load parses and sanitises the shareable pan/zoom params (degrading
Infinity/NaN, clamping zoom) into initialView, which seeds the page view. A
crafted link can no longer blank the SVG (Nora). US-PANEL-002 AC2 groundwork.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-29 16:58:36 +02:00
parent 396c87f8ab
commit 8d29bb10e2
4 changed files with 85 additions and 10 deletions

View File

@@ -1,8 +1,9 @@
import { error, redirect } from '@sveltejs/kit';
import { createApiClient, extractErrorCode } from '$lib/shared/api.server';
import { getErrorMessage } from '$lib/shared/errors';
import { parsePanZoomParams } from '$lib/person/genealogy/panZoom';
export async function load({ fetch }) {
export async function load({ fetch, url }) {
const api = createApiClient(fetch);
const result = await api.GET('/api/network');
@@ -12,6 +13,15 @@ export async function load({ fetch }) {
throw error(result.response.status, getErrorMessage(extractErrorCode(result.error)));
}
// Sanitise the shareable pan/zoom params server-side so a crafted link
// (?z=Infinity, ?cx=NaN) degrades to a safe view before reaching layout
// geometry (Nora #692).
const initialView = parsePanZoomParams({
cx: url.searchParams.get('cx'),
cy: url.searchParams.get('cy'),
z: url.searchParams.get('z')
});
const network = result.data!;
return { nodes: network.nodes ?? [], edges: network.edges ?? [] };
return { nodes: network.nodes ?? [], edges: network.edges ?? [], initialView };
}