ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
16
fork

Configure Feed

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

refactor: connect db to server and oauth

byarielm.fyi eb4ce58a fcb5502e

verified
+88 -21
+13
packages/api/.env.example
··· 1 + # Database connection 2 + DATABASE_URL=postgresql://atlast:localdev@localhost:5432/atlast 3 + 4 + # OAuth configuration 5 + # Get these from your Bluesky OAuth app 6 + OAUTH_PRIVATE_KEY= 7 + 8 + # Server configuration 9 + PORT=3000 10 + NODE_ENV=development 11 + 12 + # Frontend URL (for CORS and redirects) 13 + FRONTEND_URL=http://localhost:5173
+1
packages/api/package.json
··· 19 19 "@atproto/oauth-client-node": "^0.3.13", 20 20 "@hono/node-server": "^1.19.9", 21 21 "bullmq": "^5.66.5", 22 + "dotenv": "^17.2.3", 22 23 "hono": "^4.11.4", 23 24 "ioredis": "^5.9.2", 24 25 "kysely": "^0.28.10",
+1
packages/api/src/db/test-connection.ts
··· 5 5 * Usage: tsx src/db/test-connection.ts 6 6 */ 7 7 8 + import 'dotenv/config'; // Load environment variables first 8 9 import { db, testConnection } from './client'; 9 10 import { sql } from 'kysely'; 10 11
+16 -7
packages/api/src/infrastructure/oauth/OAuthClientFactory.ts
··· 29 29 30 30 if (isDev) { 31 31 console.log("[oauth-client] Creating loopback OAuth client"); 32 + console.log("[oauth-client] Client ID:", config.clientId); 33 + console.log("[oauth-client] Redirect URI:", config.redirectUri); 32 34 const clientMetadata = atprotoLoopbackClientMetadata(config.clientId); 33 35 34 - return new NodeOAuthClient({ 35 - clientMetadata, 36 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 - stateStore: stateStore as any, 38 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 39 - sessionStore: sessionStore as any, 40 - }); 36 + try { 37 + const client = new NodeOAuthClient({ 38 + clientMetadata, 39 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 40 + stateStore: stateStore as any, 41 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 42 + sessionStore: sessionStore as any, 43 + }); 44 + console.log("[oauth-client] Loopback client created successfully"); 45 + return client; 46 + } catch (error) { 47 + console.error("[oauth-client] Failed to create loopback client:", error); 48 + throw error; 49 + } 41 50 } 42 51 43 52 // Production client with private key
+18 -11
packages/api/src/infrastructure/oauth/stores/StateStore.ts
··· 23 23 } 24 24 25 25 async set(key: string, value: StateData): Promise<void> { 26 - await db 27 - .insertInto("oauth_states") 28 - .values({ 29 - state: key, 30 - data: value as unknown as Record<string, unknown>, 31 - }) 32 - .onConflict((oc) => 33 - oc.column("state").doUpdateSet({ 26 + try { 27 + console.log("[StateStore] Storing state:", key); 28 + await db 29 + .insertInto("oauth_states") 30 + .values({ 31 + state: key, 34 32 data: value as unknown as Record<string, unknown>, 35 - }), 36 - ) 37 - .execute(); 33 + }) 34 + .onConflict((oc) => 35 + oc.column("state").doUpdateSet({ 36 + data: value as unknown as Record<string, unknown>, 37 + }), 38 + ) 39 + .execute(); 40 + console.log("[StateStore] State stored successfully"); 41 + } catch (error) { 42 + console.error("[StateStore] Failed to store state:", error); 43 + throw error; 44 + } 38 45 } 39 46 40 47 async del(key: string): Promise<void> {
+5 -1
packages/api/src/routes/auth.ts
··· 48 48 data: { url: authUrl.toString() }, 49 49 }); 50 50 } catch (error) { 51 + console.error("[oauth-start] Failed:", error); 51 52 console.error( 52 - "[oauth-start] Failed:", 53 + "[oauth-start] Error details:", 53 54 error instanceof Error ? error.message : String(error), 54 55 ); 56 + if (error instanceof Error && error.stack) { 57 + console.error("[oauth-start] Stack trace:", error.stack); 58 + } 55 59 throw new ApiError( 56 60 "Failed to start OAuth flow", 57 61 500,
+22 -2
packages/api/src/server.ts
··· 1 + import "dotenv/config"; // Load environment variables first 1 2 import { Hono } from "hono"; 2 3 import { serve } from "@hono/node-server"; 3 4 import { cors } from "hono/cors"; ··· 5 6 import { logger } from "hono/logger"; 6 7 import { errorHandler } from "./middleware/error"; 7 8 import authRoutes from "./routes/auth"; 9 + import { db } from "./db/client"; 10 + import { sql } from "kysely"; 8 11 9 12 const app = new Hono(); 10 13 ··· 47 50 // Mount routes 48 51 app.route("/api/auth", authRoutes); 49 52 50 - // Health check endpoint 51 - app.get("/api/health", (c) => { 53 + // Health check endpoint (Phase 3C - with database check) 54 + app.get("/api/health", async (c) => { 55 + let databaseStatus = "unknown"; 56 + let databaseLatency: number | undefined; 57 + 58 + try { 59 + const start = Date.now(); 60 + await sql`SELECT 1`.execute(db); 61 + databaseLatency = Date.now() - start; 62 + databaseStatus = "connected"; 63 + } catch (error) { 64 + console.error("[HEALTH] Database check failed:", error); 65 + databaseStatus = "disconnected"; 66 + } 67 + 52 68 return c.json({ 53 69 success: true, 54 70 data: { ··· 56 72 timestamp: new Date().toISOString(), 57 73 service: "atlast-api", 58 74 version: "1.0.0", 75 + database: { 76 + status: databaseStatus, 77 + latency: databaseLatency ? `${databaseLatency}ms` : undefined, 78 + }, 59 79 }, 60 80 }); 61 81 });
+12
pnpm-lock.yaml
··· 123 123 bullmq: 124 124 specifier: ^5.66.5 125 125 version: 5.66.5 126 + dotenv: 127 + specifier: ^17.2.3 128 + version: 17.2.3 126 129 hono: 127 130 specifier: ^4.11.4 128 131 version: 4.11.4 ··· 336 339 337 340 packages/worker: 338 341 dependencies: 342 + '@atlast/shared': 343 + specifier: workspace:* 344 + version: link:../shared 339 345 '@atproto/api': 340 346 specifier: ^0.18.16 341 347 version: 0.18.16 ··· 2151 2157 2152 2158 dotenv@16.6.1: 2153 2159 resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} 2160 + engines: {node: '>=12'} 2161 + 2162 + dotenv@17.2.3: 2163 + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} 2154 2164 engines: {node: '>=12'} 2155 2165 2156 2166 dunder-proto@1.0.1: ··· 6180 6190 type-fest: 4.41.0 6181 6191 6182 6192 dotenv@16.6.1: {} 6193 + 6194 + dotenv@17.2.3: {} 6183 6195 6184 6196 dunder-proto@1.0.1: 6185 6197 dependencies: