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