{"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 = {\"allow_resurrection\": false, \"amount_mode\": \"delta\", \"audit_duplicate\": false, \"delete_wins\": false, \"gap_policy\": \"ignore\", \"inclusive_age\": false, \"latest_by\": \"timestamp\", \"max_age\": 120, \"order\": \"input\", \"precision\": 2, \"scope_key\": \"global\", \"tie_policy\": \"last\"};\n","helpers.ts":"export function parseDec(s: any): {v: bigint, scale: number} {\n  const str = String(s).trim();\n  const i = str.indexOf('.');\n  if (i < 0) return {v: BigInt(str || '0'), scale: 0};\n  const frac = str.slice(i + 1);\n  const ip = str.slice(0, i) || '0';\n  return {v: BigInt(ip + frac), scale: frac.length};\n}\n\nexport function fmt(v: bigint, scale: number, p: number): string {\n  let q: bigint;\n  if (scale <= p) q = v * 10n ** BigInt(p - scale);\n  else {\n    const d = 10n ** BigInt(scale - p);\n    q = v / d;\n    const r = v % d;\n    if (r * 2n >= d) q += 1n;\n  }\n  let s = q.toString();\n  if (p === 0) return s;\n  while (s.length <= p) s = '0' + s;\n  return s.slice(0, s.length - p) + '.' + s.slice(s.length - p);\n}\n","core.ts":"import {parseDec, fmt} 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 duplicates: any[] = [];\n  const seen = new Set<string>();\n  const retained: {e: any, idx: number}[] = [];\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 key = policy.scope_key === 'tenant' ? JSON.stringify([e.tenant, e.id]) : JSON.stringify(e.id);\n    if (seen.has(key)) {\n      if (policy.audit_duplicate) duplicates.push(e.id);\n      return;\n    }\n    seen.add(key);\n    retained.push({e, idx});\n  });\n  const field = policy.latest_by === 'seq' ? 'seq' : 'ts';\n  const groups = new Map<string, {tenant: any, entity: any, items: {e: any, idx: number}[]}>();\n  for (const r of retained) {\n    const k = JSON.stringify([r.e.tenant, r.e.entity]);\n    let g = groups.get(k);\n    if (!g) { g = {tenant: r.e.tenant, entity: r.e.entity, items: []}; groups.set(k, g); }\n    g.items.push(r);\n  }\n  const out: {first: number, res: any}[] = [];\n  for (const g of groups.values()) {\n    const first = Math.min(...g.items.map(i => i.idx));\n    const byVal = new Map<number, any>();\n    for (const it of g.items) {\n      const f = it.e[field];\n      if (!byVal.has(f) || policy.tie_policy === 'last') byVal.set(f, it.e);\n    }\n    const sorted = [...byVal.entries()].sort((a, b) => a[0] - b[0]).map(x => x[1]);\n    const parsed = sorted.map(e => parseDec(e.amount));\n    let scale = 0;\n    for (const p of parsed) if (p.scale > scale) scale = p.scale;\n    const norm = parsed.map(p => p.v * 10n ** BigInt(scale - p.scale));\n    let seq = 0, value = 0n, deleted = false;\n    sorted.forEach((e, i) => {\n      if (policy.gap_policy === 'ignore' && e.seq !== seq + 1) return;\n      seq = e.seq;\n      if (e.kind === 'delete') { deleted = true; }\n      else {\n        if (!deleted || policy.allow_resurrection) {\n          deleted = false;\n          if (policy.amount_mode === 'absolute') value = norm[i];\n          else value += norm[i];\n        }\n      }\n    });\n    if (policy.delete_wins && sorted.some(e => e.kind === 'delete')) deleted = true;\n    out.push({first, res: {tenant: g.tenant, entity: g.entity, value: fmt(value, scale, policy.precision), deleted}});\n  }\n  if (policy.order === 'key') {\n    const cmp = (a: any, b: any) => (a < b ? -1 : a > b ? 1 : 0);\n    out.sort((a, b) => cmp(a.res.tenant, b.res.tenant) || cmp(a.res.entity, b.res.entity));\n  } else {\n    out.sort((a, b) => a.first - b.first);\n  }\n  return {entities: out.map(o => o.res), duplicates};\n}\n"}}