| 1 | /** |
| 2 | * A screenshot of a project's production deployed elsewhere, for its |
| 3 | * overview: of the address its reported production deployment gives, else |
| 4 | * the one set for it (lib/production-image.ts `externalTarget`). The |
| 5 | * address is always the project's own, never one the request names, and |
| 6 | * the og service visits only public ones. For anyone who can see the |
| 7 | * project: it shows a public address. Kept by the browser for an hour; the |
| 8 | * overview's `?v=` changes with each reported deploy and each day. |
| 9 | */ |
| 10 | import { env } from "cloudflare:workers"; |
| 11 | |
| 12 | import type { Route } from "./+types/production-elsewhere"; |
| 13 | import { reportedProduction } from "../../lib/deployments"; |
| 14 | import { externalTarget } from "../../lib/production-image"; |
| 15 | import { deployments } from "../../lib/services.server"; |
| 16 | import { getViewer } from "../../lib/session.server"; |
| 17 | import { projectFor } from "../../lib/access.server"; |
| 18 | |
| 19 | const HOUR = "private, max-age=3600"; |
| 20 | const BRIEF = "private, max-age=60"; |
| 21 | |
| 22 | export async function loader({ params, context }: Route.LoaderArgs) { |
| 23 | const viewer = getViewer(context); |
| 24 | const none = (status: number) => new Response(null, { status, headers: { "cache-control": BRIEF } }); |
| 25 | if (!env.SCREENSHOTS) return none(404); |
| 26 | const project = await projectFor(context, params).catch(() => null); |
| 27 | if (!project?.ok) return none(404); |
| 28 | const repo = project.value.source.kind === "hosted" ? project.value.source.repo : { namespace: params.owner, name: params.repo }; |
| 29 | const environments = await deployments.environments(repo, viewer).catch(() => null); |
| 30 | const reported = reportedProduction(environments?.ok ? environments.value.environments : []); |
| 31 | const target = externalTarget(project.value, reported, Date.now()); |
| 32 | if (!target) return none(404); |
| 33 | const shot = await env.SCREENSHOTS.externalImage({ url: target.url, commit: target.commit, since: target.since ?? undefined }).catch( |
| 34 | (error: unknown) => (console.warn("screenshot:", error), null), |
| 35 | ); |
| 36 | if (!shot) return none(404); |
| 37 | return new Response(shot.body, { |
| 38 | headers: { |
| 39 | "content-type": shot.contentType, |
| 40 | "cache-control": HOUR, |
| 41 | "x-content-type-options": "nosniff", |
| 42 | // A picture of someone's site: shown, never run. |
| 43 | "content-security-policy": "default-src 'none'; sandbox", |
| 44 | "last-modified": new Date(shot.capturedAt).toUTCString(), |
| 45 | }, |
| 46 | }); |
| 47 | } |