Building MsgDesk: Service Workers, Timezones, and Chrome Extension Headaches
Had one of those marathon coding sessions today working on MsgDesk - my Chrome extension that helps manage Facebook Messenger contacts and follow-ups. The kind of session where you fix one thing and break three others, but somehow end up ahead by the end.
The Extension Context Nightmare
First battle was with Chrome's "Extension context invalidated" errors. Nothing more frustrating than your extension randomly crashing with cryptic error messages. Wrapped all the chrome.runtime.sendMessage calls in try/catch blocks and added proper runtime guards. Chrome extensions are finicky beasts - they terminate service workers after 30 seconds of inactivity, so I added a keep-alive alarm that fires every 24 seconds to prevent this.
The M button (my trigger for the sidebar) was also failing when the service worker went to sleep. Added retry logic with chrome.runtime.connect() to wake it back up. These are the unglamorous details that users never see but make or break the experience.
Auth Token Refresh Drama
Implemented proper JWT token refresh today. When tokens expire, the sidebar now automatically calls my /api/auth/refresh endpoint instead of hitting Supabase directly. This keeps sensitive keys server-side only, which feels cleaner. The auth flow stores both access and refresh tokens now, and the whole thing handles 401s gracefully.
Also had to add CORS headers to a bunch of routes that were failing from the extension context. Always fun debugging CORS issues.
The Timezone Rabbit Hole
Timezones are the bane of every developer's existence, and today was my turn to wrestle with them. The follow-up datetime picker was saving local times but treating them as UTC, creating all sorts of confusion. Fixed it by properly converting datetime-local input values to UTC with new Date(val).toISOString() on save, then back to local time on load.
Still have a bug where the Home tab's "today" filter uses UTC dates, so it might show the wrong day near midnight in non-UTC timezones. Adding that to the todo list.
UX Improvements That Actually Matter
Built out a proper Home tab with stats, today's follow-ups, and recent contacts. Much better than staring at an empty Contact tab when no conversation is active. Added a nice touch where the save button shows "Saved ✓" for 1.5 seconds before auto-switching to the Home view.
Moved the trigger button from bottom-right to top-right because Facebook's chat dock was covering it. These positioning details matter more than you'd think.
Follow-up Notifications Working
Got the notification system working properly. Extension checks for follow-ups every 15 minutes and fires Chrome notifications for anything due within 15 minutes or overdue by less than an hour. Added client-side deduplication so users don't get spammed.
Interestingly, I now have two notification systems running in parallel - one for explicit reminders and another for contact follow-ups. They serve different use cases, so keeping both for now.
The Small Wins
Fixed a bunch of smaller issues that were driving me crazy:
- Hidden view CSS bug where
.view { display: flex }was overriding[hidden]attributes - All Contacts showing blank screen due to a stray closing tag
- DOM detection failing when Facebook's conversation header wasn't ready (added retry logic)
- Duplicate variable declaration that prevented the service worker from loading
Next Steps
Need to clean up all the debug logging before this goes to the Chrome Web Store - there's some very noisy mutation logging that's great for development but would annoy users. Also want to add a proper sign out button and do more real-world testing of the notification timing.
10 commits and 513 lines changed today. Not bad for a Saturday.