ATlast โ€” you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto

Compare changes

Choose any two refs to compare.

Changed files
+520 -191
docs
packages
extension
functions
src
-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/
+8 -8
docs/git-history.json
··· 1 1 [ 2 2 { 3 + "hash": "15b67054a684ebb2a21761a1774ba15f9b1c29e2", 4 + "short_hash": "15b6705", 5 + "author": "Ariel M. Lighty", 6 + "date": "2025-12-28T20:38:38-05:00", 7 + "message": "fix: add health check function for extension server detection\n\n- Created /health function endpoint with CORS support\n- Updated checkServerHealth to use function endpoint instead of root URL\n- Fixes Firefox extension server detection with proper CORS headers", 8 + "files_changed": 5 9 + }, 10 + { 3 11 "hash": "603cf0a187850664336a12c9e5cbb49038906f53", 4 12 "short_hash": "603cf0a", 5 13 "author": "Ariel M. Lighty", ··· 38 46 "date": "2025-12-27T16:02:10-05:00", 39 47 "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 48 "files_changed": 6 41 - }, 42 - { 43 - "hash": "2a163c5f033a79324b100a236ea26c905909bfc6", 44 - "short_hash": "2a163c5", 45 - "author": "Ariel M. Lighty", 46 - "date": "2025-12-27T15:49:08-05:00", 47 - "message": "docs: update decision graph after documentation improvements", 48 - "files_changed": 2 49 49 }, 50 50 { 51 51 "hash": "fcf682bb8969aca108262348e7e17531077713be",
+435 -6
docs/graph-data.json
··· 4032 4032 "node_type": "goal", 4033 4033 "title": "Create Firefox-compatible version of Twitter scraper extension", 4034 4034 "description": null, 4035 - "status": "pending", 4035 + "status": "completed", 4036 4036 "created_at": "2025-12-28T18:09:33.241860800-05:00", 4037 - "updated_at": "2025-12-28T18:09:33.241860800-05:00", 4037 + "updated_at": "2025-12-28T19:21:32.412499-05:00", 4038 4038 "metadata_json": "{\"branch\":\"master\",\"confidence\":85,\"prompt\":\"let's make the extension have a firefox compatible version too.\"}" 4039 4039 }, 4040 4040 { ··· 4120 4120 "node_type": "action", 4121 4121 "title": "Installing webextension-polyfill and updating source files to use browser.* API", 4122 4122 "description": null, 4123 - "status": "pending", 4123 + "status": "completed", 4124 4124 "created_at": "2025-12-28T19:08:14.642882400-05:00", 4125 - "updated_at": "2025-12-28T19:08:14.642882400-05:00", 4125 + "updated_at": "2025-12-28T19:21:32.531034800-05:00", 4126 4126 "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 4127 4127 }, 4128 4128 { ··· 4131 4131 "node_type": "outcome", 4132 4132 "title": "Successfully implemented Firefox compatibility with webextension-polyfill. Both Chrome and Firefox builds compile successfully. Chrome uses service_worker (MV3), Firefox uses scripts array with browser_specific_settings. All chrome.* API calls replaced with browser.* imports.", 4133 4133 "description": null, 4134 - "status": "pending", 4134 + "status": "completed", 4135 4135 "created_at": "2025-12-28T19:14:22.309457600-05:00", 4136 - "updated_at": "2025-12-28T19:14:22.309457600-05:00", 4136 + "updated_at": "2025-12-28T19:21:32.658297400-05:00", 4137 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4138 + }, 4139 + { 4140 + "id": 377, 4141 + "change_id": "1dffa024-413f-4a95-b069-66db350abfaa", 4142 + "node_type": "goal", 4143 + "title": "Fix Firefox extension server detection and login check", 4144 + "description": null, 4145 + "status": "completed", 4146 + "created_at": "2025-12-28T20:14:51.646204800-05:00", 4147 + "updated_at": "2025-12-28T20:32:19.249555-05:00", 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 + }, 4150 + { 4151 + "id": 378, 4152 + "change_id": "9d5626d2-a9ae-42aa-8fda-be3c7528156f", 4153 + "node_type": "observation", 4154 + "title": "Firefox extension debugging differs from Chrome - need to use about:debugging Inspect button or Browser Console, not right-click popup", 4155 + "description": null, 4156 + "status": "pending", 4157 + "created_at": "2025-12-28T20:15:11.710473-05:00", 4158 + "updated_at": "2025-12-28T20:15:11.710473-05:00", 4159 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4160 + }, 4161 + { 4162 + "id": 379, 4163 + "change_id": "7a5af3fe-8567-4f1c-85cd-e47891704974", 4164 + "node_type": "observation", 4165 + "title": "Potential Firefox issues: 1) CORS with credentials:include may be stricter, 2) Cookie partitioning/third-party cookie blocking, 3) Extension needs explicit host_permissions for cookies to work. Firefox manifest has host_permissions but may need additional cookie permissions.", 4166 + "description": null, 4167 + "status": "pending", 4168 + "created_at": "2025-12-28T20:15:31.278249900-05:00", 4169 + "updated_at": "2025-12-28T20:15:31.278249900-05:00", 4170 + "metadata_json": "{\"branch\":\"master\",\"confidence\":85}" 4171 + }, 4172 + { 4173 + "id": 380, 4174 + "change_id": "9c197aae-18d5-46ae-87e7-82c240c8f313", 4175 + "node_type": "action", 4176 + "title": "Adding cookies permission to Firefox manifest for credentials:include support", 4177 + "description": null, 4178 + "status": "pending", 4179 + "created_at": "2025-12-28T20:16:12.019659700-05:00", 4180 + "updated_at": "2025-12-28T20:16:12.019659700-05:00", 4181 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 4182 + }, 4183 + { 4184 + "id": 381, 4185 + "change_id": "485a03b0-8a25-4fdf-a8e2-9d3a25c8edf8", 4186 + "node_type": "outcome", 4187 + "title": "Fixed Firefox cookie issue by adding cookies permission to manifest. Firefox requires explicit permission even with host_permissions. Rebuild successful.", 4188 + "description": null, 4189 + "status": "pending", 4190 + "created_at": "2025-12-28T20:16:41.702322300-05:00", 4191 + "updated_at": "2025-12-28T20:16:41.702322300-05:00", 4192 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4193 + }, 4194 + { 4195 + "id": 382, 4196 + "change_id": "35b13d37-0228-435f-a4bc-c5c42811fec3", 4197 + "node_type": "observation", 4198 + "title": "Firefox blocks extension fetch with CORS error despite host_permissions. Server responds 200 but missing Access-Control-Allow-Origin header. Firefox stricter than Chrome on extension CORS.", 4199 + "description": null, 4200 + "status": "pending", 4201 + "created_at": "2025-12-28T20:17:23.414134300-05:00", 4202 + "updated_at": "2025-12-28T20:17:23.414134300-05:00", 4203 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4204 + }, 4205 + { 4206 + "id": 383, 4207 + "change_id": "adc120cd-e56d-400a-9b3e-8207880378c3", 4208 + "node_type": "action", 4209 + "title": "Adding CORS headers to netlify.toml for extension compatibility - wildcard origin with credentials for dev", 4210 + "description": null, 4211 + "status": "pending", 4212 + "created_at": "2025-12-28T20:18:22.172869600-05:00", 4213 + "updated_at": "2025-12-28T20:18:22.172869600-05:00", 4214 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 4215 + }, 4216 + { 4217 + "id": 384, 4218 + "change_id": "0f77bfd9-590f-4f1e-be08-78a9deef6d8a", 4219 + "node_type": "outcome", 4220 + "title": "Added CORS headers to netlify.toml for all paths including root and functions. Headers include Access-Control-Allow-Origin:*, Allow-Credentials:true for dev environment. User needs to restart dev server.", 4221 + "description": null, 4222 + "status": "pending", 4223 + "created_at": "2025-12-28T20:19:54.829093600-05:00", 4224 + "updated_at": "2025-12-28T20:19:54.829093600-05:00", 4225 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 4226 + }, 4227 + { 4228 + "id": 385, 4229 + "change_id": "cc0910f0-2381-4aee-bb5d-397cb0f804d1", 4230 + "node_type": "observation", 4231 + "title": "CORS wildcard (*) incompatible with credentials:include. Browser security prevents wildcard CORS with credentialed requests. Extension origins are dynamic (moz-extension://, chrome-extension://). Need to handle CORS in serverless functions by reflecting request origin.", 4232 + "description": null, 4233 + "status": "pending", 4234 + "created_at": "2025-12-28T20:27:31.848523900-05:00", 4235 + "updated_at": "2025-12-28T20:27:31.848523900-05:00", 4236 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4237 + }, 4238 + { 4239 + "id": 386, 4240 + "change_id": "ad4a5ca7-15d1-4776-8ede-6b615613f6e1", 4241 + "node_type": "action", 4242 + "title": "Adding moz-extension:// origin detection to CORS handler for Firefox extension support", 4243 + "description": null, 4244 + "status": "completed", 4245 + "created_at": "2025-12-28T20:28:31.661326900-05:00", 4246 + "updated_at": "2025-12-28T20:32:19.367968600-05:00", 4247 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4248 + }, 4249 + { 4250 + "id": 387, 4251 + "change_id": "cffdee0f-8535-4d88-83ed-fdf6101f7ac3", 4252 + "node_type": "outcome", 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 + "description": null, 4255 + "status": "completed", 4256 + "created_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": "completed", 4267 + "created_at": "2025-12-28T20:37:22.132717600-05:00", 4268 + "updated_at": "2025-12-28T20:38:41.630020900-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": "completed", 4278 + "created_at": "2025-12-28T20:38:19.981309500-05:00", 4279 + "updated_at": "2025-12-28T20:38:41.780183300-05:00", 4280 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4281 + }, 4282 + { 4283 + "id": 390, 4284 + "change_id": "cfdcf45b-47b3-4239-8053-417bd31957ed", 4285 + "node_type": "observation", 4286 + "title": "Server receives session request but returns CORS wildcard (*) instead of extension origin. No session cookie received. Origin header might not be sent by Firefox extension or not detected correctly.", 4287 + "description": null, 4288 + "status": "pending", 4289 + "created_at": "2025-12-28T20:48:12.770638500-05:00", 4290 + "updated_at": "2025-12-28T20:48:12.770638500-05:00", 4291 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4292 + }, 4293 + { 4294 + "id": 391, 4295 + "change_id": "2b53a419-9a47-4285-9a12-9bdfaeeb9ff0", 4296 + "node_type": "observation", 4297 + "title": "Health endpoint gets CORS headers correctly (moz-extension detected). Session endpoint error middleware doesn't pass event to errorResponse, returns wildcard CORS. Need to fix error middleware to pass event.", 4298 + "description": null, 4299 + "status": "completed", 4300 + "created_at": "2025-12-28T20:55:32.024834200-05:00", 4301 + "updated_at": "2025-12-28T21:38:14.729731500-05:00", 4302 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4303 + }, 4304 + { 4305 + "id": 392, 4306 + "change_id": "c941d136-3405-483d-bf34-7fb011f6d072", 4307 + "node_type": "action", 4308 + "title": "Fixed error middleware to pass event to errorResponse for proper CORS headers on errors", 4309 + "description": null, 4310 + "status": "completed", 4311 + "created_at": "2025-12-28T20:56:38.876266200-05:00", 4312 + "updated_at": "2025-12-28T21:38:14.888627800-05:00", 4313 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4314 + }, 4315 + { 4316 + "id": 393, 4317 + "change_id": "aafd9977-8800-4152-9f7f-b817db6df573", 4318 + "node_type": "outcome", 4319 + "title": "Fixed Firefox extension CORS completely. Error middleware now passes event to errorResponse so Firefox extension origin is properly reflected in error responses with credentials. Debug logging removed.", 4320 + "description": null, 4321 + "status": "completed", 4322 + "created_at": "2025-12-28T21:37:22.780953600-05:00", 4323 + "updated_at": "2025-12-28T21:38:15.071425500-05:00", 4324 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4325 + }, 4326 + { 4327 + "id": 394, 4328 + "change_id": "3b0dea7a-c3cd-45a8-ba1a-f1040aa4e1d9", 4329 + "node_type": "observation", 4330 + "title": "CORS fully working - Firefox extension origin properly reflected with credentials. But cookies not sent from extension despite credentials:include. Cookie set in web context not accessible from extension context due to Firefox cookie partitioning.", 4331 + "description": null, 4332 + "status": "pending", 4333 + "created_at": "2025-12-28T21:46:45.822343200-05:00", 4334 + "updated_at": "2025-12-28T21:46:45.822343200-05:00", 4335 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4336 + }, 4337 + { 4338 + "id": 395, 4339 + "change_id": "8a93413f-a09c-4cc1-8693-4fe90dc055c4", 4340 + "node_type": "action", 4341 + "title": "Updated extension checkSession to read cookie via browser.cookies API and pass as query parameter. Workaround for Firefox SameSite=Lax cookie partitioning.", 4342 + "description": null, 4343 + "status": "pending", 4344 + "created_at": "2025-12-28T21:52:22.059862700-05:00", 4345 + "updated_at": "2025-12-28T21:52:22.059862700-05:00", 4346 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4347 + }, 4348 + { 4349 + "id": 396, 4350 + "change_id": "864dd973-5f15-4e31-a7da-c548dbbe1f0e", 4351 + "node_type": "outcome", 4352 + "title": "Extension now uses browser.cookies.get() API to read session cookie and pass as query parameter. Workaround for Firefox SameSite=Lax cookie partitioning in extensions. Extension rebuilt successfully.", 4353 + "description": null, 4354 + "status": "pending", 4355 + "created_at": "2025-12-28T22:51:31.578965200-05:00", 4356 + "updated_at": "2025-12-28T22:51:31.578965200-05:00", 4137 4357 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 4138 4358 } 4139 4359 ], ··· 8240 8460 "weight": 1.0, 8241 8461 "rationale": "Implementation completed successfully", 8242 8462 "created_at": "2025-12-28T19:14:24.961595600-05:00" 8463 + }, 8464 + { 8465 + "id": 374, 8466 + "from_node_id": 377, 8467 + "to_node_id": 378, 8468 + "from_change_id": "1dffa024-413f-4a95-b069-66db350abfaa", 8469 + "to_change_id": "9d5626d2-a9ae-42aa-8fda-be3c7528156f", 8470 + "edge_type": "leads_to", 8471 + "weight": 1.0, 8472 + "rationale": "First observation about debugging", 8473 + "created_at": "2025-12-28T20:15:13.725635900-05:00" 8474 + }, 8475 + { 8476 + "id": 375, 8477 + "from_node_id": 378, 8478 + "to_node_id": 379, 8479 + "from_change_id": "9d5626d2-a9ae-42aa-8fda-be3c7528156f", 8480 + "to_change_id": "7a5af3fe-8567-4f1c-85cd-e47891704974", 8481 + "edge_type": "leads_to", 8482 + "weight": 1.0, 8483 + "rationale": "Hypothesis about root causes", 8484 + "created_at": "2025-12-28T20:15:33.187041700-05:00" 8485 + }, 8486 + { 8487 + "id": 376, 8488 + "from_node_id": 379, 8489 + "to_node_id": 380, 8490 + "from_change_id": "7a5af3fe-8567-4f1c-85cd-e47891704974", 8491 + "to_change_id": "9c197aae-18d5-46ae-87e7-82c240c8f313", 8492 + "edge_type": "leads_to", 8493 + "weight": 1.0, 8494 + "rationale": "Fix based on hypothesis", 8495 + "created_at": "2025-12-28T20:16:14.104406300-05:00" 8496 + }, 8497 + { 8498 + "id": 377, 8499 + "from_node_id": 380, 8500 + "to_node_id": 381, 8501 + "from_change_id": "9c197aae-18d5-46ae-87e7-82c240c8f313", 8502 + "to_change_id": "485a03b0-8a25-4fdf-a8e2-9d3a25c8edf8", 8503 + "edge_type": "leads_to", 8504 + "weight": 1.0, 8505 + "rationale": "Fix implemented and tested", 8506 + "created_at": "2025-12-28T20:16:43.953511400-05:00" 8507 + }, 8508 + { 8509 + "id": 378, 8510 + "from_node_id": 381, 8511 + "to_node_id": 382, 8512 + "from_change_id": "485a03b0-8a25-4fdf-a8e2-9d3a25c8edf8", 8513 + "to_change_id": "35b13d37-0228-435f-a4bc-c5c42811fec3", 8514 + "edge_type": "leads_to", 8515 + "weight": 1.0, 8516 + "rationale": "Root cause identified from error logs", 8517 + "created_at": "2025-12-28T20:17:25.488041200-05:00" 8518 + }, 8519 + { 8520 + "id": 379, 8521 + "from_node_id": 382, 8522 + "to_node_id": 383, 8523 + "from_change_id": "35b13d37-0228-435f-a4bc-c5c42811fec3", 8524 + "to_change_id": "adc120cd-e56d-400a-9b3e-8207880378c3", 8525 + "edge_type": "leads_to", 8526 + "weight": 1.0, 8527 + "rationale": "Fix for CORS issue", 8528 + "created_at": "2025-12-28T20:19:41.484076700-05:00" 8529 + }, 8530 + { 8531 + "id": 380, 8532 + "from_node_id": 383, 8533 + "to_node_id": 384, 8534 + "from_change_id": "adc120cd-e56d-400a-9b3e-8207880378c3", 8535 + "to_change_id": "0f77bfd9-590f-4f1e-be08-78a9deef6d8a", 8536 + "edge_type": "leads_to", 8537 + "weight": 1.0, 8538 + "rationale": "Implementation complete", 8539 + "created_at": "2025-12-28T20:19:56.872404900-05:00" 8540 + }, 8541 + { 8542 + "id": 381, 8543 + "from_node_id": 384, 8544 + "to_node_id": 385, 8545 + "from_change_id": "0f77bfd9-590f-4f1e-be08-78a9deef6d8a", 8546 + "to_change_id": "cc0910f0-2381-4aee-bb5d-397cb0f804d1", 8547 + "edge_type": "leads_to", 8548 + "weight": 1.0, 8549 + "rationale": "New error reveals real issue", 8550 + "created_at": "2025-12-28T20:27:34.035766400-05:00" 8551 + }, 8552 + { 8553 + "id": 382, 8554 + "from_node_id": 385, 8555 + "to_node_id": 386, 8556 + "from_change_id": "cc0910f0-2381-4aee-bb5d-397cb0f804d1", 8557 + "to_change_id": "ad4a5ca7-15d1-4776-8ede-6b615613f6e1", 8558 + "edge_type": "leads_to", 8559 + "weight": 1.0, 8560 + "rationale": "Fix for Firefox extension origin", 8561 + "created_at": "2025-12-28T20:28:33.839045700-05:00" 8562 + }, 8563 + { 8564 + "id": 383, 8565 + "from_node_id": 386, 8566 + "to_node_id": 387, 8567 + "from_change_id": "ad4a5ca7-15d1-4776-8ede-6b615613f6e1", 8568 + "to_change_id": "cffdee0f-8535-4d88-83ed-fdf6101f7ac3", 8569 + "edge_type": "leads_to", 8570 + "weight": 1.0, 8571 + "rationale": "Complete fix implemented", 8572 + "created_at": "2025-12-28T20:30:09.745415200-05:00" 8573 + }, 8574 + { 8575 + "id": 384, 8576 + "from_node_id": 387, 8577 + "to_node_id": 388, 8578 + "from_change_id": "cffdee0f-8535-4d88-83ed-fdf6101f7ac3", 8579 + "to_change_id": "0ada864e-be98-4a2f-a14e-ffd3eea9aaa9", 8580 + "edge_type": "leads_to", 8581 + "weight": 1.0, 8582 + "rationale": "New issue discovered in health check", 8583 + "created_at": "2025-12-28T20:37:24.355885500-05:00" 8584 + }, 8585 + { 8586 + "id": 385, 8587 + "from_node_id": 388, 8588 + "to_node_id": 389, 8589 + "from_change_id": "0ada864e-be98-4a2f-a14e-ffd3eea9aaa9", 8590 + "to_change_id": "f522d5b2-c325-4f34-9f27-b8ea5c50618d", 8591 + "edge_type": "leads_to", 8592 + "weight": 1.0, 8593 + "rationale": "Fix implemented", 8594 + "created_at": "2025-12-28T20:38:22.044029100-05:00" 8595 + }, 8596 + { 8597 + "id": 386, 8598 + "from_node_id": 389, 8599 + "to_node_id": 390, 8600 + "from_change_id": "f522d5b2-c325-4f34-9f27-b8ea5c50618d", 8601 + "to_change_id": "cfdcf45b-47b3-4239-8053-417bd31957ed", 8602 + "edge_type": "leads_to", 8603 + "weight": 1.0, 8604 + "rationale": "Issue persists - need to debug headers", 8605 + "created_at": "2025-12-28T20:48:14.949702100-05:00" 8606 + }, 8607 + { 8608 + "id": 387, 8609 + "from_node_id": 390, 8610 + "to_node_id": 391, 8611 + "from_change_id": "cfdcf45b-47b3-4239-8053-417bd31957ed", 8612 + "to_change_id": "2b53a419-9a47-4285-9a12-9bdfaeeb9ff0", 8613 + "edge_type": "leads_to", 8614 + "weight": 1.0, 8615 + "rationale": "Root cause identified from debug logs", 8616 + "created_at": "2025-12-28T20:55:34.094943700-05:00" 8617 + }, 8618 + { 8619 + "id": 388, 8620 + "from_node_id": 391, 8621 + "to_node_id": 392, 8622 + "from_change_id": "2b53a419-9a47-4285-9a12-9bdfaeeb9ff0", 8623 + "to_change_id": "c941d136-3405-483d-bf34-7fb011f6d072", 8624 + "edge_type": "leads_to", 8625 + "weight": 1.0, 8626 + "rationale": "Fix implemented", 8627 + "created_at": "2025-12-28T20:57:35.872426900-05:00" 8628 + }, 8629 + { 8630 + "id": 389, 8631 + "from_node_id": 392, 8632 + "to_node_id": 393, 8633 + "from_change_id": "c941d136-3405-483d-bf34-7fb011f6d072", 8634 + "to_change_id": "aafd9977-8800-4152-9f7f-b817db6df573", 8635 + "edge_type": "leads_to", 8636 + "weight": 1.0, 8637 + "rationale": "Complete fix with cleanup", 8638 + "created_at": "2025-12-28T21:37:27.704906300-05:00" 8639 + }, 8640 + { 8641 + "id": 390, 8642 + "from_node_id": 393, 8643 + "to_node_id": 394, 8644 + "from_change_id": "aafd9977-8800-4152-9f7f-b817db6df573", 8645 + "to_change_id": "3b0dea7a-c3cd-45a8-ba1a-f1040aa4e1d9", 8646 + "edge_type": "leads_to", 8647 + "weight": 1.0, 8648 + "rationale": "New issue - cookie partitioning", 8649 + "created_at": "2025-12-28T21:46:48.417911400-05:00" 8650 + }, 8651 + { 8652 + "id": 391, 8653 + "from_node_id": 394, 8654 + "to_node_id": 395, 8655 + "from_change_id": "3b0dea7a-c3cd-45a8-ba1a-f1040aa4e1d9", 8656 + "to_change_id": "8a93413f-a09c-4cc1-8693-4fe90dc055c4", 8657 + "edge_type": "leads_to", 8658 + "weight": 1.0, 8659 + "rationale": "Workaround using browser.cookies API", 8660 + "created_at": "2025-12-28T21:52:52.704792400-05:00" 8661 + }, 8662 + { 8663 + "id": 392, 8664 + "from_node_id": 395, 8665 + "to_node_id": 396, 8666 + "from_change_id": "8a93413f-a09c-4cc1-8693-4fe90dc055c4", 8667 + "to_change_id": "864dd973-5f15-4e31-a7da-c548dbbe1f0e", 8668 + "edge_type": "leads_to", 8669 + "weight": 1.0, 8670 + "rationale": "Complete workaround", 8671 + "created_at": "2025-12-28T22:51:33.159870400-05:00" 8243 8672 } 8244 8673 ] 8245 8674 }
+2 -1
packages/extension/manifest.firefox.json
··· 5 5 "description": "Import your Twitter/X follows to find them on Bluesky", 6 6 "permissions": [ 7 7 "activeTab", 8 - "storage" 8 + "storage", 9 + "cookies" 9 10 ], 10 11 "host_permissions": [ 11 12 "https://twitter.com/*",
+33 -8
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; ··· 115 116 avatar?: string; 116 117 } | null> { 117 118 try { 118 - const response = await fetch(`${ATLAST_API_URL}/.netlify/functions/session`, { 119 + // Try to get session cookie using browser.cookies API 120 + // This works around Firefox's cookie partitioning for extensions 121 + let sessionId: string | null = null; 122 + 123 + try { 124 + const cookieName = __BUILD_MODE__ === 'production' ? 'atlast_session' : 'atlast_session_dev'; 125 + const cookie = await browser.cookies.get({ 126 + url: ATLAST_API_URL, 127 + name: cookieName 128 + }); 129 + 130 + if (cookie) { 131 + sessionId = cookie.value; 132 + console.log('[API Client] Found session cookie:', cookieName); 133 + } 134 + } catch (cookieError) { 135 + console.log('[API Client] Could not read cookie:', cookieError); 136 + } 137 + 138 + // Build URL with session parameter if we have one 139 + const url = sessionId 140 + ? `${ATLAST_API_URL}/.netlify/functions/session?session=${sessionId}` 141 + : `${ATLAST_API_URL}/.netlify/functions/session`; 142 + 143 + const response = await fetch(url, { 119 144 method: 'GET', 120 - credentials: 'include', // Include cookies 145 + credentials: 'include', // Include cookies as fallback 121 146 headers: { 122 147 'Accept': 'application/json' 123 148 }
+4 -2
packages/functions/src/core/middleware/error.middleware.ts
··· 21 21 } 22 22 23 23 if (error instanceof ApiError) { 24 - return errorResponse(error.message, error.statusCode, error.details); 24 + return errorResponse(error.message, error.statusCode, error.details, event); 25 25 } 26 26 27 27 // Unknown errors ··· 29 29 "Internal server error", 30 30 500, 31 31 error instanceof Error ? error.message : "Unknown error", 32 + event, 32 33 ); 33 34 } 34 35 }; ··· 48 49 console.error("Authenticated handler error:", error); 49 50 50 51 if (error instanceof ApiError) { 51 - return errorResponse(error.message, error.statusCode, error.details); 52 + return errorResponse(error.message, error.statusCode, error.details, event); 52 53 } 53 54 54 55 return errorResponse( 55 56 "Internal server error", 56 57 500, 57 58 error instanceof Error ? error.message : "Unknown error", 59 + event, 58 60 ); 59 61 } 60 62 };
+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);
+1 -1
packages/functions/src/utils/response.utils.ts
··· 22 22 'https://atlast.byarielm.fyi', 23 23 ]; 24 24 25 - const isExtension = origin.startsWith('chrome-extension://'); 25 + const isExtension = origin.startsWith('chrome-extension://') || origin.startsWith('moz-extension://'); 26 26 const isAllowedOrigin = allowedOrigins.includes(origin); 27 27 28 28 if (isExtension || isAllowedOrigin) {
+16
pnpm-lock.yaml
··· 114 114 '@atlast/shared': 115 115 specifier: workspace:* 116 116 version: link:../shared 117 + webextension-polyfill: 118 + specifier: ^0.12.0 119 + version: 0.12.0 117 120 devDependencies: 118 121 '@types/chrome': 119 122 specifier: ^0.0.256 120 123 version: 0.0.256 124 + '@types/webextension-polyfill': 125 + specifier: ^0.12.4 126 + version: 0.12.4 121 127 autoprefixer: 122 128 specifier: ^10.4.23 123 129 version: 10.4.23(postcss@8.5.6) ··· 1245 1251 '@types/triple-beam@1.3.5': 1246 1252 resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} 1247 1253 1254 + '@types/webextension-polyfill@0.12.4': 1255 + resolution: {integrity: sha512-wK8YdSI0pDiaehSLDIvtvonYmLwUUivg4Z6JCJO8rkyssMAG82cFJgwPK/V7NO61mJBLg/tXeoXQL8AFzpXZmQ==} 1256 + 1248 1257 '@types/yauzl@2.10.3': 1249 1258 resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} 1250 1259 ··· 3144 3153 optional: true 3145 3154 terser: 3146 3155 optional: true 3156 + 3157 + webextension-polyfill@0.12.0: 3158 + resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==} 3147 3159 3148 3160 webidl-conversions@3.0.1: 3149 3161 resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} ··· 4172 4184 4173 4185 '@types/triple-beam@1.3.5': {} 4174 4186 4187 + '@types/webextension-polyfill@0.12.4': {} 4188 + 4175 4189 '@types/yauzl@2.10.3': 4176 4190 dependencies: 4177 4191 '@types/node': 24.10.4 ··· 6108 6122 optionalDependencies: 6109 6123 '@types/node': 24.10.4 6110 6124 fsevents: 2.3.3 6125 + 6126 + webextension-polyfill@0.12.0: {} 6111 6127 6112 6128 webidl-conversions@3.0.1: {} 6113 6129