{"files": {"main.ts": "import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n", "core.ts": "import { parseDecimal, formatRounded } from './helpers.ts';\n\nexport function run(payload: any, policy: any): any {\n  const now: number = payload ? payload.now : 0;\n  const rawEvents: any[] = payload && Array.isArray(payload.events) ? payload.events : [];\n  const maxAge: number = policy.max_age;\n  const inclusiveAge: boolean = policy.inclusive_age;\n  const duplicates: any[] = [];\n  const seen = new Set<string>();\n  type Item = { ev: any; index: number };\n  const groups = new Map<string, { tenant: any; entity: any; minIndex: number; items: Item[] }>();\n  for (let index = 0; index < rawEvents.length; index++) {\n    const ev = rawEvents[index];\n    const age = now - ev.ts;\n    if (age > maxAge) continue;\n    if (age === maxAge && !inclusiveAge) continue;\n    const dedupKey = policy.scope_key === 'tenant' ? String(ev.tenant) + '\\u0000' + String(ev.id) : String(ev.id);\n    if (seen.has(dedupKey)) {\n      if (policy.audit_duplicate) duplicates.push(ev.id);\n      continue;\n    }\n    seen.add(dedupKey);\n    const gkey = String(ev.tenant) + '\\u0000' + String(ev.entity);\n    let group = groups.get(gkey);\n    if (!group) {\n      group = { tenant: ev.tenant, entity: ev.entity, minIndex: index, items: [] };\n      groups.set(gkey, group);\n    }\n    if (index < group.minIndex) group.minIndex = index;\n    group.items.push({ ev, index });\n  }\n  const sortField: string = policy.latest_by === 'sequence' || policy.latest_by === 'seq' ? 'seq' : 'ts';\n  const entities: any[] = [];\n  const groupList = Array.from(groups.values());\n  for (const group of groupList) {\n    const byValue = new Map<any, Item>();\n    for (const item of group.items) {\n      const key = item.ev[sortField];\n      if (policy.tie_policy === 'first') {\n        if (!byValue.has(key)) byValue.set(key, item);\n      } else {\n        byValue.set(key, item);\n      }\n    }\n    const retained: Item[] = Array.from(byValue.values());\n    const sorted: Item[] = retained.slice().sort((a: Item, b: Item) => {\n      const av = a.ev[sortField];\n      const bv = b.ev[sortField];\n      if (av < bv) return -1;\n      if (av > bv) return 1;\n      return a.index - b.index;\n    });\n    let currentSeq = 0;\n    let valueScaled = 0n;\n    let valueScale = 0;\n    let deleted = false;\n    let anyDelete = false;\n    for (const item of retained) {\n      if (item.ev.kind === 'delete') anyDelete = true;\n    }\n    for (const item of sorted) {\n      const ev = item.ev;\n      if (policy.gap_policy === 'ignore') {\n        if (ev.seq !== currentSeq + 1) continue;\n      }\n      currentSeq = ev.seq;\n      if (ev.kind === 'delete') {\n        deleted = true;\n      } else if (ev.kind === 'set') {\n        if (!deleted || policy.allow_resurrection) {\n          deleted = false;\n          const parsed = parseDecimal(ev.amount);\n          const amtScaled = parsed.scaled;\n          const amtScale = parsed.scale;\n          if (policy.amount_mode === 'absolute') {\n            valueScaled = amtScaled;\n            valueScale = amtScale;\n          } else {\n            if (amtScale > valueScale) {\n              valueScaled = valueScaled * (10n ** BigInt(amtScale - valueScale));\n              valueScale = amtScale;\n              valueScaled = valueScaled + amtScaled;\n            } else if (valueScale > amtScale) {\n              valueScaled = valueScaled + amtScaled * (10n ** BigInt(valueScale - amtScale));\n            } else {\n              valueScaled = valueScaled + amtScaled;\n            }\n          }\n        }\n      }\n    }\n    if (policy.delete_wins && anyDelete) deleted = true;\n    const value = formatRounded(valueScaled, valueScale, policy.precision);\n    entities.push({ tenant: group.tenant, entity: group.entity, value, deleted, _minIndex: group.minIndex });\n  }\n  if (policy.order === 'key') {\n    entities.sort((a: any, b: any) => {\n      const at = String(a.tenant);\n      const bt = String(b.tenant);\n      if (at < bt) return -1;\n      if (at > bt) return 1;\n      const ae = String(a.entity);\n      const be = String(b.entity);\n      if (ae < be) return -1;\n      if (ae > be) return 1;\n      return 0;\n    });\n  } else {\n    entities.sort((a: any, b: any) => a._minIndex - b._minIndex);\n  }\n  const outEntities = entities.map((e: any) => ({ tenant: e.tenant, entity: e.entity, value: e.value, deleted: e.deleted }));\n  return { entities: outEntities, duplicates };\n}\n", "policy.ts": "export const POLICY: any = {\n  scope_key: \"global\",\n  latest_by: \"timestamp\",\n  tie_policy: \"last\",\n  delete_wins: false,\n  allow_resurrection: false,\n  amount_mode: \"delta\",\n  precision: 2,\n  gap_policy: \"ignore\",\n  audit_duplicate: false,\n  order: \"input\",\n  max_age: 120,\n  inclusive_age: false\n};\n", "helpers.ts": "export function parseDecimal(amount: any): { scaled: bigint; scale: number } {\n  const text = String(amount).trim();\n  const negative = text.startsWith('-');\n  const body = negative || text.startsWith('+') ? text.slice(1) : text;\n  const dot = body.indexOf('.');\n  const intPart = dot === -1 ? body : body.slice(0, dot);\n  const fracPart = dot === -1 ? '' : body.slice(dot + 1);\n  const digits = (intPart === '' ? '0' : intPart) + fracPart;\n  const cleaned = digits.replace(/^0+(?=\\d)/, '');\n  let scaled = BigInt(cleaned === '' ? '0' : cleaned);\n  if (negative) scaled = -scaled;\n  return { scaled, scale: fracPart.length };\n}\n\nexport function formatRounded(valueScaled: bigint, valueScale: number, precision: number): string {\n  let scaled = valueScaled;\n  if (valueScale < precision) {\n    scaled = scaled * (10n ** BigInt(precision - valueScale));\n  } else if (valueScale > precision) {\n    const divisor = 10n ** BigInt(valueScale - precision);\n    const negative = scaled < 0n;\n    const abs = negative ? -scaled : scaled;\n    let quotient = abs / divisor;\n    const remainder = abs % divisor;\n    if (remainder * 2n >= divisor) quotient = quotient + 1n;\n    scaled = negative ? -quotient : quotient;\n  }\n  const negative = scaled < 0n;\n  const absText = (negative ? -scaled : scaled).toString();\n  const sign = negative ? '-' : '';\n  if (precision === 0) return sign + absText;\n  const padded = absText.padStart(precision + 1, '0');\n  const intPart = padded.slice(0, padded.length - precision);\n  const fracPart = padded.slice(padded.length - precision);\n  return sign + intPart + '.' + fracPart;\n}\n"}}