{"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  delete_wins: true,\n  latest_by: 'seq',\n  scope_key: 'tenant',\n  tie_policy: 'first',\n  allow_resurrection: true,\n  amount_mode: 'absolute',\n  gap_policy: 'accept',\n  precision: 0,\n  inclusive_age: true,\n  max_age: 60,\n  audit_duplicate: true,\n  order: 'key'\n};\n","helpers.ts":"export function decScale(s: string): number {\n  const i = String(s).indexOf('.');\n  return i < 0 ? 0 : String(s).length - i - 1;\n}\nexport function toScaled(s: string, scale: number): bigint {\n  const str = String(s);\n  const i = str.indexOf('.');\n  const ip = i < 0 ? str : str.slice(0, i);\n  let fp = i < 0 ? '' : str.slice(i + 1);\n  fp = fp.padEnd(scale, '0');\n  return BigInt((ip === '' ? '0' : ip) + fp);\n}\nexport function fmt(v: bigint, scale: number, p: number): string {\n  let q: bigint;\n  if (scale <= p) {\n    q = v * 10n ** BigInt(p - scale);\n  } else {\n    const div = 10n ** BigInt(scale - p);\n    q = v / div;\n    const r = v % div;\n    if (r * 2n >= div) q += 1n;\n  }\n  if (p === 0) return q.toString();\n  const s = q.toString().padStart(p + 1, '0');\n  return s.slice(0, s.length - p) + '.' + s.slice(s.length - p);\n}\nexport function cmp(a: string, b: string): number {\n  return a < b ? -1 : a > b ? 1 : 0;\n}\n","core.ts":"import {decScale, toScaled, fmt, cmp} 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 field = policy.latest_by === 'ts' ? 'ts' : 'seq';\n  let scale = 0;\n  for (const e of events) scale = Math.max(scale, decScale(e.amount));\n  const kept: any[] = [];\n  const duplicates: any[] = [];\n  const seen = new Set<string>();\n  events.forEach((e, idx) => {\n    const age = now - e.ts;\n    if (age > policy.max_age) return;\n    if (age === policy.max_age && !policy.inclusive_age) return;\n    const k = policy.scope_key === 'tenant' ? JSON.stringify([e.tenant, e.id]) : JSON.stringify(e.id);\n    if (seen.has(k)) {\n      if (policy.audit_duplicate) duplicates.push(e.id);\n      return;\n    }\n    seen.add(k);\n    kept.push({e, idx});\n  });\n  const groups = new Map<string, any[]>();\n  for (const it of kept) {\n    const k = JSON.stringify([it.e.tenant, it.e.entity]);\n    if (!groups.has(k)) groups.set(k, []);\n    groups.get(k)!.push(it);\n  }\n  const out: any[] = [];\n  for (const items of groups.values()) {\n    const first = items[0].idx;\n    const sorted = items.slice().sort((a, b) => a.e[field] - b.e[field]);\n    const ret: any[] = [];\n    let i = 0;\n    while (i < sorted.length) {\n      let j = i;\n      while (j + 1 < sorted.length && sorted[j + 1].e[field] === sorted[i].e[field]) j++;\n      ret.push(policy.tie_policy === 'last' ? sorted[j].e : sorted[i].e);\n      i = j + 1;\n    }\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    for (const e of ret) {\n      if (policy.gap_policy === 'ignore' && e.seq !== seq + 1) continue;\n      seq = e.seq;\n      if (e.kind === 'delete') {\n        deleted = true;\n      } else {\n        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    }\n    if (policy.delete_wins && ret.some(e => e.kind === 'delete')) deleted = true;\n    out.push({\n      first,\n      tenant: ret[0].tenant,\n      entity: ret[0].entity,\n      value: fmt(value, scale, policy.precision),\n      deleted\n    });\n  }\n  if (policy.order === 'key') {\n    out.sort((a, b) => cmp(a.tenant, b.tenant) || cmp(a.entity, b.entity));\n  } else {\n    out.sort((a, b) => a.first - b.first);\n  }\n  return {\n    entities: out.map(o => ({tenant: o.tenant, entity: o.entity, value: o.value, deleted: o.deleted})),\n    duplicates\n  };\n}\n"}}