{"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: false,\n  latest_by: 'timestamp',\n  scope_key: 'global',\n  tie_policy: 'last',\n  allow_resurrection: false,\n  amount_mode: 'delta',\n  gap_policy: 'ignore',\n  precision: 2,\n  inclusive_age: false,\n  max_age: 120,\n  audit_duplicate: false,\n  order: 'input'\n};\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 i = s.indexOf('.');\n  const ip = i < 0 ? s : s.slice(0, i);\n  let fp = i < 0 ? '' : s.slice(i + 1);\n  while (fp.length < scale) fp += '0';\n  return BigInt((ip === '' ? '0' : ip) + fp);\n}\nexport function format(v: bigint, scale: number, p: number): string {\n  let r: bigint;\n  if (scale <= p) r = v * 10n ** BigInt(p - scale);\n  else {\n    const div = 10n ** BigInt(scale - p);\n    r = (v + div / 2n) / div;\n  }\n  let s = r.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 {fracLen, toScaled, format} from './helpers.ts';\n\nexport function run(payload: any, policy: any): any {\n  const P: any = Object.assign({}, policy);\n  const src: any = payload || {};\n  for (const k of Object.keys(policy)) {\n    if (src[k] !== undefined) P[k] = src[k];\n  }\n  if (src.policy && typeof src.policy === 'object') Object.assign(P, src.policy);\n  const now = src.now;\n  const events: any[] = src.events || [];\n  const sortField = P.latest_by === 'seq' || P.latest_by === 'sequence' ? 'seq' : 'ts';\n  const amt = (e: any) => String(e.amount === undefined || e.amount === null ? '0' : e.amount);\n  let scale = 0;\n  for (const e of events) scale = Math.max(scale, fracLen(amt(e)));\n\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\n  const kept: any[] = [];\n  events.forEach((e, idx) => {\n    const age = now - e.ts;\n    if (age > P.max_age) return;\n    if (age === P.max_age && !P.inclusive_age) return;\n    const key = P.scope_key === 'tenant' ? JSON.stringify([e.tenant, e.id]) : JSON.stringify(e.id);\n    if (seen.has(key)) {\n      if (P.audit_duplicate) duplicates.push(e.id);\n      return;\n    }\n    seen.add(key);\n    kept.push({e, idx});\n  });\n\n  const groups = new Map<string, any[]>();\n  for (const k of kept) {\n    const gk = JSON.stringify([k.e.tenant, k.e.entity]);\n    if (!groups.has(gk)) groups.set(gk, []);\n    groups.get(gk)!.push(k);\n  }\n\n  const out: any[] = [];\n  for (const [, items] of groups) {\n    const first = items[0].idx;\n    const anyDelete = items.some((x) => x.e.kind === 'delete');\n    const byVal = new Map<number, any>();\n    for (const it of items) {\n      const sv = it.e[sortField];\n      if (!byVal.has(sv) || P.tie_policy === 'last') byVal.set(sv, it);\n    }\n    const chosen = Array.from(byVal.values()).sort((a, b) => a.e[sortField] - b.e[sortField]);\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    for (const it of chosen) {\n      const e = it.e;\n      if (P.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 || P.allow_resurrection) {\n          deleted = false;\n          const a = toScaled(amt(e), scale);\n          value = P.amount_mode === 'absolute' ? a : value + a;\n        }\n      }\n    }\n    if (P.delete_wins && anyDelete) deleted = true;\n    out.push({\n      first,\n      tenant: items[0].e.tenant,\n      entity: items[0].e.entity,\n      value: format(value, scale, P.precision),\n      deleted\n    });\n  }\n  if (P.order === 'key') {\n    out.sort((a, b) => {\n      const ta = String(a.tenant), tb = String(b.tenant);\n      if (ta !== tb) return ta < tb ? -1 : 1;\n      const ea = String(a.entity), eb = String(b.entity);\n      return ea < eb ? -1 : ea > eb ? 1 : 0;\n    });\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"}}