import { guardOn, type Guard } from "./types"; export interface TriggerSpec { handler: string; kind: "every-minutes" | "daily-at-hour"; value: number; } export interface ExistingTrigger { id: string; handler: string; } /** * What to create and what to delete so that exactly one trigger exists per * desired handler. Running the installer again changes nothing. Apps Script does * not expose a clock trigger's interval, so a trigger is matched by its handler. */ export function planTriggers( existing: ExistingTrigger[], desired: TriggerSpec[], managedHandlers: string[], disabled?: Guard[], /** What the last install set up (stored by the adapter). A different cadence means: replace. */ installed?: TriggerSpec[], ): { create: TriggerSpec[]; remove: string[] } { if (!guardOn(disabled, "trigger-dedup")) return { create: [...desired], remove: [] }; const create: TriggerSpec[] = []; const remove: string[] = []; for (const d of desired) { const mine = existing.filter((t) => t.handler === d.handler); const was = installed?.find((i) => i.handler === d.handler); const changed = !!was && (was.kind !== d.kind || was.value !== d.value); if (!mine.length) create.push(d); else if (changed) { remove.push(...mine.map((t) => t.id)); create.push(d); } else remove.push(...mine.slice(1).map((t) => t.id)); } for (const t of existing) if (managedHandlers.includes(t.handler) && !desired.some((d) => d.handler === t.handler)) remove.push(t.id); return { create, remove }; }