63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
import { loadState, saveState, sumMonthUsages, projectedMonthEnd } from './storage'
|
|
|
|
const ALARM_NAME = 'costdev_budget_check'
|
|
|
|
chrome.runtime.onInstalled.addListener(async () => {
|
|
await chrome.alarms.create(ALARM_NAME, { periodInMinutes: 60 })
|
|
})
|
|
|
|
chrome.alarms.onAlarm.addListener(async (alarm) => {
|
|
if (alarm.name !== ALARM_NAME) return
|
|
const state = await loadState()
|
|
if (!state.budget.enabled || state.budget.monthlyLimit <= 0) return
|
|
|
|
const spent = sumMonthUsages(state.usages)
|
|
const limit = state.budget.monthlyLimit
|
|
const threshold = limit * state.budget.alertThreshold
|
|
|
|
if (spent >= threshold && spent < limit) {
|
|
const last = state.lastAlertAt ?? 0
|
|
if (Date.now() - last > 24 * 60 * 60 * 1000) {
|
|
chrome.notifications.create('costdev-warning', {
|
|
type: 'basic',
|
|
iconUrl: 'icons/icon128.png',
|
|
title: 'Cost.dev — Budget Alert',
|
|
message: `You've spent $${spent.toFixed(2)} of your $${limit.toFixed(2)} monthly budget.`,
|
|
priority: 1,
|
|
})
|
|
state.lastAlertAt = Date.now()
|
|
await saveState(state)
|
|
}
|
|
}
|
|
|
|
if (spent >= limit) {
|
|
const last = state.lastAlertAt ?? 0
|
|
if (Date.now() - last > 24 * 60 * 60 * 1000) {
|
|
chrome.notifications.create('costdev-over', {
|
|
type: 'basic',
|
|
iconUrl: 'icons/icon128.png',
|
|
title: 'Cost.dev — Budget Overrun',
|
|
message: `You've exceeded your $${limit.toFixed(2)} monthly budget! Current spend: $${spent.toFixed(2)}.`,
|
|
priority: 2,
|
|
})
|
|
state.lastAlertAt = Date.now()
|
|
await saveState(state)
|
|
}
|
|
}
|
|
})
|
|
|
|
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|
;(async () => {
|
|
if (message.type === 'budget-check') {
|
|
const state = await loadState()
|
|
const spent = sumMonthUsages(state.usages)
|
|
const limit = state.budget.monthlyLimit
|
|
const projected = projectedMonthEnd(spent)
|
|
sendResponse({ spent, limit, projected, enabled: state.budget.enabled })
|
|
} else {
|
|
sendResponse({ ok: false })
|
|
}
|
|
})()
|
|
return true
|
|
})
|