Sifa professional network API (Fastify, AT Protocol, Jetstream) sifa.id/
at main 39 lines 1.5 kB view raw
1import type { NodeSavedState, NodeSavedStateStore } from '@atproto/oauth-client-node'; 2 3/** 4 * Valkey (Redis-compatible) backed state store for ATproto OAuth. 5 * Implements the SimpleStore<string, NodeSavedState> interface required by NodeOAuthClient. 6 * 7 * OAuth authorization state is short-lived (10 minute TTL) so Valkey is a 8 * natural fit -- no database writes needed for ephemeral data that expires 9 * quickly. 10 */ 11export class ValkeyStateStore implements NodeSavedStateStore { 12 constructor(private valkey: ValkeyClient) {} 13 14 async get(key: string): Promise<NodeSavedState | undefined> { 15 const data = await this.valkey.get(`oauth-state:${key}`); 16 return data ? (JSON.parse(data) as NodeSavedState) : undefined; 17 } 18 19 async set(key: string, val: NodeSavedState): Promise<void> { 20 // 10 minute TTL -- OAuth state should be consumed quickly 21 await this.valkey.set(`oauth-state:${key}`, JSON.stringify(val), 'EX', 600); 22 } 23 24 async del(key: string): Promise<void> { 25 await this.valkey.del(`oauth-state:${key}`); 26 } 27} 28 29/** 30 * Minimal interface for a Redis/Valkey client. Compatible with ioredis and 31 * node-redis. Using a structural type avoids coupling to a specific client 32 * library. 33 */ 34export interface ValkeyClient { 35 get(key: string): Promise<string | null>; 36 set(key: string, value: string, exFlag: 'EX', seconds: number): Promise<unknown>; 37 // eslint-disable-next-line @typescript-eslint/no-explicit-any 38 del(...args: any[]): Promise<number>; 39}