{"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 {effectiveDue, isRetryable, compareId} from './helpers.ts';\nexport function run(payload: any, policy: any): any {\n  const now: number = payload ? payload.now : 0;\n  const jobs: any[] = payload && Array.isArray(payload.jobs) ? payload.jobs : [];\n  const dedupKey: string = policy.dedup_key;\n  const retryableCodes: any[] = Array.isArray(policy.retryable_codes) ? policy.retryable_codes : [];\n  const byKey = new Map<any, {job: any, index: number}>();\n  for (let i = 0; i < jobs.length; i++) {\n    const job: any = jobs[i];\n    const k: any = job ? job[dedupKey] : undefined;\n    byKey.set(k, {job: job, index: i});\n  }\n  const selected: {job: any, index: number}[] = Array.from(byKey.values());\n  const ready: {id: any, priority: number, created: number, index: number}[] = [];\n  const waiting: {id: any, at: number, index: number}[] = [];\n  const dead: {id: any, index: number}[] = [];\n  const cancelled: {id: any, index: number}[] = [];\n  for (const entry of selected) {\n    const job: any = entry.job;\n    const index: number = entry.index;\n    if (!job) continue;\n    const retryable: boolean = isRetryable(job.last_code, retryableCodes);\n    if (job.cancelled) {\n      if (policy.cancel_wins || !retryable) {\n        cancelled.push({id: job.id, index: index});\n        continue;\n      }\n    }\n    const staleDiff: number = now - job.created;\n    const stale: boolean = policy.stale_inclusive ? staleDiff >= policy.stale_after : staleDiff > policy.stale_after;\n    const exhausted: boolean = job.attempt >= policy.max_attempts;\n    const nonRetryableFailure: boolean = job.last_code !== 0 && job.last_code !== undefined && job.last_code !== null && !retryable;\n    if (stale || exhausted || nonRetryableFailure) {\n      dead.push({id: job.id, index: index});\n      continue;\n    }\n    const due: number = effectiveDue(job, retryable, policy);\n    if (due > now) {\n      waiting.push({id: job.id, at: due, index: index});\n    } else {\n      ready.push({id: job.id, priority: job.priority, created: job.created, index: index});\n    }\n  }\n  ready.sort((a: any, b: any) => {\n    if (a.priority !== b.priority) return policy.priority_high_first ? b.priority - a.priority : a.priority - b.priority;\n    if (a.created !== b.created) return policy.fifo_ties ? a.created - b.created : b.created - a.created;\n    return a.index - b.index;\n  });\n  if (policy.dead_order === 'id') {\n    dead.sort((a: any, b: any) => {\n      const c: number = compareId(a.id, b.id);\n      return c !== 0 ? c : a.index - b.index;\n    });\n  } else {\n    dead.sort((a: any, b: any) => a.index - b.index);\n  }\n  waiting.sort((a: any, b: any) => a.index - b.index);\n  cancelled.sort((a: any, b: any) => a.index - b.index);\n  return {ready: ready.map((x: any) => x.id), waiting: waiting.map((x: any) => ({id: x.id, at: x.at})), dead: dead.map((x: any) => x.id), cancelled: cancelled.map((x: any) => x.id)};\n}\n", "policy.ts": "export const POLICY: any = {\"base_delay\": 100, \"cancel_wins\": true, \"dead_order\": \"id\", \"dedup_key\": \"id\", \"delay_cap\": 150, \"exponential\": true, \"fifo_ties\": true, \"max_attempts\": 3, \"priority_high_first\": true, \"retryable_codes\": [429, 500], \"stale_after\": 1000, \"stale_inclusive\": true};\n", "helpers.ts": "export function isRetryable(lastCode: any, retryableCodes: any[]): boolean {\n  return Array.isArray(retryableCodes) && retryableCodes.indexOf(lastCode) !== -1;\n}\nexport function backoffDelay(attempt: any, policy: any): number {\n  const exponent: number = Math.max(0, (attempt || 0) - 1);\n  const factor: number = policy.exponential ? Math.pow(2, exponent) : 1;\n  return Math.min(policy.base_delay * factor, policy.delay_cap);\n}\nexport function effectiveDue(job: any, retryable: boolean, policy: any): number {\n  if (!retryable) return job.due;\n  if (job.last_code === 0 || job.last_code === undefined || job.last_code === null) return job.due;\n  if (job.failed_at === undefined || job.failed_at === null) return job.due;\n  const candidate: number = job.failed_at + backoffDelay(job.attempt, policy);\n  return Math.max(job.due, candidate);\n}\nexport function compareId(a: any, b: any): number {\n  if (typeof a === 'number' && typeof b === 'number') return a - b;\n  const sa: string = String(a);\n  const sb: string = String(b);\n  if (sa < sb) return -1;\n  if (sa > sb) return 1;\n  return 0;\n}\n"}}