Storage implementations for AT Protocol OAuth applications. Provides a simple key-value storage interface with implementations for in-memory and SQLite backends.
at main 106 lines 3.2 kB view raw
1/** 2 * Pre-built adapters for common SQLite drivers. 3 * Each adapter converts a specific driver's API to the SQLiteAdapter interface. 4 */ 5 6import type { SQLiteAdapter } from "./types.ts"; 7 8/** 9 * Driver interface for Val.Town sqlite and libSQL/Turso client. 10 * Both use the same execute({ sql, args }) pattern. 11 */ 12export interface ExecutableDriver { 13 execute( 14 query: { sql: string; args: unknown[] }, 15 ): Promise<{ rows: unknown[][] }>; 16} 17 18/** 19 * Driver interface for @db/sqlite (Deno native) and similar prepare-based drivers. 20 */ 21export interface PrepareDriver { 22 prepare(sql: string): { 23 all<T = Record<string, unknown>>(...params: unknown[]): T[]; 24 }; 25} 26 27/** 28 * Adapter for SQLite drivers using the execute({ sql, args }) pattern. 29 * Works with Val.Town sqlite, libSQL/Turso, and similar drivers. 30 * 31 * @example Val.Town 32 * ```typescript 33 * import { sqlite } from "https://esm.town/v/std/sqlite"; 34 * import { SQLiteStorage, sqliteAdapter } from "@tijs/atproto-storage"; 35 * 36 * const storage = new SQLiteStorage(sqliteAdapter(sqlite)); 37 * ``` 38 * 39 * @example libSQL/Turso 40 * ```typescript 41 * import { createClient } from "@libsql/client"; 42 * import { SQLiteStorage, sqliteAdapter } from "@tijs/atproto-storage"; 43 * 44 * const client = createClient({ url: "libsql://..." }); 45 * const storage = new SQLiteStorage(sqliteAdapter(client)); 46 * ``` 47 */ 48export function sqliteAdapter(driver: ExecutableDriver): SQLiteAdapter { 49 return { 50 execute: async (sql: string, params: unknown[]): Promise<unknown[][]> => { 51 const result = await driver.execute({ sql, args: params }); 52 return result.rows; 53 }, 54 }; 55} 56 57/** 58 * Adapter for @db/sqlite (Deno native SQLite). 59 * Converts the synchronous prepare/all pattern to the async adapter interface. 60 * 61 * @example 62 * ```typescript 63 * import { Database } from "jsr:@db/sqlite"; 64 * import { SQLiteStorage, denoSqliteAdapter } from "@tijs/atproto-storage"; 65 * 66 * const db = new Database("storage.db"); 67 * const storage = new SQLiteStorage(denoSqliteAdapter(db)); 68 * ``` 69 */ 70export function denoSqliteAdapter(db: PrepareDriver): SQLiteAdapter { 71 return { 72 execute: (sql: string, params: unknown[]): Promise<unknown[][]> => { 73 const stmt = db.prepare(sql); 74 const rows = stmt.all(...params); 75 // Convert object rows to array rows (column order from Object.values) 76 return Promise.resolve( 77 rows.map((row) => Object.values(row as Record<string, unknown>)), 78 ); 79 }, 80 }; 81} 82 83/** 84 * Adapter for better-sqlite3 (Node.js). 85 * Same pattern as Deno native but for Node environment. 86 * 87 * @example 88 * ```typescript 89 * import Database from "better-sqlite3"; 90 * import { SQLiteStorage, betterSqlite3Adapter } from "@tijs/atproto-storage"; 91 * 92 * const db = new Database("storage.db"); 93 * const storage = new SQLiteStorage(betterSqlite3Adapter(db)); 94 * ``` 95 */ 96export function betterSqlite3Adapter(db: PrepareDriver): SQLiteAdapter { 97 return { 98 execute: (sql: string, params: unknown[]): Promise<unknown[][]> => { 99 const stmt = db.prepare(sql); 100 const rows = stmt.all(...params); 101 return Promise.resolve( 102 rows.map((row) => Object.values(row as Record<string, unknown>)), 103 ); 104 }, 105 }; 106}