{"version":3,"sources":["../src/schema.ts","../src/sqlite-cache-store.ts","../src/sqlite-dedupe-store.ts","../src/sqlite-rate-limit-store.ts","../src/sqlite-adaptive-rate-limit-store.ts"],"names":["sqliteTable","text","blob","integer","Database","drizzle","eq","count","lt","sql","and","randomUUID","DEFAULT_RATE_LIMIT","gte","AdaptiveCapacityCalculator"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGO,IAAM,UAAA,GAAaA,uBAAY,OAAA,EAAS;AAAA,EAC7C,IAAA,EAAMC,eAAA,CAAK,MAAM,CAAA,CAAE,UAAA,EAAW;AAAA,EAC9B,KAAA,EAAOC,gBAAK,OAAA,EAAS,EAAE,MAAM,MAAA,EAAQ,EAAE,OAAA,EAAQ;AAAA,EAC/C,SAAA,EAAWC,kBAAA,CAAQ,YAAY,CAAA,CAAE,OAAA,EAAQ;AAAA,EACzC,SAAA,EAAWA,kBAAA,CAAQ,YAAY,CAAA,CAAE,OAAA;AACnC,CAAC;AAGM,IAAM,WAAA,GAAcH,uBAAY,aAAA,EAAe;AAAA,EACpD,IAAA,EAAMC,eAAA,CAAK,MAAM,CAAA,CAAE,UAAA,EAAW;AAAA,EAC9B,KAAA,EAAOA,eAAA,CAAK,QAAQ,CAAA,CAAE,OAAA,EAAQ;AAAA,EAC9B,MAAA,EAAQA,eAAA,CAAK,QAAQ,CAAA,CAAE,OAAA,EAAQ;AAAA;AAAA,EAC/B,QAAQC,eAAA,CAAK,QAAA,EAAU,EAAE,IAAA,EAAM,QAAQ,CAAA;AAAA,EACvC,KAAA,EAAOD,gBAAK,OAAO,CAAA;AAAA,EACnB,SAAA,EAAWE,kBAAA,CAAQ,YAAY,CAAA,CAAE,OAAA,EAAQ;AAAA,EACzC,SAAA,EAAWA,kBAAA,CAAQ,YAAY,CAAA,CAAE,OAAA;AACnC,CAAC;AAGM,IAAM,cAAA,GAAiBH,uBAAY,aAAA,EAAe;AAAA,EACvD,QAAA,EAAUC,eAAA,CAAK,UAAU,CAAA,CAAE,OAAA,EAAQ;AAAA,EACnC,SAAA,EAAWE,kBAAA,CAAQ,WAAW,CAAA,CAAE,OAAA,EAAQ;AAAA,EACxC,EAAA,EAAIA,mBAAQ,IAAI,CAAA,CAAE,WAAW,EAAE,aAAA,EAAe,MAAM;AACtD,CAAC;;;ACbM,IAAM,mBAAN,MAA6D;AAAA,EAkBlE,WAAA,CAAY;AAAA;AAAA,IAEV,QAAA,GAAW,UAAA;AAAA;AAAA,IAEX,iBAAA,GAAoB,GAAA;AAAA;AAAA,IAEpB,iBAAA,GAAoB,IAAI,IAAA,GAAO;AAAA,GACjC,GAA6B,EAAC,EAAG;AArBjC;AAAA,IAAA,IAAA,CAAiB,mBAAA,GAA+B,KAAA;AAYhD,IAAA,IAAA,CAAQ,WAAA,GAAc,KAAA;AAcpB,IAAA,IAAI,cAAA;AACJ,IAAA,IAAI,mBAAA,GAAsB,KAAA;AAE1B,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,cAAA,GAAiB,IAAIC,0BAAS,QAAQ,CAAA;AACtC,MAAA,mBAAA,GAAsB,IAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,cAAA,GAAiB,QAAA;AAAA,IACnB;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,cAAA;AACd,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,EAAA,GAAKC,sBAAQ,cAAc,CAAA;AAChC,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA;AACzB,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA;AAEzB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,oBAAA,EAAqB;AAAA,EAC5B;AAAA,EAEM,IAAI,IAAA,EAAsC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC9C,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AAEA,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,GACA,IAAA,CAAK,UAAU,CAAA,CACf,KAAA,CAAMC,cAAG,UAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA,CAC/B,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AACrB,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,IAAI,GAAA,IAAO,KAAK,SAAA,EAAW;AACzB,QAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA,CAAE,MAAMA,aAAA,CAAG,UAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA;AAChE,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,IAAI;AACF,QAAA,IAAI,IAAA,CAAK,UAAU,eAAA,EAAiB;AAClC,UAAA,OAAO,KAAA,CAAA;AAAA,QACT;AACA,QAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAe,CAAA;AAAA,MACxC,CAAA,CAAA,OAAQ,CAAA,EAAA;AAEN,QAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA,CAAE,MAAMA,aAAA,CAAG,UAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA;AAChE,QAAA,OAAO,MAAA;AAAA,MACT;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,GAAA,CAAI,IAAA,EAAc,KAAA,EAAU,UAAA,EAAmC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACnE,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,SAAA,GAAY,UAAA,IAAc,CAAA,GAAI,GAAA,GAAM,MAAM,UAAA,GAAa,GAAA;AAE7D,MAAA,IAAI,eAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAI,UAAU,KAAA,CAAA,EAAW;AACvB,UAAA,eAAA,GAAkB,eAAA;AAAA,QACpB,CAAA,MAAO;AACL,UAAA,eAAA,GAAkB,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,QACxC;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,8BAA8B,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,SACtF;AAAA,MACF;AAMA,MAAA,IAAI,OAAO,UAAA,CAAW,eAAA,EAAiB,MAAM,CAAA,GAAI,KAAK,iBAAA,EAAmB;AACvE,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,UAAU,EACjB,MAAA,CAAO;AAAA,QACN,IAAA;AAAA,QACA,KAAA,EAAO,eAAA;AAAA,QACP,SAAA;AAAA,QACA,SAAA,EAAW;AAAA,OACZ,EACA,kBAAA,CAAmB;AAAA,QAClB,QAAQ,UAAA,CAAW,IAAA;AAAA,QACnB,GAAA,EAAK;AAAA,UACH,KAAA,EAAO,eAAA;AAAA,UACP,SAAA;AAAA,UACA,SAAA,EAAW;AAAA;AACb,OACD,CAAA;AAAA,IACL,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,OAAO,IAAA,EAA6B;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACxC,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AACA,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA,CAAE,MAAMA,aAAA,CAAG,UAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IAClE,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,MAClD;AACA,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA;AAAA,IACjC,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,QAAA,GAIH;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA1KL,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA2KI,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,CAAO,EAAE,KAAA,EAAOC,gBAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,UAAU,CAAA;AAElB,MAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,GAC9B,MAAA,CAAO,EAAE,OAAOA,gBAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,UAAU,CAAA,CACf,KAAA,CAAMC,cAAG,UAAA,CAAW,SAAA,EAAW,GAAG,CAAC,CAAA;AAGtC,MAAA,MAAM,SAAA,GAAY,MAAA;AAAA,QAChB,KAAK,MAAA,CAAO,MAAA,CAAO,cAAc,EAAE,MAAA,EAAQ,MAAM;AAAA,OACnD;AACA,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,aAAa,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA;AAGzE,MAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,QAAA,CAAS,SAAS,IAAI,SAAA,GAAY,CAAA;AAC/D,MAAA,MAAM,YAAA,GAAe,MAAA,CAAO,QAAA,CAAS,QAAQ,IAAI,QAAA,GAAW,CAAA;AAC5D,MAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,KAAA,CAAO,aAAA,GAAgB,eAAgB,IAAI,CAAA;AAEvE,MAAA,OAAO;AAAA,QACL,cAAA;AAAA,QACA,eAAc,EAAA,GAAA,CAAA,EAAA,GAAA,aAAA,CAAc,CAAC,CAAA,KAAf,IAAA,GAAA,MAAA,GAAA,EAAA,CAAkB,UAAlB,IAAA,GAAA,EAAA,GAA2B,CAAA;AAAA,QACzC,aAAY,EAAA,GAAA,CAAA,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgB,UAAhB,IAAA,GAAA,EAAA,GAAyB;AAAA,OACvC;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,OAAA,GAAyB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA,CAAE,MAAMA,aAAA,CAAG,UAAA,CAAW,SAAA,EAAW,GAAG,CAAC,CAAA;AAAA,IACtE,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAI,KAAK,eAAA,EAAiB;AACxB,QAAA,aAAA,CAAc,KAAK,eAAe,CAAA;AAClC,QAAA,IAAA,CAAK,eAAA,GAAkB,MAAA;AAAA,MACzB;AAEA,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,MAAA,IAAI,KAAK,mBAAA,IAAuB,OAAO,IAAA,CAAK,MAAA,CAAO,UAAU,UAAA,EAAY;AACvE,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,KAAA,EAAM;AAAA,EACb;AAAA,EAEQ,kBAAA,GAA2B;AAEjC,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIC,cAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CAOX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAAA,EACH;AAAA,EAEQ,oBAAA,GAA6B;AACnC,IAAA,IAAA,CAAK,eAAA,GAAkB,YAAY,MAAY,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7C,MAAA,MAAM,KAAK,OAAA,EAAQ;AAAA,IACrB,CAAA,CAAA,EAAG,KAAK,iBAAiB,CAAA;AACzB,IAAA,IAAI,OAAO,IAAA,CAAK,eAAA,CAAgB,KAAA,KAAU,UAAA,EAAY;AACpD,MAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEc,mBAAA,GAAqC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACjD,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,UAAU,CAAA,CAAE,MAAMD,aAAA,CAAG,UAAA,CAAW,SAAA,EAAW,GAAG,CAAC,CAAA;AAAA,IACtE,CAAA,CAAA;AAAA,EAAA;AACF;ACxPO,IAAM,oBAAN,MAA+D;AAAA,EAkBpE,WAAA,CAAY;AAAA;AAAA,IAEV,QAAA,GAAW,UAAA;AAAA;AAAA,IAEX,YAAA;AAAA;AAAA,IAEA,SAAA;AAAA;AAAA,IAEA,iBAAA,GAAoB;AAAA,GACtB,GAA8B,EAAC,EAAG;AAvBlC;AAAA,IAAA,IAAA,CAAiB,mBAAA,GAA+B,KAAA;AAChD,IAAA,IAAA,CAAQ,WAAA,uBAAkB,GAAA,EAAoC;AAC9D,IAAA,IAAA,CAAQ,YAAA,uBAAmB,GAAA,EAMzB;AAIF,IAAA,IAAA,CAAQ,WAAA,GAAc,KAAA;AA9BxB,IAAA,IAAA,EAAA;AA8CI,IAAA,IAAI,cAAA;AACJ,IAAA,IAAI,mBAAA,GAAsB,KAAA;AAE1B,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,cAAA,GAAiB,IAAIJ,0BAAS,QAAQ,CAAA;AACtC,MAAA,mBAAA,GAAsB,IAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,cAAA,GAAiB,QAAA;AAAA,IACnB;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,cAAA;AACd,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,EAAA,GAAKC,sBAAQ,cAAc,CAAA;AAChC,IAAA,IAAA,CAAK,YAAA,GAAA,CAAe,EAAA,GAAA,SAAA,IAAA,IAAA,GAAA,SAAA,GAAa,YAAA,KAAb,IAAA,GAAA,EAAA,GAA6B,GAAA;AACjD,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA;AAEzB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,oBAAA,EAAqB;AAAA,EAC5B;AAAA,EAEQ,oBAAA,GAA6B;AACnC,IAAA,IAAI,IAAA,CAAK,oBAAoB,CAAA,EAAG;AAC9B,MAAA,IAAA,CAAK,eAAA,GAAkB,YAAY,MAAM;AACvC,QAAA,IAAA,CAAK,kBAAA,EAAmB,CAAE,KAAA,CAAM,MAAM;AAAA,QAEtC,CAAC,CAAA;AAAA,MACH,CAAA,EAAG,KAAK,iBAAiB,CAAA;AACzB,MAAA,IAAI,OAAO,IAAA,CAAK,eAAA,CAAgB,KAAA,KAAU,UAAA,EAAY;AACpD,QAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA,EAEc,kBAAA,GAAoC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAChD,MAAA,MAAM,mBAAA,GAAsB,KAAK,YAAA,IAAgB,CAAA;AACjD,MAAA,IAAI,mBAAA,EAAqB;AACvB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,gBAAA,GAAmB,MAAM,IAAA,CAAK,YAAA;AAGpC,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,WAAW,CAAA,CAClB,KAAA;AAAA,QACCK,cAAA;AAAA,UACEJ,aAAAA,CAAG,WAAA,CAAY,MAAA,EAAQ,SAAS,CAAA;AAAA,UAChCE,aAAAA,CAAG,WAAA,CAAY,SAAA,EAAW,gBAAgB;AAAA;AAC5C,OACF;AAAA,IACJ,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,QAAQ,IAAA,EAAsC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAClD,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,IAAI,CAAA;AACjD,MAAA,IAAI,eAAA,EAAiB;AACnB,QAAA,OAAO,eAAA;AAAA,MACT;AAEA,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,GACA,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMF,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,IAAI,GAAA,CAAI,WAAW,WAAA,EAAa;AAC9B,QAAA,IAAI;AACF,UAAA,IAAI,GAAA,CAAI,MAAA,KAAW,eAAA,IAAmB,GAAA,CAAI,WAAW,UAAA,EAAY;AAC/D,YAAA,OAAO,KAAA,CAAA;AAAA,UACT,CAAA,MAAA,IAAW,IAAI,MAAA,EAAQ;AACrB,YAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,MAAgB,CAAA;AAAA,UACxC;AACA,UAAA,OAAO,KAAA,CAAA;AAAA,QACT,CAAA,CAAA,OAAQ,CAAA,EAAA;AAEN,UAAA,OAAO,MAAA;AAAA,QACT;AAAA,MACF;AAEA,MAAA,IAAI,GAAA,CAAI,WAAW,QAAA,EAAU;AAC3B,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAuB,CAAC,SAAS,MAAA,KAAW;AAC9D,QAAA,IAAA,CAAK,aAAa,GAAA,CAAI,IAAA,EAAM,EAAE,OAAA,EAAS,QAAQ,CAAA;AAE/C,QAAA,IAAI,IAAA,CAAK,eAAe,CAAA,EAAG;AACzB,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,MAAM,QAAA,GAAW,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA;AAC3C,YAAA,IAAI,QAAA,EAAU;AACZ,cAAA,IAAA,CAAK,YAAA,CAAa,OAAO,IAAI,CAAA;AAC7B,cAAA,IAAA,CAAK,WAAA,CAAY,OAAO,IAAI,CAAA;AAE5B,cAAA,IAAA,CAAK,EAAA,CACF,MAAA,CAAO,WAAW,CAAA,CAClB,GAAA,CAAI;AAAA,gBACH,MAAA,EAAQ,QAAA;AAAA,gBACR,KAAA,EAAO,eAAA;AAAA,gBACP,SAAA,EAAW,KAAK,GAAA;AAAI,eACrB,CAAA,CACA,KAAA,CAAMA,aAAAA,CAAG,WAAA,CAAY,MAAM,IAAI,CAAC,CAAA,CAChC,IAAA,CAAK,MAAM;AACV,gBAAA,OAAA,CAAQ,MAAS,CAAA;AAAA,cACnB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,gBAAA,OAAA,CAAQ,MAAS,CAAA;AAAA,cACnB,CAAC,CAAA;AAAA,YACL;AAAA,UACF,CAAA,EAAG,KAAK,YAAY,CAAA;AAAA,QACtB;AAAA,MACF,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AAClC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,SAAS,IAAA,EAA+B;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC5C,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,cAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,GACA,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMA,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,QAAA,MAAM,GAAA,GAAM,YAAY,CAAC,CAAA;AACzB,QAAA,IAAI,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,SAAA,EAAW;AACnC,UAAA,OAAO,GAAA,CAAI,KAAA;AAAA,QACb;AAAA,MACF;AAGA,MAAA,MAAM,QAAQK,iBAAA,EAAW;AACzB,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,WAAW,EAClB,MAAA,CAAO;AAAA,QACN,IAAA;AAAA,QACA,KAAA;AAAA,QACA,MAAA,EAAQ,SAAA;AAAA,QACR,SAAA,EAAW,GAAA;AAAA,QACX,SAAA,EAAW;AAAA,OACZ,EACA,kBAAA,CAAmB;AAAA,QAClB,QAAQ,WAAA,CAAY,IAAA;AAAA,QACpB,GAAA,EAAK;AAAA,UACH,KAAA;AAAA,UACA,MAAA,EAAQ,SAAA;AAAA,UACR,SAAA,EAAW;AAAA;AACb,OACD,CAAA;AAEH,MAAA,OAAO,KAAA;AAAA,IACT,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,QAAA,CAAS,MAAc,KAAA,EAAqC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA5NpE,MAAA,IAAA,EAAA;AA6NI,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAGA,MAAA,IAAI,gBAAA;AACJ,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,gBAAA,GAAmB,eAAA;AAAA,MACrB,CAAA,MAAA,IAAW,UAAU,IAAA,EAAM;AACzB,QAAA,gBAAA,GAAmB,UAAA;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,IAAI;AACF,UAAA,gBAAA,GAAmB,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,QACzC,SAAS,KAAA,EAAO;AACd,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,+BAA+B,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,WACvF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAGrB,MAAA,MAAM,cAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,GACA,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAML,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,WAAA,CAAY,SAAS,CAAA,IAAA,CAAA,CAAK,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgB,YAAW,WAAA,EAAa;AAEpE,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,WAAW,EAClB,GAAA,CAAI;AAAA,QACH,MAAA,EAAQ,WAAA;AAAA,QACR,MAAA,EAAQ,gBAAA;AAAA,QACR,SAAA,EAAW;AAAA,OACZ,CAAA,CACA,KAAA,CAAMA,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA;AAGnC,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA;AAC3C,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,QAAA,CAAS,QAAQ,KAAK,CAAA;AACtB,QAAA,IAAA,CAAK,YAAA,CAAa,OAAO,IAAI,CAAA;AAC7B,QAAA,IAAA,CAAK,WAAA,CAAY,OAAO,IAAI,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,IAAA,CAAK,MAAc,KAAA,EAA6B;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACpD,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,WAAW,EAClB,GAAA,CAAI;AAAA,QACH,MAAA,EAAQ,QAAA;AAAA,QACR,OAAO,KAAA,CAAM,OAAA;AAAA,QACb,SAAA,EAAW;AAAA,OACZ,CAAA,CACA,KAAA,CAAMA,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA;AAGnC,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA;AAC3C,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,QAAA,CAAS,OAAO,KAAK,CAAA;AACrB,QAAA,IAAA,CAAK,YAAA,CAAa,OAAO,IAAI,CAAA;AAC7B,QAAA,IAAA,CAAK,WAAA,CAAY,OAAO,IAAI,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,aAAa,IAAA,EAAgC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACjD,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,MACnD;AAEA,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,GACA,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMA,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,MAAM,UAAA,GACJ,KAAK,YAAA,GAAe,CAAA,IAAK,KAAK,GAAA,EAAI,GAAI,GAAA,CAAI,SAAA,IAAa,IAAA,CAAK,YAAA;AAC9D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,WAAW,CAAA,CAAE,MAAMA,aAAAA,CAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA;AAClE,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,OAAO,IAAI,MAAA,KAAW,SAAA;AAAA,IACxB,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,UAAU,IAAA,EAAsC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACpD,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,GACA,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMA,cAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,MAAM,SAAA,GAAY,GAAA,GAAM,GAAA,CAAI,SAAA,GAAY,IAAA,CAAK,YAAA;AAC7C,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,WAAW,CAAA,CAAE,MAAMA,aAAAA,CAAG,WAAA,CAAY,IAAA,EAAM,IAAI,CAAC,CAAA;AAClE,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,IAAI,GAAA,CAAI,WAAW,WAAA,EAAa;AAC9B,QAAA,IAAI;AACF,UAAA,IAAI,GAAA,CAAI,WAAW,eAAA,EAAiB;AAClC,YAAA,OAAO,KAAA,CAAA;AAAA,UACT,CAAA,MAAA,IAAW,GAAA,CAAI,MAAA,KAAW,UAAA,EAAY;AACpC,YAAA,OAAO,IAAA;AAAA,UACT,CAAA,MAAA,IAAW,IAAI,MAAA,EAAQ;AACrB,YAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,MAAgB,CAAA;AAAA,UACxC;AACA,UAAA,OAAO,KAAA,CAAA;AAAA,QACT,CAAA,CAAA,OAAQ,CAAA,EAAA;AACN,UAAA,OAAO,MAAA;AAAA,QACT;AAAA,MACF;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,QAAA,GAMH;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA3XL,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA4XI,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,YAAA;AAE/B,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,CAAO,EAAE,KAAA,EAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,WAAW,CAAA;AAEnB,MAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,GAC9B,MAAA,CAAO,EAAE,OAAOA,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMD,cAAG,WAAA,CAAY,MAAA,EAAQ,SAAS,CAAC,CAAA;AAE1C,MAAA,MAAM,kBAAkB,MAAM,IAAA,CAAK,GAChC,MAAA,CAAO,EAAE,OAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMD,cAAG,WAAA,CAAY,MAAA,EAAQ,WAAW,CAAC,CAAA;AAE5C,MAAA,MAAM,eAAe,MAAM,IAAA,CAAK,GAC7B,MAAA,CAAO,EAAE,OAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMD,cAAG,WAAA,CAAY,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAEzC,MAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,GAC9B,MAAA,CAAO,EAAE,OAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,WAAW,CAAA,CAChB,KAAA,CAAMC,cAAG,WAAA,CAAY,SAAA,EAAW,WAAW,CAAC,CAAA;AAE/C,MAAA,OAAO;AAAA,QACL,SAAA,EAAA,CAAA,CAAW,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,mBAAgB,KAAA,KAAS,CAAA;AAAA,QACpC,WAAA,EAAA,CAAA,CAAa,EAAA,GAAA,aAAA,CAAc,CAAC,CAAA,KAAf,mBAAkB,KAAA,KAAS,CAAA;AAAA,QACxC,aAAA,EAAA,CAAA,CAAe,EAAA,GAAA,eAAA,CAAgB,CAAC,CAAA,KAAjB,mBAAoB,KAAA,KAAS,CAAA;AAAA,QAC5C,UAAA,EAAA,CAAA,CAAY,EAAA,GAAA,YAAA,CAAa,CAAC,CAAA,KAAd,mBAAiB,KAAA,KAAS,CAAA;AAAA,QACtC,WAAA,EAAA,CAAA,CAAa,EAAA,GAAA,aAAA,CAAc,CAAC,CAAA,KAAf,mBAAkB,KAAA,KAAS;AAAA,OAC1C;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,OAAA,GAAyB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,YAAA;AAE/B,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,WAAW,CAAA,CAClB,MAAMA,aAAAA,CAAG,WAAA,CAAY,SAAA,EAAW,WAAW,CAAC,CAAA;AAAA,IACjD,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,WAAW,CAAA;AAEhC,MAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AACvB,MAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAAA,IAC1B,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAI,KAAK,eAAA,EAAiB;AACxB,QAAA,aAAA,CAAc,KAAK,eAAe,CAAA;AAClC,QAAA,IAAA,CAAK,eAAA,GAAkB,MAAA;AAAA,MACzB;AAEA,MAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AACvB,MAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAExB,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,MAAA,IAAI,KAAK,mBAAA,IAAuB,OAAO,IAAA,CAAK,MAAA,CAAO,UAAU,UAAA,EAAY;AACvE,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,KAAA,EAAM;AAAA,EACb;AAAA,EAEQ,kBAAA,GAA2B;AAEjC,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIC,cAAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CAUX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAAA,EACH;AACF;ACjdO,IAAM,uBAAN,MAAqD;AAAA,EAS1D,WAAA,CAAY;AAAA;AAAA,IAEV,QAAA,GAAW,UAAA;AAAA;AAAA,IAEX,aAAA,GAAgBG,yBAAA;AAAA;AAAA,IAEhB,eAAA,uBAAsB,GAAA;AAA6B,GACrD,GAAiC,EAAC,EAAG;AAZrC;AAAA,IAAA,IAAA,CAAiB,mBAAA,GAA+B,KAAA;AAEhD,IAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAA6B;AAC3D,IAAA,IAAA,CAAQ,WAAA,GAAc,KAAA;AAYpB,IAAA,IAAI,cAAA;AACJ,IAAA,IAAI,mBAAA,GAAsB,KAAA;AAE1B,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,cAAA,GAAiB,IAAIR,0BAAS,QAAQ,CAAA;AACtC,MAAA,mBAAA,GAAsB,IAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,cAAA,GAAiB,QAAA;AAAA,IACnB;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,cAAA;AACd,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,EAAA,GAAKC,sBAAQ,cAAc,CAAA;AAChC,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AACrB,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AAEvB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC1B;AAAA,EAEM,WAAW,QAAA,EAAoC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAzDvD,MAAA,IAAA,EAAA;AA0DI,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AAEjC,MAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAGvD,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,CAAO,EAAE,KAAA,EAAOE,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,cAAc,CAAA,CACnB,KAAA;AAAA,QACCG,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCO,cAAA,CAAI,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC3C,OACF;AAEF,MAAA,MAAM,YAAA,GAAA,CAAA,CAAgB,EAAA,GAAA,MAAA,CAAO,CAAC,CAAA,KAAR,mBAAkC,KAAA,KAAS,CAAA;AACjE,MAAA,OAAO,eAAe,MAAA,CAAO,KAAA;AAAA,IAC/B,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,OAAO,QAAA,EAAiC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC5C,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,cAAc,EAAE,MAAA,CAAO;AAAA,QAC1C,QAAA;AAAA,QACA,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,UAAU,QAAA,EAIb;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAnGL,MAAA,IAAA,EAAA;AAoGI,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AAEjC,MAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAGvD,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,EAAA,CACvB,MAAA,CAAO,EAAE,KAAA,EAAON,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,cAAc,CAAA,CACnB,KAAA;AAAA,QACCG,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCO,cAAA,CAAI,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC3C,OACF;AAEF,MAAA,MAAM,eAAA,GAAA,CAAA,CAAmB,EAAA,GAAA,MAAA,CAAO,CAAC,CAAA,KAAR,mBAAW,KAAA,KAAoB,CAAA;AACxD,MAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,QAAQ,eAAe,CAAA;AAE5D,MAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,GAAA,GAAM,OAAO,QAAQ,CAAA;AAEhD,MAAA,OAAO;AAAA,QACL,SAAA;AAAA,QACA,SAAA;AAAA,QACA,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,MAAM,QAAA,EAAiC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3C,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AACA,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,cAAc,CAAA,CACrB,MAAMP,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAC,CAAA;AAAA,IAChD,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,YAAY,QAAA,EAAmC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA9IvD,MAAA,IAAA,EAAA,EAAA,EAAA;AA+II,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAE1D,MAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACtB,QAAA,OAAO,MAAA,CAAO,QAAA;AAAA,MAChB;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AAEjC,MAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAGvD,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,CAAO,EAAE,KAAA,EAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,cAAc,CAAA,CACnB,KAAA;AAAA,QACCG,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCO,cAAA,CAAI,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC3C,OACF;AAEF,MAAA,MAAM,eAAA,GAAA,CAAA,CAAmB,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,mBAAgB,KAAA,KAAoB,CAAA;AAE7D,MAAA,IAAI,eAAA,GAAkB,OAAO,KAAA,EAAO;AAClC,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,EAAA,CAC7B,MAAA,CAAO,EAAE,SAAA,EAAW,cAAA,CAAe,SAAA,EAAW,CAAA,CAC9C,IAAA,CAAK,cAAc,CAAA,CACnB,KAAA;AAAA,QACCH,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCO,cAAA,CAAI,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC3C,QAED,OAAA,CAAQ,cAAA,CAAe,SAAS,CAAA,CAChC,MAAM,CAAC,CAAA;AAEV,MAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAC7B,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,eAAA,GAAA,CAAkB,EAAA,GAAA,YAAA,CAAa,CAAC,CAAA,KAAd,IAAA,GAAA,MAAA,GAAA,EAAA,CAAiB,SAAA;AACzC,MAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,sBAAA,GAAyB,eAAA,GAAkB,MAAA,CAAO,QAAA,GAAW,GAAA;AAEnE,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,sBAAsB,CAAA;AAAA,IAC3C,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAA,CAAkB,UAAkB,MAAA,EAA+B;AACjE,IAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,QAAA,EAAmC;AACnD,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKM,QAAA,GAIH;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA9NL,MAAA,IAAA,EAAA;AA+NI,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,CAAO,EAAE,KAAA,EAAON,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,cAAc,CAAA;AAEtB,MAAA,MAAM,kBAAkB,MAAM,IAAA,CAAK,EAAA,CAChC,MAAA,CAAO,EAAE,QAAA,EAAU,cAAA,CAAe,QAAA,EAAU,EAC5C,IAAA,CAAK,cAAc,CAAA,CACnB,OAAA,CAAQ,eAAe,QAAQ,CAAA;AAElC,MAAA,MAAM,kBAAkB,eAAA,CAAgB,MAAA;AACxC,MAAA,MAAM,uBAAsC,EAAC;AAE7C,MAAA,KAAA,MAAW,EAAE,QAAA,EAAS,IAAK,eAAA,EAAiB;AAC1C,QAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA;AACjD,QAAA,IAAI,CAAC,UAAA,EAAY;AACf,UAAA,oBAAA,CAAqB,KAAK,QAAQ,CAAA;AAAA,QACpC;AAAA,MACF;AAEA,MAAA,OAAO;AAAA,QACL,aAAA,EAAA,CAAA,CAAgB,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,mBAAgB,KAAA,KAAoB,CAAA;AAAA,QACpD,eAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AACA,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,cAAc,CAAA;AAAA,IACrC,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,OAAA,GAAyB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAGrB,MAAA,MAAM,YAAY,MAAM,IAAA,CAAK,EAAA,CAC1B,MAAA,CAAO,EAAE,QAAA,EAAU,cAAA,CAAe,QAAA,EAAU,EAC5C,IAAA,CAAK,cAAc,CAAA,CACnB,OAAA,CAAQ,eAAe,QAAQ,CAAA;AAElC,MAAA,KAAA,MAAW,EAAE,QAAA,EAAS,IAAK,SAAA,EAAW;AACpC,QAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,QAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AACjC,QAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAAA,MACzD;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,MAAA,IAAI,KAAK,mBAAA,IAAuB,OAAO,IAAA,CAAK,MAAA,CAAO,UAAU,UAAA,EAAY;AACvE,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,KAAA,EAAM;AAAA,EACb;AAAA,EAEc,sBAAA,CACZ,UACA,WAAA,EACe;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACf,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,cAAc,CAAA,CACrB,KAAA;AAAA,QACCG,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCE,aAAAA,CAAG,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC1C,OACF;AAAA,IACJ,CAAA,CAAA;AAAA,EAAA;AAAA,EAEQ,kBAAA,GAA2B;AAEjC,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIC,cAAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CAMX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAAA,EACH;AACF;AChUA,IAAMG,mBAAAA,GAAsC;AAAA,EAC1C,KAAA,EAAO,GAAA;AAAA,EACP,QAAA,EAAU;AAAA;AACZ,CAAA;AAaO,IAAM,+BAAN,MAAsE;AAAA,EAe3E,WAAA,CAAY;AAAA,IACV,QAAA,GAAW,UAAA;AAAA,IACX,aAAA,GAAgBA,mBAAAA;AAAA,IAChB,eAAA,uBAAsB,GAAA,EAA6B;AAAA,IACnD,iBAAiB;AAAC,GACpB,GAAyC,EAAC,EAAG;AAhB7C;AAAA,IAAA,IAAA,CAAiB,mBAAA,GAA+B,KAAA;AAEhD,IAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAA6B;AAC3D,IAAA,IAAA,CAAQ,WAAA,GAAc,KAAA;AAItB,IAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAA6B;AAC3D,IAAA,IAAA,CAAQ,kBAAA,uBAAyB,GAAA,EAAoB;AACrD,IAAA,IAAA,CAAQ,cAAA,uBAAqB,GAAA,EAAmC;AAU9D,IAAA,IAAI,cAAA;AACJ,IAAA,IAAI,mBAAA,GAAsB,KAAA;AAE1B,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,cAAA,GAAiB,IAAIR,0BAAS,QAAQ,CAAA;AACtC,MAAA,mBAAA,GAAsB,IAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,cAAA,GAAiB,QAAA;AAAA,IACnB;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,cAAA;AACd,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,EAAA,GAAKC,sBAAQ,cAAc,CAAA;AAChC,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AACrB,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AAGvB,IAAA,IAAA,CAAK,kBAAA,GAAqB,IAAIS,iCAAA,CAA2B,cAAc,CAAA;AAEvE,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC1B;AAAA,EAEM,UAAA,CACJ,QAAA,EACA,QAAA,GAA4B,YAAA,EACV;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAClB,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAGA,MAAA,MAAM,IAAA,CAAK,sBAAsB,QAAQ,CAAA;AACzC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,0BAAA,CAA2B,QAAQ,CAAA;AACxD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,wBAAA,CAAyB,QAAA,EAAU,OAAO,CAAA;AAGhE,MAAA,IAAI,QAAA,KAAa,YAAA,IAAgB,QAAA,CAAS,gBAAA,EAAkB;AAC1D,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,MAAM,mBAAA,GAAsB,MAAM,IAAA,CAAK,eAAA,CAAgB,UAAU,MAAM,CAAA;AACvE,MAAA,MAAM,yBAAA,GAA4B,MAAM,IAAA,CAAK,eAAA;AAAA,QAC3C,QAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI,aAAa,MAAA,EAAQ;AACvB,QAAA,OAAO,sBAAsB,QAAA,CAAS,YAAA;AAAA,MACxC,CAAA,MAAO;AACL,QAAA,OAAO,4BAA4B,QAAA,CAAS,aAAA;AAAA,MAC9C;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,MAAA,CACJ,QAAA,EACA,QAAA,GAA4B,YAAA,EACb;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACf,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAGrB,MAAA,IAAA,CAAK,GAAG,GAAA,CAAIL,cAAAA;AAAA;AAAA,cAAA,EAEA,QAAQ,CAAA,EAAA,EAAK,GAAG,CAAA,EAAA,EAAK,QAAQ,CAAA;AAAA,IAAA,CACxC,CAAA;AAGD,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,0BAAA,CAA2B,QAAQ,CAAA;AAExD,MAAA,IAAI,aAAa,MAAA,EAAQ;AACvB,QAAA,OAAA,CAAQ,kBAAA,CAAmB,KAAK,GAAG,CAAA;AACnC,QAAA,IAAA,CAAK,kBAAA,CAAmB,QAAQ,kBAAkB,CAAA;AAAA,MACpD,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,wBAAA,CAAyB,KAAK,GAAG,CAAA;AACzC,QAAA,IAAA,CAAK,kBAAA,CAAmB,QAAQ,wBAAwB,CAAA;AAAA,MAC1D;AAGA,MAAA,OAAA,CAAQ,iBAAA,GAAoB,KAAK,kBAAA,CAAmB,sBAAA;AAAA,QAClD,OAAA,CAAQ;AAAA,OACV;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,UAAU,QAAA,EAWb;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACD,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,IAAA,CAAK,sBAAsB,QAAQ,CAAA;AACzC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,0BAAA,CAA2B,QAAQ,CAAA;AACxD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,wBAAA,CAAyB,QAAA,EAAU,OAAO,CAAA;AAEhE,MAAA,MAAM,gBAAA,GAAmB,MAAM,IAAA,CAAK,eAAA,CAAgB,UAAU,MAAM,CAAA;AACpE,MAAA,MAAM,sBAAA,GAAyB,MAAM,IAAA,CAAK,eAAA;AAAA,QACxC,QAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAE1D,MAAA,OAAO;AAAA,QACL,SAAA,EACE,QAAA,CAAS,YAAA,GACT,gBAAA,IACC,SAAS,aAAA,GAAgB,sBAAA,CAAA;AAAA,QAC5B,WAAW,IAAI,IAAA,CAAK,KAAK,GAAA,EAAI,GAAI,OAAO,QAAQ,CAAA;AAAA,QAChD,KAAA,EAAO,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAAA,QACrC,QAAA,EAAU;AAAA,UACR,cAAc,QAAA,CAAS,YAAA;AAAA,UACvB,eAAe,QAAA,CAAS,aAAA;AAAA,UACxB,kBAAkB,QAAA,CAAS,gBAAA;AAAA,UAC3B,kBAAA,EAAoB,KAAK,kBAAA,CAAmB,iBAAA;AAAA,YAC1C,OAAA,CAAQ;AAAA,WACV;AAAA,UACA,QAAQ,QAAA,CAAS;AAAA;AACnB,OACF;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,MAAM,QAAA,EAAiC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3C,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAGA,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,cAAc,CAAA,CACrB,MAAMH,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAC,CAAA;AAG9C,MAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,QAAQ,CAAA;AACpC,MAAA,IAAA,CAAK,cAAA,CAAe,OAAO,QAAQ,CAAA;AACnC,MAAA,IAAA,CAAK,kBAAA,CAAmB,OAAO,QAAQ,CAAA;AAAA,IACzC,CAAA,CAAA;AAAA,EAAA;AAAA,EAEM,WAAA,CACJ,QAAA,EACA,QAAA,GAA4B,YAAA,EACX;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACjB,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAE1D,MAAA,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG;AACtB,QAAA,OAAO,MAAA,CAAO,QAAA;AAAA,MAChB;AAEA,MAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,UAAA,CAAW,UAAU,QAAQ,CAAA;AAC3D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,OAAO,CAAA;AAAA,MACT;AAGA,MAAA,MAAM,IAAA,CAAK,sBAAsB,QAAQ,CAAA;AACzC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,0BAAA,CAA2B,QAAQ,CAAA;AACxD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,wBAAA,CAAyB,QAAA,EAAU,OAAO,CAAA;AAEhE,MAAA,IAAI,QAAA,KAAa,YAAA,IAAgB,QAAA,CAAS,gBAAA,EAAkB;AAC1D,QAAA,OAAO,IAAA,CAAK,mBAAmB,MAAA,CAAO,uBAAA;AAAA,MACxC;AAGA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AAEjC,MAAA,MAAM,YAAA,GAAe,KAAK,MAAA,CACvB,OAAA;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,OAOF,CACC,GAAA,CAAI,QAAA,EAAU,QAAA,EAAU,WAAW,CAAA;AAItC,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,kBAAkB,YAAA,CAAa,SAAA;AACrC,MAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,sBAAA,GAAyB,eAAA,GAAkB,MAAA,CAAO,QAAA,GAAW,GAAA;AACnE,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,sBAAsB,CAAA;AAAA,IAC3C,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAA,CAAkB,UAAkB,MAAA,EAA+B;AACjE,IAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,QAAA,EAAmC;AACnD,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKM,QAAA,GAIH;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AA5RL,MAAA,IAAA,EAAA;AA6RI,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AAEA,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAC5B,MAAA,CAAO,EAAE,KAAA,EAAOC,gBAAAA,EAAM,EAAG,CAAA,CACzB,IAAA,CAAK,cAAc,CAAA;AAEtB,MAAA,MAAM,kBAAkB,MAAM,IAAA,CAAK,EAAA,CAChC,MAAA,CAAO,EAAE,QAAA,EAAU,cAAA,CAAe,QAAA,EAAU,EAC5C,IAAA,CAAK,cAAc,CAAA,CACnB,OAAA,CAAQ,eAAe,QAAQ,CAAA;AAElC,MAAA,MAAM,kBAAkB,eAAA,CAAgB,MAAA;AACxC,MAAA,MAAM,uBAAsC,EAAC;AAE7C,MAAA,KAAA,MAAW,EAAE,QAAA,EAAS,IAAK,eAAA,EAAiB;AAC1C,QAAA,MAAM,UAAA,GAAa,MAAM,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA;AACjD,QAAA,IAAI,CAAC,UAAA,EAAY;AACf,UAAA,oBAAA,CAAqB,KAAK,QAAQ,CAAA;AAAA,QACpC;AAAA,MACF;AAEA,MAAA,OAAO;AAAA,QACL,aAAA,EAAA,CAAA,CAAgB,EAAA,GAAA,WAAA,CAAY,CAAC,CAAA,KAAb,mBAAgB,KAAA,KAAoB,CAAA;AAAA,QACpD,eAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,MACvD;AACA,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,cAAc,CAAA;AACnC,MAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAC3B,MAAA,IAAA,CAAK,eAAe,KAAA,EAAM;AAC1B,MAAA,IAAA,CAAK,mBAAmB,KAAA,EAAM;AAAA,IAChC,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,OAAA,GAAyB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAGrB,MAAA,MAAM,YAAY,MAAM,IAAA,CAAK,EAAA,CAC1B,MAAA,CAAO,EAAE,QAAA,EAAU,cAAA,CAAe,QAAA,EAAU,EAC5C,IAAA,CAAK,cAAc,CAAA,CACnB,OAAA,CAAQ,eAAe,QAAQ,CAAA;AAElC,MAAA,KAAA,MAAW,EAAE,QAAA,EAAS,IAAK,SAAA,EAAW;AACpC,QAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,QAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AACjC,QAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAAA,MACzD;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAA,GAAuB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC3B,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,MAAA,IAAI,KAAK,mBAAA,IAAuB,OAAO,IAAA,CAAK,MAAA,CAAO,UAAU,UAAA,EAAY;AACvE,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAAA,IACF,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,KAAA,EAAM;AAAA,EACb;AAAA;AAAA,EAIQ,wBAAA,CACN,UACA,OAAA,EACuB;AAEvB,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AAC5D,IAAA,MAAM,cAAA,GACJ,IAAA,CAAK,kBAAA,CAAmB,MAAA,CAAO,uBAAA;AAEjC,IAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,UAAA,GAAa,cAAA,EAAgB;AAC5C,MAAA,OACE,KAAK,cAAA,CAAe,GAAA,CAAI,QAAQ,CAAA,IAAK,IAAA,CAAK,mBAAmB,QAAQ,CAAA;AAAA,IAEzE;AAEA,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AACjD,IAAA,MAAM,QAAA,GAAW,KAAK,kBAAA,CAAmB,wBAAA;AAAA,MACvC,QAAA;AAAA,MACA,UAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,QAAA,EAAU,QAAQ,CAAA;AAC1C,IAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,QAAA,EAAU,IAAA,CAAK,KAAK,CAAA;AAEhD,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEQ,2BAA2B,QAAA,EAAmC;AACpE,IAAA,IAAI,CAAC,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,EAAG;AACvC,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,QAAA,EAAU;AAAA,QACjC,oBAAoB,EAAC;AAAA,QACrB,0BAA0B,EAAC;AAAA,QAC3B,iBAAA,EAAmB;AAAA,OACpB,CAAA;AAAA,IACH;AACA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA;AAAA,EAC1C;AAAA,EAEc,sBAAsB,QAAA,EAAiC;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACnE,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,EAAG;AACtC,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,GAAA,GAAM,IAAA,CAAK,kBAAA,CAAmB,MAAA,CAAO,kBAAA;AAEzD,MAAA,MAAM,cAAA,GAAiB,KAAK,MAAA,CACzB,OAAA;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,OAMF,CACC,GAAA,CAAI,QAAA,EAAU,WAAW,CAAA;AAK5B,MAAA,MAAM,OAAA,GAA2B;AAAA,QAC/B,oBAAoB,EAAC;AAAA,QACrB,0BAA0B,EAAC;AAAA,QAC3B,iBAAA,EAAmB;AAAA,OACrB;AAEA,MAAA,KAAA,MAAW,WAAW,cAAA,EAAgB;AACpC,QAAA,IAAI,OAAA,CAAQ,aAAa,MAAA,EAAQ;AAC/B,UAAA,OAAA,CAAQ,kBAAA,CAAmB,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AAAA,QACnD,CAAA,MAAO;AACL,UAAA,OAAA,CAAQ,wBAAA,CAAyB,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AAAA,QACzD;AAAA,MACF;AAGA,MAAA,OAAA,CAAQ,iBAAA,GAAoB,KAAK,kBAAA,CAAmB,sBAAA;AAAA,QAClD,OAAA,CAAQ;AAAA,OACV;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAA,EAAU,OAAO,CAAA;AAAA,IAC5C,CAAA,CAAA;AAAA,EAAA;AAAA,EAEc,eAAA,CACZ,UACA,QAAA,EACiB;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACjB,MAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,QAAA;AAEjC,MAAA,MAAM,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA;AAGvD,MAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CACjB,OAAA;AAAA,QACC;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,OAKF,CACC,GAAA,CAAI,QAAA,EAAU,QAAA,EAAU,WAAW,CAAA;AAEtC,MAAA,OAAO,OAAO,KAAA,IAAS,CAAA;AAAA,IACzB,CAAA,CAAA;AAAA,EAAA;AAAA,EAEQ,mBAAmB,QAAA,EAA+B;AACxD,IAAA,MAAM,SACJ,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,mBAAmB,MAAA,CAAO,kBAAA;AAC9C,IAAA,OAAO,SAAS,MAAA,GAAS,CAAA,IAAK,QAAA,CAAS,CAAC,IAAK,MAAA,EAAQ;AACnD,MAAA,QAAA,CAAS,KAAA,EAAM;AAAA,IACjB;AAAA,EACF;AAAA,EAEQ,iBAAiB,QAAA,EAA0B;AACjD,IAAA,MAAM,SAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,QAAQ,KAAK,IAAA,CAAK,aAAA;AAC1D,IAAA,OAAO,MAAA,CAAO,KAAA;AAAA,EAChB;AAAA,EAEQ,mBAAmB,QAAA,EAAyC;AAClE,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAC5C,IAAA,OAAO;AAAA,MACL,YAAA,EAAc,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,GAAG,CAAA;AAAA,MACpC,aAAA,EAAe,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,GAAG,CAAA;AAAA,MACrC,gBAAA,EAAkB,KAAA;AAAA,MAClB,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAAA,EAEc,sBAAA,CACZ,UACA,WAAA,EACe;AAAA,IAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACf,MAAA,MAAM,IAAA,CAAK,EAAA,CACR,MAAA,CAAO,cAAc,CAAA,CACrB,KAAA;AAAA,QACCG,cAAAA;AAAA,UACEJ,aAAAA,CAAG,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAA;AAAA,UACpCE,aAAAA,CAAG,cAAA,CAAe,SAAA,EAAW,WAAW;AAAA;AAC1C,OACF;AAAA,IACJ,CAAA,CAAA;AAAA,EAAA;AAAA,EAEQ,kBAAA,GAA2B;AAEjC,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIC,cAAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CAOX,CAAA;AAGD,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,MAAA,CAEX,CAAA;AAAA,IACH,CAAA,CAAA,OAAQ,CAAA,EAAA;AAAA,IAER;AAGA,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA,IAAA,CAEX,CAAA;AAGD,IAAA,IAAA,CAAK,GAAG,GAAA,CAAIA,cAAAA;AAAA;AAAA;AAAA,IAAA,CAGX,CAAA;AAAA,EACH;AACF","file":"index.cjs","sourcesContent":["import { sqliteTable, text, integer, blob } from 'drizzle-orm/sqlite-core';\n\n// Cache table for storing cached API responses\nexport const cacheTable = sqliteTable('cache', {\n  hash: text('hash').primaryKey(),\n  value: blob('value', { mode: 'json' }).notNull(),\n  expiresAt: integer('expires_at').notNull(),\n  createdAt: integer('created_at').notNull(),\n});\n\n// Dedupe table for tracking in-progress requests\nexport const dedupeTable = sqliteTable('dedupe_jobs', {\n  hash: text('hash').primaryKey(),\n  jobId: text('job_id').notNull(),\n  status: text('status').notNull(), // 'pending', 'completed', 'failed'\n  result: blob('result', { mode: 'json' }),\n  error: text('error'),\n  createdAt: integer('created_at').notNull(),\n  updatedAt: integer('updated_at').notNull(),\n});\n\n// Rate limit table for tracking API request limits\nexport const rateLimitTable = sqliteTable('rate_limits', {\n  resource: text('resource').notNull(),\n  timestamp: integer('timestamp').notNull(),\n  id: integer('id').primaryKey({ autoIncrement: true }),\n});\n\nexport type CacheRow = typeof cacheTable.$inferSelect;\nexport type DedupeRow = typeof dedupeTable.$inferSelect;\nexport type RateLimitRow = typeof rateLimitTable.$inferSelect;\n","import type { CacheStore } from '@comic-vine/client';\nimport Database from 'better-sqlite3';\nimport { eq, lt, count, sql } from 'drizzle-orm';\nimport { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { cacheTable } from './schema.js';\n\nexport interface SQLiteCacheStoreOptions {\n  /** File path or existing `better-sqlite3` connection. Defaults to `':memory:'`. */\n  database?: string | InstanceType<typeof Database>;\n  cleanupIntervalMs?: number;\n  maxEntrySizeBytes?: number;\n}\n\nexport class SQLiteCacheStore<T = unknown> implements CacheStore<T> {\n  private db: BetterSQLite3Database;\n  private sqlite: InstanceType<typeof Database>;\n  /** Indicates whether this store is responsible for managing (and therefore closing) the SQLite connection */\n  private readonly isConnectionManaged: boolean = false;\n  private cleanupInterval?: NodeJS.Timeout;\n  private readonly cleanupIntervalMs: number;\n  /**\n   * Maximum allowed size (in bytes) for a single cache entry. If the serialized\n   * value exceeds this limit the entry will be **silently skipped** to avoid\n   * breaching SQLite's max length limits which could otherwise throw at write\n   * time. Defaults to `5 MiB`, which is well under SQLiteʼs compiled\n   * `SQLITE_MAX_LENGTH` (usually 1 GiB) yet large enough for typical Comic Vine\n   * responses.\n   */\n  private readonly maxEntrySizeBytes: number;\n  private isDestroyed = false;\n\n  constructor({\n    /** File path or existing `better-sqlite3` connection. Defaults to `':memory:'`. */\n    database = ':memory:',\n    /** Cleanup interval in milliseconds. Defaults to 1 minute. */\n    cleanupIntervalMs = 60_000,\n    /** Maximum allowed size (in bytes) for a single cache entry. Defaults to 5 MiB. */\n    maxEntrySizeBytes = 5 * 1024 * 1024,\n  }: SQLiteCacheStoreOptions = {}) {\n    // Support passing an existing `better-sqlite3` Database instance so that\n    // multiple stores can share the *same* file and connection. If a string\n    // path is provided we create the connection ourselves and therefore take\n    // ownership of it for later cleanup.\n    let sqliteInstance: InstanceType<typeof Database>;\n    let isConnectionManaged = false;\n\n    if (typeof database === 'string') {\n      sqliteInstance = new Database(database);\n      isConnectionManaged = true;\n    } else {\n      sqliteInstance = database;\n    }\n\n    this.sqlite = sqliteInstance;\n    this.isConnectionManaged = isConnectionManaged;\n    this.db = drizzle(sqliteInstance);\n    this.cleanupIntervalMs = cleanupIntervalMs;\n    this.maxEntrySizeBytes = maxEntrySizeBytes;\n\n    this.initializeDatabase();\n    this.startCleanupInterval();\n  }\n\n  async get(hash: string): Promise<T | undefined> {\n    if (this.isDestroyed) {\n      throw new Error('Cache store has been destroyed');\n    }\n\n    const result = await this.db\n      .select()\n      .from(cacheTable)\n      .where(eq(cacheTable.hash, hash))\n      .limit(1);\n\n    if (result.length === 0) {\n      return undefined;\n    }\n\n    const item = result[0];\n    if (!item) {\n      return undefined;\n    }\n\n    const now = Date.now();\n\n    if (now >= item.expiresAt) {\n      await this.db.delete(cacheTable).where(eq(cacheTable.hash, hash));\n      return undefined;\n    }\n\n    try {\n      if (item.value === '__UNDEFINED__') {\n        return undefined;\n      }\n      return JSON.parse(item.value as string);\n    } catch {\n      // If deserialization fails, remove the corrupted item\n      await this.db.delete(cacheTable).where(eq(cacheTable.hash, hash));\n      return undefined;\n    }\n  }\n\n  async set(hash: string, value: T, ttlSeconds: number): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Cache store has been destroyed');\n    }\n\n    const now = Date.now();\n    const expiresAt = ttlSeconds <= 0 ? now : now + ttlSeconds * 1000;\n\n    let serializedValue: string;\n    try {\n      if (value === undefined) {\n        serializedValue = '__UNDEFINED__';\n      } else {\n        serializedValue = JSON.stringify(value);\n      }\n    } catch (error) {\n      throw new Error(\n        `Failed to serialize value: ${error instanceof Error ? error.message : String(error)}`,\n      );\n    }\n\n    // SIZE GUARD: Skip caching if the value is too large to avoid hitting\n    // SQLite length limits. We **silently** skip because callers shouldn't be\n    // penalised for large responses — they will simply be fetched again next\n    // time.\n    if (Buffer.byteLength(serializedValue, 'utf8') > this.maxEntrySizeBytes) {\n      return;\n    }\n\n    await this.db\n      .insert(cacheTable)\n      .values({\n        hash,\n        value: serializedValue,\n        expiresAt,\n        createdAt: now,\n      })\n      .onConflictDoUpdate({\n        target: cacheTable.hash,\n        set: {\n          value: serializedValue,\n          expiresAt,\n          createdAt: now,\n        },\n      });\n  }\n\n  async delete(hash: string): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Cache store has been destroyed');\n    }\n    await this.db.delete(cacheTable).where(eq(cacheTable.hash, hash));\n  }\n\n  async clear(): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Cache store has been destroyed');\n    }\n    await this.db.delete(cacheTable);\n  }\n\n  /**\n   * Get cache statistics\n   */\n  async getStats(): Promise<{\n    totalItems: number;\n    expiredItems: number;\n    databaseSizeKB: number;\n  }> {\n    const now = Date.now();\n\n    const totalResult = await this.db\n      .select({ count: count() })\n      .from(cacheTable);\n\n    const expiredResult = await this.db\n      .select({ count: count() })\n      .from(cacheTable)\n      .where(lt(cacheTable.expiresAt, now));\n\n    // Get database size (approximate)\n    const pageCount = Number(\n      this.sqlite.pragma('page_count', { simple: true }),\n    );\n    const pageSize = Number(this.sqlite.pragma('page_size', { simple: true }));\n\n    // Fallback to 0 if parsing failed (NaN)\n    const safePageCount = Number.isFinite(pageCount) ? pageCount : 0;\n    const safePageSize = Number.isFinite(pageSize) ? pageSize : 0;\n    const databaseSizeKB = Math.round((safePageCount * safePageSize) / 1024);\n\n    return {\n      databaseSizeKB,\n      expiredItems: expiredResult[0]?.count ?? 0,\n      totalItems: totalResult[0]?.count ?? 0,\n    };\n  }\n\n  /**\n   * Manually trigger cleanup of expired items\n   */\n  async cleanup(): Promise<void> {\n    const now = Date.now();\n    await this.db.delete(cacheTable).where(lt(cacheTable.expiresAt, now));\n  }\n\n  /**\n   * Close the database connection\n   */\n  async close(): Promise<void> {\n    if (this.cleanupInterval) {\n      clearInterval(this.cleanupInterval);\n      this.cleanupInterval = undefined;\n    }\n\n    this.isDestroyed = true;\n\n    // Only close the underlying DB if **this** store manages it.\n    if (this.isConnectionManaged && typeof this.sqlite.close === 'function') {\n      this.sqlite.close();\n    }\n  }\n\n  /**\n   * Alias for close() to match test expectations\n   */\n  destroy(): void {\n    this.close();\n  }\n\n  private initializeDatabase(): void {\n    // Create table if it doesn't exist\n    this.db.run(sql`\n      CREATE TABLE IF NOT EXISTS cache (\n        hash TEXT PRIMARY KEY,\n        value BLOB NOT NULL,\n        expires_at INTEGER NOT NULL,\n        created_at INTEGER NOT NULL\n      )\n    `);\n\n    // Create index on expires_at for efficient cleanup\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_cache_expires_at ON cache(expires_at)\n    `);\n  }\n\n  private startCleanupInterval(): void {\n    this.cleanupInterval = setInterval(async () => {\n      await this.cleanup();\n    }, this.cleanupIntervalMs);\n    if (typeof this.cleanupInterval.unref === 'function') {\n      this.cleanupInterval.unref();\n    }\n  }\n\n  private async cleanupExpiredItems(): Promise<void> {\n    const now = Date.now();\n    await this.db.delete(cacheTable).where(lt(cacheTable.expiresAt, now));\n  }\n}\n","import { randomUUID } from 'crypto';\nimport type { DedupeStore } from '@comic-vine/client';\nimport Database from 'better-sqlite3';\nimport { eq, lt, count, sql, and } from 'drizzle-orm';\nimport { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { dedupeTable } from './schema.js';\n\nexport interface SQLiteDedupeStoreOptions {\n  database?: string | InstanceType<typeof Database>;\n  jobTimeoutMs?: number;\n  timeoutMs?: number;\n  cleanupIntervalMs?: number;\n}\n\nexport class SQLiteDedupeStore<T = unknown> implements DedupeStore<T> {\n  private db: BetterSQLite3Database;\n  private sqlite: InstanceType<typeof Database>;\n  /** Indicates whether this store manages (and should close) the SQLite connection */\n  private readonly isConnectionManaged: boolean = false;\n  private jobPromises = new Map<string, Promise<T | undefined>>();\n  private jobResolvers = new Map<\n    string,\n    {\n      resolve: (value: T | undefined) => void;\n      reject: (reason: unknown) => void;\n    }\n  >();\n  private readonly jobTimeoutMs: number;\n  private cleanupInterval?: NodeJS.Timeout;\n  private readonly cleanupIntervalMs: number;\n  private isDestroyed = false;\n\n  constructor({\n    /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */\n    database = ':memory:',\n    /** Job timeout in milliseconds. Preferred over timeoutMs. */\n    jobTimeoutMs,\n    /** Legacy alias for jobTimeoutMs. */\n    timeoutMs,\n    /** Cleanup interval in milliseconds. Defaults to 1 minute. */\n    cleanupIntervalMs = 60_000,\n  }: SQLiteDedupeStoreOptions = {}) {\n    // Support passing an existing `better-sqlite3` Database instance so that\n    // multiple stores can share the *same* file and connection. If a string\n    // path is provided we create the connection ourselves and therefore take\n    // ownership of it for later cleanup.\n    let sqliteInstance: InstanceType<typeof Database>;\n    let isConnectionManaged = false;\n\n    if (typeof database === 'string') {\n      sqliteInstance = new Database(database);\n      isConnectionManaged = true;\n    } else {\n      sqliteInstance = database;\n    }\n\n    this.sqlite = sqliteInstance;\n    this.isConnectionManaged = isConnectionManaged;\n    this.db = drizzle(sqliteInstance);\n    this.jobTimeoutMs = timeoutMs ?? jobTimeoutMs ?? 300000;\n    this.cleanupIntervalMs = cleanupIntervalMs;\n\n    this.initializeDatabase();\n    this.startCleanupInterval();\n  }\n\n  private startCleanupInterval(): void {\n    if (this.cleanupIntervalMs > 0) {\n      this.cleanupInterval = setInterval(() => {\n        this.cleanupExpiredJobs().catch(() => {\n          // Ignore cleanup errors\n        });\n      }, this.cleanupIntervalMs);\n      if (typeof this.cleanupInterval.unref === 'function') {\n        this.cleanupInterval.unref();\n      }\n    }\n  }\n\n  private async cleanupExpiredJobs(): Promise<void> {\n    const noTimeoutConfigured = this.jobTimeoutMs <= 0;\n    if (noTimeoutConfigured) {\n      return;\n    }\n\n    const now = Date.now();\n    const expiredThreshold = now - this.jobTimeoutMs;\n\n    // Delete expired pending jobs\n    await this.db\n      .delete(dedupeTable)\n      .where(\n        and(\n          eq(dedupeTable.status, 'pending'),\n          lt(dedupeTable.createdAt, expiredThreshold),\n        ),\n      );\n  }\n\n  async waitFor(hash: string): Promise<T | undefined> {\n    if (this.isDestroyed) {\n      throw new Error('Dedupe store has been destroyed');\n    }\n\n    const existingPromise = this.jobPromises.get(hash);\n    if (existingPromise) {\n      return existingPromise;\n    }\n\n    const result = await this.db\n      .select()\n      .from(dedupeTable)\n      .where(eq(dedupeTable.hash, hash))\n      .limit(1);\n\n    if (result.length === 0) {\n      return undefined;\n    }\n\n    const job = result[0];\n    if (!job) {\n      return undefined;\n    }\n\n    // If job is already completed, return result immediately\n    if (job.status === 'completed') {\n      try {\n        if (job.result === '__UNDEFINED__' || job.result === '__NULL__') {\n          return undefined;\n        } else if (job.result) {\n          return JSON.parse(job.result as string);\n        }\n        return undefined;\n      } catch {\n        // If parse fails, return undefined instead of throwing\n        return undefined;\n      }\n    }\n\n    if (job.status === 'failed') {\n      return undefined;\n    }\n\n    // Job is pending - create promise for deduplication\n    const promise = new Promise<T | undefined>((resolve, reject) => {\n      this.jobResolvers.set(hash, { resolve, reject });\n\n      if (this.jobTimeoutMs > 0) {\n        setTimeout(() => {\n          const resolver = this.jobResolvers.get(hash);\n          if (resolver) {\n            this.jobResolvers.delete(hash);\n            this.jobPromises.delete(hash);\n\n            this.db\n              .update(dedupeTable)\n              .set({\n                status: 'failed',\n                error: 'Job timed out',\n                updatedAt: Date.now(),\n              })\n              .where(eq(dedupeTable.hash, hash))\n              .then(() => {\n                resolve(undefined); // Resolve with undefined for timeout\n              })\n              .catch(() => {\n                resolve(undefined); // Even if update fails, resolve with undefined\n              });\n          }\n        }, this.jobTimeoutMs);\n      }\n    });\n\n    this.jobPromises.set(hash, promise);\n    return promise;\n  }\n\n  async register(hash: string): Promise<string> {\n    if (this.isDestroyed) {\n      throw new Error('Dedupe store has been destroyed');\n    }\n\n    const existingJob = await this.db\n      .select()\n      .from(dedupeTable)\n      .where(eq(dedupeTable.hash, hash))\n      .limit(1);\n\n    if (existingJob.length > 0) {\n      const job = existingJob[0];\n      if (job && job.status === 'pending') {\n        return job.jobId;\n      }\n    }\n\n    // Create new job\n    const jobId = randomUUID();\n    const now = Date.now();\n\n    await this.db\n      .insert(dedupeTable)\n      .values({\n        hash,\n        jobId,\n        status: 'pending',\n        createdAt: now,\n        updatedAt: now,\n      })\n      .onConflictDoUpdate({\n        target: dedupeTable.hash,\n        set: {\n          jobId,\n          status: 'pending',\n          updatedAt: now,\n        },\n      });\n\n    return jobId;\n  }\n\n  async complete(hash: string, value: T | undefined): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Dedupe store has been destroyed');\n    }\n\n    // Handle different value types with proper serialization\n    let serializedResult: string;\n    if (value === undefined) {\n      serializedResult = '__UNDEFINED__';\n    } else if (value === null) {\n      serializedResult = '__NULL__';\n    } else {\n      try {\n        serializedResult = JSON.stringify(value);\n      } catch (error) {\n        throw new Error(\n          `Failed to serialize result: ${error instanceof Error ? error.message : String(error)}`,\n        );\n      }\n    }\n\n    const now = Date.now();\n\n    // Check if job already completed (prevent double completion)\n    const existingJob = await this.db\n      .select()\n      .from(dedupeTable)\n      .where(eq(dedupeTable.hash, hash))\n      .limit(1);\n\n    if (existingJob.length > 0 && existingJob[0]?.status === 'completed') {\n      // Job already completed, don't update again\n      return;\n    }\n\n    await this.db\n      .update(dedupeTable)\n      .set({\n        status: 'completed',\n        result: serializedResult,\n        updatedAt: now,\n      })\n      .where(eq(dedupeTable.hash, hash));\n\n    // Resolve any waiting promises\n    const resolver = this.jobResolvers.get(hash);\n    if (resolver) {\n      resolver.resolve(value);\n      this.jobResolvers.delete(hash);\n      this.jobPromises.delete(hash);\n    }\n  }\n\n  async fail(hash: string, error: Error): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Dedupe store has been destroyed');\n    }\n\n    const now = Date.now();\n\n    await this.db\n      .update(dedupeTable)\n      .set({\n        status: 'failed',\n        error: error.message,\n        updatedAt: now,\n      })\n      .where(eq(dedupeTable.hash, hash));\n\n    // Reject any waiting promises\n    const resolver = this.jobResolvers.get(hash);\n    if (resolver) {\n      resolver.reject(error);\n      this.jobResolvers.delete(hash);\n      this.jobPromises.delete(hash);\n    }\n  }\n\n  async isInProgress(hash: string): Promise<boolean> {\n    if (this.isDestroyed) {\n      throw new Error('Dedupe store has been destroyed');\n    }\n\n    const result = await this.db\n      .select()\n      .from(dedupeTable)\n      .where(eq(dedupeTable.hash, hash))\n      .limit(1);\n\n    if (result.length === 0) {\n      return false;\n    }\n\n    const job = result[0];\n    if (!job) {\n      return false;\n    }\n\n    const jobExpired =\n      this.jobTimeoutMs > 0 && Date.now() - job.createdAt >= this.jobTimeoutMs;\n    if (jobExpired) {\n      await this.db.delete(dedupeTable).where(eq(dedupeTable.hash, hash));\n      return false;\n    }\n\n    return job.status === 'pending';\n  }\n\n  async getResult(hash: string): Promise<T | undefined> {\n    const result = await this.db\n      .select()\n      .from(dedupeTable)\n      .where(eq(dedupeTable.hash, hash))\n      .limit(1);\n\n    if (result.length === 0) {\n      return undefined;\n    }\n\n    const job = result[0];\n    if (!job) {\n      return undefined;\n    }\n\n    const now = Date.now();\n\n    const isExpired = now - job.createdAt > this.jobTimeoutMs;\n    if (isExpired) {\n      await this.db.delete(dedupeTable).where(eq(dedupeTable.hash, hash));\n      return undefined;\n    }\n\n    if (job.status === 'completed') {\n      try {\n        if (job.result === '__UNDEFINED__') {\n          return undefined;\n        } else if (job.result === '__NULL__') {\n          return null as unknown as T;\n        } else if (job.result) {\n          return JSON.parse(job.result as string);\n        }\n        return undefined;\n      } catch {\n        return undefined;\n      }\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Get statistics about dedupe jobs\n   */\n  async getStats(): Promise<{\n    totalJobs: number;\n    pendingJobs: number;\n    completedJobs: number;\n    failedJobs: number;\n    expiredJobs: number;\n  }> {\n    const now = Date.now();\n    const expiredTime = now - this.jobTimeoutMs;\n\n    const totalResult = await this.db\n      .select({ count: count() })\n      .from(dedupeTable);\n\n    const pendingResult = await this.db\n      .select({ count: count() })\n      .from(dedupeTable)\n      .where(eq(dedupeTable.status, 'pending'));\n\n    const completedResult = await this.db\n      .select({ count: count() })\n      .from(dedupeTable)\n      .where(eq(dedupeTable.status, 'completed'));\n\n    const failedResult = await this.db\n      .select({ count: count() })\n      .from(dedupeTable)\n      .where(eq(dedupeTable.status, 'failed'));\n\n    const expiredResult = await this.db\n      .select({ count: count() })\n      .from(dedupeTable)\n      .where(lt(dedupeTable.createdAt, expiredTime));\n\n    return {\n      totalJobs: totalResult[0]?.count || 0,\n      pendingJobs: pendingResult[0]?.count || 0,\n      completedJobs: completedResult[0]?.count || 0,\n      failedJobs: failedResult[0]?.count || 0,\n      expiredJobs: expiredResult[0]?.count || 0,\n    };\n  }\n\n  /**\n   * Clean up expired jobs\n   */\n  async cleanup(): Promise<void> {\n    const now = Date.now();\n    const expiredTime = now - this.jobTimeoutMs;\n\n    await this.db\n      .delete(dedupeTable)\n      .where(lt(dedupeTable.createdAt, expiredTime));\n  }\n\n  /**\n   * Clear all jobs\n   */\n  async clear(): Promise<void> {\n    await this.db.delete(dedupeTable);\n\n    this.jobPromises.clear();\n    this.jobResolvers.clear();\n  }\n\n  /**\n   * Close the database connection\n   */\n  async close(): Promise<void> {\n    if (this.cleanupInterval) {\n      clearInterval(this.cleanupInterval);\n      this.cleanupInterval = undefined;\n    }\n\n    this.jobPromises.clear();\n    this.jobResolvers.clear();\n\n    this.isDestroyed = true;\n\n    // Only close the underlying DB if **this** store created it.\n    if (this.isConnectionManaged && typeof this.sqlite.close === 'function') {\n      this.sqlite.close();\n    }\n  }\n\n  /**\n   * Alias for close() to match test expectations\n   */\n  destroy(): void {\n    this.close();\n  }\n\n  private initializeDatabase(): void {\n    // Create tables if they don't exist\n    this.db.run(sql`\n      CREATE TABLE IF NOT EXISTS dedupe_jobs (\n        hash TEXT PRIMARY KEY,\n        job_id TEXT NOT NULL,\n        status TEXT NOT NULL,\n        result BLOB,\n        error TEXT,\n        created_at INTEGER NOT NULL,\n        updated_at INTEGER NOT NULL\n      )\n    `);\n\n    // Create index on status for efficient queries\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_dedupe_status ON dedupe_jobs(status)\n    `);\n  }\n}\n","import {\n  type RateLimitConfig,\n  type RateLimitStore,\n  DEFAULT_RATE_LIMIT,\n} from '@comic-vine/client';\nimport Database from 'better-sqlite3';\nimport { and, eq, gte, count, sql, lt } from 'drizzle-orm';\nimport { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { rateLimitTable } from './schema.js';\n\nexport interface SQLiteRateLimitStoreOptions {\n  /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */\n  database?: string | InstanceType<typeof Database>;\n  /** Global/default rate-limit config applied when a resource-specific override is not provided. */\n  defaultConfig?: RateLimitConfig;\n  /** Optional per-resource overrides. */\n  resourceConfigs?: Map<string, RateLimitConfig>;\n}\n\nexport class SQLiteRateLimitStore implements RateLimitStore {\n  private db: BetterSQLite3Database;\n  private sqlite: InstanceType<typeof Database>;\n  /** Indicates whether this store manages (and should close) the SQLite connection */\n  private readonly isConnectionManaged: boolean = false;\n  private defaultConfig: RateLimitConfig;\n  private resourceConfigs = new Map<string, RateLimitConfig>();\n  private isDestroyed = false;\n\n  constructor({\n    /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */\n    database = ':memory:',\n    /** Global/default rate-limit config applied when a resource-specific override is not provided. */\n    defaultConfig = DEFAULT_RATE_LIMIT,\n    /** Optional per-resource overrides. */\n    resourceConfigs = new Map<string, RateLimitConfig>(),\n  }: SQLiteRateLimitStoreOptions = {}) {\n    // Allow callers to pass a pre-existing connection so that all stores can\n    // operate on the same underlying DB file.\n    let sqliteInstance: InstanceType<typeof Database>;\n    let isConnectionManaged = false;\n\n    if (typeof database === 'string') {\n      sqliteInstance = new Database(database);\n      isConnectionManaged = true;\n    } else {\n      sqliteInstance = database;\n    }\n\n    this.sqlite = sqliteInstance;\n    this.isConnectionManaged = isConnectionManaged;\n    this.db = drizzle(sqliteInstance);\n    this.defaultConfig = defaultConfig;\n    this.resourceConfigs = resourceConfigs;\n\n    this.initializeDatabase();\n  }\n\n  async canProceed(resource: string): Promise<boolean> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n    const now = Date.now();\n    const windowStart = now - config.windowMs;\n\n    await this.cleanupExpiredRequests(resource, windowStart);\n\n    // Count current requests in window\n    const result = await this.db\n      .select({ count: count() })\n      .from(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          gte(rateLimitTable.timestamp, windowStart),\n        ),\n      );\n\n    const currentCount = (result[0] as { count?: number })?.count || 0;\n    return currentCount < config.limit;\n  }\n\n  async record(resource: string): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const now = Date.now();\n    await this.db.insert(rateLimitTable).values({\n      resource,\n      timestamp: now,\n    });\n  }\n\n  async getStatus(resource: string): Promise<{\n    remaining: number;\n    resetTime: Date;\n    limit: number;\n  }> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n    const now = Date.now();\n    const windowStart = now - config.windowMs;\n\n    await this.cleanupExpiredRequests(resource, windowStart);\n\n    // Count current requests in the window\n    const result = await this.db\n      .select({ count: count() })\n      .from(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          gte(rateLimitTable.timestamp, windowStart),\n        ),\n      );\n\n    const currentRequests = (result[0]?.count as number) || 0;\n    const remaining = Math.max(0, config.limit - currentRequests);\n\n    const resetTime = new Date(now + config.windowMs);\n\n    return {\n      remaining,\n      resetTime,\n      limit: config.limit,\n    };\n  }\n\n  async reset(resource: string): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n    await this.db\n      .delete(rateLimitTable)\n      .where(eq(rateLimitTable.resource, resource));\n  }\n\n  async getWaitTime(resource: string): Promise<number> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n\n    if (config.limit === 0) {\n      return config.windowMs;\n    }\n\n    const now = Date.now();\n    const windowStart = now - config.windowMs;\n\n    await this.cleanupExpiredRequests(resource, windowStart);\n\n    // Count current requests in the window\n    const countResult = await this.db\n      .select({ count: count() })\n      .from(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          gte(rateLimitTable.timestamp, windowStart),\n        ),\n      );\n\n    const currentRequests = (countResult[0]?.count as number) || 0;\n\n    if (currentRequests < config.limit) {\n      return 0;\n    }\n\n    const oldestResult = await this.db\n      .select({ timestamp: rateLimitTable.timestamp })\n      .from(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          gte(rateLimitTable.timestamp, windowStart),\n        ),\n      )\n      .orderBy(rateLimitTable.timestamp)\n      .limit(1);\n\n    if (oldestResult.length === 0) {\n      return 0;\n    }\n\n    const oldestTimestamp = oldestResult[0]?.timestamp;\n    if (oldestTimestamp === undefined) {\n      return 0;\n    }\n\n    const timeUntilOldestExpires = oldestTimestamp + config.windowMs - now;\n\n    return Math.max(0, timeUntilOldestExpires);\n  }\n\n  /**\n   * Set rate limit configuration for a specific resource\n   */\n  setResourceConfig(resource: string, config: RateLimitConfig): void {\n    this.resourceConfigs.set(resource, config);\n  }\n\n  /**\n   * Get rate limit configuration for a resource\n   */\n  getResourceConfig(resource: string): RateLimitConfig {\n    return this.resourceConfigs.get(resource) || this.defaultConfig;\n  }\n\n  /**\n   * Get statistics for all resources\n   */\n  async getStats(): Promise<{\n    totalRequests: number;\n    uniqueResources: number;\n    rateLimitedResources: Array<string>;\n  }> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const totalResult = await this.db\n      .select({ count: count() })\n      .from(rateLimitTable);\n\n    const resourcesResult = await this.db\n      .select({ resource: rateLimitTable.resource })\n      .from(rateLimitTable)\n      .groupBy(rateLimitTable.resource);\n\n    const uniqueResources = resourcesResult.length;\n    const rateLimitedResources: Array<string> = [];\n\n    for (const { resource } of resourcesResult) {\n      const canProceed = await this.canProceed(resource);\n      if (!canProceed) {\n        rateLimitedResources.push(resource);\n      }\n    }\n\n    return {\n      totalRequests: (totalResult[0]?.count as number) || 0,\n      uniqueResources,\n      rateLimitedResources,\n    };\n  }\n\n  /**\n   * Clean up all rate limit data\n   */\n  async clear(): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n    await this.db.delete(rateLimitTable);\n  }\n\n  /**\n   * Clean up expired requests for all resources\n   */\n  async cleanup(): Promise<void> {\n    const now = Date.now();\n\n    // Find all unique resources\n    const resources = await this.db\n      .select({ resource: rateLimitTable.resource })\n      .from(rateLimitTable)\n      .groupBy(rateLimitTable.resource);\n\n    for (const { resource } of resources) {\n      const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n      const windowStart = now - config.windowMs;\n      await this.cleanupExpiredRequests(resource, windowStart);\n    }\n  }\n\n  /**\n   * Close the database connection\n   */\n  async close(): Promise<void> {\n    this.isDestroyed = true;\n\n    // Close only if this instance established the connection.\n    if (this.isConnectionManaged && typeof this.sqlite.close === 'function') {\n      this.sqlite.close();\n    }\n  }\n\n  /**\n   * Alias for close() to match test expectations\n   */\n  destroy(): void {\n    this.close();\n  }\n\n  private async cleanupExpiredRequests(\n    resource: string,\n    windowStart: number,\n  ): Promise<void> {\n    await this.db\n      .delete(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          lt(rateLimitTable.timestamp, windowStart),\n        ),\n      );\n  }\n\n  private initializeDatabase(): void {\n    // Create tables if they don't exist\n    this.db.run(sql`\n      CREATE TABLE IF NOT EXISTS rate_limits (\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        resource TEXT NOT NULL,\n        timestamp INTEGER NOT NULL\n      )\n    `);\n\n    // Create index on resource for efficient lookups\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_rate_limit_resource ON rate_limits(resource)\n    `);\n\n    // Create index on timestamp for efficient cleanup\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_rate_limit_timestamp ON rate_limits(timestamp)\n    `);\n  }\n}\n","import {\n  AdaptiveCapacityCalculator,\n  type AdaptiveRateLimitStore as IAdaptiveRateLimitStore,\n  type RequestPriority,\n  type AdaptiveConfigSchema,\n  type RateLimitConfig,\n  type ActivityMetrics,\n  type DynamicCapacityResult,\n} from '@comic-vine/client';\nimport Database from 'better-sqlite3';\nimport { and, eq, count, sql, lt } from 'drizzle-orm';\nimport { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { z } from 'zod';\nimport { rateLimitTable } from './schema.js';\n\nconst DEFAULT_RATE_LIMIT: RateLimitConfig = {\n  limit: 200,\n  windowMs: 3600000, // 1 hour\n};\n\nexport interface SqliteAdaptiveRateLimitStoreOptions {\n  /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */\n  database?: string | InstanceType<typeof Database>;\n  /** Global/default rate-limit config applied when a resource-specific override is not provided. */\n  defaultConfig?: RateLimitConfig;\n  /** Optional per-resource overrides. */\n  resourceConfigs?: Map<string, RateLimitConfig>;\n  /** Adaptive configuration for priority-based rate limiting */\n  adaptiveConfig?: Partial<z.input<typeof AdaptiveConfigSchema>>;\n}\n\nexport class SqliteAdaptiveRateLimitStore implements IAdaptiveRateLimitStore {\n  private db: BetterSQLite3Database;\n  private sqlite: InstanceType<typeof Database>;\n  /** Indicates whether this store manages (and should close) the SQLite connection */\n  private readonly isConnectionManaged: boolean = false;\n  private defaultConfig: RateLimitConfig;\n  private resourceConfigs = new Map<string, RateLimitConfig>();\n  private isDestroyed = false;\n\n  // Adaptive rate limiting components\n  private capacityCalculator: AdaptiveCapacityCalculator;\n  private activityMetrics = new Map<string, ActivityMetrics>();\n  private lastCapacityUpdate = new Map<string, number>();\n  private cachedCapacity = new Map<string, DynamicCapacityResult>();\n\n  constructor({\n    database = ':memory:',\n    defaultConfig = DEFAULT_RATE_LIMIT,\n    resourceConfigs = new Map<string, RateLimitConfig>(),\n    adaptiveConfig = {},\n  }: SqliteAdaptiveRateLimitStoreOptions = {}) {\n    // Allow callers to pass a pre-existing connection so that all stores can\n    // operate on the same underlying DB file.\n    let sqliteInstance: InstanceType<typeof Database>;\n    let isConnectionManaged = false;\n\n    if (typeof database === 'string') {\n      sqliteInstance = new Database(database);\n      isConnectionManaged = true;\n    } else {\n      sqliteInstance = database;\n    }\n\n    this.sqlite = sqliteInstance;\n    this.isConnectionManaged = isConnectionManaged;\n    this.db = drizzle(sqliteInstance);\n    this.defaultConfig = defaultConfig;\n    this.resourceConfigs = resourceConfigs;\n\n    // Initialize adaptive components\n    this.capacityCalculator = new AdaptiveCapacityCalculator(adaptiveConfig);\n\n    this.initializeDatabase();\n  }\n\n  async canProceed(\n    resource: string,\n    priority: RequestPriority = 'background',\n  ): Promise<boolean> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    // Load activity metrics if needed\n    await this.ensureActivityMetrics(resource);\n    const metrics = this.getOrCreateActivityMetrics(resource);\n    const capacity = this.calculateCurrentCapacity(resource, metrics);\n\n    // Check if background requests should be paused\n    if (priority === 'background' && capacity.backgroundPaused) {\n      return false; // Hard pause for background requests\n    }\n\n    // Get current usage for each priority\n    const currentUserRequests = await this.getCurrentUsage(resource, 'user');\n    const currentBackgroundRequests = await this.getCurrentUsage(\n      resource,\n      'background',\n    );\n\n    if (priority === 'user') {\n      return currentUserRequests < capacity.userReserved;\n    } else {\n      return currentBackgroundRequests < capacity.backgroundMax;\n    }\n  }\n\n  async record(\n    resource: string,\n    priority: RequestPriority = 'background',\n  ): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const now = Date.now();\n\n    // Insert into database with priority using raw SQL to handle the additional column\n    this.db.run(sql`\n      INSERT INTO rate_limits (resource, timestamp, priority)\n      VALUES (${resource}, ${now}, ${priority})\n    `);\n\n    // Update in-memory activity metrics\n    const metrics = this.getOrCreateActivityMetrics(resource);\n\n    if (priority === 'user') {\n      metrics.recentUserRequests.push(now);\n      this.cleanupOldRequests(metrics.recentUserRequests);\n    } else {\n      metrics.recentBackgroundRequests.push(now);\n      this.cleanupOldRequests(metrics.recentBackgroundRequests);\n    }\n\n    // Update activity trend\n    metrics.userActivityTrend = this.capacityCalculator.calculateActivityTrend(\n      metrics.recentUserRequests,\n    );\n  }\n\n  async getStatus(resource: string): Promise<{\n    remaining: number;\n    resetTime: Date;\n    limit: number;\n    adaptive?: {\n      userReserved: number;\n      backgroundMax: number;\n      backgroundPaused: boolean;\n      recentUserActivity: number;\n      reason: string;\n    };\n  }> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    await this.ensureActivityMetrics(resource);\n    const metrics = this.getOrCreateActivityMetrics(resource);\n    const capacity = this.calculateCurrentCapacity(resource, metrics);\n\n    const currentUserUsage = await this.getCurrentUsage(resource, 'user');\n    const currentBackgroundUsage = await this.getCurrentUsage(\n      resource,\n      'background',\n    );\n\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n\n    return {\n      remaining:\n        capacity.userReserved -\n        currentUserUsage +\n        (capacity.backgroundMax - currentBackgroundUsage),\n      resetTime: new Date(Date.now() + config.windowMs),\n      limit: this.getResourceLimit(resource),\n      adaptive: {\n        userReserved: capacity.userReserved,\n        backgroundMax: capacity.backgroundMax,\n        backgroundPaused: capacity.backgroundPaused,\n        recentUserActivity: this.capacityCalculator.getRecentActivity(\n          metrics.recentUserRequests,\n        ),\n        reason: capacity.reason,\n      },\n    };\n  }\n\n  async reset(resource: string): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    // Clear database records\n    await this.db\n      .delete(rateLimitTable)\n      .where(eq(rateLimitTable.resource, resource));\n\n    // Clear in-memory metrics\n    this.activityMetrics.delete(resource);\n    this.cachedCapacity.delete(resource);\n    this.lastCapacityUpdate.delete(resource);\n  }\n\n  async getWaitTime(\n    resource: string,\n    priority: RequestPriority = 'background',\n  ): Promise<number> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n\n    if (config.limit === 0) {\n      return config.windowMs;\n    }\n\n    const canProceed = await this.canProceed(resource, priority);\n    if (canProceed) {\n      return 0;\n    }\n\n    // For background requests that are paused, check back in 30 seconds\n    await this.ensureActivityMetrics(resource);\n    const metrics = this.getOrCreateActivityMetrics(resource);\n    const capacity = this.calculateCurrentCapacity(resource, metrics);\n\n    if (priority === 'background' && capacity.backgroundPaused) {\n      return this.capacityCalculator.config.recalculationIntervalMs;\n    }\n\n    // Find the oldest request in the current window for this priority\n    const now = Date.now();\n    const windowStart = now - config.windowMs;\n\n    const oldestResult = this.sqlite\n      .prepare(\n        `\n      SELECT timestamp\n      FROM rate_limits\n      WHERE resource = ? AND COALESCE(priority, 'background') = ? AND timestamp >= ?\n      ORDER BY timestamp\n      LIMIT 1\n    `,\n      )\n      .get(resource, priority, windowStart) as\n      | { timestamp: number }\n      | undefined;\n\n    if (!oldestResult) {\n      return 0;\n    }\n\n    const oldestTimestamp = oldestResult.timestamp;\n    if (!oldestTimestamp) {\n      return 0;\n    }\n\n    const timeUntilOldestExpires = oldestTimestamp + config.windowMs - now;\n    return Math.max(0, timeUntilOldestExpires);\n  }\n\n  /**\n   * Set rate limit configuration for a specific resource\n   */\n  setResourceConfig(resource: string, config: RateLimitConfig): void {\n    this.resourceConfigs.set(resource, config);\n  }\n\n  /**\n   * Get rate limit configuration for a resource\n   */\n  getResourceConfig(resource: string): RateLimitConfig {\n    return this.resourceConfigs.get(resource) || this.defaultConfig;\n  }\n\n  /**\n   * Get statistics for all resources\n   */\n  async getStats(): Promise<{\n    totalRequests: number;\n    uniqueResources: number;\n    rateLimitedResources: Array<string>;\n  }> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n\n    const totalResult = await this.db\n      .select({ count: count() })\n      .from(rateLimitTable);\n\n    const resourcesResult = await this.db\n      .select({ resource: rateLimitTable.resource })\n      .from(rateLimitTable)\n      .groupBy(rateLimitTable.resource);\n\n    const uniqueResources = resourcesResult.length;\n    const rateLimitedResources: Array<string> = [];\n\n    for (const { resource } of resourcesResult) {\n      const canProceed = await this.canProceed(resource);\n      if (!canProceed) {\n        rateLimitedResources.push(resource);\n      }\n    }\n\n    return {\n      totalRequests: (totalResult[0]?.count as number) || 0,\n      uniqueResources,\n      rateLimitedResources,\n    };\n  }\n\n  /**\n   * Clean up all rate limit data\n   */\n  async clear(): Promise<void> {\n    if (this.isDestroyed) {\n      throw new Error('Rate limit store has been destroyed');\n    }\n    await this.db.delete(rateLimitTable);\n    this.activityMetrics.clear();\n    this.cachedCapacity.clear();\n    this.lastCapacityUpdate.clear();\n  }\n\n  /**\n   * Clean up expired requests for all resources\n   */\n  async cleanup(): Promise<void> {\n    const now = Date.now();\n\n    // Find all unique resources\n    const resources = await this.db\n      .select({ resource: rateLimitTable.resource })\n      .from(rateLimitTable)\n      .groupBy(rateLimitTable.resource);\n\n    for (const { resource } of resources) {\n      const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n      const windowStart = now - config.windowMs;\n      await this.cleanupExpiredRequests(resource, windowStart);\n    }\n  }\n\n  /**\n   * Close the database connection\n   */\n  async close(): Promise<void> {\n    this.isDestroyed = true;\n\n    // Close only if this instance established the connection.\n    if (this.isConnectionManaged && typeof this.sqlite.close === 'function') {\n      this.sqlite.close();\n    }\n  }\n\n  /**\n   * Alias for close() to match test expectations\n   */\n  destroy(): void {\n    this.close();\n  }\n\n  // Private helper methods for adaptive functionality\n\n  private calculateCurrentCapacity(\n    resource: string,\n    metrics: ActivityMetrics,\n  ): DynamicCapacityResult {\n    // Only recalculate based on configured interval to avoid thrashing\n    const lastUpdate = this.lastCapacityUpdate.get(resource) || 0;\n    const recalcInterval =\n      this.capacityCalculator.config.recalculationIntervalMs;\n\n    if (Date.now() - lastUpdate < recalcInterval) {\n      return (\n        this.cachedCapacity.get(resource) || this.getDefaultCapacity(resource)\n      );\n    }\n\n    const totalLimit = this.getResourceLimit(resource);\n    const capacity = this.capacityCalculator.calculateDynamicCapacity(\n      resource,\n      totalLimit,\n      metrics,\n    );\n\n    this.cachedCapacity.set(resource, capacity);\n    this.lastCapacityUpdate.set(resource, Date.now());\n\n    return capacity;\n  }\n\n  private getOrCreateActivityMetrics(resource: string): ActivityMetrics {\n    if (!this.activityMetrics.has(resource)) {\n      this.activityMetrics.set(resource, {\n        recentUserRequests: [],\n        recentBackgroundRequests: [],\n        userActivityTrend: 'none',\n      });\n    }\n    return this.activityMetrics.get(resource)!;\n  }\n\n  private async ensureActivityMetrics(resource: string): Promise<void> {\n    if (this.activityMetrics.has(resource)) {\n      return; // Already loaded\n    }\n\n    // Load recent activity from database to populate in-memory metrics\n    const now = Date.now();\n    const windowStart = now - this.capacityCalculator.config.monitoringWindowMs;\n\n    const recentRequests = this.sqlite\n      .prepare(\n        `\n      SELECT timestamp, COALESCE(priority, 'background') as priority\n      FROM rate_limits\n      WHERE resource = ? AND timestamp >= ?\n      ORDER BY timestamp\n    `,\n      )\n      .all(resource, windowStart) as Array<{\n      timestamp: number;\n      priority: string;\n    }>;\n\n    const metrics: ActivityMetrics = {\n      recentUserRequests: [],\n      recentBackgroundRequests: [],\n      userActivityTrend: 'none',\n    };\n\n    for (const request of recentRequests) {\n      if (request.priority === 'user') {\n        metrics.recentUserRequests.push(request.timestamp);\n      } else {\n        metrics.recentBackgroundRequests.push(request.timestamp);\n      }\n    }\n\n    // Calculate trend based on loaded data\n    metrics.userActivityTrend = this.capacityCalculator.calculateActivityTrend(\n      metrics.recentUserRequests,\n    );\n\n    this.activityMetrics.set(resource, metrics);\n  }\n\n  private async getCurrentUsage(\n    resource: string,\n    priority: RequestPriority,\n  ): Promise<number> {\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n    const now = Date.now();\n    const windowStart = now - config.windowMs;\n\n    await this.cleanupExpiredRequests(resource, windowStart);\n\n    // Count current requests in window for this priority using raw SQL\n    const result = this.sqlite\n      .prepare(\n        `\n      SELECT COUNT(*) as count\n      FROM rate_limits\n      WHERE resource = ? AND priority = ? AND timestamp >= ?\n    `,\n      )\n      .get(resource, priority, windowStart) as { count: number };\n\n    return result.count || 0;\n  }\n\n  private cleanupOldRequests(requests: Array<number>): void {\n    const cutoff =\n      Date.now() - this.capacityCalculator.config.monitoringWindowMs;\n    while (requests.length > 0 && requests[0]! < cutoff) {\n      requests.shift();\n    }\n  }\n\n  private getResourceLimit(resource: string): number {\n    const config = this.resourceConfigs.get(resource) || this.defaultConfig;\n    return config.limit;\n  }\n\n  private getDefaultCapacity(resource: string): DynamicCapacityResult {\n    const limit = this.getResourceLimit(resource);\n    return {\n      userReserved: Math.floor(limit * 0.3),\n      backgroundMax: Math.floor(limit * 0.7),\n      backgroundPaused: false,\n      reason: 'Default capacity allocation',\n    };\n  }\n\n  private async cleanupExpiredRequests(\n    resource: string,\n    windowStart: number,\n  ): Promise<void> {\n    await this.db\n      .delete(rateLimitTable)\n      .where(\n        and(\n          eq(rateLimitTable.resource, resource),\n          lt(rateLimitTable.timestamp, windowStart),\n        ),\n      );\n  }\n\n  private initializeDatabase(): void {\n    // Create tables if they don't exist\n    this.db.run(sql`\n      CREATE TABLE IF NOT EXISTS rate_limits (\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        resource TEXT NOT NULL,\n        timestamp INTEGER NOT NULL,\n        priority TEXT NOT NULL DEFAULT 'background'\n      )\n    `);\n\n    // Check if priority column exists, add it if not (for migration from older schema)\n    try {\n      this.db.run(sql`\n        ALTER TABLE rate_limits ADD COLUMN priority TEXT DEFAULT 'background'\n      `);\n    } catch {\n      // Column already exists, ignore error\n    }\n\n    // Create index on resource for efficient lookups\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_rate_limit_resource ON rate_limits(resource)\n    `);\n\n    // Create index on timestamp for efficient cleanup\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_rate_limit_timestamp ON rate_limits(timestamp)\n    `);\n\n    // Create composite index for priority-based queries\n    this.db.run(sql`\n      CREATE INDEX IF NOT EXISTS idx_rate_limit_resource_priority_timestamp\n      ON rate_limits(resource, priority, timestamp)\n    `);\n  }\n}\n"]}