{"files":{"main.ts":"import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n","policy.ts":"export const POLICY: any = {\n  max_age: 60,\n  inclusive_age: true,\n  scope_key: 'tenant',\n  audit_duplicate: true,\n  latest_by: 'sequence',\n  tie_policy: 'first',\n  gap_policy: 'accept',\n  allow_resurrection: true,\n  amount_mode: 'absolute',\n  delete_wins: true,\n  precision: 0,\n  order: 'key'\n};\n","helpers.ts":"export function cmp(a: string, b: string): number { return a < b ? -1 : a > b ? 1 : 0; }\nexport function fracLen(s: string): number { const i = s.indexOf('.'); return i < 0 ? 0 : s.length - i - 1; }\nexport function toScaled(s: string, scale: number): bigint {\n  const i = s.indexOf('.');\n  const ip = i < 0 ? s : s.slice(0, i);\n  let fp = i < 0 ? '' : s.slice(i + 1);\n  while (fp.length < scale) fp += '0';\n  return BigInt((ip === '' ? '0' : ip) + fp);\n}\nexport function format(v: bigint, scale: number, p: number): string {\n  const div = 10n ** BigInt(scale - p);\n  const r = (v + div / 2n) / div;\n  const s = r.toString().padStart(p + 1, '0');\n  if (p === 0) return s;\n  return s.slice(0, s.length - p) + '.' + s.slice(s.length - p);\n}\n","core.ts":"import {cmp, fracLen, toScaled, format} from './helpers.ts';\n\nexport function run(payload: any, policy: any): any {\n  const now = payload.now;\n  const events: any[] = payload.events || [];\n  const p = policy.precision;\n  let scale = p;\n  for (const e of events) { if (typeof e.amount === 'string') scale = Math.max(scale, fracLen(e.amount)); }\n  const kept: any[] = [];\n  for (let i = 0; i < events.length; i++) {\n    const e = events[i];\n    const age = now - e.ts;\n    if (age > policy.max_age) continue;\n    if (age === policy.max_age && !policy.inclusive_age) continue;\n    kept.push({e, idx: i});\n  }\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\n  const uniq: any[] = [];\n  for (const k of kept) {\n    const key = policy.scope_key === 'tenant' ? JSON.stringify([k.e.tenant, k.e.id]) : JSON.stringify(k.e.id);\n    if (seen.has(key)) { if (policy.audit_duplicate) duplicates.push(k.e.id); continue; }\n    seen.add(key);\n    uniq.push(k);\n  }\n  const groups = new Map<string, {tenant: string; entity: string; first: number; items: any[]}>();\n  for (const k of uniq) {\n    const key = JSON.stringify([k.e.tenant, k.e.entity]);\n    let g = groups.get(key);\n    if (!g) { g = {tenant: k.e.tenant, entity: k.e.entity, first: k.idx, items: []}; groups.set(key, g); }\n    g.items.push(k.e);\n  }\n  const field = policy.latest_by === 'timestamp' ? 'ts' : 'seq';\n  const gl = Array.from(groups.values());\n  if (policy.order === 'key') gl.sort((a, b) => cmp(a.tenant, b.tenant) || cmp(a.entity, b.entity));\n  else gl.sort((a, b) => a.first - b.first);\n  const entities: any[] = [];\n  for (const g of gl) {\n    const byVal = new Map<number, any>();\n    for (const e of g.items) {\n      const v = e[field];\n      if (!byVal.has(v) || policy.tie_policy === 'last') byVal.set(v, e);\n    }\n    const list = Array.from(byVal.values()).sort((a, b) => a[field] - b[field]);\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    let anyDelete = false;\n    for (const e of list) {\n      if (e.kind === 'delete') anyDelete = true;\n      if (policy.gap_policy === 'ignore' && e.seq !== seq + 1) continue;\n      seq = e.seq;\n      if (e.kind === 'delete') { deleted = true; }\n      else if (!deleted || policy.allow_resurrection) {\n        deleted = false;\n        const a = toScaled(e.amount, scale);\n        value = policy.amount_mode === 'delta' ? value + a : a;\n      }\n    }\n    if (policy.delete_wins && anyDelete) deleted = true;\n    entities.push({tenant: g.tenant, entity: g.entity, value: format(value, scale, p), deleted});\n  }\n  return {entities, duplicates};\n}\n"}}