{"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: 'ts',\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 t = String(s).trim();\n  const i = t.indexOf('.');\n  const ip = i < 0 ? t : t.slice(0, i);\n  let fp = i < 0 ? '' : t.slice(i + 1);\n  fp = fp.padEnd(scale, '0');\n  return BigInt((ip === '' ? '0' : ip) + fp);\n}\nexport function format(v: bigint, scale: number, p: number): string {\n  let q: bigint;\n  if (scale > p) {\n    const d = 10n ** BigInt(scale - p);\n    q = (v + d / 2n) / d;\n  } else {\n    q = v * 10n ** BigInt(p - scale);\n  }\n  let s = q.toString();\n  if (p === 0) return s;\n  s = s.padStart(p + 1, '0');\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 now = payload.now;\n  const events: any[] = payload.events || [];\n  const p: number = policy.precision;\n  let S = p;\n  for (const e of events) S = Math.max(S, fracLen(String(e.amount)));\n  const field = policy.latest_by === 'seq' ? 'seq' : 'ts';\n\n  const aged: {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    aged.push({e, idx});\n  });\n\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\n  const kept: {e: any; idx: number}[] = [];\n  for (const x of aged) {\n    const k = policy.scope_key === 'tenant' ? JSON.stringify([x.e.tenant, x.e.id]) : JSON.stringify([x.e.id]);\n    if (seen.has(k)) {\n      if (policy.audit_duplicate) duplicates.push(x.e.id);\n      continue;\n    }\n    seen.add(k);\n    kept.push(x);\n  }\n\n  const groups = new Map<string, {tenant: any; entity: any; first: number; list: any[]}>();\n  for (const x of kept) {\n    const k = JSON.stringify([x.e.tenant, x.e.entity]);\n    let g = groups.get(k);\n    if (!g) {\n      g = {tenant: x.e.tenant, entity: x.e.entity, first: x.idx, list: []};\n      groups.set(k, g);\n    }\n    g.first = Math.min(g.first, x.idx);\n    g.list.push(x.e);\n  }\n\n  const out: any[] = [];\n  for (const g of groups.values()) {\n    const byKey = new Map<number, any>();\n    for (const e of g.list) {\n      const kk = e[field];\n      if (!byKey.has(kk) || policy.tie_policy === 'last') byKey.set(kk, e);\n    }\n    const ordered = Array.from(byKey.values()).sort((a, b) => a[field] - b[field]);\n    let seq = 0;\n    let value = 0n;\n    let deleted = false;\n    for (const e of ordered) {\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 a = toScaled(String(e.amount), S);\n          value = policy.amount_mode === 'delta' ? value + a : a;\n        }\n      }\n    }\n    if (policy.delete_wins && g.list.some((e: any) => e.kind === 'delete')) deleted = true;\n    out.push({tenant: g.tenant, entity: g.entity, value: format(value, S, p), deleted, first: g.first});\n  }\n\n  if (policy.order === 'key') {\n    out.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    out.sort((a, b) => a.first - b.first);\n  }\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"}}