feat(site): add Mux health check action (#542)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-02-17 13:11:22 -06:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 78de97ec23
commit 1d6cc2b8c0
4 changed files with 53 additions and 0 deletions
+2
View File
@@ -649,6 +649,8 @@ The site uses OAuth for authentication and Mux for video management. Required va
| Variable | Purpose |
| --- | --- |
| `MUX_API_URL` | Override Mux API endpoint (defaults to `https://api.mux.com`) |
| `MUX_TOKEN_ID` | Mux API token ID (for server-side health checks) |
| `MUX_TOKEN_SECRET` | Mux API token secret (for server-side health checks) |
| `SENTRY_AUTH_TOKEN` | Sentry error tracking auth token |
## Authentication & Mux Integration
+34
View File
@@ -22,7 +22,41 @@ function getMuxClient(token: string | undefined) {
});
}
function getHealthMuxClient() {
const tokenId = process.env.MUX_TOKEN_ID || import.meta.env.MUX_TOKEN_ID;
const tokenSecret = process.env.MUX_TOKEN_SECRET || import.meta.env.MUX_TOKEN_SECRET;
if (!tokenId || !tokenSecret) {
throw new ActionError({
code: 'INTERNAL_SERVER_ERROR',
message: 'MUX_TOKEN_ID and MUX_TOKEN_SECRET must be set',
});
}
return new Mux({
tokenId,
tokenSecret,
});
}
export const mux = {
/** Unauthenticated health check that verifies the Mux API proxy layer. */
health: defineAction({
handler: async () => {
try {
const muxClient = getHealthMuxClient();
await muxClient.video.assets.list({ limit: 0 });
return { ok: true };
} catch (error) {
if (error instanceof ActionError) throw error;
throw new ActionError({
code: 'INTERNAL_SERVER_ERROR',
message: error instanceof Error ? error.message : 'Mux health check failed',
});
}
},
}),
/**
* List video assets with pagination
*
+3
View File
@@ -22,6 +22,9 @@ function isGated(actionName: string | undefined) {
// detect UNAUTHORIZED and show a login UI before uploading
if (actionName === 'mux.createDirectUpload') return false;
// Health check uses server-side credentials, not user OAuth
if (actionName === 'mux.health') return false;
// I don't love the magic string nature of this pattern but it's what is recommended in the docs
return actionName.startsWith('mux');
}
+14
View File
@@ -0,0 +1,14 @@
import { actions } from 'astro:actions';
import type { APIRoute } from 'astro';
export const prerender = false;
export const GET: APIRoute = async (context) => {
const { data, error } = await context.callAction(actions.mux.health, {});
if (error) {
return Response.json({ ok: false, error: error.message }, { status: 502 });
}
return Response.json(data);
};