import { BillingAction } from './action-policies.js' import { calendarDayOf, midnightInTimezone, shiftCalendarDay } from './calendar-day.js' /** @param {{ actionPolicies:{ get:Function }, grant:Function, balance:Function }} billing */ export function createDailyClaim(billing) { async function claim({ user_id, now = new Date() }) { const policy = await billing.actionPolicies.get(BillingAction.DAILY_CLAIM) if (!policy.enabled) throw new Error('daily_claim is disabled') const window = losAngelesDay(now, policy.timezone) const idempotency_key = `daily_claim:${user_id}:${window.date}` const granted = await billing.grant({ user_id, amount: policy.points, source: 'daily_reward', credit_kind: 'daily', reason: 'daily_claim', ref_type: 'daily_claim', ref_id: window.date, idempotency_key, }) return { ...(await billing.balance({ user_id })), claimed: !granted.replayed, claimed_today: true, next_available_at: window.next_available_at, } } async function status({ user_id, now = new Date() }) { const policy = await billing.actionPolicies.get(BillingAction.DAILY_CLAIM) const window = losAngelesDay(now, policy.timezone) const entry = await billing.findLedgerByIdempotencyKey(`daily_claim:${user_id}:${window.date}`) return { claimed_today: entry !== null, next_available_at: window.next_available_at, points: policy.points, } } return { claim, status } } function losAngelesDay(now, timezone) { if (timezone !== 'America/Los_Angeles') throw new Error(`Unsupported daily claim timezone: ${timezone}`) const date = calendarDayOf(now, timezone) return { date, next_available_at: midnightInTimezone(shiftCalendarDay(date, 1), timezone).toISOString(), } }