ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
1[
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 {
11 "hash": "603cf0a187850664336a12c9e5cbb49038906f53",
12 "short_hash": "603cf0a",
13 "author": "Ariel M. Lighty",
14 "date": "2025-12-27T22:42:43-05:00",
15 "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",
16 "files_changed": 4
17 },
18 {
19 "hash": "bd3aabb75abb1875aef125610fcdccb14967a8e3",
20 "short_hash": "bd3aabb",
21 "author": "Ariel M. Lighty",
22 "date": "2025-12-27T22:10:11-05:00",
23 "message": "fix: extension dark mode and build mode messaging\n\n- Changed darkMode from 'class' to 'media' for automatic system preference detection\n- Made server offline message conditional on build mode (dev vs prod)\n- Hide dev server instructions in production builds",
24 "files_changed": 5
25 },
26 {
27 "hash": "bd3aabb75abb1875aef125610fcdccb14967a8e3",
28 "short_hash": "bd3aabb",
29 "author": "Ariel M. Lighty",
30 "date": "2025-12-27T22:10:11-05:00",
31 "message": "fix: extension dark mode and build mode messaging\n\n- Changed darkMode from 'class' to 'media' for automatic system preference detection\n- Made server offline message conditional on build mode (dev vs prod)\n- Hide dev server instructions in production builds",
32 "files_changed": 5
33 },
34 {
35 "hash": "d07180cd3a19328b82b35118e525b59d4e2e060b",
36 "short_hash": "d07180c",
37 "author": "Ariel M. Lighty",
38 "date": "2025-12-27T18:38:39-05:00",
39 "message": "feat: add Tailwind CSS to extension\n\nReplaced 299 lines of vanilla CSS with Tailwind for design consistency with web app. Production build minified to 13KB.",
40 "files_changed": 9
41 },
42 {
43 "hash": "fe29bb3e5faa0151f63c14724f7509af669860de",
44 "short_hash": "fe29bb3",
45 "author": "Ariel M. Lighty",
46 "date": "2025-12-27T16:02:10-05:00",
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.",
48 "files_changed": 6
49 },
50 {
51 "hash": "fcf682bb8969aca108262348e7e17531077713be",
52 "short_hash": "fcf682b",
53 "author": "Ariel M. Lighty",
54 "date": "2025-12-27T15:48:44-05:00",
55 "message": "docs: improve decision graph workflow with lifecycle management\n\nUpdated CLAUDE.md with comprehensive node lifecycle management:\n- Added node status transitions (pending → in_progress → completed)\n- Correct orphan detection commands (awk instead of cut)\n- Common mistakes section with examples\n- Enhanced audit checklist with status verification\n- Verification workflow after node creation\n\nAlso updated extension popup with ATmosphere branding.\n\nDecision graph now at 331 nodes, 332 edges - all orphans resolved.",
56 "files_changed": 4
57 },
58 {
59 "hash": "e04934ffb5e2d78791fcd23bc3afeb4d438a5546",
60 "short_hash": "e04934f",
61 "author": "Ariel M. Lighty",
62 "date": "2025-12-26T21:57:05-05:00",
63 "message": "perf: optimize Vite dev server startup\n\nAdded explicit optimizeDeps.include to pre-bundle common dependencies:\n- React ecosystem (react, react-dom, react-router-dom)\n- Icon libraries (@icons-pack/react-simple-icons, lucide-react)\n- Other deps (date-fns, jszip, zustand, @tanstack/react-virtual)\n\nAlso added server.fs.allow config for monorepo file serving.\n\nThis should speed up subsequent dev server starts by ensuring these\ndependencies are consistently pre-bundled.",
64 "files_changed": 1
65 },
66 {
67 "hash": "aacbbaa27797781098dacdfd0194c93cd71d7bd2",
68 "short_hash": "aacbbaa",
69 "author": "Ariel M. Lighty",
70 "date": "2025-12-26T21:46:06-05:00",
71 "message": "fix: use TIMESTAMPTZ for all timestamp columns\n\nChanged all TIMESTAMP columns to TIMESTAMPTZ (timestamp with timezone) to\nproperly handle timezone-aware timestamps across all tables:\n- oauth_states (created_at, expires_at)\n- oauth_sessions (created_at, expires_at)\n- user_sessions (created_at, expires_at)\n- user_uploads (created_at, last_checked)\n- source_accounts (last_checked, match_found_at, created_at)\n- user_source_follows (created_at)\n- atproto_matches (found_at, last_verified, last_follow_check)\n- user_match_status (notified_at, viewed_at, followed_at, dismissed_at)\n- notification_queue (created_at, sent_at)\n\nThis fixes the 5-hour timezone offset issue where timestamps were stored\nwithout timezone info, causing display errors across different timezones.",
72 "files_changed": 1
73 },
74 {
75 "hash": "46626f4a18eaaaaf42368361130bb1ddc7bd9677",
76 "short_hash": "46626f4",
77 "author": "Ariel M. Lighty",
78 "date": "2025-12-26T21:20:34-05:00",
79 "message": "fix: show loading screen during extension upload search\n\nPreviously when loading an upload from extension that hadn't been searched yet,\nthe app would immediately navigate to the results page showing 'none' for all\nmatches, then update them as the search progressed.\n\nNow it behaves like the file upload flow:\n- Shows loading screen during search\n- Navigates to results only after search completes and results are saved\n- If upload already has matches, navigates to results immediately",
80 "files_changed": 1
81 },
82 {
83 "hash": "212660a996d6b0f1db59f9532d2b3968c7113f10",
84 "short_hash": "212660a",
85 "author": "Ariel M. Lighty",
86 "date": "2025-12-26T20:58:45-05:00",
87 "message": "fix: pass final search results to onComplete callback\n\nFixes issue where results were displayed but not saved to database until\npage refresh. Root cause: onComplete callback accessed stale searchResults\nfrom closure instead of updated state.\n\nChanges:\n- useSearch.searchAllUsers: onComplete now receives SearchResult[] param\n- useSearch: uses setSearchResults updater to get current state\n- App.tsx: updated all 3 searchAllUsers calls to use finalResults\n- Removed setTimeout workarounds\n\nResult: Extension and file upload flows now save immediately after search.",
88 "files_changed": 4
89 },
90 {
91 "hash": "6ced3f0b015af1c9126559a393996576402cfd03",
92 "short_hash": "6ced3f0",
93 "author": "Ariel M. Lighty",
94 "date": "2025-12-26T14:12:46-05:00",
95 "message": "fix extension flow: create user_source_follows, auto-search, time display\n\nBackend (extension-import.ts):\n- Now creates user_source_follows entries linking upload to source accounts\n- Without these, get-upload-details returned empty (queries FROM user_source_follows)\n- Uses bulkCreate return value (Map<username, id>) to create links\n\nFrontend (App.tsx):\n- handleLoadUpload now detects if upload has no matches yet\n- Sets isSearching: true for new uploads\n- Automatically triggers searchAllUsers for new uploads\n- Saves results after search completes\n- Changed platform from hardcoded \"tiktok\" to \"twitter\"\n\nFrontend (HistoryTab.tsx):\n- Fixed time display: removed \"Uploaded\" prefix\n- Now shows \"about 5 hours ago\" instead of \"Uploaded in about 5 hours\"\n- formatRelativeTime with addSuffix already provides complete sentence\n\nResolves:\n- Empty results on page load\n- No automatic searching\n- History navigation not working (will work after search)\n- Grammatically incorrect time display",
96 "files_changed": 5
97 },
98 {
99 "hash": "581ed00fec3c0c5f472c6ff92e00bf4ed5b27e9a",
100 "short_hash": "581ed00",
101 "author": "Ariel M. Lighty",
102 "date": "2025-12-26T13:47:37-05:00",
103 "message": "fix extension import: use bulkCreate and handle uploadId param\n\nBackend fixes:\n- Use SourceAccountRepository.bulkCreate() instead of non-existent upsertSourceAccount()\n- Change redirectUrl from /results?uploadId= to /?uploadId=\n- More efficient bulk insert instead of loop\n\nFrontend fixes:\n- Add useEffect to load results when uploadId param present\n- Calls loadUploadResults(uploadId) automatically on page load\n- Cleans up URL param after loading\n\nResolves:\n- \"sourceAccountRepo.upsertSourceAccount is not a function\" error\n- \"No routes matched location /results?uploadId=...\" routing error",
104 "files_changed": 4
105 },
106 {
107 "hash": "9ca734749fbaa014828f8437afc5e515610afd31",
108 "short_hash": "9ca7347",
109 "author": "Ariel M. Lighty",
110 "date": "2025-12-26T13:37:24-05:00",
111 "message": "update documentation: extension ready for testing after API response fix",
112 "files_changed": 4
113 },
114 {
115 "hash": "95636330f387598f55017eda668fb9f91ccde509",
116 "short_hash": "9563633",
117 "author": "Ariel M. Lighty",
118 "date": "2025-12-26T13:35:52-05:00",
119 "message": "fix extension api-client: unwrap ApiResponse.data structure\n\nBackend endpoints use successResponse() which wraps data in:\n { success: true, data: {...} }\n\nExtension was expecting flat response structure, causing:\n- uploadToATlast to return undefined (missing importId, redirectUrl)\n- checkSession to return wrapped object instead of user data\n- Invalid URL error: \"http://127.0.0.1:8888undefined\"\n\nFixed both uploadToATlast and checkSession to access apiResponse.data",
120 "files_changed": 2
121 },
122 {
123 "hash": "34bd9dcd1237971a87627b148c0452b8484e4871",
124 "short_hash": "34bd9dc",
125 "author": "Ariel M. Lighty",
126 "date": "2025-12-26T00:50:44-05:00",
127 "message": "update documentation with current debugging status\n\nPLAN.md updates:\n- Added current status section with recent fixes and active work\n- Marked Phase 0 as complete\n- Marked Phase 1 as in progress (debugging)\n- Updated changelog with 2025-12-26 progress\n- Updated decision graph count to 288 nodes\n\nEXTENSION_STATUS.md updates:\n- Changed state from READY FOR TESTING to DEBUGGING\n- Added fixed issues section (NaN bug, database init)\n- Added active debugging section\n- Updated decision graph summary to 288 nodes\n- Added node references for recent fixes (#287-288)\n\nDecision graph:\n- Synced with latest nodes (288 total, 276 edges)\n- Tracked database initialization outcome",
128 "files_changed": 4
129 },
130 {
131 "hash": "1a355fe785eb1768dba3f4c3a8ba631904d1d6d6",
132 "short_hash": "1a355fe",
133 "author": "Ariel M. Lighty",
134 "date": "2025-12-26T00:33:21-05:00",
135 "message": "fix extension-import: add missing matchedUsers parameter to createUpload\n\nThe createUpload method expects 5 parameters but we were only passing 4,\ncausing NaN to be inserted for unmatched_users calculation. Now passing 0\nfor matchedUsers (will be updated after search is performed).",
136 "files_changed": 1
137 },
138 {
139 "hash": "d0bcf337b6d223a86443f6f67767e87b74e4dd7d",
140 "short_hash": "d0bcf33",
141 "author": "Ariel M. Lighty",
142 "date": "2025-12-26T00:26:09-05:00",
143 "message": "refactor extension to require authentication and use proper upload flow\n\nRemoved temporary storage approach and implemented proper authentication flow:\n\nExtension changes:\n- Added session check to popup init flow (checkSession in api-client)\n- Added \"not logged in\" state with login prompts\n- Updated uploadToATlast to include credentials for cookie-based auth\n- Extension now requires user to be logged in BEFORE scanning\n\nBackend changes:\n- Converted extension-import to AuthenticatedHandler (requires auth)\n- Now creates upload records immediately (no temporary storage)\n- Removed extension_imports table from database schema\n- Deleted get-extension-import function (no longer needed)\n- Deleted import-store utility (temporary approach removed)\n\nFrontend changes:\n- Removed ExtensionImport page and /import/:id route\n- Extension uploads now use same flow as file uploads\n\nThis matches the correct user flow: user logs in to ATlast first, then\nextension creates permanent upload records directly (same as file uploads).\n\nBuilt extension successfully for dev environment.",
144 "files_changed": 12
145 },
146 {
147 "hash": "c35fb0d83202607facc203dfe10325e8672ea67e",
148 "short_hash": "c35fb0d",
149 "author": "Ariel M. Lighty",
150 "date": "2025-12-25T19:16:38-05:00",
151 "message": "add validation to prevent uploading empty results\n\nCheck if usernames array has items before attempting upload.\nShows clear error message instead of hanging.",
152 "files_changed": 1
153 },
154 {
155 "hash": "0718100fbf6342cb21e8877e32b6f590b0b8cc57",
156 "short_hash": "0718100",
157 "author": "Ariel M. Lighty",
158 "date": "2025-12-25T18:52:32-05:00",
159 "message": "fix critical messaging bug: onMessage was discarding return values\n\nThe onMessage wrapper in messaging.ts was only sending {success: true}\ninstead of the actual handler return value. This caused the popup to\nreceive undefined state even though the background worker was correctly\nstoring it.\n\nChanges:\n- messaging.ts: Changed onMessage to forward handler return values\n- background service-worker.ts: Added comprehensive logging\n- popup.ts: Added state change listener and detailed logging\n\nThis fixes the issue where popup showed 'Go to...' even when on the\nfollowing page.",
160 "files_changed": 3
161 },
162 {
163 "hash": "ba29fd68872913ba0a587aa7f29f97b3d373a732",
164 "short_hash": "ba29fd6",
165 "author": "Ariel M. Lighty",
166 "date": "2025-12-25T13:22:32-05:00",
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": 5
169 },
170 {
171 "hash": "32cdee3aeac7ef986df47e0fff786b5f7471e55b",
172 "short_hash": "32cdee3",
173 "author": "Ariel M. Lighty",
174 "date": "2025-12-25T13:22:32-05:00",
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": 4
177 },
178 {
179 "hash": "c3e7afad396d130791d801a85cbfc9643bcd6309",
180 "short_hash": "c3e7afa",
181 "author": "Ariel M. Lighty",
182 "date": "2025-12-25T12:47:38-05:00",
183 "message": "migrate to pnpm monorepo structure\n\nRestructured codebase into pnpm workspace with three packages:\n- packages/web: React frontend (from src/)\n- packages/functions: Netlify serverless functions (from netlify/functions/)\n- packages/shared: Shared TypeScript types for Platform and Import APIs\n\nChanges:\n- Created pnpm-workspace.yaml for workspace configuration\n- Moved all web app files to packages/web/\n- Moved all Netlify functions to packages/functions/src/\n- Created packages/shared with Platform enum and ExtensionImportRequest/Response types\n- Updated netlify.toml to point to new paths\n- Updated root package.json scripts to use pnpm workspace commands\n- All dependencies split appropriately between packages\n\nPhase 0 (Monorepo Migration) from PLAN.md completed successfully.\nBuilds and dev server tested and working.",
184 "files_changed": 317
185 },
186 {
187 "hash": "e2d6a7e940ea402570c9397a722a4050c735cb6d",
188 "short_hash": "e2d6a7e",
189 "author": "Ariel M. Lighty",
190 "date": "2025-12-24T21:09:33-05:00",
191 "message": "remove .claude/ and dist/ from repository\n\nThese directories are already in .gitignore but were committed\nbefore the ignore rules were added. Removed from tracking while\nkeeping local files intact.",
192 "files_changed": 6
193 },
194 {
195 "hash": "f79a669dd6528340d453cb28e9fed2bd5232d46c",
196 "short_hash": "f79a669",
197 "author": "Ariel M. Lighty",
198 "date": "2025-12-24T19:38:51-05:00",
199 "message": "move tooltip from hero to login form as superscript\n\n- Removed tooltip from HeroSection (ATmosphere now plain text)\n- Added superscript info icon next to 'ATmosphere' in login form text\n- Tooltip content left-aligned for better readability\n- Maintains platform-agnostic design",
200 "files_changed": 2
201 },
202 {
203 "hash": "9bdca934948a284e1315961b4430bae0b6617cbe",
204 "short_hash": "9bdca93",
205 "author": "Ariel M. Lighty",
206 "date": "2025-12-24T18:35:00-05:00",
207 "message": "fix login avatar display by fetching from Bluesky API\n\nactor-typeahead component doesn't expose avatar data via events or attributes.\nAdded debounced API fetch (300ms) to searchActorsTypeahead endpoint when\nhandle is entered. Avatar now displays for both typeahead selections and\nmanually entered handles.",
208 "files_changed": 1
209 },
210 {
211 "hash": "6cd4d622930e2a43531f2df40d930ceb5d2b4dbc",
212 "short_hash": "6cd4d62",
213 "author": "Ariel M. Lighty",
214 "date": "2025-12-24T00:27:50-05:00",
215 "message": "use shared card component for history and results",
216 "files_changed": 4
217 },
218 {
219 "hash": "cc586d28ea8d4544467392be1083fdec11731814",
220 "short_hash": "cc586d2",
221 "author": "Ariel M. Lighty",
222 "date": "2025-12-23T21:11:19-05:00",
223 "message": "replace excessive toasts with aria-live announcer\n\nRemove redundant success/info toasts (logout, upload loaded, no results).\nKeep only error toasts for critical feedback.\nAdd AriaLiveAnnouncer component for screen reader accessibility.",
224 "files_changed": 2
225 },
226 {
227 "hash": "ebb1e05cac477f02e1901aab6f3a8005016472f9",
228 "short_hash": "ebb1e05",
229 "author": "Ariel M. Lighty",
230 "date": "2025-12-23T21:10:58-05:00",
231 "message": "fix mobile alignment: badges and descriptions align with avatar",
232 "files_changed": 1
233 },
234 {
235 "hash": "4c3ae0dbca215d10b499fc646ae7f53c43c658ac",
236 "short_hash": "4c3ae0d",
237 "author": "Ariel M. Lighty",
238 "date": "2025-12-23T20:58:15-05:00",
239 "message": "fix login typeahead autofill and auto-strip @ symbol\n\nTypeahead fix:\n- Add event listeners for input/change/blur to sync actor-typeahead selections with form state\n- Ensures Enter/Tab selections from typeahead dropdown properly update form\n- Allows Enter key to submit form after selection\n\n@ stripping:\n- Automatically remove leading @ from handle input\n- Show helpful inline message when @ is stripped\n- Inform users the @ symbol isn't needed",
240 "files_changed": 1
241 },
242 {
243 "hash": "8e9efd2577b82cb61b0162a28b4ab072bbccf00b",
244 "short_hash": "8e9efd2",
245 "author": "Ariel M. Lighty",
246 "date": "2025-12-23T20:57:21-05:00",
247 "message": "update CLAUDE.md with separate commit guidance\n\nAdd critical note that each commit should address ONE specific fix or feature.\nMultiple unrelated changes should be committed separately for clearer history.",
248 "files_changed": 1
249 },
250 {
251 "hash": "587a9b0314546b91e00c94bf87d28d29f6527456",
252 "short_hash": "587a9b0",
253 "author": "Ariel M. Lighty",
254 "date": "2025-12-23T19:34:34-05:00",
255 "message": "add rate limiting to batch endpoints\n\nOptimization #12:\n- created rateLimit.middleware with in-memory rate limiting\n- batch-search-actors: 5 requests/min (conservative)\n- batch-follow-users: 8 requests/hr (conservative)\n- calculated based on AT Protocol limits with 50% buffer\n- DRY implementation with applyRateLimit helper function\n- prevents users from exhausting AT Protocol API limits\n- leaves buffer for likes, replies, posts\n\nNote: In-memory (resets on cold starts). Upgrade to Upstash Redis for production-grade shared state.",
256 "files_changed": 3
257 },
258 {
259 "hash": "35061ae467e17724d85493c94827c361dc84e6d1",
260 "short_hash": "35061ae",
261 "author": "Ariel M. Lighty",
262 "date": "2025-12-23T19:12:00-05:00",
263 "message": "move inline animations to Tailwind config\n\nOptimization #11:\n- added float-1, float-2, float-3 animation variants to tailwind.config.js\n- replaced inline animation and animationDelay styles with Tailwind classes\n- use modulo pattern to cycle through 3 animation variants\n- maintains visual variety without Math.random() for animation timing\n- consistent with Tailwind conventions, easier to maintain",
264 "files_changed": 2
265 },
266 {
267 "hash": "6b5cf20f95ea43d18c5d05fa80ff7e94d7aa26d2",
268 "short_hash": "6b5cf20",
269 "author": "Ariel M. Lighty",
270 "date": "2025-12-23T19:05:42-05:00",
271 "message": "replace localStorage context with zustand persist store\n\nOptimization #10:\n- created useSettingsStore with zustand persist middleware\n- removed SettingsContext.tsx (88 lines) and provider wrapper\n- added SSR-safe storage with cross-tab synchronization\n- automatic JSON serialization, no manual parse/stringify\n- maintained backward-compatible API (useSettings hook)\n- bundle size: +2.3KB for zustand library",
272 "files_changed": 6
273 },
274 {
275 "hash": "43710263eec21891c899f57e4d0434322612d353",
276 "short_hash": "4371026",
277 "author": "Ariel M. Lighty",
278 "date": "2025-12-23T18:11:36-05:00",
279 "message": "replace any types with AT Protocol interfaces\n\nOptimization #9:\n- created atproto.types.ts with proper AT Protocol interfaces\n- replaced 7 any types in batch-search-actors.ts\n- added ATProtoActor, ATProtoProfile, RankedActor, EnrichedActor types\n- improves type safety, compile-time error catching, IDE support",
280 "files_changed": 3
281 },
282 {
283 "hash": "65ac856188d644baed837eea7775aed307ca0a56",
284 "short_hash": "65ac856",
285 "author": "Ariel M. Lighty",
286 "date": "2025-12-23T16:07:44-05:00",
287 "message": "remove duplicate type definitions from Results.tsx\n\nOptimization #8:\n- removed 3 duplicate type definitions (atprotoSession, SourceUser, SearchResult)\n- import AtprotoSession and SearchResult from central types\n- prevents type drift, establishes single source of truth",
288 "files_changed": 1
289 },
290 {
291 "hash": "093b47d63a6324c2e4bc231d45c5d9d6792383ed",
292 "short_hash": "093b47d",
293 "author": "Ariel M. Lighty",
294 "date": "2025-12-23T15:58:35-05:00",
295 "message": "replace duplicate validation with Zod schemas\n\nOptimizations #6 & #7:\n- #6: verified early exit optimization already implemented in FollowService\n- #7: created validation.utils.ts with Zod schemas for array validation\n- replaced 3 duplicate validation blocks with reusable Zod schemas\n- updated batch-follow-users, check-follow-status, batch-search-actors",
296 "files_changed": 5
297 }
298]