ptitlutins/app/middleware/voyage.ts
2026-06-15 23:34:49 +02:00

40 lines
1.3 KiB
TypeScript

import { parseNodePath } from "~/utils/nodePath"
import { resolvePath } from "~/utils/resolvePath"
/**
* Route loader for `/voyages/:id`. The URL is the single source of truth for
* navigation; this guard projects it into the store before the page renders:
*
* 1. ensure the link + all its entities are loaded (idempotent, deduped — a
* node change within the same voyage is an instant no-op, no refetch),
* 2. validate the `?n=` path against the freshly-built tree → 404 if it points
* at an event that doesn't exist (stale/shared deep link),
* 3. write the focused path (this guard is its only writer).
*
* On a load failure we don't 404 (the path can't be judged against missing
* data): we reset the focus and let the page surface its retryable error state.
*/
export default defineNuxtRouteMiddleware(async (to) => {
const linkId = to.params.id as string
const voyage = useVoyageStore()
await voyage.ensureVoyageLoaded(linkId)
if (voyage.error) {
voyage.setFocusedPath([])
return
}
const path = parseNodePath(to.query.n)
const resolved = resolvePath(voyage.voyageTree, path)
if (resolved.length !== path.length + 1) {
throw createError({
statusCode: 404,
statusMessage: "Not Found",
message: "Étape introuvable",
fatal: true,
})
}
voyage.setFocusedPath(path)
})