trails/apps/planner/app/routes/api.sessions.ts
Ullrich Schäfer 464ba0f64d
Add Planner session management with Yjs WebSocket (#1)
- Yjs WebSocket server at /sync/:sessionId for real-time collaboration
- Session creation API (POST /api/sessions) with optional GPX initialization
- Session join page with Planner layout (header, map area, sidebar)
- In-memory session store (PostgreSQL persistence deferred to infra setup)
- Custom production server entry with WebSocket upgrade handling
- Vite path aliases (~/) for clean imports
- Fix tsconfig for apps: noEmit, exclude build dir

Tasks completed: 4.1, 4.3, 4.4, 4.5
Deferred: 4.2 (PostgreSQL), 4.6-4.8 (need client-side Yjs from Group 6)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:26:03 +01:00

40 lines
1 KiB
TypeScript

import { data } from "react-router";
import type { Route } from "./+types/api.sessions";
import { createSession, initializeSessionWithWaypoints, listSessions } from "~/lib/sessions";
import { parseGpx } from "@trails-cool/gpx";
export async function action({ request }: Route.ActionArgs) {
if (request.method !== "POST") {
return data({ error: "Method not allowed" }, { status: 405 });
}
const body = await request.json();
const { callbackUrl, callbackToken, gpx } = body as {
callbackUrl?: string;
callbackToken?: string;
gpx?: string;
};
const session = createSession({ callbackUrl, callbackToken });
if (gpx) {
try {
const gpxData = parseGpx(gpx);
initializeSessionWithWaypoints(session.id, gpxData.waypoints);
} catch (_e) {
// Continue with empty session if GPX is invalid
}
}
return data(
{
sessionId: session.id,
url: `/session/${session.id}`,
},
{ status: 201 },
);
}
export async function loader(_args: Route.LoaderArgs) {
return data({ sessions: listSessions() });
}