acrylblends 0.3.0 → 0.4.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 (315) hide show
  1. package/dist/index.d.ts +6 -1
  2. package/dist/index.js +28 -3
  3. package/dist/index.js.map +1 -1
  4. package/package.json +1 -1
  5. package/plugins/acryl-inspect/plugin.json +2 -1
  6. package/plugins/acryl-inspect/src/report.ts +16 -13
  7. package/plugins/acryl-inspect/src/service.ts +9 -7
  8. package/plugins/acryl-inspect/tests/report.spec.ts +7 -8
  9. package/plugins/acryl-inspect/tests/service.spec.ts +11 -10
  10. package/plugins/acryl-inspect/upstream.json +2 -2
  11. package/plugins/acryl-node-server/LICENSE +26 -0
  12. package/plugins/acryl-node-server/plugin.json +2 -1
  13. package/plugins/acryl-node-server/src/adapter/conninfo.ts +23 -0
  14. package/plugins/acryl-node-server/src/adapter/early-hints.ts +55 -0
  15. package/plugins/acryl-node-server/src/adapter/error.ts +11 -0
  16. package/plugins/acryl-node-server/src/adapter/headers.ts +249 -0
  17. package/plugins/acryl-node-server/src/adapter/index.ts +6 -0
  18. package/plugins/acryl-node-server/src/adapter/listener.ts +540 -0
  19. package/plugins/acryl-node-server/src/adapter/request.ts +797 -0
  20. package/plugins/acryl-node-server/src/adapter/response.ts +186 -0
  21. package/plugins/acryl-node-server/src/adapter/serve-static.ts +238 -0
  22. package/plugins/acryl-node-server/src/adapter/server.ts +36 -0
  23. package/plugins/acryl-node-server/src/adapter/types.ts +82 -0
  24. package/plugins/acryl-node-server/src/adapter/url.ts +42 -0
  25. package/plugins/acryl-node-server/src/adapter/utils/response/constants.ts +1 -0
  26. package/plugins/acryl-node-server/src/adapter/utils/response.ts +4 -0
  27. package/plugins/acryl-node-server/src/adapter/utils/stream.ts +88 -0
  28. package/plugins/acryl-node-server/src/adapter/utils.ts +96 -0
  29. package/plugins/acryl-node-server/src/adapter/websocket-types.ts +45 -0
  30. package/plugins/acryl-node-server/src/adapter/websocket.ts +375 -0
  31. package/plugins/acryl-node-server/src/index.ts +19 -6
  32. package/plugins/acryl-node-server/tests/adapter/app.ts +76 -0
  33. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +1 -0
  34. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  35. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +1 -0
  36. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -0
  37. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +1 -0
  38. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +5 -0
  39. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +1 -0
  40. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  41. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -0
  42. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +1 -0
  43. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +1 -0
  44. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +1 -0
  45. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +1 -0
  46. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +1 -0
  47. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +1 -0
  48. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +1 -0
  49. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +34 -0
  50. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +248 -0
  51. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +457 -0
  52. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +23 -0
  53. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +27 -0
  54. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +252 -0
  55. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +190 -0
  56. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +727 -0
  57. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +189 -0
  58. package/plugins/acryl-node-server/tests/adapter/request.test.ts +1230 -0
  59. package/plugins/acryl-node-server/tests/adapter/response.test.ts +285 -0
  60. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +849 -0
  61. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +790 -0
  62. package/plugins/acryl-node-server/tests/adapter/server.test.ts +1302 -0
  63. package/plugins/acryl-node-server/tests/adapter/setup.ts +16 -0
  64. package/plugins/acryl-node-server/tests/adapter/url.test.ts +76 -0
  65. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +23 -0
  66. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +75 -0
  67. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +235 -0
  68. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +260 -0
  69. package/plugins/acryl-node-server/tests/server.spec.ts +44 -8
  70. package/plugins/acryl-node-server/upstream.json +3 -3
  71. package/plugins/acryl-router/LICENSE +26 -0
  72. package/plugins/acryl-router/plugin.json +2 -1
  73. package/plugins/acryl-router/src/client.ts +2 -0
  74. package/plugins/acryl-router/src/connection.ts +42 -0
  75. package/plugins/acryl-router/src/core/app-base.ts +544 -0
  76. package/plugins/acryl-router/src/core/app.test.ts +3833 -0
  77. package/plugins/acryl-router/src/core/app.ts +34 -0
  78. package/plugins/acryl-router/src/core/client/client.test.ts +2313 -0
  79. package/plugins/acryl-router/src/core/client/client.ts +249 -0
  80. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +95 -0
  81. package/plugins/acryl-router/src/core/client/index.ts +17 -0
  82. package/plugins/acryl-router/src/core/client/types.test.ts +149 -0
  83. package/plugins/acryl-router/src/core/client/types.ts +393 -0
  84. package/plugins/acryl-router/src/core/client/utils.test.ts +405 -0
  85. package/plugins/acryl-router/src/core/client/utils.ts +117 -0
  86. package/plugins/acryl-router/src/core/compose.test.ts +751 -0
  87. package/plugins/acryl-router/src/core/compose.ts +73 -0
  88. package/plugins/acryl-router/src/core/context.test.ts +629 -0
  89. package/plugins/acryl-router/src/core/context.ts +781 -0
  90. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +344 -0
  91. package/plugins/acryl-router/src/core/helper/accepts/accepts.ts +96 -0
  92. package/plugins/acryl-router/src/core/helper/accepts/index.ts +6 -0
  93. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +55 -0
  94. package/plugins/acryl-router/src/core/helper/adapter/index.ts +90 -0
  95. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +6 -0
  96. package/plugins/acryl-router/src/core/helper/conninfo/types.ts +45 -0
  97. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +510 -0
  98. package/plugins/acryl-router/src/core/helper/cookie/index.ts +146 -0
  99. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +434 -0
  100. package/plugins/acryl-router/src/core/helper/factory/index.ts +375 -0
  101. package/plugins/acryl-router/src/core/helper/html/index.test.ts +78 -0
  102. package/plugins/acryl-router/src/core/helper/html/index.ts +57 -0
  103. package/plugins/acryl-router/src/core/helper/route/index.test.ts +259 -0
  104. package/plugins/acryl-router/src/core/helper/route/index.ts +144 -0
  105. package/plugins/acryl-router/src/core/helper/streaming/index.ts +9 -0
  106. package/plugins/acryl-router/src/core/helper/streaming/sse.ts +101 -0
  107. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +128 -0
  108. package/plugins/acryl-router/src/core/helper/streaming/stream.ts +45 -0
  109. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +34 -0
  110. package/plugins/acryl-router/src/core/helper/streaming/text.ts +15 -0
  111. package/plugins/acryl-router/src/core/helper/streaming/utils.ts +11 -0
  112. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +42 -0
  113. package/plugins/acryl-router/src/core/helper/testing/index.ts +28 -0
  114. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +124 -0
  115. package/plugins/acryl-router/src/core/helper/websocket/index.ts +140 -0
  116. package/plugins/acryl-router/src/core/http-exception.test.ts +45 -0
  117. package/plugins/acryl-router/src/core/http-exception.ts +77 -0
  118. package/plugins/acryl-router/src/core/index.ts +53 -0
  119. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +434 -0
  120. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +152 -0
  121. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +1018 -0
  122. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +220 -0
  123. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +273 -0
  124. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +110 -0
  125. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +355 -0
  126. package/plugins/acryl-router/src/core/middleware/combine/index.ts +171 -0
  127. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +535 -0
  128. package/plugins/acryl-router/src/core/middleware/compress/index.ts +142 -0
  129. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +43 -0
  130. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +58 -0
  131. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +532 -0
  132. package/plugins/acryl-router/src/core/middleware/cors/index.ts +163 -0
  133. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +534 -0
  134. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +150 -0
  135. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +21 -0
  136. package/plugins/acryl-router/src/core/middleware/etag/digest.ts +95 -0
  137. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +503 -0
  138. package/plugins/acryl-router/src/core/middleware/etag/index.ts +135 -0
  139. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +217 -0
  140. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +278 -0
  141. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +1135 -0
  142. package/plugins/acryl-router/src/core/middleware/jwk/index.ts +1 -0
  143. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +195 -0
  144. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +48 -0
  145. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +802 -0
  146. package/plugins/acryl-router/src/core/middleware/jwt/index.ts +9 -0
  147. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +189 -0
  148. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +552 -0
  149. package/plugins/acryl-router/src/core/middleware/language/index.ts +12 -0
  150. package/plugins/acryl-router/src/core/middleware/language/language.ts +314 -0
  151. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +204 -0
  152. package/plugins/acryl-router/src/core/middleware/logger/index.ts +95 -0
  153. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +292 -0
  154. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +141 -0
  155. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +221 -0
  156. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +147 -0
  157. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +37 -0
  158. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +35 -0
  159. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +218 -0
  160. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +67 -0
  161. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +168 -0
  162. package/plugins/acryl-router/src/core/middleware/request-id/index.ts +7 -0
  163. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +59 -0
  164. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +671 -0
  165. package/plugins/acryl-router/src/core/middleware/secure-headers/index.ts +8 -0
  166. package/plugins/acryl-router/src/core/middleware/secure-headers/permissions-policy.ts +101 -0
  167. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +340 -0
  168. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +450 -0
  169. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +135 -0
  170. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +50 -0
  171. package/plugins/acryl-router/src/core/middleware/serve-static/path.ts +25 -0
  172. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +70 -0
  173. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +58 -0
  174. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +310 -0
  175. package/plugins/acryl-router/src/core/middleware/timing/index.ts +8 -0
  176. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +256 -0
  177. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +381 -0
  178. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +156 -0
  179. package/plugins/acryl-router/src/core/request/constants.ts +1 -0
  180. package/plugins/acryl-router/src/core/request.test.ts +751 -0
  181. package/plugins/acryl-router/src/core/request.ts +502 -0
  182. package/plugins/acryl-router/src/core/router/common.case.test.ts +1132 -0
  183. package/plugins/acryl-router/src/core/router/linear-router/index.ts +6 -0
  184. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +80 -0
  185. package/plugins/acryl-router/src/core/router/linear-router/router.ts +152 -0
  186. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +6 -0
  187. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +46 -0
  188. package/plugins/acryl-router/src/core/router/pattern-router/router.ts +54 -0
  189. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +7 -0
  190. package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.ts +33 -0
  191. package/plugins/acryl-router/src/core/router/reg-exp-router/node.ts +170 -0
  192. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +154 -0
  193. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.ts +165 -0
  194. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +265 -0
  195. package/plugins/acryl-router/src/core/router/reg-exp-router/router.ts +174 -0
  196. package/plugins/acryl-router/src/core/router/reg-exp-router/trie.ts +84 -0
  197. package/plugins/acryl-router/src/core/router/smart-router/index.ts +6 -0
  198. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +13 -0
  199. package/plugins/acryl-router/src/core/router/smart-router/router.ts +70 -0
  200. package/plugins/acryl-router/src/core/router/trie-router/index.ts +6 -0
  201. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +896 -0
  202. package/plugins/acryl-router/src/core/router/trie-router/node.ts +221 -0
  203. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +8 -0
  204. package/plugins/acryl-router/src/core/router/trie-router/router.ts +18 -0
  205. package/plugins/acryl-router/src/core/router/utils.ts +1 -0
  206. package/plugins/acryl-router/src/core/router.ts +103 -0
  207. package/plugins/acryl-router/src/core/types.test.ts +4134 -0
  208. package/plugins/acryl-router/src/core/types.ts +2782 -0
  209. package/plugins/acryl-router/src/core/utils/accept.test.ts +299 -0
  210. package/plugins/acryl-router/src/core/utils/accept.ts +268 -0
  211. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +56 -0
  212. package/plugins/acryl-router/src/core/utils/basic-auth.ts +26 -0
  213. package/plugins/acryl-router/src/core/utils/body.test.ts +496 -0
  214. package/plugins/acryl-router/src/core/utils/body.ts +263 -0
  215. package/plugins/acryl-router/src/core/utils/buffer.test.ts +147 -0
  216. package/plugins/acryl-router/src/core/utils/buffer.ts +117 -0
  217. package/plugins/acryl-router/src/core/utils/color.test.ts +23 -0
  218. package/plugins/acryl-router/src/core/utils/color.ts +56 -0
  219. package/plugins/acryl-router/src/core/utils/compress.ts +10 -0
  220. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +69 -0
  221. package/plugins/acryl-router/src/core/utils/concurrent.ts +55 -0
  222. package/plugins/acryl-router/src/core/utils/constants.ts +4 -0
  223. package/plugins/acryl-router/src/core/utils/cookie.test.ts +460 -0
  224. package/plugins/acryl-router/src/core/utils/cookie.ts +281 -0
  225. package/plugins/acryl-router/src/core/utils/crypto.test.ts +43 -0
  226. package/plugins/acryl-router/src/core/utils/crypto.ts +58 -0
  227. package/plugins/acryl-router/src/core/utils/encode.test.ts +61 -0
  228. package/plugins/acryl-router/src/core/utils/encode.ts +34 -0
  229. package/plugins/acryl-router/src/core/utils/filepath.test.ts +78 -0
  230. package/plugins/acryl-router/src/core/utils/filepath.ts +60 -0
  231. package/plugins/acryl-router/src/core/utils/handler.ts +15 -0
  232. package/plugins/acryl-router/src/core/utils/headers.ts +355 -0
  233. package/plugins/acryl-router/src/core/utils/html.test.ts +16 -0
  234. package/plugins/acryl-router/src/core/utils/html.ts +182 -0
  235. package/plugins/acryl-router/src/core/utils/http-status.ts +72 -0
  236. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +149 -0
  237. package/plugins/acryl-router/src/core/utils/ipaddr.ts +374 -0
  238. package/plugins/acryl-router/src/core/utils/jwt/index.ts +7 -0
  239. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +86 -0
  240. package/plugins/acryl-router/src/core/utils/jwt/jwa.ts +38 -0
  241. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +235 -0
  242. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +1788 -0
  243. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +292 -0
  244. package/plugins/acryl-router/src/core/utils/jwt/types.ts +157 -0
  245. package/plugins/acryl-router/src/core/utils/jwt/utf8.ts +7 -0
  246. package/plugins/acryl-router/src/core/utils/mime.test.ts +64 -0
  247. package/plugins/acryl-router/src/core/utils/mime.ts +94 -0
  248. package/plugins/acryl-router/src/core/utils/stream.test.ts +212 -0
  249. package/plugins/acryl-router/src/core/utils/stream.ts +107 -0
  250. package/plugins/acryl-router/src/core/utils/types.test.ts +295 -0
  251. package/plugins/acryl-router/src/core/utils/types.ts +123 -0
  252. package/plugins/acryl-router/src/core/utils/url.test.ts +384 -0
  253. package/plugins/acryl-router/src/core/utils/url.ts +337 -0
  254. package/plugins/acryl-router/src/core/validator/index.ts +8 -0
  255. package/plugins/acryl-router/src/core/validator/utils.test.ts +82 -0
  256. package/plugins/acryl-router/src/core/validator/utils.ts +69 -0
  257. package/plugins/acryl-router/src/core/validator/validator.test.ts +1488 -0
  258. package/plugins/acryl-router/src/core/validator/validator.ts +185 -0
  259. package/plugins/acryl-router/src/helpers/index.ts +13 -3
  260. package/plugins/acryl-router/src/helpers/schema-validator.ts +35 -0
  261. package/plugins/acryl-router/src/index.ts +6 -6
  262. package/plugins/acryl-router/src/middleware/index.ts +25 -6
  263. package/plugins/acryl-router/src/middleware/loopback-only.ts +19 -13
  264. package/plugins/acryl-router/src/service.ts +256 -64
  265. package/plugins/acryl-router/tests/docs-examples.spec.ts +152 -0
  266. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  267. package/plugins/acryl-router/tests/loader.spec.ts +3 -2
  268. package/plugins/acryl-router/tests/service.spec.ts +264 -66
  269. package/plugins/acryl-router/tests/shadow-state.spec.ts +79 -0
  270. package/plugins/acryl-router/upstream.json +2 -2
  271. package/plugins/acryl-router-http/plugin.json +2 -1
  272. package/plugins/acryl-router-http/src/bridge.ts +3 -1
  273. package/plugins/acryl-router-http/tests/adapter.spec.ts +16 -12
  274. package/plugins/acryl-router-http/tests/surfaces.spec.ts +12 -10
  275. package/plugins/acryl-router-http/upstream.json +3 -3
  276. package/plugins/acryl-state/NOTICE +30 -0
  277. package/plugins/acryl-state/plugin.json +1 -1
  278. package/plugins/acryl-state/src/cell.ts +1 -1
  279. package/plugins/acryl-state/src/service.ts +33 -15
  280. package/plugins/acryl-state/upstream.json +6 -4
  281. package/plugins/builder/script.ts +4 -7
  282. package/plugins/extensions/index.ts +2 -2
  283. package/plugins/extensions/resolve.ts +28 -3
  284. package/plugins/openai/prompt.ts +9 -7
  285. package/plugins/tsconfig.json +5 -4
  286. package/templates/agent/src/routes.ts +37 -27
  287. package/templates/agent/test/model.test.ts +2 -1
  288. package/templates/agent/tsconfig.json +8 -5
  289. package/templates/blank/src/routes.ts +6 -4
  290. package/templates/blank/tsconfig.json +2 -4
  291. package/templates/todo/src/page.ts +1 -1
  292. package/templates/todo/src/todo.ts +56 -29
  293. package/templates/todo/tsconfig.json +2 -4
  294. package/templates/todo/upstream.json +2 -2
  295. package/plugins/acryl-router/src/compose.ts +0 -21
  296. package/plugins/acryl-router/src/context.ts +0 -59
  297. package/plugins/acryl-router/src/helpers/read-body.ts +0 -59
  298. package/plugins/acryl-router/src/helpers/sse.ts +0 -83
  299. package/plugins/acryl-router/src/helpers/validate.ts +0 -44
  300. package/plugins/acryl-router/src/http-error.ts +0 -21
  301. package/plugins/acryl-router/src/middleware/body-limit.ts +0 -25
  302. package/plugins/acryl-router/src/middleware/cors.ts +0 -46
  303. package/plugins/acryl-router/src/middleware/logger.ts +0 -21
  304. package/plugins/acryl-router/src/middleware/request-id.ts +0 -24
  305. package/plugins/acryl-router/src/middleware/secure-headers.ts +0 -23
  306. package/plugins/acryl-router/src/pattern.ts +0 -89
  307. package/plugins/acryl-router/src/registrar.ts +0 -90
  308. package/plugins/acryl-router/src/table.ts +0 -156
  309. package/plugins/acryl-router/src/types.ts +0 -73
  310. package/plugins/acryl-router/src/util.ts +0 -23
  311. package/plugins/acryl-router/tests/api.spec.ts +0 -223
  312. package/plugins/acryl-router/tests/conformance.ts +0 -170
  313. package/plugins/acryl-router/tests/helpers.spec.ts +0 -172
  314. package/plugins/acryl-router/tests/middleware.spec.ts +0 -183
  315. package/plugins/acryl-router/tests/table.spec.ts +0 -47
@@ -0,0 +1,217 @@
1
+ import { ipRestriction } from './index.ts'
2
+ import type { IPRestrictionRule } from './index.ts'
3
+ import { Context } from '../../context.ts'
4
+ import type { AddressType, GetConnInfo } from '../../helper/conninfo/index.ts'
5
+ import { App } from '../../app.ts'
6
+
7
+ describe('ipRestriction middleware', () => {
8
+ it('Should restrict', async () => {
9
+ const getConnInfo: GetConnInfo = (c) => {
10
+ return {
11
+ remote: {
12
+ address: c.env.ip,
13
+ },
14
+ }
15
+ }
16
+ const app = new App<{
17
+ Bindings: {
18
+ ip: string
19
+ }
20
+ }>()
21
+ app.use(
22
+ '/basic',
23
+ ipRestriction(getConnInfo, {
24
+ allowList: ['192.168.1.0', '192.168.2.0/24'],
25
+ denyList: ['192.168.2.10'],
26
+ })
27
+ )
28
+ app.get('/basic', (c) => c.text('Hello World!'))
29
+
30
+ app.use(
31
+ '/allow-empty',
32
+ ipRestriction(getConnInfo, {
33
+ denyList: ['192.168.1.0'],
34
+ })
35
+ )
36
+ app.get('/allow-empty', (c) => c.text('Hello World!'))
37
+
38
+ expect((await app.request('/basic', {}, { ip: '0.0.0.0' })).status).toBe(403)
39
+
40
+ expect((await app.request('/basic', {}, { ip: '192.168.1.0' })).status).toBe(200)
41
+
42
+ expect((await app.request('/basic', {}, { ip: '192.168.2.5' })).status).toBe(200)
43
+ expect((await app.request('/basic', {}, { ip: '192.168.2.10' })).status).toBe(403)
44
+
45
+ expect((await app.request('/allow-empty', {}, { ip: '0.0.0.0' })).status).toBe(200)
46
+
47
+ expect((await app.request('/allow-empty', {}, { ip: '192.168.1.0' })).status).toBe(403)
48
+
49
+ expect((await app.request('/allow-empty', {}, { ip: '192.168.2.5' })).status).toBe(200)
50
+ expect((await app.request('/allow-empty', {}, { ip: '192.168.2.10' })).status).toBe(200)
51
+ })
52
+ it('Custom onerror', async () => {
53
+ const res = await ipRestriction(
54
+ () => '0.0.0.0',
55
+ { denyList: ['0.0.0.0'] },
56
+ () => new Response('error')
57
+ )(new Context(new Request('http://localhost/')), async () => void 0)
58
+ expect(res).toBeTruthy()
59
+ if (res) {
60
+ expect(await res.text()).toBe('error')
61
+ }
62
+ })
63
+
64
+ test.each(['999.999.999.999', '2001:db8::1%eth0', '1234:::5678'])(
65
+ 'Should reject invalid remote address: %s',
66
+ async (ip) => {
67
+ const app = new App<{
68
+ Bindings: {
69
+ ip: string
70
+ }
71
+ }>()
72
+ app.use(
73
+ '/invalid',
74
+ ipRestriction(
75
+ (c) => ({
76
+ remote: {
77
+ address: c.env.ip,
78
+ },
79
+ }),
80
+ {
81
+ allowList: ['127.0.0.1'],
82
+ }
83
+ )
84
+ )
85
+ app.get('/invalid', (c) => c.text('Hello World!'))
86
+
87
+ expect((await app.request('/invalid', {}, { ip })).status).toBe(403)
88
+ }
89
+ )
90
+
91
+ it('Should not call onError for invalid remote addresses', async () => {
92
+ const app = new App<{
93
+ Bindings: {
94
+ ip: string
95
+ }
96
+ }>()
97
+ app.use(
98
+ '/invalid',
99
+ ipRestriction(
100
+ (c) => ({
101
+ remote: {
102
+ address: c.env.ip,
103
+ },
104
+ }),
105
+ {
106
+ allowList: ['127.0.0.1'],
107
+ },
108
+ () => new Response('custom error', { status: 418 })
109
+ )
110
+ )
111
+ app.get('/invalid', (c) => c.text('Hello World!'))
112
+
113
+ const res = await app.request('/invalid', {}, { ip: '1234:::5678' })
114
+ expect(res.status).toBe(403)
115
+ expect(await res.text()).toBe('Forbidden')
116
+ })
117
+ })
118
+
119
+ describe('isMatchForRule', () => {
120
+ const isMatch = async (info: { addr: string; type: AddressType }, rule: IPRestrictionRule) => {
121
+ const middleware = ipRestriction(
122
+ () => ({
123
+ remote: {
124
+ address: info.addr,
125
+ addressType: info.type,
126
+ },
127
+ }),
128
+ {
129
+ allowList: [rule],
130
+ }
131
+ )
132
+ try {
133
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
+ await middleware(undefined as any, () => Promise.resolve())
135
+ } catch {
136
+ return false
137
+ }
138
+ return true
139
+ }
140
+
141
+ test.each(['192.168.0.0/33', '::/129', '127.0.0.1/', '::ffff:127.0.0.1/129'])(
142
+ 'Should throw for invalid CIDR rule: %s',
143
+ (rule) => {
144
+ expect(() =>
145
+ ipRestriction(() => '127.0.0.1', {
146
+ allowList: [rule],
147
+ })
148
+ ).toThrow(`Invalid rule: ${rule}`)
149
+ }
150
+ )
151
+
152
+ it('star', async () => {
153
+ expect(await isMatch({ addr: '192.168.2.0', type: 'IPv4' }, '*')).toBeTruthy()
154
+ expect(await isMatch({ addr: '192.168.2.1', type: 'IPv4' }, '*')).toBeTruthy()
155
+ expect(await isMatch({ addr: '::0', type: 'IPv6' }, '*')).toBeTruthy()
156
+ })
157
+ it('CIDR Notation', async () => {
158
+ expect(await isMatch({ addr: '192.168.2.0', type: 'IPv4' }, '192.168.2.0/24')).toBeTruthy()
159
+ expect(await isMatch({ addr: '192.168.2.1', type: 'IPv4' }, '192.168.2.0/24')).toBeTruthy()
160
+ expect(await isMatch({ addr: '192.168.2.1', type: 'IPv4' }, '192.168.2.1/32')).toBeTruthy()
161
+ expect(await isMatch({ addr: '192.168.2.1', type: 'IPv4' }, '192.168.2.2/32')).toBeFalsy()
162
+
163
+ expect(await isMatch({ addr: '::0', type: 'IPv6' }, '::0/1')).toBeTruthy()
164
+ expect(await isMatch({ addr: '::1', type: 'IPv6' }, '0.0.0.0/24')).toBeFalsy()
165
+ expect(await isMatch({ addr: '::abcd:1', type: 'IPv6' }, '127.0.0.0/8')).toBeFalsy()
166
+ expect(await isMatch({ addr: '::1', type: 'IPv6' }, '::ffff:1.0.0.0/96')).toBeFalsy()
167
+
168
+ expect(
169
+ await isMatch({ addr: '::ffff:192.168.1.1', type: 'IPv6' }, '::ffff:192.168.1.0/120')
170
+ ).toBeTruthy()
171
+ expect(
172
+ await isMatch({ addr: '192.168.1.1', type: 'IPv4' }, '::ffff:192.168.1.0/120')
173
+ ).toBeTruthy()
174
+ expect(
175
+ await isMatch({ addr: '::ffff:192.168.1.1', type: 'IPv6' }, '192.168.1.0/24')
176
+ ).toBeTruthy()
177
+ expect(await isMatch({ addr: '::ffff:10.0.0.1', type: 'IPv6' }, '192.168.1.0/24')).toBeFalsy()
178
+ expect(await isMatch({ addr: '::ffff:192.168.1.1', type: 'IPv6' }, '::/0')).toBeTruthy()
179
+ expect(
180
+ await isMatch({ addr: '::ffff:192.168.1.1', type: 'IPv6' }, '::ffff:0:0/95')
181
+ ).toBeTruthy()
182
+ })
183
+ it('Static Rules', async () => {
184
+ expect(await isMatch({ addr: '192.168.2.1', type: 'IPv4' }, '192.168.2.1')).toBeTruthy()
185
+ expect(await isMatch({ addr: '1234::5678', type: 'IPv6' }, '1234::5678')).toBeTruthy()
186
+ expect(
187
+ await isMatch({ addr: '::ffff:127.0.0.1', type: 'IPv6' }, '::ffff:127.0.0.1')
188
+ ).toBeTruthy()
189
+ expect(await isMatch({ addr: '::ffff:127.0.0.1', type: 'IPv6' }, '::ffff:7f00:1')).toBeTruthy()
190
+ expect(await isMatch({ addr: '127.0.0.1', type: 'IPv4' }, '::ffff:127.0.0.1')).toBeTruthy()
191
+ // IPv4-mapped IPv6 addresses are canonicalized to IPv4
192
+ expect(await isMatch({ addr: '::ffff:127.0.0.1', type: 'IPv6' }, '127.0.0.1')).toBeTruthy()
193
+ expect(await isMatch({ addr: '::ffff:127.0.0.1', type: 'IPv6' }, '127.0.0.2')).toBeFalsy()
194
+ expect(await isMatch({ addr: '::ffff:7f00:1', type: 'IPv6' }, '127.0.0.1')).toBeTruthy()
195
+ expect(await isMatch({ addr: '0:0:0:0:0:ffff:7f00:1', type: 'IPv6' }, '127.0.0.1')).toBeTruthy()
196
+ // regular IPv6 is matched numerically without being treated as IPv4
197
+ expect(await isMatch({ addr: '::1', type: 'IPv6' }, '::1')).toBeTruthy()
198
+ expect(
199
+ await isMatch({ addr: '2001:db8:0:0:0:0:0:1', type: 'IPv6' }, '2001:db8::1')
200
+ ).toBeTruthy()
201
+ expect(
202
+ await isMatch({ addr: '2001:db8::1', type: 'IPv6' }, '2001:db8:0:0:0:0:0:1')
203
+ ).toBeTruthy()
204
+ expect(await isMatch({ addr: '::ffff:127.0.0.2', type: 'IPv6' }, '127.0.0.1')).toBeFalsy()
205
+ expect(await isMatch({ addr: '::7f00:1', type: 'IPv6' }, '127.0.0.1')).toBeFalsy()
206
+ })
207
+ it('Function Rules', async () => {
208
+ expect(await isMatch({ addr: '0.0.0.0', type: 'IPv4' }, () => true)).toBeTruthy()
209
+ expect(await isMatch({ addr: '0.0.0.0', type: 'IPv4' }, () => false)).toBeFalsy()
210
+
211
+ const ipaddr = '93.184.216.34'
212
+ await isMatch({ addr: ipaddr, type: 'IPv4' }, (ip) => {
213
+ expect(ipaddr).toBe(ip.addr)
214
+ return false
215
+ })
216
+ })
217
+ })
@@ -0,0 +1,278 @@
1
+ /**
2
+ * IP Restriction Middleware for App
3
+ * @module
4
+ */
5
+
6
+ import type { Context, MiddlewareHandler } from '../../index.ts'
7
+ import type { AddressType, GetConnInfo } from '../../helper/conninfo/index.ts'
8
+ import { HTTPException } from '../../http-exception.ts'
9
+ import type { InvalidIPAddressError } from '../../utils/ipaddr.ts'
10
+ import {
11
+ convertIPv4MappedIPv6ToIPv4,
12
+ convertIPv4ToBinary,
13
+ convertIPv6BinaryToString,
14
+ convertIPv6ToBinary,
15
+ distinctRemoteAddr,
16
+ isIPv4MappedIPv6,
17
+ INVALID_IP_ADDRESS_ERROR_CODE,
18
+ } from '../../utils/ipaddr.ts'
19
+
20
+ /**
21
+ * Function to get IP Address
22
+ */
23
+ type GetIPAddr = GetConnInfo | ((c: Context) => string)
24
+
25
+ /**
26
+ * ### IPv4 and IPv6
27
+ * - `*` match all
28
+ *
29
+ * ### IPv4
30
+ * - `192.168.2.0` static
31
+ * - `192.168.2.0/24` CIDR Notation
32
+ *
33
+ * ### IPv6
34
+ * - `::1` static
35
+ * - `::1/10` CIDR Notation
36
+ */
37
+ type IPRestrictionRuleFunction = (addr: { addr: string; type: AddressType }) => boolean
38
+ export type IPRestrictionRule = string | ((addr: { addr: string; type: AddressType }) => boolean)
39
+
40
+ const IS_CIDR_NOTATION_REGEX = /\/[^/]*$/
41
+ const parseCidrPrefix = (rule: string, prefix: string, max: number): number => {
42
+ if (!/^[0-9]{1,3}$/.test(prefix)) {
43
+ throw new TypeError(`Invalid rule: ${rule}`)
44
+ }
45
+ const parsedPrefix = parseInt(prefix)
46
+ if (parsedPrefix > max) {
47
+ throw new TypeError(`Invalid rule: ${rule}`)
48
+ }
49
+ return parsedPrefix
50
+ }
51
+ const buildMatcher = (
52
+ rules: IPRestrictionRule[]
53
+ ): ((addr: { addr: string; type: AddressType; isIPv4: boolean }) => boolean) => {
54
+ const functionRules: IPRestrictionRuleFunction[] = []
55
+ const staticRules: Set<string> = new Set()
56
+ const staticIPv4Rules: Set<bigint> = new Set()
57
+ const staticIPv6Rules: Set<bigint> = new Set()
58
+ const cidrRules: [boolean, bigint, bigint][] = []
59
+ const registerStaticRule = (rule: string): void => {
60
+ const type = distinctRemoteAddr(rule)
61
+ if (type === undefined) {
62
+ throw new TypeError(`Invalid rule: ${rule}`)
63
+ }
64
+ if (type === 'IPv4') {
65
+ const ipv4binary = convertIPv4ToBinary(rule)
66
+ staticRules.add(rule)
67
+ staticRules.add(`::ffff:${rule}`)
68
+ staticIPv4Rules.add(ipv4binary)
69
+ staticIPv6Rules.add((0xffffn << 32n) | ipv4binary)
70
+ } else {
71
+ const ipv6binary = convertIPv6ToBinary(rule)
72
+ const ipv6Addr = convertIPv6BinaryToString(ipv6binary)
73
+ staticRules.add(ipv6Addr)
74
+ staticIPv6Rules.add(ipv6binary)
75
+ if (isIPv4MappedIPv6(ipv6binary)) {
76
+ staticRules.add(ipv6Addr.substring(7)) // remove ::ffff: prefix
77
+ staticIPv4Rules.add(convertIPv4MappedIPv6ToIPv4(ipv6binary))
78
+ }
79
+ }
80
+ }
81
+
82
+ for (let rule of rules) {
83
+ if (rule === '*') {
84
+ return () => true
85
+ } else if (typeof rule === 'function') {
86
+ functionRules.push(rule)
87
+ } else {
88
+ if (IS_CIDR_NOTATION_REGEX.test(rule)) {
89
+ const separatedRule = rule.split('/')
90
+
91
+ const addrStr = separatedRule[0]
92
+ const type = distinctRemoteAddr(addrStr)
93
+ if (type === undefined) {
94
+ throw new TypeError(`Invalid rule: ${rule}`)
95
+ }
96
+
97
+ let isIPv4 = type === 'IPv4'
98
+ let prefix = parseCidrPrefix(rule, separatedRule[1], isIPv4 ? 32 : 128)
99
+
100
+ if (isIPv4 ? prefix === 32 : prefix === 128) {
101
+ // this rule is a static rule
102
+ rule = addrStr
103
+ } else {
104
+ let addr = (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(addrStr)
105
+ if (type === 'IPv6' && isIPv4MappedIPv6(addr) && prefix >= 96) {
106
+ isIPv4 = true
107
+ addr = convertIPv4MappedIPv6ToIPv4(addr)
108
+ prefix -= 96
109
+ }
110
+
111
+ const mask = ((1n << BigInt(prefix)) - 1n) << BigInt((isIPv4 ? 32 : 128) - prefix)
112
+
113
+ cidrRules.push([isIPv4, addr & mask, mask] as [boolean, bigint, bigint])
114
+ continue
115
+ }
116
+ }
117
+
118
+ registerStaticRule(rule)
119
+ }
120
+ }
121
+
122
+ return (remote: {
123
+ addr: string
124
+ type: AddressType
125
+ isIPv4: boolean
126
+ binaryAddr?: bigint
127
+ }): boolean => {
128
+ if (staticRules.has(remote.addr)) {
129
+ return true
130
+ }
131
+ const remoteAddr = (remote.binaryAddr ||= (
132
+ remote.isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary
133
+ )(remote.addr))
134
+ const remoteIPv4Addr =
135
+ remote.isIPv4 || isIPv4MappedIPv6(remoteAddr)
136
+ ? remote.isIPv4
137
+ ? remoteAddr
138
+ : convertIPv4MappedIPv6ToIPv4(remoteAddr)
139
+ : undefined
140
+ if ((remote.isIPv4 ? staticIPv4Rules : staticIPv6Rules).has(remoteAddr)) {
141
+ return true
142
+ }
143
+ for (const [isIPv4, addr, mask] of cidrRules) {
144
+ if (isIPv4) {
145
+ if (remoteIPv4Addr === undefined) {
146
+ continue
147
+ }
148
+ if ((remoteIPv4Addr & mask) === addr) {
149
+ return true
150
+ }
151
+ continue
152
+ }
153
+ if (remote.isIPv4) {
154
+ continue
155
+ }
156
+ if ((remoteAddr & mask) === addr) {
157
+ return true
158
+ }
159
+ }
160
+ for (const rule of functionRules) {
161
+ if (rule({ addr: remote.addr, type: remote.type })) {
162
+ return true
163
+ }
164
+ }
165
+ return false
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Rules for IP Restriction Middleware
171
+ */
172
+ export interface IPRestrictionRules {
173
+ denyList?: IPRestrictionRule[]
174
+ allowList?: IPRestrictionRule[]
175
+ }
176
+
177
+ /**
178
+ * IP Restriction Middleware for App.
179
+ *
180
+ *
181
+ * @param {GetConnInfo | ((c: Context) => string)} getIP - A function to retrieve the client IP address. Use `getConnInfo` from the appropriate runtime adapter.
182
+ * @param {IPRestrictionRules} rules - An object with optional `denyList` and `allowList` arrays of IP rules. Each rule can be a static IP, a CIDR range, or a custom function.
183
+ * @param {(remote: { addr: string; type: AddressType }, c: Context) => Response | Promise<Response>} [onError] - Optional custom handler invoked when a request is blocked. Defaults to returning a 403 Forbidden response.
184
+ * @returns {MiddlewareHandler} The middleware handler function.
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * import { App } from 'acryl-router'
189
+ * import { ipRestriction } from 'acryl-router/middleware'
190
+ * import { getConnInfo } from 'acryl-router/helpers'
191
+ *
192
+ * const app = new App()
193
+ *
194
+ * app.use(
195
+ * '*',
196
+ * ipRestriction(getConnInfo, {
197
+ * // Block a specific IP and an entire subnet
198
+ * denyList: ['192.168.0.5', '10.0.0.0/8'],
199
+ * // Only allow requests from localhost and a private range
200
+ * allowList: ['127.0.0.1', '::1', '192.168.1.0/24'],
201
+ * })
202
+ * )
203
+ *
204
+ * // With a custom error handler
205
+ * app.use(
206
+ * '/admin/*',
207
+ * ipRestriction(
208
+ * getConnInfo,
209
+ * { allowList: ['203.0.113.0/24'] },
210
+ * (remote, c) => c.text(`Access denied for ${remote.addr}`, 403)
211
+ * )
212
+ * )
213
+ *
214
+ * app.get('/', (c) => c.text('Hello!'))
215
+ * ```
216
+ */
217
+ export const ipRestriction = (
218
+ getIP: GetIPAddr,
219
+ { denyList = [], allowList = [] }: IPRestrictionRules,
220
+ onError?: (
221
+ remote: { addr: string; type: AddressType },
222
+ c: Context
223
+ ) => Response | Promise<Response>
224
+ ): MiddlewareHandler => {
225
+ const allowLength = allowList.length
226
+
227
+ const denyMatcher = buildMatcher(denyList)
228
+ const allowMatcher = buildMatcher(allowList)
229
+
230
+ const blockError = (c: Context): HTTPException =>
231
+ new HTTPException(403, {
232
+ res: c.text('Forbidden', {
233
+ status: 403,
234
+ }),
235
+ })
236
+
237
+ return async function ipRestriction(c, next) {
238
+ const connInfo = getIP(c)
239
+ const addr = typeof connInfo === 'string' ? connInfo : connInfo.remote.address
240
+ if (!addr) {
241
+ throw blockError(c)
242
+ }
243
+ const type =
244
+ (typeof connInfo !== 'string' && connInfo.remote.addressType) || distinctRemoteAddr(addr)
245
+
246
+ const remoteData = { addr, type, isIPv4: type === 'IPv4' }
247
+
248
+ try {
249
+ if (denyMatcher(remoteData)) {
250
+ if (onError) {
251
+ return onError({ addr, type }, c)
252
+ }
253
+ throw blockError(c)
254
+ }
255
+ if (allowMatcher(remoteData)) {
256
+ return await next()
257
+ }
258
+ } catch (e) {
259
+ if (
260
+ e instanceof TypeError &&
261
+ (e as InvalidIPAddressError).code === INVALID_IP_ADDRESS_ERROR_CODE
262
+ ) {
263
+ // If an invalid IP address is specified, treat it as if no IP address was specified
264
+ throw blockError(c)
265
+ }
266
+ throw e
267
+ }
268
+
269
+ if (allowLength === 0) {
270
+ return await next()
271
+ } else {
272
+ if (onError) {
273
+ return await onError({ addr, type }, c)
274
+ }
275
+ throw blockError(c)
276
+ }
277
+ }
278
+ }