{"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, formatRounded} from './helpers.ts';\nexport function run(payload: any, policy: any): any {\n  const now: any = payload ? payload.now : undefined;\n  const rawEvents: any[] = payload && Array.isArray(payload.events) ? payload.events : (Array.isArray(payload) ? payload : []);\n  const maxAge: any = policy ? policy.max_age : undefined;\n  const inclusiveAge: boolean = !!(policy && policy.inclusive_age);\n  const scopeKey: any = policy ? policy.scope_key : undefined;\n  const auditDuplicate: boolean = !!(policy && policy.audit_duplicate);\n  const latestBy: any = policy ? policy.latest_by : undefined;\n  const tiePolicy: any = policy ? policy.tie_policy : undefined;\n  const gapPolicy: any = policy ? policy.gap_policy : undefined;\n  const allowResurrection: boolean = !!(policy && policy.allow_resurrection);\n  const amountMode: any = policy ? policy.amount_mode : undefined;\n  const deleteWins: boolean = !!(policy && policy.delete_wins);\n  const precision: number = policy && typeof policy.precision === 'number' ? policy.precision : 0;\n  const order: any = policy ? policy.order : undefined;\n  type Item = {e: any, idx: number};\n  const wrapped: Item[] = rawEvents.map((e: any, idx: number) => ({e: e, idx: idx}));\n  const ageFiltered: Item[] = [];\n  for (const it of wrapped) {\n    if (maxAge !== undefined && maxAge !== null && now !== undefined && now !== null && it.e && typeof it.e.ts === 'number') {\n      const age = now - it.e.ts;\n      if (age > maxAge) continue;\n      if (age === maxAge && !inclusiveAge) continue;\n    }\n    ageFiltered.push(it);\n  }\n  const seen = new Set<string>();\n  const duplicates: any[] = [];\n  const deduped: Item[] = [];\n  for (const it of ageFiltered) {\n    const e: any = it.e || {};\n    const key: string = scopeKey === 'tenant' ? String(e.tenant) + '\\u0000' + String(e.id) : String(e.id);\n    if (seen.has(key)) {\n      if (auditDuplicate) duplicates.push(e.id);\n      continue;\n    }\n    seen.add(key);\n    deduped.push(it);\n  }\n  type Group = {tenant: any, entity: any, items: Item[], earliest: number};\n  const groups = new Map<string, Group>();\n  for (const it of deduped) {\n    const e: any = it.e || {};\n    const key: string = String(e.tenant) + '\\u0000' + String(e.entity);\n    let g: Group | undefined = groups.get(key);\n    if (!g) { g = {tenant: e.tenant, entity: e.entity, items: [], earliest: it.idx}; groups.set(key, g); }\n    g.items.push(it);\n    if (it.idx < g.earliest) g.earliest = it.idx;\n  }\n  const sortField: string = (latestBy === 'ts' || latestBy === 'timestamp' || latestBy === 'time') ? 'ts' : 'seq';\n  type Out = {tenant: any, entity: any, value: string, deleted: boolean, earliest: number};\n  const out: Out[] = [];\n  for (const g of groups.values()) {\n    const byValue = new Map<any, Item>();\n    for (const it of g.items) {\n      const v: any = (it.e || {})[sortField];\n      if (tiePolicy === 'last') { byValue.set(v, it); } else if (!byValue.has(v)) { byValue.set(v, it); }\n    }\n    const retained: Item[] = Array.from(byValue.values());\n    const sorted: Item[] = retained.slice().sort((a: Item, b: Item) => {\n      const av: any = (a.e || {})[sortField];\n      const bv: any = (b.e || {})[sortField];\n      if (av < bv) return -1;\n      if (av > bv) return 1;\n      return a.idx - b.idx;\n    });\n    let seqState: number = 0;\n    let value: any = {scaled: BigInt(0), scale: 0};\n    let deleted: boolean = false;\n    const anyDelete: boolean = retained.some((it: Item) => (it.e || {}).kind === 'delete');\n    for (const it of sorted) {\n      const e: any = it.e || {};\n      if (gapPolicy === 'ignore') {\n        if (e.seq !== seqState + 1) continue;\n      }\n      seqState = e.seq;\n      if (e.kind === 'delete') {\n        deleted = true;\n      } else if (e.kind === 'set') {\n        if (!deleted || allowResurrection) {\n          deleted = false;\n          const amt: any = parseDecimal(e.amount === undefined || e.amount === null ? '0' : String(e.amount));\n          if (amountMode === 'delta') { value = addDecimal(value, amt); } else { value = amt; }\n        }\n      }\n    }\n    if (deleteWins && anyDelete) deleted = true;\n    out.push({tenant: g.tenant, entity: g.entity, value: formatRounded(value, precision), deleted: deleted, earliest: g.earliest});\n  }\n  if (order === 'key') {\n    out.sort((a: Out, b: Out) => {\n      const at: string = String(a.tenant); const bt: string = String(b.tenant);\n      if (at < bt) return -1; if (at > bt) return 1;\n      const ae: string = String(a.entity); const be: string = String(b.entity);\n      if (ae < be) return -1; if (ae > be) return 1; return 0;\n    });\n  } else {\n    out.sort((a: Out, b: Out) => a.earliest - b.earliest);\n  }\n  const entities: any[] = out.map((o: Out) => ({tenant: o.tenant, entity: o.entity, value: o.value, deleted: o.deleted}));\n  return {entities: entities, duplicates: duplicates};\n}\n", "policy.ts": "export const POLICY: any = {\"delete_wins\": true, \"latest_by\": \"sequence\", \"scope_key\": \"tenant\", \"tie_policy\": \"first\", \"allow_resurrection\": true, \"amount_mode\": \"absolute\", \"gap_policy\": \"accept\", \"precision\": 0, \"inclusive_age\": true, \"max_age\": 60, \"audit_duplicate\": true, \"order\": \"key\"};\n", "helpers.ts": "export type DecimalValue = {scaled: bigint, scale: number};\nexport function pow10(n: number): bigint { let r: bigint = BigInt(1); const ten: bigint = BigInt(10); for (let i: number = 0; i < n; i++) r = r * ten; return r; }\nexport function parseDecimal(s: string): DecimalValue { let t: string = String(s).trim(); let neg: boolean = false; if (t.startsWith('-')) { neg = true; t = t.slice(1); } else if (t.startsWith('+')) { t = t.slice(1); } let exp: number = 0; const eIdx: number = t.search(/[eE]/); if (eIdx >= 0) { exp = parseInt(t.slice(eIdx + 1), 10); t = t.slice(0, eIdx); } 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'; if (!/^[0-9]+$/.test(intPart)) intPart = '0'; if (fracPart !== '' && !/^[0-9]+$/.test(fracPart)) fracPart = ''; let digits: string = intPart + fracPart; let scale: number = fracPart.length - exp; while (scale < 0) { digits = digits + '0'; scale++; } digits = digits.replace(/^0+(?=[0-9])/, ''); let scaled: bigint = BigInt(digits === '' ? '0' : digits); if (neg) scaled = -scaled; return {scaled: scaled, scale: scale}; }\nexport function addDecimal(a: DecimalValue, b: DecimalValue): DecimalValue { const scale: number = Math.max(a.scale, b.scale); const av: bigint = a.scaled * pow10(scale - a.scale); const bv: bigint = b.scaled * pow10(scale - b.scale); return {scaled: av + bv, scale: scale}; }\nexport function formatRounded(v: DecimalValue, precision: number): string { let outScaled: bigint; if (v.scale <= precision) { outScaled = v.scaled * pow10(precision - v.scale); } else { const divisor: bigint = pow10(v.scale - precision); const neg: boolean = v.scaled < BigInt(0); const absVal: bigint = neg ? -v.scaled : v.scaled; let q: bigint = absVal / divisor; const r: bigint = absVal % divisor; if (r * BigInt(2) >= divisor) q = q + BigInt(1); outScaled = neg ? -q : q; } const negOut: boolean = outScaled < BigInt(0); const absOut: bigint = negOut ? -outScaled : outScaled; let s: string = absOut.toString(); if (precision === 0) return (negOut && absOut !== BigInt(0) ? '-' : '') + s; while (s.length <= precision) s = '0' + s; const intPart: string = s.slice(0, s.length - precision); const fracPart: string = s.slice(s.length - precision); return (negOut && absOut !== BigInt(0) ? '-' : '') + intPart + '.' + fracPart; }\n"}}