import { json } from "@remix-run/node"; import { err, fromPromise, fromSafePromise, ok } from "neverthrow"; import z from "zod"; import { logger } from "~/services/logger.server"; import { type RemoteBuildProviderStatusResponseBody } from "@trigger.dev/core/v3/schemas"; const DEPOT_STATUS_URL = "https://status.depot.dev/proxy/status.depot.dev"; const FETCH_TIMEOUT_MS = 2000; export async function loader() { return await fetchDepotStatus().match( ({ summary: { ongoing_incidents } }) => { if (ongoing_incidents.length > 0) { return json( { status: "degraded", message: "Our remote build provider is currently facing issues. You can use the `--force-local-build` flag to build and deploy the image locally. Read more about local builds here: https://trigger.dev/docs/deployment/overview#local-builds", } satisfies RemoteBuildProviderStatusResponseBody, { status: 200 } ); } return json( { status: "operational", message: "Depot is operational", } satisfies RemoteBuildProviderStatusResponseBody, { status: 200 } ); }, () => { return json( { status: "unknown", message: "Failed to fetch remote build provider status", } satisfies RemoteBuildProviderStatusResponseBody, { status: 200 } ); } ); } function fetchDepotStatus() { return fromPromise( fetch(DEPOT_STATUS_URL, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), }), (error) => { if ( error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError") ) { return { type: "timeout" as const, }; } return { type: "other" as const, cause: error, }; } ) .andThen((response) => { if (!response.ok) { return err({ type: "other" as const, cause: new Error(`Failed to fetch Depot status: ${response.status}`), }); } return fromSafePromise(response.json()); }) .andThen((json) => { const parsed = DepotStatusResponseSchema.safeParse(json); if (!parsed.success) { logger.warn("Invalid Depot status response", { error: parsed.error }); return err({ type: "validation_failed" as const, }); } return ok(parsed.data); }); } // partial schema const DepotStatusResponseSchema = z.object({ summary: z.object({ ongoing_incidents: z.array(z.any()), }), });