Attic is a cozy space with lofty ambitions. attic.social

improve login

dbushell.com 6f9cfe42 b477365b

verified
+46 -22
+4
README.md
··· 2 3 Attic is a cozy space with lofty ambitions. 4 5 * * * 6 7 Copyright © 2026 [David Bushell](https://dbushell.com)
··· 2 3 Attic is a cozy space with lofty ambitions. 4 5 + What does Attic do? I'm still deciding... it'll probably become a random assortment of features. Right now it has bookmarks. Bookmarks will have search and tags soon. 6 + 7 + Attic is extremely early in development! Use a your own risk :) 8 + 9 * * * 10 11 Copyright © 2026 [David Bushell](https://dbushell.com)
+23 -18
src/lib/server/session.ts
··· 40 handle: string, 41 ): Promise<URL> => { 42 if (isHandle(handle) === false) { 43 - throw new Error("invalid handle"); 44 } 45 - const oAuthClient = createOAuthClient(event); 46 - const { url } = await oAuthClient.authorize({ 47 - target: { "type": "account", identifier: handle }, 48 - }); 49 - // Temporary to remember handle across oauth flow 50 - event.cookies.set( 51 - HANDLE_COOKIE, 52 - handle, 53 - { 54 - httpOnly: true, 55 - maxAge: OAUTH_MAX_AGE, 56 - path: "/", 57 - sameSite: "lax", 58 - secure: !dev, 59 - }, 60 - ); 61 - return url; 62 }; 63 64 /**
··· 40 handle: string, 41 ): Promise<URL> => { 42 if (isHandle(handle) === false) { 43 + throw new Error("Invalid handle."); 44 + } 45 + try { 46 + const oAuthClient = createOAuthClient(event); 47 + const { url } = await oAuthClient.authorize({ 48 + target: { "type": "account", identifier: handle }, 49 + }); 50 + // Temporary to remember handle across oauth flow 51 + event.cookies.set( 52 + HANDLE_COOKIE, 53 + handle, 54 + { 55 + httpOnly: true, 56 + maxAge: OAUTH_MAX_AGE, 57 + path: "/", 58 + sameSite: "lax", 59 + secure: !dev, 60 + }, 61 + ); 62 + return url; 63 + } catch (err) { 64 + console.log(err); 65 + throw new Error("OAuth failed."); 66 } 67 }; 68 69 /**
+6
src/routes/+layout.svelte
··· 1 <script lang="ts"> 2 import "$css/main.css"; 3 import { pointer } from "$lib/dialog.svelte.js"; 4 import { onMount } from "svelte"; 5 6 onMount(() => { 7 if (pointer.ref) { 8 pointer.ref.showPopover(); 9 }
··· 1 <script lang="ts"> 2 + import { dev } from "$app/environment"; 3 import "$css/main.css"; 4 import { pointer } from "$lib/dialog.svelte.js"; 5 import { onMount } from "svelte"; 6 7 onMount(() => { 8 + if (dev === false) { 9 + globalThis.addEventListener("load", () => { 10 + navigator.serviceWorker.register("/service-worker.js"); 11 + }); 12 + } 13 if (pointer.ref) { 14 pointer.ref.showPopover(); 15 }
+10 -4
src/routes/+page.server.ts
··· 21 throw new Error(); 22 } 23 const formData = await event.request.formData(); 24 - const handle = formData.get("handle"); 25 let url: URL; 26 try { 27 event.cookies.delete(HANDLE_COOKIE, { path: "/" }); 28 - url = await startSession(event, String(handle ?? "")); 29 } catch (err) { 30 - console.log(err); 31 - return fail(400, { handle, action: "login", error: "Invalid handle." }); 32 } 33 redirect(303, url); 34 },
··· 21 throw new Error(); 22 } 23 const formData = await event.request.formData(); 24 + let handle = String(formData.get("handle")); 25 + if (handle.startsWith("@")) { 26 + handle = handle.substring(1); 27 + } 28 let url: URL; 29 try { 30 event.cookies.delete(HANDLE_COOKIE, { path: "/" }); 31 + url = await startSession(event, handle); 32 } catch (err) { 33 + let message = "Login failed."; 34 + if (err instanceof Error && err.message) { 35 + message = err.message; 36 + } 37 + return fail(400, { handle, action: "login", error: message }); 38 } 39 redirect(303, url); 40 },
+3
svelte.config.js
··· 14 publicPrefix: "PUBLIC", 15 privatePrefix: "PRIVATE", 16 }, 17 }, 18 }; 19
··· 14 publicPrefix: "PUBLIC", 15 privatePrefix: "PRIVATE", 16 }, 17 + serviceWorker: { 18 + register: false, 19 + }, 20 }, 21 }; 22