halt-rate 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +911 -0
- package/dist/adapters/express.d.mts +21 -0
- package/dist/adapters/express.d.ts +21 -0
- package/dist/adapters/express.js +71 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/express.mjs +68 -0
- package/dist/adapters/express.mjs.map +1 -0
- package/dist/adapters/next.d.mts +21 -0
- package/dist/adapters/next.d.ts +21 -0
- package/dist/adapters/next.js +627 -0
- package/dist/adapters/next.js.map +1 -0
- package/dist/adapters/next.mjs +623 -0
- package/dist/adapters/next.mjs.map +1 -0
- package/dist/index.d.mts +83 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +782 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +773 -0
- package/dist/index.mjs.map +1 -0
- package/dist/limiter-qGH_X_KH.d.mts +128 -0
- package/dist/limiter-qGH_X_KH.d.ts +128 -0
- package/package.json +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/policy.ts","../src/core/extractors.ts","../src/algorithms/token-bucket.ts","../src/algorithms/fixed-window.ts","../src/algorithms/sliding-window.ts","../src/algorithms/leaky-bucket.ts","../src/core/limiter.ts","../src/core/decision.ts","../src/stores/memory.ts","../src/presets/index.ts"],"names":["KeyStrategy","Algorithm","ip"],"mappings":";;;;;;;AAIO,IAAK,WAAA,qBAAAA,YAAAA,KAAL;AACH,EAAAA,aAAA,IAAA,CAAA,GAAK,IAAA;AACL,EAAAA,aAAA,MAAA,CAAA,GAAO,MAAA;AACP,EAAAA,aAAA,SAAA,CAAA,GAAU,SAAA;AACV,EAAAA,aAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,aAAA,QAAA,CAAA,GAAS,QAAA;AALD,EAAA,OAAAA,YAAAA;AAAA,CAAA,EAAA,WAAA,IAAA,EAAA;AAQL,IAAK,SAAA,qBAAAC,UAAAA,KAAL;AACH,EAAAA,WAAA,cAAA,CAAA,GAAe,cAAA;AACf,EAAAA,WAAA,cAAA,CAAA,GAAe,cAAA;AACf,EAAAA,WAAA,gBAAA,CAAA,GAAiB,gBAAA;AACjB,EAAAA,WAAA,cAAA,CAAA,GAAe,cAAA;AAJP,EAAA,OAAAA,UAAAA;AAAA,CAAA,EAAA,SAAA,IAAA,EAAA;AAiCL,SAAS,gBAAgB,MAAA,EAAkC;AAC9D,EAAA,MAAM,UAAA,GAA+B;AAAA,IACjC,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,SAAA,EAAW,OAAO,SAAA,IAAa,cAAA;AAAA,IAC/B,WAAA,EAAa,OAAO,WAAA,IAAe,IAAA;AAAA,IACnC,OAAO,MAAA,CAAO,KAAA,IAAS,KAAK,KAAA,CAAM,MAAA,CAAO,QAAQ,GAAG,CAAA;AAAA,IACpD,IAAA,EAAM,OAAO,IAAA,IAAQ,CAAA;AAAA,IACrB,aAAA,EAAe,OAAO,aAAA,IAAiB,MAAA;AAAA,IACvC,YAAA,EAAc,OAAO,YAAA,IAAgB,MAAA;AAAA,IACrC,UAAA,EAAY,MAAA,CAAO,UAAA,IAAc;AAAC,GACtC;AAGA,EAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACvB,IAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,EAC5C;AAEA,EAAA,IAAI,UAAA,CAAW,UAAU,CAAA,EAAG;AACxB,IAAA,MAAM,IAAI,MAAM,yBAAyB,CAAA;AAAA,EAC7C;AAEA,EAAA,IAAI,UAAA,CAAW,QAAQ,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EAC3C;AAEA,EAAA,IAAI,UAAA,CAAW,KAAA,GAAQ,UAAA,CAAW,KAAA,EAAO;AACrC,IAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,EAC5C;AAEA,EAAA,OAAO,UAAA;AACX;;;AC7EA,IAAA,kBAAA,GAAA;AAAA,QAAA,CAAA,kBAAA,EAAA;AAAA,EAAA,kBAAA,EAAA,MAAA,kBAAA;AAAA,EAAA,aAAA,EAAA,MAAA,aAAA;AAAA,EAAA,SAAA,EAAA,MAAA,SAAA;AAAA,EAAA,WAAA,EAAA,MAAA,WAAA;AAAA,EAAA,aAAA,EAAA,MAAA,aAAA;AAAA,EAAA,aAAA,EAAA,MAAA,aAAA;AAAA,EAAA,WAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAKO,IAAM,kBAAA,uBAAyB,GAAA,CAAI;AAAA,EACtC,SAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA;AACJ,CAAC,CAAA;AAGD,IAAM,mBAAA,GAAsB;AAAA,EACxB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,4BAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA;AACJ,CAAA;AAKO,SAAS,SAAA,CAAU,OAAA,EAAc,cAAA,GAA2B,EAAC,EAAkB;AAClF,EAAA,IAAI,QAAA,GAA0B,IAAA;AAG9B,EAAA,IAAI,OAAA,CAAQ,QAAQ,aAAA,EAAe;AAE/B,IAAA,QAAA,GAAW,QAAQ,MAAA,CAAO,aAAA;AAAA,EAC9B,CAAA,MAAA,IAAW,QAAQ,EAAA,EAAI;AAEnB,IAAA,QAAA,GAAW,OAAA,CAAQ,EAAA;AAAA,EACvB,CAAA,MAAA,IAAW,OAAA,CAAQ,UAAA,EAAY,aAAA,EAAe;AAE1C,IAAA,QAAA,GAAW,QAAQ,UAAA,CAAW,aAAA;AAAA,EAClC;AAEA,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,OAAO,IAAA;AAAA,EACX;AAGA,EAAA,QAAA,GAAW,QAAA,CAAS,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAG1C,EAAA,IAAI,eAAe,MAAA,GAAS,CAAA,IAAK,cAAA,CAAe,QAAA,EAAU,cAAc,CAAA,EAAG;AACvE,IAAA,MAAM,SAAA,GAAY,gBAAgB,OAAO,CAAA;AACzC,IAAA,IAAI,SAAA,EAAW;AACX,MAAA,OAAO,SAAA;AAAA,IACX;AAAA,EACJ;AAEA,EAAA,OAAO,QAAA;AACX;AAKA,SAAS,gBAAgB,OAAA,EAA6B;AAClD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AACpC,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,iBAAiB,CAAA,IAAK,QAAQ,iBAAiB,CAAA;AAEzE,EAAA,IAAI,SAAA,EAAW;AAEX,IAAA,OAAO,UAAU,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,EAAE,IAAA,EAAK;AAAA,EACxC;AAEA,EAAA,OAAO,IAAA;AACX;AAKA,SAAS,cAAA,CAAe,IAAY,cAAA,EAAmC;AACnE,EAAA,OAAO,cAAA,CAAe,IAAA,CAAK,CAAC,KAAA,KAAU;AAClC,IAAA,IAAI,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,EAAG;AAErB,MAAA,OAAO,GAAG,UAAA,CAAW,KAAA,CAAM,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,IAC9E;AACA,IAAA,OAAO,EAAA,KAAO,KAAA;AAAA,EAClB,CAAC,CAAA;AACL;AAKO,SAAS,YAAY,EAAA,EAAqB;AAC7C,EAAA,OAAO,oBAAoB,IAAA,CAAK,CAAC,YAAY,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAC,CAAA;AACjE;AAKO,SAAS,cAAc,IAAA,EAAuB;AACjD,EAAA,OAAO,kBAAA,CAAmB,IAAI,IAAI,CAAA;AACtC;AAKO,SAAS,cAAc,OAAA,EAA6B;AAEvD,EAAA,IAAI,OAAA,CAAQ,MAAM,EAAA,EAAI;AAClB,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAChB,IAAA,OAAO,MAAA,CAAO,QAAQ,MAAM,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,IAAA;AACX;AAKO,SAAS,cAAc,OAAA,EAA6B;AACvD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AAGpC,EAAA,MAAM,MAAA,GACF,OAAA,CAAQ,WAAW,CAAA,IACnB,OAAA,CAAQ,WAAW,CAAA,IACnB,OAAA,CAAQ,eAAe,CAAA,IACvB,OAAA,CAAQ,eAAe,CAAA;AAE3B,EAAA,IAAI,MAAA,EAAQ;AAER,IAAA,IAAI,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA,EAAG;AAC9B,MAAA,OAAO,MAAA,CAAO,UAAU,CAAC,CAAA;AAAA,IAC7B;AACA,IAAA,OAAO,MAAA;AAAA,EACX;AAEA,EAAA,OAAO,IAAA;AACX;AAKO,SAAS,YAAY,OAAA,EAA6B;AAErD,EAAA,IAAI,OAAA,CAAQ,SAAS,QAAA,EAAU;AAC3B,IAAA,OAAO,QAAQ,OAAA,CAAQ,QAAA;AAAA,EAC3B;AAGA,EAAA,IAAI,QAAQ,IAAA,EAAM;AACd,IAAA,OAAO,OAAA,CAAQ,IAAA;AAAA,EACnB;AAEA,EAAA,IAAI,QAAQ,GAAA,EAAK;AACb,IAAA,IAAI;AACA,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAK,kBAAkB,CAAA;AACnD,MAAA,OAAO,GAAA,CAAI,QAAA;AAAA,IACf,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,IACnB;AAAA,EACJ;AAEA,EAAA,OAAO,IAAA;AACX;;;AC1JO,IAAM,cAAN,MAAkB;AAAA,EAKrB,WAAA,CAAY,QAAA,EAAkB,IAAA,EAAc,MAAA,EAAgB;AACxD,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,OAAO,IAAA,GAAO,MAAA;AACnB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,CACI,eACA,UAAA,EACA,IAAA,EACA,MAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EACqC;AAEhE,IAAA,MAAM,UAAU,GAAA,GAAM,UAAA;AACtB,IAAA,MAAM,YAAA,GAAe,UAAU,IAAA,CAAK,IAAA;AACpC,IAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,QAAA,EAAU,gBAAgB,YAAY,CAAA;AAGtE,IAAA,MAAM,YAAA,GAAe,KAAK,QAAA,GAAW,SAAA;AACrC,IAAA,MAAM,UAAU,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,YAAA,GAAe,KAAK,IAAI,CAAA;AAGzD,IAAA,IAAI,aAAa,IAAA,EAAM;AAEnB,MAAA,MAAM,qBAAqB,SAAA,GAAY,IAAA;AACvC,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,kBAAkB,CAAA;AAE/C,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,IAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAA,GAAO,KAAK,MAAM,CAAA;AAAA,UACzC,SAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,SAAA,EAAW,kBAAA;AAAA,QACX,aAAA,EAAe;AAAA,OACnB;AAAA,IACJ,CAAA,MAAO;AAEH,MAAA,MAAM,gBAAgB,IAAA,GAAO,SAAA;AAC7B,MAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAM,aAAA,GAAgB,IAAA,CAAK,IAAI,CAAA,GAAI,CAAA;AAE3D,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,KAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAA,GAAO,KAAK,MAAM,CAAA;AAAA,UACzC,SAAA,EAAW,CAAA;AAAA,UACX,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,SAAA;AAAA,QACA,aAAA,EAAe;AAAA;AAAA,OACnB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,CAAa,GAAA,GAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAwB;AAC5D,IAAA,OAAO;AAAA,MACH,QAAQ,IAAA,CAAK,QAAA;AAAA,MACb,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AACJ,CAAA;;;ACzEO,IAAM,cAAN,MAAkB;AAAA,EAIrB,WAAA,CAAY,OAAe,MAAA,EAAgB;AACvC,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,CACI,cACA,WAAA,EACA,IAAA,EACA,MAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EACqC;AAEhE,IAAA,MAAM,iBAAiB,GAAA,GAAM,WAAA;AAC7B,IAAA,IAAI,cAAA,IAAkB,KAAK,MAAA,EAAQ;AAE/B,MAAA,YAAA,GAAe,CAAA;AACf,MAAA,WAAA,GAAc,GAAA;AAAA,IAClB;AAGA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,WAAA,GAAc,KAAK,MAAM,CAAA;AAGpD,IAAA,IAAI,YAAA,GAAe,IAAA,IAAQ,IAAA,CAAK,KAAA,EAAO;AAEnC,MAAA,MAAM,WAAW,YAAA,GAAe,IAAA;AAChC,MAAA,MAAM,SAAA,GAAY,KAAK,KAAA,GAAQ,QAAA;AAE/B,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,IAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,SAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,QAAA;AAAA,QACA,cAAA,EAAgB;AAAA,OACpB;AAAA,IACJ,CAAA,MAAO;AAEH,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,GAAG,CAAA,GAAI,CAAA;AAE/C,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,KAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,SAAA,EAAW,CAAA;AAAA,UACX,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,QAAA,EAAU,YAAA;AAAA,QACV,cAAA,EAAgB;AAAA,OACpB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,CAAa,GAAA,GAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAwB;AAC5D,IAAA,OAAO;AAAA,MACH,KAAA,EAAO,CAAA;AAAA,MACP,WAAA,EAAa;AAAA,KACjB;AAAA,EACJ;AACJ,CAAA;;;AC3EO,IAAM,gBAAN,MAAoB;AAAA,EAMvB,WAAA,CAAY,KAAA,EAAe,MAAA,EAAgB,SAAA,GAAoB,EAAA,EAAI;AAC/D,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,aAAa,MAAA,GAAS,SAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,gBACI,OAAA,EACA,IAAA,EACA,MAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EAC2B;AAEtD,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,KAAK,UAAU,CAAA;AAGtD,IAAA,MAAM,YAAA,GAAe,gBAAgB,IAAA,CAAK,SAAA;AAC1C,IAAA,MAAM,aAAiC,EAAC;AAExC,IAAA,KAAA,MAAW,CAAC,WAAA,EAAa,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACxD,MAAA,MAAM,QAAA,GAAW,QAAA,CAAS,WAAA,EAAa,EAAE,CAAA;AACzC,MAAA,IAAI,WAAW,YAAA,EAAc;AACzB,QAAA,UAAA,CAAW,QAAQ,CAAA,GAAI,KAAA;AAAA,MAC3B;AAAA,IACJ;AAGA,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,UAAU,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,EAAK,KAAA,KAAU,GAAA,GAAM,KAAA,EAAO,CAAC,CAAA;AAGlF,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,GAAA,CAAI,CAAC,EAAA,KAAO,QAAA,CAAS,EAAA,EAAI,EAAE,CAAC,CAAA;AACtE,IAAA,MAAM,YAAA,GAAe,UAAU,MAAA,GAAS,CAAA,GAAI,KAAK,GAAA,CAAI,GAAG,SAAS,CAAA,GAAI,aAAA;AACrE,IAAA,MAAM,OAAA,GAAU,KAAK,KAAA,CAAA,CAAO,YAAA,GAAe,KAAK,SAAA,GAAY,CAAA,IAAK,KAAK,UAAU,CAAA;AAGhF,IAAA,IAAI,UAAA,GAAa,IAAA,IAAQ,IAAA,CAAK,KAAA,EAAO;AAEjC,MAAA,UAAA,CAAW,aAAa,CAAA,GAAA,CAAK,UAAA,CAAW,aAAa,KAAK,CAAA,IAAK,IAAA;AAC/D,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,IAAS,UAAA,GAAa,IAAA,CAAA;AAE7C,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,IAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,SAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA;AAAA,OACJ;AAAA,IACJ,CAAA,MAAO;AAEH,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA,GAAI,CAAA;AAEjD,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,KAAA;AAAA,UACT,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,SAAA,EAAW,CAAA;AAAA,UACX,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA;AAAA,OACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAmC;AAC/B,IAAA,OAAO,EAAC;AAAA,EACZ;AACJ,CAAA;;;AC9EO,IAAM,cAAN,MAAkB;AAAA,EAKrB,WAAA,CAAY,QAAA,EAAkB,QAAA,EAAkB,MAAA,EAAgB;AAC5D,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,CACI,cACA,QAAA,EACA,IAAA,EACA,MAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EACkC;AAE7D,IAAA,MAAM,UAAU,GAAA,GAAM,QAAA;AACtB,IAAA,MAAM,MAAA,GAAS,UAAU,IAAA,CAAK,QAAA;AAG9B,IAAA,IAAI,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,eAAe,MAAM,CAAA;AAGhD,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI,WAAW,CAAA,EAAG;AACd,MAAA,MAAM,WAAA,GAAc,WAAW,IAAA,CAAK,QAAA;AACpC,MAAA,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,WAAW,CAAA;AAAA,IAC1C,CAAA,MAAO;AACH,MAAA,OAAA,GAAU,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,IAC5B;AAGA,IAAA,IAAI,QAAA,GAAW,IAAA,IAAQ,IAAA,CAAK,QAAA,EAAU;AAElC,MAAA,QAAA,IAAY,IAAA;AACZ,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,WAAW,QAAQ,CAAA;AAErD,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,IAAA;AAAA,UACT,OAAO,IAAA,CAAK,QAAA;AAAA,UACZ,SAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,QAAA;AAAA,QACA,WAAA,EAAa;AAAA,OACjB;AAAA,IACJ,CAAA,MAAO;AAGH,MAAA,MAAM,WAAA,GAAc,QAAA,GAAW,IAAA,GAAO,IAAA,CAAK,QAAA;AAC3C,MAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAM,WAAA,GAAc,IAAA,CAAK,QAAQ,CAAA,GAAI,CAAA;AAE7D,MAAA,OAAO;AAAA,QACH,QAAA,EAAU;AAAA,UACN,OAAA,EAAS,KAAA;AAAA,UACT,OAAO,IAAA,CAAK,QAAA;AAAA,UACZ,SAAA,EAAW,CAAA;AAAA,UACX,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,QACA,QAAA;AAAA,QACA,WAAA,EAAa;AAAA,OACjB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,CAAa,GAAA,GAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAwB;AAC5D,IAAA,OAAO;AAAA,MACH,KAAA,EAAO,CAAA;AAAA,MACP,QAAA,EAAU;AAAA,KACd;AAAA,EACJ;AACJ,CAAA;;;AC1DO,IAAM,cAAN,MAAkB;AAAA,EASrB,YAAY,OAAA,EAA6B;AACrC,IAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACrB,IAAA,IAAA,CAAK,mBAAmB,OAAA,CAAQ,MAAA;AAChC,IAAA,IAAA,CAAK,cAAA,GAAiB,OAAA,CAAQ,cAAA,IAAkB,EAAC;AACjD,IAAA,IAAA,CAAK,gBAAA,GAAmB,QAAQ,gBAAA,IAAoB,IAAA;AACpD,IAAA,IAAA,CAAK,cAAA,uBAAqB,GAAA,EAAI;AAC9B,IAAA,IAAA,CAAK,aAAa,OAAA,CAAQ,UAAA;AAC1B,IAAA,IAAA,CAAK,kBAAkB,OAAA,CAAQ,eAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAA,CAAM,OAAA,EAAc,IAAA,EAAkC;AAExD,IAAA,MAAM,QAAA,GACF,OAAO,IAAA,CAAK,gBAAA,KAAqB,UAAA,GAC3B,MAAO,IAAA,CAAK,gBAAA,CAA0D,OAAO,CAAA,GAC5E,IAAA,CAAK,gBAAA;AAEhB,IAAA,MAAM,MAAA,GAAS,gBAAgB,QAAQ,CAAA;AACvC,IAAA,MAAM,WAAA,GAAc,QAAQ,MAAA,CAAO,IAAA;AAGnC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,MAAM,CAAA,EAAG;AAChC,MAAA,MAAM,IAAA,GAAiB;AAAA,QACnB,OAAA,EAAS,IAAA;AAAA,QACT,OAAO,MAAA,CAAO,KAAA;AAAA,QACd,WAAW,MAAA,CAAO,KAAA;AAAA,QAClB,OAAA,EAAS,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,GAAI,GAAA,GAAO,OAAO,MAAM;AAAA,OACzD;AACA,MAAA,IAAA,CAAK,kBAAkB,qBAAA,EAAuB,EAAE,QAAQ,MAAA,CAAO,IAAA,IAAQ,CAAC,CAAA;AACxE,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,UAAA,CAAW,OAAA,EAAS,MAAM,CAAA;AAC3C,IAAA,IAAI,CAAC,GAAA,EAAK;AACN,MAAA,MAAM,IAAA,GAAiB;AAAA,QACnB,OAAA,EAAS,IAAA;AAAA,QACT,OAAO,MAAA,CAAO,KAAA;AAAA,QACd,WAAW,MAAA,CAAO,KAAA;AAAA,QAClB,OAAA,EAAS,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,GAAI,GAAA,GAAO,OAAO,MAAM;AAAA,OACzD;AACA,MAAA,IAAA,CAAK,kBAAkB,qBAAA,EAAuB,EAAE,QAAQ,MAAA,CAAO,IAAA,IAAQ,CAAC,CAAA;AACxE,MAAA,OAAO,IAAA;AAAA,IACX;AAEA,IAAA,MAAM,UAAA,GAAa,CAAA,KAAA,EAAQ,MAAA,CAAO,IAAI,IAAI,GAAG,CAAA,CAAA;AAG7C,IAAA,IAAI,SAAA,GAAY,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,OAAO,IAAI,CAAA;AACnD,IAAA,IAAI,CAAC,SAAA,EAAW;AACZ,MAAA,IAAI,OAAO,SAAA,KAAA,cAAA,qBAAsC;AAC7C,QAAA,SAAA,GAAY,IAAI,WAAA,CAAY,MAAA,CAAO,OAAO,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAAA,MACzE,CAAA,MAAA,IAAW,OAAO,SAAA,KAAA,cAAA,qBAAsC;AACpD,QAAA,SAAA,GAAY,IAAI,WAAA,CAAY,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAAA,MAC3D,CAAA,MAAA,IAAW,OAAO,SAAA,KAAA,gBAAA,uBAAwC;AACtD,QAAA,SAAA,GAAY,IAAI,aAAA,CAAc,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAAA,MAC7D,CAAA,MAAA,IAAW,OAAO,SAAA,KAAA,cAAA,qBAAsC;AACpD,QAAA,MAAM,QAAA,GAAW,MAAA,CAAO,KAAA,GAAQ,MAAA,CAAO,MAAA;AACvC,QAAA,SAAA,GAAY,IAAI,WAAA,CAAY,MAAA,CAAO,KAAA,EAAO,QAAA,EAAU,OAAO,MAAM,CAAA;AAAA,MACrE,CAAA,MAAO;AACH,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,UAAA,EAAa,MAAA,CAAO,SAAS,CAAA,gBAAA,CAAkB,CAAA;AAAA,MACnE;AACA,MAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,IAClD;AAGA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,UAAA,EAAY,SAAA,GAAY,YAAA,EAAc,EAAE,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA,CAAO,IAAA,EAAM,GAAA,IAAO,CAAA;AAEpG,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAU,CAAA;AACvC,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,qBAAqB,WAAA,EAAa;AAClC,MAAA,IAAI,MAAA;AACJ,MAAA,IAAI,UAAA;AAEJ,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,MAAM,YAAA,GAAe,UAAU,YAAA,EAAa;AAC5C,QAAA,MAAA,GAAS,YAAA,CAAa,MAAA;AACtB,QAAA,UAAA,GAAa,YAAA,CAAa,UAAA;AAAA,MAC9B,CAAA,MAAO;AACH,QAAA,MAAA,GAAS,KAAA,CAAM,MAAA;AACf,QAAA,UAAA,GAAa,KAAA,CAAM,UAAA;AAAA,MACvB;AAEA,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,eAAA,CAAgB,MAAA,EAAQ,YAAY,WAAW,CAAA;AACxE,MAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAElB,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,GAAS,CAAA;AAC5B,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA,CAAO,SAAA,EAAW,UAAA,EAAY,MAAA,CAAO,aAAA,EAAc,EAAG,GAAG,CAAA;AAAA,IAClG,CAAA,MAAA,IAAW,qBAAqB,WAAA,EAAa;AACzC,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI,WAAA;AAEJ,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,MAAM,YAAA,GAAe,UAAU,YAAA,EAAa;AAC5C,QAAA,KAAA,GAAQ,YAAA,CAAa,KAAA;AACrB,QAAA,WAAA,GAAc,YAAA,CAAa,WAAA;AAAA,MAC/B,CAAA,MAAO;AACH,QAAA,KAAA,GAAQ,KAAA,CAAM,KAAA;AACd,QAAA,WAAA,GAAc,KAAA,CAAM,WAAA;AAAA,MACxB;AAEA,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,eAAA,CAAgB,KAAA,EAAO,aAAa,WAAW,CAAA;AACxE,MAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAElB,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,GAAS,CAAA;AAC5B,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAA,EAAY,EAAE,KAAA,EAAO,MAAA,CAAO,QAAA,EAAU,WAAA,EAAa,MAAA,CAAO,cAAA,EAAe,EAAG,GAAG,CAAA;AAAA,IAClG,CAAA,MAAA,IAAW,qBAAqB,aAAA,EAAe;AAC3C,MAAA,MAAM,OAAA,GAAU,KAAA,IAAS,SAAA,CAAU,YAAA,EAAa;AAChD,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,eAAA,CAAgB,OAAA,EAAS,WAAW,CAAA;AAC7D,MAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAElB,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,GAAS,CAAA;AAC5B,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAA,EAAY,MAAA,CAAO,YAAY,GAAG,CAAA;AAAA,IACrD,CAAA,MAAA,IAAW,qBAAqB,WAAA,EAAa;AACzC,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI,QAAA;AAEJ,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,MAAM,YAAA,GAAe,UAAU,YAAA,EAAa;AAC5C,QAAA,KAAA,GAAQ,YAAA,CAAa,KAAA;AACrB,QAAA,QAAA,GAAW,YAAA,CAAa,QAAA;AAAA,MAC5B,CAAA,MAAO;AACH,QAAA,KAAA,GAAQ,KAAA,CAAM,KAAA;AACd,QAAA,QAAA,GAAW,KAAA,CAAM,QAAA;AAAA,MACrB;AAEA,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,eAAA,CAAgB,KAAA,EAAO,UAAU,WAAW,CAAA;AACrE,MAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAElB,MAAA,MAAM,GAAA,GAAM,OAAO,MAAA,GAAS,CAAA;AAC5B,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAA,EAAY,EAAE,KAAA,EAAO,MAAA,CAAO,QAAA,EAAU,QAAA,EAAU,MAAA,CAAO,WAAA,EAAY,EAAG,GAAG,CAAA;AAAA,IAC5F,CAAA,MAAO;AACH,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,UAAA,EAAa,OAAO,SAAS,CAAA,cAAA,CAAgB,CAAA;AAAA,IACjE;AAGA,IAAA,IAAA,CAAK,eAAA,GAAkB,sBAAA,EAAwB,EAAE,MAAA,EAAQ,MAAA,CAAO,IAAA,EAAM,OAAA,EAAS,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,EAAE,EAAG,CAAC,CAAA;AAC5G,IAAA,IAAI,SAAS,OAAA,EAAS;AAClB,MAAA,IAAA,CAAK,kBAAkB,sBAAA,EAAwB,EAAE,QAAQ,MAAA,CAAO,IAAA,IAAQ,CAAC,CAAA;AAAA,IAC7E,CAAA,MAAO;AACH,MAAA,IAAA,CAAK,kBAAkB,sBAAA,EAAwB,EAAE,QAAQ,MAAA,CAAO,IAAA,IAAQ,CAAC,CAAA;AAAA,IAC7E;AAEA,IAAA,IAAA,EAAM,GAAA,IAAM;AAEZ,IAAA,OAAO,QAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAA,CAAW,SAAc,MAAA,EAA+B;AAE5D,IAAA,IAAI,OAAO,YAAA,EAAc;AACrB,MAAA,OAAO,MAAA,CAAO,aAAa,OAAO,CAAA;AAAA,IACtC;AAGA,IAAA,IAAI,OAAO,WAAA,KAAA,IAAA,WAAgC;AACvC,MAAA,OAAO,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,cAAc,CAAA;AAAA,IACjD;AAEA,IAAA,IAAI,OAAO,WAAA,KAAA,MAAA,aAAkC;AACzC,MAAA,OAAO,cAAc,OAAO,CAAA;AAAA,IAChC;AAEA,IAAA,IAAI,OAAO,WAAA,KAAA,SAAA,gBAAqC;AAC5C,MAAA,OAAO,cAAc,OAAO,CAAA;AAAA,IAChC;AAEA,IAAA,IAAI,OAAO,WAAA,KAAA,WAAA,kBAAuC;AAE9C,MAAA,MAAM,IAAA,GAAO,cAAc,OAAO,CAAA;AAClC,MAAA,MAAM,MAAA,GAAS,cAAc,OAAO,CAAA;AACpC,MAAA,MAAM,EAAA,GAAK,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,cAAc,CAAA;AAEjD,MAAA,IAAI,QAAQ,EAAA,EAAI;AACZ,QAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA;AAAA,MACxB,CAAA,MAAA,IAAW,UAAU,EAAA,EAAI;AACrB,QAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA;AAAA,MAC1B,WAAW,IAAA,EAAM;AACb,QAAA,OAAO,IAAA;AAAA,MACX,WAAW,MAAA,EAAQ;AACf,QAAA,OAAO,MAAA;AAAA,MACX,CAAA,MAAO;AACH,QAAA,OAAO,EAAA;AAAA,MACX;AAAA,IACJ;AAEA,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKQ,QAAA,CAAS,SAAc,MAAA,EAAyB;AAEpD,IAAA,MAAM,IAAA,GAAO,YAAY,OAAO,CAAA;AAChC,IAAA,IAAI,IAAA,IAAQ,aAAA,CAAc,IAAI,CAAA,EAAG;AAC7B,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,SAAS,MAAA,CAAO,UAAA,IAAc,EAAC,EAAG,QAAA,CAAS,IAAI,CAAA,EAAG;AAClD,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,KAAK,gBAAA,EAAkB;AACvB,MAAA,MAAMC,GAAAA,GAAK,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,cAAc,CAAA;AACjD,MAAA,IAAIA,GAAAA,IAAM,WAAA,CAAYA,GAAE,CAAA,EAAG;AACvB,QAAA,OAAO,IAAA;AAAA,MACX;AAAA,IACJ;AAGA,IAAA,MAAM,EAAA,GAAK,SAAA,CAAU,OAAA,EAAS,IAAA,CAAK,cAAc,CAAA;AACjD,IAAA,IAAI,OAAO,MAAA,CAAO,UAAA,IAAc,EAAC,EAAG,QAAA,CAAS,EAAE,CAAA,EAAG;AAC9C,MAAA,OAAO,IAAA;AAAA,IACX;AAEA,IAAA,OAAO,KAAA;AAAA,EACX;AACJ;;;AC9PO,SAAS,UAAU,QAAA,EAA4C;AAClE,EAAA,MAAM,OAAA,GAAkC;AAAA,IACpC,iBAAA,EAAmB,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA;AAAA,IACxC,uBAAuB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAG,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IAC7D,iBAAA,EAAmB,MAAA,CAAO,QAAA,CAAS,OAAO;AAAA,GAC9C;AAEA,EAAA,IAAI,CAAC,QAAA,CAAS,OAAA,IAAW,QAAA,CAAS,eAAe,MAAA,EAAW;AACxD,IAAA,OAAA,CAAQ,aAAa,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA;AAAA,EACvD;AAEA,EAAA,OAAO,OAAA;AACX;;;AChBO,IAAM,gBAAN,MAAqC;AAAA,EAArC,WAAA,GAAA;AACH,IAAA,IAAA,CAAQ,IAAA,uBAAoC,GAAA,EAAI;AAAA,EAAA;AAAA,EAEhD,IAAI,GAAA,EAAkB;AAClB,IAAA,IAAA,CAAK,eAAe,GAAG,CAAA;AACvB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,OAAO,OAAO,KAAA,IAAS,IAAA;AAAA,EAC3B;AAAA,EAEA,GAAA,CAAI,GAAA,EAAa,KAAA,EAAY,GAAA,EAAoB;AAC7C,IAAA,MAAM,KAAA,GAAoB,EAAE,KAAA,EAAM;AAElC,IAAA,IAAI,QAAQ,MAAA,EAAW;AACnB,MAAA,KAAA,CAAM,MAAA,GAAS,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA,GAAM,GAAA;AAAA,IACtC;AAEA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC5B;AAAA,EAEA,SAAA,CAAU,GAAA,EAAa,KAAA,GAAgB,CAAA,EAAG,GAAA,EAAsB;AAC5D,IAAA,IAAA,CAAK,eAAe,GAAG,CAAA;AACvB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,MAAM,UAAU,OAAO,KAAA,EAAO,KAAA,KAAU,QAAA,GAAW,MAAM,KAAA,GAAQ,CAAA;AACjE,IAAA,MAAM,WAAW,OAAA,GAAU,KAAA;AAE3B,IAAA,MAAM,QAAA,GAAuB,EAAE,KAAA,EAAO,QAAA,EAAS;AAG/C,IAAA,IAAI,CAAC,KAAA,IAAS,GAAA,KAAQ,MAAA,EAAW;AAC7B,MAAA,QAAA,CAAS,MAAA,GAAS,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA,GAAM,GAAA;AAAA,IACzC,CAAA,MAAA,IAAW,OAAO,MAAA,EAAQ;AACtB,MAAA,QAAA,CAAS,SAAS,KAAA,CAAM,MAAA;AAAA,IAC5B;AAEA,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,QAAQ,CAAA;AAC3B,IAAA,OAAO,QAAA;AAAA,EACX;AAAA,EAEA,OAAO,GAAA,EAAmB;AACtB,IAAA,IAAA,CAAK,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,EACxB;AAAA,EAEQ,eAAe,GAAA,EAAmB;AACtC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,IAAI,OAAO,MAAA,IAAU,IAAA,CAAK,GAAA,EAAI,IAAK,MAAM,MAAA,EAAQ;AAC7C,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,IACxB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAA,GAA4B;AACxB,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,KAAA,GAAQ,CAAA;AAEZ,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,IAAA,CAAK,IAAA,CAAK,SAAQ,EAAG;AAC5C,MAAA,IAAI,KAAA,CAAM,MAAA,IAAU,GAAA,IAAO,KAAA,CAAM,MAAA,EAAQ;AACrC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAO,GAAG,CAAA;AACpB,QAAA,KAAA,EAAA;AAAA,MACJ;AAAA,IACJ;AAEA,IAAA,OAAO,KAAA;AAAA,EACX;AACJ;;;ACjFA,IAAA,eAAA,GAAA;AAAA,QAAA,CAAA,eAAA,EAAA;AAAA,EAAA,cAAA,EAAA,MAAA,cAAA;AAAA,EAAA,aAAA,EAAA,MAAA,aAAA;AAAA,EAAA,YAAA,EAAA,MAAA,YAAA;AAAA,EAAA,aAAA,EAAA,MAAA,aAAA;AAAA,EAAA,eAAA,EAAA,MAAA,eAAA;AAAA,EAAA,SAAA,EAAA,MAAA,SAAA;AAAA,EAAA,QAAA,EAAA,MAAA,QAAA;AAAA,EAAA,YAAA,EAAA,MAAA,YAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,UAAA,EAAA,MAAA,UAAA;AAAA,EAAA,aAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAOO,IAAM,UAAA,GAAqB;AAAA,EAC9B,IAAA,EAAM,YAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,EAAA;AAAA;AAAA,EACR,KAAA,EAAO,GAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,IAAA;AACJ,CAAA;AAGO,IAAM,cAAA,GAAyB;AAAA,EAClC,IAAA,EAAM,gBAAA;AAAA,EACN,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,EAAA;AAAA;AAAA,EACR,KAAA,EAAO,EAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,IAAA;AAAA,EACA,aAAA,EAAe;AAAA;AACnB,CAAA;AAGO,IAAM,aAAA,GAAwB;AAAA,EACjC,IAAA,EAAM,eAAA;AAAA,EACN,KAAA,EAAO,EAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,EAAA;AAAA,EACP,IAAA,EAAM,EAAA;AAAA;AAAA,EACN,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAGO,IAAM,UAAA,GAAqB;AAAA,EAC9B,IAAA,EAAM,YAAA;AAAA,EACN,KAAA,EAAO,EAAA;AAAA,EACP,MAAA,EAAQ,EAAA;AAAA;AAAA,EACR,KAAA,EAAO,EAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,SAAA;AACJ,CAAA;AAGO,IAAM,YAAA,GAAuB;AAAA,EAChC,IAAA,EAAM,cAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,EAAA;AAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,IAAA;AACJ,CAAA;AAGO,IAAM,SAAA,GAAoB;AAAA,EAC7B,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,GAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAEO,IAAM,YAAA,GAAuB;AAAA,EAChC,IAAA,EAAM,cAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,GAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAEO,IAAM,QAAA,GAAmB;AAAA,EAC5B,IAAA,EAAM,UAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAEO,IAAM,aAAA,GAAwB;AAAA,EACjC,IAAA,EAAM,eAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,GAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAEO,IAAM,eAAA,GAA0B;AAAA,EACnC,IAAA,EAAM,iBAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,MAAA,EAAQ,IAAA;AAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAA,cAAA;AAAA,EACA,WAAA,EAAA,MAAA;AACJ,CAAA;AAGO,IAAM,UAAA,GAAqC;AAAA,EAC9C,IAAA,EAAM,SAAA;AAAA,EACN,OAAA,EAAS,YAAA;AAAA,EACT,GAAA,EAAK,QAAA;AAAA,EACL,QAAA,EAAU,aAAA;AAAA,EACV,UAAA,EAAY;AAChB,CAAA;AAQO,SAAS,cAAc,QAAA,EAA0B;AACpD,EAAA,MAAM,UAAA,GAAa,SAAS,WAAA,EAAY;AACxC,EAAA,IAAI,EAAE,cAAc,UAAA,CAAA,EAAa;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACN,CAAA,cAAA,EAAiB,QAAQ,CAAA,eAAA,EAAkB,MAAA,CAAO,KAAK,UAAU,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACjF;AAAA,EACJ;AACA,EAAA,OAAO,WAAW,UAAU,CAAA;AAChC","file":"index.mjs","sourcesContent":["/**\n * Policy model for rate limiting configuration.\n */\n\nexport enum KeyStrategy {\n IP = 'ip',\n USER = 'user',\n API_KEY = 'api_key',\n COMPOSITE = 'composite',\n CUSTOM = 'custom',\n}\n\nexport enum Algorithm {\n TOKEN_BUCKET = 'token_bucket',\n FIXED_WINDOW = 'fixed_window',\n SLIDING_WINDOW = 'sliding_window',\n LEAKY_BUCKET = 'leaky_bucket',\n}\n\nexport interface Policy {\n /** Human-readable policy name */\n name: string;\n /** Maximum number of requests allowed */\n limit: number;\n /** Time window in seconds */\n window: number;\n /** Rate limiting algorithm to use */\n algorithm?: Algorithm;\n /** Strategy for extracting the rate limit key */\n keyStrategy?: KeyStrategy;\n /** Maximum burst size (for token bucket) */\n burst?: number;\n /** Cost per request (default: 1) */\n cost?: number;\n /** Duration to block after limit exceeded (seconds) */\n blockDuration?: number;\n /** Custom function to extract key from request */\n keyExtractor?: (request: any) => string | null;\n /** List of paths or IPs to exempt from rate limiting */\n exemptions?: string[];\n}\n\n/**\n * Validate and normalize policy configuration.\n */\nexport function normalizePolicy(policy: Policy): Required<Policy> {\n const normalized: Required<Policy> = {\n name: policy.name,\n limit: policy.limit,\n window: policy.window,\n algorithm: policy.algorithm ?? Algorithm.TOKEN_BUCKET,\n keyStrategy: policy.keyStrategy ?? KeyStrategy.IP,\n burst: policy.burst ?? Math.floor(policy.limit * 1.2),\n cost: policy.cost ?? 1,\n blockDuration: policy.blockDuration ?? undefined,\n keyExtractor: policy.keyExtractor ?? undefined,\n exemptions: policy.exemptions ?? [],\n } as Required<Policy>;\n\n // Validation\n if (normalized.limit <= 0) {\n throw new Error('limit must be positive');\n }\n\n if (normalized.window <= 0) {\n throw new Error('window must be positive');\n }\n\n if (normalized.cost <= 0) {\n throw new Error('cost must be positive');\n }\n\n if (normalized.burst < normalized.limit) {\n throw new Error('burst must be >= limit');\n }\n\n return normalized;\n}\n","/**\n * Utility functions for extracting rate limit keys from requests.\n */\n\n// Default health check paths\nexport const HEALTH_CHECK_PATHS = new Set([\n '/health',\n '/ping',\n '/ready',\n '/healthz',\n '/livez',\n]);\n\n// Private IP ranges (CIDR notation)\nconst PRIVATE_IP_PATTERNS = [\n /^127\\./,\n /^10\\./,\n /^172\\.(1[6-9]|2\\d|3[01])\\./,\n /^192\\.168\\./,\n /^::1$/,\n /^fc00:/,\n];\n\n/**\n * Extract client IP from request, respecting X-Forwarded-For if from trusted proxy.\n */\nexport function extractIp(request: any, trustedProxies: string[] = []): string | null {\n let clientIp: string | null = null;\n\n // Try different request object patterns\n if (request.socket?.remoteAddress) {\n // Node.js/Express\n clientIp = request.socket.remoteAddress;\n } else if (request.ip) {\n // Express with trust proxy\n clientIp = request.ip;\n } else if (request.connection?.remoteAddress) {\n // Older Node.js\n clientIp = request.connection.remoteAddress;\n }\n\n if (!clientIp) {\n return null;\n }\n\n // Clean IPv6-mapped IPv4 addresses\n clientIp = clientIp.replace(/^::ffff:/, '');\n\n // Check if we should trust X-Forwarded-For\n if (trustedProxies.length > 0 && isTrustedProxy(clientIp, trustedProxies)) {\n const forwarded = getForwardedFor(request);\n if (forwarded) {\n return forwarded;\n }\n }\n\n return clientIp;\n}\n\n/**\n * Extract first IP from X-Forwarded-For header.\n */\nfunction getForwardedFor(request: any): string | null {\n const headers = request.headers || {};\n const forwarded = headers['x-forwarded-for'] || headers['X-Forwarded-For'];\n\n if (forwarded) {\n // Take the first IP (client IP)\n return forwarded.split(',')[0].trim();\n }\n\n return null;\n}\n\n/**\n * Check if IP is in trusted proxy list.\n */\nfunction isTrustedProxy(ip: string, trustedProxies: string[]): boolean {\n return trustedProxies.some((proxy) => {\n if (proxy.includes('/')) {\n // CIDR notation - simplified check\n return ip.startsWith(proxy.split('/')[0].split('.').slice(0, -1).join('.'));\n }\n return ip === proxy;\n });\n}\n\n/**\n * Check if IP is in private range.\n */\nexport function isPrivateIp(ip: string): boolean {\n return PRIVATE_IP_PATTERNS.some((pattern) => pattern.test(ip));\n}\n\n/**\n * Check if path is a health check endpoint.\n */\nexport function isHealthCheck(path: string): boolean {\n return HEALTH_CHECK_PATHS.has(path);\n}\n\n/**\n * Extract user ID from request.\n */\nexport function extractUserId(request: any): string | null {\n // Try common patterns\n if (request.user?.id) {\n return String(request.user.id);\n }\n\n if (request.userId) {\n return String(request.userId);\n }\n\n return null;\n}\n\n/**\n * Extract API key from request headers.\n */\nexport function extractApiKey(request: any): string | null {\n const headers = request.headers || {};\n\n // Try common header names\n const apiKey =\n headers['x-api-key'] ||\n headers['X-API-Key'] ||\n headers['authorization'] ||\n headers['Authorization'];\n\n if (apiKey) {\n // Handle Bearer tokens\n if (apiKey.startsWith('Bearer ')) {\n return apiKey.substring(7);\n }\n return apiKey;\n }\n\n return null;\n}\n\n/**\n * Extract path from request.\n */\nexport function extractPath(request: any): string | null {\n // Next.js\n if (request.nextUrl?.pathname) {\n return request.nextUrl.pathname;\n }\n\n // Express\n if (request.path) {\n return request.path;\n }\n\n if (request.url) {\n try {\n const url = new URL(request.url, 'http://localhost');\n return url.pathname;\n } catch {\n return request.url;\n }\n }\n\n return null;\n}\n","/**\n * Token bucket rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface TokenBucketState {\n tokens: number;\n lastRefill: number;\n}\n\nexport class TokenBucket {\n private capacity: number;\n private rate: number;\n private window: number;\n\n constructor(capacity: number, rate: number, window: number) {\n this.capacity = capacity;\n this.rate = rate / window; // tokens per second\n this.window = window;\n }\n\n /**\n * Check if request is allowed and consume tokens.\n */\n checkAndConsume(\n currentTokens: number,\n lastRefill: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newTokens: number; newLastRefill: number } {\n // Refill tokens based on elapsed time\n const elapsed = now - lastRefill;\n const refillAmount = elapsed * this.rate;\n const newTokens = Math.min(this.capacity, currentTokens + refillAmount);\n\n // Calculate reset time (when bucket will be full)\n const tokensNeeded = this.capacity - newTokens;\n const resetAt = Math.floor(now + tokensNeeded / this.rate);\n\n // Check if we have enough tokens\n if (newTokens >= cost) {\n // Consume tokens\n const tokensAfterConsume = newTokens - cost;\n const remaining = Math.floor(tokensAfterConsume);\n\n return {\n decision: {\n allowed: true,\n limit: Math.floor(this.rate * this.window),\n remaining,\n resetAt,\n },\n newTokens: tokensAfterConsume,\n newLastRefill: now,\n };\n } else {\n // Not enough tokens\n const tokensDeficit = cost - newTokens;\n const retryAfter = Math.floor(tokensDeficit / this.rate) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: Math.floor(this.rate * this.window),\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newTokens,\n newLastRefill: lastRefill, // Don't update last_refill on rejection\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): TokenBucketState {\n return {\n tokens: this.capacity,\n lastRefill: now,\n };\n }\n}\n","/**\n * Fixed window rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface FixedWindowState {\n count: number;\n windowStart: number;\n}\n\nexport class FixedWindow {\n private limit: number;\n private window: number;\n\n constructor(limit: number, window: number) {\n this.limit = limit;\n this.window = window;\n }\n\n /**\n * Check if request is allowed and increment counter.\n */\n checkAndConsume(\n currentCount: number,\n windowStart: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newCount: number; newWindowStart: number } {\n // Check if we're in a new window\n const timeSinceStart = now - windowStart;\n if (timeSinceStart >= this.window) {\n // New window - reset counter\n currentCount = 0;\n windowStart = now;\n }\n\n // Calculate reset time (end of current window)\n const resetAt = Math.floor(windowStart + this.window);\n\n // Check if we have capacity\n if (currentCount + cost <= this.limit) {\n // Allow request\n const newCount = currentCount + cost;\n const remaining = this.limit - newCount;\n\n return {\n decision: {\n allowed: true,\n limit: this.limit,\n remaining,\n resetAt,\n },\n newCount,\n newWindowStart: windowStart,\n };\n } else {\n // Block request\n const retryAfter = Math.floor(resetAt - now) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.limit,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newCount: currentCount,\n newWindowStart: windowStart,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): FixedWindowState {\n return {\n count: 0,\n windowStart: now,\n };\n }\n}\n","/**\n * Sliding window rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport type SlidingWindowState = Record<number, number>;\n\nexport class SlidingWindow {\n private limit: number;\n private window: number;\n private precision: number;\n private bucketSize: number;\n\n constructor(limit: number, window: number, precision: number = 10) {\n this.limit = limit;\n this.window = window;\n this.precision = precision;\n this.bucketSize = window / precision;\n }\n\n /**\n * Check if request is allowed and update buckets.\n */\n checkAndConsume(\n buckets: SlidingWindowState,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newBuckets: SlidingWindowState } {\n // Calculate current bucket\n const currentBucket = Math.floor(now / this.bucketSize);\n\n // Remove expired buckets (older than window)\n const cutoffBucket = currentBucket - this.precision;\n const newBuckets: SlidingWindowState = {};\n\n for (const [bucketIdStr, count] of Object.entries(buckets)) {\n const bucketId = parseInt(bucketIdStr, 10);\n if (bucketId > cutoffBucket) {\n newBuckets[bucketId] = count;\n }\n }\n\n // Count requests in sliding window\n const totalCount = Object.values(newBuckets).reduce((sum, count) => sum + count, 0);\n\n // Calculate reset time (when oldest bucket expires)\n const bucketIds = Object.keys(newBuckets).map((id) => parseInt(id, 10));\n const oldestBucket = bucketIds.length > 0 ? Math.min(...bucketIds) : currentBucket;\n const resetAt = Math.floor((oldestBucket + this.precision + 1) * this.bucketSize);\n\n // Check if we have capacity\n if (totalCount + cost <= this.limit) {\n // Allow request\n newBuckets[currentBucket] = (newBuckets[currentBucket] || 0) + cost;\n const remaining = this.limit - (totalCount + cost);\n\n return {\n decision: {\n allowed: true,\n limit: this.limit,\n remaining,\n resetAt,\n },\n newBuckets,\n };\n } else {\n // Block request\n const retryAfter = Math.floor(this.bucketSize) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.limit,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newBuckets,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(): SlidingWindowState {\n return {};\n }\n}\n","/**\n * Leaky bucket rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface LeakyBucketState {\n level: number;\n lastLeak: number;\n}\n\nexport class LeakyBucket {\n private capacity: number;\n private leakRate: number;\n private window: number;\n\n constructor(capacity: number, leakRate: number, window: number) {\n this.capacity = capacity;\n this.leakRate = leakRate; // requests per second\n this.window = window;\n }\n\n /**\n * Check if request is allowed and update bucket level.\n */\n checkAndConsume(\n currentLevel: number,\n lastLeak: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newLevel: number; newLastLeak: number } {\n // Calculate how much has leaked since last check\n const elapsed = now - lastLeak;\n const leaked = elapsed * this.leakRate;\n\n // Update bucket level (can't go below 0)\n let newLevel = Math.max(0, currentLevel - leaked);\n\n // Calculate when bucket will be empty\n let resetAt: number;\n if (newLevel > 0) {\n const timeToEmpty = newLevel / this.leakRate;\n resetAt = Math.floor(now + timeToEmpty);\n } else {\n resetAt = Math.floor(now);\n }\n\n // Check if we have capacity\n if (newLevel + cost <= this.capacity) {\n // Allow request - add to bucket\n newLevel += cost;\n const remaining = Math.floor(this.capacity - newLevel);\n\n return {\n decision: {\n allowed: true,\n limit: this.capacity,\n remaining,\n resetAt,\n },\n newLevel,\n newLastLeak: now,\n };\n } else {\n // Block request - bucket is full\n // Calculate when there will be enough capacity\n const spaceNeeded = newLevel + cost - this.capacity;\n const retryAfter = Math.floor(spaceNeeded / this.leakRate) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.capacity,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newLevel,\n newLastLeak: now,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): LeakyBucketState {\n return {\n level: 0,\n lastLeak: now,\n };\n }\n}\n","/**\n * Main rate limiter implementation.\n */\n\nimport { Decision } from './decision';\nimport { Policy, KeyStrategy, Algorithm, normalizePolicy } from './policy';\nimport {\n extractIp,\n extractUserId,\n extractApiKey,\n extractPath,\n isHealthCheck,\n isPrivateIp,\n} from './extractors';\nimport { TokenBucket } from '../algorithms/token-bucket';\nimport { FixedWindow } from '../algorithms/fixed-window';\nimport { SlidingWindow } from '../algorithms/sliding-window';\nimport { LeakyBucket } from '../algorithms/leaky-bucket';\nimport { Store } from '../stores/memory';\n\ntype AlgorithmInstance = TokenBucket | FixedWindow | SlidingWindow | LeakyBucket;\n\nexport interface RateLimiterOptions {\n store: Store;\n /** Either a static policy or a resolver returning a policy per-request */\n policy: Policy | ((request: any) => Policy | Promise<Policy>);\n trustedProxies?: string[];\n exemptPrivateIps?: boolean;\n /** Optional OpenTelemetry-like tracer (object with startSpan) */\n otelTracer?: any;\n /** Optional metrics recorder: (name, tags?, value?) => void */\n metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n}\n\nexport class RateLimiter {\n private store: Store;\n private policyOrResolver: Policy | ((request: any) => Policy | Promise<Policy>);\n private trustedProxies: string[];\n private exemptPrivateIps: boolean;\n private algorithmCache: Map<string, AlgorithmInstance>;\n private otelTracer?: any;\n private metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n\n constructor(options: RateLimiterOptions) {\n this.store = options.store;\n this.policyOrResolver = options.policy;\n this.trustedProxies = options.trustedProxies ?? [];\n this.exemptPrivateIps = options.exemptPrivateIps ?? true;\n this.algorithmCache = new Map();\n this.otelTracer = options.otelTracer;\n this.metricsRecorder = options.metricsRecorder;\n }\n\n /**\n * Check if request is allowed under rate limit.\n */\n /**\n * Check if request is allowed under rate limit.\n * This method is async because policy resolution may be async (e.g. DB lookup).\n */\n async check(request: any, cost?: number): Promise<Decision> {\n // Resolve policy (static or per-request)\n const resolved =\n typeof this.policyOrResolver === 'function'\n ? await (this.policyOrResolver as (r: any) => Policy | Promise<Policy>)(request)\n : (this.policyOrResolver as Policy);\n\n const policy = normalizePolicy(resolved);\n const requestCost = cost ?? policy.cost;\n\n // Quick exemptions check (policy-aware)\n if (this.isExempt(request, policy)) {\n const resp: Decision = {\n allowed: true,\n limit: policy.limit,\n remaining: policy.limit,\n resetAt: Math.floor(Date.now() / 1000 + policy.window),\n };\n this.metricsRecorder?.('halt.request.exempt', { policy: policy.name }, 1);\n return resp;\n }\n\n // Extract key\n const key = this.extractKey(request, policy);\n if (!key) {\n const resp: Decision = {\n allowed: true,\n limit: policy.limit,\n remaining: policy.limit,\n resetAt: Math.floor(Date.now() / 1000 + policy.window),\n };\n this.metricsRecorder?.('halt.request.no_key', { policy: policy.name }, 1);\n return resp;\n }\n\n const storageKey = `halt:${policy.name}:${key}`;\n\n // Get or create algorithm instance for this policy\n let algorithm = this.algorithmCache.get(policy.name);\n if (!algorithm) {\n if (policy.algorithm === Algorithm.TOKEN_BUCKET) {\n algorithm = new TokenBucket(policy.burst, policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.FIXED_WINDOW) {\n algorithm = new FixedWindow(policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.SLIDING_WINDOW) {\n algorithm = new SlidingWindow(policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.LEAKY_BUCKET) {\n const leakRate = policy.limit / policy.window;\n algorithm = new LeakyBucket(policy.burst, leakRate, policy.window);\n } else {\n throw new Error(`Algorithm ${policy.algorithm} not implemented`);\n }\n this.algorithmCache.set(policy.name, algorithm);\n }\n\n // Instrumentation: start a span if tracer available\n const span = this.otelTracer?.startSpan?.('halt.check', { attributes: { policy: policy.name, key } });\n\n const state = this.store.get(storageKey);\n let decision: Decision;\n\n if (algorithm instanceof TokenBucket) {\n let tokens: number;\n let lastRefill: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n tokens = initialState.tokens;\n lastRefill = initialState.lastRefill;\n } else {\n tokens = state.tokens;\n lastRefill = state.lastRefill;\n }\n\n const result = algorithm.checkAndConsume(tokens, lastRefill, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { tokens: result.newTokens, lastRefill: result.newLastRefill }, ttl);\n } else if (algorithm instanceof FixedWindow) {\n let count: number;\n let windowStart: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n count = initialState.count;\n windowStart = initialState.windowStart;\n } else {\n count = state.count;\n windowStart = state.windowStart;\n }\n\n const result = algorithm.checkAndConsume(count, windowStart, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { count: result.newCount, windowStart: result.newWindowStart }, ttl);\n } else if (algorithm instanceof SlidingWindow) {\n const buckets = state || algorithm.initialState();\n const result = algorithm.checkAndConsume(buckets, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, result.newBuckets, ttl);\n } else if (algorithm instanceof LeakyBucket) {\n let level: number;\n let lastLeak: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n level = initialState.level;\n lastLeak = initialState.lastLeak;\n } else {\n level = state.level;\n lastLeak = state.lastLeak;\n }\n\n const result = algorithm.checkAndConsume(level, lastLeak, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { level: result.newLevel, lastLeak: result.newLastLeak }, ttl);\n } else {\n throw new Error(`Algorithm ${typeof algorithm} not supported`);\n }\n\n // Metrics and telemetry\n this.metricsRecorder?.('halt.request.checked', { policy: policy.name, allowed: String(decision.allowed) }, 1);\n if (decision.allowed) {\n this.metricsRecorder?.('halt.request.allowed', { policy: policy.name }, 1);\n } else {\n this.metricsRecorder?.('halt.request.blocked', { policy: policy.name }, 1);\n }\n\n span?.end?.();\n\n return decision;\n }\n\n /**\n * Extract rate limit key from request based on policy strategy.\n */\n private extractKey(request: any, policy: Policy): string | null {\n // Use custom extractor if provided\n if (policy.keyExtractor) {\n return policy.keyExtractor(request);\n }\n\n // Use built-in strategies\n if (policy.keyStrategy === KeyStrategy.IP) {\n return extractIp(request, this.trustedProxies);\n }\n\n if (policy.keyStrategy === KeyStrategy.USER) {\n return extractUserId(request);\n }\n\n if (policy.keyStrategy === KeyStrategy.API_KEY) {\n return extractApiKey(request);\n }\n\n if (policy.keyStrategy === KeyStrategy.COMPOSITE) {\n // Composite: user:ip or api_key:ip\n const user = extractUserId(request);\n const apiKey = extractApiKey(request);\n const ip = extractIp(request, this.trustedProxies);\n\n if (user && ip) {\n return `${user}:${ip}`;\n } else if (apiKey && ip) {\n return `${apiKey}:${ip}`;\n } else if (user) {\n return user;\n } else if (apiKey) {\n return apiKey;\n } else {\n return ip;\n }\n }\n\n return null;\n }\n\n /**\n * Check if request is exempt from rate limiting.\n */\n private isExempt(request: any, policy: Policy): boolean {\n // Check health check paths\n const path = extractPath(request);\n if (path && isHealthCheck(path)) {\n return true;\n }\n\n // Check custom exemptions\n if (path && (policy.exemptions ?? []).includes(path)) {\n return true;\n }\n\n // Check private IPs\n if (this.exemptPrivateIps) {\n const ip = extractIp(request, this.trustedProxies);\n if (ip && isPrivateIp(ip)) {\n return true;\n }\n }\n\n // Check IP exemptions\n const ip = extractIp(request, this.trustedProxies);\n if (ip && (policy.exemptions ?? []).includes(ip)) {\n return true;\n }\n\n return false;\n }\n}\n","/**\n * Decision model for rate limiting results.\n */\n\nexport interface Decision {\n /** Whether the request is allowed */\n allowed: boolean;\n /** Maximum number of requests allowed in the window */\n limit: number;\n /** Number of requests remaining in the current window */\n remaining: number;\n /** Unix timestamp when the limit resets */\n resetAt: number;\n /** Seconds to wait before retrying (only set when blocked) */\n retryAfter?: number;\n}\n\n/**\n * Convert decision to standard rate limit headers.\n */\nexport function toHeaders(decision: Decision): Record<string, string> {\n const headers: Record<string, string> = {\n 'RateLimit-Limit': String(decision.limit),\n 'RateLimit-Remaining': String(Math.max(0, decision.remaining)),\n 'RateLimit-Reset': String(decision.resetAt),\n };\n\n if (!decision.allowed && decision.retryAfter !== undefined) {\n headers['Retry-After'] = String(decision.retryAfter);\n }\n\n return headers;\n}\n","/**\n * In-memory storage backend for rate limiting.\n */\n\nexport interface Store {\n get(key: string): any;\n set(key: string, value: any, ttl?: number): void;\n increment(key: string, delta?: number, ttl?: number): number;\n delete(key: string): void;\n}\n\ninterface StoreEntry {\n value: any;\n expiry?: number;\n}\n\nexport class InMemoryStore implements Store {\n private data: Map<string, StoreEntry> = new Map();\n\n get(key: string): any {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n return entry?.value ?? null;\n }\n\n set(key: string, value: any, ttl?: number): void {\n const entry: StoreEntry = { value };\n\n if (ttl !== undefined) {\n entry.expiry = Date.now() + ttl * 1000;\n }\n\n this.data.set(key, entry);\n }\n\n increment(key: string, delta: number = 1, ttl?: number): number {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n const current = typeof entry?.value === 'number' ? entry.value : 0;\n const newValue = current + delta;\n\n const newEntry: StoreEntry = { value: newValue };\n\n // Set TTL only if key didn't exist\n if (!entry && ttl !== undefined) {\n newEntry.expiry = Date.now() + ttl * 1000;\n } else if (entry?.expiry) {\n newEntry.expiry = entry.expiry;\n }\n\n this.data.set(key, newEntry);\n return newValue;\n }\n\n delete(key: string): void {\n this.data.delete(key);\n }\n\n private cleanupExpired(key: string): void {\n const entry = this.data.get(key);\n if (entry?.expiry && Date.now() >= entry.expiry) {\n this.data.delete(key);\n }\n }\n\n /**\n * Clean up all expired keys.\n */\n cleanupAllExpired(): number {\n const now = Date.now();\n let count = 0;\n\n for (const [key, entry] of this.data.entries()) {\n if (entry.expiry && now >= entry.expiry) {\n this.data.delete(key);\n count++;\n }\n }\n\n return count;\n }\n}\n","/**\n * Preset rate limiting policies for common use cases.\n */\n\nimport { Policy, KeyStrategy, Algorithm } from '../core/policy';\n\n// Public API - moderate limits for general public access\nexport const PUBLIC_API: Policy = {\n name: 'public_api',\n limit: 100,\n window: 60, // 1 minute\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Authentication endpoints - strict limits to prevent brute force\nexport const AUTH_ENDPOINTS: Policy = {\n name: 'auth_endpoints',\n limit: 5,\n window: 60, // 1 minute\n burst: 10,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n blockDuration: 300, // 5 minute cooldown after limit exceeded\n};\n\n// Expensive operations - very strict limits for resource-intensive endpoints\nexport const EXPENSIVE_OPS: Policy = {\n name: 'expensive_ops',\n limit: 10,\n window: 3600, // 1 hour\n burst: 15,\n cost: 10, // Each request costs 10 tokens\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Strict API - for sensitive operations\nexport const STRICT_API: Policy = {\n name: 'strict_api',\n limit: 20,\n window: 60, // 1 minute\n burst: 25,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.API_KEY,\n};\n\n// Generous API - for internal or trusted services\nexport const GENEROUS_API: Policy = {\n name: 'generous_api',\n limit: 1000,\n window: 60, // 1 minute\n burst: 1200,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Plan-based presets for SaaS platforms\nexport const PLAN_FREE: Policy = {\n name: 'free_plan',\n limit: 100,\n window: 3600, // 100 requests per hour\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_STARTER: Policy = {\n name: 'starter_plan',\n limit: 500,\n window: 3600, // 500 requests per hour\n burst: 600,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_PRO: Policy = {\n name: 'pro_plan',\n limit: 2000,\n window: 3600, // 2000 requests per hour\n burst: 2500,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_BUSINESS: Policy = {\n name: 'business_plan',\n limit: 5000,\n window: 3600, // 5000 requests per hour\n burst: 6000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_ENTERPRISE: Policy = {\n name: 'enterprise_plan',\n limit: 20000,\n window: 3600, // 20000 requests per hour\n burst: 25000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Plan mapping helper\nexport const PLAN_TIERS: Record<string, Policy> = {\n free: PLAN_FREE,\n starter: PLAN_STARTER,\n pro: PLAN_PRO,\n business: PLAN_BUSINESS,\n enterprise: PLAN_ENTERPRISE,\n};\n\n/**\n * Get policy for a plan tier.\n * @param planName - Plan tier name (free, starter, pro, business, enterprise)\n * @returns Policy for the plan\n * @throws Error if plan name is invalid\n */\nexport function getPlanPolicy(planName: string): Policy {\n const normalized = planName.toLowerCase();\n if (!(normalized in PLAN_TIERS)) {\n throw new Error(\n `Invalid plan: ${planName}. Valid plans: ${Object.keys(PLAN_TIERS).join(', ')}`\n );\n }\n return PLAN_TIERS[normalized];\n}\n"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision model for rate limiting results.
|
|
3
|
+
*/
|
|
4
|
+
interface Decision {
|
|
5
|
+
/** Whether the request is allowed */
|
|
6
|
+
allowed: boolean;
|
|
7
|
+
/** Maximum number of requests allowed in the window */
|
|
8
|
+
limit: number;
|
|
9
|
+
/** Number of requests remaining in the current window */
|
|
10
|
+
remaining: number;
|
|
11
|
+
/** Unix timestamp when the limit resets */
|
|
12
|
+
resetAt: number;
|
|
13
|
+
/** Seconds to wait before retrying (only set when blocked) */
|
|
14
|
+
retryAfter?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert decision to standard rate limit headers.
|
|
18
|
+
*/
|
|
19
|
+
declare function toHeaders(decision: Decision): Record<string, string>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Policy model for rate limiting configuration.
|
|
23
|
+
*/
|
|
24
|
+
declare enum KeyStrategy {
|
|
25
|
+
IP = "ip",
|
|
26
|
+
USER = "user",
|
|
27
|
+
API_KEY = "api_key",
|
|
28
|
+
COMPOSITE = "composite",
|
|
29
|
+
CUSTOM = "custom"
|
|
30
|
+
}
|
|
31
|
+
declare enum Algorithm {
|
|
32
|
+
TOKEN_BUCKET = "token_bucket",
|
|
33
|
+
FIXED_WINDOW = "fixed_window",
|
|
34
|
+
SLIDING_WINDOW = "sliding_window",
|
|
35
|
+
LEAKY_BUCKET = "leaky_bucket"
|
|
36
|
+
}
|
|
37
|
+
interface Policy {
|
|
38
|
+
/** Human-readable policy name */
|
|
39
|
+
name: string;
|
|
40
|
+
/** Maximum number of requests allowed */
|
|
41
|
+
limit: number;
|
|
42
|
+
/** Time window in seconds */
|
|
43
|
+
window: number;
|
|
44
|
+
/** Rate limiting algorithm to use */
|
|
45
|
+
algorithm?: Algorithm;
|
|
46
|
+
/** Strategy for extracting the rate limit key */
|
|
47
|
+
keyStrategy?: KeyStrategy;
|
|
48
|
+
/** Maximum burst size (for token bucket) */
|
|
49
|
+
burst?: number;
|
|
50
|
+
/** Cost per request (default: 1) */
|
|
51
|
+
cost?: number;
|
|
52
|
+
/** Duration to block after limit exceeded (seconds) */
|
|
53
|
+
blockDuration?: number;
|
|
54
|
+
/** Custom function to extract key from request */
|
|
55
|
+
keyExtractor?: (request: any) => string | null;
|
|
56
|
+
/** List of paths or IPs to exempt from rate limiting */
|
|
57
|
+
exemptions?: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate and normalize policy configuration.
|
|
61
|
+
*/
|
|
62
|
+
declare function normalizePolicy(policy: Policy): Required<Policy>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* In-memory storage backend for rate limiting.
|
|
66
|
+
*/
|
|
67
|
+
interface Store {
|
|
68
|
+
get(key: string): any;
|
|
69
|
+
set(key: string, value: any, ttl?: number): void;
|
|
70
|
+
increment(key: string, delta?: number, ttl?: number): number;
|
|
71
|
+
delete(key: string): void;
|
|
72
|
+
}
|
|
73
|
+
declare class InMemoryStore implements Store {
|
|
74
|
+
private data;
|
|
75
|
+
get(key: string): any;
|
|
76
|
+
set(key: string, value: any, ttl?: number): void;
|
|
77
|
+
increment(key: string, delta?: number, ttl?: number): number;
|
|
78
|
+
delete(key: string): void;
|
|
79
|
+
private cleanupExpired;
|
|
80
|
+
/**
|
|
81
|
+
* Clean up all expired keys.
|
|
82
|
+
*/
|
|
83
|
+
cleanupAllExpired(): number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Main rate limiter implementation.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
interface RateLimiterOptions {
|
|
91
|
+
store: Store;
|
|
92
|
+
/** Either a static policy or a resolver returning a policy per-request */
|
|
93
|
+
policy: Policy | ((request: any) => Policy | Promise<Policy>);
|
|
94
|
+
trustedProxies?: string[];
|
|
95
|
+
exemptPrivateIps?: boolean;
|
|
96
|
+
/** Optional OpenTelemetry-like tracer (object with startSpan) */
|
|
97
|
+
otelTracer?: any;
|
|
98
|
+
/** Optional metrics recorder: (name, tags?, value?) => void */
|
|
99
|
+
metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;
|
|
100
|
+
}
|
|
101
|
+
declare class RateLimiter {
|
|
102
|
+
private store;
|
|
103
|
+
private policyOrResolver;
|
|
104
|
+
private trustedProxies;
|
|
105
|
+
private exemptPrivateIps;
|
|
106
|
+
private algorithmCache;
|
|
107
|
+
private otelTracer?;
|
|
108
|
+
private metricsRecorder?;
|
|
109
|
+
constructor(options: RateLimiterOptions);
|
|
110
|
+
/**
|
|
111
|
+
* Check if request is allowed under rate limit.
|
|
112
|
+
*/
|
|
113
|
+
/**
|
|
114
|
+
* Check if request is allowed under rate limit.
|
|
115
|
+
* This method is async because policy resolution may be async (e.g. DB lookup).
|
|
116
|
+
*/
|
|
117
|
+
check(request: any, cost?: number): Promise<Decision>;
|
|
118
|
+
/**
|
|
119
|
+
* Extract rate limit key from request based on policy strategy.
|
|
120
|
+
*/
|
|
121
|
+
private extractKey;
|
|
122
|
+
/**
|
|
123
|
+
* Check if request is exempt from rate limiting.
|
|
124
|
+
*/
|
|
125
|
+
private isExempt;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { Algorithm as A, type Decision as D, InMemoryStore as I, KeyStrategy as K, type Policy as P, RateLimiter as R, type Store as S, type RateLimiterOptions as a, normalizePolicy as n, toHeaders as t };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision model for rate limiting results.
|
|
3
|
+
*/
|
|
4
|
+
interface Decision {
|
|
5
|
+
/** Whether the request is allowed */
|
|
6
|
+
allowed: boolean;
|
|
7
|
+
/** Maximum number of requests allowed in the window */
|
|
8
|
+
limit: number;
|
|
9
|
+
/** Number of requests remaining in the current window */
|
|
10
|
+
remaining: number;
|
|
11
|
+
/** Unix timestamp when the limit resets */
|
|
12
|
+
resetAt: number;
|
|
13
|
+
/** Seconds to wait before retrying (only set when blocked) */
|
|
14
|
+
retryAfter?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert decision to standard rate limit headers.
|
|
18
|
+
*/
|
|
19
|
+
declare function toHeaders(decision: Decision): Record<string, string>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Policy model for rate limiting configuration.
|
|
23
|
+
*/
|
|
24
|
+
declare enum KeyStrategy {
|
|
25
|
+
IP = "ip",
|
|
26
|
+
USER = "user",
|
|
27
|
+
API_KEY = "api_key",
|
|
28
|
+
COMPOSITE = "composite",
|
|
29
|
+
CUSTOM = "custom"
|
|
30
|
+
}
|
|
31
|
+
declare enum Algorithm {
|
|
32
|
+
TOKEN_BUCKET = "token_bucket",
|
|
33
|
+
FIXED_WINDOW = "fixed_window",
|
|
34
|
+
SLIDING_WINDOW = "sliding_window",
|
|
35
|
+
LEAKY_BUCKET = "leaky_bucket"
|
|
36
|
+
}
|
|
37
|
+
interface Policy {
|
|
38
|
+
/** Human-readable policy name */
|
|
39
|
+
name: string;
|
|
40
|
+
/** Maximum number of requests allowed */
|
|
41
|
+
limit: number;
|
|
42
|
+
/** Time window in seconds */
|
|
43
|
+
window: number;
|
|
44
|
+
/** Rate limiting algorithm to use */
|
|
45
|
+
algorithm?: Algorithm;
|
|
46
|
+
/** Strategy for extracting the rate limit key */
|
|
47
|
+
keyStrategy?: KeyStrategy;
|
|
48
|
+
/** Maximum burst size (for token bucket) */
|
|
49
|
+
burst?: number;
|
|
50
|
+
/** Cost per request (default: 1) */
|
|
51
|
+
cost?: number;
|
|
52
|
+
/** Duration to block after limit exceeded (seconds) */
|
|
53
|
+
blockDuration?: number;
|
|
54
|
+
/** Custom function to extract key from request */
|
|
55
|
+
keyExtractor?: (request: any) => string | null;
|
|
56
|
+
/** List of paths or IPs to exempt from rate limiting */
|
|
57
|
+
exemptions?: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate and normalize policy configuration.
|
|
61
|
+
*/
|
|
62
|
+
declare function normalizePolicy(policy: Policy): Required<Policy>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* In-memory storage backend for rate limiting.
|
|
66
|
+
*/
|
|
67
|
+
interface Store {
|
|
68
|
+
get(key: string): any;
|
|
69
|
+
set(key: string, value: any, ttl?: number): void;
|
|
70
|
+
increment(key: string, delta?: number, ttl?: number): number;
|
|
71
|
+
delete(key: string): void;
|
|
72
|
+
}
|
|
73
|
+
declare class InMemoryStore implements Store {
|
|
74
|
+
private data;
|
|
75
|
+
get(key: string): any;
|
|
76
|
+
set(key: string, value: any, ttl?: number): void;
|
|
77
|
+
increment(key: string, delta?: number, ttl?: number): number;
|
|
78
|
+
delete(key: string): void;
|
|
79
|
+
private cleanupExpired;
|
|
80
|
+
/**
|
|
81
|
+
* Clean up all expired keys.
|
|
82
|
+
*/
|
|
83
|
+
cleanupAllExpired(): number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Main rate limiter implementation.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
interface RateLimiterOptions {
|
|
91
|
+
store: Store;
|
|
92
|
+
/** Either a static policy or a resolver returning a policy per-request */
|
|
93
|
+
policy: Policy | ((request: any) => Policy | Promise<Policy>);
|
|
94
|
+
trustedProxies?: string[];
|
|
95
|
+
exemptPrivateIps?: boolean;
|
|
96
|
+
/** Optional OpenTelemetry-like tracer (object with startSpan) */
|
|
97
|
+
otelTracer?: any;
|
|
98
|
+
/** Optional metrics recorder: (name, tags?, value?) => void */
|
|
99
|
+
metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;
|
|
100
|
+
}
|
|
101
|
+
declare class RateLimiter {
|
|
102
|
+
private store;
|
|
103
|
+
private policyOrResolver;
|
|
104
|
+
private trustedProxies;
|
|
105
|
+
private exemptPrivateIps;
|
|
106
|
+
private algorithmCache;
|
|
107
|
+
private otelTracer?;
|
|
108
|
+
private metricsRecorder?;
|
|
109
|
+
constructor(options: RateLimiterOptions);
|
|
110
|
+
/**
|
|
111
|
+
* Check if request is allowed under rate limit.
|
|
112
|
+
*/
|
|
113
|
+
/**
|
|
114
|
+
* Check if request is allowed under rate limit.
|
|
115
|
+
* This method is async because policy resolution may be async (e.g. DB lookup).
|
|
116
|
+
*/
|
|
117
|
+
check(request: any, cost?: number): Promise<Decision>;
|
|
118
|
+
/**
|
|
119
|
+
* Extract rate limit key from request based on policy strategy.
|
|
120
|
+
*/
|
|
121
|
+
private extractKey;
|
|
122
|
+
/**
|
|
123
|
+
* Check if request is exempt from rate limiting.
|
|
124
|
+
*/
|
|
125
|
+
private isExempt;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { Algorithm as A, type Decision as D, InMemoryStore as I, KeyStrategy as K, type Policy as P, RateLimiter as R, type Store as S, type RateLimiterOptions as a, normalizePolicy as n, toHeaders as t };
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "halt-rate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drop-in middleware that enforces consistent rate limits with safe defaults and Redis-backed accuracy",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.cjs",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./express": {
|
|
14
|
+
"import": "./dist/adapters/express.js",
|
|
15
|
+
"require": "./dist/adapters/express.cjs",
|
|
16
|
+
"types": "./dist/adapters/express.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./next": {
|
|
19
|
+
"import": "./dist/adapters/next.js",
|
|
20
|
+
"require": "./dist/adapters/next.cjs",
|
|
21
|
+
"types": "./dist/adapters/next.d.ts"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage",
|
|
32
|
+
"lint": "eslint src --ext .ts",
|
|
33
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"rate-limiting",
|
|
38
|
+
"throttling",
|
|
39
|
+
"middleware",
|
|
40
|
+
"express",
|
|
41
|
+
"nextjs"
|
|
42
|
+
],
|
|
43
|
+
"author": "Halt Contributors",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/surafel-kindu/halt"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/express": "^4.17.21",
|
|
51
|
+
"@types/node": "^20.10.0",
|
|
52
|
+
"next": "^14.0.0",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
54
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
55
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
56
|
+
"eslint": "^8.54.0",
|
|
57
|
+
"prettier": "^3.1.0",
|
|
58
|
+
"tsup": "^8.0.0",
|
|
59
|
+
"typescript": "^5.3.0",
|
|
60
|
+
"vitest": "^1.0.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"express": "^4.18.0",
|
|
64
|
+
"next": "^14.0.0",
|
|
65
|
+
"ioredis": "^5.3.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"express": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"next": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"ioredis": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|