@arcis/node 1.0.0 → 1.2.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 +156 -222
- package/dist/core/index.d.mts +4 -4
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +13 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +13 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/index-A-m-pPeW.d.mts +340 -0
- package/dist/index-CgK94hY_.d.mts +532 -0
- package/dist/index-Co5kPRZz.d.ts +340 -0
- package/dist/index-D_bdJcF0.d.ts +532 -0
- package/dist/index.d.mts +144 -108
- package/dist/index.d.ts +144 -108
- package/dist/index.js +1541 -211
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1515 -212
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.d.mts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +12 -1
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs +12 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/middleware/index.d.mts +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +524 -4
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +517 -5
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/{headers-DBQedhrb.d.mts → pii-CXcHMlnX.d.mts} +156 -2
- package/dist/{headers-BJq2OA0i.d.ts → pii-DhNpl7M3.d.ts} +156 -2
- package/dist/sanitizers/index.d.mts +2 -2
- package/dist/sanitizers/index.d.ts +2 -2
- package/dist/sanitizers/index.js +331 -3
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +321 -4
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/stores/index.d.mts +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs.map +1 -1
- package/dist/{types-BOdL3ZWo.d.mts → types-CsOFHoD9.d.mts} +6 -1
- package/dist/{types-BOdL3ZWo.d.ts → types-CsOFHoD9.d.ts} +6 -1
- package/dist/validation/index.d.mts +2 -2
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +504 -2
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs +498 -3
- package/dist/validation/index.mjs.map +1 -1
- package/package.json +114 -109
- package/dist/index-BgHPM7LC.d.ts +0 -129
- package/dist/index-BpT7flAQ.d.ts +0 -255
- package/dist/index-JaFOUKyK.d.mts +0 -255
- package/dist/index-nAgXexwD.d.mts +0 -129
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/constants.ts","../src/middleware/headers.ts","../src/middleware/rate-limit.ts","../src/middleware/error-handler.ts","../src/core/errors.ts","../src/sanitizers/utils.ts","../src/sanitizers/xss.ts","../src/sanitizers/sql.ts","../src/sanitizers/path.ts","../src/sanitizers/command.ts","../src/sanitizers/sanitize.ts","../src/sanitizers/nosql.ts","../src/sanitizers/prototype.ts","../src/sanitizers/headers.ts","../src/validation/schema.ts","../src/validation/file.ts","../src/logging/redactor.ts","../src/middleware/main.ts","../src/middleware/cors.ts","../src/middleware/cookies.ts","../src/validation/url.ts","../src/validation/redirect.ts","../src/stores/memory.ts","../src/stores/redis.ts"],"names":["host"],"mappings":";;;;;AAQO,IAAM,KAAA,GAAQ;AAAA;AAAA,EAEnB,gBAAA,EAAkB,GAAA;AAAA;AAAA,EAElB,mBAAA,EAAqB;AACvB;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,iBAAA,EAAmB,GAAA;AAAA;AAAA,EAEnB,oBAAA,EAAsB,GAAA;AAAA;AAAA,EAEtB,mBAAA,EAAqB,GAAA;AAAA;AAAA,EAErB,eAAA,EAAiB,4CAAA;AAAA;AAAA,EAEjB,aAAA,EAAe,GAAA;AAAA;AAAA,EAEf,aAAA,EAAe;AACjB;AAKO,IAAM,OAAA,GAAU;AAAA;AAAA,EAErB,WAAA,EAAa;AAAA,IACX,oBAAA;AAAA,IACA,mBAAA;AAAA,IACA,kCAAA;AAAA,IACA,6BAAA;AAAA,IACA,iBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AAAA;AAAA,EAEX,YAAA,EAAc,OAAA;AAAA;AAAA,EAEd,aAAA,EAAe,MAAA;AAAA;AAAA,EAEf,oBAAA,EAAsB,SAAA;AAAA;AAAA,EAEtB,eAAA,EAAiB,iCAAA;AAAA;AAAA,EAEjB,kBAAA,EAAoB,0CAAA;AAAA;AAAA,EAEpB,aAAA,EAAe;AACjB;AAUO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,mCAAA;AAAA;AAAA,EAEA,kBAAA;AAAA;AAAA,EAEA,gBAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,UAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EAEA,aAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAQO,IAAM,mBAAA,GAAsB;AAAA;AAAA,EAEjC,mCAAA;AAAA;AAAA,EAEA,iBAAA;AAAA;AAAA,EAEA,mCAAA;AAAA,EACA,gBAAA;AAAA;AAAA,EAEA,mCAAA;AAAA,EACA,gBAAA;AAAA;AAAA,EAEA,eAAA;AAAA;AAAA,EAEA,yBAAA;AAAA;AAAA,EAEA,aAAA;AAAA;AAAA,EAEA,uCAAA;AAAA;AAAA,EAEA,gCAAA;AAAA;AAAA,EAEA,kBAAA;AAAA,EACA,gBAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAKO,IAAM,YAAA,GAAe;AAAA;AAAA,EAE1B,qFAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,wBAAA;AAAA;AAAA,EAEA,8CAAA;AAAA,EACA,oDAAA;AAAA;AAAA,EAEA,yBAAA;AAAA;AAAA,EAEA,+CAAA;AAAA,EACA,qDAAA;AAAA;AAAA,EAEA,2BAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAKO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,SAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,UAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,cAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAEA,aAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAKO,IAAM,gBAAA,GAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU9B,SAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAiBO,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA,EAC1C,WAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAC,CAAA;AAGM,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA;AAAA,EAE1C,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,MAAA;AAAA;AAAA,EAEnD,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,MAAA;AAAA;AAAA,EAEvB,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,OAAA;AAAA;AAAA,EAEzD,YAAA;AAAA,EAAc,MAAA;AAAA,EAAQ,OAAA;AAAA;AAAA,EAEtB,WAAA;AAAA,EAAa,cAAA;AAAA;AAAA,EAEb,SAAA;AAAA,EAAW,QAAA;AAAA,EAAU,UAAA;AAAA,EAAY,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,OAAA;AAAA,EAC9D,SAAA;AAAA,EAAW,YAAA;AAAA,EAAc;AAC3B,CAAC,CAAA;AAKM,IAAM,SAAA,GAAY;AAAA;AAAA,EAEvB,WAAA,EAAa,YAAA;AAAA;AAAA,EAEb,SAAA,EAAW,aAAA;AAAA;AAAA,EAEX,SAAA,EAAW,aAAA;AAAA;AAAA,EAEX,kBAAA,EAAoB,GAAA;AAAA;AAAA,EAEpB,cAAA,sBAAoB,GAAA,CAAI;AAAA,IACtB,UAAA;AAAA,IAAY,QAAA;AAAA,IAAU,KAAA;AAAA,IAAO,QAAA;AAAA,IAAU,OAAA;AAAA,IAAS,QAAA;AAAA,IAChD,SAAA;AAAA,IAAW,QAAA;AAAA,IAAU,MAAA;AAAA,IAAQ,eAAA;AAAA,IAAiB,aAAA;AAAA,IAC9C,YAAA;AAAA,IAAc,IAAA;AAAA,IAAM,KAAA;AAAA,IAAO,iBAAA;AAAA,IAAmB,aAAA;AAAA,IAC9C,YAAA;AAAA,IAAc,cAAA;AAAA,IAAgB,aAAA;AAAA,IAAe,eAAA;AAAA,IAC7C,cAAA;AAAA,IAAgB,QAAA;AAAA,IAAU,KAAA;AAAA,IAAO,SAAA;AAAA,IAAW,QAAA;AAAA,IAC5C,aAAA;AAAA,IAAe,WAAA;AAAA,IAAa;AAAA,GAC7B;AACH;AAKO,IAAM,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,KAAA,EAAO,wDAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMP,GAAA,EAAK,+BAAA;AAAA;AAAA,EAEL,IAAA,EAAM;AACR;AAKO,IAAM,MAAA,GAAS;AAAA;AAAA,EAEpB,qBAAA,EAAuB,uBAAA;AAAA;AAAA,EAEvB,eAAA,EAAiB,CAAC,OAAA,KAAoB,CAAA,8BAAA,EAAiC,OAAO,CAAA,MAAA,CAAA;AAAA;AAAA,EAE9E,UAAA,EAAY;AAAA,IACV,QAAA,EAAU,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,YAAA,CAAA;AAAA,IACrC,cAAc,CAAC,KAAA,EAAe,SAAiB,CAAA,EAAG,KAAK,cAAc,IAAI,CAAA,CAAA;AAAA,IACzE,YAAY,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,qBAAqB,GAAG,CAAA,WAAA,CAAA;AAAA,IAC5E,YAAY,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,oBAAoB,GAAG,CAAA,WAAA,CAAA;AAAA,IAC3E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,qBAAqB,GAAG,CAAA,CAAA;AAAA,IAC3E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,oBAAoB,GAAG,CAAA,CAAA;AAAA,IAC1E,cAAA,EAAgB,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,kBAAA,CAAA;AAAA,IAC3C,aAAA,EAAe,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,sBAAA,CAAA;AAAA,IAC1C,WAAA,EAAa,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,oBAAA,CAAA;AAAA,IACxC,YAAA,EAAc,CAAC,KAAA,KAAkB,CAAA,EAAG,KAAK,CAAA,qBAAA,CAAA;AAAA,IACzC,YAAA,EAAc,CAAC,KAAA,EAAe,MAAA,KAAsB,CAAA,EAAG,KAAK,CAAA,iBAAA,EAAoB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,IACjG,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,uBAAuB,GAAG,CAAA,MAAA,CAAA;AAAA,IAC7E,WAAW,CAAC,KAAA,EAAe,QAAgB,CAAA,EAAG,KAAK,sBAAsB,GAAG,CAAA,MAAA;AAAA;AAEhF;AAKO,IAAM,OAAA,GAAU;;;AC1RhB,SAAS,aAAA,CAAc,OAAA,GAAyB,EAAC,EAAmB;AACzE,EAAA,MAAM;AAAA,IACJ,qBAAA,GAAwB,IAAA;AAAA,IACxB,SAAA,GAAY,IAAA;AAAA,IACZ,OAAA,GAAU,IAAA;AAAA,IACV,eAAe,OAAA,CAAQ,aAAA;AAAA,IACvB,IAAA,GAAO,IAAA;AAAA,IACP,iBAAiB,OAAA,CAAQ,eAAA;AAAA,IACzB,oBAAoB,OAAA,CAAQ,kBAAA;AAAA,IAC5B,YAAA,GAAe;AAAA,GACjB,GAAI,OAAA;AAEJ,EAAA,OAAO,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AAE1D,IAAA,IAAI,qBAAA,EAAuB;AACzB,MAAA,MAAM,GAAA,GAAM,OAAO,qBAAA,KAA0B,QAAA,GACzC,wBACA,OAAA,CAAQ,WAAA;AACZ,MAAA,GAAA,CAAI,SAAA,CAAU,2BAA2B,GAAG,CAAA;AAAA,IAC9C;AAGA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,GAAA,CAAI,SAAA,CAAU,oBAAoB,eAAe,CAAA;AAAA,IACnD;AAGA,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,GAAA,CAAI,SAAA,CAAU,wBAAA,EAA0B,OAAA,CAAQ,oBAAoB,CAAA;AAAA,IACtE;AAGA,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,GAAA,CAAI,SAAA,CAAU,mBAAmB,YAAY,CAAA;AAAA,IAC/C;AAOA,IAAA,MAAM,cAAA,GAAkB,GAAA,CAAI,OAAA,CAAQ,mBAAmB,CAAA,EACnD,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CACb,IAAA,EAAK,CACL,WAAA,EAAY;AACf,IAAA,MAAM,qBAAA,GAAwB,cAAA,KAAmB,OAAA,IAAW,cAAA,KAAmB,SAC3E,cAAA,GACA,MAAA;AACJ,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,MAAA,IAAU,qBAAA,KAA0B,OAAA;AAExD,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAA,MAAM,QAAA,GAAwB,OAAO,IAAA,KAAS,QAAA,GAAW,OAAO,EAAC;AACjE,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,MAAA,IAAU,OAAA,CAAQ,YAAA;AAC1C,MAAA,MAAM,iBAAA,GAAoB,SAAS,iBAAA,KAAsB,KAAA;AACzD,MAAA,MAAM,OAAA,GAAU,SAAS,OAAA,KAAY,IAAA;AAErC,MAAA,IAAI,SAAA,GAAY,WAAW,MAAM,CAAA,CAAA;AACjC,MAAA,IAAI,mBAAmB,SAAA,IAAa,qBAAA;AACpC,MAAA,IAAI,SAAS,SAAA,IAAa,WAAA;AAE1B,MAAA,GAAA,CAAI,SAAA,CAAU,6BAA6B,SAAS,CAAA;AAAA,IACtD;AAGA,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,GAAA,CAAI,SAAA,CAAU,mBAAmB,cAAc,CAAA;AAAA,IACjD;AAGA,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,GAAA,CAAI,SAAA,CAAU,sBAAsB,iBAAiB,CAAA;AAAA,IACvD;AAGA,IAAA,GAAA,CAAI,SAAA,CAAU,qCAAqC,MAAM,CAAA;AAGzD,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,iBAAA,GAAoB,OAAO,YAAA,KAAiB,QAAA,GAC9C,eACA,OAAA,CAAQ,aAAA;AACZ,MAAA,GAAA,CAAI,SAAA,CAAU,iBAAiB,iBAAiB,CAAA;AAChD,MAAA,GAAA,CAAI,SAAA,CAAU,UAAU,UAAU,CAAA;AAClC,MAAA,GAAA,CAAI,SAAA,CAAU,WAAW,GAAG,CAAA;AAAA,IAC9B;AAGA,IAAA,GAAA,CAAI,aAAa,cAAc,CAAA;AAE/B,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF;AAMO,IAAM,eAAA,GAAkB;;;ACtFxB,SAAS,iBAAA,CAAkB,OAAA,GAA4B,EAAC,EAA0B;AACvF,EAAA,MAAM;AAAA,IACJ,MAAM,UAAA,CAAW,oBAAA;AAAA,IACjB,WAAW,UAAA,CAAW,iBAAA;AAAA,IACtB,UAAU,UAAA,CAAW,eAAA;AAAA,IACrB,aAAa,UAAA,CAAW,mBAAA;AAAA,IACxB,YAAA,GAAe,CAAC,GAAA,KAAQ;AACtB,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,EAAA,IAAM,GAAA,CAAI,MAAA,EAAQ,aAAA;AACjC,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN;AAAA,SAEF;AACA,QAAA,OAAO,SAAA;AAAA,MACT;AACA,MAAA,OAAO,EAAA;AAAA,IACT,CAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA,EAAO;AAAA,GACT,GAAI,OAAA;AAIJ,EAAA,MAAM,aAAA,mBAAgB,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAGxC,EAAA,IAAI,eAAA,GAAyD,IAAA;AAE7D,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,eAAA,GAAkB,YAAY,MAAM;AAClC,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA,EAAG;AAC5C,QAAA,IAAI,aAAA,CAAc,GAAG,CAAA,CAAE,SAAA,GAAY,GAAA,EAAK;AACtC,UAAA,OAAO,cAAc,GAAG,CAAA;AAAA,QAC1B;AAAA,MACF;AAAA,IACF,GAAG,QAAQ,CAAA;AAGX,IAAA,IAAI,OAAO,eAAA,CAAgB,KAAA,KAAU,UAAA,EAAY;AAC/C,MAAA,eAAA,CAAgB,KAAA,EAAM;AAAA,IACxB;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAA0B,OAAO,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AACzF,IAAA,IAAI;AACF,MAAA,IAAI,IAAA,GAAO,GAAG,CAAA,EAAG;AACf,QAAA,OAAO,IAAA,EAAK;AAAA,MACd;AAEA,MAAA,MAAM,GAAA,GAAM,aAAa,GAAG,CAAA;AAC5B,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI,SAAA;AAEJ,MAAA,IAAI,aAAA,EAAe;AAEjB,QAAA,MAAM,KAAA,GAAQ,MAAM,aAAA,CAAc,GAAA,CAAI,GAAG,CAAA;AACzC,QAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,SAAA,GAAY,GAAA,EAAK;AACnC,UAAA,MAAM,aAAA,CAAc,IAAI,GAAA,EAAK,EAAE,OAAO,CAAA,EAAG,SAAA,EAAW,GAAA,GAAM,QAAA,EAAU,CAAA;AACpE,UAAA,KAAA,GAAQ,CAAA;AACR,UAAA,SAAA,GAAY,GAAA,GAAM,QAAA;AAAA,QACpB,CAAA,MAAO;AACL,UAAA,KAAA,GAAQ,MAAM,aAAA,CAAc,SAAA,CAAU,GAAG,CAAA;AACzC,UAAA,SAAA,GAAY,KAAA,CAAM,SAAA;AAAA,QACpB;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,IAAI,CAAC,cAAc,GAAG,CAAA,IAAK,cAAc,GAAG,CAAA,CAAE,YAAY,GAAA,EAAK;AAC7D,UAAA,aAAA,CAAc,GAAG,CAAA,GAAI,EAAE,OAAO,CAAA,EAAG,SAAA,EAAW,MAAM,QAAA,EAAS;AAAA,QAC7D,CAAA,MAAO;AACL,UAAA,aAAA,CAAc,GAAG,CAAA,CAAE,KAAA,EAAA;AAAA,QACrB;AACA,QAAA,KAAA,GAAQ,aAAA,CAAc,GAAG,CAAA,CAAE,KAAA;AAC3B,QAAA,SAAA,GAAY,aAAA,CAAc,GAAG,CAAA,CAAE,SAAA;AAAA,MACjC;AAEA,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,KAAK,CAAA;AACzC,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,IAAA,CAAA,CAAM,SAAA,GAAY,OAAO,GAAI,CAAA;AAGvD,MAAA,GAAA,CAAI,SAAA,CAAU,mBAAA,EAAqB,GAAA,CAAI,QAAA,EAAU,CAAA;AACjD,MAAA,GAAA,CAAI,SAAA,CAAU,uBAAA,EAAyB,SAAA,CAAU,QAAA,EAAU,CAAA;AAC3D,MAAA,GAAA,CAAI,SAAA,CAAU,mBAAA,EAAqB,YAAA,CAAa,QAAA,EAAU,CAAA;AAE1D,MAAA,IAAI,QAAQ,GAAA,EAAK;AACf,QAAA,GAAA,CAAI,SAAA,CAAU,aAAA,EAAe,YAAA,CAAa,QAAA,EAAU,CAAA;AACpD,QAAA,GAAA,CAAI,MAAA,CAAO,UAAU,CAAA,CAAE,IAAA,CAAK;AAAA,UAC1B,KAAA,EAAO,OAAA;AAAA,UACP,UAAA,EAAY;AAAA,SACb,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,IAAA,EAAK;AAAA,IACP,SAAS,KAAA,EAAO;AAEd,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAA+B,KAAK,CAAA;AAClD,MAAA,IAAA,EAAK;AAAA,IACP;AAAA,EACF,CAAA;AAGA,EAAA,MAAM,UAAA,GAAa,OAAA;AACnB,EAAA,UAAA,CAAW,QAAQ,MAAM;AACvB,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,aAAA,CAAc,eAAe,CAAA;AAC7B,MAAA,eAAA,GAAkB,IAAA;AAAA,IACpB;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,UAAA;AACT;AAMO,IAAM,SAAA,GAAY;;;AC9IzB,IAAM,wBAAA,GAAqC;AAAA;AAAA,EAEzC,qEAAA;AAAA,EACA,2DAAA;AAAA,EACA,+CAAA;AAAA,EACA,qDAAA;AAAA,EACA,4CAAA;AAAA;AAAA,EAEA,yEAAA;AAAA;AAAA,EAEA,0DAAA;AAAA;AAAA,EAEA,oEAAA;AAAA;AAAA,EAEA,oCAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAKO,SAAS,sBAAsB,OAAA,EAA0B;AAC9D,EAAA,OAAO,yBAAyB,IAAA,CAAK,CAAA,OAAA,KAAW,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAC,CAAA;AACvE;AA4BO,SAAS,YAAA,CACd,UAAyC,KAAA,EAC8B;AACvE,EAAA,MAAM,QAAQ,OAAO,OAAA,KAAY,SAAA,GAAY,OAAA,GAAU,QAAQ,KAAA,IAAS,KAAA;AACxE,EAAA,MAAM,YAAY,OAAO,OAAA,KAAY,QAAA,GAAW,OAAA,CAAQ,aAAa,IAAA,GAAO,IAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,OAAO,OAAA,KAAY,QAAA,GAAW,QAAQ,MAAA,GAAS,MAAA;AAC9D,EAAA,MAAM,aAAA,GAAgB,OAAO,OAAA,KAAY,QAAA,GAAW,QAAQ,aAAA,GAAgB,MAAA;AAE5E,EAAA,OAAO,CAAC,GAAA,EAAgB,GAAA,EAAc,GAAA,EAAe,KAAA,KAAwB;AAC3E,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,MAAA,IAAU,GAAA;AAGnD,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,OAAO,aAAA,CAAc,GAAA,EAAK,GAAA,EAAK,GAAG,CAAA;AAAA,IACpC;AAGA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,OAAO,GAAA,CAAI,OAAA;AAAA,QACX,OAAO,GAAA,CAAI,KAAA;AAAA,QACX,UAAA;AAAA,QACA,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,QAAQ,GAAA,CAAI;AAAA,OACd;AAEA,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,MAAA,CAAO,KAAA,CAAM,iBAAiB,OAAO,CAAA;AAAA,MACvC,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,KAAA,CAAM,0BAA0B,OAAO,CAAA;AAAA,MACjD;AAAA,IACF;AAMA,IAAA,MAAM,aAAA,GAAgB,KAAA,IAAS,GAAA,CAAI,MAAA,KAAW,IAAA;AAE9C,IAAA,IAAI,aAAA;AACJ,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,aAAA,GAAgB,MAAA,CAAO,qBAAA;AAAA,IACzB,CAAA,MAAA,IAAW,qBAAA,CAAsB,GAAA,CAAI,OAAO,CAAA,EAAG;AAE7C,MAAA,aAAA,GAAgB,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,qBAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,aAAA,GAAgB,GAAA,CAAI,OAAA;AAAA,IACtB;AAEA,IAAA,MAAM,QAAA,GAAoC;AAAA,MACxC,KAAA,EAAO;AAAA,KACT;AAGA,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,QAAQ,GAAA,CAAI,KAAA;AACrB,MAAA,QAAA,CAAS,UAAU,GAAA,CAAI,OAAA;AAAA,IACzB;AAEA,IAAA,GAAA,CAAI,MAAA,CAAO,UAAU,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA;AAAA,EACtC,CAAA;AACF;AAMO,IAAM,kBAAA,GAAqB;;;AC5H3B,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EAMpC,WAAA,CAAY,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK,OAAO,aAAA,EAAe;AACnE,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAGZ,IAAA,IAAA,CAAK,SAAS,UAAA,GAAa,GAAA;AAG3B,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,IAChD;AAAA,EACF;AACF;AAKO,IAAM,eAAA,GAAN,cAA8B,UAAA,CAAW;AAAA,EAG9C,YAAY,MAAA,EAAkB;AAC5B,IAAA,KAAA,CAAM,mBAAA,EAAqB,KAAK,kBAAkB,CAAA;AAClD,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AACF;AAQO,IAAM,cAAA,GAAN,cAA6B,UAAA,CAAW;AAAA,EAG7C,WAAA,CAAY,SAAiB,UAAA,EAAoB;AAC/C,IAAA,KAAA,CAAM,OAAA,EAAS,KAAK,qBAAqB,CAAA;AACzC,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AACF;AAKO,IAAM,kBAAA,GAAN,cAAiC,UAAA,CAAW;AAAA,EAIjD,WAAA,CAAY,SAAiB,UAAA,EAAoB;AAC/C,IAAA,KAAA,CAAM,CAAA,8BAAA,EAAiC,OAAO,CAAA,MAAA,CAAA,EAAU,GAAA,EAAK,iBAAiB,CAAA;AAC9E,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AACF;AAKO,IAAM,mBAAA,GAAN,cAAkC,UAAA,CAAW;AAAA,EAIlD,WAAA,CAAY,YAAoB,OAAA,EAAiB;AAC/C,IAAA,KAAA,CAAM,sCAAA,EAAwC,KAAK,iBAAiB,CAAA;AACpE,IAAA,IAAA,CAAK,IAAA,GAAO,qBAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF;AAKO,IAAM,iBAAA,GAAN,cAAgC,UAAA,CAAW;AAAA,EAChD,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAA,EAAS,KAAK,oBAAoB,CAAA;AACxC,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AAAA,EACd;AACF;;;ACtFO,SAAS,mBAAmB,GAAA,EAAqB;AACtD,EAAA,OAAO,IACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;;;ACYO,SAAS,WAAA,CAAY,KAAA,EAAe,cAAA,GAAiB,KAAA,EAAO,aAAa,KAAA,EAAgC;AAC9G,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,cAAA,GACH,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE,GACzD,OAAO,KAAK,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,EAAA,IAAI,YAAA,GAAe,KAAA;AAInB,EAAA,KAAA,MAAW,WAAW,mBAAA,EAAqB;AACzC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AACnC,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,YAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,cACX,IAAA,EAAM,KAAA;AAAA,cACN,SAAS,OAAA,CAAQ,MAAA;AAAA,cACjB,QAAA,EAAU;AAAA,aACX,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AACjC,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AAAA,EACF;AAMA,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,OAAA,GAAU,mBAAmB,KAAK,CAAA;AACxC,IAAA,IAAI,YAAY,KAAA,EAAO;AACrB,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AACA,IAAA,KAAA,GAAQ,OAAA;AAAA,EACV;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,OAAO,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAQ;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,UAAU,KAAA,EAAwB;AAChD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAGtC,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,IAAA;AAGxC,EAAA,IAAI,iBAAA,CAAkB,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,IAAA;AAC1C,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,IAAA;AACxC,EAAA,IAAI,wBAAA,CAAyB,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,IAAA;AAGjD,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;AC1FO,SAAS,WAAA,CAAY,KAAA,EAAe,cAAA,GAAiB,KAAA,EAAgC;AAC1F,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,cAAA,GACH,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE,GACzD,OAAO,KAAK,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAElC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AACnC,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,YAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,cACX,IAAA,EAAM,eAAA;AAAA,cACN,SAAS,OAAA,CAAQ,MAAA;AAAA,cACjB,QAAA,EAAU;AAAA,aACX,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAIA,MAAA,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA;AAClC,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AAAA,EACF;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,OAAO,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAQ;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,UAAU,KAAA,EAAwB;AAChD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAEtC,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;AC/DO,SAAS,YAAA,CAAa,KAAA,EAAe,cAAA,GAAiB,KAAA,EAAgC;AAC3F,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,cAAA,GACH,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE,GACzD,OAAO,KAAK,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AAEnC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AACnC,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,YAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,cACX,IAAA,EAAM,gBAAA;AAAA,cACN,SAAS,OAAA,CAAQ,MAAA;AAAA,cACjB,QAAA,EAAU;AAAA,aACX,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AACjC,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AAAA,EACF;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,OAAO,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAQ;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAEtC,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;AC7DO,SAAS,eAAA,CAAgB,KAAA,EAAe,cAAA,GAAiB,KAAA,EAAgC;AAC9F,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,cAAA,GACH,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE,GACzD,OAAO,KAAK,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,KAAA,MAAW,WAAW,gBAAA,EAAkB;AAEtC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AACnC,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,YAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,cACX,IAAA,EAAM,mBAAA;AAAA,cACN,SAAS,OAAA,CAAQ,MAAA;AAAA,cACjB,QAAA,EAAU;AAAA,aACX,CAAA;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA;AAClC,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AAAA,EACF;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,OAAO,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAQ;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,uBAAuB,KAAA,EAAwB;AAC7D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAEtC,EAAA,KAAA,MAAW,WAAW,gBAAA,EAAkB;AACtC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACjDO,SAAS,cAAA,CAAe,KAAA,EAAe,OAAA,GAA2B,EAAC,EAAW;AACnF,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAGtC,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,KAAA,CAAM,gBAAA;AACzC,EAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,IAAA,MAAM,IAAI,kBAAA,CAAmB,OAAA,EAAS,KAAA,CAAM,MAAM,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,MAAA,GAAS,QAAQ,IAAA,KAAS,UAAA;AAChC,EAAA,IAAI,MAAA,GAAS,KAAA;AAGb,EAAA,IAAI,OAAA,CAAQ,QAAQ,KAAA,EAAO;AACzB,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI,SAAA,CAAU,MAAM,CAAA,EAAG;AACrB,QAAA,MAAM,IAAI,mBAAA,CAAoB,eAAA,EAAiB,+BAA+B,CAAA;AAAA,MAChF;AAAA,IACF,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,YAAY,MAAM,CAAA;AAAA,IAC7B;AAAA,EACF;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,IAAA,MAAA,GAAS,aAAa,MAAM,CAAA;AAAA,EAC9B;AAGA,EAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,EAAO;AAC7B,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI,sBAAA,CAAuB,MAAM,CAAA,EAAG;AAClC,QAAA,MAAM,IAAI,mBAAA,CAAoB,mBAAA,EAAqB,uCAAuC,CAAA;AAAA,MAC5F;AAAA,IACF,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,gBAAgB,MAAM,CAAA;AAAA,IACjC;AAAA,EACF;AAIA,EAAA,IAAI,OAAA,CAAQ,QAAQ,KAAA,EAAO;AACzB,IAAA,MAAA,GAAS,WAAA,CAAY,MAAA,EAAQ,KAAA,EAAO,OAAA,CAAQ,cAAc,KAAK,CAAA;AAAA,EACjE;AAEA,EAAA,OAAO,MAAA;AACT;AAUO,SAAS,cAAA,CAAe,GAAA,EAAc,OAAA,GAA2B,EAAC,EAAY;AACnF,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,MAAA,EAAW,OAAO,GAAA;AAC9C,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,cAAA,CAAe,KAAK,OAAO,CAAA;AAC/D,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,GAAA,CAAI,GAAA,CAAI,CAAA,IAAA,KAAQ,cAAA,CAAe,IAAA,EAAM,OAAO,CAAC,CAAA;AAE5E,EAAA,OAAO,mBAAA,CAAoB,GAAA,EAAgC,OAAA,EAAS,CAAC,CAAA;AACvE;AAKA,SAAS,mBAAA,CACP,GAAA,EACA,OAAA,EACA,KAAA,EACyB;AACzB,EAAA,IAAI,KAAA,IAAS,KAAA,CAAM,mBAAA,EAAqB,OAAO,GAAA;AAE/C,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAG;AAElC,IAAA,IAAI,OAAA,CAAQ,UAAU,KAAA,IAAS,oBAAA,CAAqB,IAAI,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AAC1E,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,QAAQ,KAAA,KAAU,KAAA,IAAS,oBAAA,CAAqB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC5D,MAAA;AAAA,IACF;AAIA,IAAA,MAAM,YAAA,GAAe,cAAA,CAAe,GAAA,EAAK,OAAO,CAAA;AAGhD,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAG,CAAA;AACrB,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AACzC,MAAA,MAAA,CAAO,YAAY,CAAA,GAAI,KAAA;AAAA,IACzB,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,MAAA,MAAA,CAAO,YAAY,CAAA,GAAI,cAAA,CAAe,KAAA,EAAO,OAAO,CAAA;AAAA,IACtD,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/B,MAAA,MAAA,CAAO,YAAY,IAAI,KAAA,CAAM,GAAA,CAAI,UAAQ,cAAA,CAAe,IAAA,EAAM,OAAO,CAAC,CAAA;AAAA,IACxE,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,MAAA,MAAA,CAAO,YAAY,CAAA,GAAI,mBAAA,CAAoB,KAAA,EAAkC,OAAA,EAAS,QAAQ,CAAC,CAAA;AAAA,IACjG,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,YAAY,CAAA,GAAI,KAAA;AAAA,IACzB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAeO,SAAS,eAAA,CAAgB,OAAA,GAA2B,EAAC,EAAmB;AAC7E,EAAA,OAAO,CAAC,GAAA,EAAc,IAAA,EAAgB,IAAA,KAAuB;AAC3D,IAAA,IAAI;AACF,MAAA,IAAI,GAAA,CAAI,IAAA,IAAQ,OAAO,GAAA,CAAI,SAAS,QAAA,EAAU;AAC5C,QAAA,GAAA,CAAI,IAAA,GAAO,cAAA,CAAe,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AAAA,MAC7C;AACA,MAAA,IAAI,GAAA,CAAI,KAAA,IAAS,OAAO,GAAA,CAAI,UAAU,QAAA,EAAU;AAC9C,QAAA,MAAM,cAAA,GAAiB,cAAA,CAAe,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAExD,QAAA,MAAA,CAAO,cAAA,CAAe,GAAA,EAAK,OAAA,EAAS,EAAE,KAAA,EAAO,gBAAgB,QAAA,EAAU,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,CAAA;AAAA,MACnG;AACA,MAAA,IAAI,GAAA,CAAI,MAAA,IAAU,OAAO,GAAA,CAAI,WAAW,QAAA,EAAU;AAChD,QAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,GAAA,CAAI,MAAA,EAAQ,OAAO,CAAA;AAC1D,QAAA,MAAA,CAAO,cAAA,CAAe,GAAA,EAAK,QAAA,EAAU,EAAE,KAAA,EAAO,iBAAiB,QAAA,EAAU,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,CAAA;AAAA,MACrG;AACA,MAAA,IAAA,EAAK;AAAA,IACP,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAG,CAAA;AAAA,IACV;AAAA,EACF,CAAA;AACF;;;AChKO,SAAS,oBAAoB,GAAA,EAAsB;AACxD,EAAA,OAAO,oBAAA,CAAqB,IAAI,GAAG,CAAA;AACrC;AASO,SAAS,oBAAA,CAAqB,GAAA,EAAc,QAAA,GAAW,EAAA,EAAa;AACzE,EAAA,IAAI,QAAA,IAAY,GAAG,OAAO,KAAA;AAC1B,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,UAAU,OAAO,KAAA;AAEpD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,OAAO,IAAI,IAAA,CAAK,CAAA,IAAA,KAAQ,qBAAqB,IAAA,EAAM,QAAA,GAAW,CAAC,CAAC,CAAA;AAAA,EAClE;AAEA,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAA8B,CAAA,EAAG;AAC7D,IAAA,IAAI,mBAAA,CAAoB,GAAG,CAAA,EAAG;AAC5B,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,KAAA,GAAS,IAAgC,GAAG,CAAA;AAClD,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,EAAM;AAC/C,MAAA,IAAI,oBAAA,CAAqB,KAAA,EAAO,QAAA,GAAW,CAAC,CAAA,EAAG;AAC7C,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;AC9BO,SAAS,oBAAoB,GAAA,EAAsB;AACxD,EAAA,OAAO,oBAAA,CAAqB,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,CAAA;AACnD;AASO,SAAS,wBAAA,CAAyB,GAAA,EAAc,QAAA,GAAW,EAAA,EAAa;AAC7E,EAAA,IAAI,QAAA,IAAY,GAAG,OAAO,KAAA;AAC1B,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,UAAU,OAAO,KAAA;AAEpD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,OAAO,IAAI,IAAA,CAAK,CAAA,IAAA,KAAQ,yBAAyB,IAAA,EAAM,QAAA,GAAW,CAAC,CAAC,CAAA;AAAA,EACtE;AAEA,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAA8B,CAAA,EAAG;AAC7D,IAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AAC/C,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,KAAA,GAAS,IAAgC,GAAG,CAAA;AAClD,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,EAAM;AAC/C,MAAA,IAAI,wBAAA,CAAyB,KAAA,EAAO,QAAA,GAAW,CAAC,CAAA,EAAG;AACjD,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACpCA,IAAM,wBAAA,GAA2B,gBAAA;AAkB1B,SAAS,mBAAA,CAAoB,KAAA,EAAe,cAAA,GAAiB,KAAA,EAAgC;AAClG,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,cAAA,GACH,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE,GACzD,OAAO,KAAK,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,IAAI,wBAAA,CAAyB,IAAA,CAAK,KAAK,CAAA,EAAG;AACxC,IAAA,wBAAA,CAAyB,SAAA,GAAY,CAAA;AACrC,IAAA,YAAA,GAAe,IAAA;AAEf,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,wBAAwB,CAAA;AACpD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,YACX,IAAA,EAAM,kBAAA;AAAA,YACN,SAAS,wBAAA,CAAyB,MAAA;AAAA,YAClC,QAAA,EAAU;AAAA,WACX,CAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,wBAAA,CAAyB,SAAA,GAAY,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,wBAAA,EAA0B,EAAE,CAAA;AAExD,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,OAAO,EAAE,KAAA,EAAO,YAAA,EAAc,OAAA,EAAQ;AAAA,EACxC;AAEA,EAAA,OAAO,KAAA;AACT;AAaO,SAAS,gBAAgB,OAAA,EAAyD;AACvF,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC3C,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,SAAiC,EAAC;AAExC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AAClD,IAAA,MAAM,YAAA,GAAe,mBAAA,CAAoB,MAAA,CAAO,GAAG,CAAC,CAAA;AACpD,IAAA,MAAM,cAAA,GAAiB,mBAAA,CAAoB,MAAA,CAAO,KAAK,CAAC,CAAA;AACxD,IAAA,MAAA,CAAO,YAAY,CAAA,GAAI,cAAA;AAAA,EACzB;AAEA,EAAA,OAAO,MAAA;AACT;AASO,SAAS,sBAAsB,KAAA,EAAwB;AAC5D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAEtC,EAAA,wBAAA,CAAyB,SAAA,GAAY,CAAA;AACrC,EAAA,OAAO,wBAAA,CAAyB,KAAK,KAAK,CAAA;AAC5C;;;AC/EO,SAAS,QAAA,CACd,MAAA,EACA,MAAA,GAAsC,MAAA,EACtB;AAChB,EAAA,OAAO,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AAC1D,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,MAAM,CAAA,IAAK,EAAC;AAC7B,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,MAAM,YAAqC,EAAC;AAE5C,IAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AACnD,MAAA,MAAM,KAAA,GAAQ,KAAK,KAAK,CAAA;AACxB,MAAA,MAAM,MAAA,GAAS,aAAA,CAAc,KAAA,EAAO,KAAA,EAAO,KAAK,CAAA;AAEhD,MAAA,IAAI,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG;AAC5B,QAAA,MAAA,CAAO,IAAA,CAAK,GAAG,MAAA,CAAO,MAAM,CAAA;AAAA,MAC9B,CAAA,MAAA,IAAW,MAAA,CAAO,KAAA,KAAU,MAAA,EAAW;AACrC,QAAA,SAAA,CAAU,KAAK,IAAI,MAAA,CAAO,KAAA;AAAA,MAC5B;AAAA,IACF;AAEA,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,QAAQ,CAAA;AAC/B,MAAA;AAAA,IACF;AAGA,IAAA,GAAA,CAAI,MAAM,CAAA,GAAI,SAAA;AACd,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF;AAKA,SAAS,aAAA,CACP,KAAA,EACA,KAAA,EACA,KAAA,EACuC;AACvC,EAAA,MAAM,SAAmB,EAAC;AAG1B,EAAA,IAAI,MAAM,QAAA,KAAa,KAAA,KAAU,UAAa,KAAA,KAAU,IAAA,IAAQ,UAAU,EAAA,CAAA,EAAK;AAC7E,IAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,QAAA,CAAS,KAAK,CAAC,CAAA;AAC7C,IAAA,OAAO,EAAE,MAAA,EAAO;AAAA,EAClB;AAGA,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAC,EAAE;AAAA,EACtB;AAEA,EAAA,IAAI,UAAA,GAAsB,KAAA;AAC1B,EAAA,IAAI,OAAA,GAAU,IAAA;AAGd,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,QAAA;AACH,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAA,EAAO,QAAQ,CAAC,CAAA;AAC3D,QAAA,OAAA,GAAU,KAAA;AACV,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAM,GAAA,KAAQ,MAAA,IAAa,KAAA,CAAM,MAAA,GAAS,MAAM,GAAA,EAAK;AACvD,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,WAAW,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AAC1D,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,MAAM,GAAA,KAAQ,MAAA,IAAa,KAAA,CAAM,MAAA,GAAS,MAAM,GAAA,EAAK;AACvD,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,WAAW,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AAC1D,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,MAAM,OAAA,IAAW,CAAC,MAAM,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AAC/C,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,cAAA,CAAe,KAAK,CAAC,CAAA;AACnD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AAIA,MAAA,IAAI,OAAA,IAAW,MAAM,IAAA,IAAQ,CAAC,MAAM,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxD,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,aAAa,KAAA,EAAO,KAAA,CAAM,IAAI,CAAC,CAAA;AAC7D,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,OAAA,IAAW,KAAA,CAAM,QAAA,KAAa,KAAA,EAAO;AACvC,QAAA,UAAA,GAAa,eAAe,KAAK,CAAA;AAAA,MACnC;AACA,MAAA;AAAA,IAEF,KAAK,QAAA;AACH,MAAA,UAAA,GAAa,OAAO,KAAK,CAAA;AACzB,MAAA,IAAI,KAAA,CAAM,UAAoB,CAAA,EAAG;AAC/B,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAA,EAAO,QAAQ,CAAC,CAAA;AAC3D,QAAA,OAAA,GAAU,KAAA;AACV,QAAA;AAAA,MACF;AACA,MAAA,IAAI,KAAA,CAAM,GAAA,KAAQ,MAAA,IAAc,UAAA,GAAwB,MAAM,GAAA,EAAK;AACjE,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,UAAU,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACzD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,KAAA,CAAM,GAAA,KAAQ,MAAA,IAAc,UAAA,GAAwB,MAAM,GAAA,EAAK;AACjE,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,UAAU,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACzD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA;AAAA,IAEF,KAAK,SAAA;AACH,MAAA,IAAI,UAAU,MAAA,IAAU,KAAA,KAAU,QAAQ,KAAA,KAAU,CAAA,IAAK,UAAU,GAAA,EAAK;AACtE,QAAA,UAAA,GAAa,IAAA;AAAA,MACf,CAAA,MAAA,IAAW,UAAU,OAAA,IAAW,KAAA,KAAU,SAAS,KAAA,KAAU,CAAA,IAAK,UAAU,GAAA,EAAK;AAC/E,QAAA,UAAA,GAAa,KAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAA,EAAO,SAAS,CAAC,CAAA;AAC5D,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,CAAC,UAAA,CAAW,KAAA,CAAM,KAAK,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG;AACzC,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,aAAA,CAAc,KAAK,CAAC,CAAA;AAClD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,UAAA,GAAa,eAAe,MAAA,CAAO,KAAK,EAAE,WAAA,EAAY,CAAE,MAAM,CAAA;AAAA,MAChE;AACA,MAAA;AAAA,IAEF,KAAK,KAAA;AACH,MAAA,IAAI,CAAC,UAAA,CAAW,GAAA,CAAI,KAAK,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG;AACvC,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,WAAA,CAAY,KAAK,CAAC,CAAA;AAChD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,UAAA,GAAa,cAAA,CAAe,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,MAC3C;AACA,MAAA;AAAA,IAEF,KAAK,MAAA;AACH,MAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,KAAK,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG;AACxC,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAK,CAAC,CAAA;AACjD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAA,EAAO,OAAO,CAAC,CAAA;AAC1D,QAAA,OAAA,GAAU,KAAA;AACV,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAM,GAAA,KAAQ,MAAA,IAAa,KAAA,CAAM,MAAA,GAAS,MAAM,GAAA,EAAK;AACvD,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,UAAU,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACzD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA,IAAI,MAAM,GAAA,KAAQ,MAAA,IAAa,KAAA,CAAM,MAAA,GAAS,MAAM,GAAA,EAAK;AACvD,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,UAAU,KAAA,EAAO,KAAA,CAAM,GAAG,CAAC,CAAA;AACzD,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA;AAAA,IAEF,KAAK,QAAA;AACH,MAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,CAAM,QAAQ,KAAK,CAAA,IAAK,UAAU,IAAA,EAAM;AACvE,QAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,YAAA,CAAa,KAAA,EAAO,QAAQ,CAAC,CAAA;AAC3D,QAAA,OAAA,GAAU,KAAA;AAAA,MACZ;AACA,MAAA;AAAA;AAIJ,EAAA,IAAI,OAAA,IAAW,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,IAAA,KAAS,QAAA,IAAY,CAAC,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA,EAAG;AACxF,IAAA,MAAA,CAAO,KAAK,MAAA,CAAO,UAAA,CAAW,aAAa,KAAA,EAAO,KAAA,CAAM,IAAI,CAAC,CAAA;AAC7D,IAAA,OAAA,GAAU,KAAA;AAAA,EACZ;AAGA,EAAA,IAAI,OAAA,IAAW,MAAM,MAAA,EAAQ;AAC3B,IAAA,MAAM,YAAA,GAAe,KAAA,CAAM,MAAA,CAAO,UAAU,CAAA;AAC5C,IAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,+BAA+B,KAAK,CAAA,oFAAA;AAAA,OAEtC;AAAA,IACF;AACA,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,MAAA,CAAO,IAAA,CAAK,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,CAAa,SAAS,CAAA,GAAI,YAAA,GAAe,CAAA,EAAG,KAAK,CAAA,WAAA,CAAa,CAAA;AAC9G,MAAA,OAAA,GAAU,KAAA;AAAA,IACZ;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,UAAU,UAAA,GAAa,MAAA;AAAA,IAC9B;AAAA,GACF;AACF;AAMO,IAAM,eAAA,GAAkB;;;AC7N/B,IAAM,WAAA,GAAwC;AAAA;AAAA,EAE5C,YAAA,EAAc,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,GAAA,EAAM,GAAA,EAAM,GAAI,CAAC,CAAC,CAAA;AAAA,EAC9C,WAAA,EAAa,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,KAAM,EAAA,EAAM,EAAA,EAAM,EAAI,CAAC,CAAC,CAAA;AAAA,EACnD,WAAA,EAAa,CAAC,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAC,CAAA;AAAA,EAC1D,YAAA,EAAc,CAAC,MAAA,CAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA;AAAA,EAClC,WAAA,EAAa,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,EAAA,EAAM,EAAI,CAAC,CAAC,CAAA;AAAA,EACvC,iBAAiB,EAAC;AAAA;AAAA;AAAA,EAGlB,iBAAA,EAAmB,CAAC,MAAA,CAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,EACvC,iBAAA,EAAmB,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,IAAM,EAAA,EAAM,CAAA,EAAM,CAAI,CAAC,CAAC,CAAA;AAAA;AAAA,EAGzD,YAAA,EAAc,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,GAAA,EAAM,GAAI,CAAC,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,CAAC,GAAA,EAAM,GAAI,CAAC,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,CAAC,EAAA,EAAM,EAAA,EAAM,EAAI,CAAC,CAAC,CAAA;AAAA,EACpG,aAAa;AAAC;AAChB,CAAA;AAMA,IAAM,oBAAA,uBAA2B,GAAA,CAAI;AAAA;AAAA,EAEnC,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAChD,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EACtD,MAAA;AAAA,EAAQ,SAAA;AAAA,EAAW,MAAA;AAAA,EAAQ,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,OAAA;AAAA,EAC/C,KAAA;AAAA,EAAO,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,MAAA;AAAA;AAAA,EAExB,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,MAAA;AAAA,EAC7C,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,MAAA;AAAA,EACnC,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,MAAA;AAAA,EACzB,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,KAAA;AAAA;AAAA,EAEtB,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,QAAA;AAAA;AAAA,EAExB,WAAA;AAAA,EAAa,WAAA;AAAA;AAAA,EAEb,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,aAAA;AAAA,EAAe,MAAA;AAAA,EAAQ,OAAA;AAAA;AAAA,EAE/C,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA;AAAA,EAExB,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS;AAC7B,CAAC,CAAA;AAkDD,IAAM,gBAAA,GAAmB,IAAI,IAAA,GAAO,IAAA;AAqB7B,SAAS,iBAAiB,QAAA,EAA0B;AACzD,EAAA,IAAI,IAAA,GAAO,QAAA;AAGX,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAG7B,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAGlC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,kBAAA,EAAoB,EAAE,CAAA;AAG1C,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB,EAAE,CAAA;AAGvC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA;AAGnC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAG9B,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,QAAA,EAAU,GAAG,CAAA;AACjC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA;AAGlC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,GAAG,CAAA;AAGhC,EAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAGlC,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,KAAS,GAAA,EAAK;AACzB,IAAA,IAAA,GAAO,SAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA;AACT;AASA,SAAS,iBAAA,CAAkB,QAAgB,QAAA,EAA2B;AACpE,EAAA,MAAM,UAAA,GAAa,YAAY,QAAQ,CAAA;AACvC,EAAA,IAAI,CAAC,UAAA,IAAc,UAAA,CAAW,MAAA,KAAW,GAAG,OAAO,IAAA;AAEnD,EAAA,OAAO,UAAA,CAAW,KAAK,CAAA,GAAA,KAAO;AAC5B,IAAA,IAAI,MAAA,CAAO,MAAA,GAAS,GAAA,CAAI,MAAA,EAAQ,OAAO,KAAA;AACvC,IAAA,OAAO,OAAO,QAAA,CAAS,CAAA,EAAG,IAAI,MAAM,CAAA,CAAE,OAAO,GAAG,CAAA;AAAA,EAClD,CAAC,CAAA;AACH;AASA,SAAS,aAAa,QAAA,EAA0B;AAC9C,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,WAAA,CAAY,GAAG,CAAA;AACxC,EAAA,IAAI,OAAA,GAAU,GAAG,OAAO,EAAA;AACxB,EAAA,OAAO,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA,CAAE,WAAA,EAAY;AAC7C;AAKA,SAAS,mBAAmB,QAAA,EAA2B;AACrD,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA;AAChC,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AAG7B,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,MAAA,GAAS,GAAG,CAAA,EAAA,EAAK;AACzC,IAAA,MAAM,GAAA,GAAM,GAAA,GAAM,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AACvC,IAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,IAAA;AAAA,EAC5C;AACA,EAAA,OAAO,KAAA;AACT;AA8BO,SAAS,YAAA,CACd,IAAA,EACA,OAAA,GAA+B,EAAC,EACZ;AACpB,EAAA,MAAM;AAAA,IACJ,OAAA,GAAU,gBAAA;AAAA,IACV,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA,GAAmB,IAAA;AAAA,IACnB,kBAAA,GAAqB,IAAA;AAAA,IACrB,gBAAA,GAAmB,IAAA;AAAA,IACnB,qBAAA,GAAwB;AAAA,GAC1B,GAAI,OAAA;AAEJ,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,MAAM,iBAAA,GAAoB,gBAAA,CAAiB,IAAA,CAAK,QAAQ,CAAA;AACxD,EAAA,MAAM,SAAA,GAAY,aAAa,iBAAiB,CAAA;AAGhD,EAAA,IAAI,IAAA,CAAK,OAAO,OAAA,EAAS;AACvB,IAAA,MAAA,CAAO,KAAK,CAAA,UAAA,EAAa,IAAA,CAAK,IAAI,CAAA,iBAAA,EAAoB,OAAO,CAAA,MAAA,CAAQ,CAAA;AAAA,EACvE;AAEA,EAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,IAAA,MAAA,CAAO,KAAK,eAAe,CAAA;AAAA,EAC7B;AAGA,EAAA,IAAI,gBAAA,IAAoB,CAAC,SAAA,EAAW;AAClC,IAAA,MAAA,CAAO,KAAK,uBAAuB,CAAA;AAAA,EACrC;AAEA,EAAA,IAAI,gBAAA,IAAoB,SAAA,IAAa,oBAAA,CAAqB,GAAA,CAAI,SAAS,CAAA,EAAG;AACxE,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,sBAAA,EAAyB,SAAS,CAAA,gBAAA,CAAkB,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,qBAAA,IAAyB,kBAAA,CAAmB,iBAAiB,CAAA,EAAG;AAClE,IAAA,MAAA,CAAO,KAAK,yDAAyD,CAAA;AAAA,EACvE;AAEA,EAAA,IAAI,qBAAqB,SAAA,EAAW;AAClC,IAAA,MAAM,oBAAoB,iBAAA,CAAkB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa,CAAA;AACpE,IAAA,IAAI,CAAC,iBAAA,CAAkB,QAAA,CAAS,SAAS,CAAA,EAAG;AAC1C,MAAA,MAAA,CAAO,IAAA,CAAK,cAAc,SAAS,CAAA,2BAAA,EAA8B,kBAAkB,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IACjG;AAAA,EACF;AAGA,EAAA,IAAI,gBAAgB,CAAC,YAAA,CAAa,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,EAAG;AACzD,IAAA,MAAA,CAAO,IAAA,CAAK,cAAc,IAAA,CAAK,QAAQ,8BAA8B,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EAChG;AAGA,EAAA,IAAI,sBAAsB,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,MAAA,CAAO,SAAS,CAAA,EAAG;AAC/D,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG;AAClD,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,+CAAA,EAAkD,IAAA,CAAK,QAAQ,CAAA,CAAA,CAAG,CAAA;AAAA,IAChF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,OAAO,MAAA,KAAW,CAAA;AAAA,IACzB,MAAA;AAAA,IACA;AAAA,GACF;AACF;AAQO,SAAS,qBAAqB,QAAA,EAA2B;AAC9D,EAAA,MAAM,GAAA,GAAM,aAAa,QAAQ,CAAA;AACjC,EAAA,OAAO,GAAA,KAAQ,EAAA,IAAM,oBAAA,CAAqB,GAAA,CAAI,GAAG,CAAA;AACnD;;;AC/RO,SAAS,gBAAA,CAAiB,OAAA,GAAsB,EAAC,EAAe;AACrE,EAAA,MAAM;AAAA,IACJ,aAAa,EAAC;AAAA,IACd,YAAY,SAAA,CAAU,kBAAA;AAAA,IACtB,iBAAiB;AAAC,GACpB,GAAI,OAAA;AAGJ,EAAA,MAAM,aAAA,uBAAoB,GAAA,CAAI;AAAA,IAC5B,GAAG,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,cAAc,CAAA;AAAA,IACtC,GAAG,UAAA,CAAW,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa;AAAA,GACvC,CAAA;AAKD,EAAA,SAAS,MAAA,CAAO,GAAA,EAAc,KAAA,GAAQ,CAAA,EAAY;AAChD,IAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,mBAAA,EAAqB,OAAO,SAAA,CAAU,SAAA;AACxD,IAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,MAAA,EAAW,OAAO,GAAA;AAE9C,IAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,MAAA,OAAO,YAAA,CAAa,GAAA,EAAK,SAAA,EAAW,cAAc,CAAA;AAAA,IACpD;AAEA,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AAEpC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,MAAA,OAAO,IAAI,GAAA,CAAI,CAAA,IAAA,KAAQ,OAAO,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAA8B,CAAA,EAAG;AACzE,MAAA,IAAI,aAAA,CAAc,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AACxC,QAAA,MAAA,CAAO,GAAG,IAAI,SAAA,CAAU,WAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,EAAO,QAAQ,CAAC,CAAA;AAAA,MACvC;AAAA,IACF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAKA,EAAA,SAAS,GAAA,CAAI,KAAA,EAAe,OAAA,EAAiB,IAAA,EAAsB;AACjE,IAAA,MAAM,KAAA,GAAiC;AAAA,MACrC,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,KAAA;AAAA,MACA,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,SAAA,EAAW,cAAc;AAAA,KAC1D;AAEA,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,KAAA,CAAM,IAAA,GAAO,OAAO,IAAI,CAAA;AAAA,IAC1B;AAEA,IAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EACnC;AAEA,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,MAAM,CAAC,GAAA,EAAa,SAAmB,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC5D,MAAM,CAAC,GAAA,EAAa,SAAmB,GAAA,CAAI,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC5D,OAAO,CAAC,GAAA,EAAa,SAAmB,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI,CAAA;AAAA,IAC9D,OAAO,CAAC,GAAA,EAAa,SAAmB,GAAA,CAAI,OAAA,EAAS,KAAK,IAAI;AAAA,GAChE;AACF;AAMA,SAAS,YAAA,CAAa,GAAA,EAAa,SAAA,EAAmB,QAAA,EAA4B;AAIhF,EAAA,IAAI,IAAA,GAAO,IACR,OAAA,CAAQ,WAAA,EAAa,GAAG,CAAA,CACxB,OAAA,CAAQ,8CAA8C,EAAE,CAAA;AAG3D,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,SAAA,CAAU,WAAW,CAAA;AAAA,EACpD;AAGA,EAAA,IAAI,IAAA,CAAK,SAAS,SAAA,EAAW;AAC3B,IAAA,IAAA,GAAO,KAAK,SAAA,CAAU,CAAA,EAAG,SAAS,CAAA,GAAI,CAAA,GAAA,EAAM,UAAU,SAAS,CAAA,CAAA;AAAA,EACjE;AAEA,EAAA,OAAO,IAAA;AACT;AAQO,SAAS,cAAA,CAAe,aAAA,GAA0B,EAAC,EAA8B;AACtF,EAAA,MAAM,OAAA,uBAAc,GAAA,CAAI;AAAA,IACtB,GAAG,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,cAAc,CAAA;AAAA,IACtC,GAAG,aAAA,CAAc,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa;AAAA,GAC1C,CAAA;AAED,EAAA,SAAS,MAAA,CAAO,GAAA,EAAc,KAAA,GAAQ,CAAA,EAAY;AAChD,IAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,mBAAA,EAAqB,OAAO,SAAA,CAAU,SAAA;AACxD,IAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,MAAA,EAAW,OAAO,GAAA;AAC9C,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AAEpC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,MAAA,OAAO,IAAI,GAAA,CAAI,CAAA,IAAA,KAAQ,OAAO,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAA8B,CAAA,EAAG;AACzE,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AAClC,QAAA,MAAA,CAAO,GAAG,IAAI,SAAA,CAAU,WAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,EAAO,QAAQ,CAAC,CAAA;AAAA,MACvC;AAAA,IACF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,MAAA;AACT;AAMO,IAAM,OAAA,GAAU;;;ACvGhB,SAAS,KAAA,CAAM,OAAA,GAAwB,EAAC,EAAyB;AACtE,EAAA,MAAM,cAAgC,EAAC;AACvC,EAAA,MAAM,aAA6B,EAAC;AAGpC,EAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,EAAO;AAC7B,IAAA,MAAM,aAA4B,OAAO,OAAA,CAAQ,YAAY,QAAA,GACzD,OAAA,CAAQ,UACR,EAAC;AACL,IAAA,WAAA,CAAY,IAAA,CAAK,aAAA,CAAc,UAAU,CAAC,CAAA;AAAA,EAC5C;AAGA,EAAA,IAAI,OAAA,CAAQ,cAAc,KAAA,EAAO;AAC/B,IAAA,MAAM,gBAAkC,OAAO,OAAA,CAAQ,cAAc,QAAA,GACjE,OAAA,CAAQ,YACR,EAAC;AACL,IAAA,MAAM,WAAA,GAAc,kBAAkB,aAAa,CAAA;AACnD,IAAA,WAAA,CAAY,KAAK,WAAW,CAAA;AAC5B,IAAA,UAAA,CAAW,IAAA,CAAK,MAAM,WAAA,CAAY,KAAA,EAAO,CAAA;AAAA,EAC3C;AAGA,EAAA,IAAI,OAAA,CAAQ,aAAa,KAAA,EAAO;AAC9B,IAAA,MAAM,eAAgC,OAAO,OAAA,CAAQ,aAAa,QAAA,GAC9D,OAAA,CAAQ,WACR,EAAC;AACL,IAAA,WAAA,CAAY,IAAA,CAAK,eAAA,CAAgB,YAAY,CAAC,CAAA;AAAA,EAChD;AAGA,EAAA,MAAM,MAAA,GAAS,WAAA;AACf,EAAA,MAAA,CAAO,QAAQ,MAAM;AACnB,IAAA,KAAA,MAAW,MAAM,UAAA,EAAY;AAC3B,MAAA,EAAA,EAAG;AAAA,IACL;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,MAAA;AACT;AAGA,IAAM,gBAAA,GAAmB;AACzB,gBAAA,CAAiB,QAAA,GAAW,eAAA;AAC5B,gBAAA,CAAiB,SAAA,GAAY,iBAAA;AAC7B,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAC3B,gBAAA,CAAiB,QAAA,GAAW,QAAA;AAC5B,gBAAA,CAAiB,MAAA,GAAS,gBAAA;AAC1B,gBAAA,CAAiB,YAAA,GAAe,kBAAA;AAGhC,IAAO,YAAA,GAAQ;;;AC9Df,IAAM,kBAAkB,CAAC,KAAA,EAAO,QAAQ,KAAA,EAAO,OAAA,EAAS,QAAQ,QAAQ,CAAA;AACxE,IAAM,eAAA,GAAkB,CAAC,cAAA,EAAgB,eAAe,CAAA;AACxD,IAAM,eAAA,GAAkB,GAAA;AAKxB,SAAS,eAAA,CACP,eACA,OAAA,EACS;AAET,EAAA,IAAI,aAAA,KAAkB,QAAQ,OAAO,KAAA;AAErC,EAAA,IAAI,OAAA,KAAY,MAAM,OAAO,IAAA;AAE7B,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,OAAO,aAAA,KAAkB,OAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,OAAO,OAAA,CAAQ,SAAS,aAAa,CAAA;AAAA,EACvC;AAEA,EAAA,IAAI,mBAAmB,MAAA,EAAQ;AAC7B,IAAA,OAAO,OAAA,CAAQ,KAAK,aAAa,CAAA;AAAA,EACnC;AAEA,EAAA,IAAI,OAAO,YAAY,UAAA,EAAY;AACjC,IAAA,OAAO,QAAQ,aAAa,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,KAAA;AACT;AA6BO,SAAS,SAAS,OAAA,EAAsC;AAC7D,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,OAAA,GAAU,eAAA;AAAA,IACV,cAAA,GAAiB,eAAA;AAAA,IACjB,iBAAiB,EAAC;AAAA,IAClB,WAAA,GAAc,KAAA;AAAA,IACd,MAAA,GAAS,eAAA;AAAA,IACT,iBAAA,GAAoB;AAAA,GACtB,GAAI,OAAA;AAEJ,EAAA,OAAO,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAAuB;AAC1D,IAAA,MAAM,aAAA,GAAgB,IAAI,OAAA,CAAQ,MAAA;AAGlC,IAAA,GAAA,CAAI,SAAA,CAAU,QAAQ,QAAQ,CAAA;AAG9B,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAEA,IAAA,MAAM,OAAA,GAAU,eAAA,CAAgB,aAAA,EAAe,MAAM,CAAA;AAErD,IAAA,IAAI,CAAC,OAAA,EAAS;AAEZ,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAGA,IAAA,GAAA,CAAI,SAAA,CAAU,+BAA+B,aAAa,CAAA;AAE1D,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,GAAA,CAAI,SAAA,CAAU,oCAAoC,MAAM,CAAA;AAAA,IAC1D;AAEA,IAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,MAAA,GAAA,CAAI,SAAA,CAAU,+BAAA,EAAiC,cAAA,CAAe,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,IAC1E;AAGA,IAAA,IAAI,GAAA,CAAI,WAAW,SAAA,EAAW;AAC5B,MAAA,GAAA,CAAI,SAAA,CAAU,8BAAA,EAAgC,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA;AAChE,MAAA,GAAA,CAAI,SAAA,CAAU,8BAAA,EAAgC,cAAA,CAAe,IAAA,CAAK,IAAI,CAAC,CAAA;AACvE,MAAA,GAAA,CAAI,SAAA,CAAU,wBAAA,EAA0B,MAAA,CAAO,MAAM,CAAC,CAAA;AAEtD,MAAA,IAAI,iBAAA,EAAmB;AACrB,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AACpB,QAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF;AAMO,IAAM,UAAA,GAAa;;;AC/I1B,IAAM,YAAA,GAAe;AAAA,EACnB,SAAA,EAAW,YAAA;AAAA,EACX,MAAA,EAAQ,UAAA;AAAA,EACR,gBAAA,EAAkB,mBAAA;AAAA,EAClB,aAAA,EAAe,gBAAA;AAAA,EACf,cAAA,EAAgB;AAClB,CAAA;AAKO,SAAS,mBAAA,CACd,WACA,OAAA,EACQ;AACR,EAAA,MAAM,KAAA,GAAQ,UAAU,WAAA,EAAY;AACpC,EAAA,IAAI,MAAA,GAAS,SAAA;AAGb,EAAA,IAAI,QAAQ,QAAA,IAAY,CAAC,KAAA,CAAM,QAAA,CAAS,UAAU,CAAA,EAAG;AACnD,IAAA,MAAA,IAAU,YAAA,CAAa,SAAA;AAAA,EACzB;AAGA,EAAA,IAAI,QAAQ,MAAA,IAAU,CAAC,KAAA,CAAM,QAAA,CAAS,UAAU,CAAA,EAAG;AACjD,IAAA,MAAA,IAAU,YAAA,CAAa,MAAA;AAAA,EACzB;AAGA,EAAA,IAAI,QAAQ,QAAA,KAAa,KAAA,IAAS,CAAC,KAAA,CAAM,QAAA,CAAS,UAAU,CAAA,EAAG;AAC7D,IAAA,QAAQ,QAAQ,QAAA;AAAU,MACxB,KAAK,QAAA;AACH,QAAA,MAAA,IAAU,YAAA,CAAa,gBAAA;AACvB,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,MAAA,IAAU,YAAA,CAAa,cAAA;AAEvB,QAAA,IAAI,CAAC,MAAA,CAAO,WAAA,EAAY,CAAE,QAAA,CAAS,UAAU,CAAA,EAAG;AAC9C,UAAA,MAAA,IAAU,YAAA,CAAa,MAAA;AAAA,QACzB;AACA,QAAA;AAAA,MACF,KAAK,KAAA;AAAA,MACL;AACE,QAAA,MAAA,IAAU,YAAA,CAAa,aAAA;AACvB,QAAA;AAAA;AACJ,EACF;AAGA,EAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,IAAA,IAAI,KAAA,CAAM,QAAA,CAAS,OAAO,CAAA,EAAG;AAC3B,MAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,iBAAA,EAAmB,CAAA,OAAA,EAAU,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AAAA,IACrE,CAAA,MAAO;AACL,MAAA,MAAA,IAAU,CAAA,OAAA,EAAU,QAAQ,IAAI,CAAA,CAAA;AAAA,IAClC;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAqBO,SAAS,oBAAA,CAAqB,OAAA,GAA+B,EAAC,EAAmB;AACtF,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA;AAC9C,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,QAAA,EAAU,QAAQ,QAAA,IAAY,IAAA;AAAA,IAC9B,MAAA,EAAQ,QAAQ,MAAA,IAAU,YAAA;AAAA,IAC1B,QAAA,EAAU,QAAQ,QAAA,IAAY,KAAA;AAAA,IAC9B,MAAM,OAAA,CAAQ;AAAA,GAChB;AAEA,EAAA,OAAO,CAAC,IAAA,EAAe,GAAA,EAAe,IAAA,KAAuB;AAE3D,IAAA,MAAM,iBAAA,GAAoB,GAAA,CAAI,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA;AAEhD,IAAA,GAAA,CAAI,SAAA,GAAY,SAAS,gBAAA,CAAiB,IAAA,EAAc,KAAA,EAA4C;AAClG,MAAA,IAAI,IAAA,CAAK,WAAA,EAAY,KAAM,YAAA,EAAc;AACvC,QAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,UAAA,KAAA,GAAQ,KAAA,CAAM,IAAI,CAAA,CAAA,KAAK,mBAAA,CAAoB,OAAO,CAAC,CAAA,EAAG,QAAQ,CAAC,CAAA;AAAA,QACjE,CAAA,MAAO;AACL,UAAA,KAAA,GAAQ,mBAAA,CAAoB,MAAA,CAAO,KAAK,CAAA,EAAG,QAAQ,CAAA;AAAA,QACrD;AAAA,MACF;AACA,MAAA,OAAO,iBAAA,CAAkB,MAAM,KAAK,CAAA;AAAA,IACtC,CAAA;AAEA,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF;AAMO,IAAM,mBAAA,GAAsB;;;ACxE5B,SAAS,WAAA,CAAY,GAAA,EAAa,OAAA,GAA8B,EAAC,EAAsB;AAC5F,EAAA,MAAM;AAAA,IACJ,gBAAA,GAAmB,CAAC,OAAA,EAAS,QAAQ,CAAA;AAAA,IACrC,eAAe,EAAC;AAAA,IAChB,eAAe,EAAC;AAAA,IAChB,cAAA,GAAiB,KAAA;AAAA,IACjB,YAAA,GAAe;AAAA,GACjB,GAAI,OAAA;AAEJ,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,IAAA,OAAW,EAAA,EAAI;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,oCAAA,EAAqC;AAAA,EACrE;AAGA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,IAAI,GAAG,CAAA;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,8BAAA,EAA+B;AAAA,EAC/D;AAGA,EAAA,IAAI,CAAC,gBAAA,CAAiB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC/C,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA,qBAAA,EAAwB,MAAA,CAAO,QAAQ,CAAA,CAAA,EAAG;AAAA,EAC1E;AAGA,EAAA,IAAI,MAAA,CAAO,QAAA,IAAY,MAAA,CAAO,QAAA,EAAU;AACtC,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,0BAAA,EAA2B;AAAA,EAC3D;AAEA,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,WAAA,EAAY;AAG7C,EAAA,IAAI,aAAa,IAAA,CAAK,CAAA,CAAA,KAAK,aAAa,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AACxD,IAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AAAA,EACtB;AAGA,EAAA,IAAI,aAAa,IAAA,CAAK,CAAA,CAAA,KAAK,aAAa,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AACxD,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,CAAA,cAAA,EAAiB,QAAQ,CAAA,CAAA,EAAG;AAAA,EAC5D;AAGA,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,IACE,QAAA,KAAa,WAAA,IACb,QAAA,KAAa,WAAA,IACb,QAAA,KAAa,OAAA,IACb,QAAA,KAAa,KAAA,IACb,QAAA,KAAa,SAAA,IACb,QAAA,CAAS,QAAA,CAAS,YAAY,CAAA,EAC9B;AACA,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,kBAAA,EAAmB;AAAA,IACnD;AAGA,IAAA,IAAI,kCAAA,CAAmC,IAAA,CAAK,QAAQ,CAAA,EAAG;AACrD,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,kBAAA,EAAmB;AAAA,IACnD;AAAA,EACF;AAGA,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,MAAM,YAAA,GAAe,eAAe,QAAQ,CAAA;AAC5C,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,YAAA,EAAa;AAAA,IAC7C;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AACtB;AASO,SAAS,SAAA,CAAU,GAAA,EAAa,OAAA,GAA8B,EAAC,EAAY;AAChF,EAAA,OAAO,WAAA,CAAY,GAAA,EAAK,OAAO,CAAA,CAAE,IAAA;AACnC;AAMA,SAAS,eAAe,QAAA,EAAiC;AAEvD,EAAA,IAAI,iCAAA,CAAkC,IAAA,CAAK,QAAQ,CAAA,EAAG;AACpD,IAAA,OAAO,8BAAA;AAAA,EACT;AAGA,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,oCAAoC,CAAA;AACpE,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,QAAA,CAAS,CAAC,GAAG,EAAE,CAAA;AACvC,IAAA,IAAI,MAAA,IAAU,EAAA,IAAM,MAAA,IAAU,EAAA,EAAI;AAChC,MAAA,OAAO,iCAAA;AAAA,IACT;AAAA,EACF;AAGA,EAAA,IAAI,8BAAA,CAA+B,IAAA,CAAK,QAAQ,CAAA,EAAG;AACjD,IAAA,OAAO,kCAAA;AAAA,EACT;AAIA,EAAA,IAAI,8BAAA,CAA+B,IAAA,CAAK,QAAQ,CAAA,EAAG;AACjD,IAAA,OAAO,qCAAA;AAAA,EACT;AAGA,EAAA,IAAI,gCAAA,CAAiC,IAAA,CAAK,QAAQ,CAAA,EAAG;AACnD,IAAA,OAAO,qCAAA;AAAA,EACT;AAGA,EAAA,IACE,QAAA,KAAa,0BAAA,IACb,QAAA,KAAa,mBAAA,EACb;AACA,IAAA,OAAO,yBAAA;AAAA,EACT;AAGA,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAC5C,EAAA,IACE,IAAA,KAAS,KAAA,IACT,IAAA,KAAS,IAAA,IACT,KAAK,UAAA,CAAW,IAAI,CAAA,IACpB,IAAA,CAAK,WAAW,IAAI,CAAA,IACpB,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,EACtB;AACA,IAAA,OAAO,sBAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA;AACT;;;AC9JA,IAAM,mBAAA,GAAsB,oCAAA;AAG5B,IAAM,aAAA,GAAgB,WAAA;AAoBf,SAAS,gBAAA,CACd,GAAA,EACA,OAAA,GAAmC,EAAC,EACZ;AACxB,EAAA,MAAM;AAAA,IACJ,eAAe,EAAC;AAAA,IAChB,qBAAA,GAAwB,KAAA;AAAA,IACxB,gBAAA,GAAmB,CAAC,OAAA,EAAS,QAAQ;AAAA,GACvC,GAAI,OAAA;AAEJ,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,IAAA,OAAW,EAAA,EAAI;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,yCAAA,EAA0C;AAAA,EAC1E;AAGA,EAAA,MAAM,OAAA,GAAU,GAAA,CAAI,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAG7C,EAAA,IAAI,mBAAA,CAAoB,IAAA,CAAK,OAAO,CAAA,EAAG;AACrC,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,mBAAmB,CAAA;AAC/C,IAAA,OAAO,EAAE,MAAM,KAAA,EAAO,MAAA,EAAQ,uBAAuB,KAAA,CAAO,CAAC,CAAC,CAAA,CAAA,EAAG;AAAA,EACnE;AAIA,EAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,EAAG;AAC5B,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,8DAAA,EAA+D;AAAA,EAC/F;AAGA,EAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,EAAG;AAC5B,IAAA,IAAI,CAAC,qBAAA,EAAuB;AAE1B,MAAA,MAAMA,KAAAA,GAAO,YAAY,OAAO,CAAA;AAChC,MAAA,IAAIA,KAAAA,IAAQ,aAAa,IAAA,CAAK,CAAA,CAAA,KAAKA,UAAS,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AAC5D,QAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AAAA,MACtB;AACA,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,4CAAA,EAA6C;AAAA,IAC7E;AACA,IAAA,MAAM,IAAA,GAAO,YAAY,OAAO,CAAA;AAChC,IAAA,IAAI,IAAA,IAAQ,YAAA,CAAa,MAAA,GAAS,CAAA,IAAK,CAAC,YAAA,CAAa,IAAA,CAAK,CAAA,CAAA,KAAK,IAAA,KAAS,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AACxF,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,4CAAA,EAA6C;AAAA,IAC7E;AACA,IAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AAAA,EACtB;AAGA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAI,IAAI,OAAO,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AAAA,EACtB;AAIA,EAAA,IAAI,CAAC,gBAAA,CAAiB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC/C,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA,qBAAA,EAAwB,MAAA,CAAO,QAAQ,CAAA,CAAA,EAAG;AAAA,EAC1E;AAGA,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,WAAA,EAAY;AAC7C,EAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAC7B,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,mCAAA,EAAoC;AAAA,EACpE;AAEA,EAAA,IAAI,CAAC,aAAa,IAAA,CAAK,CAAA,CAAA,KAAK,aAAa,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AACzD,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,CAAA,kBAAA,EAAqB,QAAQ,CAAA,CAAA,EAAG;AAAA,EAChE;AAEA,EAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AACtB;AASO,SAAS,cAAA,CAAe,GAAA,EAAa,OAAA,GAAmC,EAAC,EAAY;AAC1F,EAAA,OAAO,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA,CAAE,IAAA;AACxC;AAKA,SAAS,YAAY,GAAA,EAA4B;AAE/C,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,iBAAiB,CAAA;AACzC,EAAA,OAAO,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE,aAAY,GAAI,IAAA;AAC1C;;;AC1IO,IAAM,cAAN,MAA4C;AAAA,EAKjD,WAAA,CAAY,QAAA,GAAmB,UAAA,CAAW,iBAAA,EAAmB;AAJ7D,IAAA,IAAA,CAAQ,KAAA,uBAAyC,GAAA,EAAI;AACrD,IAAA,IAAA,CAAQ,eAAA,GAAyD,IAAA;AAI/D,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,QAAQ,CAAA,IAAK,QAAA,GAAW,WAAW,aAAA,EAAe;AACrE,MAAA,MAAM,IAAI,UAAA;AAAA,QACR,CAAA,iDAAA,EAAoD,UAAA,CAAW,aAAa,CAAA,MAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,OAC/F;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,YAAA,EAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAA,GAAqB;AAI3B,IAAA,MAAM,cAAA,GAAiB,GAAA;AACvB,IAAA,MAAM,cAAA,GAAiB,GAAA;AACvB,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,IAAA,CAAK,QAAA,EAAU,cAAc,CAAA,EAAG,cAAc,CAAA;AAElF,IAAA,IAAA,CAAK,eAAA,GAAkB,YAAY,MAAM;AACvC,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,IAAA,CAAK,KAAA,CAAM,SAAQ,EAAG;AAC/C,QAAA,IAAI,KAAA,CAAM,YAAY,GAAA,EAAK;AACzB,UAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,QACvB;AAAA,MACF;AAAA,IACF,GAAG,SAAS,CAAA;AAGZ,IAAA,IAAI,OAAO,IAAA,CAAK,eAAA,CAAgB,KAAA,KAAU,UAAA,EAAY;AACpD,MAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,GAAA,EAA6C;AACrD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAGnB,IAAA,IAAI,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,EAAG;AAChC,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,MAAM,GAAA,CAAI,GAAA,EAAa,KAAA,EAAsC;AAC3D,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC3B;AAAA,EAEA,MAAM,UAAU,GAAA,EAA8B;AAC5C,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAEhC,IAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,SAAA,GAAY,GAAA,EAAK;AAEnC,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,EAAE,KAAA,EAAO,GAAG,SAAA,EAAW,GAAA,GAAM,IAAA,CAAK,QAAA,EAAU,CAAA;AAChE,MAAA,OAAO,CAAA;AAAA,IACT;AAEA,IAAA,KAAA,CAAM,KAAA,EAAA;AACN,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AAAA,EAEA,MAAM,UAAU,GAAA,EAA4B;AAC1C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,KAAA,IAAS,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG;AAC5B,MAAA,KAAA,CAAM,KAAA,EAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,GAAA,EAA4B;AACtC,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,EACvB;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI,KAAK,eAAA,EAAiB;AACxB,MAAA,aAAA,CAAc,KAAK,eAAe,CAAA;AAClC,MAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAAA,IACzB;AACA,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,IAAA,GAAe;AACjB,IAAA,OAAO,KAAK,KAAA,CAAM,IAAA;AAAA,EACpB;AACF;;;ACjEO,IAAM,aAAN,MAA2C;AAAA,EAMhD,YAAY,OAAA,EAA4B;AACtC,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,MAAA,IAAU,WAAA;AAChC,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,QAAA,IAAY,UAAA,CAAW,iBAAA;AAC/C,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,WAAW,GAAI,CAAA;AAAA,EACjD;AAAA,EAEQ,OAAO,GAAA,EAAqB;AAClC,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,EAAG,GAAG,CAAA,CAAA;AAAA,EAC7B;AAAA,EAEA,MAAM,IAAI,GAAA,EAA6C;AACrD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAEhC,IAAA,MAAM,CAAC,QAAA,EAAU,GAAG,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MACxC,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAA;AAAA,MACxB,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ;AAAA,KACzB,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,IAAY,GAAA,GAAM,CAAA,EAAG;AACxB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,QAAA,EAAU,EAAE,CAAA;AACnC,IAAA,IAAI,KAAA,CAAM,KAAK,CAAA,EAAG;AAEhB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO;AAAA,MACL,KAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAK,GAAA,GAAM;AAAA,KACjC;AAAA,EACF;AAAA,EAEA,MAAM,GAAA,CAAI,GAAA,EAAa,KAAA,EAAsC;AAC3D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAGhC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAA,CAAA,CAAM,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,IAAK,GAAI,CAAC,CAAA;AAC3E,IAAA,MAAM,IAAA,CAAK,OAAO,KAAA,CAAM,QAAA,EAAU,QAAQ,KAAA,CAAM,KAAA,CAAM,UAAU,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,UAAU,GAAA,EAA8B;AAC5C,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAGhC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;AAK7C,IAAA,IAAI,UAAU,CAAA,EAAG;AACf,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,QAAA,EAAU,KAAK,SAAS,CAAA;AAAA,IACnD;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,GAAA,EAA4B;AAC1C,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAChC,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA;AAAA,EACjC;AAAA,EAEA,MAAM,MAAM,GAAA,EAA4B;AACtC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAChC,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAA;AAAA,EAChC;AAAA,EAEA,MAAM,KAAA,GAAuB;AAAA,EAG7B;AACF;AASO,SAAS,iBAAiB,OAAA,EAAwC;AACvE,EAAA,OAAO,IAAI,WAAW,OAAO,CAAA;AAC/B","file":"index.js","sourcesContent":["/**\r\n * @module @arcis/node/core/constants\r\n * Named constants for Arcis - no magic numbers\r\n */\r\n\r\n// =============================================================================\r\n// INPUT LIMITS\r\n// =============================================================================\r\nexport const INPUT = {\r\n /** Default maximum input size (1MB) */\r\n DEFAULT_MAX_SIZE: 1_000_000,\r\n /** Maximum recursion depth for nested objects */\r\n MAX_RECURSION_DEPTH: 10,\r\n} as const;\r\n\r\n// =============================================================================\r\n// RATE LIMITING\r\n// =============================================================================\r\nexport const RATE_LIMIT = {\r\n /** Default window size (1 minute) */\r\n DEFAULT_WINDOW_MS: 60_000,\r\n /** Default max requests per window */\r\n DEFAULT_MAX_REQUESTS: 100,\r\n /** Default HTTP status code for rate limited responses */\r\n DEFAULT_STATUS_CODE: 429,\r\n /** Default error message */\r\n DEFAULT_MESSAGE: 'Too many requests, please try again later.',\r\n /** Minimum window size (1 second) */\r\n MIN_WINDOW_MS: 1_000,\r\n /** Maximum window size (24 hours) */\r\n MAX_WINDOW_MS: 86_400_000,\r\n} as const;\r\n\r\n// =============================================================================\r\n// SECURITY HEADERS\r\n// =============================================================================\r\nexport const HEADERS = {\r\n /** Default Content Security Policy */\r\n DEFAULT_CSP: [\r\n \"default-src 'self'\",\r\n \"script-src 'self'\",\r\n \"style-src 'self' 'unsafe-inline'\",\r\n \"img-src 'self' data: https:\",\r\n \"font-src 'self'\",\r\n \"object-src 'none'\",\r\n \"frame-ancestors 'none'\",\r\n ].join('; '),\r\n /** Default HSTS max age (1 year in seconds) */\r\n HSTS_MAX_AGE: 31_536_000,\r\n /** Default X-Frame-Options value */\r\n FRAME_OPTIONS: 'DENY' as const,\r\n /** Default X-Content-Type-Options value */\r\n CONTENT_TYPE_OPTIONS: 'nosniff',\r\n /** Default Referrer-Policy value */\r\n REFERRER_POLICY: 'strict-origin-when-cross-origin',\r\n /** Default Permissions-Policy value */\r\n PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\r\n /** Default Cache-Control value for security */\r\n CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\r\n} as const;\r\n\r\n// =============================================================================\r\n// XSS PATTERNS (ReDoS-safe)\r\n// =============================================================================\r\n\r\n/**\r\n * Detection patterns — used to flag whether a string contains XSS payloads.\r\n * Must stay in sync with XSS_REMOVE_PATTERNS below.\r\n */\r\nexport const XSS_PATTERNS = [\r\n /** Script tags (ReDoS-safe version) */\r\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\r\n /** javascript: protocol (allow optional spaces before colon) */\r\n /javascript\\s*:/gi,\r\n /** vbscript: protocol */\r\n /vbscript\\s*:/gi,\r\n /** Event handlers (onclick, onerror, etc.) — any separator before attribute */\r\n /(?:[\\s/])on\\w+\\s*=/gi,\r\n /** iframe tags */\r\n /<iframe/gi,\r\n /** object tags */\r\n /<object/gi,\r\n /** embed tags */\r\n /<embed/gi,\r\n /** data: URIs (only dangerous ones, avoid false positives) */\r\n /(?:^|[\\s\"'=])data:/gi,\r\n /** URL-encoded script tags */\r\n /%3Cscript/gi,\r\n /** SVG with onload */\r\n /<svg[^>]*onload/gi,\r\n] as const;\r\n\r\n/**\r\n * Removal patterns — used by sanitizeXss() to strip dangerous content.\r\n * More targeted than XSS_PATTERNS: each pattern captures the full dangerous\r\n * substring (tag, attribute + value, protocol) so it can be replaced safely.\r\n * Must stay in sync with XSS_PATTERNS above.\r\n */\r\nexport const XSS_REMOVE_PATTERNS = [\r\n /** Full script blocks (content + tags) */\r\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\r\n /** Standalone/unclosed script tags */\r\n /<script[^>]*>/gi,\r\n /** iframe — full block and partial/unclosed */\r\n /<iframe[^>]*>[\\s\\S]*?<\\/iframe>/gi,\r\n /<iframe[^>]*/gi,\r\n /** object — full block and partial/unclosed */\r\n /<object[^>]*>[\\s\\S]*?<\\/object>/gi,\r\n /<object[^>]*/gi,\r\n /** embed tags */\r\n /<embed[^>]*/gi,\r\n /** SVG with inline event handlers */\r\n /<svg[^>]*onload[^>]*>/gi,\r\n /** URL-encoded script tags */\r\n /%3Cscript/gi,\r\n /** Event handlers with quoted values: onclick=\"...\", onerror='...' */\r\n /(?:[\\s/])on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi,\r\n /** Event handlers with unquoted values: onload=value */\r\n /(?:[\\s/])on\\w+\\s*=\\s*[^\\s>]*/gi,\r\n /** javascript: and vbscript: protocols (allow optional spaces before colon) */\r\n /javascript\\s*:/gi,\r\n /vbscript\\s*:/gi,\r\n /** data: URIs with HTML/script content */\r\n /data\\s*:\\s*text\\/html[^>\\s]*/gi,\r\n] as const;\r\n\r\n// =============================================================================\r\n// SQL INJECTION PATTERNS\r\n// =============================================================================\r\nexport const SQL_PATTERNS = [\r\n /** SQL keywords */\r\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\\b)/gi,\r\n /** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */\r\n /(--|\\/\\*|\\*\\/|#)/g,\r\n /** SQL statement separators */\r\n /(;|\\|\\||&&)/g,\r\n /** Boolean injection: OR 1=1 */\r\n /\\bOR\\s+\\d+\\s*=\\s*\\d+/gi,\r\n /** Boolean injection: OR 'a'='a' or OR \"a\"=\"a\" (including mixed quotes) */\r\n /\\bOR\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\r\n /\\bOR\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\r\n /** Boolean injection: AND 1=1 */\r\n /\\bAND\\s+\\d+\\s*=\\s*\\d+/gi,\r\n /** Boolean injection: AND 'a'='a' or AND \"a\"=\"a\" (including mixed quotes) */\r\n /\\bAND\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\r\n /\\bAND\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\r\n /** Time-based blind: SLEEP() */\r\n /\\bSLEEP\\s*\\(\\s*\\d+\\s*\\)/gi,\r\n /** Time-based blind: BENCHMARK() */\r\n /\\bBENCHMARK\\s*\\(/gi,\r\n] as const;\r\n\r\n// =============================================================================\r\n// PATH TRAVERSAL PATTERNS\r\n// =============================================================================\r\nexport const PATH_PATTERNS = [\r\n /** Unix path traversal */\r\n /\\.\\.\\//g,\r\n /** Windows path traversal */\r\n /\\.\\.\\\\/g,\r\n /** URL-encoded traversal (%2e%2e) */\r\n /%2e%2e/gi,\r\n /** Double URL-encoded traversal (%252e) */\r\n /%252e/gi,\r\n /** Mixed encoding: ..%2F */\r\n /\\.\\.%2F/gi,\r\n /** Mixed encoding: %2e./ and .%2e/ */\r\n /%2e\\.[\\\\/]/gi,\r\n /\\.%2e[\\\\/]/gi,\r\n /** Fully URL-encoded: %2e%2e%2f */\r\n /%2e%2e%2f/gi,\r\n /** Null byte injection in paths */\r\n /\\0/g,\r\n] as const;\r\n\r\n// =============================================================================\r\n// COMMAND INJECTION PATTERNS\r\n// =============================================================================\r\nexport const COMMAND_PATTERNS = [\r\n /**\r\n * Shell metacharacters that enable command chaining/substitution.\r\n * Bare ( and ) are excluded — they appear in common legitimate values\r\n * (function calls in code fields, math expressions, etc.).\r\n * Command substitution is caught by the $( combined pattern below.\r\n * NOTE: ';', '&', '|' may appear in legitimate URL query strings\r\n * and Markdown; consider disabling command checking (command: false)\r\n * for fields that intentionally allow those characters.\r\n */\r\n /[;&|`]/g,\r\n /** Command substitution: $( ... ) — matched as a pair to reduce false positives */\r\n /\\$\\(/g,\r\n] as const;\r\n\r\n// =============================================================================\r\n// DANGEROUS KEYS\r\n// =============================================================================\r\n\r\n/**\r\n * Prototype pollution keys to block.\r\n * Stored lowercase — always compare with key.toLowerCase().\r\n *\r\n * Includes:\r\n * - __proto__: direct prototype assignment\r\n * - constructor: access to constructor.prototype chain\r\n * - prototype: direct prototype property\r\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\r\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\r\n */\r\nexport const DANGEROUS_PROTO_KEYS = new Set([\r\n '__proto__',\r\n 'constructor',\r\n 'prototype',\r\n '__definegetter__',\r\n '__definesetter__',\r\n '__lookupgetter__',\r\n '__lookupsetter__',\r\n]);\r\n\r\n/** MongoDB operators to block */\r\nexport const NOSQL_DANGEROUS_KEYS = new Set([\r\n // Comparison\r\n '$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin',\r\n // Logical\r\n '$and', '$or', '$not', '$nor',\r\n // Element / evaluation\r\n '$exists', '$type', '$regex', '$where', '$expr', '$mod', '$text',\r\n // Array\r\n '$elemMatch', '$all', '$size',\r\n // JavaScript execution (critical)\r\n '$function', '$accumulator',\r\n // Aggregation pipeline operators (injectable via $lookup etc.)\r\n '$lookup', '$match', '$project', '$group', '$sort', '$limit', '$skip',\r\n '$unwind', '$addFields', '$replaceRoot',\r\n]);\r\n\r\n// =============================================================================\r\n// REDACTION\r\n// =============================================================================\r\nexport const REDACTION = {\r\n /** Replacement text for redacted values */\r\n REPLACEMENT: '[REDACTED]',\r\n /** Truncation indicator */\r\n TRUNCATED: '[TRUNCATED]',\r\n /** Max depth indicator */\r\n MAX_DEPTH: '[MAX_DEPTH]',\r\n /** Default max message length */\r\n DEFAULT_MAX_LENGTH: 10_000,\r\n /** Default sensitive keys to redact */\r\n SENSITIVE_KEYS: new Set([\r\n 'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\r\n 'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\r\n 'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\r\n 'privateKey', 'access_token', 'accessToken', 'refresh_token',\r\n 'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\r\n 'credentials', 'x-api-key', 'x-auth-token',\r\n ]),\r\n} as const;\r\n\r\n// =============================================================================\r\n// VALIDATION PATTERNS\r\n// =============================================================================\r\nexport const VALIDATION = {\r\n /**\r\n * Email regex pattern.\r\n * Rejects consecutive dots in local part (e.g. test..foo@example.com),\r\n * leading/trailing dots, and other common invalid forms.\r\n */\r\n EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\r\n /**\r\n * URL regex pattern.\r\n * Only allows http:// and https:// — explicitly rejects javascript:,\r\n * data:, vbscript:, and other dangerous URI schemes.\r\n */\r\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/,\r\n /** UUID regex pattern (v4) */\r\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\r\n} as const;\r\n\r\n// =============================================================================\r\n// ERROR MESSAGES\r\n// =============================================================================\r\nexport const ERRORS = {\r\n /** Generic error message (production) */\r\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\r\n /** Input too large error */\r\n INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\r\n /** Validation error messages */\r\n VALIDATION: {\r\n REQUIRED: (field: string) => `${field} is required`,\r\n INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\r\n MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\r\n MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\r\n MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\r\n MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\r\n INVALID_FORMAT: (field: string) => `${field} format is invalid`,\r\n INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\r\n INVALID_URL: (field: string) => `${field} must be a valid URL`,\r\n INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\r\n INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\r\n MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\r\n MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\r\n },\r\n} as const;\r\n\r\n// =============================================================================\r\n// BLOCKED TEXT (for sanitizer replacements)\r\n// =============================================================================\r\nexport const BLOCKED = '[BLOCKED]' as const;\r\n","/**\r\n * @module @arcis/node/middleware/headers\r\n * Security headers middleware\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\nimport { HEADERS } from '../core/constants';\r\nimport type { HeaderOptions, HstsOptions } from '../core/types';\r\n\r\n/**\r\n * Create Express middleware for security headers.\r\n * Sets CSP, HSTS, X-Frame-Options, and other security headers.\r\n * \r\n * @param options - Header configuration\r\n * @returns Express middleware\r\n * \r\n * @example\r\n * app.use(createHeaders());\r\n * \r\n * @example\r\n * app.use(createHeaders({\r\n * frameOptions: 'SAMEORIGIN',\r\n * contentSecurityPolicy: \"default-src 'self'\"\r\n * }));\r\n */\r\nexport function createHeaders(options: HeaderOptions = {}): RequestHandler {\r\n const {\r\n contentSecurityPolicy = true,\r\n xssFilter = true,\r\n noSniff = true,\r\n frameOptions = HEADERS.FRAME_OPTIONS,\r\n hsts = true,\r\n referrerPolicy = HEADERS.REFERRER_POLICY,\r\n permissionsPolicy = HEADERS.PERMISSIONS_POLICY,\r\n cacheControl = true,\r\n } = options;\r\n\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n // Content Security Policy\r\n if (contentSecurityPolicy) {\r\n const csp = typeof contentSecurityPolicy === 'string' \r\n ? contentSecurityPolicy \r\n : HEADERS.DEFAULT_CSP;\r\n res.setHeader('Content-Security-Policy', csp);\r\n }\r\n\r\n // X-XSS-Protection (legacy but still useful for older browsers)\r\n if (xssFilter) {\r\n res.setHeader('X-XSS-Protection', '1; mode=block');\r\n }\r\n\r\n // Prevent MIME type sniffing\r\n if (noSniff) {\r\n res.setHeader('X-Content-Type-Options', HEADERS.CONTENT_TYPE_OPTIONS);\r\n }\r\n\r\n // Clickjacking protection\r\n if (frameOptions) {\r\n res.setHeader('X-Frame-Options', frameOptions);\r\n }\r\n\r\n // HTTPS enforcement (HSTS)\r\n // Only send HSTS over HTTPS — sending it over HTTP can brick HTTP-only\r\n // development servers and confuses browsers that cache the directive.\r\n // X-Forwarded-Proto is client-supplied so we validate the extracted value\r\n // is exactly 'https' or 'http' before trusting it.\r\n const forwardedProto = (req.headers['x-forwarded-proto'] as string | undefined)\r\n ?.split(',')[0]\r\n .trim()\r\n .toLowerCase();\r\n const trustedForwardedProto = forwardedProto === 'https' || forwardedProto === 'http'\r\n ? forwardedProto\r\n : undefined;\r\n const isHttps = req.secure || trustedForwardedProto === 'https';\r\n\r\n if (hsts && isHttps) {\r\n const hstsOpts: HstsOptions = typeof hsts === 'object' ? hsts : {};\r\n const maxAge = hstsOpts.maxAge ?? HEADERS.HSTS_MAX_AGE;\r\n const includeSubDomains = hstsOpts.includeSubDomains !== false;\r\n const preload = hstsOpts.preload === true;\r\n\r\n let hstsValue = `max-age=${maxAge}`;\r\n if (includeSubDomains) hstsValue += '; includeSubDomains';\r\n if (preload) hstsValue += '; preload';\r\n\r\n res.setHeader('Strict-Transport-Security', hstsValue);\r\n }\r\n\r\n // Referrer Policy\r\n if (referrerPolicy) {\r\n res.setHeader('Referrer-Policy', referrerPolicy);\r\n }\r\n\r\n // Permissions Policy\r\n if (permissionsPolicy) {\r\n res.setHeader('Permissions-Policy', permissionsPolicy);\r\n }\r\n\r\n // Additional security headers\r\n res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');\r\n\r\n // Cache-Control headers\r\n if (cacheControl) {\r\n const cacheControlValue = typeof cacheControl === 'string'\r\n ? cacheControl\r\n : HEADERS.CACHE_CONTROL;\r\n res.setHeader('Cache-Control', cacheControlValue);\r\n res.setHeader('Pragma', 'no-cache');\r\n res.setHeader('Expires', '0');\r\n }\r\n\r\n // Remove fingerprinting headers\r\n res.removeHeader('X-Powered-By');\r\n\r\n next();\r\n };\r\n}\r\n\r\n/**\r\n * Alias for createHeaders\r\n * @see createHeaders\r\n */\r\nexport const securityHeaders = createHeaders;\r\n","/**\r\n * @module @arcis/node/middleware/rate-limit\r\n * Rate limiting middleware\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\nimport { RATE_LIMIT } from '../core/constants';\r\nimport type { RateLimitOptions, RateLimiterMiddleware, RateLimitEntry } from '../core/types';\r\n\r\n/** In-memory rate limit store */\r\ninterface InMemoryRateLimitStore {\r\n [key: string]: RateLimitEntry;\r\n}\r\n\r\n/**\r\n * Create Express middleware for rate limiting.\r\n * \r\n * @param options - Rate limit configuration\r\n * @returns Express middleware with cleanup method\r\n * \r\n * @example\r\n * app.use(createRateLimiter({ max: 100, windowMs: 60000 }));\r\n * \r\n * @example\r\n * // Skip rate limiting for certain routes\r\n * app.use(createRateLimiter({\r\n * max: 50,\r\n * skip: (req) => req.path === '/health'\r\n * }));\r\n * \r\n * @example\r\n * // Cleanup on shutdown\r\n * const limiter = createRateLimiter();\r\n * app.use(limiter);\r\n * process.on('SIGTERM', () => limiter.close());\r\n */\r\nexport function createRateLimiter(options: RateLimitOptions = {}): RateLimiterMiddleware {\r\n const {\r\n max = RATE_LIMIT.DEFAULT_MAX_REQUESTS,\r\n windowMs = RATE_LIMIT.DEFAULT_WINDOW_MS,\r\n message = RATE_LIMIT.DEFAULT_MESSAGE,\r\n statusCode = RATE_LIMIT.DEFAULT_STATUS_CODE,\r\n keyGenerator = (req) => {\r\n const ip = req.ip ?? req.socket?.remoteAddress;\r\n if (!ip) {\r\n console.warn(\r\n '[arcis] Rate limiter: cannot resolve client IP. All unresolvable clients share ' +\r\n 'one counter. Set Express trust proxy if behind a reverse proxy.'\r\n );\r\n return 'unknown';\r\n }\r\n return ip;\r\n },\r\n skip,\r\n store: externalStore,\r\n } = options;\r\n\r\n // Object.create(null) avoids prototype pollution if keyGenerator ever\r\n // returns '__proto__', 'constructor', or 'prototype'.\r\n const inMemoryStore = Object.create(null) as InMemoryRateLimitStore;\r\n\r\n // Cleanup interval for in-memory store (only create if not using external store)\r\n let cleanupInterval: ReturnType<typeof setInterval> | null = null;\r\n \r\n if (!externalStore) {\r\n cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const key of Object.keys(inMemoryStore)) {\r\n if (inMemoryStore[key].resetTime < now) {\r\n delete inMemoryStore[key];\r\n }\r\n }\r\n }, windowMs);\r\n\r\n // Prevent interval from keeping the process alive (Node.js only)\r\n if (typeof cleanupInterval.unref === 'function') {\r\n cleanupInterval.unref();\r\n }\r\n }\r\n\r\n const handler: RequestHandler = async (req: Request, res: Response, next: NextFunction) => {\r\n try {\r\n if (skip?.(req)) {\r\n return next();\r\n }\r\n\r\n const key = keyGenerator(req);\r\n const now = Date.now();\r\n\r\n let count: number;\r\n let resetTime: number;\r\n\r\n if (externalStore) {\r\n // Use external store (e.g., Redis)\r\n const entry = await externalStore.get(key);\r\n if (!entry || entry.resetTime < now) {\r\n await externalStore.set(key, { count: 1, resetTime: now + windowMs });\r\n count = 1;\r\n resetTime = now + windowMs;\r\n } else {\r\n count = await externalStore.increment(key);\r\n resetTime = entry.resetTime;\r\n }\r\n } else {\r\n // Use in-memory store\r\n if (!inMemoryStore[key] || inMemoryStore[key].resetTime < now) {\r\n inMemoryStore[key] = { count: 1, resetTime: now + windowMs };\r\n } else {\r\n inMemoryStore[key].count++;\r\n }\r\n count = inMemoryStore[key].count;\r\n resetTime = inMemoryStore[key].resetTime;\r\n }\r\n\r\n const remaining = Math.max(0, max - count);\r\n const resetSeconds = Math.ceil((resetTime - now) / 1000);\r\n\r\n // Set rate limit headers\r\n res.setHeader('X-RateLimit-Limit', max.toString());\r\n res.setHeader('X-RateLimit-Remaining', remaining.toString());\r\n res.setHeader('X-RateLimit-Reset', resetSeconds.toString());\r\n\r\n if (count > max) {\r\n res.setHeader('Retry-After', resetSeconds.toString());\r\n res.status(statusCode).json({\r\n error: message,\r\n retryAfter: resetSeconds,\r\n });\r\n return;\r\n }\r\n\r\n next();\r\n } catch (error) {\r\n // Log error but fail open (allow request through) to prevent DoS\r\n console.error('[arcis] Rate limiter error:', error);\r\n next();\r\n }\r\n };\r\n\r\n // Attach close method for cleanup\r\n const middleware = handler as RateLimiterMiddleware;\r\n middleware.close = () => {\r\n if (cleanupInterval) {\r\n clearInterval(cleanupInterval);\r\n cleanupInterval = null;\r\n }\r\n };\r\n\r\n return middleware;\r\n}\r\n\r\n/**\r\n * Alias for createRateLimiter\r\n * @see createRateLimiter\r\n */\r\nexport const rateLimit = createRateLimiter;\r\n","/**\r\n * @module @arcis/node/middleware/error-handler\r\n * Production-safe error handler middleware\r\n */\r\n\r\nimport type { Request, Response, NextFunction } from 'express';\r\nimport { ERRORS } from '../core/constants';\r\nimport type { ErrorHandlerOptions, HttpError } from '../core/types';\r\n\r\n/**\r\n * Patterns that indicate database or infrastructure internals in error messages.\r\n * When detected, the message is replaced with a generic error to prevent info leakage.\r\n */\r\nconst SENSITIVE_ERROR_PATTERNS: RegExp[] = [\r\n // SQL database errors\r\n /\\b(SQLITE_ERROR|SQLSTATE|ORA-\\d|PG::|mysql_|pg_query|ECONNREFUSED)/i,\r\n /\\b(syntax error at or near|relation \".*\" does not exist)/i,\r\n /\\b(column \".*\" (does not exist|of relation))/i,\r\n /\\b(duplicate key value violates unique constraint)/i,\r\n /\\b(table .* doesn't exist|unknown column)/i,\r\n // MongoDB errors\r\n /\\b(MongoError|MongoServerError|MongoNetworkError|E11000 duplicate key)/i,\r\n // Redis errors\r\n /\\b(WRONGTYPE|CROSSSLOT|CLUSTERDOWN|READONLY|ReplyError)/i,\r\n // Connection strings and DSNs\r\n /\\b(mongodb(\\+srv)?:\\/\\/|postgres(ql)?:\\/\\/|mysql:\\/\\/|redis:\\/\\/)/i,\r\n // Stack traces with file paths\r\n /\\bat\\s+.*\\.(js|ts|py|go|java):\\d+/i,\r\n // Internal IP addresses\r\n /\\b(127\\.0\\.0\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+|172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+)\\b/,\r\n];\r\n\r\n/**\r\n * Check if an error message contains sensitive infrastructure details.\r\n */\r\nexport function containsSensitiveInfo(message: string): boolean {\r\n return SENSITIVE_ERROR_PATTERNS.some(pattern => pattern.test(message));\r\n}\r\n\r\n/**\r\n * Create Express error handler that hides sensitive details in production.\r\n *\r\n * Prevents information leakage by:\r\n * - Hiding stack traces in production\r\n * - Hiding error messages unless explicitly exposed\r\n * - Scrubbing database errors, connection strings, and internal IPs\r\n *\r\n * @param options - Error handler configuration (or boolean for isDev)\r\n * @returns Express error handling middleware\r\n *\r\n * @example\r\n * // Production mode (default) - hides error details\r\n * app.use(errorHandler());\r\n *\r\n * @example\r\n * // Development mode - shows error details and stack traces\r\n * app.use(errorHandler({ isDev: true }));\r\n *\r\n * @example\r\n * // With custom logger\r\n * app.use(errorHandler({\r\n * isDev: false,\r\n * logger: arcis.logger()\r\n * }));\r\n */\r\nexport function errorHandler(\r\n options: ErrorHandlerOptions | boolean = false\r\n): (err: Error, req: Request, res: Response, next: NextFunction) => void {\r\n const isDev = typeof options === 'boolean' ? options : options.isDev ?? false;\r\n const logErrors = typeof options === 'object' ? options.logErrors ?? true : true;\r\n const logger = typeof options === 'object' ? options.logger : undefined;\r\n const customHandler = typeof options === 'object' ? options.customHandler : undefined;\r\n\r\n return (err: HttpError, req: Request, res: Response, _next: NextFunction) => {\r\n const statusCode = err.statusCode || err.status || 500;\r\n\r\n // Custom handler takes precedence\r\n if (customHandler) {\r\n return customHandler(err, req, res);\r\n }\r\n\r\n // Always log full error details server-side\r\n if (logErrors) {\r\n const logData = {\r\n error: err.message,\r\n stack: err.stack,\r\n statusCode,\r\n path: req.path,\r\n method: req.method,\r\n };\r\n\r\n if (logger) {\r\n logger.error('Request error', logData);\r\n } else {\r\n console.error('[arcis] Request error:', logData);\r\n }\r\n }\r\n\r\n // Build response\r\n // Only expose err.message when err.expose === true (caller opted in) or in dev mode.\r\n // This prevents internal details leaking through arbitrary 4xx errors that happen\r\n // to contain sensitive info (e.g. \"DB query failed for user admin@corp.com\").\r\n const exposeMessage = isDev || err.expose === true;\r\n\r\n let clientMessage: string;\r\n if (!exposeMessage) {\r\n clientMessage = ERRORS.INTERNAL_SERVER_ERROR;\r\n } else if (containsSensitiveInfo(err.message)) {\r\n // Even when expose is true, scrub DB errors and infra details\r\n clientMessage = isDev ? err.message : ERRORS.INTERNAL_SERVER_ERROR;\r\n } else {\r\n clientMessage = err.message;\r\n }\r\n\r\n const response: Record<string, unknown> = {\r\n error: clientMessage,\r\n };\r\n\r\n // Only show details in development\r\n if (isDev) {\r\n response.stack = err.stack;\r\n response.details = err.message;\r\n }\r\n\r\n res.status(statusCode).json(response);\r\n };\r\n}\r\n\r\n/**\r\n * Alias for errorHandler\r\n * @see errorHandler\r\n */\r\nexport const createErrorHandler = errorHandler;\r\n","/**\r\n * @module @arcis/node/core/errors\r\n * Custom error classes for Arcis\r\n */\r\n\r\n/**\r\n * Base class for all Arcis errors\r\n */\r\nexport class ArcisError extends Error {\r\n public readonly statusCode: number;\r\n public readonly code: string;\r\n /** Whether the error message is safe to expose to API clients. */\r\n public readonly expose: boolean;\r\n\r\n constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\r\n super(message);\r\n this.name = 'ArcisError';\r\n this.statusCode = statusCode;\r\n this.code = code;\r\n // Client errors (4xx) have controlled messages — safe to expose.\r\n // Server errors (5xx) may contain internal details — hide by default.\r\n this.expose = statusCode < 500;\r\n\r\n // Maintains proper stack trace for where error was thrown (V8 engines)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, this.constructor);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when input validation fails\r\n */\r\nexport class ValidationError extends ArcisError {\r\n public readonly errors: string[];\r\n\r\n constructor(errors: string[]) {\r\n super('Validation failed', 400, 'VALIDATION_ERROR');\r\n this.name = 'ValidationError';\r\n this.errors = errors;\r\n }\r\n}\r\n\r\n/** Alias for ValidationError (backwards compatibility) */\r\nexport { ValidationError as ArcisValidationError };\r\n\r\n/**\r\n * Error thrown when rate limit is exceeded\r\n */\r\nexport class RateLimitError extends ArcisError {\r\n public readonly retryAfter: number;\r\n\r\n constructor(message: string, retryAfter: number) {\r\n super(message, 429, 'RATE_LIMIT_EXCEEDED');\r\n this.name = 'RateLimitError';\r\n this.retryAfter = retryAfter;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when input is too large\r\n */\r\nexport class InputTooLargeError extends ArcisError {\r\n public readonly maxSize: number;\r\n public readonly actualSize: number;\r\n\r\n constructor(maxSize: number, actualSize: number) {\r\n super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\r\n this.name = 'InputTooLargeError';\r\n this.maxSize = maxSize;\r\n this.actualSize = actualSize;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when security threat is detected\r\n */\r\nexport class SecurityThreatError extends ArcisError {\r\n public readonly threatType: string;\r\n public readonly pattern: string;\r\n\r\n constructor(threatType: string, pattern: string) {\r\n super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\r\n this.name = 'SecurityThreatError';\r\n this.threatType = threatType;\r\n this.pattern = pattern;\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown when sanitization fails\r\n */\r\nexport class SanitizationError extends ArcisError {\r\n constructor(message: string) {\r\n super(message, 400, 'SANITIZATION_ERROR');\r\n this.name = 'SanitizationError';\r\n }\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/utils\r\n * Shared utilities for sanitizers\r\n */\r\n\r\n/**\r\n * Encodes HTML entities to prevent interpretation as markup.\r\n * \r\n * @param str - The string to encode\r\n * @returns The encoded string\r\n */\r\nexport function encodeHtmlEntities(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\n/**\r\n * Checks if a value is a plain object (not null, array, Date, etc.)\r\n * \r\n * @param value - Value to check\r\n * @returns True if plain object\r\n */\r\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n return false;\r\n }\r\n // Check the actual prototype chain rather than toString, which can be spoofed\r\n // via Symbol.toStringTag. Accepts both Object.prototype (plain {}) and null\r\n // prototype objects (Object.create(null)).\r\n const proto = Object.getPrototypeOf(value as object);\r\n return proto === Object.prototype || proto === null;\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/xss\r\n * XSS (Cross-Site Scripting) prevention\r\n */\r\n\r\nimport { XSS_PATTERNS, XSS_REMOVE_PATTERNS } from '../core/constants';\r\nimport { encodeHtmlEntities } from './utils';\r\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\r\n\r\n/**\r\n * Sanitizes a string to prevent XSS attacks.\r\n * \r\n * Strategy:\r\n * 1. Remove dangerous patterns (script tags, event handlers, etc.)\r\n * 2. HTML-encode the remaining content\r\n * \r\n * @param input - The string to sanitize\r\n * @param collectThreats - Whether to collect threat information (default: false for performance)\r\n * @returns Sanitized string or SanitizeResult if collectThreats is true\r\n * \r\n * @example\r\n * sanitizeXss(\"<script>alert('xss')</script>\")\r\n * // Returns: \"<script>alert('xss')</script>\"\r\n * \r\n * @example\r\n * sanitizeXss(\"<img onerror='alert(1)'>\")\r\n * // Returns: \"<img>\" (event handler removed)\r\n */\r\nexport function sanitizeXss(input: string, collectThreats?: false, htmlEncode?: boolean): string;\r\nexport function sanitizeXss(input: string, collectThreats: true, htmlEncode?: boolean): SanitizeResult;\r\nexport function sanitizeXss(input: string, collectThreats = false, htmlEncode = false): string | SanitizeResult {\r\n if (typeof input !== 'string') {\r\n return collectThreats \r\n ? { value: String(input), wasSanitized: false, threats: [] }\r\n : String(input);\r\n }\r\n\r\n const threats: ThreatInfo[] = [];\r\n let value = input;\r\n let wasSanitized = false;\r\n\r\n // Remove dangerous patterns FIRST — XSS_REMOVE_PATTERNS is the single\r\n // source of truth (defined in constants.ts alongside XSS_PATTERNS).\r\n for (const pattern of XSS_REMOVE_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n if (pattern.test(value)) {\r\n pattern.lastIndex = 0;\r\n \r\n if (collectThreats) {\r\n const matches = value.match(pattern);\r\n if (matches) {\r\n for (const match of matches) {\r\n threats.push({\r\n type: 'xss',\r\n pattern: pattern.source,\r\n original: match,\r\n });\r\n }\r\n }\r\n }\r\n \r\n value = value.replace(pattern, '');\r\n wasSanitized = true;\r\n }\r\n }\r\n\r\n // HTML-encode only when explicitly requested (SSR/template context).\r\n // Do NOT encode by default — this is a REST API middleware; encoding\r\n // here corrupts JSON data with HTML entities (<, &, etc.) that\r\n // consumers would receive verbatim.\r\n if (htmlEncode) {\r\n const encoded = encodeHtmlEntities(value);\r\n if (encoded !== value) {\r\n wasSanitized = true;\r\n }\r\n value = encoded;\r\n }\r\n\r\n if (collectThreats) {\r\n return { value, wasSanitized, threats };\r\n }\r\n \r\n return value;\r\n}\r\n\r\n/**\r\n * Checks if a string contains potential XSS patterns.\r\n * Does not sanitize — use sanitizeXss() for that.\r\n * \r\n * @param input - The string to check\r\n * @returns True if XSS patterns detected\r\n */\r\nexport function detectXss(input: string): boolean {\r\n if (typeof input !== 'string') return false;\r\n \r\n // Check for event handlers\r\n if (/\\s+on\\w+\\s*=/i.test(input)) return true;\r\n \r\n // Check for dangerous protocols\r\n if (/javascript\\s*:/i.test(input)) return true;\r\n if (/vbscript\\s*:/i.test(input)) return true;\r\n if (/data\\s*:\\s*text\\/html/i.test(input)) return true;\r\n \r\n // Check for patterns from constants\r\n for (const pattern of XSS_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n if (pattern.test(input)) {\r\n return true;\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/sql\r\n * SQL injection prevention\r\n */\r\n\r\nimport { SQL_PATTERNS } from '../core/constants';\r\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\r\n\r\n/**\r\n * Sanitizes a string to prevent SQL injection attacks.\r\n * Replaces dangerous SQL patterns with [BLOCKED].\r\n * \r\n * @param input - The string to sanitize\r\n * @param collectThreats - Whether to collect threat information (default: false for performance)\r\n * @returns Sanitized string or SanitizeResult if collectThreats is true\r\n * \r\n * @example\r\n * sanitizeSql(\"'; DROP TABLE users; --\")\r\n * // Returns: \"'; TABLE users \"\r\n */\r\nexport function sanitizeSql(input: string, collectThreats?: false): string;\r\nexport function sanitizeSql(input: string, collectThreats: true): SanitizeResult;\r\nexport function sanitizeSql(input: string, collectThreats = false): string | SanitizeResult {\r\n if (typeof input !== 'string') {\r\n return collectThreats \r\n ? { value: String(input), wasSanitized: false, threats: [] }\r\n : String(input);\r\n }\r\n\r\n const threats: ThreatInfo[] = [];\r\n let value = input;\r\n let wasSanitized = false;\r\n\r\n for (const pattern of SQL_PATTERNS) {\r\n // Reset regex lastIndex for global patterns\r\n pattern.lastIndex = 0;\r\n \r\n if (pattern.test(value)) {\r\n pattern.lastIndex = 0; // Reset again for replace\r\n \r\n if (collectThreats) {\r\n const matches = value.match(pattern);\r\n if (matches) {\r\n for (const match of matches) {\r\n threats.push({\r\n type: 'sql_injection',\r\n pattern: pattern.source,\r\n original: match,\r\n });\r\n }\r\n }\r\n }\r\n \r\n // Replace the matched content with a space to avoid concatenating surrounding\r\n // tokens into new dangerous strings (e.g. \"SELECTname\" after stripping \"SELECT\").\r\n value = value.replace(pattern, ' ');\r\n wasSanitized = true;\r\n }\r\n }\r\n\r\n if (collectThreats) {\r\n return { value, wasSanitized, threats };\r\n }\r\n \r\n return value;\r\n}\r\n\r\n/**\r\n * Checks if a string contains potential SQL injection patterns.\r\n * Does not sanitize — use sanitizeSql() for that.\r\n * \r\n * @param input - The string to check\r\n * @returns True if SQL injection patterns detected\r\n */\r\nexport function detectSql(input: string): boolean {\r\n if (typeof input !== 'string') return false;\r\n \r\n for (const pattern of SQL_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n if (pattern.test(input)) {\r\n return true;\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/path\r\n * Path traversal prevention\r\n */\r\n\r\nimport { PATH_PATTERNS } from '../core/constants';\r\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\r\n\r\n/**\r\n * Sanitizes a string to prevent path traversal attacks.\r\n * Removes ../ and ..\\ patterns (including URL-encoded variants).\r\n * \r\n * @param input - The string to sanitize\r\n * @param collectThreats - Whether to collect threat information (default: false for performance)\r\n * @returns Sanitized string or SanitizeResult if collectThreats is true\r\n * \r\n * @example\r\n * sanitizePath(\"../../etc/passwd\")\r\n * // Returns: \"etc/passwd\"\r\n */\r\nexport function sanitizePath(input: string, collectThreats?: false): string;\r\nexport function sanitizePath(input: string, collectThreats: true): SanitizeResult;\r\nexport function sanitizePath(input: string, collectThreats = false): string | SanitizeResult {\r\n if (typeof input !== 'string') {\r\n return collectThreats \r\n ? { value: String(input), wasSanitized: false, threats: [] }\r\n : String(input);\r\n }\r\n\r\n const threats: ThreatInfo[] = [];\r\n let value = input;\r\n let wasSanitized = false;\r\n\r\n for (const pattern of PATH_PATTERNS) {\r\n // Reset regex lastIndex for global patterns\r\n pattern.lastIndex = 0;\r\n \r\n if (pattern.test(value)) {\r\n pattern.lastIndex = 0; // Reset again for replace\r\n \r\n if (collectThreats) {\r\n const matches = value.match(pattern);\r\n if (matches) {\r\n for (const match of matches) {\r\n threats.push({\r\n type: 'path_traversal',\r\n pattern: pattern.source,\r\n original: match,\r\n });\r\n }\r\n }\r\n }\r\n \r\n value = value.replace(pattern, '');\r\n wasSanitized = true;\r\n }\r\n }\r\n\r\n if (collectThreats) {\r\n return { value, wasSanitized, threats };\r\n }\r\n \r\n return value;\r\n}\r\n\r\n/**\r\n * Checks if a string contains path traversal patterns.\r\n * Does not sanitize — use sanitizePath() for that.\r\n * \r\n * @param input - The string to check\r\n * @returns True if path traversal patterns detected\r\n */\r\nexport function detectPathTraversal(input: string): boolean {\r\n if (typeof input !== 'string') return false;\r\n \r\n for (const pattern of PATH_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n if (pattern.test(input)) {\r\n return true;\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/command\r\n * Command injection prevention\r\n */\r\n\r\nimport { COMMAND_PATTERNS } from '../core/constants';\r\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\r\n\r\n/**\r\n * Sanitizes a string to prevent command injection attacks.\r\n * Replaces shell metacharacters and dangerous commands with [BLOCKED].\r\n * \r\n * @param input - The string to sanitize\r\n * @param collectThreats - Whether to collect threat information (default: false for performance)\r\n * @returns Sanitized string or SanitizeResult if collectThreats is true\r\n * \r\n * @example\r\n * sanitizeCommand(\"file.txt; rm -rf /\")\r\n * // Returns: \"file.txt rm -rf /\"\r\n */\r\nexport function sanitizeCommand(input: string, collectThreats?: false): string;\r\nexport function sanitizeCommand(input: string, collectThreats: true): SanitizeResult;\r\nexport function sanitizeCommand(input: string, collectThreats = false): string | SanitizeResult {\r\n if (typeof input !== 'string') {\r\n return collectThreats \r\n ? { value: String(input), wasSanitized: false, threats: [] }\r\n : String(input);\r\n }\r\n\r\n const threats: ThreatInfo[] = [];\r\n let value = input;\r\n let wasSanitized = false;\r\n\r\n for (const pattern of COMMAND_PATTERNS) {\r\n // Reset regex lastIndex for global patterns\r\n pattern.lastIndex = 0;\r\n \r\n if (pattern.test(value)) {\r\n pattern.lastIndex = 0; // Reset again for replace\r\n \r\n if (collectThreats) {\r\n const matches = value.match(pattern);\r\n if (matches) {\r\n for (const match of matches) {\r\n threats.push({\r\n type: 'command_injection',\r\n pattern: pattern.source,\r\n original: match,\r\n });\r\n }\r\n }\r\n }\r\n \r\n value = value.replace(pattern, ' ');\r\n wasSanitized = true;\r\n }\r\n }\r\n\r\n if (collectThreats) {\r\n return { value, wasSanitized, threats };\r\n }\r\n \r\n return value;\r\n}\r\n\r\n/**\r\n * Checks if a string contains command injection patterns.\r\n * Does not sanitize — use sanitizeCommand() for that.\r\n * \r\n * @param input - The string to check\r\n * @returns True if command injection patterns detected\r\n */\r\nexport function detectCommandInjection(input: string): boolean {\r\n if (typeof input !== 'string') return false;\r\n \r\n for (const pattern of COMMAND_PATTERNS) {\r\n pattern.lastIndex = 0;\r\n if (pattern.test(input)) {\r\n return true;\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/sanitize\r\n * Main sanitization functions that combine all sanitizers\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\nimport { INPUT, DANGEROUS_PROTO_KEYS, NOSQL_DANGEROUS_KEYS } from '../core/constants';\r\nimport { InputTooLargeError, SecurityThreatError } from '../core/errors';\r\nimport type { SanitizeOptions } from '../core/types';\r\nimport { sanitizeXss } from './xss';\r\nimport { sanitizeSql, detectSql } from './sql';\r\nimport { sanitizePath } from './path';\r\nimport { sanitizeCommand, detectCommandInjection } from './command';\r\n\r\n/**\r\n * Sanitize a string value against multiple attack vectors.\r\n * \r\n * Order matters: We do XSS encoding LAST because:\r\n * 1. Other sanitizers need to see the original patterns (e.g., SQL keywords)\r\n * 2. HTML encoding is the final safe output transformation\r\n * 3. Encoded entities like < shouldn't be treated as SQL/command threats\r\n * \r\n * @param value - The string to sanitize\r\n * @param options - Sanitization options\r\n * @returns The sanitized string\r\n * \r\n * @example\r\n * sanitizeString(\"<script>alert('xss')</script>\")\r\n * // Returns: \"<script>alert('xss')</script>\"\r\n * \r\n * @example\r\n * sanitizeString(\"../../etc/passwd\")\r\n * // Returns: \"etc/passwd\"\r\n */\r\nexport function sanitizeString(value: string, options: SanitizeOptions = {}): string {\r\n if (typeof value !== 'string') return value;\r\n\r\n // Input size limit to prevent DoS\r\n const maxSize = options.maxSize ?? INPUT.DEFAULT_MAX_SIZE;\r\n if (value.length > maxSize) {\r\n throw new InputTooLargeError(maxSize, value.length);\r\n }\r\n\r\n const reject = options.mode !== 'sanitize'; // default: 'reject'\r\n let result = value;\r\n\r\n // 1. SQL injection\r\n if (options.sql !== false) {\r\n if (reject) {\r\n if (detectSql(result)) {\r\n throw new SecurityThreatError('sql_injection', 'SQL pattern detected in input');\r\n }\r\n } else {\r\n result = sanitizeSql(result);\r\n }\r\n }\r\n\r\n // 2. Path traversal prevention\r\n if (options.path !== false) {\r\n result = sanitizePath(result);\r\n }\r\n\r\n // 3. Command injection\r\n if (options.command !== false) {\r\n if (reject) {\r\n if (detectCommandInjection(result)) {\r\n throw new SecurityThreatError('command_injection', 'Shell metacharacter detected in input');\r\n }\r\n } else {\r\n result = sanitizeCommand(result);\r\n }\r\n }\r\n\r\n // 4. XSS stripping — always runs to remove dangerous patterns.\r\n // HTML encoding is opt-in via options.htmlEncode (for SSR contexts only).\r\n if (options.xss !== false) {\r\n result = sanitizeXss(result, false, options.htmlEncode ?? false);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Sanitize an object recursively, including nested objects and arrays.\r\n * Also removes prototype pollution and NoSQL injection keys.\r\n * \r\n * @param obj - The object to sanitize\r\n * @param options - Sanitization options\r\n * @returns The sanitized object\r\n */\r\nexport function sanitizeObject(obj: unknown, options: SanitizeOptions = {}): unknown {\r\n if (obj === null || obj === undefined) return obj;\r\n if (typeof obj === 'string') return sanitizeString(obj, options);\r\n if (typeof obj !== 'object') return obj;\r\n if (Array.isArray(obj)) return obj.map(item => sanitizeObject(item, options));\r\n\r\n return sanitizeObjectDepth(obj as Record<string, unknown>, options, 0);\r\n}\r\n\r\n/**\r\n * Internal recursive sanitization with depth tracking.\r\n */\r\nfunction sanitizeObjectDepth(\r\n obj: Record<string, unknown>,\r\n options: SanitizeOptions,\r\n depth: number\r\n): Record<string, unknown> {\r\n if (depth >= INPUT.MAX_RECURSION_DEPTH) return obj;\r\n\r\n const result: Record<string, unknown> = {};\r\n\r\n for (const key of Object.keys(obj)) {\r\n // Prototype pollution protection - always block dangerous keys (case-insensitive)\r\n if (options.proto !== false && DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\r\n continue;\r\n }\r\n\r\n // NoSQL injection - skip dangerous MongoDB operators in keys\r\n if (options.nosql !== false && NOSQL_DANGEROUS_KEYS.has(key)) {\r\n continue;\r\n }\r\n\r\n // Sanitize the key against all active threat vectors (not just XSS).\r\n // Keys can carry injection payloads that bubble into query builders or ORMs.\r\n const sanitizedKey = sanitizeString(key, options);\r\n\r\n // Recursively sanitize value\r\n const value = obj[key];\r\n if (value === null || value === undefined) {\r\n result[sanitizedKey] = value;\r\n } else if (typeof value === 'string') {\r\n result[sanitizedKey] = sanitizeString(value, options);\r\n } else if (Array.isArray(value)) {\r\n result[sanitizedKey] = value.map(item => sanitizeObject(item, options));\r\n } else if (typeof value === 'object') {\r\n result[sanitizedKey] = sanitizeObjectDepth(value as Record<string, unknown>, options, depth + 1);\r\n } else {\r\n result[sanitizedKey] = value;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Create Express middleware for request sanitization.\r\n * Sanitizes req.body, req.query, and req.params.\r\n * \r\n * @param options - Sanitization options\r\n * @returns Express middleware\r\n * \r\n * @example\r\n * app.use(createSanitizer());\r\n * \r\n * @example\r\n * app.use(createSanitizer({ xss: true, sql: true, nosql: true }));\r\n */\r\nexport function createSanitizer(options: SanitizeOptions = {}): RequestHandler {\r\n return (req: Request, _res: Response, next: NextFunction) => {\r\n try {\r\n if (req.body && typeof req.body === 'object') {\r\n req.body = sanitizeObject(req.body, options);\r\n }\r\n if (req.query && typeof req.query === 'object') {\r\n const sanitizedQuery = sanitizeObject(req.query, options);\r\n // Express 5: req.query is a getter with no setter — override on instance\r\n Object.defineProperty(req, 'query', { value: sanitizedQuery, writable: true, configurable: true });\r\n }\r\n if (req.params && typeof req.params === 'object') {\r\n const sanitizedParams = sanitizeObject(req.params, options);\r\n Object.defineProperty(req, 'params', { value: sanitizedParams, writable: true, configurable: true });\r\n }\r\n next();\r\n } catch (err) {\r\n next(err);\r\n }\r\n };\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/nosql\r\n * NoSQL injection prevention (MongoDB operators)\r\n */\r\n\r\nimport { NOSQL_DANGEROUS_KEYS } from '../core/constants';\r\n\r\n/**\r\n * Checks if a key is a dangerous MongoDB operator.\r\n * \r\n * @param key - The key to check\r\n * @returns True if the key is a MongoDB operator\r\n * \r\n * @example\r\n * isDangerousNoSqlKey('$gt') // true\r\n * isDangerousNoSqlKey('name') // false\r\n */\r\nexport function isDangerousNoSqlKey(key: string): boolean {\r\n return NOSQL_DANGEROUS_KEYS.has(key);\r\n}\r\n\r\n/**\r\n * Recursively checks if an object contains dangerous MongoDB operators.\r\n * \r\n * @param obj - The object to check\r\n * @param maxDepth - Maximum recursion depth (default: 10)\r\n * @returns True if dangerous operators found\r\n */\r\nexport function detectNoSqlInjection(obj: unknown, maxDepth = 10): boolean {\r\n if (maxDepth <= 0) return false;\r\n if (obj === null || typeof obj !== 'object') return false;\r\n \r\n if (Array.isArray(obj)) {\r\n return obj.some(item => detectNoSqlInjection(item, maxDepth - 1));\r\n }\r\n \r\n for (const key of Object.keys(obj as Record<string, unknown>)) {\r\n if (isDangerousNoSqlKey(key)) {\r\n return true;\r\n }\r\n \r\n const value = (obj as Record<string, unknown>)[key];\r\n if (typeof value === 'object' && value !== null) {\r\n if (detectNoSqlInjection(value, maxDepth - 1)) {\r\n return true;\r\n }\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n\r\n/**\r\n * Get list of all MongoDB operators considered dangerous.\r\n * Useful for documentation or custom validation.\r\n * \r\n * @returns Array of dangerous operator strings\r\n */\r\nexport function getDangerousOperators(): string[] {\r\n return Array.from(NOSQL_DANGEROUS_KEYS);\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/prototype\r\n * Prototype pollution prevention\r\n */\r\n\r\nimport { DANGEROUS_PROTO_KEYS } from '../core/constants';\r\n\r\n/**\r\n * Checks if a key is dangerous for prototype pollution.\r\n * Case-insensitive — catches __PROTO__, Constructor, etc.\r\n *\r\n * @param key - The key to check\r\n * @returns True if the key could cause prototype pollution\r\n *\r\n * @example\r\n * isDangerousProtoKey('__proto__') // true\r\n * isDangerousProtoKey('__PROTO__') // true\r\n * isDangerousProtoKey('Constructor') // true\r\n * isDangerousProtoKey('name') // false\r\n */\r\nexport function isDangerousProtoKey(key: string): boolean {\r\n return DANGEROUS_PROTO_KEYS.has(key.toLowerCase());\r\n}\r\n\r\n/**\r\n * Recursively checks if an object contains prototype pollution keys.\r\n * \r\n * @param obj - The object to check\r\n * @param maxDepth - Maximum recursion depth (default: 10)\r\n * @returns True if dangerous keys found\r\n */\r\nexport function detectPrototypePollution(obj: unknown, maxDepth = 10): boolean {\r\n if (maxDepth <= 0) return false;\r\n if (obj === null || typeof obj !== 'object') return false;\r\n \r\n if (Array.isArray(obj)) {\r\n return obj.some(item => detectPrototypePollution(item, maxDepth - 1));\r\n }\r\n \r\n for (const key of Object.keys(obj as Record<string, unknown>)) {\r\n if (DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\r\n return true;\r\n }\r\n \r\n const value = (obj as Record<string, unknown>)[key];\r\n if (typeof value === 'object' && value !== null) {\r\n if (detectPrototypePollution(value, maxDepth - 1)) {\r\n return true;\r\n }\r\n }\r\n }\r\n \r\n return false;\r\n}\r\n\r\n/**\r\n * Get list of all keys considered dangerous for prototype pollution.\r\n * Useful for documentation or custom validation.\r\n * \r\n * @returns Array of dangerous key strings\r\n */\r\nexport function getDangerousProtoKeys(): string[] {\r\n return Array.from(DANGEROUS_PROTO_KEYS);\r\n}\r\n","/**\r\n * @module @arcis/node/sanitizers/headers\r\n * HTTP Header Injection & CRLF Injection prevention\r\n *\r\n * Prevents attackers from injecting newline characters (\\r\\n) into HTTP header\r\n * values, which can lead to response splitting, session fixation, XSS via\r\n * injected headers, and cache poisoning.\r\n */\r\n\r\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\r\n\r\n/**\r\n * Characters and sequences that enable header injection.\r\n * - \\r\\n (CRLF) — HTTP header delimiter, enables response splitting\r\n * - \\r, \\n alone — partial line breaks, some servers normalize to CRLF\r\n * - \\0 (null byte) — can truncate header values in some implementations\r\n */\r\nconst HEADER_INJECTION_PATTERN = /\\r\\n|\\r|\\n|\\0/g;\r\n\r\n/**\r\n * Sanitizes a header value by stripping CRLF sequences, bare CR/LF, and null bytes.\r\n *\r\n * @param input - The header value to sanitize\r\n * @param collectThreats - Whether to collect threat information (default: false)\r\n * @returns Sanitized string or SanitizeResult if collectThreats is true\r\n *\r\n * @example\r\n * sanitizeHeaderValue(\"safe-value\")\r\n * // Returns: \"safe-value\"\r\n *\r\n * sanitizeHeaderValue(\"value\\r\\nX-Injected: evil\")\r\n * // Returns: \"valueX-Injected: evil\"\r\n */\r\nexport function sanitizeHeaderValue(input: string, collectThreats?: false): string;\r\nexport function sanitizeHeaderValue(input: string, collectThreats: true): SanitizeResult;\r\nexport function sanitizeHeaderValue(input: string, collectThreats = false): string | SanitizeResult {\r\n if (typeof input !== 'string') {\r\n return collectThreats\r\n ? { value: String(input), wasSanitized: false, threats: [] }\r\n : String(input);\r\n }\r\n\r\n const threats: ThreatInfo[] = [];\r\n let wasSanitized = false;\r\n\r\n if (HEADER_INJECTION_PATTERN.test(input)) {\r\n HEADER_INJECTION_PATTERN.lastIndex = 0;\r\n wasSanitized = true;\r\n\r\n if (collectThreats) {\r\n const matches = input.match(HEADER_INJECTION_PATTERN);\r\n if (matches) {\r\n for (const match of matches) {\r\n threats.push({\r\n type: 'header_injection',\r\n pattern: HEADER_INJECTION_PATTERN.source,\r\n original: match,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n HEADER_INJECTION_PATTERN.lastIndex = 0;\r\n const value = input.replace(HEADER_INJECTION_PATTERN, '');\r\n\r\n if (collectThreats) {\r\n return { value, wasSanitized, threats };\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Sanitizes an object of header key-value pairs.\r\n * Strips CRLF/null bytes from both keys and values.\r\n *\r\n * @param headers - Object with header names as keys and header values as values\r\n * @returns New object with sanitized header names and values\r\n *\r\n * @example\r\n * sanitizeHeaders({ \"X-Custom\": \"safe\", \"X-Bad\\r\\n\": \"value\\r\\ninjected\" })\r\n * // Returns: { \"X-Custom\": \"safe\", \"X-Bad\": \"valueinjected\" }\r\n */\r\nexport function sanitizeHeaders(headers: Record<string, string>): Record<string, string> {\r\n if (!headers || typeof headers !== 'object') {\r\n return {};\r\n }\r\n\r\n const result: Record<string, string> = {};\r\n\r\n for (const [key, value] of Object.entries(headers)) {\r\n const sanitizedKey = sanitizeHeaderValue(String(key));\r\n const sanitizedValue = sanitizeHeaderValue(String(value));\r\n result[sanitizedKey] = sanitizedValue;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Checks if a string contains HTTP header injection patterns (CRLF, null bytes).\r\n * Does not sanitize — use sanitizeHeaderValue() for that.\r\n *\r\n * @param input - The string to check\r\n * @returns True if header injection patterns detected\r\n */\r\nexport function detectHeaderInjection(input: string): boolean {\r\n if (typeof input !== 'string') return false;\r\n\r\n HEADER_INJECTION_PATTERN.lastIndex = 0;\r\n return HEADER_INJECTION_PATTERN.test(input);\r\n}\r\n","/**\r\n * @module @arcis/node/validation/schema\r\n * Request validation middleware\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\nimport { VALIDATION, ERRORS } from '../core/constants';\r\nimport type { ValidationSchema, FieldValidator } from '../core/types';\r\nimport { sanitizeString } from '../sanitizers';\r\n\r\n/**\r\n * Create Express middleware for request validation.\r\n * Prevents mass assignment by only allowing fields defined in the schema.\r\n * \r\n * @param schema - Validation schema defining expected fields\r\n * @param source - Request property to validate ('body', 'query', or 'params')\r\n * @returns Express middleware\r\n * \r\n * @example\r\n * app.post('/users', validate({\r\n * email: { type: 'email', required: true },\r\n * name: { type: 'string', min: 2, max: 50 },\r\n * age: { type: 'number', min: 0, max: 150 },\r\n * role: { type: 'string', enum: ['user', 'admin'] }\r\n * }), handler);\r\n * \r\n * @example\r\n * // Validate query params\r\n * app.get('/search', validate({\r\n * q: { type: 'string', required: true, min: 1 },\r\n * page: { type: 'number', min: 1 }\r\n * }, 'query'), handler);\r\n */\r\nexport function validate(\r\n schema: ValidationSchema,\r\n source: 'body' | 'query' | 'params' = 'body'\r\n): RequestHandler {\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const data = req[source] || {};\r\n const errors: string[] = [];\r\n const validated: Record<string, unknown> = {};\r\n\r\n for (const [field, rules] of Object.entries(schema)) {\r\n const value = data[field];\r\n const result = validateField(field, value, rules);\r\n \r\n if (result.errors.length > 0) {\r\n errors.push(...result.errors);\r\n } else if (result.value !== undefined) {\r\n validated[field] = result.value;\r\n }\r\n }\r\n\r\n if (errors.length > 0) {\r\n res.status(400).json({ errors });\r\n return;\r\n }\r\n\r\n // Replace with validated data (prevents mass assignment)\r\n req[source] = validated as typeof req[typeof source];\r\n next();\r\n };\r\n}\r\n\r\n/**\r\n * Validate a single field against its rules.\r\n */\r\nfunction validateField(\r\n field: string,\r\n value: unknown,\r\n rules: FieldValidator\r\n): { value?: unknown; errors: string[] } {\r\n const errors: string[] = [];\r\n\r\n // Required check\r\n if (rules.required && (value === undefined || value === null || value === '')) {\r\n errors.push(ERRORS.VALIDATION.REQUIRED(field));\r\n return { errors };\r\n }\r\n\r\n // Skip optional empty fields\r\n if (value === undefined || value === null) {\r\n return { errors: [] };\r\n }\r\n\r\n let typedValue: unknown = value;\r\n let isValid = true;\r\n\r\n // Type validation and coercion\r\n switch (rules.type) {\r\n case 'string':\r\n if (typeof value !== 'string') {\r\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'string'));\r\n isValid = false;\r\n break;\r\n }\r\n if (rules.min !== undefined && value.length < rules.min) {\r\n errors.push(ERRORS.VALIDATION.MIN_LENGTH(field, rules.min));\r\n isValid = false;\r\n }\r\n if (rules.max !== undefined && value.length > rules.max) {\r\n errors.push(ERRORS.VALIDATION.MAX_LENGTH(field, rules.max));\r\n isValid = false;\r\n }\r\n if (rules.pattern && !rules.pattern.test(value)) {\r\n errors.push(ERRORS.VALIDATION.INVALID_FORMAT(field));\r\n isValid = false;\r\n }\r\n // Enum check runs before sanitization so the raw value is compared.\r\n // Sanitizing first could silently modify the value and cause a mismatch\r\n // with enum entries that contain characters the sanitizer would strip.\r\n if (isValid && rules.enum && !rules.enum.includes(value)) {\r\n errors.push(ERRORS.VALIDATION.INVALID_ENUM(field, rules.enum));\r\n isValid = false;\r\n }\r\n if (isValid && rules.sanitize !== false) {\r\n typedValue = sanitizeString(value);\r\n }\r\n break;\r\n\r\n case 'number':\r\n typedValue = Number(value);\r\n if (isNaN(typedValue as number)) {\r\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'number'));\r\n isValid = false;\r\n break;\r\n }\r\n if (rules.min !== undefined && (typedValue as number) < rules.min) {\r\n errors.push(ERRORS.VALIDATION.MIN_VALUE(field, rules.min));\r\n isValid = false;\r\n }\r\n if (rules.max !== undefined && (typedValue as number) > rules.max) {\r\n errors.push(ERRORS.VALIDATION.MAX_VALUE(field, rules.max));\r\n isValid = false;\r\n }\r\n break;\r\n\r\n case 'boolean':\r\n if (value === 'true' || value === true || value === 1 || value === '1') {\r\n typedValue = true;\r\n } else if (value === 'false' || value === false || value === 0 || value === '0') {\r\n typedValue = false;\r\n } else {\r\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'boolean'));\r\n isValid = false;\r\n }\r\n break;\r\n\r\n case 'email':\r\n if (!VALIDATION.EMAIL.test(String(value))) {\r\n errors.push(ERRORS.VALIDATION.INVALID_EMAIL(field));\r\n isValid = false;\r\n }\r\n if (isValid) {\r\n typedValue = sanitizeString(String(value).toLowerCase().trim());\r\n }\r\n break;\r\n\r\n case 'url':\r\n if (!VALIDATION.URL.test(String(value))) {\r\n errors.push(ERRORS.VALIDATION.INVALID_URL(field));\r\n isValid = false;\r\n }\r\n if (isValid) {\r\n typedValue = sanitizeString(String(value));\r\n }\r\n break;\r\n\r\n case 'uuid':\r\n if (!VALIDATION.UUID.test(String(value))) {\r\n errors.push(ERRORS.VALIDATION.INVALID_UUID(field));\r\n isValid = false;\r\n }\r\n break;\r\n\r\n case 'array':\r\n if (!Array.isArray(value)) {\r\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'array'));\r\n isValid = false;\r\n break;\r\n }\r\n if (rules.min !== undefined && value.length < rules.min) {\r\n errors.push(ERRORS.VALIDATION.MIN_ITEMS(field, rules.min));\r\n isValid = false;\r\n }\r\n if (rules.max !== undefined && value.length > rules.max) {\r\n errors.push(ERRORS.VALIDATION.MAX_ITEMS(field, rules.max));\r\n isValid = false;\r\n }\r\n break;\r\n\r\n case 'object':\r\n if (typeof value !== 'object' || Array.isArray(value) || value === null) {\r\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'object'));\r\n isValid = false;\r\n }\r\n break;\r\n }\r\n\r\n // Enum validation for non-string types (strings check enum before sanitizing above).\r\n if (isValid && rules.enum && rules.type !== 'string' && !rules.enum.includes(typedValue)) {\r\n errors.push(ERRORS.VALIDATION.INVALID_ENUM(field, rules.enum));\r\n isValid = false;\r\n }\r\n\r\n // Custom validation\r\n if (isValid && rules.custom) {\r\n const customResult = rules.custom(typedValue);\r\n if (customResult === undefined) {\r\n throw new TypeError(\r\n `Custom validator for field \"${field}\" returned undefined. ` +\r\n 'Return true to pass, false to fail, or a string error message.'\r\n );\r\n }\r\n if (customResult !== true) {\r\n errors.push(typeof customResult === 'string' && customResult.length > 0 ? customResult : `${field} is invalid`);\r\n isValid = false;\r\n }\r\n }\r\n\r\n return {\r\n value: isValid ? typedValue : undefined,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Alias for validate\r\n * @see validate\r\n */\r\nexport const createValidator = validate;\r\n","/**\r\n * @module @arcis/node/validation/file\r\n * File upload validation and filename sanitization\r\n */\r\n\r\n// =============================================================================\r\n// MAGIC BYTES — first bytes of common file types\r\n// =============================================================================\r\n\r\nconst MAGIC_BYTES: Record<string, Buffer[]> = {\r\n // Images\r\n 'image/jpeg': [Buffer.from([0xFF, 0xD8, 0xFF])],\r\n 'image/png': [Buffer.from([0x89, 0x50, 0x4E, 0x47])],\r\n 'image/gif': [Buffer.from('GIF87a'), Buffer.from('GIF89a')],\r\n 'image/webp': [Buffer.from('RIFF')], // RIFF....WEBP\r\n 'image/bmp': [Buffer.from([0x42, 0x4D])],\r\n 'image/svg+xml': [], // text-based, check separately\r\n\r\n // Documents\r\n 'application/pdf': [Buffer.from('%PDF')],\r\n 'application/zip': [Buffer.from([0x50, 0x4B, 0x03, 0x04])],\r\n\r\n // Audio/Video\r\n 'audio/mpeg': [Buffer.from([0xFF, 0xFB]), Buffer.from([0xFF, 0xF3]), Buffer.from([0x49, 0x44, 0x33])],\r\n 'video/mp4': [], // ftyp at offset 4\r\n};\r\n\r\n// =============================================================================\r\n// DANGEROUS EXTENSIONS — files that can execute code\r\n// =============================================================================\r\n\r\nconst DANGEROUS_EXTENSIONS = new Set([\r\n // Scripts\r\n '.exe', '.bat', '.cmd', '.com', '.msi', '.scr', '.pif',\r\n '.vbs', '.vbe', '.js', '.jse', '.ws', '.wsf', '.wsc', '.wsh',\r\n '.ps1', '.ps1xml', '.ps2', '.ps2xml', '.psc1', '.psc2',\r\n '.sh', '.bash', '.csh', '.ksh',\r\n // Server-side\r\n '.php', '.php3', '.php4', '.php5', '.phtml', '.pht',\r\n '.asp', '.aspx', '.ashx', '.asmx', '.cer',\r\n '.jsp', '.jspx', '.jsw', '.jsv',\r\n '.cgi', '.pl', '.py', '.rb',\r\n // Java\r\n '.jar', '.war', '.ear', '.class',\r\n // Config that can execute\r\n '.htaccess', '.htpasswd',\r\n // Template engines\r\n '.ejs', '.pug', '.hbs', '.handlebars', '.njk', '.twig',\r\n // Shortcuts/links\r\n '.lnk', '.inf', '.reg', '.url',\r\n // Office macros\r\n '.docm', '.xlsm', '.pptm', '.dotm',\r\n]);\r\n\r\n// =============================================================================\r\n// TYPES\r\n// =============================================================================\r\n\r\n/** File upload validation options */\r\nexport interface ValidateFileOptions {\r\n /** Maximum file size in bytes. Default: 5MB */\r\n maxSize?: number;\r\n /** Allowed MIME types (e.g., ['image/jpeg', 'image/png']) */\r\n allowedTypes?: string[];\r\n /** Allowed file extensions (e.g., ['.jpg', '.png']). Includes dot. */\r\n allowedExtensions?: string[];\r\n /** Block dangerous/executable extensions. Default: true */\r\n blockExecutables?: boolean;\r\n /** Validate magic bytes match the claimed MIME type. Default: true */\r\n validateMagicBytes?: boolean;\r\n /** Block files with no extension. Default: true */\r\n blockNoExtension?: boolean;\r\n /** Block double extensions (e.g., file.php.jpg). Default: true */\r\n blockDoubleExtensions?: boolean;\r\n}\r\n\r\n/** File metadata for validation */\r\nexport interface FileInput {\r\n /** Original filename */\r\n filename: string;\r\n /** MIME type (as claimed by client) */\r\n mimetype: string;\r\n /** File size in bytes */\r\n size: number;\r\n /** File content buffer (for magic byte validation) */\r\n buffer?: Buffer;\r\n}\r\n\r\n/** File validation result */\r\nexport interface ValidateFileResult {\r\n /** Whether the file passed validation */\r\n valid: boolean;\r\n /** Validation errors (empty if valid) */\r\n errors: string[];\r\n /** Sanitized filename (safe for storage) */\r\n sanitizedFilename: string;\r\n}\r\n\r\n// =============================================================================\r\n// DEFAULTS\r\n// =============================================================================\r\n\r\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5MB\r\n\r\n// =============================================================================\r\n// FILENAME SANITIZATION\r\n// =============================================================================\r\n\r\n/**\r\n * Sanitize a filename for safe storage.\r\n *\r\n * Strips path traversal, null bytes, control characters, and special characters.\r\n * Preserves the extension and converts to a filesystem-safe name.\r\n *\r\n * @param filename - The original filename\r\n * @returns A sanitized filename safe for storage\r\n *\r\n * @example\r\n * sanitizeFilename('../../etc/passwd') // 'etc_passwd'\r\n * sanitizeFilename('file<name>.jpg') // 'filename.jpg'\r\n * sanitizeFilename('photo (1).jpg') // 'photo_1.jpg'\r\n * sanitizeFilename('.htaccess') // 'htaccess'\r\n */\r\nexport function sanitizeFilename(filename: string): string {\r\n let name = filename;\r\n\r\n // Strip null bytes\r\n name = name.replace(/\\0/g, '');\r\n\r\n // Strip path components (both Unix and Windows)\r\n name = name.replace(/^.*[/\\\\]/, '');\r\n\r\n // Strip control characters\r\n name = name.replace(/[\\x00-\\x1F\\x7F]/g, '');\r\n\r\n // Strip characters unsafe for filesystems\r\n name = name.replace(/[<>:\"/\\\\|?*]/g, '');\r\n\r\n // Replace spaces and parens with underscores\r\n name = name.replace(/[\\s()]+/g, '_');\r\n\r\n // Strip leading dots (hidden files / .htaccess)\r\n name = name.replace(/^\\.+/, '');\r\n\r\n // Collapse multiple underscores/dots\r\n name = name.replace(/_{2,}/g, '_');\r\n name = name.replace(/\\.{2,}/g, '.');\r\n\r\n // Trim underscores before dots (e.g., \"photo_1_.jpg\" → \"photo_1.jpg\")\r\n name = name.replace(/_+\\./g, '.');\r\n\r\n // Trim underscores from edges\r\n name = name.replace(/^_+|_+$/g, '');\r\n\r\n // Fallback for empty name\r\n if (!name || name === '.') {\r\n name = 'unnamed';\r\n }\r\n\r\n return name;\r\n}\r\n\r\n// =============================================================================\r\n// MAGIC BYTE VALIDATION\r\n// =============================================================================\r\n\r\n/**\r\n * Check if file content matches the claimed MIME type via magic bytes.\r\n */\r\nfunction matchesMagicBytes(buffer: Buffer, mimetype: string): boolean {\r\n const signatures = MAGIC_BYTES[mimetype];\r\n if (!signatures || signatures.length === 0) return true; // no signature to check\r\n\r\n return signatures.some(sig => {\r\n if (buffer.length < sig.length) return false;\r\n return buffer.subarray(0, sig.length).equals(sig);\r\n });\r\n}\r\n\r\n// =============================================================================\r\n// EXTENSION HELPERS\r\n// =============================================================================\r\n\r\n/**\r\n * Get the extension from a filename (lowercase, with dot).\r\n */\r\nfunction getExtension(filename: string): string {\r\n const lastDot = filename.lastIndexOf('.');\r\n if (lastDot < 1) return '';\r\n return filename.slice(lastDot).toLowerCase();\r\n}\r\n\r\n/**\r\n * Check if a filename has double extensions (e.g., file.php.jpg).\r\n */\r\nfunction hasDoubleExtension(filename: string): boolean {\r\n const parts = filename.split('.');\r\n if (parts.length < 3) return false;\r\n\r\n // Check if any non-final extension is dangerous\r\n for (let i = 1; i < parts.length - 1; i++) {\r\n const ext = '.' + parts[i].toLowerCase();\r\n if (DANGEROUS_EXTENSIONS.has(ext)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n// =============================================================================\r\n// FILE VALIDATION\r\n// =============================================================================\r\n\r\n/**\r\n * Validate a file upload for security.\r\n *\r\n * Checks file size, MIME type, extension, magic bytes, and dangerous patterns.\r\n * Returns a result with validation errors and a sanitized filename.\r\n *\r\n * @param file - File metadata and optional content\r\n * @param options - Validation options\r\n * @returns Validation result\r\n *\r\n * @example\r\n * const result = validateFile(\r\n * { filename: 'photo.jpg', mimetype: 'image/jpeg', size: 1024, buffer },\r\n * { allowedTypes: ['image/jpeg', 'image/png'], maxSize: 2 * 1024 * 1024 }\r\n * );\r\n * if (!result.valid) {\r\n * return res.status(400).json({ errors: result.errors });\r\n * }\r\n * // Use result.sanitizedFilename for storage\r\n *\r\n * @example\r\n * // Block executables only (no whitelist)\r\n * const result = validateFile(file, { blockExecutables: true });\r\n */\r\nexport function validateFile(\r\n file: FileInput,\r\n options: ValidateFileOptions = {}\r\n): ValidateFileResult {\r\n const {\r\n maxSize = DEFAULT_MAX_SIZE,\r\n allowedTypes,\r\n allowedExtensions,\r\n blockExecutables = true,\r\n validateMagicBytes = true,\r\n blockNoExtension = true,\r\n blockDoubleExtensions = true,\r\n } = options;\r\n\r\n const errors: string[] = [];\r\n const sanitizedFilename = sanitizeFilename(file.filename);\r\n const extension = getExtension(sanitizedFilename);\r\n\r\n // Size check\r\n if (file.size > maxSize) {\r\n errors.push(`File size ${file.size} exceeds maximum ${maxSize} bytes`);\r\n }\r\n\r\n if (file.size === 0) {\r\n errors.push('File is empty');\r\n }\r\n\r\n // Extension checks\r\n if (blockNoExtension && !extension) {\r\n errors.push('File has no extension');\r\n }\r\n\r\n if (blockExecutables && extension && DANGEROUS_EXTENSIONS.has(extension)) {\r\n errors.push(`Executable extension \"${extension}\" is not allowed`);\r\n }\r\n\r\n if (blockDoubleExtensions && hasDoubleExtension(sanitizedFilename)) {\r\n errors.push('Double extensions with executable types are not allowed');\r\n }\r\n\r\n if (allowedExtensions && extension) {\r\n const normalizedAllowed = allowedExtensions.map(e => e.toLowerCase());\r\n if (!normalizedAllowed.includes(extension)) {\r\n errors.push(`Extension \"${extension}\" is not allowed. Allowed: ${normalizedAllowed.join(', ')}`);\r\n }\r\n }\r\n\r\n // MIME type check\r\n if (allowedTypes && !allowedTypes.includes(file.mimetype)) {\r\n errors.push(`MIME type \"${file.mimetype}\" is not allowed. Allowed: ${allowedTypes.join(', ')}`);\r\n }\r\n\r\n // Magic bytes validation\r\n if (validateMagicBytes && file.buffer && file.buffer.length > 0) {\r\n if (!matchesMagicBytes(file.buffer, file.mimetype)) {\r\n errors.push(`File content does not match claimed MIME type \"${file.mimetype}\"`);\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n sanitizedFilename,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a file extension is considered dangerous/executable.\r\n *\r\n * @param filename - Filename or extension to check\r\n * @returns true if the extension is dangerous\r\n */\r\nexport function isDangerousExtension(filename: string): boolean {\r\n const ext = getExtension(filename);\r\n return ext !== '' && DANGEROUS_EXTENSIONS.has(ext);\r\n}\r\n","/**\r\n * @module @arcis/node/logging/redactor\r\n * Safe logging with PII/secret redaction\r\n */\r\n\r\nimport { REDACTION, INPUT } from '../core/constants';\r\nimport type { LogOptions, SafeLogger } from '../core/types';\r\n\r\n/**\r\n * Create a safe logger that redacts sensitive data and prevents log injection.\r\n * \r\n * @param options - Logger configuration\r\n * @returns SafeLogger instance\r\n * \r\n * @example\r\n * const logger = createSafeLogger();\r\n * logger.info('User login', { email: 'user@test.com', password: 'secret' });\r\n * // Logs: { \"email\": \"user@test.com\", \"password\": \"[REDACTED]\" }\r\n * \r\n * @example\r\n * // With custom redact keys\r\n * const logger = createSafeLogger({ redactKeys: ['customToken', 'internalId'] });\r\n */\r\nexport function createSafeLogger(options: LogOptions = {}): SafeLogger {\r\n const { \r\n redactKeys = [], \r\n maxLength = REDACTION.DEFAULT_MAX_LENGTH,\r\n redactPatterns = [],\r\n } = options;\r\n\r\n // Combine default and custom keys (lowercase for case-insensitive matching)\r\n const allRedactKeys = new Set([\r\n ...Array.from(REDACTION.SENSITIVE_KEYS),\r\n ...redactKeys.map(k => k.toLowerCase()),\r\n ]);\r\n\r\n /**\r\n * Redact sensitive data from an object recursively.\r\n */\r\n function redact(obj: unknown, depth = 0): unknown {\r\n if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\r\n if (obj === null || obj === undefined) return obj;\r\n\r\n if (typeof obj === 'string') {\r\n return redactString(obj, maxLength, redactPatterns);\r\n }\r\n\r\n if (typeof obj !== 'object') return obj;\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => redact(item, depth + 1));\r\n }\r\n\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\r\n if (allRedactKeys.has(key.toLowerCase())) {\r\n result[key] = REDACTION.REPLACEMENT;\r\n } else {\r\n result[key] = redact(value, depth + 1);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Log a message at the specified level.\r\n */\r\n function log(level: string, message: string, data?: unknown): void {\r\n const entry: Record<string, unknown> = {\r\n timestamp: new Date().toISOString(),\r\n level,\r\n message: redactString(message, maxLength, redactPatterns),\r\n };\r\n \r\n if (data !== undefined) {\r\n entry.data = redact(data);\r\n }\r\n \r\n console.log(JSON.stringify(entry));\r\n }\r\n\r\n return {\r\n log,\r\n info: (msg: string, data?: unknown) => log('info', msg, data),\r\n warn: (msg: string, data?: unknown) => log('warn', msg, data),\r\n error: (msg: string, data?: unknown) => log('error', msg, data),\r\n debug: (msg: string, data?: unknown) => log('debug', msg, data),\r\n };\r\n}\r\n\r\n/**\r\n * Redact a string value.\r\n * Removes newlines (log injection prevention), applies patterns, and truncates.\r\n */\r\nfunction redactString(str: string, maxLength: number, patterns: RegExp[]): string {\r\n // Remove newlines/tabs (log injection prevention) and genuine control characters.\r\n // Only strip C0/C1 control chars and null bytes — preserve all printable Unicode\r\n // (CJK, Cyrillic, Arabic, etc.) so multilingual content isn't silently lost.\r\n let safe = str\r\n .replace(/[\\r\\n\\t]/g, ' ')\r\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F\\x80-\\x9F]/g, '');\r\n\r\n // Apply custom redaction patterns\r\n for (const pattern of patterns) {\r\n safe = safe.replace(pattern, REDACTION.REPLACEMENT);\r\n }\r\n\r\n // Truncate if too long\r\n if (safe.length > maxLength) {\r\n safe = safe.substring(0, maxLength) + `...${REDACTION.TRUNCATED}`;\r\n }\r\n\r\n return safe;\r\n}\r\n\r\n/**\r\n * Create a redactor function for custom use.\r\n * \r\n * @param sensitiveKeys - Keys to redact\r\n * @returns Redactor function\r\n */\r\nexport function createRedactor(sensitiveKeys: string[] = []): (obj: unknown) => unknown {\r\n const allKeys = new Set([\r\n ...Array.from(REDACTION.SENSITIVE_KEYS),\r\n ...sensitiveKeys.map(k => k.toLowerCase()),\r\n ]);\r\n\r\n function redact(obj: unknown, depth = 0): unknown {\r\n if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\r\n if (obj === null || obj === undefined) return obj;\r\n if (typeof obj !== 'object') return obj;\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => redact(item, depth + 1));\r\n }\r\n\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\r\n if (allKeys.has(key.toLowerCase())) {\r\n result[key] = REDACTION.REPLACEMENT;\r\n } else {\r\n result[key] = redact(value, depth + 1);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n return redact;\r\n}\r\n\r\n/**\r\n * Alias for createSafeLogger\r\n * @see createSafeLogger\r\n */\r\nexport const safeLog = createSafeLogger;\r\n","/**\r\n * @module @arcis/node/middleware/main\r\n * Main arcis() middleware factory\r\n */\r\n\r\nimport type { RequestHandler } from 'express';\r\nimport type {\r\n ArcisOptions,\r\n ArcisFunction,\r\n ArcisMiddlewareStack,\r\n HeaderOptions,\r\n RateLimitOptions,\r\n SanitizeOptions,\r\n} from '../core/types';\r\nimport { createHeaders } from './headers';\r\nimport { createRateLimiter } from './rate-limit';\r\nimport { createErrorHandler } from './error-handler';\r\nimport { createSanitizer } from '../sanitizers';\r\nimport { validate } from '../validation';\r\nimport { createSafeLogger } from '../logging';\r\n\r\n/**\r\n * Create Arcis middleware with all protections enabled.\r\n * \r\n * @param options - Configuration options\r\n * @returns Array of Express middleware\r\n * \r\n * @example\r\n * // Full protection (recommended)\r\n * app.use(arcis());\r\n * \r\n * @example\r\n * // Custom configuration\r\n * app.use(arcis({\r\n * rateLimit: { max: 50 },\r\n * headers: { frameOptions: 'SAMEORIGIN' }\r\n * }));\r\n * \r\n * @example\r\n * // Disable specific features\r\n * app.use(arcis({\r\n * rateLimit: false,\r\n * sanitize: { sql: false }\r\n * }));\r\n * \r\n * @example\r\n * // Cleanup on shutdown\r\n * const middleware = arcis();\r\n * app.use(middleware);\r\n * process.on('SIGTERM', () => middleware.close());\r\n */\r\nexport function arcis(options: ArcisOptions = {}): ArcisMiddlewareStack {\r\n const middlewares: RequestHandler[] = [];\r\n const cleanupFns: (() => void)[] = [];\r\n\r\n // Security headers (first, always)\r\n if (options.headers !== false) {\r\n const headerOpts: HeaderOptions = typeof options.headers === 'object' \r\n ? options.headers \r\n : {};\r\n middlewares.push(createHeaders(headerOpts));\r\n }\r\n\r\n // Rate limiting\r\n if (options.rateLimit !== false) {\r\n const rateLimitOpts: RateLimitOptions = typeof options.rateLimit === 'object' \r\n ? options.rateLimit \r\n : {};\r\n const rateLimiter = createRateLimiter(rateLimitOpts);\r\n middlewares.push(rateLimiter);\r\n cleanupFns.push(() => rateLimiter.close());\r\n }\r\n\r\n // Input sanitization (last, after body parsing)\r\n if (options.sanitize !== false) {\r\n const sanitizeOpts: SanitizeOptions = typeof options.sanitize === 'object' \r\n ? options.sanitize \r\n : {};\r\n middlewares.push(createSanitizer(sanitizeOpts));\r\n }\r\n\r\n // Attach close() directly on the array so callers can clean up without any-casts.\r\n const result = middlewares as ArcisMiddlewareStack;\r\n result.close = () => {\r\n for (const fn of cleanupFns) {\r\n fn();\r\n }\r\n };\r\n\r\n return result;\r\n}\r\n\r\n// Attach individual functions for granular use\r\nconst arcisWithMethods = arcis as ArcisFunction;\r\narcisWithMethods.sanitize = createSanitizer;\r\narcisWithMethods.rateLimit = createRateLimiter;\r\narcisWithMethods.headers = createHeaders;\r\narcisWithMethods.validate = validate;\r\narcisWithMethods.logger = createSafeLogger;\r\narcisWithMethods.errorHandler = createErrorHandler;\r\n\r\nexport { arcisWithMethods as arcisFunction };\r\nexport default arcisWithMethods;\r\n","/**\r\n * @module @arcis/node/middleware/cors\r\n * Safe CORS middleware with secure defaults\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\n\r\n/** CORS configuration options */\r\nexport interface CorsOptions {\r\n /**\r\n * Allowed origins. Can be:\r\n * - A string: exact match (e.g., 'https://example.com')\r\n * - An array: whitelist of allowed origins\r\n * - A RegExp: pattern match (use with care)\r\n * - A function: custom validation `(origin) => boolean`\r\n * - `true`: reflect the request origin (DANGEROUS — only for dev)\r\n *\r\n * Default: none (no origin allowed). You must explicitly set this.\r\n */\r\n origin: string | string[] | RegExp | ((origin: string) => boolean) | true;\r\n\r\n /** Allowed HTTP methods. Default: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] */\r\n methods?: string[];\r\n\r\n /** Allowed headers. Default: ['Content-Type', 'Authorization'] */\r\n allowedHeaders?: string[];\r\n\r\n /** Headers exposed to the browser. Default: [] */\r\n exposedHeaders?: string[];\r\n\r\n /** Allow credentials (cookies, authorization headers). Default: false */\r\n credentials?: boolean;\r\n\r\n /** Preflight cache duration in seconds. Default: 600 (10 minutes) */\r\n maxAge?: number;\r\n\r\n /** Respond to preflight with 204 (no content). Default: true */\r\n preflightContinue?: boolean;\r\n}\r\n\r\nconst DEFAULT_METHODS = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];\r\nconst DEFAULT_HEADERS = ['Content-Type', 'Authorization'];\r\nconst DEFAULT_MAX_AGE = 600;\r\n\r\n/**\r\n * Check if an origin is allowed by the configured policy.\r\n */\r\nfunction isOriginAllowed(\r\n requestOrigin: string,\r\n allowed: CorsOptions['origin']\r\n): boolean {\r\n // 'null' origin is always blocked — sent by sandboxed iframes, data: URIs, etc.\r\n if (requestOrigin === 'null') return false;\r\n\r\n if (allowed === true) return true;\r\n\r\n if (typeof allowed === 'string') {\r\n return requestOrigin === allowed;\r\n }\r\n\r\n if (Array.isArray(allowed)) {\r\n return allowed.includes(requestOrigin);\r\n }\r\n\r\n if (allowed instanceof RegExp) {\r\n return allowed.test(requestOrigin);\r\n }\r\n\r\n if (typeof allowed === 'function') {\r\n return allowed(requestOrigin);\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Create safe CORS middleware.\r\n *\r\n * Unlike permissive CORS libraries, this enforces secure defaults:\r\n * - No wildcard `*` when credentials are enabled\r\n * - `null` origin is always blocked\r\n * - `Vary: Origin` is always set for proper caching\r\n * - You must explicitly configure allowed origins\r\n *\r\n * @param options - CORS configuration\r\n * @returns Express middleware\r\n *\r\n * @example\r\n * // Allow a single origin\r\n * app.use(safeCors({ origin: 'https://myapp.com' }));\r\n *\r\n * @example\r\n * // Allow multiple origins with credentials\r\n * app.use(safeCors({\r\n * origin: ['https://myapp.com', 'https://admin.myapp.com'],\r\n * credentials: true,\r\n * }));\r\n *\r\n * @example\r\n * // Development: allow all (NOT for production)\r\n * app.use(safeCors({ origin: true }));\r\n */\r\nexport function safeCors(options: CorsOptions): RequestHandler {\r\n const {\r\n origin,\r\n methods = DEFAULT_METHODS,\r\n allowedHeaders = DEFAULT_HEADERS,\r\n exposedHeaders = [],\r\n credentials = false,\r\n maxAge = DEFAULT_MAX_AGE,\r\n preflightContinue = true,\r\n } = options;\r\n\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const requestOrigin = req.headers.origin;\r\n\r\n // Always set Vary: Origin for proper caching\r\n res.setHeader('Vary', 'Origin');\r\n\r\n // No origin header = same-origin request, skip CORS headers\r\n if (!requestOrigin) {\r\n return next();\r\n }\r\n\r\n const allowed = isOriginAllowed(requestOrigin, origin);\r\n\r\n if (!allowed) {\r\n // Don't set any CORS headers — browser will block the request\r\n return next();\r\n }\r\n\r\n // Set Access-Control-Allow-Origin to the specific origin (not *)\r\n res.setHeader('Access-Control-Allow-Origin', requestOrigin);\r\n\r\n if (credentials) {\r\n res.setHeader('Access-Control-Allow-Credentials', 'true');\r\n }\r\n\r\n if (exposedHeaders.length > 0) {\r\n res.setHeader('Access-Control-Expose-Headers', exposedHeaders.join(', '));\r\n }\r\n\r\n // Handle preflight requests\r\n if (req.method === 'OPTIONS') {\r\n res.setHeader('Access-Control-Allow-Methods', methods.join(', '));\r\n res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));\r\n res.setHeader('Access-Control-Max-Age', String(maxAge));\r\n\r\n if (preflightContinue) {\r\n res.status(204).end();\r\n return;\r\n }\r\n }\r\n\r\n next();\r\n };\r\n}\r\n\r\n/**\r\n * Alias for safeCors\r\n * @see safeCors\r\n */\r\nexport const createCors = safeCors;\r\n","/**\r\n * @module @arcis/node/middleware/cookies\r\n * Secure cookie defaults middleware\r\n */\r\n\r\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\r\n\r\n/** Cookie security configuration */\r\nexport interface SecureCookieOptions {\r\n /** Force HttpOnly on all cookies. Default: true */\r\n httpOnly?: boolean;\r\n /** Force Secure flag (HTTPS only). Default: true in production, false in dev */\r\n secure?: boolean;\r\n /** SameSite attribute. Default: 'Lax' */\r\n sameSite?: 'Strict' | 'Lax' | 'None' | false;\r\n /** Override Path attribute. Default: undefined (keep original) */\r\n path?: string;\r\n}\r\n\r\nconst COOKIE_ATTRS = {\r\n HTTP_ONLY: '; HttpOnly',\r\n SECURE: '; Secure',\r\n SAME_SITE_STRICT: '; SameSite=Strict',\r\n SAME_SITE_LAX: '; SameSite=Lax',\r\n SAME_SITE_NONE: '; SameSite=None',\r\n} as const;\r\n\r\n/**\r\n * Enforce secure defaults on a Set-Cookie header value.\r\n */\r\nexport function enforceSecureCookie(\r\n cookieStr: string,\r\n options: Required<Omit<SecureCookieOptions, 'path'>> & { path?: string }\r\n): string {\r\n const lower = cookieStr.toLowerCase();\r\n let result = cookieStr;\r\n\r\n // HttpOnly — prevent JavaScript access\r\n if (options.httpOnly && !lower.includes('httponly')) {\r\n result += COOKIE_ATTRS.HTTP_ONLY;\r\n }\r\n\r\n // Secure — HTTPS only\r\n if (options.secure && !lower.includes('; secure')) {\r\n result += COOKIE_ATTRS.SECURE;\r\n }\r\n\r\n // SameSite — CSRF protection\r\n if (options.sameSite !== false && !lower.includes('samesite')) {\r\n switch (options.sameSite) {\r\n case 'Strict':\r\n result += COOKIE_ATTRS.SAME_SITE_STRICT;\r\n break;\r\n case 'None':\r\n result += COOKIE_ATTRS.SAME_SITE_NONE;\r\n // SameSite=None requires Secure\r\n if (!result.toLowerCase().includes('; secure')) {\r\n result += COOKIE_ATTRS.SECURE;\r\n }\r\n break;\r\n case 'Lax':\r\n default:\r\n result += COOKIE_ATTRS.SAME_SITE_LAX;\r\n break;\r\n }\r\n }\r\n\r\n // Override path if specified\r\n if (options.path) {\r\n if (lower.includes('path=')) {\r\n result = result.replace(/;\\s*path=[^;]*/i, `; Path=${options.path}`);\r\n } else {\r\n result += `; Path=${options.path}`;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Create middleware that enforces secure cookie defaults.\r\n *\r\n * Intercepts Set-Cookie headers and adds missing security attributes:\r\n * - HttpOnly: prevents JavaScript access (XSS cookie theft)\r\n * - Secure: cookies only sent over HTTPS\r\n * - SameSite: CSRF protection\r\n *\r\n * @param options - Cookie security configuration\r\n * @returns Express middleware\r\n *\r\n * @example\r\n * // Enforce defaults on all cookies\r\n * app.use(secureCookieDefaults());\r\n *\r\n * @example\r\n * // Strict SameSite for sensitive apps\r\n * app.use(secureCookieDefaults({ sameSite: 'Strict' }));\r\n */\r\nexport function secureCookieDefaults(options: SecureCookieOptions = {}): RequestHandler {\r\n const isProduction = process.env.NODE_ENV === 'production';\r\n const resolved = {\r\n httpOnly: options.httpOnly ?? true,\r\n secure: options.secure ?? isProduction,\r\n sameSite: options.sameSite ?? 'Lax' as const,\r\n path: options.path,\r\n };\r\n\r\n return (_req: Request, res: Response, next: NextFunction) => {\r\n // Monkey-patch res.setHeader to intercept Set-Cookie\r\n const originalSetHeader = res.setHeader.bind(res);\r\n\r\n res.setHeader = function patchedSetHeader(name: string, value: string | number | readonly string[]) {\r\n if (name.toLowerCase() === 'set-cookie') {\r\n if (Array.isArray(value)) {\r\n value = value.map(v => enforceSecureCookie(String(v), resolved));\r\n } else {\r\n value = enforceSecureCookie(String(value), resolved);\r\n }\r\n }\r\n return originalSetHeader(name, value);\r\n } as typeof res.setHeader;\r\n\r\n next();\r\n };\r\n}\r\n\r\n/**\r\n * Alias for secureCookieDefaults\r\n * @see secureCookieDefaults\r\n */\r\nexport const createSecureCookies = secureCookieDefaults;\r\n","/**\r\n * @module @arcis/node/validation/url\r\n * SSRF (Server-Side Request Forgery) prevention\r\n *\r\n * Validates URLs to ensure they don't target private/internal networks,\r\n * localhost, cloud metadata endpoints, or use dangerous protocols.\r\n *\r\n * @example\r\n * import { validateUrl } from '@arcis/node';\r\n *\r\n * // Block SSRF attempts\r\n * validateUrl('http://169.254.169.254/latest/meta-data/') // { safe: false, reason: 'link-local address' }\r\n * validateUrl('http://10.0.0.1/admin') // { safe: false, reason: 'private address (10.0.0.0/8)' }\r\n * validateUrl('http://localhost/secret') // { safe: false, reason: 'loopback address' }\r\n * validateUrl('file:///etc/passwd') // { safe: false, reason: 'disallowed protocol: file:' }\r\n *\r\n * // Allow safe URLs\r\n * validateUrl('https://api.example.com/data') // { safe: true }\r\n */\r\n\r\n/** Options for URL validation */\r\nexport interface ValidateUrlOptions {\r\n /** Allowed protocols. Default: ['http:', 'https:'] */\r\n allowedProtocols?: string[];\r\n /** Additional hostnames to block (e.g., internal service names) */\r\n blockedHosts?: string[];\r\n /** Additional hostnames to always allow (bypass IP checks) */\r\n allowedHosts?: string[];\r\n /** Allow localhost/loopback. Default: false */\r\n allowLocalhost?: boolean;\r\n /** Allow private/internal IPs. Default: false */\r\n allowPrivate?: boolean;\r\n}\r\n\r\n/** Result of URL validation */\r\nexport interface ValidateUrlResult {\r\n /** Whether the URL is safe to fetch */\r\n safe: boolean;\r\n /** Reason the URL was blocked (only set when safe=false) */\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Validate a URL for SSRF safety.\r\n *\r\n * Checks:\r\n * 1. Valid URL format\r\n * 2. Allowed protocol (default: http, https only)\r\n * 3. Not localhost/loopback (127.x.x.x, ::1, localhost)\r\n * 4. Not private IP (10.x, 172.16-31.x, 192.168.x)\r\n * 5. Not link-local (169.254.x.x — includes AWS/GCP/Azure metadata)\r\n * 6. Not blocked hostname\r\n * 7. No credentials in URL (user:pass@host)\r\n *\r\n * @param url - The URL string to validate\r\n * @param options - Validation options\r\n * @returns Validation result with safe flag and optional reason\r\n */\r\nexport function validateUrl(url: string, options: ValidateUrlOptions = {}): ValidateUrlResult {\r\n const {\r\n allowedProtocols = ['http:', 'https:'],\r\n blockedHosts = [],\r\n allowedHosts = [],\r\n allowLocalhost = false,\r\n allowPrivate = false,\r\n } = options;\r\n\r\n if (typeof url !== 'string' || url.trim() === '') {\r\n return { safe: false, reason: 'invalid URL: empty or not a string' };\r\n }\r\n\r\n // Parse URL\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(url);\r\n } catch {\r\n return { safe: false, reason: 'invalid URL: failed to parse' };\r\n }\r\n\r\n // Check protocol\r\n if (!allowedProtocols.includes(parsed.protocol)) {\r\n return { safe: false, reason: `disallowed protocol: ${parsed.protocol}` };\r\n }\r\n\r\n // Check for credentials in URL (user:pass@host)\r\n if (parsed.username || parsed.password) {\r\n return { safe: false, reason: 'URL contains credentials' };\r\n }\r\n\r\n const hostname = parsed.hostname.toLowerCase();\r\n\r\n // Check explicit allowlist first (bypass IP checks)\r\n if (allowedHosts.some(h => hostname === h.toLowerCase())) {\r\n return { safe: true };\r\n }\r\n\r\n // Check explicit blocklist\r\n if (blockedHosts.some(h => hostname === h.toLowerCase())) {\r\n return { safe: false, reason: `blocked host: ${hostname}` };\r\n }\r\n\r\n // Check localhost/loopback\r\n if (!allowLocalhost) {\r\n if (\r\n hostname === 'localhost' ||\r\n hostname === '127.0.0.1' ||\r\n hostname === '[::1]' ||\r\n hostname === '::1' ||\r\n hostname === '0.0.0.0' ||\r\n hostname.endsWith('.localhost')\r\n ) {\r\n return { safe: false, reason: 'loopback address' };\r\n }\r\n\r\n // Check 127.x.x.x range\r\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\r\n return { safe: false, reason: 'loopback address' };\r\n }\r\n }\r\n\r\n // Check private/internal IPs\r\n if (!allowPrivate) {\r\n const privateCheck = checkPrivateIp(hostname);\r\n if (privateCheck) {\r\n return { safe: false, reason: privateCheck };\r\n }\r\n }\r\n\r\n return { safe: true };\r\n}\r\n\r\n/**\r\n * Convenience wrapper that returns true/false.\r\n *\r\n * @param url - The URL to check\r\n * @param options - Validation options\r\n * @returns true if the URL is safe to fetch\r\n */\r\nexport function isUrlSafe(url: string, options: ValidateUrlOptions = {}): boolean {\r\n return validateUrl(url, options).safe;\r\n}\r\n\r\n/**\r\n * Check if a hostname is a private/internal IP address.\r\n * Returns the reason string if private, or null if not.\r\n */\r\nfunction checkPrivateIp(hostname: string): string | null {\r\n // 10.0.0.0/8\r\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\r\n return 'private address (10.0.0.0/8)';\r\n }\r\n\r\n // 172.16.0.0/12 (172.16.x.x - 172.31.x.x)\r\n const match172 = hostname.match(/^172\\.(\\d{1,3})\\.\\d{1,3}\\.\\d{1,3}$/);\r\n if (match172) {\r\n const second = parseInt(match172[1], 10);\r\n if (second >= 16 && second <= 31) {\r\n return 'private address (172.16.0.0/12)';\r\n }\r\n }\r\n\r\n // 192.168.0.0/16\r\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\r\n return 'private address (192.168.0.0/16)';\r\n }\r\n\r\n // 169.254.0.0/16 — link-local, includes cloud metadata endpoints\r\n // AWS: 169.254.169.254, GCP: metadata.google.internal, Azure: 169.254.169.254\r\n if (/^169\\.254\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\r\n return 'link-local address (169.254.0.0/16)';\r\n }\r\n\r\n // 0.0.0.0/8 (current network)\r\n if (/^0\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\r\n return 'current network address (0.0.0.0/8)';\r\n }\r\n\r\n // Cloud metadata hostnames\r\n if (\r\n hostname === 'metadata.google.internal' ||\r\n hostname === 'metadata.internal'\r\n ) {\r\n return 'cloud metadata endpoint';\r\n }\r\n\r\n // IPv6 private ranges (simplified — bracket-wrapped in URLs)\r\n const ipv6 = hostname.replace(/^\\[|\\]$/g, '');\r\n if (\r\n ipv6 === '::1' ||\r\n ipv6 === '::' ||\r\n ipv6.startsWith('fc') ||\r\n ipv6.startsWith('fd') ||\r\n ipv6.startsWith('fe80')\r\n ) {\r\n return 'private IPv6 address';\r\n }\r\n\r\n return null;\r\n}\r\n","/**\r\n * @module @arcis/node/validation/redirect\r\n * Open Redirect prevention\r\n *\r\n * Prevents attackers from using your app to redirect users to malicious sites\r\n * via manipulated query parameters like ?returnUrl=http://evil.com\r\n *\r\n * @example\r\n * import { validateRedirect, isRedirectSafe } from '@arcis/node';\r\n *\r\n * // Block open redirects\r\n * validateRedirect('http://evil.com') // { safe: false, reason: 'absolute URL not in allowed hosts' }\r\n * validateRedirect('//evil.com') // { safe: false, reason: 'protocol-relative URL not in allowed hosts' }\r\n * validateRedirect('javascript:alert(1)') // { safe: false, reason: 'dangerous protocol: javascript:' }\r\n *\r\n * // Allow safe redirects\r\n * validateRedirect('/dashboard') // { safe: true }\r\n * validateRedirect('/users?page=2') // { safe: true }\r\n * validateRedirect('https://myapp.com/home', { allowedHosts: ['myapp.com'] }) // { safe: true }\r\n */\r\n\r\n/** Options for redirect validation */\r\nexport interface ValidateRedirectOptions {\r\n /** Hostnames that are allowed for absolute URL redirects */\r\n allowedHosts?: string[];\r\n /** Allow protocol-relative URLs (//example.com). Default: false */\r\n allowProtocolRelative?: boolean;\r\n /** Allowed protocols for absolute URLs. Default: ['http:', 'https:'] */\r\n allowedProtocols?: string[];\r\n}\r\n\r\n/** Result of redirect validation */\r\nexport interface ValidateRedirectResult {\r\n /** Whether the redirect URL is safe */\r\n safe: boolean;\r\n /** Reason the redirect was blocked (only set when safe=false) */\r\n reason?: string;\r\n}\r\n\r\n/** Protocols that can execute code or exfiltrate data */\r\nconst DANGEROUS_PROTOCOLS = /^(javascript|data|vbscript|blob):/i;\r\n\r\n/** Characters used to disguise URLs (tabs, newlines inside scheme) */\r\nconst CONTROL_CHARS = /[\\t\\n\\r]/g;\r\n\r\n/**\r\n * Validate a redirect URL to prevent open redirect attacks.\r\n *\r\n * Safe redirects:\r\n * - Relative paths: /dashboard, /users?page=2, ../settings\r\n * - Absolute URLs to allowed hosts (when configured)\r\n *\r\n * Blocked redirects:\r\n * - Absolute URLs to unknown hosts\r\n * - Protocol-relative URLs (//evil.com)\r\n * - javascript:, data:, vbscript:, blob: protocols\r\n * - Backslash-prefixed paths (\\\\evil.com — browser treats as //)\r\n * - URLs with control characters that could disguise the target\r\n *\r\n * @param url - The redirect target URL to validate\r\n * @param options - Validation options\r\n * @returns Validation result with safe flag and optional reason\r\n */\r\nexport function validateRedirect(\r\n url: string,\r\n options: ValidateRedirectOptions = {},\r\n): ValidateRedirectResult {\r\n const {\r\n allowedHosts = [],\r\n allowProtocolRelative = false,\r\n allowedProtocols = ['http:', 'https:'],\r\n } = options;\r\n\r\n if (typeof url !== 'string' || url.trim() === '') {\r\n return { safe: false, reason: 'invalid redirect: empty or not a string' };\r\n }\r\n\r\n // Strip control characters that could disguise the URL\r\n const cleaned = url.replace(CONTROL_CHARS, '');\r\n\r\n // Block dangerous protocols (javascript:, data:, etc.)\r\n if (DANGEROUS_PROTOCOLS.test(cleaned)) {\r\n const proto = cleaned.match(DANGEROUS_PROTOCOLS);\r\n return { safe: false, reason: `dangerous protocol: ${proto![0]}` };\r\n }\r\n\r\n // Block backslash-prefixed paths — browsers treat \\ as / in URLs\r\n // so \\evil.com or \\/evil.com could redirect to //evil.com\r\n if (cleaned.startsWith('\\\\')) {\r\n return { safe: false, reason: 'backslash-prefixed URL (browser treats as protocol-relative)' };\r\n }\r\n\r\n // Check protocol-relative URLs (//evil.com)\r\n if (cleaned.startsWith('//')) {\r\n if (!allowProtocolRelative) {\r\n // Still check allowedHosts\r\n const host = extractHost(cleaned);\r\n if (host && allowedHosts.some(h => host === h.toLowerCase())) {\r\n return { safe: true };\r\n }\r\n return { safe: false, reason: 'protocol-relative URL not in allowed hosts' };\r\n }\r\n const host = extractHost(cleaned);\r\n if (host && allowedHosts.length > 0 && !allowedHosts.some(h => host === h.toLowerCase())) {\r\n return { safe: false, reason: 'protocol-relative URL not in allowed hosts' };\r\n }\r\n return { safe: true };\r\n }\r\n\r\n // Check if it's an absolute URL (has scheme)\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(cleaned);\r\n } catch {\r\n // Not a valid absolute URL — treat as relative path (safe)\r\n return { safe: true };\r\n }\r\n\r\n // If we got here, it parsed as an absolute URL\r\n // Check protocol\r\n if (!allowedProtocols.includes(parsed.protocol)) {\r\n return { safe: false, reason: `disallowed protocol: ${parsed.protocol}` };\r\n }\r\n\r\n // Check if host is in allowed list\r\n const hostname = parsed.hostname.toLowerCase();\r\n if (allowedHosts.length === 0) {\r\n return { safe: false, reason: 'absolute URL not in allowed hosts' };\r\n }\r\n\r\n if (!allowedHosts.some(h => hostname === h.toLowerCase())) {\r\n return { safe: false, reason: `host not allowed: ${hostname}` };\r\n }\r\n\r\n return { safe: true };\r\n}\r\n\r\n/**\r\n * Convenience wrapper that returns true/false.\r\n *\r\n * @param url - The redirect URL to check\r\n * @param options - Validation options\r\n * @returns true if the redirect is safe\r\n */\r\nexport function isRedirectSafe(url: string, options: ValidateRedirectOptions = {}): boolean {\r\n return validateRedirect(url, options).safe;\r\n}\r\n\r\n/**\r\n * Extract hostname from a protocol-relative URL.\r\n */\r\nfunction extractHost(url: string): string | null {\r\n // //hostname/path or //hostname:port/path\r\n const match = url.match(/^\\/\\/([^/:?#]+)/);\r\n return match ? match[1].toLowerCase() : null;\r\n}\r\n","/**\r\n * @module @arcis/node/stores/memory\r\n * In-memory rate limit store\r\n */\r\n\r\nimport type { RateLimitStore, RateLimitEntry } from '../core/types';\r\nimport { RATE_LIMIT } from '../core/constants';\r\n\r\n/**\r\n * In-memory rate limit store.\r\n * Suitable for single-instance deployments.\r\n * For distributed systems, use RedisStore or a custom store.\r\n * \r\n * @example\r\n * const store = new MemoryStore(60000); // 1 minute window\r\n * const limiter = createRateLimiter({ store });\r\n */\r\nexport class MemoryStore implements RateLimitStore {\r\n private store: Map<string, RateLimitEntry> = new Map();\r\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\r\n private windowMs: number;\r\n\r\n constructor(windowMs: number = RATE_LIMIT.DEFAULT_WINDOW_MS) {\r\n if (!Number.isFinite(windowMs) || windowMs < RATE_LIMIT.MIN_WINDOW_MS) {\r\n throw new RangeError(\r\n `MemoryStore: windowMs must be a finite number >= ${RATE_LIMIT.MIN_WINDOW_MS} (got ${windowMs})`\r\n );\r\n }\r\n this.windowMs = windowMs;\r\n this.startCleanup();\r\n }\r\n\r\n /**\r\n * Start the cleanup interval to remove expired entries.\r\n */\r\n private startCleanup(): void {\r\n // Clamp the cleanup interval between 30 s and 5 min regardless of windowMs.\r\n // Running it every windowMs is fine for typical windows but would fire every\r\n // second for short windows (e.g. windowMs: 1000), causing O(n) GC pressure.\r\n const CLEANUP_MIN_MS = 30_000;\r\n const CLEANUP_MAX_MS = 300_000;\r\n const cleanupMs = Math.min(Math.max(this.windowMs, CLEANUP_MIN_MS), CLEANUP_MAX_MS);\r\n\r\n this.cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of this.store.entries()) {\r\n if (entry.resetTime < now) {\r\n this.store.delete(key);\r\n }\r\n }\r\n }, cleanupMs);\r\n\r\n // Prevent interval from keeping the process alive\r\n if (typeof this.cleanupInterval.unref === 'function') {\r\n this.cleanupInterval.unref();\r\n }\r\n }\r\n\r\n async get(key: string): Promise<RateLimitEntry | null> {\r\n const entry = this.store.get(key);\r\n if (!entry) return null;\r\n \r\n // Check if expired\r\n if (entry.resetTime < Date.now()) {\r\n this.store.delete(key);\r\n return null;\r\n }\r\n \r\n return entry;\r\n }\r\n\r\n async set(key: string, entry: RateLimitEntry): Promise<void> {\r\n this.store.set(key, entry);\r\n }\r\n\r\n async increment(key: string): Promise<number> {\r\n const now = Date.now();\r\n const entry = this.store.get(key);\r\n \r\n if (!entry || entry.resetTime < now) {\r\n // Start new window\r\n this.store.set(key, { count: 1, resetTime: now + this.windowMs });\r\n return 1;\r\n }\r\n \r\n entry.count++;\r\n return entry.count;\r\n }\r\n\r\n async decrement(key: string): Promise<void> {\r\n const entry = this.store.get(key);\r\n if (entry && entry.count > 0) {\r\n entry.count--;\r\n }\r\n }\r\n\r\n async reset(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n }\r\n this.store.clear();\r\n }\r\n\r\n /**\r\n * Get current store size (for monitoring).\r\n */\r\n get size(): number {\r\n return this.store.size;\r\n }\r\n}\r\n","/**\r\n * @module @arcis/node/stores/redis\r\n * Redis rate limit store\r\n * \r\n * Note: This is a reference implementation. You'll need to install\r\n * the 'ioredis' or 'redis' package and pass your client instance.\r\n */\r\n\r\nimport type { RateLimitStore, RateLimitEntry } from '../core/types';\r\nimport { RATE_LIMIT } from '../core/constants';\r\n\r\n/** Generic Redis client interface (works with ioredis, redis, etc.) */\r\nexport interface RedisClientLike {\r\n get(key: string): Promise<string | null>;\r\n set(key: string, value: string, mode?: string, duration?: number): Promise<unknown>;\r\n setex(key: string, seconds: number, value: string): Promise<unknown>;\r\n expire(key: string, seconds: number): Promise<unknown>;\r\n incr(key: string): Promise<number>;\r\n decr(key: string): Promise<number>;\r\n del(key: string): Promise<number>;\r\n ttl(key: string): Promise<number>;\r\n quit?(): Promise<unknown>;\r\n disconnect?(): Promise<unknown>;\r\n}\r\n\r\nexport interface RedisStoreOptions {\r\n /** Redis client instance */\r\n client: RedisClientLike;\r\n /** Key prefix. Default: 'arcis:rl:' */\r\n prefix?: string;\r\n /** Window size in milliseconds. Default: 60000 */\r\n windowMs?: number;\r\n}\r\n\r\n/**\r\n * Redis rate limit store for distributed deployments.\r\n * \r\n * @example\r\n * import Redis from 'ioredis';\r\n * \r\n * const redis = new Redis();\r\n * const store = new RedisStore({ client: redis });\r\n * const limiter = createRateLimiter({ store });\r\n * \r\n * // Cleanup on shutdown\r\n * process.on('SIGTERM', async () => {\r\n * await store.close();\r\n * });\r\n */\r\nexport class RedisStore implements RateLimitStore {\r\n private client: RedisClientLike;\r\n private prefix: string;\r\n private windowMs: number;\r\n private windowSec: number;\r\n\r\n constructor(options: RedisStoreOptions) {\r\n this.client = options.client;\r\n this.prefix = options.prefix ?? 'arcis:rl:';\r\n this.windowMs = options.windowMs ?? RATE_LIMIT.DEFAULT_WINDOW_MS;\r\n this.windowSec = Math.ceil(this.windowMs / 1000);\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}${key}`;\r\n }\r\n\r\n async get(key: string): Promise<RateLimitEntry | null> {\r\n const redisKey = this.getKey(key);\r\n \r\n const [countStr, ttl] = await Promise.all([\r\n this.client.get(redisKey),\r\n this.client.ttl(redisKey),\r\n ]);\r\n \r\n if (!countStr || ttl < 0) {\r\n return null;\r\n }\r\n \r\n const count = parseInt(countStr, 10);\r\n if (isNaN(count)) {\r\n // Corrupt value in Redis — treat as if key doesn't exist\r\n return null;\r\n }\r\n\r\n return {\r\n count,\r\n resetTime: Date.now() + (ttl * 1000),\r\n };\r\n }\r\n\r\n async set(key: string, entry: RateLimitEntry): Promise<void> {\r\n const redisKey = this.getKey(key);\r\n // Clamp to at least 1 second — Math.ceil can produce 0 or negative values\r\n // when entry.resetTime is in the past due to Redis latency or clock skew.\r\n const ttlSec = Math.max(1, Math.ceil((entry.resetTime - Date.now()) / 1000));\r\n await this.client.setex(redisKey, ttlSec, entry.count.toString());\r\n }\r\n\r\n async increment(key: string): Promise<number> {\r\n const redisKey = this.getKey(key);\r\n \r\n // INCR creates key with value 1 if it doesn't exist\r\n const count = await this.client.incr(redisKey);\r\n\r\n // Set expiry only on first increment using EXPIRE, which sets the TTL\r\n // without overwriting the value (unlike SET ... EX which would reset the\r\n // counter if two requests increment concurrently before expiry is set).\r\n if (count === 1) {\r\n await this.client.expire(redisKey, this.windowSec);\r\n }\r\n\r\n return count;\r\n }\r\n\r\n async decrement(key: string): Promise<void> {\r\n const redisKey = this.getKey(key);\r\n await this.client.decr(redisKey);\r\n }\r\n\r\n async reset(key: string): Promise<void> {\r\n const redisKey = this.getKey(key);\r\n await this.client.del(redisKey);\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Don't close the client - it may be shared\r\n // The caller should manage the client lifecycle\r\n }\r\n}\r\n\r\n/**\r\n * Create a Redis store with the given options.\r\n * Convenience function for functional programming style.\r\n * \r\n * @example\r\n * const store = createRedisStore({ client: redisClient });\r\n */\r\nexport function createRedisStore(options: RedisStoreOptions): RedisStore {\r\n return new RedisStore(options);\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts","../src/middleware/headers.ts","../src/middleware/rate-limit.ts","../src/middleware/error-handler.ts","../src/core/errors.ts","../src/sanitizers/utils.ts","../src/sanitizers/xss.ts","../src/sanitizers/sql.ts","../src/sanitizers/path.ts","../src/sanitizers/command.ts","../src/sanitizers/sanitize.ts","../src/sanitizers/nosql.ts","../src/sanitizers/prototype.ts","../src/sanitizers/ssti.ts","../src/sanitizers/xxe.ts","../src/sanitizers/jsonp.ts","../src/sanitizers/headers.ts","../src/sanitizers/pii.ts","../src/validation/schema.ts","../src/validation/file.ts","../src/validation/url.ts","../src/validation/redirect.ts","../src/validation/email.ts","../src/logging/redactor.ts","../src/middleware/main.ts","../src/utils/duration.ts","../src/middleware/rate-limit-sliding.ts","../src/middleware/rate-limit-token.ts","../src/middleware/cors.ts","../src/middleware/cookies.ts","../src/middleware/bot-detection.ts","../src/middleware/csrf.ts","../src/utils/ip.ts","../src/utils/fingerprint.ts","../src/stores/memory.ts","../src/stores/redis.ts"],"names":["host","dns","randomBytes","xff","getHeader","createHash"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @arcis/node/core/constants\n * Named constants for Arcis - no magic numbers\n */\n\n// =============================================================================\n// INPUT LIMITS\n// =============================================================================\nexport const INPUT = {\n /** Default maximum input size (1MB) */\n DEFAULT_MAX_SIZE: 1_000_000,\n /** Maximum recursion depth for nested objects */\n MAX_RECURSION_DEPTH: 10,\n} as const;\n\n// =============================================================================\n// RATE LIMITING\n// =============================================================================\nexport const RATE_LIMIT = {\n /** Default window size (1 minute) */\n DEFAULT_WINDOW_MS: 60_000,\n /** Default max requests per window */\n DEFAULT_MAX_REQUESTS: 100,\n /** Default HTTP status code for rate limited responses */\n DEFAULT_STATUS_CODE: 429,\n /** Default error message */\n DEFAULT_MESSAGE: 'Too many requests, please try again later.',\n /** Minimum window size (1 second) */\n MIN_WINDOW_MS: 1_000,\n /** Maximum window size (24 hours) */\n MAX_WINDOW_MS: 86_400_000,\n} as const;\n\n// =============================================================================\n// SECURITY HEADERS\n// =============================================================================\nexport const HEADERS = {\n /** Default Content Security Policy */\n DEFAULT_CSP: [\n \"default-src 'self'\",\n \"script-src 'self'\",\n \"style-src 'self' 'unsafe-inline'\",\n \"img-src 'self' data: https:\",\n \"font-src 'self'\",\n \"object-src 'none'\",\n \"frame-ancestors 'none'\",\n ].join('; '),\n /** Default HSTS max age (1 year in seconds) */\n HSTS_MAX_AGE: 31_536_000,\n /** Default X-Frame-Options value */\n FRAME_OPTIONS: 'DENY' as const,\n /** Default X-Content-Type-Options value */\n CONTENT_TYPE_OPTIONS: 'nosniff',\n /** Default Referrer-Policy value */\n REFERRER_POLICY: 'strict-origin-when-cross-origin',\n /** Default Permissions-Policy value */\n PERMISSIONS_POLICY: 'geolocation=(), microphone=(), camera=()',\n /** Default Cache-Control value for security */\n CACHE_CONTROL: 'no-store, no-cache, must-revalidate, proxy-revalidate',\n} as const;\n\n// =============================================================================\n// XSS PATTERNS (ReDoS-safe)\n// =============================================================================\n\n/**\n * Detection patterns — used to flag whether a string contains XSS payloads.\n * Must stay in sync with XSS_REMOVE_PATTERNS below.\n */\nexport const XSS_PATTERNS = [\n /** Script tags (ReDoS-safe version) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** javascript: protocol (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /** vbscript: protocol */\n /vbscript\\s*:/gi,\n /** Event handlers (onclick, onerror, etc.) — any separator before attribute */\n /(?:[\\s/])on\\w+\\s*=/gi,\n /** iframe tags */\n /<iframe/gi,\n /** object tags */\n /<object/gi,\n /** embed tags */\n /<embed/gi,\n /** data: URIs (only dangerous ones, avoid false positives) */\n /(?:^|[\\s\"'=])data:/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** SVG with onload */\n /<svg[^>]*onload/gi,\n] as const;\n\n/**\n * Removal patterns — used by sanitizeXss() to strip dangerous content.\n * More targeted than XSS_PATTERNS: each pattern captures the full dangerous\n * substring (tag, attribute + value, protocol) so it can be replaced safely.\n * Must stay in sync with XSS_PATTERNS above.\n */\nexport const XSS_REMOVE_PATTERNS = [\n /** Full script blocks (content + tags) */\n /<script[^>]*>[\\s\\S]*?<\\/script>/gi,\n /** Standalone/unclosed script tags */\n /<script[^>]*>/gi,\n /** iframe — full block and partial/unclosed */\n /<iframe[^>]*>[\\s\\S]*?<\\/iframe>/gi,\n /<iframe[^>]*/gi,\n /** object — full block and partial/unclosed */\n /<object[^>]*>[\\s\\S]*?<\\/object>/gi,\n /<object[^>]*/gi,\n /** embed tags */\n /<embed[^>]*/gi,\n /** SVG with inline event handlers */\n /<svg[^>]*onload[^>]*>/gi,\n /** URL-encoded script tags */\n /%3Cscript/gi,\n /** Event handlers with quoted values: onclick=\"...\", onerror='...' */\n /(?:[\\s/])on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi,\n /** Event handlers with unquoted values: onload=value */\n /(?:[\\s/])on\\w+\\s*=\\s*[^\\s>]*/gi,\n /** javascript: and vbscript: protocols (allow optional spaces before colon) */\n /javascript\\s*:/gi,\n /vbscript\\s*:/gi,\n /** data: URIs with HTML/script content */\n /data\\s*:\\s*text\\/html[^>\\s]*/gi,\n] as const;\n\n// =============================================================================\n// SQL INJECTION PATTERNS\n// =============================================================================\nexport const SQL_PATTERNS = [\n /** SQL keywords */\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE|EXEC|EXECUTE)\\b)/gi,\n /** SQL comments: ANSI (--), C-style (slash-star ... star-slash), MySQL (#) */\n /(--|\\/\\*|\\*\\/|#)/g,\n /** SQL statement separators */\n /(;|\\|\\||&&)/g,\n /** Boolean injection: OR 1=1 */\n /\\bOR\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: OR 'a'='a' or OR \"a\"=\"a\" (including mixed quotes) */\n /\\bOR\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bOR\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Boolean injection: AND 1=1 */\n /\\bAND\\s+\\d+\\s*=\\s*\\d+/gi,\n /** Boolean injection: AND 'a'='a' or AND \"a\"=\"a\" (including mixed quotes) */\n /\\bAND\\s+(['\"])[^'\"]*\\1\\s*=\\s*(['\"])[^'\"]*\\2/gi,\n /\\bAND\\s+('[^']*'|\"[^\"]*\")\\s*=\\s*('[^']*'|\"[^\"]*\")/gi,\n /** Time-based blind: SLEEP() */\n /\\bSLEEP\\s*\\(\\s*\\d+\\s*\\)/gi,\n /** Time-based blind: BENCHMARK() */\n /\\bBENCHMARK\\s*\\(/gi,\n /** Time-based blind: PostgreSQL pg_sleep() */\n /\\bpg_sleep\\s*\\(/gi,\n /** Time-based blind: MSSQL WAITFOR DELAY */\n /\\bWAITFOR\\s+DELAY\\b/gi,\n] as const;\n\n// =============================================================================\n// PATH TRAVERSAL PATTERNS\n// =============================================================================\nexport const PATH_PATTERNS = [\n /** Unix path traversal */\n /\\.\\.\\//g,\n /** Windows path traversal */\n /\\.\\.\\\\/g,\n /** URL-encoded traversal (%2e%2e) */\n /%2e%2e/gi,\n /** Double URL-encoded traversal (%252e) */\n /%252e/gi,\n /** Mixed encoding: ..%2F */\n /\\.\\.%2F/gi,\n /** Mixed encoding: %2e./ and .%2e/ */\n /%2e\\.[\\\\/]/gi,\n /\\.%2e[\\\\/]/gi,\n /** Fully URL-encoded: %2e%2e%2f */\n /%2e%2e%2f/gi,\n /** Double URL-encoded forward slash: %252f */\n /%252f/gi,\n /** Dotdotslash bypass: ....// or ....\\\\ */\n /\\.{2,}[/\\\\]{2,}/g,\n /** Null byte injection in paths */\n /\\0/g,\n] as const;\n\n// =============================================================================\n// COMMAND INJECTION PATTERNS\n// =============================================================================\nexport const COMMAND_PATTERNS = [\n /**\n * Shell metacharacters that enable command chaining/substitution.\n * Bare ( and ) are excluded — they appear in common legitimate values\n * (function calls in code fields, math expressions, etc.).\n * Command substitution is caught by the $( combined pattern below.\n * NOTE: ';', '&', '|' may appear in legitimate URL query strings\n * and Markdown; consider disabling command checking (command: false)\n * for fields that intentionally allow those characters.\n */\n /[;&|`]/g,\n /** Command substitution: $( ... ) — matched as a pair to reduce false positives */\n /\\$\\(/g,\n /** URL-encoded newline/carriage-return injection (%0a, %0d) */\n /%0[ad]/gi,\n] as const;\n\n// =============================================================================\n// DANGEROUS KEYS\n// =============================================================================\n\n/**\n * Prototype pollution keys to block.\n * Stored lowercase — always compare with key.toLowerCase().\n *\n * Includes:\n * - __proto__: direct prototype assignment\n * - constructor: access to constructor.prototype chain\n * - prototype: direct prototype property\n * - __defineGetter__/__defineSetter__: legacy property definition (can override getters/setters)\n * - __lookupGetter__/__lookupSetter__: legacy property introspection\n */\nexport const DANGEROUS_PROTO_KEYS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n '__definegetter__',\n '__definesetter__',\n '__lookupgetter__',\n '__lookupsetter__',\n]);\n\n/** MongoDB operators to block */\nexport const NOSQL_DANGEROUS_KEYS = new Set([\n // Comparison\n '$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin',\n // Logical\n '$and', '$or', '$not', '$nor',\n // Element / evaluation\n '$exists', '$type', '$regex', '$where', '$expr', '$mod', '$text', '$jsonSchema',\n // Array\n '$elemMatch', '$all', '$size',\n // JavaScript execution (critical)\n '$function', '$accumulator',\n // Aggregation pipeline operators (injectable via $lookup etc.)\n '$lookup', '$match', '$project', '$group', '$sort', '$limit', '$skip',\n '$unwind', '$addFields', '$replaceRoot',\n]);\n\n// =============================================================================\n// REDACTION\n// =============================================================================\nexport const REDACTION = {\n /** Replacement text for redacted values */\n REPLACEMENT: '[REDACTED]',\n /** Truncation indicator */\n TRUNCATED: '[TRUNCATED]',\n /** Max depth indicator */\n MAX_DEPTH: '[MAX_DEPTH]',\n /** Default max message length */\n DEFAULT_MAX_LENGTH: 10_000,\n /** Default sensitive keys to redact */\n SENSITIVE_KEYS: new Set([\n 'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',\n 'api_key', 'apiKey', 'auth', 'authorization', 'credit_card',\n 'creditcard', 'cc', 'ssn', 'social_security', 'private_key',\n 'privateKey', 'access_token', 'accessToken', 'refresh_token',\n 'refreshToken', 'bearer', 'jwt', 'session', 'cookie',\n 'credentials', 'x-api-key', 'x-auth-token',\n ]),\n} as const;\n\n// =============================================================================\n// VALIDATION PATTERNS\n// =============================================================================\nexport const VALIDATION = {\n /**\n * Email regex pattern.\n * Rejects consecutive dots in local part (e.g. test..foo@example.com),\n * leading/trailing dots, and other common invalid forms.\n */\n EMAIL: /^[^\\s@.][^\\s@]*(?:\\.[^\\s@.][^\\s@]*)*@[^\\s@]+\\.[^\\s@]+$/,\n /**\n * URL regex pattern.\n * Only allows http:// and https:// — explicitly rejects javascript:,\n * data:, vbscript:, and other dangerous URI schemes.\n */\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/,\n /** UUID regex pattern (v4) */\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n} as const;\n\n// =============================================================================\n// ERROR MESSAGES\n// =============================================================================\nexport const ERRORS = {\n /** Generic error message (production) */\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\n /** Input too large error */\n INPUT_TOO_LARGE: (maxSize: number) => `Input exceeds maximum size of ${maxSize} bytes`,\n /** Validation error messages */\n VALIDATION: {\n REQUIRED: (field: string) => `${field} is required`,\n INVALID_TYPE: (field: string, type: string) => `${field} must be a ${type}`,\n MIN_LENGTH: (field: string, min: number) => `${field} must be at least ${min} characters`,\n MAX_LENGTH: (field: string, max: number) => `${field} must be at most ${max} characters`,\n MIN_VALUE: (field: string, min: number) => `${field} must be at least ${min}`,\n MAX_VALUE: (field: string, max: number) => `${field} must be at most ${max}`,\n INVALID_FORMAT: (field: string) => `${field} format is invalid`,\n INVALID_EMAIL: (field: string) => `${field} must be a valid email`,\n INVALID_URL: (field: string) => `${field} must be a valid URL`,\n INVALID_UUID: (field: string) => `${field} must be a valid UUID`,\n INVALID_ENUM: (field: string, values: unknown[]) => `${field} must be one of: ${values.join(', ')}`,\n MIN_ITEMS: (field: string, min: number) => `${field} must have at least ${min} items`,\n MAX_ITEMS: (field: string, max: number) => `${field} must have at most ${max} items`,\n },\n} as const;\n\n// =============================================================================\n// BLOCKED TEXT (for sanitizer replacements)\n// =============================================================================\nexport const BLOCKED = '[BLOCKED]' as const;\n","/**\n * @module @arcis/node/middleware/headers\n * Security headers middleware\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { HEADERS } from '../core/constants';\nimport type { HeaderOptions, HstsOptions } from '../core/types';\n\n/**\n * Create Express middleware for security headers.\n * Sets CSP, HSTS, X-Frame-Options, and other security headers.\n * \n * @param options - Header configuration\n * @returns Express middleware\n * \n * @example\n * app.use(createHeaders());\n * \n * @example\n * app.use(createHeaders({\n * frameOptions: 'SAMEORIGIN',\n * contentSecurityPolicy: \"default-src 'self'\"\n * }));\n */\nexport function createHeaders(options: HeaderOptions = {}): RequestHandler {\n const {\n contentSecurityPolicy = true,\n xssFilter = true,\n noSniff = true,\n frameOptions = HEADERS.FRAME_OPTIONS,\n hsts = true,\n referrerPolicy = HEADERS.REFERRER_POLICY,\n permissionsPolicy = HEADERS.PERMISSIONS_POLICY,\n cacheControl = true,\n } = options;\n\n return (req: Request, res: Response, next: NextFunction) => {\n // Content Security Policy\n if (contentSecurityPolicy) {\n const csp = typeof contentSecurityPolicy === 'string' \n ? contentSecurityPolicy \n : HEADERS.DEFAULT_CSP;\n res.setHeader('Content-Security-Policy', csp);\n }\n\n // X-XSS-Protection (legacy but still useful for older browsers)\n if (xssFilter) {\n res.setHeader('X-XSS-Protection', '1; mode=block');\n }\n\n // Prevent MIME type sniffing\n if (noSniff) {\n res.setHeader('X-Content-Type-Options', HEADERS.CONTENT_TYPE_OPTIONS);\n }\n\n // Clickjacking protection\n if (frameOptions) {\n res.setHeader('X-Frame-Options', frameOptions);\n }\n\n // HTTPS enforcement (HSTS)\n // Only send HSTS over HTTPS — sending it over HTTP can brick HTTP-only\n // development servers and confuses browsers that cache the directive.\n // X-Forwarded-Proto is client-supplied so we validate the extracted value\n // is exactly 'https' or 'http' before trusting it.\n const forwardedProto = (req.headers['x-forwarded-proto'] as string | undefined)\n ?.split(',')[0]\n .trim()\n .toLowerCase();\n const trustedForwardedProto = forwardedProto === 'https' || forwardedProto === 'http'\n ? forwardedProto\n : undefined;\n const isHttps = req.secure || trustedForwardedProto === 'https';\n\n if (hsts && isHttps) {\n const hstsOpts: HstsOptions = typeof hsts === 'object' ? hsts : {};\n const maxAge = hstsOpts.maxAge ?? HEADERS.HSTS_MAX_AGE;\n const includeSubDomains = hstsOpts.includeSubDomains !== false;\n const preload = hstsOpts.preload === true;\n\n let hstsValue = `max-age=${maxAge}`;\n if (includeSubDomains) hstsValue += '; includeSubDomains';\n if (preload) hstsValue += '; preload';\n\n res.setHeader('Strict-Transport-Security', hstsValue);\n }\n\n // Referrer Policy\n if (referrerPolicy) {\n res.setHeader('Referrer-Policy', referrerPolicy);\n }\n\n // Permissions Policy\n if (permissionsPolicy) {\n res.setHeader('Permissions-Policy', permissionsPolicy);\n }\n\n // Additional security headers\n res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');\n\n // Cache-Control headers\n if (cacheControl) {\n const cacheControlValue = typeof cacheControl === 'string'\n ? cacheControl\n : HEADERS.CACHE_CONTROL;\n res.setHeader('Cache-Control', cacheControlValue);\n res.setHeader('Pragma', 'no-cache');\n res.setHeader('Expires', '0');\n }\n\n // Remove fingerprinting headers\n res.removeHeader('X-Powered-By');\n\n next();\n };\n}\n\n/**\n * Alias for createHeaders\n * @see createHeaders\n */\nexport const securityHeaders = createHeaders;\n","/**\n * @module @arcis/node/middleware/rate-limit\n * Rate limiting middleware\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { RATE_LIMIT } from '../core/constants';\nimport type { RateLimitOptions, RateLimiterMiddleware, RateLimitEntry } from '../core/types';\n\n/** In-memory rate limit store */\ninterface InMemoryRateLimitStore {\n [key: string]: RateLimitEntry;\n}\n\n/**\n * Create Express middleware for rate limiting.\n * \n * @param options - Rate limit configuration\n * @returns Express middleware with cleanup method\n * \n * @example\n * app.use(createRateLimiter({ max: 100, windowMs: 60000 }));\n * \n * @example\n * // Skip rate limiting for certain routes\n * app.use(createRateLimiter({\n * max: 50,\n * skip: (req) => req.path === '/health'\n * }));\n * \n * @example\n * // Cleanup on shutdown\n * const limiter = createRateLimiter();\n * app.use(limiter);\n * process.on('SIGTERM', () => limiter.close());\n */\nexport function createRateLimiter(options: RateLimitOptions = {}): RateLimiterMiddleware {\n const {\n max = RATE_LIMIT.DEFAULT_MAX_REQUESTS,\n windowMs = RATE_LIMIT.DEFAULT_WINDOW_MS,\n message = RATE_LIMIT.DEFAULT_MESSAGE,\n statusCode = RATE_LIMIT.DEFAULT_STATUS_CODE,\n keyGenerator = (req) => {\n const ip = req.ip ?? req.socket?.remoteAddress;\n if (!ip) {\n console.warn(\n '[arcis] Rate limiter: cannot resolve client IP. All unresolvable clients share ' +\n 'one counter. Set Express trust proxy if behind a reverse proxy.'\n );\n return 'unknown';\n }\n return ip;\n },\n skip,\n store: externalStore,\n } = options;\n\n // Object.create(null) avoids prototype pollution if keyGenerator ever\n // returns '__proto__', 'constructor', or 'prototype'.\n const inMemoryStore = Object.create(null) as InMemoryRateLimitStore;\n\n // Cleanup interval for in-memory store (only create if not using external store)\n let cleanupInterval: ReturnType<typeof setInterval> | null = null;\n \n if (!externalStore) {\n cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const key of Object.keys(inMemoryStore)) {\n if (inMemoryStore[key].resetTime < now) {\n delete inMemoryStore[key];\n }\n }\n }, windowMs);\n\n // Prevent interval from keeping the process alive (Node.js only)\n if (typeof cleanupInterval.unref === 'function') {\n cleanupInterval.unref();\n }\n }\n\n const handler: RequestHandler = async (req: Request, res: Response, next: NextFunction) => {\n try {\n if (skip?.(req)) {\n return next();\n }\n\n const key = keyGenerator(req);\n const now = Date.now();\n\n let count: number;\n let resetTime: number;\n\n if (externalStore) {\n // Use external store (e.g., Redis)\n const entry = await externalStore.get(key);\n if (!entry || entry.resetTime < now) {\n await externalStore.set(key, { count: 1, resetTime: now + windowMs });\n count = 1;\n resetTime = now + windowMs;\n } else {\n count = await externalStore.increment(key);\n resetTime = entry.resetTime;\n }\n } else {\n // Use in-memory store\n if (!inMemoryStore[key] || inMemoryStore[key].resetTime < now) {\n inMemoryStore[key] = { count: 1, resetTime: now + windowMs };\n } else {\n inMemoryStore[key].count++;\n }\n count = inMemoryStore[key].count;\n resetTime = inMemoryStore[key].resetTime;\n }\n\n const remaining = Math.max(0, max - count);\n const resetSeconds = Math.ceil((resetTime - now) / 1000);\n\n // Set rate limit headers\n res.setHeader('X-RateLimit-Limit', max.toString());\n res.setHeader('X-RateLimit-Remaining', remaining.toString());\n res.setHeader('X-RateLimit-Reset', resetSeconds.toString());\n\n if (count > max) {\n res.setHeader('Retry-After', resetSeconds.toString());\n res.status(statusCode).json({\n error: message,\n retryAfter: resetSeconds,\n });\n return;\n }\n\n next();\n } catch (error) {\n // Log error but fail open (allow request through) to prevent DoS\n console.error('[arcis] Rate limiter error:', error);\n next();\n }\n };\n\n // Attach close method for cleanup\n const middleware = handler as RateLimiterMiddleware;\n middleware.close = () => {\n if (cleanupInterval) {\n clearInterval(cleanupInterval);\n cleanupInterval = null;\n }\n };\n\n return middleware;\n}\n\n/**\n * Alias for createRateLimiter\n * @see createRateLimiter\n */\nexport const rateLimit = createRateLimiter;\n","/**\n * @module @arcis/node/middleware/error-handler\n * Production-safe error handler middleware\n */\n\nimport type { Request, Response, NextFunction } from 'express';\nimport { ERRORS } from '../core/constants';\nimport type { ErrorHandlerOptions, HttpError } from '../core/types';\n\n/**\n * Patterns that indicate database or infrastructure internals in error messages.\n * When detected, the message is replaced with a generic error to prevent info leakage.\n */\nconst SENSITIVE_ERROR_PATTERNS: RegExp[] = [\n // SQL database errors\n /\\b(SQLITE_ERROR|SQLSTATE|ORA-\\d|PG::|mysql_|pg_query|ECONNREFUSED)/i,\n /\\b(syntax error at or near|relation \".*\" does not exist)/i,\n /\\b(column \".*\" (does not exist|of relation))/i,\n /\\b(duplicate key value violates unique constraint)/i,\n /\\b(table .* doesn't exist|unknown column)/i,\n // MongoDB errors\n /\\b(MongoError|MongoServerError|MongoNetworkError|E11000 duplicate key)/i,\n // Redis errors\n /\\b(WRONGTYPE|CROSSSLOT|CLUSTERDOWN|READONLY|ReplyError)/i,\n // Connection strings and DSNs\n /\\b(mongodb(\\+srv)?:\\/\\/|postgres(ql)?:\\/\\/|mysql:\\/\\/|redis:\\/\\/)/i,\n // Stack traces with file paths\n /\\bat\\s+.*\\.(js|ts|py|go|java):\\d+/i,\n // Internal IP addresses\n /\\b(127\\.0\\.0\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+|172\\.(1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+)\\b/,\n];\n\n/**\n * Check if an error message contains sensitive infrastructure details.\n */\nexport function containsSensitiveInfo(message: string): boolean {\n return SENSITIVE_ERROR_PATTERNS.some(pattern => pattern.test(message));\n}\n\n/**\n * Create Express error handler that hides sensitive details in production.\n *\n * Prevents information leakage by:\n * - Hiding stack traces in production\n * - Hiding error messages unless explicitly exposed\n * - Scrubbing database errors, connection strings, and internal IPs\n *\n * @param options - Error handler configuration (or boolean for isDev)\n * @returns Express error handling middleware\n *\n * @example\n * // Production mode (default) - hides error details\n * app.use(errorHandler());\n *\n * @example\n * // Development mode - shows error details and stack traces\n * app.use(errorHandler({ isDev: true }));\n *\n * @example\n * // With custom logger\n * app.use(errorHandler({\n * isDev: false,\n * logger: arcis.logger()\n * }));\n */\nexport function errorHandler(\n options: ErrorHandlerOptions | boolean = false\n): (err: Error, req: Request, res: Response, next: NextFunction) => void {\n const isDev = typeof options === 'boolean' ? options : options.isDev ?? false;\n const logErrors = typeof options === 'object' ? options.logErrors ?? true : true;\n const logger = typeof options === 'object' ? options.logger : undefined;\n const customHandler = typeof options === 'object' ? options.customHandler : undefined;\n\n return (err: HttpError, req: Request, res: Response, _next: NextFunction) => {\n const statusCode = err.statusCode || err.status || 500;\n\n // Custom handler takes precedence\n if (customHandler) {\n return customHandler(err, req, res);\n }\n\n // Always log full error details server-side\n if (logErrors) {\n const logData = {\n error: err.message,\n stack: err.stack,\n statusCode,\n path: req.path,\n method: req.method,\n };\n\n if (logger) {\n logger.error('Request error', logData);\n } else {\n console.error('[arcis] Request error:', logData);\n }\n }\n\n // Build response\n // Only expose err.message when err.expose === true (caller opted in) or in dev mode.\n // This prevents internal details leaking through arbitrary 4xx errors that happen\n // to contain sensitive info (e.g. \"DB query failed for user admin@corp.com\").\n const exposeMessage = isDev || err.expose === true;\n\n let clientMessage: string;\n if (!exposeMessage) {\n clientMessage = ERRORS.INTERNAL_SERVER_ERROR;\n } else if (containsSensitiveInfo(err.message)) {\n // Even when expose is true, scrub DB errors and infra details\n clientMessage = isDev ? err.message : ERRORS.INTERNAL_SERVER_ERROR;\n } else {\n clientMessage = err.message;\n }\n\n const response: Record<string, unknown> = {\n error: clientMessage,\n };\n\n // Only show details in development\n if (isDev) {\n response.stack = err.stack;\n response.details = err.message;\n }\n\n res.status(statusCode).json(response);\n };\n}\n\n/**\n * Alias for errorHandler\n * @see errorHandler\n */\nexport const createErrorHandler = errorHandler;\n","/**\n * @module @arcis/node/core/errors\n * Custom error classes for Arcis\n */\n\n/**\n * Base class for all Arcis errors\n */\nexport class ArcisError extends Error {\n public readonly statusCode: number;\n public readonly code: string;\n /** Whether the error message is safe to expose to API clients. */\n public readonly expose: boolean;\n\n constructor(message: string, statusCode = 500, code = 'ARCIS_ERROR') {\n super(message);\n this.name = 'ArcisError';\n this.statusCode = statusCode;\n this.code = code;\n // Client errors (4xx) have controlled messages — safe to expose.\n // Server errors (5xx) may contain internal details — hide by default.\n this.expose = statusCode < 500;\n\n // Maintains proper stack trace for where error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when input validation fails\n */\nexport class ValidationError extends ArcisError {\n public readonly errors: string[];\n\n constructor(errors: string[]) {\n super('Validation failed', 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n this.errors = errors;\n }\n}\n\n/** Alias for ValidationError (backwards compatibility) */\nexport { ValidationError as ArcisValidationError };\n\n/**\n * Error thrown when rate limit is exceeded\n */\nexport class RateLimitError extends ArcisError {\n public readonly retryAfter: number;\n\n constructor(message: string, retryAfter: number) {\n super(message, 429, 'RATE_LIMIT_EXCEEDED');\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when input is too large\n */\nexport class InputTooLargeError extends ArcisError {\n public readonly maxSize: number;\n public readonly actualSize: number;\n\n constructor(maxSize: number, actualSize: number) {\n super(`Input exceeds maximum size of ${maxSize} bytes`, 413, 'INPUT_TOO_LARGE');\n this.name = 'InputTooLargeError';\n this.maxSize = maxSize;\n this.actualSize = actualSize;\n }\n}\n\n/**\n * Error thrown when security threat is detected\n */\nexport class SecurityThreatError extends ArcisError {\n public readonly threatType: string;\n public readonly pattern: string;\n\n constructor(threatType: string, pattern: string) {\n super('Request blocked for security reasons', 400, 'SECURITY_THREAT');\n this.name = 'SecurityThreatError';\n this.threatType = threatType;\n this.pattern = pattern;\n }\n}\n\n/**\n * Error thrown when sanitization fails\n */\nexport class SanitizationError extends ArcisError {\n constructor(message: string) {\n super(message, 400, 'SANITIZATION_ERROR');\n this.name = 'SanitizationError';\n }\n}\n","/**\n * @module @arcis/node/sanitizers/utils\n * Shared utilities for sanitizers\n */\n\n/**\n * Encodes HTML entities to prevent interpretation as markup.\n * \n * @param str - The string to encode\n * @returns The encoded string\n */\nexport function encodeHtmlEntities(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Checks if a value is a plain object (not null, array, Date, etc.)\n * \n * @param value - Value to check\n * @returns True if plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n // Check the actual prototype chain rather than toString, which can be spoofed\n // via Symbol.toStringTag. Accepts both Object.prototype (plain {}) and null\n // prototype objects (Object.create(null)).\n const proto = Object.getPrototypeOf(value as object);\n return proto === Object.prototype || proto === null;\n}\n","/**\n * @module @arcis/node/sanitizers/xss\n * XSS (Cross-Site Scripting) prevention\n */\n\nimport { XSS_PATTERNS, XSS_REMOVE_PATTERNS } from '../core/constants';\nimport { encodeHtmlEntities } from './utils';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent XSS attacks.\n * \n * Strategy:\n * 1. Remove dangerous patterns (script tags, event handlers, etc.)\n * 2. HTML-encode the remaining content\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeXss(\"<script>alert('xss')</script>\")\n * // Returns: \"<script>alert('xss')</script>\"\n * \n * @example\n * sanitizeXss(\"<img onerror='alert(1)'>\")\n * // Returns: \"<img>\" (event handler removed)\n */\nexport function sanitizeXss(input: string, collectThreats?: false, htmlEncode?: boolean): string;\nexport function sanitizeXss(input: string, collectThreats: true, htmlEncode?: boolean): SanitizeResult;\nexport function sanitizeXss(input: string, collectThreats = false, htmlEncode = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats \n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n // Remove dangerous patterns FIRST — XSS_REMOVE_PATTERNS is the single\n // source of truth (defined in constants.ts alongside XSS_PATTERNS).\n for (const pattern of XSS_REMOVE_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(value)) {\n pattern.lastIndex = 0;\n \n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'xss',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n \n value = value.replace(pattern, '');\n wasSanitized = true;\n }\n }\n\n // HTML-encode only when explicitly requested (SSR/template context).\n // Do NOT encode by default — this is a REST API middleware; encoding\n // here corrupts JSON data with HTML entities (<, &, etc.) that\n // consumers would receive verbatim.\n if (htmlEncode) {\n const encoded = encodeHtmlEntities(value);\n if (encoded !== value) {\n wasSanitized = true;\n }\n value = encoded;\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n \n return value;\n}\n\n/**\n * Checks if a string contains potential XSS patterns.\n * Does not sanitize — use sanitizeXss() for that.\n * \n * @param input - The string to check\n * @returns True if XSS patterns detected\n */\nexport function detectXss(input: string): boolean {\n if (typeof input !== 'string') return false;\n \n // Check for event handlers\n if (/\\s+on\\w+\\s*=/i.test(input)) return true;\n \n // Check for dangerous protocols\n if (/javascript\\s*:/i.test(input)) return true;\n if (/vbscript\\s*:/i.test(input)) return true;\n if (/data\\s*:\\s*text\\/html/i.test(input)) return true;\n \n // Check for patterns from constants\n for (const pattern of XSS_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n \n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/sql\n * SQL injection prevention\n */\n\nimport { SQL_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent SQL injection attacks.\n * Replaces dangerous SQL patterns with [BLOCKED].\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeSql(\"'; DROP TABLE users; --\")\n * // Returns: \"'; TABLE users \"\n */\nexport function sanitizeSql(input: string, collectThreats?: false): string;\nexport function sanitizeSql(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeSql(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats \n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n for (const pattern of SQL_PATTERNS) {\n // Reset regex lastIndex for global patterns\n pattern.lastIndex = 0;\n \n if (pattern.test(value)) {\n pattern.lastIndex = 0; // Reset again for replace\n \n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'sql_injection',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n \n // Replace the matched content with a space to avoid concatenating surrounding\n // tokens into new dangerous strings (e.g. \"SELECTname\" after stripping \"SELECT\").\n value = value.replace(pattern, ' ');\n wasSanitized = true;\n }\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n \n return value;\n}\n\n/**\n * Checks if a string contains potential SQL injection patterns.\n * Does not sanitize — use sanitizeSql() for that.\n * \n * @param input - The string to check\n * @returns True if SQL injection patterns detected\n */\nexport function detectSql(input: string): boolean {\n if (typeof input !== 'string') return false;\n \n for (const pattern of SQL_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n \n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/path\n * Path traversal prevention\n */\n\nimport { PATH_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent path traversal attacks.\n * Removes ../ and ..\\ patterns (including URL-encoded variants).\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizePath(\"../../etc/passwd\")\n * // Returns: \"etc/passwd\"\n */\nexport function sanitizePath(input: string, collectThreats?: false): string;\nexport function sanitizePath(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizePath(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats \n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n for (const pattern of PATH_PATTERNS) {\n // Reset regex lastIndex for global patterns\n pattern.lastIndex = 0;\n \n if (pattern.test(value)) {\n pattern.lastIndex = 0; // Reset again for replace\n \n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'path_traversal',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n \n value = value.replace(pattern, '');\n wasSanitized = true;\n }\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n \n return value;\n}\n\n/**\n * Checks if a string contains path traversal patterns.\n * Does not sanitize — use sanitizePath() for that.\n * \n * @param input - The string to check\n * @returns True if path traversal patterns detected\n */\nexport function detectPathTraversal(input: string): boolean {\n if (typeof input !== 'string') return false;\n \n for (const pattern of PATH_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n \n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/command\n * Command injection prevention\n */\n\nimport { COMMAND_PATTERNS } from '../core/constants';\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Sanitizes a string to prevent command injection attacks.\n * Replaces shell metacharacters and dangerous commands with [BLOCKED].\n * \n * @param input - The string to sanitize\n * @param collectThreats - Whether to collect threat information (default: false for performance)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n * \n * @example\n * sanitizeCommand(\"file.txt; rm -rf /\")\n * // Returns: \"file.txt rm -rf /\"\n */\nexport function sanitizeCommand(input: string, collectThreats?: false): string;\nexport function sanitizeCommand(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeCommand(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats \n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n for (const pattern of COMMAND_PATTERNS) {\n // Reset regex lastIndex for global patterns\n pattern.lastIndex = 0;\n \n if (pattern.test(value)) {\n pattern.lastIndex = 0; // Reset again for replace\n \n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'command_injection',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n \n value = value.replace(pattern, ' ');\n wasSanitized = true;\n }\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n \n return value;\n}\n\n/**\n * Checks if a string contains command injection patterns.\n * Does not sanitize — use sanitizeCommand() for that.\n * \n * @param input - The string to check\n * @returns True if command injection patterns detected\n */\nexport function detectCommandInjection(input: string): boolean {\n if (typeof input !== 'string') return false;\n \n for (const pattern of COMMAND_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n \n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/sanitize\n * Main sanitization functions that combine all sanitizers\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { INPUT, DANGEROUS_PROTO_KEYS, NOSQL_DANGEROUS_KEYS } from '../core/constants';\nimport { InputTooLargeError, SecurityThreatError } from '../core/errors';\nimport type { SanitizeOptions } from '../core/types';\nimport { sanitizeXss } from './xss';\nimport { sanitizeSql, detectSql } from './sql';\nimport { sanitizePath } from './path';\nimport { sanitizeCommand, detectCommandInjection } from './command';\n\n/**\n * Sanitize a string value against multiple attack vectors.\n * \n * Order matters: We do XSS encoding LAST because:\n * 1. Other sanitizers need to see the original patterns (e.g., SQL keywords)\n * 2. HTML encoding is the final safe output transformation\n * 3. Encoded entities like < shouldn't be treated as SQL/command threats\n * \n * @param value - The string to sanitize\n * @param options - Sanitization options\n * @returns The sanitized string\n * \n * @example\n * sanitizeString(\"<script>alert('xss')</script>\")\n * // Returns: \"<script>alert('xss')</script>\"\n * \n * @example\n * sanitizeString(\"../../etc/passwd\")\n * // Returns: \"etc/passwd\"\n */\nexport function sanitizeString(value: string, options: SanitizeOptions = {}): string {\n if (typeof value !== 'string') return value;\n\n // Input size limit to prevent DoS\n const maxSize = options.maxSize ?? INPUT.DEFAULT_MAX_SIZE;\n if (value.length > maxSize) {\n throw new InputTooLargeError(maxSize, value.length);\n }\n\n const reject = options.mode !== 'sanitize'; // default: 'reject'\n let result = value;\n\n // 1. SQL injection\n if (options.sql !== false) {\n if (reject) {\n if (detectSql(result)) {\n throw new SecurityThreatError('sql_injection', 'SQL pattern detected in input');\n }\n } else {\n result = sanitizeSql(result);\n }\n }\n\n // 2. Path traversal prevention\n if (options.path !== false) {\n result = sanitizePath(result);\n }\n\n // 3. Command injection\n if (options.command !== false) {\n if (reject) {\n if (detectCommandInjection(result)) {\n throw new SecurityThreatError('command_injection', 'Shell metacharacter detected in input');\n }\n } else {\n result = sanitizeCommand(result);\n }\n }\n\n // 4. XSS stripping — always runs to remove dangerous patterns.\n // HTML encoding is opt-in via options.htmlEncode (for SSR contexts only).\n if (options.xss !== false) {\n result = sanitizeXss(result, false, options.htmlEncode ?? false);\n }\n\n return result;\n}\n\n/**\n * Sanitize an object recursively, including nested objects and arrays.\n * Also removes prototype pollution and NoSQL injection keys.\n * \n * @param obj - The object to sanitize\n * @param options - Sanitization options\n * @returns The sanitized object\n */\nexport function sanitizeObject(obj: unknown, options: SanitizeOptions = {}): unknown {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj === 'string') return sanitizeString(obj, options);\n if (typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(item => sanitizeObject(item, options));\n\n const result = sanitizeObjectDepth(obj as Record<string, unknown>, options, 0);\n return options.freeze ? Object.freeze(result) : result;\n}\n\n/**\n * Internal recursive sanitization with depth tracking.\n */\nfunction sanitizeObjectDepth(\n obj: Record<string, unknown>,\n options: SanitizeOptions,\n depth: number\n): Record<string, unknown> {\n if (depth >= INPUT.MAX_RECURSION_DEPTH) return obj;\n\n const result: Record<string, unknown> = {};\n\n for (const key of Object.keys(obj)) {\n // Prototype pollution protection - always block dangerous keys (case-insensitive)\n if (options.proto !== false && DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\n continue;\n }\n\n // NoSQL injection - skip dangerous MongoDB operators in keys\n if (options.nosql !== false && NOSQL_DANGEROUS_KEYS.has(key)) {\n continue;\n }\n\n // Sanitize the key against all active threat vectors (not just XSS).\n // Keys can carry injection payloads that bubble into query builders or ORMs.\n const sanitizedKey = sanitizeString(key, options);\n\n // Recursively sanitize value\n const value = obj[key];\n if (value === null || value === undefined) {\n result[sanitizedKey] = value;\n } else if (typeof value === 'string') {\n result[sanitizedKey] = sanitizeString(value, options);\n } else if (Array.isArray(value)) {\n result[sanitizedKey] = value.map(item => sanitizeObject(item, options));\n } else if (typeof value === 'object') {\n result[sanitizedKey] = sanitizeObjectDepth(value as Record<string, unknown>, options, depth + 1);\n } else {\n result[sanitizedKey] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Create Express middleware for request sanitization.\n * Sanitizes req.body, req.query, and req.params.\n * \n * @param options - Sanitization options\n * @returns Express middleware\n * \n * @example\n * app.use(createSanitizer());\n * \n * @example\n * app.use(createSanitizer({ xss: true, sql: true, nosql: true }));\n */\nexport function createSanitizer(options: SanitizeOptions = {}): RequestHandler {\n return (req: Request, _res: Response, next: NextFunction) => {\n try {\n if (req.body && typeof req.body === 'object') {\n req.body = sanitizeObject(req.body, options);\n }\n if (req.query && typeof req.query === 'object') {\n const sanitizedQuery = sanitizeObject(req.query, options);\n // Express 5: req.query is a getter with no setter — override on instance\n Object.defineProperty(req, 'query', { value: sanitizedQuery, writable: true, configurable: true });\n }\n if (req.params && typeof req.params === 'object') {\n const sanitizedParams = sanitizeObject(req.params, options);\n Object.defineProperty(req, 'params', { value: sanitizedParams, writable: true, configurable: true });\n }\n next();\n } catch (err) {\n next(err);\n }\n };\n}\n","/**\n * @module @arcis/node/sanitizers/nosql\n * NoSQL injection prevention (MongoDB operators)\n */\n\nimport { NOSQL_DANGEROUS_KEYS } from '../core/constants';\n\n/**\n * Checks if a key is a dangerous MongoDB operator.\n * \n * @param key - The key to check\n * @returns True if the key is a MongoDB operator\n * \n * @example\n * isDangerousNoSqlKey('$gt') // true\n * isDangerousNoSqlKey('name') // false\n */\nexport function isDangerousNoSqlKey(key: string): boolean {\n return NOSQL_DANGEROUS_KEYS.has(key);\n}\n\n/**\n * Recursively checks if an object contains dangerous MongoDB operators.\n * \n * @param obj - The object to check\n * @param maxDepth - Maximum recursion depth (default: 10)\n * @returns True if dangerous operators found\n */\nexport function detectNoSqlInjection(obj: unknown, maxDepth = 10): boolean {\n if (maxDepth <= 0) return false;\n if (obj === null || typeof obj !== 'object') return false;\n \n if (Array.isArray(obj)) {\n return obj.some(item => detectNoSqlInjection(item, maxDepth - 1));\n }\n \n for (const key of Object.keys(obj as Record<string, unknown>)) {\n if (isDangerousNoSqlKey(key)) {\n return true;\n }\n \n const value = (obj as Record<string, unknown>)[key];\n if (typeof value === 'object' && value !== null) {\n if (detectNoSqlInjection(value, maxDepth - 1)) {\n return true;\n }\n }\n }\n \n return false;\n}\n\n/**\n * Get list of all MongoDB operators considered dangerous.\n * Useful for documentation or custom validation.\n * \n * @returns Array of dangerous operator strings\n */\nexport function getDangerousOperators(): string[] {\n return Array.from(NOSQL_DANGEROUS_KEYS);\n}\n","/**\n * @module @arcis/node/sanitizers/prototype\n * Prototype pollution prevention\n */\n\nimport { DANGEROUS_PROTO_KEYS } from '../core/constants';\n\n/**\n * Checks if a key is dangerous for prototype pollution.\n * Case-insensitive — catches __PROTO__, Constructor, etc.\n *\n * @param key - The key to check\n * @returns True if the key could cause prototype pollution\n *\n * @example\n * isDangerousProtoKey('__proto__') // true\n * isDangerousProtoKey('__PROTO__') // true\n * isDangerousProtoKey('Constructor') // true\n * isDangerousProtoKey('name') // false\n */\nexport function isDangerousProtoKey(key: string): boolean {\n return DANGEROUS_PROTO_KEYS.has(key.toLowerCase());\n}\n\n/**\n * Recursively checks if an object contains prototype pollution keys.\n * \n * @param obj - The object to check\n * @param maxDepth - Maximum recursion depth (default: 10)\n * @returns True if dangerous keys found\n */\nexport function detectPrototypePollution(obj: unknown, maxDepth = 10): boolean {\n if (maxDepth <= 0) return false;\n if (obj === null || typeof obj !== 'object') return false;\n \n if (Array.isArray(obj)) {\n return obj.some(item => detectPrototypePollution(item, maxDepth - 1));\n }\n \n for (const key of Object.keys(obj as Record<string, unknown>)) {\n if (DANGEROUS_PROTO_KEYS.has(key.toLowerCase())) {\n return true;\n }\n \n const value = (obj as Record<string, unknown>)[key];\n if (typeof value === 'object' && value !== null) {\n if (detectPrototypePollution(value, maxDepth - 1)) {\n return true;\n }\n }\n }\n \n return false;\n}\n\n/**\n * Get list of all keys considered dangerous for prototype pollution.\n * Useful for documentation or custom validation.\n * \n * @returns Array of dangerous key strings\n */\nexport function getDangerousProtoKeys(): string[] {\n return Array.from(DANGEROUS_PROTO_KEYS);\n}\n","/**\n * @module @arcis/node/sanitizers/ssti\n * Server-Side Template Injection (SSTI) prevention\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * SSTI detection patterns (ReDoS-safe).\n *\n * Covers Jinja2, Twig, Nunjucks, Freemarker, Thymeleaf, Spring EL,\n * ERB, EJS, Pug/Jade, and Python sandbox-escape dunder chains.\n */\nconst SSTI_DETECT_PATTERNS = [\n /** Jinja2 / Twig / Nunjucks: {{ ... }} */\n /\\{\\{.*?\\}\\}/g,\n /** Freemarker / Thymeleaf / Spring EL: ${ ... } */\n /\\$\\{.*?\\}/g,\n /** ERB / EJS: <%= ... %> or <% ... %> */\n /<%[=\\-]?.*?%>/gs,\n /** Pug / Jade / Slim: #{ ... } */\n /#\\{.*?\\}/g,\n /** Python dunder sandbox escape */\n /__(?:class|mro|subclasses|globals|builtins|import)__/gi,\n /** Jinja2 config leak: {{config.X}} or {{config['X']}} */\n /\\{\\{\\s*config[.\\[]/gi,\n /** Jinja2 built-in objects */\n /\\{\\{\\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\\b/gi,\n] as const;\n\n/** Removal patterns — strip the full template expression */\nconst SSTI_REMOVE_PATTERNS = [\n /\\{\\{.*?\\}\\}/g,\n /\\$\\{.*?\\}/g,\n /<%[=\\-]?.*?%>/gs,\n /#\\{.*?\\}/g,\n /__(?:class|mro|subclasses|globals|builtins|import)__/gi,\n] as const;\n\n/**\n * Sanitizes a string to prevent SSTI attacks.\n * Removes template expression syntax.\n */\nexport function sanitizeSsti(input: string, collectThreats?: false): string;\nexport function sanitizeSsti(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeSsti(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats\n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n for (const pattern of SSTI_REMOVE_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(value)) {\n pattern.lastIndex = 0;\n\n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'ssti',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n\n value = value.replace(pattern, '');\n wasSanitized = true;\n }\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n\n return value;\n}\n\n/**\n * Checks if a string contains SSTI patterns.\n * Does not sanitize — use sanitizeSsti() for that.\n *\n * @param input - The string to check\n * @returns True if SSTI patterns detected\n */\nexport function detectSsti(input: string): boolean {\n if (typeof input !== 'string') return false;\n\n for (const pattern of SSTI_DETECT_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/xxe\n * XML External Entity (XXE) injection prevention\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * XXE detection patterns (ReDoS-safe).\n *\n * Covers DOCTYPE declarations, ENTITY definitions, SYSTEM/PUBLIC references,\n * parameter entities, and CDATA abuse.\n */\nconst XXE_DETECT_PATTERNS = [\n /** DOCTYPE declaration */\n /<!DOCTYPE\\b/gi,\n /** ENTITY declaration */\n /<!ENTITY\\b/gi,\n /** SYSTEM keyword with URI */\n /\\bSYSTEM\\s+[\"']/gi,\n /** PUBLIC keyword with URI */\n /\\bPUBLIC\\s+[\"']/gi,\n /** Parameter entity reference (%entity;) */\n /%\\s*\\w+\\s*;/g,\n /** CDATA section (often used to smuggle payloads) */\n /<!\\[CDATA\\[/gi,\n] as const;\n\n/** Removal patterns — strip the dangerous XML constructs */\nconst XXE_REMOVE_PATTERNS = [\n /** Full DOCTYPE block with optional internal subset: <!DOCTYPE ... [...]> */\n /<!DOCTYPE\\s[^[>]*(?:\\[[^\\]]*\\]\\s*)?>|<!DOCTYPE\\s[^>]*>/gi,\n /** Full ENTITY declaration: <!ENTITY ... > */\n /<!ENTITY[^>]*>/gi,\n /** CDATA sections: <![CDATA[ ... ]]> */\n /<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/gi,\n] as const;\n\n/**\n * Sanitizes a string to prevent XXE attacks.\n * Removes DOCTYPE, ENTITY, and CDATA constructs.\n */\nexport function sanitizeXxe(input: string, collectThreats?: false): string;\nexport function sanitizeXxe(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeXxe(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats\n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let value = input;\n let wasSanitized = false;\n\n for (const pattern of XXE_REMOVE_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(value)) {\n pattern.lastIndex = 0;\n\n if (collectThreats) {\n const matches = value.match(pattern);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'xxe',\n pattern: pattern.source,\n original: match,\n });\n }\n }\n }\n\n value = value.replace(pattern, '');\n wasSanitized = true;\n }\n }\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n\n return value;\n}\n\n/**\n * Checks if a string contains XXE patterns.\n * Does not sanitize — use sanitizeXxe() for that.\n *\n * @param input - The string to check\n * @returns True if XXE patterns detected\n */\nexport function detectXxe(input: string): boolean {\n if (typeof input !== 'string') return false;\n\n for (const pattern of XXE_DETECT_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(input)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/jsonp\n * JSONP callback sanitization to prevent XSS via callback parameters\n */\n\n/**\n * Valid JSONP callback pattern: only alphanumeric, underscore, dot, and bracket notation.\n * This prevents injection of arbitrary JS via callback parameters.\n */\nconst SAFE_CALLBACK_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$.[\\]]*$/;\n\n/**\n * Dangerous patterns that should never appear in a callback name,\n * even if they technically match the safe pattern.\n */\nconst DANGEROUS_CALLBACK_PATTERNS = [\n /\\.\\./, // prototype chain traversal\n /\\[\\s*\\]/, // empty bracket access\n] as const;\n\n/**\n * Validates and sanitizes a JSONP callback parameter.\n *\n * Returns the callback name if safe, or null if the callback is dangerous.\n * Use this to validate `?callback=` query parameters before wrapping responses.\n *\n * @param callback - The callback parameter value\n * @param maxLength - Maximum allowed length (default: 128)\n * @returns The safe callback name, or null if invalid\n *\n * @example\n * ```ts\n * const cb = sanitizeJsonpCallback(req.query.callback);\n * if (cb) {\n * res.set('Content-Type', 'application/javascript');\n * res.send(`${cb}(${JSON.stringify(data)})`);\n * } else {\n * res.status(400).json({ error: 'Invalid callback' });\n * }\n * ```\n */\nexport function sanitizeJsonpCallback(callback: string, maxLength = 128): string | null {\n if (typeof callback !== 'string' || callback.length === 0) {\n return null;\n }\n\n if (callback.length > maxLength) {\n return null;\n }\n\n if (!SAFE_CALLBACK_PATTERN.test(callback)) {\n return null;\n }\n\n for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {\n if (pattern.test(callback)) {\n return null;\n }\n }\n\n return callback;\n}\n\n/**\n * Checks if a JSONP callback parameter contains potentially dangerous content.\n *\n * @param callback - The callback parameter value\n * @returns True if the callback is dangerous / invalid\n */\nexport function detectJsonpInjection(callback: string): boolean {\n if (typeof callback !== 'string' || callback.length === 0) {\n return false;\n }\n\n // If it doesn't match the safe pattern, it's potentially dangerous\n if (!SAFE_CALLBACK_PATTERN.test(callback)) {\n return true;\n }\n\n for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {\n if (pattern.test(callback)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * @module @arcis/node/sanitizers/headers\n * HTTP Header Injection & CRLF Injection prevention\n *\n * Prevents attackers from injecting newline characters (\\r\\n) into HTTP header\n * values, which can lead to response splitting, session fixation, XSS via\n * injected headers, and cache poisoning.\n */\n\nimport type { SanitizeResult, ThreatInfo } from '../core/types';\n\n/**\n * Characters and sequences that enable header injection.\n * - \\r\\n (CRLF) — HTTP header delimiter, enables response splitting\n * - \\r, \\n alone — partial line breaks, some servers normalize to CRLF\n * - \\0 (null byte) — can truncate header values in some implementations\n */\nconst HEADER_INJECTION_PATTERN = /\\r\\n|\\r|\\n|\\0/g;\n\n/**\n * Sanitizes a header value by stripping CRLF sequences, bare CR/LF, and null bytes.\n *\n * @param input - The header value to sanitize\n * @param collectThreats - Whether to collect threat information (default: false)\n * @returns Sanitized string or SanitizeResult if collectThreats is true\n *\n * @example\n * sanitizeHeaderValue(\"safe-value\")\n * // Returns: \"safe-value\"\n *\n * sanitizeHeaderValue(\"value\\r\\nX-Injected: evil\")\n * // Returns: \"valueX-Injected: evil\"\n */\nexport function sanitizeHeaderValue(input: string, collectThreats?: false): string;\nexport function sanitizeHeaderValue(input: string, collectThreats: true): SanitizeResult;\nexport function sanitizeHeaderValue(input: string, collectThreats = false): string | SanitizeResult {\n if (typeof input !== 'string') {\n return collectThreats\n ? { value: String(input), wasSanitized: false, threats: [] }\n : String(input);\n }\n\n const threats: ThreatInfo[] = [];\n let wasSanitized = false;\n\n if (HEADER_INJECTION_PATTERN.test(input)) {\n HEADER_INJECTION_PATTERN.lastIndex = 0;\n wasSanitized = true;\n\n if (collectThreats) {\n const matches = input.match(HEADER_INJECTION_PATTERN);\n if (matches) {\n for (const match of matches) {\n threats.push({\n type: 'header_injection',\n pattern: HEADER_INJECTION_PATTERN.source,\n original: match,\n });\n }\n }\n }\n }\n\n HEADER_INJECTION_PATTERN.lastIndex = 0;\n const value = input.replace(HEADER_INJECTION_PATTERN, '');\n\n if (collectThreats) {\n return { value, wasSanitized, threats };\n }\n\n return value;\n}\n\n/**\n * Sanitizes an object of header key-value pairs.\n * Strips CRLF/null bytes from both keys and values.\n *\n * @param headers - Object with header names as keys and header values as values\n * @returns New object with sanitized header names and values\n *\n * @example\n * sanitizeHeaders({ \"X-Custom\": \"safe\", \"X-Bad\\r\\n\": \"value\\r\\ninjected\" })\n * // Returns: { \"X-Custom\": \"safe\", \"X-Bad\": \"valueinjected\" }\n */\nexport function sanitizeHeaders(headers: Record<string, string>): Record<string, string> {\n if (!headers || typeof headers !== 'object') {\n return {};\n }\n\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n const sanitizedKey = sanitizeHeaderValue(String(key));\n const sanitizedValue = sanitizeHeaderValue(String(value));\n result[sanitizedKey] = sanitizedValue;\n }\n\n return result;\n}\n\n/**\n * Checks if a string contains HTTP header injection patterns (CRLF, null bytes).\n * Does not sanitize — use sanitizeHeaderValue() for that.\n *\n * @param input - The string to check\n * @returns True if header injection patterns detected\n */\nexport function detectHeaderInjection(input: string): boolean {\n if (typeof input !== 'string') return false;\n\n HEADER_INJECTION_PATTERN.lastIndex = 0;\n return HEADER_INJECTION_PATTERN.test(input);\n}\n","/**\n * @module @arcis/node/sanitizers/pii\n * PII (Personally Identifiable Information) detection and redaction\n *\n * Detects: email addresses, phone numbers, credit card numbers, SSNs, IP addresses\n */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport type PiiType = 'email' | 'phone' | 'credit_card' | 'ssn' | 'ip_address';\n\nexport interface PiiMatch {\n type: PiiType;\n value: string;\n start: number;\n end: number;\n}\n\nexport interface PiiScanOptions {\n /** PII types to scan for. Default: all types */\n types?: PiiType[];\n}\n\nexport interface PiiRedactOptions extends PiiScanOptions {\n /** Replacement for redacted values. Default: '[REDACTED]' */\n replacement?: string;\n /** Use type-specific replacements like '[EMAIL]', '[SSN]'. Default: false */\n typeLabels?: boolean;\n}\n\n// ─── Patterns ────────────────────────────────────────────────────────────────\n\n// Email: simplified RFC 5322 — catches real-world emails without ReDoS risk\nconst EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z]{2,})+/g;\n\n// US phone numbers: (xxx) xxx-xxxx, xxx-xxx-xxxx, xxx.xxx.xxxx, xxx xxx xxxx, +1xxxxxxxxxx\nconst PHONE_RE = /(?:\\+?1[-.\\s]?)?\\(?[2-9]\\d{2}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}/g;\n\n// Credit cards: 13-19 digits with optional separators (spaces or dashes)\nconst CREDIT_CARD_RE = /\\b(?:\\d[ -]*?){13,19}\\b/g;\n\n// SSN: XXX-XX-XXXX (with dashes or spaces)\nconst SSN_RE = /\\b\\d{3}[-\\s]\\d{2}[-\\s]\\d{4}\\b/g;\n\n// IPv4 addresses\nconst IPV4_RE = /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g;\n\n// IPv6 addresses (simplified — full addresses and common abbreviations)\nconst IPV6_RE = /\\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\b|\\b(?:[0-9a-fA-F]{1,4}:){1,7}:|::(?:[0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4}\\b/g;\n\nconst PATTERN_MAP: Record<PiiType, RegExp[]> = {\n email: [EMAIL_RE],\n phone: [PHONE_RE],\n credit_card: [CREDIT_CARD_RE],\n ssn: [SSN_RE],\n ip_address: [IPV4_RE, IPV6_RE],\n};\n\nconst ALL_TYPES: PiiType[] = ['email', 'phone', 'credit_card', 'ssn', 'ip_address'];\n\nconst TYPE_LABELS: Record<PiiType, string> = {\n email: '[EMAIL]',\n phone: '[PHONE]',\n credit_card: '[CREDIT_CARD]',\n ssn: '[SSN]',\n ip_address: '[IP_ADDRESS]',\n};\n\n// ─── Luhn Check ──────────────────────────────────────────────────────────────\n\n/**\n * Validate a credit card number using the Luhn algorithm.\n * Strips spaces and dashes before checking.\n */\nfunction luhnCheck(value: string): boolean {\n const digits = value.replace(/[\\s-]/g, '');\n if (!/^\\d{13,19}$/.test(digits)) return false;\n\n let sum = 0;\n let alternate = false;\n for (let i = digits.length - 1; i >= 0; i--) {\n let n = parseInt(digits[i], 10);\n if (alternate) {\n n *= 2;\n if (n > 9) n -= 9;\n }\n sum += n;\n alternate = !alternate;\n }\n return sum % 10 === 0;\n}\n\n// ─── Core Functions ──────────────────────────────────────────────────────────\n\n/**\n * Scan a string for PII and return all matches.\n *\n * @param input - String to scan\n * @param options - Optional scan configuration\n * @returns Array of PII matches with type, value, and position\n *\n * @example\n * scanPii('Call me at 555-123-4567 or email john@example.com')\n * // [\n * // { type: 'phone', value: '555-123-4567', start: 11, end: 23 },\n * // { type: 'email', value: 'john@example.com', start: 33, end: 49 }\n * // ]\n */\nexport function scanPii(input: string, options: PiiScanOptions = {}): PiiMatch[] {\n if (!input || typeof input !== 'string') return [];\n\n const types = options.types ?? ALL_TYPES;\n const matches: PiiMatch[] = [];\n\n for (const type of types) {\n const patterns = PATTERN_MAP[type];\n if (!patterns) continue;\n\n for (const pattern of patterns) {\n const re = new RegExp(pattern.source, pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = re.exec(input)) !== null) {\n const value = match[0];\n\n // Credit card: validate with Luhn algorithm\n if (type === 'credit_card' && !luhnCheck(value)) continue;\n\n // SSN: reject invalid ranges (000, 666, 900-999 for area)\n if (type === 'ssn') {\n const area = parseInt(value.substring(0, 3), 10);\n if (area === 0 || area === 666 || area >= 900) continue;\n }\n\n matches.push({\n type,\n value,\n start: match.index,\n end: match.index + value.length,\n });\n }\n }\n }\n\n // Sort by position\n matches.sort((a, b) => a.start - b.start);\n return matches;\n}\n\n/**\n * Check if a string contains any PII.\n *\n * @param input - String to check\n * @param options - Optional scan configuration\n * @returns true if PII is detected\n */\nexport function detectPii(input: string, options: PiiScanOptions = {}): boolean {\n return scanPii(input, options).length > 0;\n}\n\n/**\n * Redact PII from a string, replacing matches with a placeholder.\n *\n * @param input - String to redact\n * @param options - Redaction options\n * @returns String with PII replaced\n *\n * @example\n * redactPii('Email: john@example.com, SSN: 123-45-6789')\n * // 'Email: [REDACTED], SSN: [REDACTED]'\n *\n * redactPii('Email: john@example.com', { typeLabels: true })\n * // 'Email: [EMAIL]'\n */\nexport function redactPii(input: string, options: PiiRedactOptions = {}): string {\n if (!input || typeof input !== 'string') return input;\n\n const matches = scanPii(input, options);\n if (matches.length === 0) return input;\n\n const replacement = options.replacement ?? '[REDACTED]';\n\n // Replace from end to preserve positions\n let result = input;\n for (let i = matches.length - 1; i >= 0; i--) {\n const m = matches[i];\n const label = options.typeLabels ? TYPE_LABELS[m.type] : replacement;\n result = result.substring(0, m.start) + label + result.substring(m.end);\n }\n\n return result;\n}\n\n/**\n * Scan an object's string values for PII recursively.\n *\n * @param obj - Object to scan\n * @param options - Optional scan configuration\n * @returns Array of PII matches with the field path prepended\n */\nexport function scanObjectPii(\n obj: Record<string, unknown>,\n options: PiiScanOptions = {},\n path = '',\n): (PiiMatch & { field: string })[] {\n const results: (PiiMatch & { field: string })[] = [];\n if (!obj || typeof obj !== 'object') return results;\n\n for (const [key, value] of Object.entries(obj)) {\n const fieldPath = path ? `${path}.${key}` : key;\n\n if (typeof value === 'string') {\n const matches = scanPii(value, options);\n for (const m of matches) {\n results.push({ ...m, field: fieldPath });\n }\n } else if (value && typeof value === 'object' && !Array.isArray(value)) {\n results.push(...scanObjectPii(value as Record<string, unknown>, options, fieldPath));\n } else if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n if (typeof item === 'string') {\n const matches = scanPii(item, options);\n for (const m of matches) {\n results.push({ ...m, field: `${fieldPath}[${i}]` });\n }\n } else if (item && typeof item === 'object') {\n results.push(...scanObjectPii(item as Record<string, unknown>, options, `${fieldPath}[${i}]`));\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Redact PII from all string values in an object recursively.\n *\n * @param obj - Object to redact\n * @param options - Redaction options\n * @returns New object with PII redacted\n */\nexport function redactObjectPii<T extends Record<string, unknown>>(\n obj: T,\n options: PiiRedactOptions = {},\n): T {\n if (!obj || typeof obj !== 'object') return obj;\n\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n result[key] = redactPii(value, options);\n } else if (Array.isArray(value)) {\n result[key] = value.map(item => {\n if (typeof item === 'string') return redactPii(item, options);\n if (item && typeof item === 'object') return redactObjectPii(item as Record<string, unknown>, options);\n return item;\n });\n } else if (value && typeof value === 'object') {\n result[key] = redactObjectPii(value as Record<string, unknown>, options);\n } else {\n result[key] = value;\n }\n }\n\n return result as T;\n}\n","/**\n * @module @arcis/node/validation/schema\n * Request validation middleware\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { VALIDATION, ERRORS } from '../core/constants';\nimport type { ValidationSchema, FieldValidator } from '../core/types';\nimport { sanitizeString } from '../sanitizers';\n\n/**\n * Create Express middleware for request validation.\n * Prevents mass assignment by only allowing fields defined in the schema.\n * \n * @param schema - Validation schema defining expected fields\n * @param source - Request property to validate ('body', 'query', or 'params')\n * @returns Express middleware\n * \n * @example\n * app.post('/users', validate({\n * email: { type: 'email', required: true },\n * name: { type: 'string', min: 2, max: 50 },\n * age: { type: 'number', min: 0, max: 150 },\n * role: { type: 'string', enum: ['user', 'admin'] }\n * }), handler);\n * \n * @example\n * // Validate query params\n * app.get('/search', validate({\n * q: { type: 'string', required: true, min: 1 },\n * page: { type: 'number', min: 1 }\n * }, 'query'), handler);\n */\nexport function validate(\n schema: ValidationSchema,\n source: 'body' | 'query' | 'params' = 'body'\n): RequestHandler {\n return (req: Request, res: Response, next: NextFunction) => {\n const data = req[source] || {};\n const errors: string[] = [];\n const validated: Record<string, unknown> = {};\n\n for (const [field, rules] of Object.entries(schema)) {\n const value = data[field];\n const result = validateField(field, value, rules);\n \n if (result.errors.length > 0) {\n errors.push(...result.errors);\n } else if (result.value !== undefined) {\n validated[field] = result.value;\n }\n }\n\n if (errors.length > 0) {\n res.status(400).json({ errors });\n return;\n }\n\n // Replace with validated data (prevents mass assignment)\n req[source] = validated as typeof req[typeof source];\n next();\n };\n}\n\n/**\n * Validate a single field against its rules.\n */\nfunction validateField(\n field: string,\n value: unknown,\n rules: FieldValidator\n): { value?: unknown; errors: string[] } {\n const errors: string[] = [];\n\n // Required check\n if (rules.required && (value === undefined || value === null || value === '')) {\n errors.push(ERRORS.VALIDATION.REQUIRED(field));\n return { errors };\n }\n\n // Skip optional empty fields\n if (value === undefined || value === null) {\n return { errors: [] };\n }\n\n let typedValue: unknown = value;\n let isValid = true;\n\n // Type validation and coercion\n switch (rules.type) {\n case 'string':\n if (typeof value !== 'string') {\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'string'));\n isValid = false;\n break;\n }\n if (rules.min !== undefined && value.length < rules.min) {\n errors.push(ERRORS.VALIDATION.MIN_LENGTH(field, rules.min));\n isValid = false;\n }\n if (rules.max !== undefined && value.length > rules.max) {\n errors.push(ERRORS.VALIDATION.MAX_LENGTH(field, rules.max));\n isValid = false;\n }\n if (rules.pattern && !rules.pattern.test(value)) {\n errors.push(ERRORS.VALIDATION.INVALID_FORMAT(field));\n isValid = false;\n }\n // Enum check runs before sanitization so the raw value is compared.\n // Sanitizing first could silently modify the value and cause a mismatch\n // with enum entries that contain characters the sanitizer would strip.\n if (isValid && rules.enum && !rules.enum.includes(value)) {\n errors.push(ERRORS.VALIDATION.INVALID_ENUM(field, rules.enum));\n isValid = false;\n }\n if (isValid && rules.sanitize !== false) {\n typedValue = sanitizeString(value);\n }\n break;\n\n case 'number':\n typedValue = Number(value);\n if (isNaN(typedValue as number)) {\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'number'));\n isValid = false;\n break;\n }\n if (rules.min !== undefined && (typedValue as number) < rules.min) {\n errors.push(ERRORS.VALIDATION.MIN_VALUE(field, rules.min));\n isValid = false;\n }\n if (rules.max !== undefined && (typedValue as number) > rules.max) {\n errors.push(ERRORS.VALIDATION.MAX_VALUE(field, rules.max));\n isValid = false;\n }\n break;\n\n case 'boolean':\n if (value === 'true' || value === true || value === 1 || value === '1') {\n typedValue = true;\n } else if (value === 'false' || value === false || value === 0 || value === '0') {\n typedValue = false;\n } else {\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'boolean'));\n isValid = false;\n }\n break;\n\n case 'email':\n if (!VALIDATION.EMAIL.test(String(value))) {\n errors.push(ERRORS.VALIDATION.INVALID_EMAIL(field));\n isValid = false;\n }\n if (isValid) {\n typedValue = sanitizeString(String(value).toLowerCase().trim());\n }\n break;\n\n case 'url':\n if (!VALIDATION.URL.test(String(value))) {\n errors.push(ERRORS.VALIDATION.INVALID_URL(field));\n isValid = false;\n }\n if (isValid) {\n typedValue = sanitizeString(String(value));\n }\n break;\n\n case 'uuid':\n if (!VALIDATION.UUID.test(String(value))) {\n errors.push(ERRORS.VALIDATION.INVALID_UUID(field));\n isValid = false;\n }\n break;\n\n case 'array':\n if (!Array.isArray(value)) {\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'array'));\n isValid = false;\n break;\n }\n if (rules.min !== undefined && value.length < rules.min) {\n errors.push(ERRORS.VALIDATION.MIN_ITEMS(field, rules.min));\n isValid = false;\n }\n if (rules.max !== undefined && value.length > rules.max) {\n errors.push(ERRORS.VALIDATION.MAX_ITEMS(field, rules.max));\n isValid = false;\n }\n break;\n\n case 'object':\n if (typeof value !== 'object' || Array.isArray(value) || value === null) {\n errors.push(ERRORS.VALIDATION.INVALID_TYPE(field, 'object'));\n isValid = false;\n }\n break;\n }\n\n // Enum validation for non-string types (strings check enum before sanitizing above).\n if (isValid && rules.enum && rules.type !== 'string' && !rules.enum.includes(typedValue)) {\n errors.push(ERRORS.VALIDATION.INVALID_ENUM(field, rules.enum));\n isValid = false;\n }\n\n // Custom validation\n if (isValid && rules.custom) {\n const customResult = rules.custom(typedValue);\n if (customResult === undefined) {\n throw new TypeError(\n `Custom validator for field \"${field}\" returned undefined. ` +\n 'Return true to pass, false to fail, or a string error message.'\n );\n }\n if (customResult !== true) {\n errors.push(typeof customResult === 'string' && customResult.length > 0 ? customResult : `${field} is invalid`);\n isValid = false;\n }\n }\n\n return {\n value: isValid ? typedValue : undefined,\n errors,\n };\n}\n\n/**\n * Alias for validate\n * @see validate\n */\nexport const createValidator = validate;\n","/**\n * @module @arcis/node/validation/file\n * File upload validation and filename sanitization\n */\n\n// =============================================================================\n// MAGIC BYTES — first bytes of common file types\n// =============================================================================\n\nconst MAGIC_BYTES: Record<string, Buffer[]> = {\n // Images\n 'image/jpeg': [Buffer.from([0xFF, 0xD8, 0xFF])],\n 'image/png': [Buffer.from([0x89, 0x50, 0x4E, 0x47])],\n 'image/gif': [Buffer.from('GIF87a'), Buffer.from('GIF89a')],\n 'image/webp': [Buffer.from('RIFF')], // RIFF....WEBP\n 'image/bmp': [Buffer.from([0x42, 0x4D])],\n 'image/svg+xml': [], // text-based, check separately\n\n // Documents\n 'application/pdf': [Buffer.from('%PDF')],\n 'application/zip': [Buffer.from([0x50, 0x4B, 0x03, 0x04])],\n\n // Audio/Video\n 'audio/mpeg': [Buffer.from([0xFF, 0xFB]), Buffer.from([0xFF, 0xF3]), Buffer.from([0x49, 0x44, 0x33])],\n 'video/mp4': [], // ftyp at offset 4\n};\n\n// =============================================================================\n// DANGEROUS EXTENSIONS — files that can execute code\n// =============================================================================\n\nconst DANGEROUS_EXTENSIONS = new Set([\n // Scripts\n '.exe', '.bat', '.cmd', '.com', '.msi', '.scr', '.pif',\n '.vbs', '.vbe', '.js', '.jse', '.ws', '.wsf', '.wsc', '.wsh',\n '.ps1', '.ps1xml', '.ps2', '.ps2xml', '.psc1', '.psc2',\n '.sh', '.bash', '.csh', '.ksh',\n // Server-side\n '.php', '.php3', '.php4', '.php5', '.phtml', '.pht',\n '.asp', '.aspx', '.ashx', '.asmx', '.cer',\n '.jsp', '.jspx', '.jsw', '.jsv',\n '.cgi', '.pl', '.py', '.rb',\n // Java\n '.jar', '.war', '.ear', '.class',\n // Config that can execute\n '.htaccess', '.htpasswd',\n // Template engines\n '.ejs', '.pug', '.hbs', '.handlebars', '.njk', '.twig',\n // Shortcuts/links\n '.lnk', '.inf', '.reg', '.url',\n // Office macros\n '.docm', '.xlsm', '.pptm', '.dotm',\n]);\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/** File upload validation options */\nexport interface ValidateFileOptions {\n /** Maximum file size in bytes. Default: 5MB */\n maxSize?: number;\n /** Allowed MIME types (e.g., ['image/jpeg', 'image/png']) */\n allowedTypes?: string[];\n /** Allowed file extensions (e.g., ['.jpg', '.png']). Includes dot. */\n allowedExtensions?: string[];\n /** Block dangerous/executable extensions. Default: true */\n blockExecutables?: boolean;\n /** Validate magic bytes match the claimed MIME type. Default: true */\n validateMagicBytes?: boolean;\n /** Block files with no extension. Default: true */\n blockNoExtension?: boolean;\n /** Block double extensions (e.g., file.php.jpg). Default: true */\n blockDoubleExtensions?: boolean;\n}\n\n/** File metadata for validation */\nexport interface FileInput {\n /** Original filename */\n filename: string;\n /** MIME type (as claimed by client) */\n mimetype: string;\n /** File size in bytes */\n size: number;\n /** File content buffer (for magic byte validation) */\n buffer?: Buffer;\n}\n\n/** File validation result */\nexport interface ValidateFileResult {\n /** Whether the file passed validation */\n valid: boolean;\n /** Validation errors (empty if valid) */\n errors: string[];\n /** Sanitized filename (safe for storage) */\n sanitizedFilename: string;\n}\n\n// =============================================================================\n// DEFAULTS\n// =============================================================================\n\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5MB\n\n// =============================================================================\n// FILENAME SANITIZATION\n// =============================================================================\n\n/**\n * Sanitize a filename for safe storage.\n *\n * Strips path traversal, null bytes, control characters, and special characters.\n * Preserves the extension and converts to a filesystem-safe name.\n *\n * @param filename - The original filename\n * @returns A sanitized filename safe for storage\n *\n * @example\n * sanitizeFilename('../../etc/passwd') // 'etc_passwd'\n * sanitizeFilename('file<name>.jpg') // 'filename.jpg'\n * sanitizeFilename('photo (1).jpg') // 'photo_1.jpg'\n * sanitizeFilename('.htaccess') // 'htaccess'\n */\nexport function sanitizeFilename(filename: string): string {\n let name = filename;\n\n // Strip null bytes\n name = name.replace(/\\0/g, '');\n\n // Strip path components (both Unix and Windows)\n name = name.replace(/^.*[/\\\\]/, '');\n\n // Strip control characters\n name = name.replace(/[\\x00-\\x1F\\x7F]/g, '');\n\n // Strip characters unsafe for filesystems\n name = name.replace(/[<>:\"/\\\\|?*]/g, '');\n\n // Replace spaces and parens with underscores\n name = name.replace(/[\\s()]+/g, '_');\n\n // Strip leading dots (hidden files / .htaccess)\n name = name.replace(/^\\.+/, '');\n\n // Collapse multiple underscores/dots\n name = name.replace(/_{2,}/g, '_');\n name = name.replace(/\\.{2,}/g, '.');\n\n // Trim underscores before dots (e.g., \"photo_1_.jpg\" → \"photo_1.jpg\")\n name = name.replace(/_+\\./g, '.');\n\n // Trim underscores from edges\n name = name.replace(/^_+|_+$/g, '');\n\n // Fallback for empty name\n if (!name || name === '.') {\n name = 'unnamed';\n }\n\n return name;\n}\n\n// =============================================================================\n// MAGIC BYTE VALIDATION\n// =============================================================================\n\n/**\n * Check if file content matches the claimed MIME type via magic bytes.\n */\nfunction matchesMagicBytes(buffer: Buffer, mimetype: string): boolean {\n const signatures = MAGIC_BYTES[mimetype];\n if (!signatures || signatures.length === 0) return true; // no signature to check\n\n return signatures.some(sig => {\n if (buffer.length < sig.length) return false;\n return buffer.subarray(0, sig.length).equals(sig);\n });\n}\n\n// =============================================================================\n// EXTENSION HELPERS\n// =============================================================================\n\n/**\n * Get the extension from a filename (lowercase, with dot).\n */\nfunction getExtension(filename: string): string {\n const lastDot = filename.lastIndexOf('.');\n if (lastDot < 1) return '';\n return filename.slice(lastDot).toLowerCase();\n}\n\n/**\n * Check if a filename has double extensions (e.g., file.php.jpg).\n */\nfunction hasDoubleExtension(filename: string): boolean {\n const parts = filename.split('.');\n if (parts.length < 3) return false;\n\n // Check if any non-final extension is dangerous\n for (let i = 1; i < parts.length - 1; i++) {\n const ext = '.' + parts[i].toLowerCase();\n if (DANGEROUS_EXTENSIONS.has(ext)) return true;\n }\n return false;\n}\n\n// =============================================================================\n// FILE VALIDATION\n// =============================================================================\n\n/**\n * Validate a file upload for security.\n *\n * Checks file size, MIME type, extension, magic bytes, and dangerous patterns.\n * Returns a result with validation errors and a sanitized filename.\n *\n * @param file - File metadata and optional content\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * const result = validateFile(\n * { filename: 'photo.jpg', mimetype: 'image/jpeg', size: 1024, buffer },\n * { allowedTypes: ['image/jpeg', 'image/png'], maxSize: 2 * 1024 * 1024 }\n * );\n * if (!result.valid) {\n * return res.status(400).json({ errors: result.errors });\n * }\n * // Use result.sanitizedFilename for storage\n *\n * @example\n * // Block executables only (no whitelist)\n * const result = validateFile(file, { blockExecutables: true });\n */\nexport function validateFile(\n file: FileInput,\n options: ValidateFileOptions = {}\n): ValidateFileResult {\n const {\n maxSize = DEFAULT_MAX_SIZE,\n allowedTypes,\n allowedExtensions,\n blockExecutables = true,\n validateMagicBytes = true,\n blockNoExtension = true,\n blockDoubleExtensions = true,\n } = options;\n\n const errors: string[] = [];\n const sanitizedFilename = sanitizeFilename(file.filename);\n const extension = getExtension(sanitizedFilename);\n\n // Size check\n if (file.size > maxSize) {\n errors.push(`File size ${file.size} exceeds maximum ${maxSize} bytes`);\n }\n\n if (file.size === 0) {\n errors.push('File is empty');\n }\n\n // Extension checks\n if (blockNoExtension && !extension) {\n errors.push('File has no extension');\n }\n\n if (blockExecutables && extension && DANGEROUS_EXTENSIONS.has(extension)) {\n errors.push(`Executable extension \"${extension}\" is not allowed`);\n }\n\n if (blockDoubleExtensions && hasDoubleExtension(sanitizedFilename)) {\n errors.push('Double extensions with executable types are not allowed');\n }\n\n if (allowedExtensions && extension) {\n const normalizedAllowed = allowedExtensions.map(e => e.toLowerCase());\n if (!normalizedAllowed.includes(extension)) {\n errors.push(`Extension \"${extension}\" is not allowed. Allowed: ${normalizedAllowed.join(', ')}`);\n }\n }\n\n // MIME type check\n if (allowedTypes && !allowedTypes.includes(file.mimetype)) {\n errors.push(`MIME type \"${file.mimetype}\" is not allowed. Allowed: ${allowedTypes.join(', ')}`);\n }\n\n // Magic bytes validation\n if (validateMagicBytes && file.buffer && file.buffer.length > 0) {\n if (!matchesMagicBytes(file.buffer, file.mimetype)) {\n errors.push(`File content does not match claimed MIME type \"${file.mimetype}\"`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n sanitizedFilename,\n };\n}\n\n/**\n * Check if a file extension is considered dangerous/executable.\n *\n * @param filename - Filename or extension to check\n * @returns true if the extension is dangerous\n */\nexport function isDangerousExtension(filename: string): boolean {\n const ext = getExtension(filename);\n return ext !== '' && DANGEROUS_EXTENSIONS.has(ext);\n}\n","/**\n * @module @arcis/node/validation/url\n * SSRF (Server-Side Request Forgery) prevention\n *\n * Validates URLs to ensure they don't target private/internal networks,\n * localhost, cloud metadata endpoints, or use dangerous protocols.\n *\n * @example\n * import { validateUrl } from '@arcis/node';\n *\n * // Block SSRF attempts\n * validateUrl('http://169.254.169.254/latest/meta-data/') // { safe: false, reason: 'link-local address' }\n * validateUrl('http://10.0.0.1/admin') // { safe: false, reason: 'private address (10.0.0.0/8)' }\n * validateUrl('http://localhost/secret') // { safe: false, reason: 'loopback address' }\n * validateUrl('file:///etc/passwd') // { safe: false, reason: 'disallowed protocol: file:' }\n *\n * // Allow safe URLs\n * validateUrl('https://api.example.com/data') // { safe: true }\n */\n\n/** Options for URL validation */\nexport interface ValidateUrlOptions {\n /** Allowed protocols. Default: ['http:', 'https:'] */\n allowedProtocols?: string[];\n /** Additional hostnames to block (e.g., internal service names) */\n blockedHosts?: string[];\n /** Additional hostnames to always allow (bypass IP checks) */\n allowedHosts?: string[];\n /** Allow localhost/loopback. Default: false */\n allowLocalhost?: boolean;\n /** Allow private/internal IPs. Default: false */\n allowPrivate?: boolean;\n}\n\n/** Result of URL validation */\nexport interface ValidateUrlResult {\n /** Whether the URL is safe to fetch */\n safe: boolean;\n /** Reason the URL was blocked (only set when safe=false) */\n reason?: string;\n}\n\n/**\n * Validate a URL for SSRF safety.\n *\n * Checks:\n * 1. Valid URL format\n * 2. Allowed protocol (default: http, https only)\n * 3. Not localhost/loopback (127.x.x.x, ::1, localhost)\n * 4. Not private IP (10.x, 172.16-31.x, 192.168.x)\n * 5. Not link-local (169.254.x.x — includes AWS/GCP/Azure metadata)\n * 6. Not blocked hostname\n * 7. No credentials in URL (user:pass@host)\n *\n * @param url - The URL string to validate\n * @param options - Validation options\n * @returns Validation result with safe flag and optional reason\n */\nexport function validateUrl(url: string, options: ValidateUrlOptions = {}): ValidateUrlResult {\n const {\n allowedProtocols = ['http:', 'https:'],\n blockedHosts = [],\n allowedHosts = [],\n allowLocalhost = false,\n allowPrivate = false,\n } = options;\n\n if (typeof url !== 'string' || url.trim() === '') {\n return { safe: false, reason: 'invalid URL: empty or not a string' };\n }\n\n // Parse URL\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return { safe: false, reason: 'invalid URL: failed to parse' };\n }\n\n // Check protocol\n if (!allowedProtocols.includes(parsed.protocol)) {\n return { safe: false, reason: `disallowed protocol: ${parsed.protocol}` };\n }\n\n // Check for credentials in URL (user:pass@host)\n if (parsed.username || parsed.password) {\n return { safe: false, reason: 'URL contains credentials' };\n }\n\n const hostname = parsed.hostname.toLowerCase();\n\n // Check explicit allowlist first (bypass IP checks)\n if (allowedHosts.some(h => hostname === h.toLowerCase())) {\n return { safe: true };\n }\n\n // Check explicit blocklist\n if (blockedHosts.some(h => hostname === h.toLowerCase())) {\n return { safe: false, reason: `blocked host: ${hostname}` };\n }\n\n // Check localhost/loopback\n if (!allowLocalhost) {\n if (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '[::1]' ||\n hostname === '::1' ||\n hostname === '0.0.0.0' ||\n hostname.endsWith('.localhost')\n ) {\n return { safe: false, reason: 'loopback address' };\n }\n\n // Check 127.x.x.x range\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\n return { safe: false, reason: 'loopback address' };\n }\n }\n\n // Check decimal IP (e.g., 2130706433 = 127.0.0.1)\n if (!allowLocalhost || !allowPrivate) {\n const decimalCheck = checkDecimalIp(hostname, allowLocalhost, allowPrivate);\n if (decimalCheck) {\n return { safe: false, reason: decimalCheck };\n }\n }\n\n // Check octal IP (e.g., 0177.0.0.1 = 127.0.0.1)\n if (!allowLocalhost || !allowPrivate) {\n const octalCheck = checkOctalIp(hostname, allowLocalhost, allowPrivate);\n if (octalCheck) {\n return { safe: false, reason: octalCheck };\n }\n }\n\n // Check private/internal IPs\n if (!allowPrivate) {\n const privateCheck = checkPrivateIp(hostname);\n if (privateCheck) {\n return { safe: false, reason: privateCheck };\n }\n }\n\n return { safe: true };\n}\n\n/**\n * Convenience wrapper that returns true/false.\n *\n * @param url - The URL to check\n * @param options - Validation options\n * @returns true if the URL is safe to fetch\n */\nexport function isUrlSafe(url: string, options: ValidateUrlOptions = {}): boolean {\n return validateUrl(url, options).safe;\n}\n\n/**\n * Check if a hostname is a private/internal IP address.\n * Returns the reason string if private, or null if not.\n */\nfunction checkPrivateIp(hostname: string): string | null {\n // 10.0.0.0/8\n if (/^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\n return 'private address (10.0.0.0/8)';\n }\n\n // 172.16.0.0/12 (172.16.x.x - 172.31.x.x)\n const match172 = hostname.match(/^172\\.(\\d{1,3})\\.\\d{1,3}\\.\\d{1,3}$/);\n if (match172) {\n const second = parseInt(match172[1], 10);\n if (second >= 16 && second <= 31) {\n return 'private address (172.16.0.0/12)';\n }\n }\n\n // 192.168.0.0/16\n if (/^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\n return 'private address (192.168.0.0/16)';\n }\n\n // 169.254.0.0/16 — link-local, includes cloud metadata endpoints\n // AWS: 169.254.169.254, GCP: metadata.google.internal, Azure: 169.254.169.254\n if (/^169\\.254\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\n return 'link-local address (169.254.0.0/16)';\n }\n\n // 0.0.0.0/8 (current network)\n if (/^0\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(hostname)) {\n return 'current network address (0.0.0.0/8)';\n }\n\n // Cloud metadata hostnames\n if (\n hostname === 'metadata.google.internal' ||\n hostname === 'metadata.internal' ||\n hostname === 'metadata.azure.internal'\n ) {\n return 'cloud metadata endpoint';\n }\n\n // IPv6 private ranges (simplified — bracket-wrapped in URLs)\n const ipv6 = hostname.replace(/^\\[|\\]$/g, '');\n if (\n ipv6 === '::1' ||\n ipv6 === '::' ||\n ipv6.startsWith('fc') ||\n ipv6.startsWith('fd') ||\n ipv6.startsWith('fe80')\n ) {\n return 'private IPv6 address';\n }\n\n // IPv6-mapped IPv4 — dotted form (::ffff:127.0.0.1)\n const mappedDotted = ipv6.match(/^::ffff:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/i);\n if (mappedDotted) {\n const mappedIp = mappedDotted[1];\n if (/^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(mappedIp)) {\n return 'IPv6-mapped loopback address';\n }\n const mappedCheck = checkPrivateIp(mappedIp);\n if (mappedCheck) {\n return `IPv6-mapped ${mappedCheck}`;\n }\n }\n\n // IPv6-mapped IPv4 — hex form (::ffff:7f00:1 = 127.0.0.1)\n // Node's URL parser normalizes ::ffff:a.b.c.d to ::ffff:XXYY:ZZWW\n const mappedHex = ipv6.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);\n if (mappedHex) {\n const hi = parseInt(mappedHex[1], 16);\n const lo = parseInt(mappedHex[2], 16);\n const a = (hi >> 8) & 0xFF;\n const b = hi & 0xFF;\n const c = (lo >> 8) & 0xFF;\n const d = lo & 0xFF;\n const dotted = `${a}.${b}.${c}.${d}`;\n if (a === 127) {\n return 'IPv6-mapped loopback address';\n }\n const hexCheck = checkPrivateIp(dotted);\n if (hexCheck) {\n return `IPv6-mapped ${hexCheck}`;\n }\n }\n\n return null;\n}\n\n/**\n * Parse a decimal integer as an IPv4 address and check if it's private/loopback.\n * e.g., 2130706433 = 127.0.0.1, 167772160 = 10.0.0.0\n */\nfunction checkDecimalIp(hostname: string, allowLocalhost: boolean, allowPrivate: boolean): string | null {\n // Must be a pure decimal integer\n if (!/^\\d+$/.test(hostname)) return null;\n\n const num = parseInt(hostname, 10);\n if (isNaN(num) || num < 0 || num > 0xFFFFFFFF) return null;\n\n const a = (num >>> 24) & 0xFF;\n const b = (num >>> 16) & 0xFF;\n const c = (num >>> 8) & 0xFF;\n const d = num & 0xFF;\n const dotted = `${a}.${b}.${c}.${d}`;\n\n // Check loopback\n if (!allowLocalhost && a === 127) {\n return `loopback address (decimal IP: ${dotted})`;\n }\n\n // Check private ranges\n if (!allowPrivate) {\n const privateCheck = checkPrivateIp(dotted);\n if (privateCheck) {\n return `${privateCheck} (decimal IP: ${dotted})`;\n }\n }\n\n return null;\n}\n\n/**\n * Parse octal-notation IPv4 address and check if it's private/loopback.\n * e.g., 0177.0.0.1 = 127.0.0.1, 0x7f.0.0.1 = 127.0.0.1\n */\nfunction checkOctalIp(hostname: string, allowLocalhost: boolean, allowPrivate: boolean): string | null {\n // Must look like a dotted quad where at least one octet has a leading zero or 0x prefix\n const parts = hostname.split('.');\n if (parts.length !== 4) return null;\n\n // Check if any part uses octal (leading 0) or hex (0x) notation\n const hasAlternateNotation = parts.some(p => /^0[0-7]+$/.test(p) || /^0x[0-9a-fA-F]+$/i.test(p));\n if (!hasAlternateNotation) return null;\n\n const octets: number[] = [];\n for (const part of parts) {\n let val: number;\n if (/^0x[0-9a-fA-F]+$/i.test(part)) {\n val = parseInt(part, 16);\n } else if (/^0[0-7]*$/.test(part)) {\n val = parseInt(part, 8);\n } else if (/^\\d+$/.test(part)) {\n val = parseInt(part, 10);\n } else {\n return null;\n }\n if (val < 0 || val > 255) return null;\n octets.push(val);\n }\n\n const dotted = octets.join('.');\n\n // Check loopback\n if (!allowLocalhost && octets[0] === 127) {\n return `loopback address (octal IP: ${dotted})`;\n }\n\n // Check private ranges\n if (!allowPrivate) {\n const privateCheck = checkPrivateIp(dotted);\n if (privateCheck) {\n return `${privateCheck} (octal IP: ${dotted})`;\n }\n }\n\n return null;\n}\n","/**\n * @module @arcis/node/validation/redirect\n * Open Redirect prevention\n *\n * Prevents attackers from using your app to redirect users to malicious sites\n * via manipulated query parameters like ?returnUrl=http://evil.com\n *\n * @example\n * import { validateRedirect, isRedirectSafe } from '@arcis/node';\n *\n * // Block open redirects\n * validateRedirect('http://evil.com') // { safe: false, reason: 'absolute URL not in allowed hosts' }\n * validateRedirect('//evil.com') // { safe: false, reason: 'protocol-relative URL not in allowed hosts' }\n * validateRedirect('javascript:alert(1)') // { safe: false, reason: 'dangerous protocol: javascript:' }\n *\n * // Allow safe redirects\n * validateRedirect('/dashboard') // { safe: true }\n * validateRedirect('/users?page=2') // { safe: true }\n * validateRedirect('https://myapp.com/home', { allowedHosts: ['myapp.com'] }) // { safe: true }\n */\n\n/** Options for redirect validation */\nexport interface ValidateRedirectOptions {\n /** Hostnames that are allowed for absolute URL redirects */\n allowedHosts?: string[];\n /** Allow protocol-relative URLs (//example.com). Default: false */\n allowProtocolRelative?: boolean;\n /** Allowed protocols for absolute URLs. Default: ['http:', 'https:'] */\n allowedProtocols?: string[];\n}\n\n/** Result of redirect validation */\nexport interface ValidateRedirectResult {\n /** Whether the redirect URL is safe */\n safe: boolean;\n /** Reason the redirect was blocked (only set when safe=false) */\n reason?: string;\n}\n\n/** Protocols that can execute code or exfiltrate data */\nconst DANGEROUS_PROTOCOLS = /^(javascript|data|vbscript|blob):/i;\n\n/** Characters used to disguise URLs (tabs, newlines inside scheme) */\nconst CONTROL_CHARS = /[\\t\\n\\r]/g;\n\n/**\n * Validate a redirect URL to prevent open redirect attacks.\n *\n * Safe redirects:\n * - Relative paths: /dashboard, /users?page=2, ../settings\n * - Absolute URLs to allowed hosts (when configured)\n *\n * Blocked redirects:\n * - Absolute URLs to unknown hosts\n * - Protocol-relative URLs (//evil.com)\n * - javascript:, data:, vbscript:, blob: protocols\n * - Backslash-prefixed paths (\\\\evil.com — browser treats as //)\n * - URLs with control characters that could disguise the target\n *\n * @param url - The redirect target URL to validate\n * @param options - Validation options\n * @returns Validation result with safe flag and optional reason\n */\nexport function validateRedirect(\n url: string,\n options: ValidateRedirectOptions = {},\n): ValidateRedirectResult {\n const {\n allowedHosts = [],\n allowProtocolRelative = false,\n allowedProtocols = ['http:', 'https:'],\n } = options;\n\n if (typeof url !== 'string' || url.trim() === '') {\n return { safe: false, reason: 'invalid redirect: empty or not a string' };\n }\n\n // Strip control characters that could disguise the URL\n const cleaned = url.replace(CONTROL_CHARS, '');\n\n // Block dangerous protocols (javascript:, data:, etc.)\n if (DANGEROUS_PROTOCOLS.test(cleaned)) {\n const proto = cleaned.match(DANGEROUS_PROTOCOLS);\n return { safe: false, reason: `dangerous protocol: ${proto![0]}` };\n }\n\n // Block backslash-prefixed paths — browsers treat \\ as / in URLs\n // so \\evil.com or \\/evil.com could redirect to //evil.com\n if (cleaned.startsWith('\\\\')) {\n return { safe: false, reason: 'backslash-prefixed URL (browser treats as protocol-relative)' };\n }\n\n // Check protocol-relative URLs (//evil.com)\n if (cleaned.startsWith('//')) {\n if (!allowProtocolRelative) {\n // Still check allowedHosts\n const host = extractHost(cleaned);\n if (host && allowedHosts.some(h => host === h.toLowerCase())) {\n return { safe: true };\n }\n return { safe: false, reason: 'protocol-relative URL not in allowed hosts' };\n }\n const host = extractHost(cleaned);\n if (host && allowedHosts.length > 0 && !allowedHosts.some(h => host === h.toLowerCase())) {\n return { safe: false, reason: 'protocol-relative URL not in allowed hosts' };\n }\n return { safe: true };\n }\n\n // Check if it's an absolute URL (has scheme)\n let parsed: URL;\n try {\n parsed = new URL(cleaned);\n } catch {\n // Not a valid absolute URL — treat as relative path (safe)\n return { safe: true };\n }\n\n // If we got here, it parsed as an absolute URL\n // Check protocol\n if (!allowedProtocols.includes(parsed.protocol)) {\n return { safe: false, reason: `disallowed protocol: ${parsed.protocol}` };\n }\n\n // Check if host is in allowed list\n const hostname = parsed.hostname.toLowerCase();\n if (allowedHosts.length === 0) {\n return { safe: false, reason: 'absolute URL not in allowed hosts' };\n }\n\n if (!allowedHosts.some(h => hostname === h.toLowerCase())) {\n return { safe: false, reason: `host not allowed: ${hostname}` };\n }\n\n return { safe: true };\n}\n\n/**\n * Convenience wrapper that returns true/false.\n *\n * @param url - The redirect URL to check\n * @param options - Validation options\n * @returns true if the redirect is safe\n */\nexport function isRedirectSafe(url: string, options: ValidateRedirectOptions = {}): boolean {\n return validateRedirect(url, options).safe;\n}\n\n/**\n * Extract hostname from a protocol-relative URL.\n */\nfunction extractHost(url: string): string | null {\n // //hostname/path or //hostname:port/path\n const match = url.match(/^\\/\\/([^/:?#]+)/);\n return match ? match[1].toLowerCase() : null;\n}\n","/**\n * @module @arcis/node/validation/email\n * Advanced email validation with disposable detection and typo suggestions.\n *\n * Three levels of validation:\n * 1. Syntax — RFC-compliant format checking\n * 2. Domain intelligence — disposable/free provider detection, typo correction\n * 3. MX verification — DNS MX record lookup (async, optional)\n *\n * @example\n * const result = validateEmail('user@tempmail.com');\n * // { valid: false, reason: 'disposable' }\n *\n * const result = validateEmail('user@gmial.com');\n * // { valid: true, reason: 'typo', suggestion: 'user@gmail.com' }\n */\n\nimport { promises as dns } from 'dns';\n\nexport interface EmailValidationOptions {\n /** Check for disposable email providers. Default: true */\n checkDisposable?: boolean;\n /** Suggest corrections for typos. Default: true */\n suggestTypoFix?: boolean;\n /** Verify MX records via DNS. Default: false */\n checkMx?: boolean;\n /** Additional blocked domains */\n blockedDomains?: string[];\n /** Additional allowed domains (bypasses disposable check) */\n allowedDomains?: string[];\n}\n\nexport interface EmailValidationResult {\n /** Whether the email is valid */\n valid: boolean;\n /** Reason for the result */\n reason: 'valid' | 'invalid_syntax' | 'disposable' | 'no_mx' | 'blocked' | 'typo';\n /** Suggested correction if a typo was detected */\n suggestion: string | null;\n /** Whether the domain is a free email provider */\n isFree: boolean;\n /** Whether the domain is a disposable email provider */\n isDisposable: boolean;\n /** The normalized email address */\n normalized: string;\n}\n\n// RFC 5321: local part max 64, domain max 255, total max 254\nconst MAX_EMAIL_LENGTH = 254;\nconst MAX_LOCAL_LENGTH = 64;\nconst MAX_DOMAIN_LENGTH = 255;\n\n/**\n * Strict email syntax regex.\n * - No consecutive dots in local part\n * - No leading/trailing dots in local part\n * - Domain must have at least one dot\n * - No spaces anywhere\n */\nconst EMAIL_SYNTAX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\\.[a-zA-Z]{2,}$/;\n\n/** Common free email providers */\nconst FREE_PROVIDERS = new Set([\n 'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'aol.com',\n 'protonmail.com', 'proton.me', 'icloud.com', 'mail.com', 'zoho.com',\n 'yandex.com', 'gmx.com', 'gmx.net', 'live.com', 'msn.com',\n 'me.com', 'mac.com', 'fastmail.com', 'tutanota.com', 'hey.com',\n]);\n\n/** Common disposable email domains */\nconst DISPOSABLE_DOMAINS = new Set([\n // Popular disposable services\n 'guerrillamail.com', 'guerrillamail.net', 'guerrillamail.org',\n 'tempmail.com', 'temp-mail.org', 'temp-mail.io',\n 'throwaway.email', 'throwaway.com',\n 'mailinator.com', 'mailinator.net',\n 'yopmail.com', 'yopmail.fr', 'yopmail.net',\n 'sharklasers.com', 'grr.la', 'guerrillamail.info',\n 'guerrillamail.biz', 'guerrillamail.de',\n 'trashmail.com', 'trashmail.me', 'trashmail.net',\n 'dispostable.com', 'maildrop.cc',\n 'mailnesia.com', 'tempail.com',\n 'mohmal.com', 'getnada.com',\n 'emailondeck.com', 'discard.email',\n 'fakeinbox.com', 'mailcatch.com',\n 'mintemail.com', 'tempr.email',\n 'tempinbox.com', 'burnermail.io',\n 'mailsac.com', 'harakirimail.com',\n 'tempmailo.com', 'emailfake.com',\n 'crazymailing.com', 'armyspy.com',\n 'dayrep.com', 'einrot.com',\n 'fleckens.hu', 'gustr.com',\n 'jourrapide.com', 'rhyta.com',\n 'superrito.com', 'teleworm.us',\n '10minutemail.com', '10minutemail.net',\n 'minutemail.com', 'tempsky.com',\n 'spamgourmet.com', 'mytrashmail.com',\n 'mailexpire.com', 'safetymail.info',\n 'filzmail.com', 'trashymail.com',\n 'sharkmail.com', 'jetable.org',\n 'nospam.ze.tc', 'trash-me.com',\n 'dodgit.com', 'mailmoat.com',\n 'spamfree24.org', 'incognitomail.org',\n 'tempomail.fr', 'ephemail.net',\n 'hidemail.de', 'spaml.de',\n 'uggsrock.com', 'binkmail.com',\n 'suremail.info', 'bugmenot.com',\n]);\n\n/** Common typos and their corrections */\nconst DOMAIN_TYPOS: Record<string, string> = {\n 'gmial.com': 'gmail.com',\n 'gmaill.com': 'gmail.com',\n 'gmai.com': 'gmail.com',\n 'gamil.com': 'gmail.com',\n 'gnail.com': 'gmail.com',\n 'gmal.com': 'gmail.com',\n 'gmil.com': 'gmail.com',\n 'gmail.co': 'gmail.com',\n 'gmail.cm': 'gmail.com',\n 'gmail.om': 'gmail.com',\n 'gmail.con': 'gmail.com',\n 'gmail.cim': 'gmail.com',\n 'gmail.comm': 'gmail.com',\n 'yahooo.com': 'yahoo.com',\n 'yaho.com': 'yahoo.com',\n 'yahoo.co': 'yahoo.com',\n 'yahoo.cm': 'yahoo.com',\n 'yahoo.con': 'yahoo.com',\n 'yahho.com': 'yahoo.com',\n 'hotmial.com': 'hotmail.com',\n 'hotmal.com': 'hotmail.com',\n 'hotmai.com': 'hotmail.com',\n 'hotmil.com': 'hotmail.com',\n 'hotmail.co': 'hotmail.com',\n 'hotmail.cm': 'hotmail.com',\n 'hotmail.con': 'hotmail.com',\n 'outlok.com': 'outlook.com',\n 'outloo.com': 'outlook.com',\n 'outlook.co': 'outlook.com',\n 'outlook.cm': 'outlook.com',\n 'protonmal.com': 'protonmail.com',\n 'protonmail.co': 'protonmail.com',\n 'icloud.co': 'icloud.com',\n 'icloud.cm': 'icloud.com',\n 'icoud.com': 'icloud.com',\n};\n\nfunction invalidResult(reason: EmailValidationResult['reason'], email: string): EmailValidationResult {\n return {\n valid: false,\n reason,\n suggestion: null,\n isFree: false,\n isDisposable: false,\n normalized: email,\n };\n}\n\n/**\n * Validate an email address with syntax checking, disposable detection,\n * and typo suggestions.\n *\n * @param email - Email address to validate\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * validateEmail('user@gmail.com')\n * // { valid: true, reason: 'valid', isFree: true }\n *\n * validateEmail('user@tempmail.com')\n * // { valid: false, reason: 'disposable' }\n *\n * validateEmail('user@gmial.com')\n * // { valid: true, reason: 'typo', suggestion: 'user@gmail.com' }\n */\nexport function validateEmail(\n email: string,\n options: EmailValidationOptions = {}\n): EmailValidationResult {\n const {\n checkDisposable = true,\n suggestTypoFix = true,\n blockedDomains = [],\n allowedDomains = [],\n } = options;\n\n // Normalize\n const normalized = email.trim().toLowerCase();\n\n // Basic checks\n if (!normalized || normalized.length > MAX_EMAIL_LENGTH) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n const atIndex = normalized.lastIndexOf('@');\n if (atIndex === -1) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n const localPart = normalized.slice(0, atIndex);\n const domain = normalized.slice(atIndex + 1);\n\n // Length checks\n if (localPart.length === 0 || localPart.length > MAX_LOCAL_LENGTH) {\n return invalidResult('invalid_syntax', normalized);\n }\n if (domain.length === 0 || domain.length > MAX_DOMAIN_LENGTH) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n // Consecutive dots in local part\n if (localPart.includes('..')) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n // Leading/trailing dots in local part\n if (localPart.startsWith('.') || localPart.endsWith('.')) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n // Full regex validation\n if (!EMAIL_SYNTAX.test(normalized)) {\n return invalidResult('invalid_syntax', normalized);\n }\n\n // Check if domain is explicitly allowed (bypass other checks)\n const allowedSet = new Set(allowedDomains.map(d => d.toLowerCase()));\n if (allowedSet.has(domain)) {\n return {\n valid: true,\n reason: 'valid',\n suggestion: null,\n isFree: FREE_PROVIDERS.has(domain),\n isDisposable: false,\n normalized,\n };\n }\n\n // Check blocked domains\n const blockedSet = new Set(blockedDomains.map(d => d.toLowerCase()));\n if (blockedSet.has(domain)) {\n return invalidResult('blocked', normalized);\n }\n\n // Check disposable\n const isDisposable = DISPOSABLE_DOMAINS.has(domain);\n if (checkDisposable && isDisposable) {\n return {\n valid: false,\n reason: 'disposable',\n suggestion: null,\n isFree: false,\n isDisposable: true,\n normalized,\n };\n }\n\n // Check typos\n const isFree = FREE_PROVIDERS.has(domain);\n if (suggestTypoFix && DOMAIN_TYPOS[domain]) {\n const corrected = `${localPart}@${DOMAIN_TYPOS[domain]}`;\n return {\n valid: true,\n reason: 'typo',\n suggestion: corrected,\n isFree: FREE_PROVIDERS.has(DOMAIN_TYPOS[domain]),\n isDisposable: false,\n normalized,\n };\n }\n\n return {\n valid: true,\n reason: 'valid',\n suggestion: null,\n isFree,\n isDisposable,\n normalized,\n };\n}\n\n/**\n * Verify that the email domain has MX records (can receive email).\n *\n * This performs a DNS lookup and requires network access.\n * Use for registration flows where you need high confidence.\n *\n * @param email - Email address to verify\n * @returns True if the domain has MX records\n *\n * @example\n * if (await verifyEmailMx('user@example.com')) {\n * // Domain can receive email\n * }\n */\nexport async function verifyEmailMx(email: string): Promise<boolean> {\n if (!isValidEmailSyntax(email)) return false;\n\n const atIndex = email.lastIndexOf('@');\n const domain = email.slice(atIndex + 1).trim().toLowerCase();\n if (!domain) return false;\n\n try {\n const records = await dns.resolveMx(domain);\n return records.length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Quick check if an email address has valid syntax.\n * Faster than validateEmail() — just syntax, no domain intelligence.\n */\nexport function isValidEmailSyntax(email: string): boolean {\n const normalized = email.trim().toLowerCase();\n if (!normalized || normalized.length > MAX_EMAIL_LENGTH) return false;\n\n const atIndex = normalized.lastIndexOf('@');\n if (atIndex === -1) return false;\n\n const localPart = normalized.slice(0, atIndex);\n if (localPart.includes('..') || localPart.startsWith('.') || localPart.endsWith('.')) return false;\n\n return EMAIL_SYNTAX.test(normalized);\n}\n","/**\n * @module @arcis/node/logging/redactor\n * Safe logging with PII/secret redaction\n */\n\nimport { REDACTION, INPUT } from '../core/constants';\nimport type { LogOptions, SafeLogger } from '../core/types';\n\nconst LOG_LEVELS: Record<string, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\n/**\n * Create a safe logger that redacts sensitive data and prevents log injection.\n * \n * @param options - Logger configuration\n * @returns SafeLogger instance\n * \n * @example\n * const logger = createSafeLogger();\n * logger.info('User login', { email: 'user@test.com', password: 'secret' });\n * // Logs: { \"email\": \"user@test.com\", \"password\": \"[REDACTED]\" }\n * \n * @example\n * // With custom redact keys\n * const logger = createSafeLogger({ redactKeys: ['customToken', 'internalId'] });\n */\nexport function createSafeLogger(options: LogOptions = {}): SafeLogger {\n const {\n redactKeys = [],\n maxLength = REDACTION.DEFAULT_MAX_LENGTH,\n redactPatterns = [],\n level: minLevel = 'debug',\n } = options;\n\n const minLevelNum = LOG_LEVELS[minLevel] ?? 0;\n\n // Combine default and custom keys (lowercase for case-insensitive matching)\n const allRedactKeys = new Set([\n ...Array.from(REDACTION.SENSITIVE_KEYS),\n ...redactKeys.map(k => k.toLowerCase()),\n ]);\n\n /**\n * Redact sensitive data from an object recursively.\n */\n function redact(obj: unknown, depth = 0): unknown {\n if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\n if (obj === null || obj === undefined) return obj;\n\n if (typeof obj === 'string') {\n return redactString(obj, maxLength, redactPatterns);\n }\n\n if (typeof obj !== 'object') return obj;\n\n if (Array.isArray(obj)) {\n return obj.map(item => redact(item, depth + 1));\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (allRedactKeys.has(key.toLowerCase())) {\n result[key] = REDACTION.REPLACEMENT;\n } else {\n result[key] = redact(value, depth + 1);\n }\n }\n return result;\n }\n\n /**\n * Log a message at the specified level.\n */\n function log(level: string, message: string, data?: unknown): void {\n // Early exit: skip all work if message level is below minimum\n const levelNum = LOG_LEVELS[level] ?? 0;\n if (levelNum < minLevelNum) return;\n\n const entry: Record<string, unknown> = {\n timestamp: new Date().toISOString(),\n level,\n message: redactString(message, maxLength, redactPatterns),\n };\n\n if (data !== undefined) {\n entry.data = redact(data);\n }\n\n console.log(JSON.stringify(entry));\n }\n\n return {\n log,\n info: (msg: string, data?: unknown) => log('info', msg, data),\n warn: (msg: string, data?: unknown) => log('warn', msg, data),\n error: (msg: string, data?: unknown) => log('error', msg, data),\n debug: (msg: string, data?: unknown) => log('debug', msg, data),\n };\n}\n\n/**\n * Redact a string value.\n * Removes newlines (log injection prevention), applies patterns, and truncates.\n */\nfunction redactString(str: string, maxLength: number, patterns: RegExp[]): string {\n // Remove newlines/tabs (log injection prevention) and genuine control characters.\n // Only strip C0/C1 control chars and null bytes — preserve all printable Unicode\n // (CJK, Cyrillic, Arabic, etc.) so multilingual content isn't silently lost.\n let safe = str\n .replace(/[\\r\\n\\t]/g, ' ')\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F\\x80-\\x9F]/g, '');\n\n // Apply custom redaction patterns\n for (const pattern of patterns) {\n safe = safe.replace(pattern, REDACTION.REPLACEMENT);\n }\n\n // Truncate if too long\n if (safe.length > maxLength) {\n safe = safe.substring(0, maxLength) + `...${REDACTION.TRUNCATED}`;\n }\n\n return safe;\n}\n\n/**\n * Create a redactor function for custom use.\n * \n * @param sensitiveKeys - Keys to redact\n * @returns Redactor function\n */\nexport function createRedactor(sensitiveKeys: string[] = []): (obj: unknown) => unknown {\n const allKeys = new Set([\n ...Array.from(REDACTION.SENSITIVE_KEYS),\n ...sensitiveKeys.map(k => k.toLowerCase()),\n ]);\n\n function redact(obj: unknown, depth = 0): unknown {\n if (depth > INPUT.MAX_RECURSION_DEPTH) return REDACTION.MAX_DEPTH;\n if (obj === null || obj === undefined) return obj;\n if (typeof obj !== 'object') return obj;\n\n if (Array.isArray(obj)) {\n return obj.map(item => redact(item, depth + 1));\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (allKeys.has(key.toLowerCase())) {\n result[key] = REDACTION.REPLACEMENT;\n } else {\n result[key] = redact(value, depth + 1);\n }\n }\n return result;\n }\n\n return redact;\n}\n\n/**\n * Alias for createSafeLogger\n * @see createSafeLogger\n */\nexport const safeLog = createSafeLogger;\n","/**\n * @module @arcis/node/middleware/main\n * Main arcis() middleware factory\n */\n\nimport type { RequestHandler } from 'express';\nimport type {\n ArcisOptions,\n ArcisFunction,\n ArcisMiddlewareStack,\n HeaderOptions,\n RateLimitOptions,\n SanitizeOptions,\n} from '../core/types';\nimport { createHeaders } from './headers';\nimport { createRateLimiter } from './rate-limit';\nimport { createErrorHandler } from './error-handler';\nimport { createSanitizer } from '../sanitizers';\nimport { validate } from '../validation';\nimport { createSafeLogger } from '../logging';\n\n/**\n * Create Arcis middleware with all protections enabled.\n * \n * @param options - Configuration options\n * @returns Array of Express middleware\n * \n * @example\n * // Full protection (recommended)\n * app.use(arcis());\n * \n * @example\n * // Custom configuration\n * app.use(arcis({\n * rateLimit: { max: 50 },\n * headers: { frameOptions: 'SAMEORIGIN' }\n * }));\n * \n * @example\n * // Disable specific features\n * app.use(arcis({\n * rateLimit: false,\n * sanitize: { sql: false }\n * }));\n * \n * @example\n * // Cleanup on shutdown\n * const middleware = arcis();\n * app.use(middleware);\n * process.on('SIGTERM', () => middleware.close());\n */\nexport function arcis(options: ArcisOptions = {}): ArcisMiddlewareStack {\n const middlewares: RequestHandler[] = [];\n const cleanupFns: (() => void)[] = [];\n\n // Security headers (first, always)\n if (options.headers !== false) {\n const headerOpts: HeaderOptions = typeof options.headers === 'object' \n ? options.headers \n : {};\n middlewares.push(createHeaders(headerOpts));\n }\n\n // Rate limiting\n if (options.rateLimit !== false) {\n const rateLimitOpts: RateLimitOptions = typeof options.rateLimit === 'object' \n ? options.rateLimit \n : {};\n const rateLimiter = createRateLimiter(rateLimitOpts);\n middlewares.push(rateLimiter);\n cleanupFns.push(() => rateLimiter.close());\n }\n\n // Input sanitization (last, after body parsing)\n if (options.sanitize !== false) {\n const sanitizeOpts: SanitizeOptions = typeof options.sanitize === 'object' \n ? options.sanitize \n : {};\n middlewares.push(createSanitizer(sanitizeOpts));\n }\n\n // Attach close() directly on the array so callers can clean up without any-casts.\n const result = middlewares as ArcisMiddlewareStack;\n result.close = () => {\n for (const fn of cleanupFns) {\n fn();\n }\n };\n\n return result;\n}\n\n// Attach individual functions for granular use\nconst arcisWithMethods = arcis as ArcisFunction;\narcisWithMethods.sanitize = createSanitizer;\narcisWithMethods.rateLimit = createRateLimiter;\narcisWithMethods.headers = createHeaders;\narcisWithMethods.validate = validate;\narcisWithMethods.logger = createSafeLogger;\narcisWithMethods.errorHandler = createErrorHandler;\n\nexport { arcisWithMethods as arcisFunction };\nexport default arcisWithMethods;\n","/**\n * @module @arcis/node/utils/duration\n * Parse human-readable duration strings into milliseconds.\n *\n * Supports: ms, s, m, h, d\n *\n * @example\n * parseDuration('5m') // 300000\n * parseDuration('2h') // 7200000\n * parseDuration(60000) // 60000 (passthrough)\n * parseDuration('500ms') // 500\n */\n\n/** Maximum duration: ~49.7 days (uint32 max in ms) */\nconst MAX_DURATION_MS = 4_294_967_295;\n\nconst DURATION_REGEX = /^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/i;\n\nconst UNIT_TO_MS: Record<string, number> = {\n ms: 1,\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n};\n\n/**\n * Parse a duration string or number into milliseconds.\n *\n * @param value - Duration string (e.g. \"5m\", \"2h\", \"30s\") or number (ms)\n * @returns Duration in milliseconds\n * @throws {Error} If the value is not a valid duration\n *\n * @example\n * parseDuration('15m') // 900000\n * parseDuration('1d') // 86400000\n * parseDuration('500ms') // 500\n * parseDuration(60000) // 60000\n */\nexport function parseDuration(value: string | number): number {\n if (typeof value === 'number') {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`Invalid duration: ${value}. Must be a non-negative finite number.`);\n }\n return Math.min(Math.floor(value), MAX_DURATION_MS);\n }\n\n if (typeof value !== 'string' || value.trim() === '') {\n throw new Error(`Invalid duration: \"${value}\". Expected a duration string (e.g. \"5m\", \"2h\") or number.`);\n }\n\n const match = value.trim().match(DURATION_REGEX);\n if (!match) {\n throw new Error(\n `Invalid duration: \"${value}\". Expected format: <number><unit> where unit is ms, s, m, h, or d.`\n );\n }\n\n const amount = parseFloat(match[1]);\n const unit = match[2].toLowerCase();\n const ms = Math.floor(amount * UNIT_TO_MS[unit]);\n\n if (ms < 0 || ms > MAX_DURATION_MS) {\n throw new Error(`Duration \"${value}\" exceeds maximum allowed (${MAX_DURATION_MS}ms / ~49.7 days).`);\n }\n\n return ms;\n}\n\n/**\n * Format milliseconds into a human-readable duration string.\n *\n * @param ms - Duration in milliseconds\n * @returns Human-readable string (e.g. \"5m\", \"2h 30m\")\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '0ms';\n\n if (ms < 1000) return `${ms}ms`;\n\n const days = Math.floor(ms / 86_400_000);\n const hours = Math.floor((ms % 86_400_000) / 3_600_000);\n const minutes = Math.floor((ms % 3_600_000) / 60_000);\n const seconds = Math.floor((ms % 60_000) / 1_000);\n\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (seconds > 0) parts.push(`${seconds}s`);\n\n return parts.join(' ') || '0ms';\n}\n","/**\n * @module @arcis/node/middleware/rate-limit-sliding\n * Sliding window rate limiting middleware.\n *\n * More accurate than fixed window — uses a weighted sum of the previous\n * and current window to approximate a true sliding window.\n *\n * Algorithm:\n * weight = (windowMs - elapsed) / windowMs\n * count = (prevWindow * weight) + currentWindow\n * allow = count < limit\n *\n * @example\n * app.use(createSlidingWindowLimiter({ max: 100, window: '15m' }));\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { parseDuration } from '../utils/duration';\nimport { RATE_LIMIT } from '../core/constants';\n\nexport interface SlidingWindowOptions {\n /** Maximum requests per window. Default: 100 */\n max?: number;\n /** Window size in ms or duration string. Default: '1m' */\n window?: string | number;\n /** Error message when limit exceeded */\n message?: string;\n /** HTTP status code for rate limited responses. Default: 429 */\n statusCode?: number;\n /** Function to generate rate limit key from request */\n keyGenerator?: (req: Request) => string;\n /** Function to skip rate limiting for certain requests */\n skip?: (req: Request) => boolean;\n}\n\ninterface WindowEntry {\n count: number;\n startTime: number;\n}\n\nexport interface SlidingWindowMiddleware extends RequestHandler {\n close: () => void;\n}\n\n/**\n * Create sliding window rate limiter middleware.\n *\n * @example\n * // 100 requests per 15 minutes\n * app.use(createSlidingWindowLimiter({ max: 100, window: '15m' }));\n *\n * @example\n * // Strict API limit\n * app.use('/api', createSlidingWindowLimiter({ max: 30, window: '1m' }));\n */\nexport function createSlidingWindowLimiter(options: SlidingWindowOptions = {}): SlidingWindowMiddleware {\n const {\n max = RATE_LIMIT.DEFAULT_MAX_REQUESTS,\n window: windowOpt = RATE_LIMIT.DEFAULT_WINDOW_MS,\n message = RATE_LIMIT.DEFAULT_MESSAGE,\n statusCode = RATE_LIMIT.DEFAULT_STATUS_CODE,\n keyGenerator = (req) => req.ip ?? req.socket?.remoteAddress ?? 'unknown',\n skip,\n } = options;\n\n const windowMs = parseDuration(windowOpt);\n\n // Two windows per key: current and previous\n const currentWindows = Object.create(null) as Record<string, WindowEntry>;\n const previousWindows = Object.create(null) as Record<string, WindowEntry>;\n\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n const cutoff = now - windowMs * 2; // Keep 2 windows worth\n for (const key of Object.keys(previousWindows)) {\n if (previousWindows[key].startTime < cutoff) {\n delete previousWindows[key];\n }\n }\n for (const key of Object.keys(currentWindows)) {\n if (currentWindows[key].startTime < cutoff) {\n delete currentWindows[key];\n }\n }\n }, windowMs);\n\n if (typeof cleanupInterval.unref === 'function') {\n cleanupInterval.unref();\n }\n\n const handler: RequestHandler = (req: Request, res: Response, next: NextFunction) => {\n try {\n if (skip?.(req)) return next();\n\n const key = keyGenerator(req);\n const now = Date.now();\n\n // Determine current window boundaries\n const windowStart = Math.floor(now / windowMs) * windowMs;\n\n // Rotate windows if needed\n if (!currentWindows[key] || currentWindows[key].startTime < windowStart) {\n // Move current to previous\n if (currentWindows[key]) {\n previousWindows[key] = currentWindows[key];\n }\n currentWindows[key] = { count: 0, startTime: windowStart };\n }\n\n // Calculate weighted count BEFORE incrementing\n const elapsed = now - windowStart;\n const weight = Math.max(0, (windowMs - elapsed) / windowMs);\n const prevCount = previousWindows[key]?.count ?? 0;\n const estimatedCount = (prevCount * weight) + currentWindows[key].count + 1;\n\n const remaining = Math.max(0, Math.floor(max - estimatedCount));\n const resetMs = windowStart + windowMs - now;\n const resetSeconds = Math.max(1, Math.ceil(resetMs / 1000));\n\n // Set rate limit headers\n res.setHeader('X-RateLimit-Limit', max.toString());\n res.setHeader('X-RateLimit-Remaining', remaining.toString());\n res.setHeader('X-RateLimit-Reset', resetSeconds.toString());\n res.setHeader('X-RateLimit-Policy', `${max};w=${Math.floor(windowMs / 1000)}`);\n\n if (estimatedCount > max) {\n // Don't increment — rejected requests should not consume quota\n res.setHeader('Retry-After', resetSeconds.toString());\n res.status(statusCode).json({\n error: message,\n retryAfter: resetSeconds,\n });\n return;\n }\n\n // Only increment on allowed requests\n currentWindows[key].count++;\n\n next();\n } catch (error) {\n // Fail open\n console.error('[arcis] Sliding window rate limiter error:', error);\n next();\n }\n };\n\n const middleware = handler as SlidingWindowMiddleware;\n middleware.close = () => {\n clearInterval(cleanupInterval);\n };\n\n return middleware;\n}\n","/**\n * @module @arcis/node/middleware/rate-limit-token\n * Token bucket rate limiting middleware.\n *\n * Allows burst traffic while enforcing an average rate.\n * Tokens refill at a steady rate. Each request costs 1 token.\n *\n * Algorithm:\n * tokens = min(capacity, tokens + elapsed * refillRate)\n * if tokens >= cost: allow, subtract cost\n * else: deny\n *\n * @example\n * app.use(createTokenBucketLimiter({ capacity: 50, refillRate: 10 }));\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport { RATE_LIMIT } from '../core/constants';\n\nexport interface TokenBucketOptions {\n /** Maximum tokens (burst size). Default: 100 */\n capacity?: number;\n /** Tokens added per second. Default: 10 */\n refillRate?: number;\n /** Tokens consumed per request. Default: 1 */\n cost?: number;\n /** Error message when limit exceeded */\n message?: string;\n /** HTTP status code for rate limited responses. Default: 429 */\n statusCode?: number;\n /** Function to generate rate limit key from request */\n keyGenerator?: (req: Request) => string;\n /** Function to skip rate limiting for certain requests */\n skip?: (req: Request) => boolean;\n}\n\ninterface Bucket {\n tokens: number;\n lastRefill: number;\n}\n\nexport interface TokenBucketMiddleware extends RequestHandler {\n close: () => void;\n}\n\n/**\n * Create token bucket rate limiter middleware.\n *\n * @example\n * // Allow bursts of 50, sustained rate of 10/sec\n * app.use(createTokenBucketLimiter({ capacity: 50, refillRate: 10 }));\n *\n * @example\n * // Strict API: 5 requests burst, 1/sec sustained\n * app.use('/api/expensive', createTokenBucketLimiter({\n * capacity: 5,\n * refillRate: 1,\n * }));\n */\nexport function createTokenBucketLimiter(options: TokenBucketOptions = {}): TokenBucketMiddleware {\n const {\n capacity = 100,\n refillRate = 10,\n cost = 1,\n message = RATE_LIMIT.DEFAULT_MESSAGE,\n statusCode = RATE_LIMIT.DEFAULT_STATUS_CODE,\n keyGenerator = (req) => req.ip ?? req.socket?.remoteAddress ?? 'unknown',\n skip,\n } = options;\n\n if (capacity < 1) throw new RangeError(`Token bucket capacity must be >= 1, got ${capacity}`);\n if (refillRate <= 0) throw new RangeError(`Token bucket refillRate must be > 0, got ${refillRate}`);\n if (cost < 1) throw new RangeError(`Token bucket cost must be >= 1, got ${cost}`);\n if (cost > capacity) throw new RangeError(`Token bucket cost (${cost}) must be <= capacity (${capacity}), otherwise all requests are permanently denied`);\n\n const buckets = Object.create(null) as Record<string, Bucket>;\n\n // Cleanup stale buckets (full buckets that haven't been accessed)\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n const staleThreshold = (capacity / refillRate) * 1000 * 2; // 2x time to refill\n for (const key of Object.keys(buckets)) {\n if (now - buckets[key].lastRefill > staleThreshold) {\n delete buckets[key];\n }\n }\n }, 60_000);\n\n if (typeof cleanupInterval.unref === 'function') {\n cleanupInterval.unref();\n }\n\n function refillBucket(bucket: Bucket, now: number): void {\n const elapsed = (now - bucket.lastRefill) / 1000; // seconds\n const tokensToAdd = elapsed * refillRate;\n bucket.tokens = Math.min(capacity, bucket.tokens + tokensToAdd);\n bucket.lastRefill = now;\n }\n\n const handler: RequestHandler = (req: Request, res: Response, next: NextFunction) => {\n try {\n if (skip?.(req)) return next();\n\n const key = keyGenerator(req);\n const now = Date.now();\n\n // Get or create bucket\n if (!buckets[key]) {\n buckets[key] = { tokens: capacity, lastRefill: now };\n }\n\n const bucket = buckets[key];\n refillBucket(bucket, now);\n\n // Calculate retry-after (time until enough tokens are available)\n const retryAfterSec = bucket.tokens < cost\n ? Math.ceil((cost - bucket.tokens) / refillRate)\n : 0;\n\n // Set headers\n res.setHeader('X-RateLimit-Limit', capacity.toString());\n res.setHeader('X-RateLimit-Remaining', Math.floor(Math.max(0, bucket.tokens - cost)).toString());\n res.setHeader('X-RateLimit-Policy', `${capacity};w=${Math.floor(capacity / refillRate)};burst=${capacity}`);\n\n if (bucket.tokens < cost) {\n res.setHeader('Retry-After', retryAfterSec.toString());\n res.setHeader('X-RateLimit-Reset', retryAfterSec.toString());\n res.status(statusCode).json({\n error: message,\n retryAfter: retryAfterSec,\n });\n return;\n }\n\n // Consume token\n bucket.tokens -= cost;\n next();\n } catch (error) {\n // Fail open\n console.error('[arcis] Token bucket rate limiter error:', error);\n next();\n }\n };\n\n const middleware = handler as TokenBucketMiddleware;\n middleware.close = () => {\n clearInterval(cleanupInterval);\n };\n\n return middleware;\n}\n","/**\n * @module @arcis/node/middleware/cors\n * Safe CORS middleware with secure defaults\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n/** CORS configuration options */\nexport interface CorsOptions {\n /**\n * Allowed origins. Can be:\n * - A string: exact match (e.g., 'https://example.com')\n * - An array: whitelist of allowed origins\n * - A RegExp: pattern match (use with care)\n * - A function: custom validation `(origin) => boolean`\n * - `true`: reflect the request origin (DANGEROUS — only for dev)\n *\n * Default: none (no origin allowed). You must explicitly set this.\n */\n origin: string | string[] | RegExp | ((origin: string) => boolean) | true;\n\n /** Allowed HTTP methods. Default: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] */\n methods?: string[];\n\n /** Allowed headers. Default: ['Content-Type', 'Authorization'] */\n allowedHeaders?: string[];\n\n /** Headers exposed to the browser. Default: [] */\n exposedHeaders?: string[];\n\n /** Allow credentials (cookies, authorization headers). Default: false */\n credentials?: boolean;\n\n /** Preflight cache duration in seconds. Default: 600 (10 minutes) */\n maxAge?: number;\n\n /** Respond to preflight with 204 (no content). Default: true */\n preflightContinue?: boolean;\n}\n\nconst DEFAULT_METHODS = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'];\nconst DEFAULT_HEADERS = ['Content-Type', 'Authorization'];\nconst DEFAULT_MAX_AGE = 600;\n\n/**\n * Check if an origin is allowed by the configured policy.\n */\nfunction isOriginAllowed(\n requestOrigin: string,\n allowed: CorsOptions['origin']\n): boolean {\n // 'null' origin is always blocked — sent by sandboxed iframes, data: URIs, etc.\n if (requestOrigin === 'null') return false;\n\n if (allowed === true) return true;\n\n if (typeof allowed === 'string') {\n return requestOrigin === allowed;\n }\n\n if (Array.isArray(allowed)) {\n return allowed.includes(requestOrigin);\n }\n\n if (allowed instanceof RegExp) {\n return allowed.test(requestOrigin);\n }\n\n if (typeof allowed === 'function') {\n return allowed(requestOrigin);\n }\n\n return false;\n}\n\n/**\n * Create safe CORS middleware.\n *\n * Unlike permissive CORS libraries, this enforces secure defaults:\n * - No wildcard `*` when credentials are enabled\n * - `null` origin is always blocked\n * - `Vary: Origin` is always set for proper caching\n * - You must explicitly configure allowed origins\n *\n * @param options - CORS configuration\n * @returns Express middleware\n *\n * @example\n * // Allow a single origin\n * app.use(safeCors({ origin: 'https://myapp.com' }));\n *\n * @example\n * // Allow multiple origins with credentials\n * app.use(safeCors({\n * origin: ['https://myapp.com', 'https://admin.myapp.com'],\n * credentials: true,\n * }));\n *\n * @example\n * // Development: allow all (NOT for production)\n * app.use(safeCors({ origin: true }));\n */\nexport function safeCors(options: CorsOptions): RequestHandler {\n const {\n origin,\n methods = DEFAULT_METHODS,\n allowedHeaders = DEFAULT_HEADERS,\n exposedHeaders = [],\n credentials = false,\n maxAge = DEFAULT_MAX_AGE,\n preflightContinue = true,\n } = options;\n\n return (req: Request, res: Response, next: NextFunction) => {\n const requestOrigin = req.headers.origin;\n\n // Always set Vary: Origin for proper caching\n res.setHeader('Vary', 'Origin');\n\n // No origin header = same-origin request, skip CORS headers\n if (!requestOrigin) {\n return next();\n }\n\n const allowed = isOriginAllowed(requestOrigin, origin);\n\n if (!allowed) {\n // Don't set any CORS headers — browser will block the request\n return next();\n }\n\n // Set Access-Control-Allow-Origin to the specific origin (not *)\n res.setHeader('Access-Control-Allow-Origin', requestOrigin);\n\n if (credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n\n if (exposedHeaders.length > 0) {\n res.setHeader('Access-Control-Expose-Headers', exposedHeaders.join(', '));\n }\n\n // Handle preflight requests\n if (req.method === 'OPTIONS') {\n res.setHeader('Access-Control-Allow-Methods', methods.join(', '));\n res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));\n res.setHeader('Access-Control-Max-Age', String(maxAge));\n\n if (preflightContinue) {\n res.status(204).end();\n return;\n }\n }\n\n next();\n };\n}\n\n/**\n * Alias for safeCors\n * @see safeCors\n */\nexport const createCors = safeCors;\n","/**\n * @module @arcis/node/middleware/cookies\n * Secure cookie defaults middleware\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n/** Cookie security configuration */\nexport interface SecureCookieOptions {\n /** Force HttpOnly on all cookies. Default: true */\n httpOnly?: boolean;\n /** Force Secure flag (HTTPS only). Default: true in production, false in dev */\n secure?: boolean;\n /** SameSite attribute. Default: 'Lax' */\n sameSite?: 'Strict' | 'Lax' | 'None' | false;\n /** Override Path attribute. Default: undefined (keep original) */\n path?: string;\n}\n\nconst COOKIE_ATTRS = {\n HTTP_ONLY: '; HttpOnly',\n SECURE: '; Secure',\n SAME_SITE_STRICT: '; SameSite=Strict',\n SAME_SITE_LAX: '; SameSite=Lax',\n SAME_SITE_NONE: '; SameSite=None',\n} as const;\n\n/**\n * Enforce secure defaults on a Set-Cookie header value.\n */\nexport function enforceSecureCookie(\n cookieStr: string,\n options: Required<Omit<SecureCookieOptions, 'path'>> & { path?: string }\n): string {\n const lower = cookieStr.toLowerCase();\n let result = cookieStr;\n\n // HttpOnly — prevent JavaScript access\n if (options.httpOnly && !lower.includes('httponly')) {\n result += COOKIE_ATTRS.HTTP_ONLY;\n }\n\n // Secure — HTTPS only\n if (options.secure && !lower.includes('; secure')) {\n result += COOKIE_ATTRS.SECURE;\n }\n\n // SameSite — CSRF protection\n if (options.sameSite !== false && !lower.includes('samesite')) {\n switch (options.sameSite) {\n case 'Strict':\n result += COOKIE_ATTRS.SAME_SITE_STRICT;\n break;\n case 'None':\n result += COOKIE_ATTRS.SAME_SITE_NONE;\n // SameSite=None requires Secure\n if (!result.toLowerCase().includes('; secure')) {\n result += COOKIE_ATTRS.SECURE;\n }\n break;\n case 'Lax':\n default:\n result += COOKIE_ATTRS.SAME_SITE_LAX;\n break;\n }\n }\n\n // Override path if specified\n if (options.path) {\n if (lower.includes('path=')) {\n result = result.replace(/;\\s*path=[^;]*/i, `; Path=${options.path}`);\n } else {\n result += `; Path=${options.path}`;\n }\n }\n\n return result;\n}\n\n/**\n * Create middleware that enforces secure cookie defaults.\n *\n * Intercepts Set-Cookie headers and adds missing security attributes:\n * - HttpOnly: prevents JavaScript access (XSS cookie theft)\n * - Secure: cookies only sent over HTTPS\n * - SameSite: CSRF protection\n *\n * @param options - Cookie security configuration\n * @returns Express middleware\n *\n * @example\n * // Enforce defaults on all cookies\n * app.use(secureCookieDefaults());\n *\n * @example\n * // Strict SameSite for sensitive apps\n * app.use(secureCookieDefaults({ sameSite: 'Strict' }));\n */\nexport function secureCookieDefaults(options: SecureCookieOptions = {}): RequestHandler {\n const isProduction = process.env.NODE_ENV === 'production';\n const resolved = {\n httpOnly: options.httpOnly ?? true,\n secure: options.secure ?? isProduction,\n sameSite: options.sameSite ?? 'Lax' as const,\n path: options.path,\n };\n\n return (_req: Request, res: Response, next: NextFunction) => {\n // Monkey-patch res.setHeader to intercept Set-Cookie\n const originalSetHeader = res.setHeader.bind(res);\n\n res.setHeader = function patchedSetHeader(name: string, value: string | number | readonly string[]) {\n if (name.toLowerCase() === 'set-cookie') {\n if (Array.isArray(value)) {\n value = value.map(v => enforceSecureCookie(String(v), resolved));\n } else {\n value = enforceSecureCookie(String(value), resolved);\n }\n }\n return originalSetHeader(name, value);\n } as typeof res.setHeader;\n\n next();\n };\n}\n\n/**\n * Alias for secureCookieDefaults\n * @see secureCookieDefaults\n */\nexport const createSecureCookies = secureCookieDefaults;\n","/**\n * @module @arcis/node/middleware/bot-detection\n * Local-only bot detection using User-Agent and behavioral signals.\n *\n * Categorizes requests into bot types and allows/denies based on config.\n * No cloud calls — everything runs locally.\n *\n * @example\n * // Block automated tools, allow search engines\n * app.use(botProtection({\n * allow: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'],\n * deny: ['AUTOMATED', 'SCRAPER'],\n * }));\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n// =============================================================================\n// BOT CATEGORIES\n// =============================================================================\n\nexport type BotCategory =\n | 'SEARCH_ENGINE'\n | 'SOCIAL'\n | 'MONITORING'\n | 'AI_CRAWLER'\n | 'SCRAPER'\n | 'AUTOMATED'\n | 'UNKNOWN'\n | 'HUMAN';\n\nexport interface BotDetectionResult {\n /** Whether the request appears to be from a bot */\n isBot: boolean;\n /** Bot category */\n category: BotCategory;\n /** Matched bot name (e.g. 'Googlebot', 'curl') or null */\n name: string | null;\n /** Confidence score: 0-1 */\n confidence: number;\n /** Behavioral signals detected */\n signals: string[];\n}\n\nexport interface BotProtectionOptions {\n /** Categories to explicitly allow. Default: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'] */\n allow?: BotCategory[];\n /** Categories to explicitly deny. Default: ['AUTOMATED'] */\n deny?: BotCategory[];\n /** Action for categories not in allow or deny. Default: 'allow' */\n defaultAction?: 'allow' | 'deny';\n /** HTTP status code for denied bots. Default: 403 */\n statusCode?: number;\n /** Error message for denied bots */\n message?: string;\n /** Enable behavioral signal detection. Default: true */\n detectBehavior?: boolean;\n /** Custom handler called on detection (instead of default deny response) */\n onDetected?: (req: Request, res: Response, result: BotDetectionResult) => void;\n}\n\n// =============================================================================\n// BOT DATABASE\n// =============================================================================\n\ninterface BotPattern {\n /** Regex pattern to match against User-Agent */\n pattern: RegExp;\n /** Bot name */\n name: string;\n /** Category */\n category: BotCategory;\n}\n\n/**\n * Bot patterns ordered by specificity — more specific patterns first.\n * All patterns are case-insensitive and tested against the full UA string.\n */\nconst BOT_PATTERNS: BotPattern[] = [\n // --- SEARCH ENGINES (specific variants before generic) ---\n { pattern: /Googlebot-Image/i, name: 'Googlebot-Image', category: 'SEARCH_ENGINE' },\n { pattern: /Googlebot-Video/i, name: 'Googlebot-Video', category: 'SEARCH_ENGINE' },\n { pattern: /Googlebot-News/i, name: 'Googlebot-News', category: 'SEARCH_ENGINE' },\n { pattern: /Googlebot/i, name: 'Googlebot', category: 'SEARCH_ENGINE' },\n { pattern: /AdsBot-Google/i, name: 'AdsBot-Google', category: 'SEARCH_ENGINE' },\n { pattern: /Mediapartners-Google/i, name: 'Mediapartners-Google', category: 'SEARCH_ENGINE' },\n { pattern: /Bingbot/i, name: 'Bingbot', category: 'SEARCH_ENGINE' },\n { pattern: /msnbot/i, name: 'msnbot', category: 'SEARCH_ENGINE' },\n { pattern: /Slurp/i, name: 'Yahoo Slurp', category: 'SEARCH_ENGINE' },\n { pattern: /DuckDuckBot/i, name: 'DuckDuckBot', category: 'SEARCH_ENGINE' },\n { pattern: /Baiduspider/i, name: 'Baiduspider', category: 'SEARCH_ENGINE' },\n { pattern: /YandexBot/i, name: 'YandexBot', category: 'SEARCH_ENGINE' },\n { pattern: /YandexImages/i, name: 'YandexImages', category: 'SEARCH_ENGINE' },\n { pattern: /Sogou/i, name: 'Sogou', category: 'SEARCH_ENGINE' },\n { pattern: /Exabot/i, name: 'Exabot', category: 'SEARCH_ENGINE' },\n { pattern: /ia_archiver/i, name: 'Alexa', category: 'SEARCH_ENGINE' },\n { pattern: /Applebot/i, name: 'Applebot', category: 'SEARCH_ENGINE' },\n { pattern: /Qwantify/i, name: 'Qwantify', category: 'SEARCH_ENGINE' },\n { pattern: /PetalBot/i, name: 'PetalBot', category: 'SEARCH_ENGINE' },\n { pattern: /SeznamBot/i, name: 'SeznamBot', category: 'SEARCH_ENGINE' },\n\n // --- SOCIAL ---\n { pattern: /Twitterbot/i, name: 'Twitterbot', category: 'SOCIAL' },\n { pattern: /facebookexternalhit/i, name: 'Facebook', category: 'SOCIAL' },\n { pattern: /Facebot/i, name: 'Facebot', category: 'SOCIAL' },\n { pattern: /LinkedInBot/i, name: 'LinkedInBot', category: 'SOCIAL' },\n { pattern: /Pinterest/i, name: 'Pinterest', category: 'SOCIAL' },\n { pattern: /Slackbot/i, name: 'Slackbot', category: 'SOCIAL' },\n { pattern: /TelegramBot/i, name: 'TelegramBot', category: 'SOCIAL' },\n { pattern: /WhatsApp/i, name: 'WhatsApp', category: 'SOCIAL' },\n { pattern: /Discordbot/i, name: 'Discordbot', category: 'SOCIAL' },\n { pattern: /Redditbot/i, name: 'Redditbot', category: 'SOCIAL' },\n { pattern: /Embedly/i, name: 'Embedly', category: 'SOCIAL' },\n { pattern: /Quora Link Preview/i, name: 'Quora', category: 'SOCIAL' },\n { pattern: /Mastodon/i, name: 'Mastodon', category: 'SOCIAL' },\n\n // --- MONITORING ---\n { pattern: /UptimeRobot/i, name: 'UptimeRobot', category: 'MONITORING' },\n { pattern: /Pingdom/i, name: 'Pingdom', category: 'MONITORING' },\n { pattern: /Site24x7/i, name: 'Site24x7', category: 'MONITORING' },\n { pattern: /StatusCake/i, name: 'StatusCake', category: 'MONITORING' },\n { pattern: /Datadog/i, name: 'Datadog', category: 'MONITORING' },\n { pattern: /NewRelicPinger/i, name: 'New Relic', category: 'MONITORING' },\n { pattern: /Better Uptime Bot/i, name: 'Better Uptime', category: 'MONITORING' },\n { pattern: /GTmetrix/i, name: 'GTmetrix', category: 'MONITORING' },\n { pattern: /PageSpeed/i, name: 'PageSpeed Insights', category: 'MONITORING' },\n\n // --- AI CRAWLERS ---\n { pattern: /GPTBot/i, name: 'GPTBot', category: 'AI_CRAWLER' },\n { pattern: /ChatGPT-User/i, name: 'ChatGPT-User', category: 'AI_CRAWLER' },\n { pattern: /Claude-Web/i, name: 'Claude-Web', category: 'AI_CRAWLER' },\n { pattern: /ClaudeBot/i, name: 'ClaudeBot', category: 'AI_CRAWLER' },\n { pattern: /anthropic-ai/i, name: 'Anthropic', category: 'AI_CRAWLER' },\n { pattern: /Bytespider/i, name: 'Bytespider', category: 'AI_CRAWLER' },\n { pattern: /CCBot/i, name: 'CCBot', category: 'AI_CRAWLER' },\n { pattern: /cohere-ai/i, name: 'Cohere', category: 'AI_CRAWLER' },\n { pattern: /PerplexityBot/i, name: 'PerplexityBot', category: 'AI_CRAWLER' },\n { pattern: /YouBot/i, name: 'YouBot', category: 'AI_CRAWLER' },\n { pattern: /Google-Extended/i, name: 'Google-Extended', category: 'AI_CRAWLER' },\n { pattern: /Diffbot/i, name: 'Diffbot', category: 'AI_CRAWLER' },\n { pattern: /Amazonbot/i, name: 'Amazonbot', category: 'AI_CRAWLER' },\n { pattern: /meta-externalagent/i, name: 'Meta AI', category: 'AI_CRAWLER' },\n\n // --- AUTOMATED TOOLS (headless browsers, testing frameworks) ---\n { pattern: /HeadlessChrome/i, name: 'Headless Chrome', category: 'AUTOMATED' },\n { pattern: /PhantomJS/i, name: 'PhantomJS', category: 'AUTOMATED' },\n { pattern: /Selenium/i, name: 'Selenium', category: 'AUTOMATED' },\n { pattern: /Puppeteer/i, name: 'Puppeteer', category: 'AUTOMATED' },\n { pattern: /Playwright/i, name: 'Playwright', category: 'AUTOMATED' },\n { pattern: /Cypress/i, name: 'Cypress', category: 'AUTOMATED' },\n { pattern: /webdriver/i, name: 'WebDriver', category: 'AUTOMATED' },\n { pattern: /MSIE 6\\.0/i, name: 'Fake IE6', category: 'AUTOMATED' },\n\n // --- SCRAPERS / CLI TOOLS ---\n { pattern: /^curl\\//i, name: 'curl', category: 'SCRAPER' },\n { pattern: /^wget\\//i, name: 'wget', category: 'SCRAPER' },\n { pattern: /^python-requests\\//i, name: 'python-requests', category: 'SCRAPER' },\n { pattern: /^python-httpx\\//i, name: 'python-httpx', category: 'SCRAPER' },\n { pattern: /^Python-urllib/i, name: 'Python-urllib', category: 'SCRAPER' },\n { pattern: /^aiohttp\\//i, name: 'aiohttp', category: 'SCRAPER' },\n { pattern: /^Go-http-client/i, name: 'Go-http-client', category: 'SCRAPER' },\n { pattern: /^Java\\//i, name: 'Java HttpClient', category: 'SCRAPER' },\n { pattern: /^Apache-HttpClient/i, name: 'Apache HttpClient', category: 'SCRAPER' },\n { pattern: /^okhttp\\//i, name: 'OkHttp', category: 'SCRAPER' },\n { pattern: /^node-fetch\\//i, name: 'node-fetch', category: 'SCRAPER' },\n { pattern: /^axios\\//i, name: 'axios', category: 'SCRAPER' },\n { pattern: /^got\\//i, name: 'got', category: 'SCRAPER' },\n { pattern: /^libwww-perl/i, name: 'libwww-perl', category: 'SCRAPER' },\n { pattern: /^Ruby/i, name: 'Ruby', category: 'SCRAPER' },\n { pattern: /^PHP\\//i, name: 'PHP', category: 'SCRAPER' },\n { pattern: /Scrapy/i, name: 'Scrapy', category: 'SCRAPER' },\n { pattern: /^Postman/i, name: 'Postman', category: 'SCRAPER' },\n { pattern: /^Insomnia/i, name: 'Insomnia', category: 'SCRAPER' },\n { pattern: /^HTTPie\\//i, name: 'HTTPie', category: 'SCRAPER' },\n];\n\n// =============================================================================\n// DETECTION ENGINE\n// =============================================================================\n\n/**\n * Detect behavioral signals that suggest a bot.\n */\nfunction detectBehavioralSignals(req: Request): string[] {\n const signals: string[] = [];\n const headers = req.headers;\n\n // Missing User-Agent\n if (!headers['user-agent']) {\n signals.push('missing_user_agent');\n }\n\n // Missing Accept header (browsers always send this)\n if (!headers['accept']) {\n signals.push('missing_accept');\n }\n\n // Missing Accept-Language (browsers always send this)\n if (!headers['accept-language']) {\n signals.push('missing_accept_language');\n }\n\n // Missing Accept-Encoding (browsers always send this)\n if (!headers['accept-encoding']) {\n signals.push('missing_accept_encoding');\n }\n\n // Connection: close (browsers typically use keep-alive)\n if (headers['connection'] === 'close') {\n signals.push('connection_close');\n }\n\n return signals;\n}\n\n/**\n * Detect what kind of bot (if any) is making the request.\n *\n * @param req - HTTP request object\n * @returns Detection result with category, name, confidence, and signals\n *\n * @example\n * const result = detectBot(req);\n * if (result.isBot && result.category === 'AUTOMATED') {\n * // Block automated tools\n * }\n */\nexport function detectBot(req: Request): BotDetectionResult {\n const rawUa = req.headers['user-agent'] ?? '';\n // Truncate to prevent CPU abuse from very long UA strings\n const ua = rawUa.length > 2048 ? rawUa.slice(0, 2048) : rawUa;\n const signals = detectBehavioralSignals(req);\n\n // No User-Agent at all\n if (!ua) {\n return {\n isBot: true,\n category: 'UNKNOWN',\n name: null,\n confidence: 0.8,\n signals,\n };\n }\n\n // Match against known bot patterns\n for (const bot of BOT_PATTERNS) {\n if (bot.pattern.test(ua)) {\n return {\n isBot: true,\n category: bot.category,\n name: bot.name,\n confidence: 0.95,\n signals,\n };\n }\n }\n\n // Behavioral analysis for unrecognized UAs\n const behaviorScore = signals.length;\n\n // 3+ missing standard headers = likely bot\n if (behaviorScore >= 3) {\n return {\n isBot: true,\n category: 'UNKNOWN',\n name: null,\n confidence: Math.min(1.0, 0.6 + (behaviorScore * 0.1)),\n signals,\n };\n }\n\n return {\n isBot: false,\n category: 'HUMAN',\n name: null,\n confidence: Math.max(0.0, 1.0 - (behaviorScore * 0.15)),\n signals,\n };\n}\n\n/**\n * Create Express middleware for bot protection.\n *\n * @example\n * // Block automated tools and scrapers\n * app.use(botProtection({\n * allow: ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'],\n * deny: ['AUTOMATED', 'SCRAPER'],\n * }));\n *\n * @example\n * // Block everything except search engines\n * app.use(botProtection({\n * allow: ['SEARCH_ENGINE'],\n * defaultAction: 'deny',\n * }));\n *\n * @example\n * // Custom handler\n * app.use(botProtection({\n * deny: ['AUTOMATED'],\n * onDetected: (req, res, result) => {\n * console.log(`Bot blocked: ${result.name} (${result.category})`);\n * res.status(403).json({ error: 'Bots not allowed' });\n * },\n * }));\n */\nexport function botProtection(options: BotProtectionOptions = {}): RequestHandler {\n const {\n allow = ['SEARCH_ENGINE', 'SOCIAL', 'MONITORING'],\n deny = ['AUTOMATED'],\n defaultAction = 'allow',\n statusCode = 403,\n message = 'Access denied.',\n onDetected,\n } = options;\n\n const allowSet = new Set(allow);\n const denySet = new Set(deny);\n\n return (req: Request, res: Response, next: NextFunction) => {\n const result = detectBot(req);\n\n // Attach result to request for downstream use\n (req as unknown as Record<string, unknown>).botDetection = result;\n\n // Humans always pass\n if (!result.isBot) {\n return next();\n }\n\n // Check explicit allow/deny lists\n if (allowSet.has(result.category)) {\n return next();\n }\n\n if (denySet.has(result.category)) {\n if (onDetected) {\n return onDetected(req, res, result);\n }\n res.status(statusCode).json({ error: message });\n return;\n }\n\n // Default action for uncategorized bots\n if (defaultAction === 'deny') {\n if (onDetected) {\n return onDetected(req, res, result);\n }\n res.status(statusCode).json({ error: message });\n return;\n }\n\n next();\n };\n}\n","/**\n * @module @arcis/node/middleware/csrf\n * CSRF (Cross-Site Request Forgery) protection middleware\n *\n * Implements the double-submit cookie pattern:\n * 1. Server sets a CSRF token in a cookie\n * 2. Client must send the same token in a header or form field\n * 3. Middleware rejects requests where cookie token !== header/field token\n *\n * This works because an attacker's cross-origin form submission will include\n * the cookie automatically, but cannot read it (same-origin policy) to set\n * the matching header.\n */\n\nimport { randomBytes } from 'crypto';\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n/** CSRF protection configuration */\nexport interface CsrfOptions {\n /** Cookie name for the CSRF token. Default: '_csrf' */\n cookieName?: string;\n /** Header name to check for the token. Default: 'x-csrf-token' */\n headerName?: string;\n /** Form field name to check for the token. Default: '_csrf' */\n fieldName?: string;\n /** Token byte length (hex-encoded = 2x chars). Default: 32 */\n tokenLength?: number;\n /** HTTP methods to protect. Default: ['POST', 'PUT', 'PATCH', 'DELETE'] */\n protectedMethods?: string[];\n /** Paths to exclude from CSRF checks (e.g., webhook endpoints) */\n excludePaths?: string[];\n /** Cookie options */\n cookie?: {\n /** Cookie path. Default: '/' */\n path?: string;\n /** HttpOnly — set false so client JS can read it for headers. Default: false */\n httpOnly?: boolean;\n /** Secure flag (HTTPS only). Default: true in production */\n secure?: boolean;\n /** SameSite attribute. Default: 'Lax' */\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Cookie domain */\n domain?: string;\n };\n /** Custom error handler when CSRF validation fails */\n onError?: (req: Request, res: Response, next: NextFunction) => void;\n}\n\nconst DEFAULTS = {\n cookieName: '_csrf',\n headerName: 'x-csrf-token',\n fieldName: '_csrf',\n tokenLength: 32,\n protectedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],\n} as const;\n\n/**\n * Generate a cryptographically random CSRF token.\n *\n * @param length - Byte length (output is hex, so 2x chars). Default: 32\n * @returns Hex-encoded random token\n *\n * @example\n * const token = generateCsrfToken(); // 64 hex chars\n */\nexport function generateCsrfToken(length: number = 32): string {\n return randomBytes(length).toString('hex');\n}\n\n/**\n * Validate that two CSRF tokens match using constant-time comparison.\n *\n * @param cookieToken - Token from the cookie\n * @param requestToken - Token from the header or form field\n * @returns true if tokens match\n */\nexport function validateCsrfToken(cookieToken: string, requestToken: string): boolean {\n if (!cookieToken || !requestToken) return false;\n if (cookieToken.length !== requestToken.length) return false;\n\n // Constant-time comparison to prevent timing attacks\n let result = 0;\n for (let i = 0; i < cookieToken.length; i++) {\n result |= cookieToken.charCodeAt(i) ^ requestToken.charCodeAt(i);\n }\n return result === 0;\n}\n\n/**\n * Extract the CSRF token from a request (checks header, then body field, then query).\n */\nfunction getRequestToken(req: Request, headerName: string, fieldName: string): string | undefined {\n // 1. Check header (most common for SPAs)\n const headerToken = req.headers[headerName.toLowerCase()];\n if (typeof headerToken === 'string' && headerToken) return headerToken;\n\n // 2. Check body field (form submissions)\n if (req.body && typeof req.body === 'object' && fieldName in req.body) {\n const bodyToken = req.body[fieldName];\n if (typeof bodyToken === 'string' && bodyToken) return bodyToken;\n }\n\n // 3. Check query string (fallback)\n if (req.query && fieldName in req.query) {\n const queryToken = req.query[fieldName];\n if (typeof queryToken === 'string' && queryToken) return queryToken;\n }\n\n return undefined;\n}\n\n/**\n * Create CSRF protection middleware using double-submit cookie pattern.\n *\n * For safe methods (GET, HEAD, OPTIONS), sets a CSRF token cookie if not present.\n * For unsafe methods (POST, PUT, PATCH, DELETE), validates the token.\n *\n * @param options - CSRF configuration\n * @returns Express middleware\n *\n * @example\n * // Basic usage\n * app.use(csrfProtection());\n *\n * @example\n * // Exclude webhook paths\n * app.use(csrfProtection({\n * excludePaths: ['/api/webhooks/stripe', '/api/webhooks/github']\n * }));\n *\n * @example\n * // Client-side: read cookie + set header\n * const token = document.cookie.match(/_csrf=([^;]+)/)?.[1];\n * fetch('/api/data', {\n * method: 'POST',\n * headers: { 'X-CSRF-Token': token },\n * credentials: 'same-origin'\n * });\n */\nexport function csrfProtection(options: CsrfOptions = {}): RequestHandler {\n const cookieName = options.cookieName ?? DEFAULTS.cookieName;\n const headerName = options.headerName ?? DEFAULTS.headerName;\n const fieldName = options.fieldName ?? DEFAULTS.fieldName;\n const tokenLength = options.tokenLength ?? DEFAULTS.tokenLength;\n const protectedMethods = options.protectedMethods ?? [...DEFAULTS.protectedMethods];\n const excludePaths = options.excludePaths ?? [];\n\n const isProduction = process.env.NODE_ENV === 'production';\n const cookieOpts = {\n path: options.cookie?.path ?? '/',\n httpOnly: options.cookie?.httpOnly ?? false, // Must be readable by client JS\n secure: options.cookie?.secure ?? isProduction,\n sameSite: options.cookie?.sameSite ?? 'Lax',\n domain: options.cookie?.domain,\n };\n\n const defaultOnError = (_req: Request, res: Response, _next: NextFunction) => {\n res.status(403).json({\n error: 'CSRF token validation failed',\n message: 'Invalid or missing CSRF token. Include the token from the cookie in the X-CSRF-Token header.',\n });\n };\n\n const onError = options.onError ?? defaultOnError;\n\n // Normalize protected methods to uppercase\n const protectedSet = new Set(protectedMethods.map(m => m.toUpperCase()));\n\n return (req: Request, res: Response, next: NextFunction) => {\n const method = req.method.toUpperCase();\n\n // Check if path is excluded\n const requestPath = req.path || req.url;\n if (excludePaths.some(p => requestPath === p || requestPath.startsWith(p + '/'))) {\n return next();\n }\n\n // Expose token generation on the request for templates/views\n (req as unknown as Record<string, unknown>).csrfToken = () => {\n const existing = getCookieValue(req, cookieName);\n if (existing) return existing;\n\n const token = generateCsrfToken(tokenLength);\n setCsrfCookie(res, cookieName, token, cookieOpts);\n return token;\n };\n\n // For safe methods — ensure a CSRF cookie exists\n if (!protectedSet.has(method)) {\n const existing = getCookieValue(req, cookieName);\n if (!existing) {\n const token = generateCsrfToken(tokenLength);\n setCsrfCookie(res, cookieName, token, cookieOpts);\n }\n return next();\n }\n\n // For protected methods — validate the token\n const cookieToken = getCookieValue(req, cookieName);\n if (!cookieToken) {\n return onError(req, res, next);\n }\n\n const requestToken = getRequestToken(req, headerName, fieldName);\n if (!requestToken) {\n return onError(req, res, next);\n }\n\n if (!validateCsrfToken(cookieToken, requestToken)) {\n return onError(req, res, next);\n }\n\n next();\n };\n}\n\n/**\n * Read a cookie value from the request.\n */\nfunction getCookieValue(req: Request, name: string): string | undefined {\n // Express parses cookies if cookie-parser is used\n if (req.cookies && typeof req.cookies === 'object' && name in req.cookies) {\n return req.cookies[name];\n }\n\n // Fallback: parse from raw Cookie header\n const cookieHeader = req.headers.cookie;\n if (!cookieHeader) return undefined;\n\n const match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${escapeRegex(name)}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : undefined;\n}\n\n/**\n * Set the CSRF token cookie on the response.\n */\nfunction setCsrfCookie(\n res: Response,\n name: string,\n token: string,\n opts: { path: string; httpOnly: boolean; secure: boolean; sameSite: string; domain?: string }\n): void {\n const parts = [`${name}=${token}`];\n parts.push(`Path=${opts.path}`);\n if (opts.httpOnly) parts.push('HttpOnly');\n if (opts.secure) parts.push('Secure');\n parts.push(`SameSite=${opts.sameSite}`);\n if (opts.domain) parts.push(`Domain=${opts.domain}`);\n\n res.setHeader('Set-Cookie', parts.join('; '));\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Alias for csrfProtection */\nexport const createCsrf = csrfProtection;\n","/**\n * @module @arcis/node/utils/ip\n * Platform-aware client IP detection.\n *\n * Prevents IP spoofing by reading platform-specific headers\n * instead of blindly trusting X-Forwarded-For.\n *\n * @example\n * // Auto-detect platform from environment\n * const ip = detectClientIp(req);\n *\n * // Explicit platform\n * const ip = detectClientIp(req, { platform: 'cloudflare' });\n */\n\nimport type { IncomingMessage } from 'http';\n\nexport type Platform =\n | 'auto'\n | 'cloudflare'\n | 'vercel'\n | 'flyio'\n | 'render'\n | 'firebase'\n | 'aws-alb'\n | 'generic';\n\nexport interface DetectIpOptions {\n /** Platform to use for header selection. Default: 'auto' */\n platform?: Platform;\n /** Number of trusted proxies (for X-Forwarded-For parsing). Default: 1 */\n trustedProxyCount?: number;\n}\n\ninterface RequestLike {\n headers: Record<string, string | string[] | undefined>;\n socket?: { remoteAddress?: string };\n connection?: { remoteAddress?: string };\n ip?: string;\n}\n\n/**\n * Platform-specific header configurations.\n * Each platform sets a trusted header that cannot be spoofed by the client.\n */\nconst PLATFORM_HEADERS: Record<Exclude<Platform, 'auto' | 'generic'>, string> = {\n cloudflare: 'cf-connecting-ip',\n vercel: 'x-real-ip',\n flyio: 'fly-client-ip',\n render: 'x-render-client-ip',\n firebase: 'x-appengine-user-ip',\n 'aws-alb': 'x-forwarded-for',\n};\n\n/**\n * Auto-detect the platform from environment variables.\n */\nfunction detectPlatform(): Platform {\n const env = typeof process !== 'undefined' ? process.env : {};\n\n if (env.CF_PAGES || env.CF_WORKERS) return 'cloudflare';\n if (env.VERCEL) return 'vercel';\n if (env.FLY_APP_NAME) return 'flyio';\n if (env.RENDER) return 'render';\n if (env.FIREBASE_CONFIG || env.GCLOUD_PROJECT) return 'firebase';\n if (env.AWS_EXECUTION_ENV || env.AWS_LAMBDA_FUNCTION_NAME) return 'aws-alb';\n\n return 'generic';\n}\n\n// Cache the detected platform — it won't change during process lifetime\nlet _cachedPlatform: Platform | null = null;\n\nfunction getCachedPlatform(): Platform {\n if (_cachedPlatform === null) {\n _cachedPlatform = detectPlatform();\n }\n return _cachedPlatform;\n}\n\n/** Max IP string length (IPv6 max = 45 chars) */\nconst MAX_IP_LENGTH = 45;\n\n/**\n * Sanitize an IP string: trim, truncate, strip control characters.\n * Prevents unbounded strings from being used as map keys.\n */\nfunction sanitizeIp(ip: string): string {\n const trimmed = ip.trim();\n if (trimmed.length > MAX_IP_LENGTH) return trimmed.slice(0, MAX_IP_LENGTH);\n return trimmed;\n}\n\n/**\n * Get a header value from the request, handling string arrays.\n */\nfunction getHeader(req: RequestLike, name: string): string | undefined {\n const val = req.headers[name];\n if (Array.isArray(val)) return val[0];\n return val;\n}\n\n/**\n * Parse the rightmost trusted IP from X-Forwarded-For.\n * Reading from the right prevents client spoofing — the rightmost entry\n * is the one added by the closest trusted proxy.\n */\nfunction parseForwardedFor(header: string, trustedProxyCount: number): string | undefined {\n const ips = header.split(',').map(ip => ip.trim()).filter(Boolean);\n if (ips.length === 0) return undefined;\n\n // The client IP is at position (length - trustedProxyCount)\n const clientIndex = Math.max(0, ips.length - trustedProxyCount);\n return ips[clientIndex] || undefined;\n}\n\n/**\n * Detect the real client IP address from a request.\n *\n * Uses platform-specific headers when available to prevent IP spoofing.\n * Falls back to X-Forwarded-For (parsed from the right) and then\n * the socket remote address.\n *\n * @param req - HTTP request object (Express, raw http, etc.)\n * @param options - Detection options\n * @returns Client IP address, or 'unknown' if unresolvable\n *\n * @example\n * // Auto-detect platform\n * app.use((req, res, next) => {\n * const clientIp = detectClientIp(req);\n * console.log('Client IP:', clientIp);\n * next();\n * });\n *\n * @example\n * // Behind Cloudflare\n * const ip = detectClientIp(req, { platform: 'cloudflare' });\n *\n * @example\n * // Behind 2 proxies (e.g. CDN + load balancer)\n * const ip = detectClientIp(req, { trustedProxyCount: 2 });\n */\nexport function detectClientIp(\n req: RequestLike | IncomingMessage,\n options: DetectIpOptions = {}\n): string {\n const { platform = 'auto', trustedProxyCount = 1 } = options;\n const r = req as RequestLike;\n\n const resolvedPlatform = platform === 'auto' ? getCachedPlatform() : platform;\n\n // 1. Try platform-specific header (most trusted)\n if (resolvedPlatform !== 'generic' && resolvedPlatform in PLATFORM_HEADERS) {\n const headerName = PLATFORM_HEADERS[resolvedPlatform as keyof typeof PLATFORM_HEADERS];\n if (headerName) {\n if (resolvedPlatform === 'aws-alb') {\n // AWS ALB: parse X-Forwarded-For from the right\n const xff = getHeader(r, 'x-forwarded-for');\n if (xff) {\n const ip = parseForwardedFor(xff, trustedProxyCount);\n if (ip) return sanitizeIp(ip);\n }\n } else {\n const ip = getHeader(r, headerName);\n if (ip) return sanitizeIp(ip);\n }\n }\n }\n\n // 2. Try Express req.ip (respects trust proxy setting)\n if (r.ip) return sanitizeIp(r.ip);\n\n // 3. Try X-Forwarded-For (parsed from the right for safety)\n const xff = getHeader(r, 'x-forwarded-for');\n if (xff) {\n const ip = parseForwardedFor(xff, trustedProxyCount);\n if (ip) return sanitizeIp(ip);\n }\n\n // 4. Try X-Real-IP\n const realIp = getHeader(r, 'x-real-ip');\n if (realIp) return sanitizeIp(realIp);\n\n // 5. Socket remote address\n const socketIp = r.socket?.remoteAddress ?? r.connection?.remoteAddress;\n if (socketIp) return sanitizeIp(socketIp);\n\n return 'unknown';\n}\n\n/**\n * Check if an IP address is a private/internal address.\n *\n * Detects: loopback, private ranges (RFC 1918), link-local, IPv6 equivalents.\n */\nexport function isPrivateIp(ip: string): boolean {\n // Strip IPv4-mapped IPv6 prefix (::ffff:127.0.0.1 -> 127.0.0.1)\n const normalized = ip.startsWith('::ffff:') ? ip.slice(7) : ip;\n\n // IPv4 private ranges\n if (/^127\\./.test(normalized)) return true; // Loopback\n if (/^10\\./.test(normalized)) return true; // Class A private\n if (/^172\\.(1[6-9]|2\\d|3[01])\\./.test(normalized)) return true; // Class B private\n if (/^192\\.168\\./.test(normalized)) return true; // Class C private\n if (/^169\\.254\\./.test(normalized)) return true; // Link-local\n if (/^0\\./.test(normalized)) return true; // Current network\n\n // IPv6\n if (ip === '::1') return true; // Loopback\n if (/^fe80:/i.test(ip)) return true; // Link-local\n if (/^fc00:/i.test(ip)) return true; // Unique local\n if (/^fd/i.test(ip)) return true; // Unique local\n\n return false;\n}\n\n/** Reset cached platform (for testing). */\nexport function _resetPlatformCache(): void {\n _cachedPlatform = null;\n}\n","/**\n * @module @arcis/node/utils/fingerprint\n * Deterministic request fingerprinting via SHA-256.\n *\n * Generates a stable hash from request characteristics for\n * rate limiting keys, abuse detection, and analytics.\n *\n * @example\n * const fp = await fingerprint(req);\n * // \"a3f2b8c1d4e5...\"\n */\n\nimport { createHash } from 'crypto';\nimport { detectClientIp } from './ip';\nimport type { DetectIpOptions } from './ip';\n\nexport interface FingerprintOptions {\n /** Include IP address in fingerprint. Default: true */\n ip?: boolean;\n /** Include User-Agent header. Default: true */\n userAgent?: boolean;\n /** Include Accept header. Default: true */\n accept?: boolean;\n /** Include Accept-Language header. Default: true */\n acceptLanguage?: boolean;\n /** Include Accept-Encoding header. Default: true */\n acceptEncoding?: boolean;\n /** Additional custom components to include */\n custom?: string[];\n /** IP detection options */\n ipOptions?: DetectIpOptions;\n}\n\ninterface RequestLike {\n headers: Record<string, string | string[] | undefined>;\n socket?: { remoteAddress?: string };\n connection?: { remoteAddress?: string };\n ip?: string;\n}\n\nfunction getHeader(req: RequestLike, name: string): string {\n const val = req.headers[name];\n if (Array.isArray(val)) return val[0] ?? '';\n return val ?? '';\n}\n\n/**\n * Generate a deterministic fingerprint for a request.\n *\n * Creates a SHA-256 hash from configurable request components.\n * The fingerprint is stable across requests from the same client\n * (same IP, browser, language settings).\n *\n * @param req - HTTP request object\n * @param options - Fingerprint configuration\n * @returns Hex-encoded SHA-256 hash (64 characters)\n *\n * @example\n * // Default fingerprint (IP + UA + Accept headers)\n * const fp = fingerprint(req);\n *\n * @example\n * // IP-only fingerprint (for simple rate limiting)\n * const fp = fingerprint(req, { userAgent: false, accept: false, acceptLanguage: false, acceptEncoding: false });\n *\n * @example\n * // With custom components\n * const fp = fingerprint(req, { custom: [req.body?.userId] });\n */\nexport function fingerprint(req: RequestLike, options: FingerprintOptions = {}): string {\n const {\n ip = true,\n userAgent = true,\n accept = true,\n acceptLanguage = true,\n acceptEncoding = true,\n custom = [],\n ipOptions,\n } = options;\n\n const components: string[] = [];\n\n if (ip) {\n components.push(`ip:${detectClientIp(req, ipOptions)}`);\n }\n if (userAgent) {\n components.push(`ua:${getHeader(req, 'user-agent')}`);\n }\n if (accept) {\n components.push(`accept:${getHeader(req, 'accept')}`);\n }\n if (acceptLanguage) {\n components.push(`lang:${getHeader(req, 'accept-language')}`);\n }\n if (acceptEncoding) {\n components.push(`enc:${getHeader(req, 'accept-encoding')}`);\n }\n\n for (const c of custom) {\n if (c != null) components.push(`custom:${c}`);\n }\n\n // Sort for deterministic ordering\n components.sort();\n\n const hash = createHash('sha256');\n hash.update(components.join('|'));\n return hash.digest('hex');\n}\n","/**\n * @module @arcis/node/stores/memory\n * In-memory rate limit store\n */\n\nimport type { RateLimitStore, RateLimitEntry } from '../core/types';\nimport { RATE_LIMIT } from '../core/constants';\n\n/**\n * In-memory rate limit store.\n * Suitable for single-instance deployments.\n * For distributed systems, use RedisStore or a custom store.\n * \n * @example\n * const store = new MemoryStore(60000); // 1 minute window\n * const limiter = createRateLimiter({ store });\n */\nexport class MemoryStore implements RateLimitStore {\n private store: Map<string, RateLimitEntry> = new Map();\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private windowMs: number;\n\n constructor(windowMs: number = RATE_LIMIT.DEFAULT_WINDOW_MS) {\n if (!Number.isFinite(windowMs) || windowMs < RATE_LIMIT.MIN_WINDOW_MS) {\n throw new RangeError(\n `MemoryStore: windowMs must be a finite number >= ${RATE_LIMIT.MIN_WINDOW_MS} (got ${windowMs})`\n );\n }\n this.windowMs = windowMs;\n this.startCleanup();\n }\n\n /**\n * Start the cleanup interval to remove expired entries.\n */\n private startCleanup(): void {\n // Clamp the cleanup interval between 30 s and 5 min regardless of windowMs.\n // Running it every windowMs is fine for typical windows but would fire every\n // second for short windows (e.g. windowMs: 1000), causing O(n) GC pressure.\n const CLEANUP_MIN_MS = 30_000;\n const CLEANUP_MAX_MS = 300_000;\n const cleanupMs = Math.min(Math.max(this.windowMs, CLEANUP_MIN_MS), CLEANUP_MAX_MS);\n\n this.cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.store.entries()) {\n if (entry.resetTime < now) {\n this.store.delete(key);\n }\n }\n }, cleanupMs);\n\n // Prevent interval from keeping the process alive\n if (typeof this.cleanupInterval.unref === 'function') {\n this.cleanupInterval.unref();\n }\n }\n\n async get(key: string): Promise<RateLimitEntry | null> {\n const entry = this.store.get(key);\n if (!entry) return null;\n \n // Check if expired\n if (entry.resetTime < Date.now()) {\n this.store.delete(key);\n return null;\n }\n \n return entry;\n }\n\n async set(key: string, entry: RateLimitEntry): Promise<void> {\n this.store.set(key, entry);\n }\n\n async increment(key: string): Promise<number> {\n const now = Date.now();\n const entry = this.store.get(key);\n \n if (!entry || entry.resetTime < now) {\n // Start new window\n this.store.set(key, { count: 1, resetTime: now + this.windowMs });\n return 1;\n }\n \n entry.count++;\n return entry.count;\n }\n\n async decrement(key: string): Promise<void> {\n const entry = this.store.get(key);\n if (entry && entry.count > 0) {\n entry.count--;\n }\n }\n\n async reset(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async close(): Promise<void> {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n this.store.clear();\n }\n\n /**\n * Get current store size (for monitoring).\n */\n get size(): number {\n return this.store.size;\n }\n}\n","/**\n * @module @arcis/node/stores/redis\n * Redis rate limit store\n * \n * Note: This is a reference implementation. You'll need to install\n * the 'ioredis' or 'redis' package and pass your client instance.\n */\n\nimport type { RateLimitStore, RateLimitEntry } from '../core/types';\nimport { RATE_LIMIT } from '../core/constants';\n\n/** Generic Redis client interface (works with ioredis, redis, etc.) */\nexport interface RedisClientLike {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, mode?: string, duration?: number): Promise<unknown>;\n setex(key: string, seconds: number, value: string): Promise<unknown>;\n expire(key: string, seconds: number): Promise<unknown>;\n incr(key: string): Promise<number>;\n decr(key: string): Promise<number>;\n del(key: string): Promise<number>;\n ttl(key: string): Promise<number>;\n quit?(): Promise<unknown>;\n disconnect?(): Promise<unknown>;\n}\n\nexport interface RedisStoreOptions {\n /** Redis client instance */\n client: RedisClientLike;\n /** Key prefix. Default: 'arcis:rl:' */\n prefix?: string;\n /** Window size in milliseconds. Default: 60000 */\n windowMs?: number;\n}\n\n/**\n * Redis rate limit store for distributed deployments.\n * \n * @example\n * import Redis from 'ioredis';\n * \n * const redis = new Redis();\n * const store = new RedisStore({ client: redis });\n * const limiter = createRateLimiter({ store });\n * \n * // Cleanup on shutdown\n * process.on('SIGTERM', async () => {\n * await store.close();\n * });\n */\nexport class RedisStore implements RateLimitStore {\n private client: RedisClientLike;\n private prefix: string;\n private windowMs: number;\n private windowSec: number;\n\n constructor(options: RedisStoreOptions) {\n this.client = options.client;\n this.prefix = options.prefix ?? 'arcis:rl:';\n this.windowMs = options.windowMs ?? RATE_LIMIT.DEFAULT_WINDOW_MS;\n this.windowSec = Math.ceil(this.windowMs / 1000);\n }\n\n private getKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n async get(key: string): Promise<RateLimitEntry | null> {\n const redisKey = this.getKey(key);\n \n const [countStr, ttl] = await Promise.all([\n this.client.get(redisKey),\n this.client.ttl(redisKey),\n ]);\n \n if (!countStr || ttl < 0) {\n return null;\n }\n \n const count = parseInt(countStr, 10);\n if (isNaN(count)) {\n // Corrupt value in Redis — treat as if key doesn't exist\n return null;\n }\n\n return {\n count,\n resetTime: Date.now() + (ttl * 1000),\n };\n }\n\n async set(key: string, entry: RateLimitEntry): Promise<void> {\n const redisKey = this.getKey(key);\n // Clamp to at least 1 second — Math.ceil can produce 0 or negative values\n // when entry.resetTime is in the past due to Redis latency or clock skew.\n const ttlSec = Math.max(1, Math.ceil((entry.resetTime - Date.now()) / 1000));\n await this.client.setex(redisKey, ttlSec, entry.count.toString());\n }\n\n async increment(key: string): Promise<number> {\n const redisKey = this.getKey(key);\n \n // INCR creates key with value 1 if it doesn't exist\n const count = await this.client.incr(redisKey);\n\n // Set expiry only on first increment using EXPIRE, which sets the TTL\n // without overwriting the value (unlike SET ... EX which would reset the\n // counter if two requests increment concurrently before expiry is set).\n if (count === 1) {\n await this.client.expire(redisKey, this.windowSec);\n }\n\n return count;\n }\n\n async decrement(key: string): Promise<void> {\n const redisKey = this.getKey(key);\n await this.client.decr(redisKey);\n }\n\n async reset(key: string): Promise<void> {\n const redisKey = this.getKey(key);\n await this.client.del(redisKey);\n }\n\n async close(): Promise<void> {\n // Don't close the client - it may be shared\n // The caller should manage the client lifecycle\n }\n}\n\n/**\n * Create a Redis store with the given options.\n * Convenience function for functional programming style.\n * \n * @example\n * const store = createRedisStore({ client: redisClient });\n */\nexport function createRedisStore(options: RedisStoreOptions): RedisStore {\n return new RedisStore(options);\n}\n"]}
|