{"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): {n: bigint, sc: number} {\n  const str = String(s).trim();\n  const i = str.indexOf('.');\n  if (i < 0) return {n: BigInt(str), sc: 0};\n  const frac = str.slice(i + 1);\n  return {n: BigInt(str.slice(0, i) + frac), sc: frac.length};\n}\n","core.ts":"import {parseDec} 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 prec: number = policy.precision;\n  const field = policy.latest_by === 'seq' ? 'seq' : 'ts';\n  const kept: {e: any, idx: number}[] = [];\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\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    kept.push({e, idx});\n  });\n  let S = prec;\n  for (const k of kept) {\n    if (k.e.amount !== undefined && k.e.amount !== null) {\n      const d = parseDec(k.e.amount);\n      if (d.sc > S) S = d.sc;\n    }\n  }\n  const groups = new Map<string, {tenant: any, entity: any, first: number, evs: {e: any, idx: number}[]}>();\n  for (const k of kept) {\n    const gk = JSON.stringify([k.e.tenant, k.e.entity]);\n    let g = groups.get(gk);\n    if (!g) { g = {tenant: k.e.tenant, entity: k.e.entity, first: k.idx, evs: []}; groups.set(gk, g); }\n    g.evs.push(k);\n  }\n  let list = Array.from(groups.values());\n  if (policy.order === 'key') {\n    list.sort((a, b) => {\n      if (a.tenant !== b.tenant) return a.tenant < b.tenant ? -1 : 1;\n      if (a.entity !== b.entity) return a.entity < b.entity ? -1 : 1;\n      return 0;\n    });\n  } else {\n    list.sort((a, b) => a.first - b.first);\n  }\n  const pow = (n: number) => 10n ** BigInt(n);\n  const entities = list.map(g => {\n    const byVal = new Map<number, any>();\n    for (const k of g.evs) {\n      const v = k.e[field];\n      if (!byVal.has(v) || policy.tie_policy === 'last') byVal.set(v, k.e);\n    }\n    const sorted = Array.from(byVal.entries()).sort((a, b) => a[0] - b[0]).map(x => x[1]);\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    for (const e of sorted) {\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 if (e.kind === 'set') {\n        if (!deleted || policy.allow_resurrection) {\n          deleted = false;\n          const d = parseDec(e.amount);\n          const sv = d.n * pow(S - d.sc);\n          value = policy.amount_mode === 'absolute' ? sv : value + sv;\n        }\n      }\n    }\n    if (policy.delete_wins && g.evs.some(k => k.e.kind === 'delete')) deleted = true;\n    let r = value;\n    if (S > prec) {\n      const div = pow(S - prec);\n      r = value / div;\n      if ((value % div) * 2n >= div) r += 1n;\n    }\n    let s = r.toString();\n    if (prec > 0) {\n      s = s.padStart(prec + 1, '0');\n      s = s.slice(0, s.length - prec) + '.' + s.slice(s.length - prec);\n    }\n    return {tenant: g.tenant, entity: g.entity, value: s, deleted};\n  });\n  return {entities, duplicates};\n}\n"}}