Something went wrong. Try again.
A Takuzu game native to the AT Protocol. forked from pds.dad/atproto-sveltekit-template atkuzu.tomplanche.com
binairo atproto game takuzu
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127import { readFile } from "node:fs/promises";import { join } from "node:path";import { db } from "$lib/server/db";import type { Handle, ServerInit } from "@sveltejs/kit";import { sequence } from "@sveltejs/kit/hooks";import { migrate } from "drizzle-orm/better-sqlite3/migrator";import { env } from "$env/dynamic/private";import { keyValueStore } from "$lib/server/db/schema";import { and, eq, lt } from "drizzle-orm";import { STATE_STORE } from "$lib/server/cache";import { logger } from "$lib/server/logger";import { HOUR } from "@atproto/common";import { getSessionManager, SessionRestorationError } from "$lib/server/session";
const clearExpiredStates = async () => { try { logger.info("Running cleanup of the state store"); const oneHourAgo = new Date(Date.now() - HOUR); const result = await db .delete(keyValueStore) .where( and(eq(keyValueStore.storeName, STATE_STORE), lt(keyValueStore.createdAt, oneHourAgo)) );
if (result.changes > 0) { logger.info(`Cleaned up ${result.changes} expired key(s) from keyValueStore`); } } catch (err) { logger.error(`${(err as Error).message}`); }};
export const init: ServerInit = async () => { // Run Drizzle migrations on server startup migrate(db, { migrationsFolder: env.MIGRATIONS_FOLDER ?? "drizzle" });
await clearExpiredStates();
// Start a background job to clean up state every hour, which is recommended in the oauth docs setInterval(async () => { await clearExpiredStates(); //TODO prob should do one for the session store as well for expired sessions }, HOUR); // Run every hour};
// `/daily/index.json` or `/daily/<YYYY-MM-DD>.json`, the archive files of ADR 0001.const DAILY_FILE_PATTERN = /^\/daily\/(index|\d{4}-\d{2}-\d{2})\.json$/;
/** * Serves the daily archive from `DAILY_DIR` when it is set (production). The dailies are * written there after the build, so they are not among the static assets of the build, and * the server-side render of /daily, which fetches them through SvelteKit's internal fetch, * would not see them. This hook answers that internal fetch and the browser alike, so a new * daily needs no rebuild and no restart. Without `DAILY_DIR` (dev), static/daily serves them. */const serveDaily: Handle = async ({ event, resolve }) => { const match = DAILY_FILE_PATTERN.exec(event.url.pathname); if (!env.DAILY_DIR || match === null) { return resolve(event); }
const name = match[1]; try { const body = await readFile(join(env.DAILY_DIR, `${name}.json`));
return new Response(body, { headers: { "content-type": "application/json", // A dated daily never changes once published; the index gains a date every day. "cache-control": name === "index" ? "no-cache" : "public, max-age=86400" } }); } catch { return new Response("not found", { status: 404 }); }};
const restoreSession: Handle = async ({ event, resolve }) => { const token = event.cookies.get("session") ?? null; if (token === null) { event.locals.session = null; event.locals.atpAgent = null; return resolve(event); }
const sessionManager = await getSessionManager();
try { const { atpAgent, did, handle: sessionHandle } = await sessionManager.getSessionFromRequest(event);
if (atpAgent == null) { event.locals.session = null; event.locals.atpAgent = null; return resolve(event); }
// Store atpAgent in locals (server-side only, not serialized) event.locals.atpAgent = atpAgent;
// Store only serializable data in session (gets passed to client via load functions) event.locals.session = { did, handle: sessionHandle }; } catch (err) { if (err instanceof SessionRestorationError) { //You can propagate this error to the frontend to let your users know their session unexpectedly ended //I opted out of not completely implementing this since everyone may have a different idea of what to do in their apps //For instance I would use the cache to create a flash message that when loaded it deletes and show it on the layout } else { // Unexpected error, re-throw throw err; }
event.locals.session = null; event.locals.atpAgent = null; }
return resolve(event);};
export const handle = sequence(serveDaily, restoreSession);