1export async function authRequest<T>(path: string, body?: object): Promise<T> {
2 const response = await fetch(`/auth/${path}`, body ? {
3 method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body),
4 } : undefined);
5 if (!response.ok) throw new DetailedError(response.statusText, { statusCode: response.status, detail: { data: await response.text() } });
6 return response.status === 204 ? undefined as T : response.json();
7}
8
9export async function addPasskey(label: string) {
10 const { csrf } = await authRequest<{ csrf: string }>("status");
11 const { options, token } = await authRequest<{ options: { publicKey: PublicKeyCredentialCreationOptionsJSON }; token: string }>("passkey/register", { csrf });
12 const credential = await navigator.credentials.create({ publicKey: PublicKeyCredential.parseCreationOptionsFromJSON(options.publicKey) });
13 if (!(credential instanceof PublicKeyCredential)) throw new Error("Passkey setup was canceled. Try again when you're ready.");
14 await authRequest("passkey/save", { csrf, token, credential: credential.toJSON(), label });
15}
16
17export async function signOut() {
18 await authRequest("sign-out", {});
19 window.location.assign("/sign-in");
20}
21
22export const authReason = (failure: unknown) => failure instanceof DetailedError ? reason(failure) : failure instanceof Error ? failure.message : "Couldn't finish sign-in. Try again.";
23import { DetailedError } from "hono/client";
24import { reason } from "./api.ts";