πŸ•Œ

Adhan Caster Pro Architecture Β· System Design Β· Workflow β€” interactive & animated

Chrome Extension Β· Manifest V3
v1.6.6 Β· module service worker
πŸ—ΊοΈ Layered map. Five layers: external services (amber), the popup UI (blue), the background service worker hub (green), the Chrome platform (violet), and content scripts in every tab (teal). Animated dashes show the live data channels. Click any node for its responsibility.

πŸ‘† Click a node to inspect itguide

Every box is a real file or Chrome API in the extension. The lines are message, storage and network channels β€” switch to the Workflow tab to watch data actually flow through them, step by step, during an Adhan event.

β‘  Configure & Schedule
Step 1 / 11

Pick your location

β€”

πŸ“¦ Manifest & permissions

manifestv3 Β· background type:module permissionsstorage Β· alarms Β· notifications Β· scripting Β· tabs hostapi.aladhan.com Β· http/https://* contentall frames Β· document_idle commandtoggle-focus β†’ Ctrl/⌘+Shift+Y

🧱 Components

background.jsMV3 worker: fetch Β· alarms Β· notify Β· broadcast Β· auto-resume content.jsevery frame: 1 Hz tick Β· overlays (Shadow DOM) Β· pause/resume media popup.*prayer list Β· countdown Β· Resume Β· location search Β· settings lib/schedulepure: parse times Β· next prayer Β· stale-fire Β· format lib/geocodepure: Open-Meteo place search

⏰ Alarms

PRAYERadhan-prayer-fire β€” fires at next prayer ts RESUMEadhan-auto-resume β€” now + autoResumeMinutes TICKadhan-tick β€” every 15 min (self-heal)

Alarms re-armed on install, startup & each tick. isStaleFire() (β‰₯90 s late) skips a slept-through Adhan.

πŸ’Ύ Storage schema chrome.storage.local

// settings β€” user config, merged over DEFAULT_SETTINGS
{ enabled, country, state, city, lat, lon,
  autoResumeMinutes:5, leadSeconds:30, focusMode:true }

// schedule β€” today's prayers (parsed to local-tz timestamps)
{ date:"YYYY-MM-DD", prayers:[{name,time,ts}…], fetchedAt }

// nextPrayer β€” the one alarm is armed for  (test:true on dev fires)
{ name, time, ts }

// paused β€” central cross-tab pause state
{ active, prayer, time, since, focus }

πŸ“‘ Message catalog

GET_STATE Β· SAVE_SETTINGS Β· REFRESHpopup β†’read state / save+refetch / refetch
RESUME_NOW Β· FOCUS_NOWpopup / content β†’end pause Β· turn on focus
PRAYER_FALLBACKcontent β†’tab's own countdown hit 0 first
TEST_ADHANpopup β†’dev-only simulated Adhan (30s)
PRAYER_NOW Β· RESUMEbg β‡’ all tabspause everything Β· resume everything
FOCUS_ON Β· FOCUS_OFFbg β‡’ all tabsraise / drop focus overlay

🌐 External services

adhan-apiVercel β€” /api/prayerTimes β†’ 5 daily times Open-Meteokeyless geocoding β€” city β†’ region + coords

No backend of its own, no API keys, no runtime deps. The popup calls Open-Meteo directly; the worker calls adhan-api.

πŸ›‘οΈ Resilience patterns

  • Dual trigger β€” alarm and per-tab countdown both pause; idempotent.
  • Self-resume β€” content.js resumes if ALARM_RESUME never fires.
  • Reconcile β€” worker restart re-arms an in-progress pause.
  • Stale skip β€” slept-through Adhan is ignored, not replayed.
  • Single instance β€” token kills orphaned content scripts.
  • Re-prime tabs β€” inject into open tabs on install & startup.

πŸ§ͺ Stack & quality

Vanilla JS ES modules Shadow DOM MV3 SW Jest unit tests Zero runtime deps

Pure logic in lib/ is unit-tested; manifest qualification tests gate every build.

Generated from source β€” background.js Β· content.js Β· popup.js Β· lib/  β€’  Adhan Caster Pro v1.6.6  β€’  single self-contained file