Skip to content
Source
Sign inSign up
Open History to see the last commit

ui.ts

109 lines3.7 KB

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