{
  "files": {
    "main.ts": "import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n",
    "core.ts": "import {byIndex, readyComparator} from './helpers.ts';\n\nexport function run(payload: any, policy: any): any {\n  const now = payload.now;\n  const selected = new Map<any, {job: any, index: number}>();\n  payload.jobs.forEach((job: any, index: number) => {\n    selected.set(job[policy.dedup_key], {job, index});\n  });\n\n  const ready: any[] = [];\n  const waiting: any[] = [];\n  const dead: any[] = [];\n  const cancelled: any[] = [];\n  const retryableCodes = new Set<number>(policy.retryable_codes);\n\n  for (const entry of selected.values()) {\n    const {job, index} = entry;\n    const retryable = retryableCodes.has(job.last_code);\n    if (job.cancelled && (policy.cancel_wins || !retryable)) {\n      cancelled.push(entry);\n      continue;\n    }\n\n    const age = now - job.created;\n    const stale = policy.stale_inclusive\n      ? age >= policy.stale_after\n      : age > policy.stale_after;\n    if (stale || job.attempt >= policy.max_attempts ||\n        (job.last_code !== 0 && !retryable)) {\n      dead.push(entry);\n      continue;\n    }\n\n    let due = job.due;\n    if (retryable) {\n      const multiplier = policy.exponential\n        ? 2 ** Math.max(0, job.attempt - 1)\n        : 1;\n      const delay = Math.min(policy.base_delay * multiplier, policy.delay_cap);\n      due = Math.max(due, job.failed_at + delay);\n    }\n    if (due > now) {\n      waiting.push({job, index, at: due});\n    } else {\n      ready.push(entry);\n    }\n  }\n\n  ready.sort(readyComparator(policy));\n  waiting.sort(byIndex);\n  cancelled.sort(byIndex);\n  dead.sort(policy.dead_order === 'id'\n    ? (a: any, b: any) => a.job.id < b.job.id ? -1 : a.job.id > b.job.id ? 1 : byIndex(a, b)\n    : byIndex);\n\n  return {\n    ready: ready.map(entry => entry.job.id),\n    waiting: waiting.map(entry => ({id: entry.job.id, at: entry.at})),\n    dead: dead.map(entry => entry.job.id),\n    cancelled: cancelled.map(entry => entry.job.id)\n  };\n}\n",
    "policy.ts": "export const POLICY: any = {\n  max_attempts: 4,\n  base_delay: 200,\n  exponential: false,\n  retryable_codes: [408, 503],\n  cancel_wins: false,\n  priority_high_first: false,\n  fifo_ties: false,\n  dedup_key: 'key',\n  stale_after: 2000,\n  stale_inclusive: false,\n  delay_cap: 400,\n  dead_order: 'input'\n};\n",
    "helpers.ts": "export function byIndex(a: any, b: any): number {\n  return a.index - b.index;\n}\n\nexport function readyComparator(policy: any): (a: any, b: any) => number {\n  return (a: any, b: any): number => {\n    const priority = policy.priority_high_first\n      ? b.job.priority - a.job.priority\n      : a.job.priority - b.job.priority;\n    const created = policy.fifo_ties\n      ? a.job.created - b.job.created\n      : b.job.created - a.job.created;\n    return priority || created || byIndex(a, b);\n  };\n}\n"
  }
}