mirror your GitHub repos to tangled.org automatically
1

Configure Feed

Select the types of activity you want to include in your feed.

1import type { H3Event, SessionConfig } from 'h3' 2 3/** 4 * Cookie-backed session for the dashboard. The OAuth callback writes the 5 * session after a successful AT Proto login; `requireSession()` reads it on 6 * every dashboard / `/api/me/*` / `/api/repos/*` request. 7 * 8 * Iron-session-style sealed cookie via h3's built-in `useSession`. The 9 * `password` comes from `NUXT_SESSION_PASSWORD` (32+ chars). We read 10 * `process.env` directly so the helper is callable outside a request context 11 * for tests, mirroring `encryption.ts`. 12 * 13 * v1 stores `installationId` alongside `did`: a user may have installed the 14 * GitHub App on more than one account (personal + an org), but the session 15 * pins us to the one they last authenticated against. See the dashboard 16 * "Connect a different installation?" link for the workaround. 17 */ 18export interface SynchubSessionData { 19 did: string 20 installationId: number 21 handle?: string 22} 23 24const COOKIE_NAME = 'synchub-session' 25const COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30 // 30 days 26 27function sessionPassword(): string { 28 const raw = process.env.NUXT_SESSION_PASSWORD 29 if (!raw || raw.length < 32) { 30 throw new Error('NUXT_SESSION_PASSWORD is not set (need 32+ characters of entropy)') 31 } 32 return raw 33} 34 35export function sessionConfig(): SessionConfig { 36 return { 37 name: COOKIE_NAME, 38 password: sessionPassword(), 39 maxAge: COOKIE_MAX_AGE_SECONDS, 40 cookie: { 41 httpOnly: true, 42 sameSite: 'lax', 43 secure: !(process.env.NUXT_PUBLIC_URL?.startsWith('http://127.0.0.1') 44 || process.env.NUXT_PUBLIC_URL?.startsWith('http://localhost')), 45 path: '/', 46 }, 47 } 48} 49 50export async function getSessionData(event: H3Event): Promise<SynchubSessionData | null> { 51 const session = await useSession<SynchubSessionData>(event, sessionConfig()) 52 const { did, installationId } = session.data 53 if (typeof did !== 'string' || typeof installationId !== 'number') return null 54 return { did, installationId, handle: session.data.handle } 55} 56 57/** 58 * Return the current session or throw a 401. Use from any handler that needs 59 * an authenticated user. The thrown error is consumed by Nitro and rendered 60 * as `{ statusCode: 401, statusMessage: 'unauthenticated' }`. 61 */ 62export async function requireSession(event: H3Event): Promise<SynchubSessionData> { 63 const data = await getSessionData(event) 64 if (!data) { 65 throw createError({ statusCode: 401, statusMessage: 'unauthenticated' }) 66 } 67 return data 68} 69 70export async function writeSession(event: H3Event, data: SynchubSessionData): Promise<void> { 71 const session = await useSession<SynchubSessionData>(event, sessionConfig()) 72 await session.update(data) 73}