The Appview for the kipclip.com atproto bookmarking service

Fix OAuth state validation by enabling int64 mode in local SQLite

JavaScript timestamps (milliseconds since epoch) are larger than 32-bit integers can hold.
Without int64 mode, Deno SQLite truncates these to signed 32-bit values, causing negative timestamps.

This caused OAuth state lookups to fail because DrizzleStorage's expiration check (expires_at > now)
would compare negative values against current timestamps.

Solution: Enable int64 mode in Database constructor to properly store 64-bit INTEGER values.

Also improved DEVELOPMENT.md OAuth setup instructions.

+13 -4
+10 -3
DEVELOPMENT.md
··· 11 - ✅ **Database** - Local SQLite with migrations 12 - ⚠️ **OAuth Flow** - Requires public URL (see below) 13 14 - ### OAuth Limitations 15 16 ATProto OAuth requires a **publicly accessible** client metadata URL. For local 17 - development: 18 19 - **Option 1: Use ngrok (recommended for full OAuth testing)** 20 21 ```bash 22 # In terminal 1: Start dev server ··· 27 28 # Update .env with ngrok URL 29 BASE_URL=https://your-random-id.ngrok.io 30 ``` 31 32 **Option 2: Mock authentication (recommended for API development)** 33
··· 11 - ✅ **Database** - Local SQLite with migrations 12 - ⚠️ **OAuth Flow** - Requires public URL (see below) 13 14 + ### OAuth Setup with ngrok 15 16 ATProto OAuth requires a **publicly accessible** client metadata URL. For local 17 + development, use ngrok to expose your local server: 18 19 + **Setup Steps:** 20 21 ```bash 22 # In terminal 1: Start dev server ··· 27 28 # Update .env with ngrok URL 29 BASE_URL=https://your-random-id.ngrok.io 30 + 31 + # Restart dev server to pick up new BASE_URL 32 + # Ctrl+C in terminal 1, then: 33 + deno task dev 34 ``` 35 + 36 + **Important:** Always restart the dev server after changing `BASE_URL` in `.env` 37 + so OAuth redirects work correctly. 38 39 **Option 2: Mock authentication (recommended for API development)** 40
+3 -1
backend/database/local-sqlite.ts
··· 34 } 35 } 36 37 - const db = new Database(dbPath); 38 39 return { 40 /**
··· 34 } 35 } 36 37 + // Create database with int64 mode to handle JavaScript timestamps (> 2^31) 38 + // Without this, timestamps get truncated to 32-bit signed integers 39 + const db = new Database(dbPath, { int64: true }); 40 41 return { 42 /**