Auth is Supabase end to end and always was: the backend verifies access tokens asymmetrically against the project's published JWKS and holds no signing key of its own, and `requireUser` wants that token in `Authorization: Bearer`. Nothing about that needed changing. What was wrong is only here. The two REST calls forwarded `useRequestHeaders(["cookie"])`, which is what you do when a Nuxt server is proxying a browser's request - and this app sets `ssr: false` so the same static bundle can serve the browser and the Tauri shell. There is no server to forward anything, so the header arrived empty and every call should have been getting a flat 401. The token was to hand the whole time. `stores/telemetry.ts` has been reading `session.access_token` for its socket since it was written; the REST side simply never did. `useApiFetch` is now the one way this app calls the backend, and it reads the token inside the fetcher rather than capturing it at setup, because supabase-js refreshes the session in the background about once an hour - a captured token would work until it quietly stopped. With no session it omits the header entirely rather than sending an empty Bearer, which the backend rejects with a message about the header's shape and reads like a client bug; getting the user a session is the Supabase module's redirect's job. The socket keeps using a `?token=` query parameter, which is not an inconsistency: a browser WebSocket cannot set request headers. `nuxt typecheck` clean.
57 lines
2.5 KiB
TypeScript
57 lines
2.5 KiB
TypeScript
/**
|
|
* Where a printer's camera can be watched, from `GET /printers/:id/stream`.
|
|
*/
|
|
export interface PrinterStream {
|
|
streamUrl: string;
|
|
cameraId: string;
|
|
}
|
|
|
|
/**
|
|
* Asks the backend where a printer's camera can be watched, or `null` if it
|
|
* cannot.
|
|
*
|
|
* This replaces the build-time `go2rtcStreamBase` that used to live in
|
|
* `nuxt.config.ts`. A single compiled-in URL can only ever be correct for a
|
|
* one-farm deployment: the stream lives on a gateway box inside a farm's own
|
|
* network, each farm has its own, and the gateway reports its address to the
|
|
* backend when it connects. So the address has to be asked for at runtime,
|
|
* per printer, rather than baked in.
|
|
*
|
|
* A plain function and not a `useAsyncData` wrapper despite the file it lives
|
|
* in: the caller needs one of these per printer, discovered from a list that
|
|
* itself arrives asynchronously, and Nuxt's data composables may only be
|
|
* called while a component is setting up. A loop over a resolved list is not
|
|
* that. It takes the fetcher as an argument for the same reason - the caller
|
|
* builds it in setup, where `useApiFetch` is valid.
|
|
*
|
|
* **Absence is the normal case, not an error.** Only Bambu's X1/H2 class
|
|
* publishes a camera URL a gateway can restream; a P1 or A1 reports that it
|
|
* has a camera and gives nothing to connect to. The backend answers 404 for
|
|
* those, so this answers `null` and the caller shows no player at all -
|
|
* rendering one that can never load would be worse than rendering nothing.
|
|
*
|
|
* It is also a LAN address with no relay in front of it, so the stream plays
|
|
* only for someone on the same network as the printers. That is the right
|
|
* trade-off for an operator standing in the workshop, and a real limitation
|
|
* for anyone else.
|
|
*/
|
|
export async function fetchPrinterStream(
|
|
apiFetch: ReturnType<typeof useApiFetch>,
|
|
printerId: string,
|
|
): Promise<PrinterStream | null> {
|
|
try {
|
|
return await apiFetch<PrinterStream>(`/printers/${printerId}/stream`);
|
|
} catch (err: unknown) {
|
|
// A 404 means "this printer has no watchable camera", which is expected
|
|
// often enough that treating it as a failure would put an error state on
|
|
// most cards in a mixed fleet. Anything else is a real problem: logged
|
|
// and then treated as "no stream", because a broken camera lookup should
|
|
// not take the fleet overview down with it.
|
|
const status = (err as { statusCode?: number }).statusCode;
|
|
if (status !== 404) {
|
|
console.warn(`could not look up the camera stream for printer ${printerId}`, err);
|
|
}
|
|
return null;
|
|
}
|
|
}
|