{"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 {parseAmount, addScaled, formatValue} from './helpers.ts';\nexport function run(payload: any, policy: any): any {\n  const now: any = payload ? payload.now : 0;\n  const eventsIn: any[] = payload && Array.isArray(payload.events) ? payload.events : [];\n  const maxAge: number = policy.max_age;\n  const inclusiveAge: boolean = !!policy.inclusive_age;\n  const filtered: any[] = [];\n  for (let i = 0; i < eventsIn.length; i++) {\n    const ev: any = eventsIn[i];\n    const age: number = now - ev.ts;\n    if (inclusiveAge) { if (age > maxAge) continue; } else { if (age > maxAge || age === maxAge) continue; }\n    filtered.push({ev: ev, idx: i});\n  }\n  const seen: Set<string> = new Set<string>();\n  const duplicates: any[] = [];\n  const deduped: any[] = [];\n  for (const item of filtered) {\n    const ev: any = item.ev;\n    const key: string = policy.scope_key === 'tenant' ? String(ev.tenant) + '\\u0000' + String(ev.id) : String(ev.id);\n    if (seen.has(key)) { if (policy.audit_duplicate) duplicates.push(ev.id); continue; }\n    seen.add(key);\n    deduped.push(item);\n  }\n  const groupsMap: Map<string, any> = new Map<string, any>();\n  for (const item of deduped) {\n    const ev: any = item.ev;\n    const gkey: string = String(ev.tenant) + '\\u0000' + String(ev.entity);\n    let g: any = groupsMap.get(gkey);\n    if (!g) { g = {tenant: ev.tenant, entity: ev.entity, items: [], minIdx: item.idx}; groupsMap.set(gkey, g); }\n    g.items.push(item);\n    if (item.idx < g.minIdx) g.minIdx = item.idx;\n  }\n  const field: string = (policy.latest_by === 'seq' || policy.latest_by === 'sequence') ? 'seq' : 'ts';\n  const groups: any[] = Array.from(groupsMap.values());\n  const entities: any[] = [];\n  for (const g of groups) {\n    const tieMap: Map<string, any> = new Map<string, any>();\n    for (const item of g.items) {\n      const k: string = String(item.ev[field]);\n      if (!tieMap.has(k)) tieMap.set(k, item);\n      else if (policy.tie_policy === 'last') tieMap.set(k, item);\n    }\n    const retained: any[] = Array.from(tieMap.values());\n    const sorted: any[] = retained.slice().sort((a: any, b: any) => {\n      const av: number = a.ev[field]; const bv: number = b.ev[field];\n      if (av < bv) return -1; if (av > bv) return 1; return a.idx - b.idx;\n    });\n    let seqState: number = 0;\n    let units: bigint = BigInt(0);\n    let scale: number = 0;\n    let deleted: boolean = false;\n    let anyDelete: boolean = false;\n    for (const item of retained) if (item.ev.kind === 'delete') anyDelete = true;\n    for (const item of sorted) {\n      const ev: any = item.ev;\n      if (policy.gap_policy === 'ignore') { if (ev.seq !== seqState + 1) continue; }\n      seqState = ev.seq;\n      if (ev.kind === 'delete') { deleted = true; }\n      else if (ev.kind === 'set') {\n        if (!deleted || policy.allow_resurrection) {\n          deleted = false;\n          const parsed: any = parseAmount(ev.amount);\n          if (policy.amount_mode === 'absolute') { units = parsed.units; scale = parsed.scale; }\n          else { const r: any = addScaled(units, scale, parsed.units, parsed.scale); units = r.units; scale = r.scale; }\n        }\n      }\n    }\n    if (policy.delete_wins && anyDelete) deleted = true;\n    const value: string = formatValue(units, scale, policy.precision);\n    entities.push({tenant: g.tenant, entity: g.entity, value: value, deleted: deleted, _minIdx: g.minIdx});\n  }\n  if (policy.order === 'key') {\n    entities.sort((a: any, b: any) => { if (a.tenant < b.tenant) return -1; if (a.tenant > b.tenant) return 1; if (a.entity < b.entity) return -1; if (a.entity > b.entity) return 1; return 0; });\n  } else {\n    entities.sort((a: any, b: any) => a._minIdx - b._minIdx);\n  }\n  const outEntities: any[] = entities.map((e: any) => ({tenant: e.tenant, entity: e.entity, value: e.value, deleted: e.deleted}));\n  return {entities: outEntities, duplicates: duplicates};\n}\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 pow10(n: number): bigint { let r: bigint = BigInt(1); for (let i = 0; i < n; i++) r = r * BigInt(10); return r; }\nexport function parseAmount(amount: any): any { const s: string = String(amount).trim(); let neg: boolean = false; let t: string = s; if (t.startsWith('-')) { neg = true; t = t.slice(1); } else if (t.startsWith('+')) { t = t.slice(1); } const dot: number = t.indexOf('.'); let intPart: string = dot >= 0 ? t.slice(0, dot) : t; let fracPart: string = dot >= 0 ? t.slice(dot + 1) : ''; if (intPart === '') intPart = '0'; const digits: string = intPart + fracPart; let units: bigint = digits === '' ? BigInt(0) : BigInt(digits); if (neg) units = -units; return {units: units, scale: fracPart.length}; }\nexport function addScaled(aUnits: bigint, aScale: number, bUnits: bigint, bScale: number): any { const scale: number = Math.max(aScale, bScale); const a: bigint = aUnits * pow10(scale - aScale); const b: bigint = bUnits * pow10(scale - bScale); return {units: a + b, scale: scale}; }\nexport function formatValue(unitsIn: bigint, scale: number, precision: number): string { let units: bigint = unitsIn; let neg: boolean = false; if (units < BigInt(0)) { neg = true; units = -units; } let scaled: bigint; if (scale <= precision) { scaled = units * pow10(precision - scale); } else { const div: bigint = pow10(scale - precision); const q: bigint = units / div; const r: bigint = units % div; scaled = (r * BigInt(2) >= div) ? q + BigInt(1) : q; } let s: string = scaled.toString(); if (precision === 0) return (neg && scaled !== BigInt(0) ? '-' : '') + s; if (s.length <= precision) s = '0'.repeat(precision - s.length + 1) + s; const intPart: string = s.slice(0, s.length - precision); const fracPart: string = s.slice(s.length - precision); return (neg && scaled !== BigInt(0) ? '-' : '') + intPart + '.' + fracPart; }\n"}}