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.

fix: add health check function for extension server detection

- Created /health function endpoint with CORS support
- Updated checkServerHealth to use function endpoint instead of root URL
- Fixes Firefox extension server detection with proper CORS headers

byarielm.fyi 15b67054 bb14ec5f

verified
+94 -193
-165
EXTENSION_STATUS.md
··· 1 - # Extension Implementation Status 2 - 3 - ## Current State: ✅ COMPLETE - Ready for Production Testing 4 - 5 - ### What's Complete ✅ 6 - 7 - 1. **Environment Configuration** 8 - - Dev/prod builds with correct API URLs 9 - - Build: `npm run build` (dev) or `npm run build:prod` 10 - - Dev: `http://127.0.0.1:8888` 11 - - Prod: `https://atlast.byarielm.fyi` 12 - 13 - 2. **Server Health Check** 14 - - Extension checks if dev server is running (dev mode only) 15 - - Shows "Server offline" state with instructions 16 - - "Check Again" button to retry 17 - 18 - 3. **Authentication Flow** 19 - - Extension checks `/session` endpoint on init 20 - - Shows "Not logged in" state if no session 21 - - "Open ATlast" button to log in 22 - - "Check Again" to retry after login 23 - - **User must be logged in to ATlast BEFORE using extension** 24 - 25 - 4. **Upload Flow** (matches file upload) 26 - - Scan Twitter Following page 27 - - POST to `/extension-import` (requires auth) 28 - - Backend: 29 - - Gets DID from session 30 - - Creates `user_upload` entry 31 - - Saves to `source_accounts` table 32 - - Returns `uploadId` 33 - - Opens `/results?uploadId={id}` 34 - - Frontend searches and displays (same as file upload) 35 - 36 - 5. **CORS Permissions** 37 - - Extension has host_permissions for: 38 - - `http://127.0.0.1:8888/*` 39 - - `http://localhost:8888/*` 40 - - `https://atlast.byarielm.fyi/*` 41 - 42 - 6. **Cleanup Complete** 43 - - ❌ Removed `extension_imports` table 44 - - ❌ Removed `get-extension-import` function 45 - - ❌ Removed `ExtensionImport.tsx` page 46 - - ❌ Removed `/import/:id` route 47 - - ❌ Removed `utils/import-store.ts` 48 - 49 - ### What Needs Testing 🧪 50 - 51 - 1. **Full Flow Test** 52 - ```bash 53 - # 1. Start dev server 54 - npx netlify-cli dev --filter @atlast/web 55 - 56 - # 2. Build extension 57 - cd packages/extension 58 - npm run build 59 - 60 - # 3. Load extension in Chrome 61 - chrome://extensions/ → Load unpacked → packages/extension/dist/chrome/ 62 - 63 - # 4. Log in to ATlast 64 - Open http://127.0.0.1:8888 → Log in 65 - 66 - # 5. Go to Twitter 67 - https://twitter.com/justadev_atlast/following 68 - 69 - # 6. Open extension popup 70 - - Should show "Ready to scan Twitter/X" 71 - - Click "Start Scan" 72 - - Wait for completion 73 - - Click "Open in ATlast" 74 - - Should open /results?uploadId={id} 75 - - Results should load and search automatically 76 - ``` 77 - 78 - 2. **Error Cases to Test** 79 - - Not logged in → should show login prompt 80 - - Server offline → should show offline state 81 - - Empty results → should show appropriate message 82 - - Network errors → should handle gracefully 83 - 84 - ### Recently Completed (Dec 2024 - Jan 2025) 🎉 85 - 86 - **Extension Flow Fixes:** 87 - - ✅ NaN database error - Fixed missing `matchedUsers` parameter in `extension-import.ts` (node #287) 88 - - ✅ Database initialized successfully (node #288) 89 - - ✅ API response unwrapping - Fixed api-client to access ApiResponse.data field (nodes #290-295) 90 - - ✅ Loading screen during extension upload search (node #325) 91 - - ✅ Timezone fixes - All timestamp columns use TIMESTAMPTZ (node #326) 92 - - ✅ Vite dev server optimization - Pre-bundling dependencies for faster startup (node #327) 93 - 94 - **Decision Graph Documentation:** 95 - - ✅ Fixed 18 orphan nodes and linked to parent goals (nodes #328-331) 96 - - ✅ Improved decision graph workflow with lifecycle management (node #332) 97 - - ✅ Updated CLAUDE.md with node status transitions and common mistakes 98 - 99 - ### Current Status 📊 100 - 101 - **All extension bugs resolved!** The extension is fully functional and ready for production testing and deployment. 102 - 103 - ### Next Steps 📋 104 - 105 - 1. ✅ Build extension: `cd packages/extension && pnpm run build` 106 - 2. ✅ Reload extension in Chrome 107 - 3. ✅ Test login flow 108 - 4. ✅ Test scan and upload 109 - 5. ✅ Verify results page works 110 - 6. ✅ All bugs fixed 111 - 7. 🔜 Test production build: `pnpm run build:prod` 112 - 8. 🔜 Chrome Web Store submission 113 - 9. 🔜 Firefox Add-ons support and submission 114 - 115 - ### Architecture Notes 📝 116 - 117 - **Removed temporary import storage approach:** 118 - - Previously tried in-memory storage (doesn't work in serverless) 119 - - Then tried database storage with temp table (overkill) 120 - 121 - **Current approach:** 122 - - User logs in to ATlast FIRST 123 - - Extension requires authentication 124 - - Upload creates permanent records immediately 125 - - No temporary storage needed 126 - - Matches file upload behavior exactly 127 - 128 - **Why this is better:** 129 - - Simpler architecture 130 - - No temporary storage to expire 131 - - Proper user association from the start 132 - - Reuses existing upload/search infrastructure 133 - - Same flow as file uploads (consistency) 134 - 135 - ### Files Modified in Latest Refactor 136 - 137 - **Deleted:** 138 - - `packages/functions/src/get-extension-import.ts` 139 - - `packages/functions/src/utils/import-store.ts` 140 - - `packages/web/src/pages/ExtensionImport.tsx` 141 - 142 - **Modified:** 143 - - `packages/functions/src/extension-import.ts` - Now requires auth, creates upload 144 - - `packages/functions/src/infrastructure/database/DatabaseService.ts` - Removed extension_imports table 145 - - `packages/functions/src/core/types/database.types.ts` - Removed ExtensionImportRow 146 - - `packages/web/src/Router.tsx` - Removed /import/:id route 147 - - `packages/extension/src/popup/popup.ts` - Added session check, login state 148 - - `packages/extension/src/popup/popup.html` - Added not-logged-in state 149 - - `packages/extension/src/lib/api-client.ts` - Added checkSession(), credentials: 'include' 150 - 151 - ### Decision Graph Summary 152 - 153 - **Total nodes:** 332 nodes, 333 edges 154 - **Key decisions tracked:** 155 - - Environment configuration approach (#261-269) 156 - - Port 8888 conflict resolution (#270-274) 157 - - CORS permissions fix (#275-277) 158 - - Storage approach: in-memory → database → proper auth flow (#278-284) 159 - - Refactor and build (#285-286) 160 - - Bug fixes: NaN parameter error (#287), database initialization (#288) 161 - - API response unwrapping fix (#290-295) 162 - - Extension upload flow fixes (#296-327) 163 - - Decision graph integrity fixes (#328-332) 164 - 165 - **Live graph:** https://notactuallytreyanastasio.github.io/deciduous/
+16 -16
docs/git-history.json
··· 1 1 [ 2 2 { 3 - "hash": "603cf0a187850664336a12c9e5cbb49038906f53", 4 - "short_hash": "603cf0a", 3 + "hash": "be9f4207b61429400e44ccfda326595c1087235c", 4 + "short_hash": "be9f420", 5 5 "author": "Ariel M. Lighty", 6 - "date": "2025-12-27T22:42:43-05:00", 7 - "message": "fix: CORS for extension credentialed requests\n\nUpdated CORS headers to support credentials from Chrome extensions:\n- Added getCorsHeaders() to detect chrome-extension:// origins\n- Changed from wildcard Access-Control-Allow-Origin to specific origin\n- Added Access-Control-Allow-Credentials: true for credentialed requests\n- Updated session endpoint to pass event for CORS header detection", 8 - "files_changed": 4 6 + "date": "2025-12-28T19:21:29-05:00", 7 + "message": "feat: add Firefox support with webextension-polyfill\n\nImplemented cross-browser compatibility for the extension:\n\n- Installed webextension-polyfill for unified browser.* API\n- Replaced all chrome.* API calls with browser.* imports\n- Updated build system to output both chrome/ and firefox/ directories\n- Created Firefox-specific manifest with browser_specific_settings", 8 + "files_changed": 12 9 9 }, 10 10 { 11 11 "hash": "603cf0a187850664336a12c9e5cbb49038906f53", ··· 32 32 "files_changed": 9 33 33 }, 34 34 { 35 - "hash": "fe29bb3e5faa0151f63c14724f7509af669860de", 36 - "short_hash": "fe29bb3", 35 + "hash": "6ac877ee6d1990bdab4ef3b03ac59f4682afe0a5", 36 + "short_hash": "6ac877e", 37 37 "author": "Ariel M. Lighty", 38 - "date": "2025-12-27T16:02:10-05:00", 39 - "message": "docs: update all .md files to reflect current project status\n\nUpdated 4 markdown files with current state:\n\nEXTENSION_STATUS.md:\n- Changed status from DEBUGGING to COMPLETE\n- Updated decision graph count (295 → 332 nodes)\n- Added recently completed section (nodes 296-332)\n- Marked all extension bugs as resolved\n\nCONTRIBUTING.md:\n- Replaced npm with pnpm throughout\n- Added monorepo structure documentation\n- Updated development commands (netlify-cli dev --filter)\n- Added extension development workflow\n\nPLAN.md:\n- Updated status to Phase 1 COMPLETE\n- Added all recent fixes to completion list\n- Updated decision graph count to 332 nodes\n- Added changelog entries for latest work\n\npackages/extension/README.md:\n- Added prerequisites section (dev server + login required)\n- Updated build commands with dev/prod distinction\n- Added Step 0: Start ATlast Dev Server\n- Added common issues for auth and server states\n\nAll files now accurately reflect completion status and use pnpm.", 40 - "files_changed": 6 38 + "date": "2025-12-27T16:03:56-05:00", 39 + "message": "docs: update decision graph after markdown updates", 40 + "files_changed": 2 41 41 }, 42 42 { 43 43 "hash": "fe29bb3e5faa0151f63c14724f7509af669860de", ··· 160 160 "files_changed": 3 161 161 }, 162 162 { 163 - "hash": "32cdee3aeac7ef986df47e0fff786b5f7471e55b", 164 - "short_hash": "32cdee3", 163 + "hash": "ba29fd68872913ba0a587aa7f29f97b3d373a732", 164 + "short_hash": "ba29fd6", 165 165 "author": "Ariel M. Lighty", 166 166 "date": "2025-12-25T13:22:32-05:00", 167 167 "message": "configure Netlify dev for monorepo with --filter flag\n\nFixed Netlify CLI monorepo detection issue by using --filter flag:\n- Updated root package.json scripts to use 'npx netlify-cli dev --filter @atlast/web'\n- Updated netlify.toml [dev] section to use npm with --prefix for framework command\n- Added monorepo development instructions to CLAUDE.md\n- Documented Windows Git Bash compatibility issue with netlify command\n\nSolution: Use 'npx netlify-cli dev --filter @atlast/web' to bypass monorepo\nproject selection prompt and specify which workspace package to run.\n\nDev server now runs successfully at http://localhost:8888 with all backend\nfunctions loaded.", 168 - "files_changed": 4 168 + "files_changed": 5 169 169 }, 170 170 { 171 - "hash": "ba29fd68872913ba0a587aa7f29f97b3d373a732", 172 - "short_hash": "ba29fd6", 171 + "hash": "32cdee3aeac7ef986df47e0fff786b5f7471e55b", 172 + "short_hash": "32cdee3", 173 173 "author": "Ariel M. Lighty", 174 174 "date": "2025-12-25T13:22:32-05:00", 175 175 "message": "configure Netlify dev for monorepo with --filter flag\n\nFixed Netlify CLI monorepo detection issue by using --filter flag:\n- Updated root package.json scripts to use 'npx netlify-cli dev --filter @atlast/web'\n- Updated netlify.toml [dev] section to use npm with --prefix for framework command\n- Added monorepo development instructions to CLAUDE.md\n- Documented Windows Git Bash compatibility issue with netlify command\n\nSolution: Use 'npx netlify-cli dev --filter @atlast/web' to bypass monorepo\nproject selection prompt and specify which workspace package to run.\n\nDev server now runs successfully at http://localhost:8888 with all backend\nfunctions loaded.", 176 - "files_changed": 5 176 + "files_changed": 4 177 177 }, 178 178 { 179 179 "hash": "c3e7afad396d130791d801a85cbfc9643bcd6309",
+50 -6
docs/graph-data.json
··· 4142 4142 "node_type": "goal", 4143 4143 "title": "Fix Firefox extension server detection and login check", 4144 4144 "description": null, 4145 - "status": "pending", 4145 + "status": "completed", 4146 4146 "created_at": "2025-12-28T20:14:51.646204800-05:00", 4147 - "updated_at": "2025-12-28T20:14:51.646204800-05:00", 4147 + "updated_at": "2025-12-28T20:32:19.249555-05:00", 4148 4148 "metadata_json": "{\"branch\":\"master\",\"confidence\":85,\"prompt\":\"The extension works in chrome. In firefox, it's failing to detect that the dev server is running and open + logged in on firefox. There's no right-click to inspect on the popup either.\"}" 4149 4149 }, 4150 4150 { ··· 4241 4241 "node_type": "action", 4242 4242 "title": "Adding moz-extension:// origin detection to CORS handler for Firefox extension support", 4243 4243 "description": null, 4244 - "status": "pending", 4244 + "status": "completed", 4245 4245 "created_at": "2025-12-28T20:28:31.661326900-05:00", 4246 - "updated_at": "2025-12-28T20:28:31.661326900-05:00", 4246 + "updated_at": "2025-12-28T20:32:19.367968600-05:00", 4247 4247 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4248 4248 }, 4249 4249 { ··· 4252 4252 "node_type": "outcome", 4253 4253 "title": "Fixed Firefox extension CORS by adding moz-extension:// origin detection to response.utils.ts. Reverted netlify.toml changes as functions handle CORS correctly. User needs to restart dev server.", 4254 4254 "description": null, 4255 - "status": "pending", 4255 + "status": "completed", 4256 4256 "created_at": "2025-12-28T20:29:39.856303800-05:00", 4257 - "updated_at": "2025-12-28T20:29:39.856303800-05:00", 4257 + "updated_at": "2025-12-28T20:32:19.494690-05:00", 4258 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4259 + }, 4260 + { 4261 + "id": 388, 4262 + "change_id": "0ada864e-be98-4a2f-a14e-ffd3eea9aaa9", 4263 + "node_type": "observation", 4264 + "title": "Health check uses HEAD request to root URL (Vite server), not a Netlify function. Doesn't get CORS headers from getCorsHeaders. Need dedicated health endpoint or change check to use existing function.", 4265 + "description": null, 4266 + "status": "pending", 4267 + "created_at": "2025-12-28T20:37:22.132717600-05:00", 4268 + "updated_at": "2025-12-28T20:37:22.132717600-05:00", 4269 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4270 + }, 4271 + { 4272 + "id": 389, 4273 + "change_id": "f522d5b2-c325-4f34-9f27-b8ea5c50618d", 4274 + "node_type": "outcome", 4275 + "title": "Created /health function endpoint with CORS support. Updated checkServerHealth to use /.netlify/functions/health instead of root URL. Extension rebuilt successfully.", 4276 + "description": null, 4277 + "status": "pending", 4278 + "created_at": "2025-12-28T20:38:19.981309500-05:00", 4279 + "updated_at": "2025-12-28T20:38:19.981309500-05:00", 4258 4280 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4259 4281 } 4260 4282 ], ··· 8471 8493 "weight": 1.0, 8472 8494 "rationale": "Complete fix implemented", 8473 8495 "created_at": "2025-12-28T20:30:09.745415200-05:00" 8496 + }, 8497 + { 8498 + "id": 384, 8499 + "from_node_id": 387, 8500 + "to_node_id": 388, 8501 + "from_change_id": "cffdee0f-8535-4d88-83ed-fdf6101f7ac3", 8502 + "to_change_id": "0ada864e-be98-4a2f-a14e-ffd3eea9aaa9", 8503 + "edge_type": "leads_to", 8504 + "weight": 1.0, 8505 + "rationale": "New issue discovered in health check", 8506 + "created_at": "2025-12-28T20:37:24.355885500-05:00" 8507 + }, 8508 + { 8509 + "id": 385, 8510 + "from_node_id": 388, 8511 + "to_node_id": 389, 8512 + "from_change_id": "0ada864e-be98-4a2f-a14e-ffd3eea9aaa9", 8513 + "to_change_id": "f522d5b2-c325-4f34-9f27-b8ea5c50618d", 8514 + "edge_type": "leads_to", 8515 + "weight": 1.0, 8516 + "rationale": "Fix implemented", 8517 + "created_at": "2025-12-28T20:38:22.044029100-05:00" 8474 8518 } 8475 8519 ] 8476 8520 }
+7 -6
packages/extension/src/lib/api-client.ts
··· 78 78 */ 79 79 export async function checkServerHealth(): Promise<boolean> { 80 80 try { 81 - // Try to fetch the root URL with a short timeout 81 + // Try to fetch the health endpoint with a short timeout 82 82 const controller = new AbortController(); 83 83 const timeoutId = setTimeout(() => controller.abort(), 3000); 84 84 85 - const response = await fetch(ATLAST_API_URL, { 86 - method: 'HEAD', 87 - signal: controller.signal 85 + const response = await fetch(`${ATLAST_API_URL}/.netlify/functions/health`, { 86 + method: 'GET', 87 + signal: controller.signal, 88 + credentials: 'include', // Include for CORS 88 89 }); 89 90 90 91 clearTimeout(timeoutId); 91 92 92 - // Any response (even 404) means server is running 93 - return true; 93 + // Any successful response means server is running 94 + return response.ok; 94 95 } catch (error) { 95 96 console.error('[API Client] Server health check failed:', error); 96 97 return false;
+21
packages/functions/src/health.ts
··· 1 + import { SimpleHandler } from "./core/types/api.types"; 2 + import { successResponse } from "./utils"; 3 + import { withErrorHandling } from "./core/middleware"; 4 + 5 + /** 6 + * Health check endpoint 7 + * Returns 200 OK with server status 8 + */ 9 + const healthHandler: SimpleHandler = async (event) => { 10 + return successResponse( 11 + { 12 + status: "ok", 13 + timestamp: new Date().toISOString(), 14 + }, 15 + 200, 16 + {}, 17 + event 18 + ); 19 + }; 20 + 21 + export const handler = withErrorHandling(healthHandler);