1import { authClient } from "./client.ts";
2
3const form = document.querySelector<HTMLFormElement>("#auth-form")!;
4const status = document.querySelector<HTMLOutputElement>("#status")!;
5const sessionOutput = document.querySelector<HTMLPreElement>("#session")!;
6const meOutput = document.querySelector<HTMLPreElement>("#me")!;
7const providers = document.querySelector<HTMLDivElement>("#providers")!;
8const name = document.querySelector<HTMLInputElement>("#name")!;
9const email = document.querySelector<HTMLInputElement>("#email")!;
10const password = document.querySelector<HTMLInputElement>("#password")!;
11
12async function refresh() {
13 const session = await authClient.getSession();
14 if (session.error)
15 throw new Error(session.error.message ?? "Session lookup failed");
16 sessionOutput.textContent = JSON.stringify(
17 session.data
18 ? { user: session.data.user, expiresAt: session.data.session.expiresAt }
19 : null,
20 null,
21 2,
22 );
23 const response = await fetch("/api/me");
24 const body = await response.json();
25 meOutput.textContent = `${response.status}\n${JSON.stringify(body, null, 2)}`;
26 if (!response.ok && response.status !== 401) {
27 throw new Error(`The private API returned ${response.status}`);
28 }
29}
30
31async function run(action: () => Promise<void>) {
32 const buttons = document.querySelectorAll<HTMLButtonElement>("button");
33 buttons.forEach((button) => {
34 button.disabled = true;
35 });
36 status.textContent = "Working…";
37 try {
38 await action();
39 status.textContent = "Ready";
40 } catch (error) {
41 status.textContent = error instanceof Error ? error.message : String(error);
42 } finally {
43 buttons.forEach((button) => {
44 button.disabled = false;
45 });
46 }
47}
48
49form.addEventListener("submit", (event) => event.preventDefault());
50
51document.querySelector("#sign-up")!.addEventListener("click", () => {
52 if (!form.reportValidity()) return;
53 if (!name.value.trim()) {
54 status.textContent = "Enter a name to sign up.";
55 return;
56 }
57 void run(async () => {
58 const result = await authClient.signUp.email({
59 name: name.value.trim(),
60 email: email.value,
61 password: password.value,
62 });
63 if (result.error) throw new Error(result.error.message ?? "Sign up failed");
64 password.value = "";
65 await refresh();
66 });
67});
68
69document.querySelector("#sign-in")!.addEventListener("click", () => {
70 if (!form.reportValidity()) return;
71 void run(async () => {
72 const result = await authClient.signIn.email({
73 email: email.value,
74 password: password.value,
75 });
76 if (result.error) throw new Error(result.error.message ?? "Sign in failed");
77 password.value = "";
78 await refresh();
79 });
80});
81
82document.querySelector("#sign-out")!.addEventListener("click", () => {
83 void run(async () => {
84 const result = await authClient.signOut();
85 if (result.error)
86 throw new Error(result.error.message ?? "Sign out failed");
87 await refresh();
88 });
89});
90
91document
92 .querySelector("#refresh")!
93 .addEventListener("click", () => void run(refresh));
94
95void run(async () => {
96 const response = await fetch("/api/providers");
97 if (!response.ok)
98 throw new Error(`Provider lookup returned ${response.status}`);
99 const enabled: { github: boolean } = await response.json();
100 if (enabled.github) {
101 const button = document.createElement("button");
102 button.type = "button";
103 button.textContent = "Continue with GitHub";
104 button.addEventListener("click", () => {
105 void run(async () => {
106 const result = await authClient.signIn.social({
107 provider: "github",
108 callbackURL: "/",
109 });
110 if (result.error)
111 throw new Error(result.error.message ?? "GitHub sign in failed");
112 });
113 });
114 providers.append(button);
115 }
116 await refresh();
117});