{"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, addDecimal, formatDecimal} from './helpers.ts';\nexport function run(payload: any, policy: any): any {\n  const now: any = payload ? payload.now : 0;\n  const events: 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: Set<string> = new Set<string>();\n  const retained: any[] = [];\n  for (let i = 0; i < events.length; i++) {\n    const ev: any = events[i];\n    const age: number = now - ev.ts;\n    if (age > maxAge) continue;\n    if (age === maxAge && !inclusiveAge) continue;\n    const dedupKey: string = 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    retained.push({event: ev, index: i});\n  }\n  const groups: Map<string, any> = new Map<string, any>();\n  for (const item of retained) {\n    const ev: any = item.event;\n    const key: string = String(ev.tenant) + '\\u0000' + String(ev.entity);\n    let group: any = groups.get(key);\n    if (!group) {\n      group = {tenant: ev.tenant, entity: ev.entity, items: [], earliest: item.index};\n      groups.set(key, group);\n    }\n    group.items.push(item);\n    if (item.index < group.earliest) group.earliest = item.index;\n  }\n  const sortField: string = policy.latest_by === 'seq' ? 'seq' : 'ts';\n  const results: any[] = [];\n  for (const group of groups.values()) {\n    const tieMap: Map<string, any> = new Map<string, any>();\n    for (const item of group.items) {\n      const fieldValue: any = item.event[sortField];\n      const tieKey: string = String(fieldValue);\n      if (!tieMap.has(tieKey)) {\n        tieMap.set(tieKey, item);\n      } else if (policy.tie_policy === 'last') {\n        tieMap.set(tieKey, item);\n      }\n    }\n    const kept: any[] = Array.from(tieMap.values());\n    kept.sort((a: any, b: any) => {\n      const av: number = a.event[sortField];\n      const bv: number = b.event[sortField];\n      if (av < bv) return -1;\n      if (av > bv) return 1;\n      return 0;\n    });\n    let processedSeq: number = 0;\n    let value: any = parseDecimal('0');\n    let deleted: boolean = false;\n    for (const item of kept) {\n      const ev: any = item.event;\n      if (policy.gap_policy === 'ignore') {\n        if (ev.seq !== processedSeq + 1) continue;\n      }\n      processedSeq = 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 amount: any = parseDecimal(ev.amount === undefined || ev.amount === null ? '0' : String(ev.amount));\n          if (policy.amount_mode === 'delta') {\n            value = addDecimal(value, amount);\n          } else {\n            value = amount;\n          }\n        }\n      }\n    }\n    if (policy.delete_wins) {\n      let hasDelete: boolean = false;\n      for (const item of kept) {\n        if (item.event.kind === 'delete') { hasDelete = true; break; }\n      }\n      if (hasDelete) deleted = true;\n    }\n    const precision: number = typeof policy.precision === 'number' ? policy.precision : 0;\n    results.push({tenant: group.tenant, entity: group.entity, value: formatDecimal(value, precision), deleted: deleted, earliest: group.earliest});\n  }\n  if (policy.order === 'key') {\n    results.sort((a: any, b: any) => {\n      const at: string = String(a.tenant);\n      const bt: string = String(b.tenant);\n      if (at < bt) return -1;\n      if (at > bt) return 1;\n      const ae: string = String(a.entity);\n      const be: string = String(b.entity);\n      if (ae < be) return -1;\n      if (ae > be) return 1;\n      return 0;\n    });\n  } else {\n    results.sort((a: any, b: any) => a.earliest - b.earliest);\n  }\n  const entities: any[] = results.map((r: any) => ({tenant: r.tenant, entity: r.entity, value: r.value, deleted: r.deleted}));\n  return {entities: entities, duplicates: 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 interface DecimalValue { units: bigint; scale: number; }\nfunction pow10(n: number): bigint {\n  let result: bigint = BigInt(1);\n  for (let i = 0; i < n; i++) result = result * BigInt(10);\n  return result;\n}\nexport function parseDecimal(text: string): DecimalValue {\n  let s: string = String(text).trim();\n  let negative: boolean = false;\n  if (s.startsWith('-')) { negative = true; s = s.slice(1); }\n  else if (s.startsWith('+')) { s = s.slice(1); }\n  let exponent: number = 0;\n  let eIndex: number = s.search(/[eE]/);\n  if (eIndex >= 0) {\n    exponent = parseInt(s.slice(eIndex + 1), 10);\n    s = s.slice(0, eIndex);\n  }\n  const parts: string[] = s.split('.');\n  const intPart: string = parts[0] === '' || parts[0] === undefined ? '0' : parts[0];\n  const fracPart: string = parts.length > 1 ? parts[1] : '';\n  let digits: string = intPart + fracPart;\n  digits = digits.replace(/^0+(?=\\d)/, '');\n  if (digits === '') digits = '0';\n  let units: bigint = BigInt(digits);\n  let scale: number = fracPart.length - exponent;\n  if (scale < 0) {\n    units = units * pow10(-scale);\n    scale = 0;\n  }\n  if (negative) units = -units;\n  return {units: units, scale: scale};\n}\nexport function addDecimal(a: DecimalValue, b: DecimalValue): DecimalValue {\n  const scale: number = Math.max(a.scale, b.scale);\n  const au: bigint = a.units * pow10(scale - a.scale);\n  const bu: bigint = b.units * pow10(scale - b.scale);\n  return {units: au + bu, scale: scale};\n}\nexport function formatDecimal(value: DecimalValue, precision: number): string {\n  const prec: number = Math.max(0, Math.trunc(precision));\n  let rounded: bigint;\n  const absUnits: bigint = value.units < BigInt(0) ? -value.units : value.units;\n  if (value.scale > prec) {\n    const divisor: bigint = pow10(value.scale - prec);\n    let q: bigint = absUnits / divisor;\n    const r: bigint = absUnits % divisor;\n    if (r * BigInt(2) >= divisor) q = q + BigInt(1);\n    rounded = q;\n  } else {\n    rounded = absUnits * pow10(prec - value.scale);\n  }\n  const negative: boolean = value.units < BigInt(0) && rounded !== BigInt(0);\n  let digits: string = rounded.toString();\n  let out: string;\n  if (prec === 0) {\n    out = digits;\n  } else {\n    while (digits.length <= prec) digits = '0' + digits;\n    out = digits.slice(0, digits.length - prec) + '.' + digits.slice(digits.length - prec);\n  }\n  return negative ? '-' + out : out;\n}\n"}}