| 1 | import { env } from "cloudflare:workers"; |
| 2 | |
| 3 | import type { Route } from "./+types/observability-live"; |
| 4 | import { observed } from "../../lib/observability.server"; |
| 5 | |
| 6 | /** |
| 7 | * A project's live tail: `wss://<site>/<owner>/<project>/observability/live`. |
| 8 | * The site checks the viewer may read the project's observability and that |
| 9 | * the page asking is its own, then hands the upgrade to the project's store |
| 10 | * (services/telemetry), which sends each request, log line and span as it |
| 11 | * arrives. Nothing of the browser's goes on. |
| 12 | */ |
| 13 | export async function loader({ context, request, params }: Route.LoaderArgs) { |
| 14 | if (request.headers.get("upgrade")?.toLowerCase() !== "websocket") { |
| 15 | return new Response("This address takes a WebSocket.", { status: 426, headers: { upgrade: "websocket" } }); |
| 16 | } |
| 17 | const origin = request.headers.get("origin"); |
| 18 | if (origin && origin !== new URL(request.url).origin) return new Response("Cross-origin socket refused", { status: 403 }); |
| 19 | const { projectId } = await observed(context, params, request); |
| 20 | if (!env.TELEMETRY) return new Response("Observability is not set up here.", { status: 503 }); |
| 21 | return env.TELEMETRY.fetch( |
| 22 | new Request(`https://telemetry/live?project_id=${encodeURIComponent(projectId)}`, { headers: { upgrade: "websocket" } }), |
| 23 | ); |
| 24 | } |