Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

24 linesCodeBlameRaw
1import { env } from "cloudflare:workers";
2
3import type { Route } from "./+types/observability-live";
4import { 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 */
13export 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}