tangled
alpha
login
or
join now
byarielm.fyi
/
atlast
16
fork
atom
ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
16
fork
atom
overview
issues
1
pulls
pipelines
use shared connection for db calls, reuse db client
byarielm.fyi
4 months ago
5c3cd5c4
195d3540
+12
-17
2 changed files
expand all
collapse all
unified
split
netlify
functions
db.ts
oauth-stores-db.ts
+2
netlify/functions/db.ts
···
1
1
import { neon, NeonQueryFunction } from '@neondatabase/serverless';
2
2
3
3
let sql: NeonQueryFunction<any, any> | undefined = undefined;
4
4
+
let connectionInitialized = false;
4
5
5
6
export function getDbClient() {
6
7
if (!sql) {
7
8
sql = neon(process.env.NETLIFY_DATABASE_URL!);
9
9
+
connectionInitialized = true;
8
10
}
9
11
return sql;
10
12
}
+10
-17
netlify/functions/oauth-stores-db.ts
···
11
11
tokenSet: any;
12
12
}
13
13
14
14
+
// Reuse the same DB client across all store instances
15
15
+
const sql = getDbClient();
16
16
+
14
17
export class PostgresStateStore {
15
18
async get(key: string): Promise<StateData | undefined> {
16
16
-
const sql = getDbClient();
17
19
const result = await sql`
18
20
SELECT data FROM oauth_states
19
21
WHERE key = ${key} AND expires_at > NOW()
20
22
`;
21
21
-
// FIX: Cast result to an array of records to resolve TypeScript error 7053
22
23
return (result as Record<string, any>[])[0]?.data as StateData | undefined;
23
24
}
24
25
25
26
async set(key: string, value: StateData): Promise<void> {
26
26
-
const sql = getDbClient();
27
27
-
const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes
28
28
-
await sql`
29
29
-
INSERT INTO oauth_states (key, data, expires_at)
30
30
-
VALUES (${key}, ${JSON.stringify(value)}, ${expiresAt.toISOString()})
31
31
-
ON CONFLICT (key) DO UPDATE SET data = ${JSON.stringify(value)}, expires_at = ${expiresAt.toISOString()}
32
32
-
`;
33
33
-
}
27
27
+
const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes
28
28
+
await sql`
29
29
+
INSERT INTO oauth_states (key, data, expires_at)
30
30
+
VALUES (${key}, ${JSON.stringify(value)}, ${expiresAt.toISOString()})
31
31
+
ON CONFLICT (key) DO UPDATE SET data = ${JSON.stringify(value)}, expires_at = ${expiresAt.toISOString()}
32
32
+
`;
33
33
+
}
34
34
35
35
async del(key: string): Promise<void> {
36
36
-
const sql = getDbClient();
37
36
await sql`DELETE FROM oauth_states WHERE key = ${key}`;
38
37
}
39
38
}
40
39
41
40
export class PostgresSessionStore {
42
41
async get(key: string): Promise<SessionData | undefined> {
43
43
-
const sql = getDbClient();
44
42
const result = await sql`
45
43
SELECT data FROM oauth_sessions
46
44
WHERE key = ${key} AND expires_at > NOW()
···
49
47
}
50
48
51
49
async set(key: string, value: SessionData): Promise<void> {
52
52
-
const sql = getDbClient();
53
50
// Session includes tokens, DPoP keys, etc.
54
51
const expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000); // 14 days
55
52
await sql`
···
60
57
}
61
58
62
59
async del(key: string): Promise<void> {
63
63
-
const sql = getDbClient();
64
60
await sql`DELETE FROM oauth_sessions WHERE key = ${key}`;
65
61
}
66
62
}
67
63
68
64
export class PostgresUserSessionStore {
69
65
async get(sessionId: string): Promise<{ did: string } | undefined> {
70
70
-
const sql = getDbClient();
71
66
const result = await sql`
72
67
SELECT did FROM user_sessions
73
68
WHERE session_id = ${sessionId} AND expires_at > NOW()
···
77
72
}
78
73
79
74
async set(sessionId: string, data: { did: string }): Promise<void> {
80
80
-
const sql = getDbClient();
81
75
const expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000); // 14 days
82
76
await sql`
83
77
INSERT INTO user_sessions (session_id, did, expires_at)
···
89
83
}
90
84
91
85
async del(sessionId: string): Promise<void> {
92
92
-
const sql = getDbClient();
93
86
await sql`DELETE FROM user_sessions WHERE session_id = ${sessionId}`;
94
87
}
95
88
}