an app to share curated trails sidetrail.app
1

Configure Feed

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

at main 1.6 kB View raw
1import "server-only"; 2import Redis from "ioredis"; 3 4let redis: Redis | null = null; 5 6function getRedis(): Redis { 7 if (!redis) { 8 redis = new Redis(process.env.REDIS_URL || "redis://localhost:6379", { 9 maxRetriesPerRequest: 3, 10 lazyConnect: true, 11 }); 12 redis.on("error", (err) => { 13 console.error("[redis] connection error:", err.message); 14 }); 15 } 16 return redis; 17} 18 19export type SimpleStoreRedisOptions = { 20 keyPrefix: string; 21 ttlSeconds: number; 22}; 23 24/** 25 * Simple Redis-backed store compatible with @atproto SimpleStore interface. 26 * Used for OAuth caches that should survive server restarts. 27 */ 28export class SimpleStoreRedis<V> { 29 private keyPrefix: string; 30 private ttlSeconds: number; 31 32 constructor(options: SimpleStoreRedisOptions) { 33 this.keyPrefix = options.keyPrefix; 34 this.ttlSeconds = options.ttlSeconds; 35 } 36 37 async get(key: string): Promise<V | undefined> { 38 try { 39 const value = await getRedis().get(this.keyPrefix + key); 40 if (!value) return undefined; 41 return JSON.parse(value) as V; 42 } catch (err) { 43 console.error("[redis-store] get error:", err); 44 return undefined; 45 } 46 } 47 48 async set(key: string, value: V): Promise<void> { 49 try { 50 await getRedis().set(this.keyPrefix + key, JSON.stringify(value), "EX", this.ttlSeconds); 51 } catch (err) { 52 console.error("[redis-store] set error:", err); 53 } 54 } 55 56 async del(key: string): Promise<void> { 57 try { 58 await getRedis().del(this.keyPrefix + key); 59 } catch (err) { 60 console.error("[redis-store] del error:", err); 61 } 62 } 63}