{"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 function fracLen(s: string): number {\n  const i = s.indexOf('.');\n  return i < 0 ? 0 : s.length - i - 1;\n}\nexport function toScaled(s: string, scale: number): bigint {\n  const str = String(s).trim();\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  while (fp.length < scale) fp += '0';\n  return BigInt((ip === '' ? '0' : ip) + fp);\n}\nexport function format(n: bigint, scale: number, prec: number): string {\n  let q: bigint;\n  if (scale > prec) {\n    const d = 10n ** BigInt(scale - prec);\n    q = (n + d / 2n) / d;\n  } else {\n    q = n * (10n ** BigInt(prec - scale));\n  }\n  let s = q.toString();\n  if (prec === 0) return s;\n  while (s.length <= prec) s = '0' + s;\n  return s.slice(0, s.length - prec) + '.' + s.slice(s.length - prec);\n}\n","core.ts":"import {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 sortField = policy.latest_by === 'ts' ? 'ts' : 'seq';\n  let scale = 0;\n  for (const e of events) scale = Math.max(scale, fracLen(String(e.amount ?? '0')));\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\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    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      continue;\n    }\n    seen.add(key);\n    kept.push(e);\n  }\n  const groups = new Map<string, {tenant: any; entity: any; idx: number; evs: any[]}>();\n  kept.forEach((e, i) => {\n    const k = JSON.stringify([e.tenant, e.entity]);\n    let g = groups.get(k);\n    if (!g) { g = {tenant: e.tenant, entity: e.entity, idx: i, evs: []}; groups.set(k, g); }\n    g.evs.push(e);\n  });\n  const list = Array.from(groups.values());\n  if (policy.order === 'key') {\n    list.sort((a, b) => a.tenant < b.tenant ? -1 : a.tenant > b.tenant ? 1 : a.entity < b.entity ? -1 : a.entity > b.entity ? 1 : 0);\n  } else {\n    list.sort((a, b) => a.idx - b.idx);\n  }\n  const entities: any[] = [];\n  for (const g of list) {\n    const sorted = g.evs.map((e, i) => ({e, i})).sort((a, b) => (a.e[sortField] - b.e[sortField]) || (a.i - b.i)).map(x => x.e);\n    const retained: any[] = [];\n    for (const e of sorted) {\n      const last = retained[retained.length - 1];\n      if (last && last[sortField] === e[sortField]) {\n        if (policy.tie_policy === 'last') retained[retained.length - 1] = e;\n      } else retained.push(e);\n    }\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    for (const e of retained) {\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 (!deleted || policy.allow_resurrection) {\n        deleted = false;\n        const a = toScaled(String(e.amount ?? '0'), scale);\n        value = policy.amount_mode === 'delta' ? value + a : a;\n      }\n    }\n    if (policy.delete_wins && retained.some(e => e.kind === 'delete')) deleted = true;\n    entities.push({tenant: g.tenant, entity: g.entity, value: format(value, scale, policy.precision), deleted});\n  }\n  return {entities, duplicates};\n}\n"}}