example restaurant review app on atproto
1import type {
2 NodeSavedSession,
3 NodeSavedSessionStore,
4 NodeSavedState,
5 NodeSavedStateStore,
6} from "@atproto/oauth-client-node";
7import type { DrizzleClient } from "../drizzle/db";
8import { eq } from "drizzle-orm";
9import { sessions, states } from "../drizzle/schema";
10
11export class StateStore implements NodeSavedStateStore {
12 constructor(private db: DrizzleClient) {}
13 async get(key: string): Promise<NodeSavedState | undefined> {
14 const result = await this.db.query.states.findFirst({
15 where: eq(states.key, key),
16 });
17
18 if (!result?.state) return;
19 return JSON.parse(result.state);
20 }
21 async set(key: string, value: NodeSavedState) {
22 const state = JSON.stringify(value);
23
24 await this.db
25 .insert(states)
26 .values({
27 key,
28 state,
29 })
30 .onConflictDoUpdate({
31 target: states.key,
32 set: {
33 state,
34 },
35 });
36 }
37 async del(key: string) {
38 await this.db.delete(states).where(eq(states.key, key));
39 }
40}
41
42export class SessionStore implements NodeSavedSessionStore {
43 constructor(private db: DrizzleClient) {}
44 async get(key: string): Promise<NodeSavedSession | undefined> {
45 const result = await this.db.query.sessions.findFirst({
46 where: eq(states.key, key),
47 });
48
49 if (!result?.session) return;
50 return JSON.parse(result.session) as NodeSavedSession;
51 }
52 async set(key: string, value: NodeSavedSession) {
53 const session = JSON.stringify(value);
54
55 await this.db
56 .insert(sessions)
57 .values({
58 key,
59 session,
60 })
61 .onConflictDoUpdate({
62 target: sessions.key,
63 set: {
64 session,
65 },
66 });
67 }
68 async del(key: string) {
69 await this.db.delete(sessions).where(eq(states.key, key));
70 }
71}