Scratch space for learning atproto app development
1import assert from 'node:assert'
2import type { IncomingMessage, ServerResponse } from 'node:http'
3import { getIronSession } from 'iron-session'
4import { env } from '#/lib/env'
5import { AppContext } from '#/index'
6
7export type Session = { did: string }
8
9export async function createSession(
10 req: IncomingMessage,
11 res: ServerResponse<IncomingMessage>,
12 did: string
13) {
14 const session = await getSessionRaw(req, res)
15 assert(!session.did, 'session already exists')
16 session.did = did
17 await session.save()
18 return { did: session.did }
19}
20
21export async function destroySession(
22 req: IncomingMessage,
23 res: ServerResponse<IncomingMessage>
24) {
25 const session = await getSessionRaw(req, res)
26 await session.destroy()
27 return null
28}
29
30export async function getSession(
31 req: IncomingMessage,
32 res: ServerResponse<IncomingMessage>
33) {
34 const session = await getSessionRaw(req, res)
35 if (!session.did) return null
36 return { did: session.did }
37}
38
39export async function getSessionAgent(
40 req: IncomingMessage,
41 res: ServerResponse<IncomingMessage>,
42 ctx: AppContext
43) {
44 const session = await getSessionRaw(req, res)
45 if (!session.did) return null
46 return await ctx.oauthClient.restore(session.did).catch(async (err) => {
47 ctx.logger.warn({ err }, 'oauth restore failed')
48 await destroySession(req, res)
49 return null
50 })
51}
52
53async function getSessionRaw(
54 req: IncomingMessage,
55 res: ServerResponse<IncomingMessage>
56) {
57 return await getIronSession<Session>(req, res, {
58 cookieName: 'sid',
59 password: env.COOKIE_SECRET,
60 })
61}