@arcis/node 1.4.3 → 1.5.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.
Files changed (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -5
  3. package/dist/astro/index.js +6141 -0
  4. package/dist/astro/index.js.map +1 -0
  5. package/dist/astro/index.mjs +6136 -0
  6. package/dist/astro/index.mjs.map +1 -0
  7. package/dist/bun/index.js +6195 -0
  8. package/dist/bun/index.js.map +1 -0
  9. package/dist/bun/index.mjs +6189 -0
  10. package/dist/bun/index.mjs.map +1 -0
  11. package/dist/core/constants.d.ts +4 -3
  12. package/dist/core/constants.d.ts.map +1 -1
  13. package/dist/core/index.js +8 -4
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/index.mjs +8 -4
  16. package/dist/core/index.mjs.map +1 -1
  17. package/dist/core/types.d.ts +43 -0
  18. package/dist/core/types.d.ts.map +1 -1
  19. package/dist/fastify/index.js +6160 -0
  20. package/dist/fastify/index.js.map +1 -0
  21. package/dist/fastify/index.mjs +6155 -0
  22. package/dist/fastify/index.mjs.map +1 -0
  23. package/dist/guards.d.ts +156 -0
  24. package/dist/guards.d.ts.map +1 -0
  25. package/dist/hono/index.js +6159 -0
  26. package/dist/hono/index.js.map +1 -0
  27. package/dist/hono/index.mjs +6154 -0
  28. package/dist/hono/index.mjs.map +1 -0
  29. package/dist/index.d.ts +23 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +7365 -305
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +7327 -306
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/koa/index.js +6158 -0
  36. package/dist/koa/index.js.map +1 -0
  37. package/dist/koa/index.mjs +6153 -0
  38. package/dist/koa/index.mjs.map +1 -0
  39. package/dist/logging/index.js.map +1 -1
  40. package/dist/logging/index.mjs.map +1 -1
  41. package/dist/logging/redactor.d.ts.map +1 -1
  42. package/dist/middleware/astro.d.ts +64 -0
  43. package/dist/middleware/astro.d.ts.map +1 -0
  44. package/dist/middleware/bot-detection.d.ts.map +1 -1
  45. package/dist/middleware/bun.d.ts +75 -0
  46. package/dist/middleware/bun.d.ts.map +1 -0
  47. package/dist/middleware/csrf.d.ts.map +1 -1
  48. package/dist/middleware/error-handler.d.ts.map +1 -1
  49. package/dist/middleware/fastify.d.ts +89 -0
  50. package/dist/middleware/fastify.d.ts.map +1 -0
  51. package/dist/middleware/graphql.d.ts +35 -0
  52. package/dist/middleware/graphql.d.ts.map +1 -0
  53. package/dist/middleware/hono.d.ts +63 -0
  54. package/dist/middleware/hono.d.ts.map +1 -0
  55. package/dist/middleware/index.d.ts +12 -0
  56. package/dist/middleware/index.d.ts.map +1 -1
  57. package/dist/middleware/index.js +6693 -122
  58. package/dist/middleware/index.js.map +1 -1
  59. package/dist/middleware/index.mjs +6683 -123
  60. package/dist/middleware/index.mjs.map +1 -1
  61. package/dist/middleware/koa.d.ts +84 -0
  62. package/dist/middleware/koa.d.ts.map +1 -0
  63. package/dist/middleware/main.d.ts +0 -30
  64. package/dist/middleware/main.d.ts.map +1 -1
  65. package/dist/middleware/mass-assign.d.ts +81 -0
  66. package/dist/middleware/mass-assign.d.ts.map +1 -0
  67. package/dist/middleware/method-allowlist.d.ts +66 -0
  68. package/dist/middleware/method-allowlist.d.ts.map +1 -0
  69. package/dist/middleware/nestjs.d.ts +62 -0
  70. package/dist/middleware/nestjs.d.ts.map +1 -0
  71. package/dist/middleware/nextjs.d.ts +102 -0
  72. package/dist/middleware/nextjs.d.ts.map +1 -0
  73. package/dist/middleware/nuxt.d.ts +61 -0
  74. package/dist/middleware/nuxt.d.ts.map +1 -0
  75. package/dist/middleware/overload.d.ts +92 -0
  76. package/dist/middleware/overload.d.ts.map +1 -0
  77. package/dist/middleware/protect.d.ts +91 -0
  78. package/dist/middleware/protect.d.ts.map +1 -0
  79. package/dist/middleware/rate-limit-sliding.d.ts.map +1 -1
  80. package/dist/middleware/rate-limit-token.d.ts.map +1 -1
  81. package/dist/middleware/rate-limit.d.ts.map +1 -1
  82. package/dist/middleware/response-splitting.d.ts +83 -0
  83. package/dist/middleware/response-splitting.d.ts.map +1 -0
  84. package/dist/middleware/sveltekit.d.ts +68 -0
  85. package/dist/middleware/sveltekit.d.ts.map +1 -0
  86. package/dist/middleware/token-budget.d.ts +75 -0
  87. package/dist/middleware/token-budget.d.ts.map +1 -0
  88. package/dist/nestjs/index.js +1724 -0
  89. package/dist/nestjs/index.js.map +1 -0
  90. package/dist/nestjs/index.mjs +1717 -0
  91. package/dist/nestjs/index.mjs.map +1 -0
  92. package/dist/nextjs/index.js +6184 -0
  93. package/dist/nextjs/index.js.map +1 -0
  94. package/dist/nextjs/index.mjs +6178 -0
  95. package/dist/nextjs/index.mjs.map +1 -0
  96. package/dist/nuxt/index.js +6141 -0
  97. package/dist/nuxt/index.js.map +1 -0
  98. package/dist/nuxt/index.mjs +6136 -0
  99. package/dist/nuxt/index.mjs.map +1 -0
  100. package/dist/sanitizers/encode.d.ts.map +1 -1
  101. package/dist/sanitizers/graphql.d.ts +72 -0
  102. package/dist/sanitizers/graphql.d.ts.map +1 -0
  103. package/dist/sanitizers/headers.d.ts +18 -0
  104. package/dist/sanitizers/headers.d.ts.map +1 -1
  105. package/dist/sanitizers/index.d.ts +6 -2
  106. package/dist/sanitizers/index.d.ts.map +1 -1
  107. package/dist/sanitizers/index.js +339 -197
  108. package/dist/sanitizers/index.js.map +1 -1
  109. package/dist/sanitizers/index.mjs +333 -198
  110. package/dist/sanitizers/index.mjs.map +1 -1
  111. package/dist/sanitizers/prompt-injection.d.ts +62 -0
  112. package/dist/sanitizers/prompt-injection.d.ts.map +1 -0
  113. package/dist/sanitizers/sanitize.d.ts +13 -0
  114. package/dist/sanitizers/sanitize.d.ts.map +1 -1
  115. package/dist/sanitizers/xpath.d.ts +37 -0
  116. package/dist/sanitizers/xpath.d.ts.map +1 -0
  117. package/dist/stores/index.js +4 -4
  118. package/dist/stores/index.js.map +1 -1
  119. package/dist/stores/index.mjs +4 -4
  120. package/dist/stores/index.mjs.map +1 -1
  121. package/dist/stores/redis.d.ts +7 -1
  122. package/dist/stores/redis.d.ts.map +1 -1
  123. package/dist/sveltekit/index.js +6142 -0
  124. package/dist/sveltekit/index.js.map +1 -0
  125. package/dist/sveltekit/index.mjs +6137 -0
  126. package/dist/sveltekit/index.mjs.map +1 -0
  127. package/dist/telemetry/client.d.ts +3 -0
  128. package/dist/telemetry/client.d.ts.map +1 -1
  129. package/dist/telemetry/types.d.ts +12 -0
  130. package/dist/telemetry/types.d.ts.map +1 -1
  131. package/dist/validation/index.d.ts +2 -0
  132. package/dist/validation/index.d.ts.map +1 -1
  133. package/dist/validation/index.js +137 -12
  134. package/dist/validation/index.js.map +1 -1
  135. package/dist/validation/index.mjs +116 -13
  136. package/dist/validation/index.mjs.map +1 -1
  137. package/dist/validation/redirect.d.ts.map +1 -1
  138. package/dist/validation/schema.d.ts.map +1 -1
  139. package/dist/validation/url-async.d.ts +137 -0
  140. package/dist/validation/url-async.d.ts.map +1 -0
  141. package/package.json +52 -4
  142. package/scripts/postinstall.cjs +26 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/constants.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/sanitizers/encode.ts","../../src/sanitizers/ldap.ts"],"names":[],"mappings":";AAQO,IAAM,KAAA,GAAQ;AAAA;AAAA,EAEnB,gBAAA,EAAkB,GAAA;AAAA;AAAA,EAElB,mBAAA,EAAqB;AACvB,CAAA;AAwDO,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,mBAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAQO,IAAM,mBAAA,GAAsB;AAAA;AAAA,EAEjC,mCAAA;AAAA;AAAA,EAEA,iBAAA;AAAA;AAAA,EAEA,iCAAA;AAAA,EACA,eAAA;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,gCAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,mBAAA;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,oBAAA;AAAA;AAAA,EAEA,mBAAA;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,SAAA;AAAA;AAAA,EAEA,kBAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAKO,IAAM,gBAAA,GAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU9B,SAAA;AAAA;AAAA,EAEA,OAAA;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,EAAS,aAAA;AAAA;AAAA,EAElE,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;;;AC9PM,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,CAAA;AAkCO,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,CAAA;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,CAAA;;;AC5EO,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;AAQO,SAAS,cAAc,KAAA,EAAkD;AAC9E,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AAIA,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,cAAA,CAAe,KAAe,CAAA;AACnD,EAAA,OAAO,KAAA,KAAU,MAAA,CAAO,SAAA,IAAa,KAAA,KAAU,IAAA;AACjD;;;ACLO,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;AAInB,EAAA,KAAA,GAAQ,KAAA,CAAM,UAAU,MAAM,CAAA;AAI9B,EAAA,IAAI,IAAA;AACJ,EAAA,GAAG;AACD,IAAA,IAAA,GAAO,KAAA;AACP,IAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,MAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACvB,QAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AAEpB,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AACnC,UAAA,IAAI,OAAA,EAAS;AACX,YAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,cAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,gBACX,IAAA,EAAM,gBAAA;AAAA,gBACN,SAAS,OAAA,CAAQ,MAAA;AAAA,gBACjB,QAAA,EAAU;AAAA,eACX,CAAA;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,QAAA,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AACjC,QAAA,YAAA,GAAe,IAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF,SAAS,KAAA,KAAU,IAAA;AAEnB,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;AAGtC,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,SAAA,CAAU,MAAM,CAAA;AAEzC,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,IAAA,OAAA,CAAQ,SAAA,GAAY,CAAA;AACpB,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA,EAAG;AAC5B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACzEO,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;AAIA,EAAA,MAAM,MAAA,GAAS,QAAQ,IAAA,KAAS,QAAA;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,MAAM,MAAA,GAAS,mBAAA,CAAoB,GAAA,EAAgC,OAAA,EAAS,CAAC,CAAA;AAC7E,EAAA,OAAO,OAAA,CAAQ,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,GAAI,MAAA;AAClD;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;;;ACnKO,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;AAQO,SAAS,qBAAA,GAAkC;AAChD,EAAA,OAAO,KAAA,CAAM,KAAK,oBAAoB,CAAA;AACxC;;;ACxCO,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;AAQO,SAAS,qBAAA,GAAkC;AAChD,EAAA,OAAO,KAAA,CAAM,KAAK,oBAAoB,CAAA;AACxC;;;AClDA,IAAM,oBAAA,GAAuB;AAAA;AAAA,EAE3B,cAAA;AAAA;AAAA,EAEA,YAAA;AAAA;AAAA,EAEA,iBAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEA,wDAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAYA,IAAM,oBAAA,GAAuB;AAAA;AAAA,EAE3B,cAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,0BAAA;AAAA,EACA,8BAAA;AAAA;AAAA,EAEA,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAA;AAAA,EACA,6BAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAQO,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,oBAAA,EAAsB;AAC1C,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,MAAA;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,WAAW,KAAA,EAAwB;AACjD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAEtC,EAAA,KAAA,MAAW,WAAW,oBAAA,EAAsB;AAC1C,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;;;AC7GA,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,qBAAA,GAAwB,EAAA;AAE9B,IAAM,mBAAA,GAAsB;AAAA;AAAA,EAE1B,eAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,mBAAA;AAAA;AAAA,EAEA,cAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAGA,IAAM,mBAAA,GAAsB;AAAA;AAAA,EAE1B,0DAAA;AAAA;AAAA,EAEA,kBAAA;AAAA;AAAA,EAEA;AACF,CAAA;AAQO,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;AAInB,EAAA,IAAI,KAAA,CAAM,SAAS,mBAAA,EAAqB;AACtC,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,gBAAA,EAAkB,QAAA,EAAU,CAAA,OAAA,EAAU,KAAA,CAAM,MAAM,CAAA,CAAA,EAAI,CAAA;AAAA,IAC7F;AACA,IAAA,OAAO,iBAAiB,EAAE,KAAA,EAAO,IAAI,YAAA,EAAc,IAAA,EAAM,SAAQ,GAAI,EAAA;AAAA,EACvE;AACA,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AACvC,EAAA,IAAI,UAAA,IAAc,UAAA,CAAW,MAAA,GAAS,qBAAA,EAAuB;AAC3D,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,kBAAA,EAAoB,QAAA,EAAU,CAAA,MAAA,EAAS,UAAA,CAAW,MAAM,CAAA,CAAA,EAAI,CAAA;AAAA,IACnG;AACA,IAAA,OAAO,iBAAiB,EAAE,KAAA,EAAO,IAAI,YAAA,EAAc,IAAA,EAAM,SAAQ,GAAI,EAAA;AAAA,EACvE;AAEA,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;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,mBAAA,EAAqB;AACzC,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;;;ACrHA,IAAM,qBAAA,GAAwB,6BAAA;AAM9B,IAAM,2BAAA,GAA8B;AAAA,EAClC;AAAA;AACF,CAAA;AAuBO,SAAS,qBAAA,CAAsB,QAAA,EAAkB,SAAA,GAAY,GAAA,EAAoB;AACtF,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,WAAW,CAAA,EAAG;AACzD,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAA,CAAS,SAAS,SAAA,EAAW;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,qBAAA,CAAsB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,WAAW,2BAAA,EAA6B;AACjD,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAQO,SAAS,qBAAqB,QAAA,EAA2B;AAC9D,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,WAAW,CAAA,EAAG;AACzD,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,qBAAA,CAAsB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,WAAW,2BAAA,EAA6B;AACjD,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACrEA,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/EA,IAAM,QAAA,GAAW,qFAAA;AAKjB,IAAM,QAAA,GAAW,wEAAA;AAGjB,IAAM,cAAA,GAAiB,0BAAA;AAGvB,IAAM,MAAA,GAAS,gCAAA;AAGf,IAAM,OAAA,GAAU,8EAAA;AAGhB,IAAM,OAAA,GAAU,4HAAA;AAEhB,IAAM,WAAA,GAAyC;AAAA,EAC7C,KAAA,EAAO,CAAC,QAAQ,CAAA;AAAA,EAChB,KAAA,EAAO,CAAC,QAAQ,CAAA;AAAA,EAChB,WAAA,EAAa,CAAC,cAAc,CAAA;AAAA,EAC5B,GAAA,EAAK,CAAC,MAAM,CAAA;AAAA,EACZ,UAAA,EAAY,CAAC,OAAA,EAAS,OAAO;AAC/B,CAAA;AAEA,IAAM,YAAuB,CAAC,OAAA,EAAS,OAAA,EAAS,aAAA,EAAe,OAAO,YAAY,CAAA;AAElF,IAAM,WAAA,GAAuC;AAAA,EAC3C,KAAA,EAAO,SAAA;AAAA,EACP,KAAA,EAAO,SAAA;AAAA,EACP,WAAA,EAAa,eAAA;AAAA,EACb,GAAA,EAAK,OAAA;AAAA,EACL,UAAA,EAAY;AACd,CAAA;AAQA,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACzC,EAAA,IAAI,CAAC,aAAA,CAAc,IAAA,CAAK,MAAM,GAAG,OAAO,KAAA;AAExC,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,KAAA,IAAS,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC3C,IAAA,IAAI,CAAA,GAAI,QAAA,CAAS,MAAA,CAAO,CAAC,GAAG,EAAE,CAAA;AAC9B,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,CAAA,IAAK,CAAA;AACL,MAAA,IAAI,CAAA,GAAI,GAAG,CAAA,IAAK,CAAA;AAAA,IAClB;AACA,IAAA,GAAA,IAAO,CAAA;AACP,IAAA,SAAA,GAAY,CAAC,SAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAM,EAAA,KAAO,CAAA;AACtB;AAkBO,SAAS,OAAA,CAAQ,KAAA,EAAe,OAAA,GAA0B,EAAC,EAAe;AAC/E,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,SAAiB,EAAC;AAEjD,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,SAAA;AAC/B,EAAA,MAAM,UAAsB,EAAC;AAE7B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,QAAA,GAAW,YAAY,IAAI,CAAA;AACjC,IAAA,IAAI,CAAC,QAAA,EAAU;AAEf,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,MAAM,KAAK,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,QAAQ,KAAK,CAAA;AACnD,MAAA,IAAI,KAAA;AAEJ,MAAA,OAAA,CAAQ,KAAA,GAAQ,EAAA,CAAG,IAAA,CAAK,KAAK,OAAO,IAAA,EAAM;AACxC,QAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA;AAGrB,QAAA,IAAI,IAAA,KAAS,aAAA,IAAiB,CAAC,SAAA,CAAU,KAAK,CAAA,EAAG;AAGjD,QAAA,IAAI,SAAS,KAAA,EAAO;AAClB,UAAA,MAAM,OAAO,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,EAAG,CAAC,GAAG,EAAE,CAAA;AAC/C,UAAA,IAAI,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,GAAA,IAAO,QAAQ,GAAA,EAAK;AAAA,QACjD;AAEA,QAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,UACX,IAAA;AAAA,UACA,KAAA;AAAA,UACA,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,GAAA,EAAK,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM;AAAA,SAC1B,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AACxC,EAAA,OAAO,OAAA;AACT;AASO,SAAS,SAAA,CAAU,KAAA,EAAe,OAAA,GAA0B,EAAC,EAAY;AAC9E,EAAA,OAAO,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAA,CAAE,MAAA,GAAS,CAAA;AAC1C;AAgBO,SAAS,SAAA,CAAU,KAAA,EAAe,OAAA,GAA4B,EAAC,EAAW;AAC/E,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAEhD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAA;AACtC,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAEjC,EAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,YAAA;AAG3C,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,IAAS,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC5C,IAAA,MAAM,CAAA,GAAI,QAAQ,CAAC,CAAA;AACnB,IAAA,MAAM,QAAQ,OAAA,CAAQ,UAAA,GAAa,WAAA,CAAY,CAAA,CAAE,IAAI,CAAA,GAAI,WAAA;AACzD,IAAA,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,CAAA,EAAG,CAAA,CAAE,KAAK,IAAI,KAAA,GAAQ,MAAA,CAAO,SAAA,CAAU,CAAA,CAAE,GAAG,CAAA;AAAA,EACxE;AAEA,EAAA,OAAO,MAAA;AACT;AASO,SAAS,cACd,GAAA,EACA,OAAA,GAA0B,EAAC,EAC3B,OAAO,EAAA,EAC2B;AAClC,EAAA,MAAM,UAA4C,EAAC;AACnD,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,OAAA;AAE5C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,MAAM,YAAY,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAE5C,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAA;AACtC,MAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,QAAA,OAAA,CAAQ,KAAK,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,WAAW,CAAA;AAAA,MACzC;AAAA,IACF,CAAA,MAAA,IAAW,SAAS,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,KAAK,GAAG,aAAA,CAAc,KAAA,EAAkC,OAAA,EAAS,SAAS,CAAC,CAAA;AAAA,IACrF,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/B,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,QAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,QAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,UAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AACrC,UAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,YAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,GAAG,SAAS,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAA,EAAK,CAAA;AAAA,UACpD;AAAA,QACF,CAAA,MAAA,IAAW,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AAC3C,UAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,aAAA,CAAc,IAAA,EAAiC,OAAA,EAAS,GAAG,SAAS,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,eAAA,CACd,GAAA,EACA,OAAA,GAA4B,EAAC,EAC1B;AACH,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,GAAA;AAE5C,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,SAAA,CAAU,KAAA,EAAO,OAAO,CAAA;AAAA,IACxC,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/B,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AAC9B,QAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,SAAA,CAAU,MAAM,OAAO,CAAA;AAC5D,QAAA,IAAI,QAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,eAAA,CAAgB,MAAiC,OAAO,CAAA;AACrG,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAA,MAAA,IAAW,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AAC7C,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,eAAA,CAAgB,KAAA,EAAkC,OAAO,CAAA;AAAA,IACzE,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA;AAAA,IAChB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;;;ACrQA,IAAM,aAAA,GAAwC;AAAA,EAC5C,GAAA,EAAK,OAAA;AAAA,EACL,GAAA,EAAK,MAAA;AAAA,EACL,GAAA,EAAK,MAAA;AAAA,EACL,GAAA,EAAK,QAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAEA,IAAM,cAAA,GAAiB,UAAA;AAQhB,SAAS,cAAc,KAAA,EAAuB;AACnD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,OAAO,MAAM,OAAA,CAAQ,cAAA,EAAgB,CAAC,EAAA,KAAO,aAAA,CAAc,EAAE,CAAC,CAAA;AAChE;AASO,SAAS,mBAAmB,KAAA,EAAuB;AACxD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA;AAE7B,IAAA,IACG,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,EAAA,IAAQ,EAAA,IAAM,GAAA,EACrB;AACA,MAAA,MAAA,IAAU,MAAM,CAAC,CAAA;AAAA,IACnB,CAAA,MAAO;AACL,MAAA,MAAA,IAAU,MAAM,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,aAAa,CAAA,CAAA,CAAA;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AASO,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,IAAI,MAAA,GAAS,EAAA;AAGb,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,WAAA,CAAY,CAAC,CAAA;AAE7B,IAAA,IACG,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,EAAA,IAAQ,EAAA,IAAM,GAAA,EACrB;AACA,MAAA,MAAA,IAAU,IAAA;AAAA,IACZ,CAAA,MAAA,IAAW,KAAK,GAAA,EAAO;AACrB,MAAA,MAAA,IAAU,CAAA,GAAA,EAAM,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,aAAY,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAAA,IAChE,CAAA,MAAA,IAAW,MAAM,KAAA,EAAQ;AACvB,MAAA,MAAA,IAAU,CAAA,GAAA,EAAM,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,aAAY,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAAA,IAChE,CAAA,MAAO;AAEL,MAAA,MAAA,IAAU,OAAO,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,aAAa,CAAA,CAAA,CAAA;AAAA,IAChD;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,aAAa,KAAA,EAAuB;AAClD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAGnB,EAAA,OAAO,mBAAmB,KAAK,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,CAAC,EAAA,KAAO;AAC3D,IAAA,OAAO,CAAA,CAAA,EAAI,GAAG,UAAA,CAAW,CAAC,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,WAAA,EAAa,CAAA,CAAA;AAAA,EACxD,CAAC,CAAA;AACH;AASO,SAAS,aAAa,KAAA,EAAuB;AAClD,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA;AAE7B,IAAA,IACG,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,MAAQ,EAAA,IAAM,EAAA;AAAA,IACpB,EAAA,IAAM,EAAA,IAAQ,EAAA,IAAM,GAAA,EACrB;AACA,MAAA,MAAA,IAAU,MAAM,CAAC,CAAA;AAAA,IACnB,CAAA,MAAO;AAEL,MAAA,MAAA,IAAU,KAAK,EAAA,CAAG,QAAA,CAAS,EAAE,CAAA,CAAE,aAAa,CAAA,CAAA,CAAA;AAAA,IAC9C;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;;;ACpHA,IAAM,iBAAA,GAAoB,cAAA;AAG1B,IAAM,aAAA,GAAgB,2BAAA;AAGtB,IAAM,mBAAA,GAAsB,aAAA;AAG5B,IAAM,sBAAA,GAAyB,sBAAA;AAE/B,IAAM,UAAA,GAAa,CAAC,IAAA,KAAiB,IAAA,GAAO,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAUpF,SAAS,mBAAmB,KAAA,EAAuB;AACxD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAO,KAAK,CAAA;AAClD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,iBAAA,EAAmB,UAAU,CAAA;AACpD;AAUO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAO,KAAK,CAAA;AAClD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,aAAA,EAAe,UAAU,CAAA;AAChD;AAaO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,OAAO,oBAAoB,IAAA,CAAK,KAAK,CAAA,IAAK,sBAAA,CAAuB,KAAK,KAAK,CAAA;AAC7E","file":"index.mjs","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 /** form tags — phishing/credential harvesting via action= redirection */\n /<form[\\s>]/gi,\n /** meta tags — http-equiv refresh redirects or CSP bypass */\n /<meta[\\s>]/gi,\n /** base href hijacking — redirects all relative URLs to attacker domain */\n /<base[\\s>]/gi,\n /** link tag injection — stylesheet or preload CSRF attacks */\n /<link[\\s>]/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 /** style — CSS expression() and behavior: attacks (IE-era but still relevant) */\n /<style[^>]*>[\\s\\S]*?<\\/style>/gi,\n /<style[^>]*/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 /** form tag injection — phishing via action= redirection */\n /<form[\\s>][^>]*/gi,\n /** meta tag injection — http-equiv refresh or CSP bypass */\n /<meta[\\s>][^>]*/gi,\n /** base href hijacking */\n /<base[\\s>][^>]*/gi,\n /** link tag injection — stylesheet or preload attacks */\n /<link[\\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 control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */\n /%0[0-9a-f]/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/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, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#x27;');\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: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\n * \n * @example\n * sanitizeXss(\"<img onerror='alert(1)'>\")\n * // Returns: \"&lt;img&gt;\" (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 (&lt;, &amp;, 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 // SECURITY: Normalize Unicode to NFKC before pattern matching.\n // Fullwidth dot U+FF0E normalizes to '.', preventing ../ bypass of ../ detection.\n value = value.normalize('NFKC');\n\n // Apply patterns repeatedly until the string stops changing.\n // Single-pass stripping is bypassable: \"....//\".replace(\"../\",\"\") → \"../\"\n let prev: string;\n do {\n prev = value;\n for (const pattern of PATH_PATTERNS) {\n pattern.lastIndex = 0;\n\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: '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 } while (value !== prev);\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 // SECURITY: Normalize Unicode to NFKC — same as sanitizePath\n const normalized = input.normalize('NFKC');\n\n for (const pattern of PATH_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(normalized)) {\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 &lt; 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: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\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 // Default mode is 'sanitize' (strip threats and return cleaned string).\n // Pass mode: 'reject' to throw SecurityThreatError instead of stripping.\n const reject = options.mode === '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/**\n * Removal patterns — strip template expressions that look like actual attacks.\n *\n * ${ and #{ patterns are narrowed to require operators/method-calls inside to\n * avoid false-positives on JS template literals (${name}) and Ruby/Pug output\n * expressions (#{name}) that appear in legitimate user-submitted content.\n *\n * The broader detection patterns above still flag these for detectSsti() —\n * narrowing only applies to destructive sanitization.\n */\nconst SSTI_REMOVE_PATTERNS = [\n /** Jinja2 / Twig: {{ ... }} — always strip (not valid in any JS context) */\n /\\{\\{.*?\\}\\}/g,\n /**\n * Freemarker / Spring EL: ${...} — strip when expression contains operators,\n * method calls, or Python dunder patterns (sandbox escape).\n * Bare ${name} and ${user.name} are left intact (JS template literal syntax).\n */\n /\\$\\{[^}]*__\\w+__[^}]*\\}/g,\n /\\$\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n /** ERB / EJS: <%= ... %> */\n /<%[=\\-]?.*?%>/gs,\n /**\n * Pug / Jade: #{...} — same narrowing as ${ above, plus dunder detection.\n * #{name} output expressions are left intact.\n */\n /#\\{[^}]*__\\w+__[^}]*\\}/g,\n /#\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n /** Python dunder sandbox escape — always strip */\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 */\n/**\n * Billion-laughs defense: cap raw XML input length and the count of\n * entity references. A valid document rarely needs more than a handful of\n * entities; thousands of `&foo;` references is the classic bomb shape.\n */\nconst MAX_XXE_INPUT_BYTES = 1_000_000; // 1 MB — above any reasonable config/SOAP payload\nconst MAX_ENTITY_REFERENCES = 64;\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 // Billion-laughs defense: oversize input or many entity refs → flatten to empty.\n // Safer to discard than to attempt partial sanitization of a bomb payload.\n if (value.length > MAX_XXE_INPUT_BYTES) {\n if (collectThreats) {\n threats.push({ type: 'xxe', pattern: 'oversize_input', original: `length=${value.length}` });\n }\n return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n }\n const entityRefs = value.match(/&\\w+;/g);\n if (entityRefs && entityRefs.length > MAX_ENTITY_REFERENCES) {\n if (collectThreats) {\n threats.push({ type: 'xxe', pattern: 'entity_expansion', original: `count=${entityRefs.length}` });\n }\n return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n }\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, dollar, and dot.\n * Bracket notation is rejected — it enables bypasses like `cb[x` (unbalanced)\n * and isn't needed for real-world JSONP callbacks.\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] 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\n// (?<!\\d) / (?!\\d) boundaries prevent false positives inside longer digit\n// sequences like ZIP+number combos (\"94102 555-1234\") or bank account strings.\nconst PHONE_RE = /(?<!\\d)(?:\\+?1[-.\\s]?)?\\(?[2-9]\\d{2}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}(?!\\d)/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/sanitizers/encode\n * Context-aware output encoding for XSS prevention.\n *\n * Wrong-context encoding is the #1 cause of XSS bypasses in \"protected\" apps.\n * A single sanitize() is not enough when output goes to JS, CSS, or attribute contexts.\n */\n\n// HTML entity map — covers the 5 dangerous chars in HTML body context\nconst HTML_ENTITIES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n};\n\nconst HTML_ENCODE_RE = /[&<>\"']/g;\n\n/**\n * Encodes for HTML body context. Entity-encodes & < > \" '\n *\n * Use when outputting to HTML element content:\n * `<p>${encodeForHtml(userInput)}</p>`\n */\nexport function encodeForHtml(value: string): string {\n if (!value) return '';\n return value.replace(HTML_ENCODE_RE, (ch) => HTML_ENTITIES[ch]);\n}\n\n/**\n * Encodes for HTML attribute context.\n * All non-alphanumeric characters are encoded as `&#xHH;` hex entities.\n *\n * Use when outputting to HTML attributes:\n * `<div title=\"${encodeForAttribute(userInput)}\">`\n */\nexport function encodeForAttribute(value: string): string {\n if (!value) return '';\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n // Allow a-z A-Z 0-9\n if (\n (ch >= 0x30 && ch <= 0x39) || // 0-9\n (ch >= 0x41 && ch <= 0x5a) || // A-Z\n (ch >= 0x61 && ch <= 0x7a) // a-z\n ) {\n result += value[i];\n } else {\n result += `&#x${ch.toString(16).toUpperCase()};`;\n }\n }\n return result;\n}\n\n/**\n * Encodes for JavaScript string context.\n * Non-alphanumeric characters are escaped as `\\xHH` (ASCII) or `\\uHHHH` (Unicode).\n *\n * Use when embedding in JS string literals:\n * `var x = '${encodeForJs(userInput)}';`\n */\nexport function encodeForJs(value: string): string {\n if (!value) return '';\n let result = '';\n // Use for-of to iterate codepoints, not UTF-16 code units.\n // This correctly handles surrogate pairs (emoji, symbols outside BMP).\n for (const char of value) {\n const cp = char.codePointAt(0)!;\n // Allow a-z A-Z 0-9\n if (\n (cp >= 0x30 && cp <= 0x39) || // 0-9\n (cp >= 0x41 && cp <= 0x5a) || // A-Z\n (cp >= 0x61 && cp <= 0x7a) // a-z\n ) {\n result += char;\n } else if (cp < 0x100) {\n result += `\\\\x${cp.toString(16).toUpperCase().padStart(2, '0')}`;\n } else if (cp <= 0xFFFF) {\n result += `\\\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;\n } else {\n // Codepoints above BMP — use ES6 Unicode escape\n result += `\\\\u{${cp.toString(16).toUpperCase()}}`;\n }\n }\n return result;\n}\n\n/**\n * Encodes for URL parameter context. Percent-encodes all non-unreserved chars.\n *\n * Use when building query strings:\n * `?q=${encodeForUrl(userInput)}`\n */\nexport function encodeForUrl(value: string): string {\n if (!value) return '';\n // encodeURIComponent handles most cases but doesn't encode: ! ' ( ) *\n // We encode these additionally for full safety per RFC 3986\n return encodeURIComponent(value).replace(/[!'()*]/g, (ch) => {\n return `%${ch.charCodeAt(0).toString(16).toUpperCase()}`;\n });\n}\n\n/**\n * Encodes for CSS value context.\n * Non-alphanumeric characters are hex-escaped as `\\HH ` (trailing space per CSS spec).\n *\n * Use when embedding in CSS values:\n * `content: '${encodeForCss(userInput)}';`\n */\nexport function encodeForCss(value: string): string {\n if (!value) return '';\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n // Allow a-z A-Z 0-9\n if (\n (ch >= 0x30 && ch <= 0x39) || // 0-9\n (ch >= 0x41 && ch <= 0x5a) || // A-Z\n (ch >= 0x61 && ch <= 0x7a) // a-z\n ) {\n result += value[i];\n } else {\n // CSS hex escape: backslash + hex code + trailing space (CSS spec requirement)\n result += `\\\\${ch.toString(16).toUpperCase()} `;\n }\n }\n return result;\n}\n","/**\n * @module @arcis/node/sanitizers/ldap\n * LDAP injection prevention\n *\n * LDAP special characters in filter context: * ( ) \\ NUL\n * LDAP special characters in DN context: , + < > ; \" = / \\ NUL\n *\n * RFC 4515 (filter) and RFC 4514 (DN) define the escaping rules.\n * Sanitization escapes rather than strips — preserves the original value\n * while making it safe to embed in LDAP queries.\n */\n\n// LDAP filter special characters per RFC 4515 (single pass includes NUL)\nconst LDAP_FILTER_CHARS = /[*()\\\\\\x00]/g;\n\n// LDAP DN special characters per RFC 4514 (single pass includes NUL)\nconst LDAP_DN_CHARS = /[,+<>;\"=\\/\\\\\\x00*()\\x00]/g;\n\n// Detection pattern — unescaped LDAP special chars in filter context\nconst LDAP_DETECT_PATTERN = /[*()\\\\\\x00]/;\n\n// Detection pattern for OR/AND bypass and wildcard abuse\nconst LDAP_INJECTION_PATTERN = /\\)\\s*\\(|\\*\\s*\\)\\s*\\(/;\n\nconst escapeChar = (char: string) => '\\\\' + char.charCodeAt(0).toString(16).padStart(2, '0');\n\n/**\n * Sanitizes a string for safe use in LDAP filter expressions.\n * Escapes * ( ) \\ and NUL per RFC 4515.\n *\n * @example\n * sanitizeLdapFilter(\"user*(admin)\")\n * // Returns: \"user\\2a\\28admin\\29\"\n */\nexport function sanitizeLdapFilter(input: string): string {\n if (typeof input !== 'string') return String(input);\n return input.replace(LDAP_FILTER_CHARS, escapeChar);\n}\n\n/**\n * Sanitizes a string for safe use in LDAP Distinguished Names (DN).\n * Escapes , + < > ; \" = / \\ and NUL per RFC 4514.\n *\n * @example\n * sanitizeLdapDn(\"cn=admin,dc=example\")\n * // Returns: \"cn\\3dadmin\\2cdc\\3dexample\"\n */\nexport function sanitizeLdapDn(input: string): string {\n if (typeof input !== 'string') return String(input);\n return input.replace(LDAP_DN_CHARS, escapeChar);\n}\n\n/**\n * Detects potential LDAP injection patterns in a string.\n * Does not sanitize — use sanitizeLdapFilter() or sanitizeLdapDn() for that.\n *\n * @param input - The string to check\n * @returns True if LDAP injection patterns detected\n *\n * @example\n * detectLdapInjection(\"*)(uid=*))(|(uid=*\") // true\n * detectLdapInjection(\"john\") // false\n */\nexport function detectLdapInjection(input: string): boolean {\n if (typeof input !== 'string') return false;\n return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input);\n}\n"]}
1
+ {"version":3,"sources":["../../src/core/constants.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/ssti.ts","../../src/sanitizers/xxe.ts","../../src/sanitizers/ldap.ts","../../src/sanitizers/xpath.ts","../../src/sanitizers/headers.ts","../../src/sanitizers/sanitize.ts","../../src/sanitizers/nosql.ts","../../src/sanitizers/prototype.ts","../../src/sanitizers/jsonp.ts","../../src/sanitizers/pii.ts","../../src/sanitizers/encode.ts","../../src/sanitizers/graphql.ts"],"names":[],"mappings":"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","file":"index.mjs","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 /** form tags — phishing/credential harvesting via action= redirection */\n /<form[\\s>]/gi,\n /** meta tags — http-equiv refresh redirects or CSP bypass */\n /<meta[\\s>]/gi,\n /** base href hijacking — redirects all relative URLs to attacker domain */\n /<base[\\s>]/gi,\n /** link tag injection — stylesheet or preload CSRF attacks */\n /<link[\\s>]/gi,\n /** style tag — CSS expression() / behavior: / IE-era attacks. Mirrors\n * Python's xss-style-tag from packages/core/patterns.json. */\n /<style[\\s>]/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 /** style — CSS expression() and behavior: attacks (IE-era but still relevant) */\n /<style[^>]*>[\\s\\S]*?<\\/style>/gi,\n /<style[^>]*/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 or SVG content (SVG can run JS via inline event handlers) */\n /data\\s*:\\s*(?:text\\/html|image\\/svg)[^>\\s]*/gi,\n /** form tag injection — phishing via action= redirection */\n /<form[\\s>][^>]*/gi,\n /** meta tag injection — http-equiv refresh or CSP bypass */\n /<meta[\\s>][^>]*/gi,\n /** base href hijacking */\n /<base[\\s>][^>]*/gi,\n /** link tag injection — stylesheet or preload attacks */\n /<link[\\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 control characters (%00-%0F): null, tab, vtab, formfeed, LF, CR */\n /%0[0-9a-f]/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:// (case-insensitive scheme per\n * RFC 3986); explicitly rejects javascript:, data:, vbscript:, and\n * other dangerous URI schemes.\n */\n URL: /^https?:\\/\\/[^\\s/$.?#][^\\s]*$/i,\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/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, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#x27;');\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: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\n * \n * @example\n * sanitizeXss(\"<img onerror='alert(1)'>\")\n * // Returns: \"&lt;img&gt;\" (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 (&lt;, &amp;, 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 // SECURITY: Normalize Unicode to NFKC before pattern matching.\n // Fullwidth dot U+FF0E normalizes to '.', preventing ../ bypass of ../ detection.\n value = value.normalize('NFKC');\n\n // Apply patterns repeatedly until the string stops changing.\n // Single-pass stripping is bypassable: \"....//\".replace(\"../\",\"\") → \"../\"\n let prev: string;\n do {\n prev = value;\n for (const pattern of PATH_PATTERNS) {\n pattern.lastIndex = 0;\n\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: '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 } while (value !== prev);\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 // SECURITY: Normalize Unicode to NFKC — same as sanitizePath\n const normalized = input.normalize('NFKC');\n\n for (const pattern of PATH_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(normalized)) {\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/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/**\n * Removal patterns — strip template expressions that look like actual attacks.\n *\n * ${ and #{ patterns are narrowed to require operators/method-calls inside to\n * avoid false-positives on JS template literals (${name}) and Ruby/Pug output\n * expressions (#{name}) that appear in legitimate user-submitted content.\n *\n * The broader detection patterns above still flag these for detectSsti() —\n * narrowing only applies to destructive sanitization.\n */\nconst SSTI_REMOVE_PATTERNS = [\n /** Jinja2 / Twig: {{ ... }} — always strip (not valid in any JS context) */\n /\\{\\{.*?\\}\\}/g,\n /**\n * Freemarker / Spring EL: ${...} — strip when expression contains operators,\n * method calls, or Python dunder patterns (sandbox escape).\n * Bare ${name} and ${user.name} are left intact (JS template literal syntax).\n */\n /\\$\\{[^}]*__\\w+__[^}]*\\}/g,\n /\\$\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n /** ERB / EJS: <%= ... %> */\n /<%[=\\-]?.*?%>/gs,\n /**\n * Pug / Jade: #{...} — same narrowing as ${ above, plus dunder detection.\n * #{name} output expressions are left intact.\n */\n /#\\{[^}]*__\\w+__[^}]*\\}/g,\n /#\\{[^}]*[?!()*+\\-/][^}]*\\}/g,\n /** Python dunder sandbox escape — always strip */\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 */\n/**\n * Billion-laughs defense: cap raw XML input length and the count of\n * entity references. A valid document rarely needs more than a handful of\n * entities; thousands of `&foo;` references is the classic bomb shape.\n */\nconst MAX_XXE_INPUT_BYTES = 1_000_000; // 1 MB — above any reasonable config/SOAP payload\nconst MAX_ENTITY_REFERENCES = 64;\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 // Billion-laughs defense: oversize input or many entity refs → flatten to empty.\n // Safer to discard than to attempt partial sanitization of a bomb payload.\n if (value.length > MAX_XXE_INPUT_BYTES) {\n if (collectThreats) {\n threats.push({ type: 'xxe', pattern: 'oversize_input', original: `length=${value.length}` });\n }\n return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n }\n const entityRefs = value.match(/&\\w+;/g);\n if (entityRefs && entityRefs.length > MAX_ENTITY_REFERENCES) {\n if (collectThreats) {\n threats.push({ type: 'xxe', pattern: 'entity_expansion', original: `count=${entityRefs.length}` });\n }\n return collectThreats ? { value: '', wasSanitized: true, threats } : '';\n }\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/ldap\n * LDAP injection prevention\n *\n * LDAP special characters in filter context: * ( ) \\ NUL\n * LDAP special characters in DN context: , + < > ; \" = / \\ NUL\n *\n * RFC 4515 (filter) and RFC 4514 (DN) define the escaping rules.\n * Sanitization escapes rather than strips — preserves the original value\n * while making it safe to embed in LDAP queries.\n */\n\n// LDAP filter special characters per RFC 4515 (single pass includes NUL)\nconst LDAP_FILTER_CHARS = /[*()\\\\\\x00]/g;\n\n// LDAP DN special characters per RFC 4514 (single pass includes NUL)\nconst LDAP_DN_CHARS = /[,+<>;\"=\\/\\\\\\x00*()\\x00]/g;\n\n// Detection pattern — unescaped LDAP special chars in filter context\nconst LDAP_DETECT_PATTERN = /[*()\\\\\\x00]/;\n\n// Detection pattern for OR/AND bypass and wildcard abuse\nconst LDAP_INJECTION_PATTERN = /\\)\\s*\\(|\\*\\s*\\)\\s*\\(/;\n\nconst escapeChar = (char: string) => '\\\\' + char.charCodeAt(0).toString(16).padStart(2, '0');\n\n/**\n * Sanitizes a string for safe use in LDAP filter expressions.\n * Escapes * ( ) \\ and NUL per RFC 4515.\n *\n * @example\n * sanitizeLdapFilter(\"user*(admin)\")\n * // Returns: \"user\\2a\\28admin\\29\"\n */\nexport function sanitizeLdapFilter(input: string): string {\n if (typeof input !== 'string') return String(input);\n return input.replace(LDAP_FILTER_CHARS, escapeChar);\n}\n\n/**\n * Sanitizes a string for safe use in LDAP Distinguished Names (DN).\n * Escapes , + < > ; \" = / \\ and NUL per RFC 4514.\n *\n * @example\n * sanitizeLdapDn(\"cn=admin,dc=example\")\n * // Returns: \"cn\\3dadmin\\2cdc\\3dexample\"\n */\nexport function sanitizeLdapDn(input: string): string {\n if (typeof input !== 'string') return String(input);\n return input.replace(LDAP_DN_CHARS, escapeChar);\n}\n\n/**\n * Detects potential LDAP injection patterns in a string.\n * Does not sanitize — use sanitizeLdapFilter() or sanitizeLdapDn() for that.\n *\n * @param input - The string to check\n * @returns True if LDAP injection patterns detected\n *\n * @example\n * detectLdapInjection(\"*)(uid=*))(|(uid=*\") // true\n * detectLdapInjection(\"john\") // false\n */\nexport function detectLdapInjection(input: string): boolean {\n if (typeof input !== 'string') return false;\n return LDAP_DETECT_PATTERN.test(input) || LDAP_INJECTION_PATTERN.test(input);\n}\n","/**\n * @module @arcis/node/sanitizers/xpath\n * XPath injection prevention.\n *\n * XPath 1.0 has no escape syntax for string literals — the only way to\n * embed user input safely is parameterised queries / variable bindings.\n * Neither libxml2 nor most JS XPath libraries expose a canonical escape\n * function. The pragmatic answer everyone ships:\n *\n * - Detect: scan for unescaped quotes or expression-control chars\n * that suggest the user is trying to break out of a string literal.\n * - Sanitize: strip the offending control characters. Lossy by design;\n * callers that need lossless input should use parameterised queries\n * directly.\n *\n * Detection is the load-bearing surface for this vector. Sanitization is\n * a fallback for users running existing XPath strings through user input\n * who can't switch to bound parameters today.\n */\n\n// XPath expression-control characters that an attacker uses to escape\n// a string literal: single quote, double quote, comma (changes function\n// arity), the union operator |, and parens (used in `) or (` toggles\n// against XPath function calls). These are the same shapes Aikido /\n// Snyk's xpath rules look for.\nconst XPATH_INJECTION_CHARS = /['\"|,()]/;\n\n// Common operator-injection patterns: unescaped boolean injection\n// (`' or '1'='1`), function tampering (`,`), and union (`|`).\nconst XPATH_INJECTION_PATTERN =\n /('\\s*(or|and)\\s*'|\"\\s*(or|and)\\s*\"|\\)\\s*(or|and)\\s*\\(|\\|\\s*\\/)/i;\n\n/**\n * Detects XPath-injection-shaped patterns in a string. Returns true when\n * the input looks like it's trying to break out of an XPath string\n * literal or hijack the expression structure.\n *\n * Conservative on purpose: triggers on any control char in the input\n * combined with a boolean / union pattern. Plain user names and emails\n * (no quotes, no pipes) pass clean.\n */\nexport function detectXpathInjection(input: string): boolean {\n if (typeof input !== 'string' || input.length === 0) return false;\n // Fast path: skip the regex test entirely when no control chars exist.\n if (!XPATH_INJECTION_CHARS.test(input)) return false;\n return XPATH_INJECTION_PATTERN.test(input);\n}\n\n/**\n * Strips XPath expression-control characters from a string. Lossy —\n * `O'Brien` becomes `OBrien`. Use only when migrating legacy code that\n * concatenates user input into XPath; new code should use bound\n * parameters via the underlying XPath library.\n */\nexport function sanitizeXpath(input: string): string {\n if (typeof input !== 'string') return String(input);\n return input.replace(/['\"|,]/g, '');\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/**\n * Email-header injection prevention. Same byte-level threat as HTTP\n * header injection — `\\r\\n` in a user-controlled email field\n * (`To`, `From`, `Subject`, etc.) lets an attacker inject extra headers\n * (most commonly Bcc) and pivot a contact form into a spam relay.\n *\n * Aliased to the HTTP-header sanitizers because the wire-level fix is\n * identical: strip CRLF + null bytes from the value before\n * concatenating into the header. Use these in form-to-email handlers:\n *\n * ```ts\n * const subject = sanitizeEmailHeader(req.body.subject);\n * const to = sanitizeEmailHeader(req.body.to);\n * if (detectEmailHeaderInjection(req.body.to)) reject(...);\n * ```\n */\nexport const sanitizeEmailHeader = sanitizeHeaderValue;\nexport const detectEmailHeaderInjection = detectHeaderInjection;\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, detectXss } from './xss';\nimport { sanitizeSql, detectSql } from './sql';\nimport { sanitizePath, detectPathTraversal } from './path';\nimport { sanitizeCommand, detectCommandInjection } from './command';\nimport { detectSsti } from './ssti';\nimport { detectXxe } from './xxe';\nimport { detectLdapInjection } from './ldap';\nimport { detectXpathInjection } from './xpath';\nimport { detectHeaderInjection } from './headers';\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 &lt; 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: \"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;\"\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 // Default mode is 'sanitize' (strip threats and return cleaned string).\n // Pass mode: 'reject' to throw SecurityThreatError instead of stripping.\n const reject = options.mode === '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/** Threat triple returned from scanThreats. */\nexport interface ThreatHit {\n vector:\n | 'xss'\n | 'sql'\n | 'nosql'\n | 'path'\n | 'command'\n | 'prototype'\n | 'ssti'\n | 'xxe'\n | 'ldap'\n | 'xpath'\n | 'header';\n rule: string;\n matchedPattern: string;\n}\n\n/**\n * Walk a value (string, array, or object) and return the first threat hit\n * found. Used by block-mode middleware to attribute the deny decision.\n *\n * Vector ordering matches Python's scan_threats for cross-SDK parity.\n */\nexport function scanThreats(data: unknown, depth = 0): ThreatHit | null {\n if (depth > INPUT.MAX_RECURSION_DEPTH) return null;\n\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n for (const key of Object.keys(data as Record<string, unknown>)) {\n const lower = key.toLowerCase();\n if (DANGEROUS_PROTO_KEYS.has(lower)) {\n return { vector: 'prototype', rule: 'prototype/match', matchedPattern: key };\n }\n if (NOSQL_DANGEROUS_KEYS.has(key)) {\n return { vector: 'nosql', rule: 'nosql/match', matchedPattern: key };\n }\n const inner = scanThreats((data as Record<string, unknown>)[key], depth + 1);\n if (inner) return inner;\n }\n return null;\n }\n\n if (Array.isArray(data)) {\n for (const item of data) {\n const inner = scanThreats(item, depth + 1);\n if (inner) return inner;\n }\n return null;\n }\n\n if (typeof data !== 'string') return null;\n\n const sample = data.slice(0, 80);\n if (detectXss(data)) {\n return { vector: 'xss', rule: 'xss/match', matchedPattern: sample };\n }\n if (detectSsti(data)) {\n return { vector: 'ssti', rule: 'ssti/match', matchedPattern: sample };\n }\n if (detectXxe(data)) {\n return { vector: 'xxe', rule: 'xxe/match', matchedPattern: sample };\n }\n if (detectSql(data)) {\n return { vector: 'sql', rule: 'sql/match', matchedPattern: sample };\n }\n if (detectPathTraversal(data)) {\n return { vector: 'path', rule: 'path/match', matchedPattern: sample };\n }\n if (detectCommandInjection(data)) {\n return { vector: 'command', rule: 'command/match', matchedPattern: sample };\n }\n // LDAP + XPath checks come AFTER command/path so a string that's\n // primarily a path-traversal payload (`../`) gets attributed to\n // path, not LDAP (the `\\` in `..\\..\\` would otherwise hit the LDAP\n // backslash filter).\n if (detectLdapInjection(data)) {\n return { vector: 'ldap', rule: 'ldap/match', matchedPattern: sample };\n }\n if (detectXpathInjection(data)) {\n return { vector: 'xpath', rule: 'xpath/match', matchedPattern: sample };\n }\n // Header injection (HTTP response splitting + email-header injection\n // share the same byte-level threat: CRLF in a value that gets\n // concatenated into a header). Last in the chain so the more-specific\n // detectors (xss / sql / etc.) win on input that's both — e.g. an XSS\n // payload with a stray newline still attributes to xss.\n if (detectHeaderInjection(data)) {\n return { vector: 'header', rule: 'header/match', matchedPattern: sample };\n }\n return null;\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 // Block mode: scan first, return 403 on threat. The telemetry emitter\n // reads the marker on res.finish to attribute the deny decision.\n if (options.block) {\n const hit =\n scanThreats(req.body) ||\n scanThreats(req.query) ||\n scanThreats(req.params) ||\n scanThreats(req.path);\n if (hit) {\n req.__arcis = {\n vector: hit.vector,\n rule: hit.rule,\n severity: 'high',\n matchedPattern: hit.matchedPattern,\n reason: `${hit.vector} pattern detected in request`,\n decision: 'deny',\n };\n res.status(403).json({\n error: 'Request blocked for security reasons',\n code: 'SECURITY_THREAT',\n vector: hit.vector,\n });\n return;\n }\n }\n\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/jsonp\n * JSONP callback sanitization to prevent XSS via callback parameters\n */\n\n/**\n * Valid JSONP callback pattern: only alphanumeric, underscore, dollar, and dot.\n * Bracket notation is rejected — it enables bypasses like `cb[x` (unbalanced)\n * and isn't needed for real-world JSONP callbacks.\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] 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/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\n// (?<!\\d) / (?!\\d) boundaries prevent false positives inside longer digit\n// sequences like ZIP+number combos (\"94102 555-1234\") or bank account strings.\nconst PHONE_RE = /(?<!\\d)(?:\\+?1[-.\\s]?)?\\(?[2-9]\\d{2}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}(?!\\d)/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/sanitizers/encode\n * Context-aware output encoding for XSS prevention.\n *\n * Wrong-context encoding is the #1 cause of XSS bypasses in \"protected\" apps.\n * A single sanitize() is not enough when output goes to JS, CSS, or attribute contexts.\n */\n\n// HTML entity map — covers the 5 dangerous chars in HTML body context\nconst HTML_ENTITIES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n};\n\nconst HTML_ENCODE_RE = /[&<>\"']/g;\n\n/**\n * Encodes for HTML body context. Entity-encodes & < > \" '\n *\n * Use when outputting to HTML element content:\n * `<p>${encodeForHtml(userInput)}</p>`\n */\nexport function encodeForHtml(value: string): string {\n if (!value) return '';\n return value.replace(HTML_ENCODE_RE, (ch) => HTML_ENTITIES[ch]);\n}\n\n/**\n * Encodes for HTML attribute context.\n * All non-alphanumeric characters are encoded as `&#xHH;` hex entities.\n *\n * Use when outputting to HTML attributes:\n * `<div title=\"${encodeForAttribute(userInput)}\">`\n */\nexport function encodeForAttribute(value: string): string {\n if (!value) return '';\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n // Allow a-z A-Z 0-9\n if (\n (ch >= 0x30 && ch <= 0x39) || // 0-9\n (ch >= 0x41 && ch <= 0x5a) || // A-Z\n (ch >= 0x61 && ch <= 0x7a) // a-z\n ) {\n result += value[i];\n } else {\n result += `&#x${ch.toString(16).toUpperCase()};`;\n }\n }\n return result;\n}\n\n/**\n * Encodes for JavaScript string context.\n * Non-alphanumeric characters are escaped as `\\xHH` (ASCII) or `\\uHHHH` (Unicode).\n *\n * Use when embedding in JS string literals:\n * `var x = '${encodeForJs(userInput)}';`\n */\nexport function encodeForJs(value: string): string {\n if (!value) return '';\n let result = '';\n // Use for-of to iterate codepoints, not UTF-16 code units.\n // This correctly handles surrogate pairs (emoji, symbols outside BMP).\n for (const char of value) {\n const cp = char.codePointAt(0);\n if (cp === undefined) continue;\n // Allow a-z A-Z 0-9\n if (\n (cp >= 0x30 && cp <= 0x39) || // 0-9\n (cp >= 0x41 && cp <= 0x5a) || // A-Z\n (cp >= 0x61 && cp <= 0x7a) // a-z\n ) {\n result += char;\n } else if (cp < 0x100) {\n result += `\\\\x${cp.toString(16).toUpperCase().padStart(2, '0')}`;\n } else if (cp <= 0xFFFF) {\n result += `\\\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;\n } else {\n // Codepoints above BMP — use ES6 Unicode escape\n result += `\\\\u{${cp.toString(16).toUpperCase()}}`;\n }\n }\n return result;\n}\n\n/**\n * Encodes for URL parameter context. Percent-encodes all non-unreserved chars.\n *\n * Use when building query strings:\n * `?q=${encodeForUrl(userInput)}`\n */\nexport function encodeForUrl(value: string): string {\n if (!value) return '';\n // encodeURIComponent handles most cases but doesn't encode: ! ' ( ) *\n // We encode these additionally for full safety per RFC 3986\n return encodeURIComponent(value).replace(/[!'()*]/g, (ch) => {\n return `%${ch.charCodeAt(0).toString(16).toUpperCase()}`;\n });\n}\n\n/**\n * Encodes for CSS value context.\n * Non-alphanumeric characters are hex-escaped as `\\HH ` (trailing space per CSS spec).\n *\n * Use when embedding in CSS values:\n * `content: '${encodeForCss(userInput)}';`\n */\nexport function encodeForCss(value: string): string {\n if (!value) return '';\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const ch = value.charCodeAt(i);\n // Allow a-z A-Z 0-9\n if (\n (ch >= 0x30 && ch <= 0x39) || // 0-9\n (ch >= 0x41 && ch <= 0x5a) || // A-Z\n (ch >= 0x61 && ch <= 0x7a) // a-z\n ) {\n result += value[i];\n } else {\n // CSS hex escape: backslash + hex code + trailing space (CSS spec requirement)\n result += `\\\\${ch.toString(16).toUpperCase()} `;\n }\n }\n return result;\n}\n","/**\n * @module @arcis/node/sanitizers/graphql\n * GraphQL injection prevention (sdk-vectors.md tier 1 #21).\n *\n * Two threats covered:\n *\n * 1. **Depth-bomb DoS** — nested-query payloads like\n * `query { x { x { x { ... } } } }` to ridiculous depth that explode\n * resolver work (each `{` typically maps to a database round-trip).\n * Even a 50-deep query against a real schema can hammer the\n * backend; 1000-deep crashes the resolver entirely.\n *\n * 2. **Introspection abuse** — `__schema` / `__type` / `__typename`\n * queries that let an attacker enumerate the entire schema, then\n * use that map to find sensitive fields, deprecated mutations,\n * or unprotected admin paths. Production GraphQL endpoints should\n * disable introspection by default.\n *\n * v1 is regex-based: count `{` / `}` for nesting depth (no escape\n * handling — strings inside the query that contain `{` will\n * over-count). False positives are an acceptable tradeoff for v1\n * because (a) the depth threshold is well above legitimate query\n * shapes, (b) a real GraphQL parser pulls in `graphql` as a runtime\n * dep — significant for a sanitizer that ships in every Arcis\n * install. Customers running queries near the threshold can either\n * raise `maxDepth` or bring their own AST pre-pass.\n *\n * NOT included in v1:\n * - Field-count limit (some servers have this; orthogonal to depth)\n * - Alias-bomb detection (`q { f1: foo, f2: foo, ...}` — easier as\n * a length-check than a parse)\n * - Variable rebinding attacks\n *\n * Each is a follow-up if customers ask. Documented inline.\n */\n\nexport interface GraphqlGuardOptions {\n /** Maximum allowed nesting depth. Default: 10. Most legit queries are <8. */\n maxDepth?: number;\n /** Maximum query string length in characters. Default: 10000. */\n maxLength?: number;\n /**\n * Block introspection queries (`__schema`, `__type`). Default: true.\n * Set `false` in development if you rely on GraphiQL / Apollo\n * Studio. Production should leave this on.\n */\n blockIntrospection?: boolean;\n}\n\nexport type GraphqlViolation = 'depth' | 'length' | 'introspection';\n\nexport interface GraphqlGuardResult {\n /** True if the query violated any configured limit. */\n blocked: boolean;\n /** Which limit fired first (depth → introspection → length precedence). */\n reason?: GraphqlViolation;\n /** Observed nesting depth. Always returned, even on clean queries. */\n depth: number;\n /** Observed length. Always returned. */\n length: number;\n}\n\nconst DEFAULTS = {\n maxDepth: 10,\n maxLength: 10000,\n blockIntrospection: true,\n} as const;\n\n/**\n * Word-boundary `__` reflection markers. GraphQL spec reserves the\n * `__` prefix for introspection — `__schema`, `__type`, `__typename`,\n * `__typeKind`, `__directive`. Matching the prefix catches them all\n * without enumerating; the boundary anchor (`\\b__`) avoids\n * false-matches on user fields like `last__updated_at`.\n *\n * `__typename` is the one introspection field that's commonly used\n * legitimately (Apollo client requests it on every query). We\n * deliberately let it through by listing the others explicitly.\n */\nconst INTROSPECTION_PATTERN = /\\b__(schema|type|typeKind|directive)\\b/;\n\n/**\n * Compute the maximum nesting depth of a GraphQL query string by\n * counting `{` and `}` runs. Strings inside the query (e.g.\n * `field(arg: \"{...}\")`) inflate this — accepted v1 tradeoff. A\n * future AST-mode implementation lives behind a separate flag.\n */\nfunction computeDepth(query: string): number {\n let depth = 0;\n let max = 0;\n for (let i = 0; i < query.length; i++) {\n const c = query.charCodeAt(i);\n if (c === 123 /* { */) {\n depth++;\n if (depth > max) max = depth;\n } else if (c === 125 /* } */) {\n // Don't go negative on malformed input — clamp at 0.\n if (depth > 0) depth--;\n }\n }\n return max;\n}\n\n/**\n * Inspect a GraphQL query against the configured limits. Returns a\n * structured result; the middleware below uses this directly. Pure\n * function — no I/O, no res handle.\n */\nexport function inspectGraphqlQuery(\n query: string,\n options: GraphqlGuardOptions = {},\n): GraphqlGuardResult {\n const maxDepth = options.maxDepth ?? DEFAULTS.maxDepth;\n const maxLength = options.maxLength ?? DEFAULTS.maxLength;\n const blockIntrospection = options.blockIntrospection ?? DEFAULTS.blockIntrospection;\n\n const length = query.length;\n const depth = computeDepth(query);\n\n // Precedence: depth > introspection > length. Depth is the most\n // expensive to surface (caller wants to know the actual number);\n // introspection is the most security-critical signal so beats\n // length; length last because it's the easiest false-positive\n // (long queries with deep inline fragments are legitimate).\n if (depth > maxDepth) {\n return { blocked: true, reason: 'depth', depth, length };\n }\n if (blockIntrospection && INTROSPECTION_PATTERN.test(query)) {\n return { blocked: true, reason: 'introspection', depth, length };\n }\n if (length > maxLength) {\n return { blocked: true, reason: 'length', depth, length };\n }\n\n return { blocked: false, depth, length };\n}\n\n/**\n * Detect-only API matching the rest of the sanitizer module surface\n * (`detectXss` / `detectSql` / `detectXxe` / etc.). Returns a boolean\n * for callers that just want a yes/no — use `inspectGraphqlQuery` if\n * you need the structured reason.\n */\nexport function detectGraphqlAbuse(\n query: string,\n options?: GraphqlGuardOptions,\n): boolean {\n if (typeof query !== 'string' || query.length === 0) return false;\n return inspectGraphqlQuery(query, options).blocked;\n}\n"]}