{"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\": true, \"amount_mode\": \"absolute\", \"audit_duplicate\": true, \"delete_wins\": true, \"gap_policy\": \"accept\", \"inclusive_age\": true, \"latest_by\": \"sequence\", \"max_age\": 60, \"order\": \"key\", \"precision\": 0, \"scope_key\": \"tenant\", \"tie_policy\": \"first\"};\n","helpers.ts":"export type Dec = {n: bigint; s: number};\n\nexport function parseDec(x: any): Dec {\n  const str = String(x).trim();\n  const neg = str.startsWith('-');\n  const body = neg ? str.slice(1) : str;\n  const parts = body.split('.');\n  const ip = parts[0] || '0';\n  const fp = parts[1] || '';\n  let n = BigInt(ip + fp);\n  if (neg) n = -n;\n  return {n, s: fp.length};\n}\n\nexport function addDec(a: Dec, b: Dec): Dec {\n  const s = Math.max(a.s, b.s);\n  const an = a.n * 10n ** BigInt(s - a.s);\n  const bn = b.n * 10n ** BigInt(s - b.s);\n  return {n: an + bn, s};\n}\n\nexport function fmtDec(d: Dec, p: number): string {\n  let n = d.n;\n  if (d.s > p) {\n    const div = 10n ** BigInt(d.s - p);\n    const neg = n < 0n;\n    let m = neg ? -n : n;\n    let q = m / div;\n    const r = m % div;\n    if (r * 2n >= div) q += 1n;\n    n = neg ? -q : q;\n  } else if (d.s < p) {\n    n = n * 10n ** BigInt(p - d.s);\n  }\n  const neg = n < 0n;\n  let str = (neg ? -n : n).toString();\n  if (p > 0) {\n    while (str.length <= p) str = '0' + str;\n    str = str.slice(0, str.length - p) + '.' + str.slice(str.length - p);\n  }\n  return (neg && /[1-9]/.test(str) ? '-' : '') + str;\n}\n\nexport function cmp(a: any, b: any): number {\n  return a < b ? -1 : a > b ? 1 : 0;\n}\n","core.ts":"import {parseDec, addDec, fmtDec, cmp, Dec} 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  const kept: any[] = [];\n  for (const e of events) {\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);\n  }\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\n  const uniq: any[] = [];\n  for (const e of kept) {\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      continue;\n    }\n    seen.add(k);\n    uniq.push(e);\n  }\n  const groups = new Map<string, {tenant: any; entity: any; first: number; evs: any[]}>();\n  uniq.forEach((e, i) => {\n    const k = JSON.stringify([e.tenant, e.entity]);\n    let g = groups.get(k);\n    if (!g) {\n      g = {tenant: e.tenant, entity: e.entity, first: i, evs: []};\n      groups.set(k, g);\n    }\n    g.evs.push(e);\n  });\n  const list = Array.from(groups.values());\n  if (policy.order === 'key') {\n    list.sort((a, b) => cmp(a.tenant, b.tenant) || cmp(a.entity, b.entity));\n  } else {\n    list.sort((a, b) => a.first - b.first);\n  }\n  const entities = list.map((g) => {\n    const sorted = g.evs.map((e, i) => ({e, i})).sort((a, b) => a.e[field] - b.e[field] || a.i - b.i).map((x) => x.e);\n    const ret: any[] = [];\n    for (const e of sorted) {\n      const last = ret[ret.length - 1];\n      if (last && last[field] === e[field]) {\n        if (policy.tie_policy === 'last') ret[ret.length - 1] = e;\n      } else ret.push(e);\n    }\n    let seq = 0;\n    let value: Dec = {n: 0n, s: 0};\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 amt = parseDec(e.amount);\n          value = policy.amount_mode === 'delta' ? addDec(value, amt) : amt;\n        }\n      }\n    }\n    if (policy.delete_wins && ret.some((e) => e.kind === 'delete')) deleted = true;\n    return {tenant: g.tenant, entity: g.entity, value: fmtDec(value, policy.precision), deleted};\n  });\n  return {entities, duplicates};\n}\n"}}