{"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 events: any[] = payload && Array.isArray(payload.events) ? payload.events : [];\n  const now: any = payload ? payload.now : 0;\n  const maxAge: number = policy.max_age;\n  const inclusiveAge: boolean = !!policy.inclusive_age;\n  const auditDuplicate: boolean = !!policy.audit_duplicate;\n  const duplicates: any[] = [];\n  const seen = 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 (inclusiveAge ? age > maxAge : age >= maxAge) continue;\n    const dedupKey: string = policy.scope_key === 'tenant' ? JSON.stringify([ev.tenant, ev.id]) : JSON.stringify([ev.id]);\n    if (seen.has(dedupKey)) {\n      if (auditDuplicate) duplicates.push(ev.id);\n      continue;\n    }\n    seen.add(dedupKey);\n    retained.push({event: ev, index: i});\n  }\n  const groups = new Map<string, any>();\n  for (const item of retained) {\n    const ev: any = item.event;\n    const key: string = JSON.stringify([ev.tenant, 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' || policy.latest_by === 'sequence' ? 'seq' : 'ts';\n  const wrapped: any[] = [];\n  for (const group of groups.values()) {\n    const byTie = new Map<any, any>();\n    for (const item of group.items) {\n      const tieValue: any = item.event[sortField];\n      if (policy.tie_policy === 'last') {\n        byTie.set(tieValue, item);\n      } else if (!byTie.has(tieValue)) {\n        byTie.set(tieValue, item);\n      }\n    }\n    const ordered: any[] = Array.from(byTie.values()).sort((a: any, b: any) => {\n      const av: number = a.event[sortField];\n      const bv: number = b.event[sortField];\n      return av < bv ? -1 : av > bv ? 1 : 0;\n    });\n    let currentSeq: number = 0;\n    let value: any = {units: 0n, scale: 0};\n    let deleted: boolean = false;\n    let hasDelete: boolean = false;\n    for (const item of ordered) if (item.event.kind === 'delete') hasDelete = true;\n    for (const item of ordered) {\n      const ev: any = item.event;\n      if (policy.gap_policy === 'ignore' && ev.seq !== currentSeq + 1) continue;\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 amount: any = parseDecimal(ev.amount === undefined || ev.amount === null ? '0' : ev.amount);\n          if (policy.amount_mode === 'absolute' || policy.amount_mode === 'assign') value = amount;\n          else value = addDecimal(value, amount);\n        }\n      }\n    }\n    if (policy.delete_wins && hasDelete) deleted = true;\n    wrapped.push({tenant: group.tenant, entity: group.entity, value: formatDecimal(value, policy.precision), deleted: deleted, earliest: group.earliest});\n  }\n  if (policy.order === 'key') {\n    wrapped.sort((a: any, b: any) => {\n      const at: string = String(a.tenant);\n      const bt: string = String(b.tenant);\n      if (at !== bt) return at < bt ? -1 : 1;\n      const ae: string = String(a.entity);\n      const be: string = String(b.entity);\n      if (ae !== be) return ae < be ? -1 : 1;\n      return 0;\n    });\n  } else {\n    wrapped.sort((a: any, b: any) => a.earliest - b.earliest);\n  }\n  const entities: any[] = wrapped.map((w: any) => ({tenant: w.tenant, entity: w.entity, value: w.value, deleted: w.deleted}));\n  return {entities: entities, duplicates: duplicates};\n}\n", "policy.ts": "export const POLICY: any = {\"delete_wins\": false, \"latest_by\": \"timestamp\", \"scope_key\": \"global\", \"tie_policy\": \"last\", \"allow_resurrection\": false, \"amount_mode\": \"delta\", \"gap_policy\": \"ignore\", \"precision\": 2, \"inclusive_age\": false, \"max_age\": 120, \"audit_duplicate\": false, \"order\": \"input\"};\n", "helpers.ts": "export function pow10(n: number): bigint {\n  let result: bigint = 1n;\n  for (let i = 0; i < n; i++) result *= 10n;\n  return result;\n}\nexport function parseDecimal(input: any): any {\n  let s: string = String(input).trim();\n  if (s === '') return {units: 0n, scale: 0};\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 exp: number = 0;\n  const eIndex: number = s.search(/[eE]/);\n  if (eIndex >= 0) {\n    exp = parseInt(s.slice(eIndex + 1), 10) || 0;\n    s = s.slice(0, eIndex);\n  }\n  const dot: number = s.indexOf('.');\n  let intPart: string = dot >= 0 ? s.slice(0, dot) : s;\n  let fracPart: string = dot >= 0 ? s.slice(dot + 1) : '';\n  if (intPart === '') intPart = '0';\n  const digits: string = (intPart + fracPart).replace(/^0+(?=\\d)/, '');\n  let units: bigint = BigInt(digits === '' ? '0' : digits);\n  let scale: number = fracPart.length - exp;\n  if (scale < 0) { units *= pow10(-scale); scale = 0; }\n  if (negative && units !== 0n) units = -units;\n  return {units: units, scale: scale};\n}\nexport function addDecimal(a: any, b: any): any {\n  if (a.scale === b.scale) return {units: a.units + b.units, scale: a.scale};\n  if (a.scale < b.scale) return {units: a.units * pow10(b.scale - a.scale) + b.units, scale: b.scale};\n  return {units: a.units + b.units * pow10(a.scale - b.scale), scale: a.scale};\n}\nexport function formatDecimal(value: any, precision: number): string {\n  let units: bigint = value.units;\n  const scale: number = value.scale;\n  let negative: boolean = false;\n  if (units < 0n) { negative = true; units = -units; }\n  let rounded: bigint;\n  if (scale > precision) {\n    const divisor: bigint = pow10(scale - precision);\n    const quotient: bigint = units / divisor;\n    const remainder: bigint = units % divisor;\n    rounded = remainder * 2n >= divisor ? quotient + 1n : quotient;\n  } else if (scale < precision) {\n    rounded = units * pow10(precision - scale);\n  } else {\n    rounded = units;\n  }\n  const sign: string = negative && rounded !== 0n ? '-' : '';\n  if (precision === 0) return sign + rounded.toString();\n  let digits: string = rounded.toString();\n  while (digits.length <= precision) digits = '0' + digits;\n  const intPart: string = digits.slice(0, digits.length - precision);\n  const fracPart: string = digits.slice(digits.length - precision);\n  return sign + intPart + '.' + fracPart;\n}\n"}}