241 lines · 9.7 KB
import { forgetLocator, type LocatorKind } from "../scoped-db/locators";
import type { ScopedValue } from "../scoped-db/types";

const DAY_MS = 24 * 60 * 60 * 1000;
/** Sliding idle timeout of a browser session (auth.ts SESSION_IDLE_MS). */
export const SESSION_IDLE_MS = 14 * DAY_MS;
/** Rotated refresh tokens are kept this long for reuse detection. */
export const USED_REFRESH_TOKEN_MS = 30 * DAY_MS;
/** Per-message delivery markers only need to outlive queue retries. */
export const DELIVERY_MARKER_TTL_MS = 7 * DAY_MS;
/** Used or expired runner registration tokens are kept this long after expiry (ci/runner-registration.ts). */
const REGISTRATION_KEEP_MS = 60 * 60 * 1000;
const USAGE_EVENT_RETENTION_MS = 400 * DAY_MS;
/** Never wake more often than this, however soon something expires (or if a flush keeps failing). */
const MIN_INTERVAL_MS = 10 * 1000;
/**
 * Expired rows are garbage, not a deadline (every read checks expiry itself), so they are collected at most this
 * often: a busy account wakes hourly for them, not every time one of many rows expires. Digests stay precise.
 */
const GC_INTERVAL_MS = 60 * 60 * 1000;
/** A task that threw waits this long before its next attempt. */
const FAILURE_BACKOFF_MS = 5 * 60 * 1000;

/**
 * Rows an AccountState expires by itself. Writing one of these tables arms the object's alarm; the alarm deletes
 * what is due (forgetting its D1 locators) and re-arms for the next expiry, so nothing walks every account on a
 * cron and an idle account costs nothing.
 */
type Rule = {
  table: string;
  /** SQL over the table, every `?` bound to now: rows to delete. */
  stale: string;
  /** SQL expression: when a row next becomes stale. */
  due: string;
  locator?: { kind: LocatorKind; column: string };
};

const RULES: Rule[] = [
  {
    table: "sessions",