Skip to content

Instantly share code, notes, and snippets.

@nandordudas
Created June 24, 2025 17:33
Show Gist options
  • Save nandordudas/2cc7961dd98d0c47371930fb39bd2ed5 to your computer and use it in GitHub Desktop.
Save nandordudas/2cc7961dd98d0c47371930fb39bd2ed5 to your computer and use it in GitHub Desktop.
import type { Alarms } from 'webextension-polyfill'
import { consola } from 'consola'
import { alarms } from 'webextension-polyfill'
interface ScheduledEmail {
readonly id: string
scheduledTime: number
status: 'pending' | 'sent' | 'failed'
readonly created: number
}
class DailyScheduler {
readonly #alarmName = 'daily-scheduler'
constructor() {
void this.#init()
}
async #init(): Promise<void> {
alarms.onAlarm.addListener(this.#handleAlarm)
await this.#createDailyAlarm()
}
async #createDailyAlarm(): Promise<void> {
await alarms.clear(this.#alarmName)
const now = new Date()
const eightAM = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0)
if (eightAM <= now)
eightAM.setDate(eightAM.getDate() + 1)
alarms.create(this.#alarmName, {
// when: eightAM.getTime(),
delayInMinutes: 0.167 * 4.5, // 10 seconds = 0.167 minutes, original 24 hours = 1440 minutes
periodInMinutes: 0.167 * 4.5,
})
consola.log('Daily scheduler set for 45 seconds interval')
// consola.log(`Daily scheduler set for: ${eightAM.toLocaleString()}`)
}
#handleAlarm = async (alarm: Alarms.Alarm): Promise<void> => {
if (alarm.name === this.#alarmName)
await this.#performDailyTasks()
}
async #performDailyTasks(): Promise<void> {
consola.log('πŸ”„ Daily scheduler running - fetching email configs')
const emails: ScheduledEmail[] = []
const now = Date.now()
for (let i = 0; i < 5; ++i) {
const scheduledTime = now + Math.random() * 30_000
emails.push({
id: `email-${Date.now()}-${i}`,
scheduledTime,
status: 'pending',
created: now,
})
}
const { scheduledEmails = [] } = await messenger.storage.local.get('scheduledEmails') as {
scheduledEmails: ScheduledEmail[]
}
scheduledEmails.push(...emails)
await messenger.storage.local.set({ scheduledEmails })
consola.log(`πŸ“§ Scheduled ${emails.length} emails for the day`)
emails.forEach((email) => {
consola.log(` - Email ${email.id} scheduled for ${new Date(email.scheduledTime).toLocaleTimeString()}`)
})
}
}
class FiveMinuteScheduler {
readonly #alarmName = 'five-minute-scheduler'
constructor() {
void this.#init()
}
async #init(): Promise<void> {
alarms.onAlarm.addListener(this.#handleAlarm)
await this.#createFiveMinuteAlarm()
}
async #createFiveMinuteAlarm(): Promise<void> {
await alarms.clear(this.#alarmName)
alarms.create(this.#alarmName, {
delayInMinutes: 0.033 * 2.5, // 2 seconds = 0.033 minutes, original 5
periodInMinutes: 0.033 * 2.5,
})
consola.log('Five-minute scheduler set for 5 seconds interval')
}
#handleAlarm = async (alarm: Alarms.Alarm): Promise<void> => {
if (alarm.name === this.#alarmName)
await this.#checkScheduledEmails()
}
async #checkScheduledEmails(): Promise<void> {
const { scheduledEmails = [] } = await messenger.storage.local.get('scheduledEmails') as {
scheduledEmails: ScheduledEmail[]
}
const now = Date.now()
const emailsToSend = scheduledEmails.filter((email: ScheduledEmail) => {
return email.status === 'pending' && email.scheduledTime <= now
})
if (emailsToSend.length === 0)
return consola.log('⏰ Checking scheduled emails... none ready to send')
consola.log(`πŸ“€ Found ${emailsToSend.length} emails ready to send`)
for (const email of emailsToSend) {
email.status = 'sent'
consola.log(`βœ… Sent email: ${email.id}`)
}
await messenger.storage.local.set({ scheduledEmails })
consola.log(`πŸ“¬ Successfully sent ${emailsToSend.length} emails`)
}
}
class TestScheduler {
static readonly #symbol: unique symbol = Symbol.for('TestScheduler')
static create(): TestScheduler {
return new TestScheduler(this.#symbol)
}
readonly #dailyScheduler = new DailyScheduler()
readonly #fiveMinuteScheduler = new FiveMinuteScheduler()
protected constructor(symbol: symbol) {
if (symbol !== TestScheduler.#symbol)
throw new Error('Cannot create instance of TestScheduler')
consola.log('πŸš€ Test Scheduler initialized')
consola.log(' - Daily scheduler: 10 seconds', this.#dailyScheduler)
consola.log(' - Email checker: 2 seconds', this.#fiveMinuteScheduler)
}
}
TestScheduler.create()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment