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,405 @@
1
+ import { HttpResponse, http } from 'msw'
2
+ import { setupServer } from 'msw/node'
3
+ import { App } from '../app.ts'
4
+ import type { Expect, Equal } from '../utils/types.ts'
5
+ import { hc } from './client.ts'
6
+ import {
7
+ buildSearchParams,
8
+ deepMerge,
9
+ parseResponse,
10
+ mergePath,
11
+ removeIndexString,
12
+ replaceUrlParam,
13
+ replaceUrlProtocol,
14
+ } from './utils.ts'
15
+
16
+ describe('mergePath', () => {
17
+ it('Should merge paths correctly', () => {
18
+ expect(mergePath('http://localhost', '/api')).toBe('http://localhost/api')
19
+ expect(mergePath('http://localhost/', '/api')).toBe('http://localhost/api')
20
+ expect(mergePath('http://localhost', 'api')).toBe('http://localhost/api')
21
+ expect(mergePath('http://localhost/', 'api')).toBe('http://localhost/api')
22
+ expect(mergePath('http://localhost/', '/')).toBe('http://localhost/')
23
+ })
24
+ })
25
+
26
+ describe('replaceUrlParams', () => {
27
+ it('Should replace correctly', () => {
28
+ const url = 'http://localhost/posts/:postId/comments/:commentId'
29
+ const params = {
30
+ postId: '123',
31
+ commentId: '456',
32
+ }
33
+ const replacedUrl = replaceUrlParam(url, params)
34
+ expect(replacedUrl).toBe('http://localhost/posts/123/comments/456')
35
+ })
36
+
37
+ it('Should replace correctly when there is regex pattern', () => {
38
+ const url = 'http://localhost/posts/:postId{[abc]+}/comments/:commentId{[0-9]+}'
39
+ const params = {
40
+ postId: 'abc',
41
+ commentId: '456',
42
+ }
43
+ const replacedUrl = replaceUrlParam(url, params)
44
+ expect(replacedUrl).toBe('http://localhost/posts/abc/comments/456')
45
+ })
46
+
47
+ it('Should replace correctly when there is regex pattern with length limit', () => {
48
+ const url = 'http://localhost/year/:year{[1-9]{1}[0-9]{3}}/month/:month{[0-9]{2}}'
49
+ const params = {
50
+ year: '2024',
51
+ month: '2',
52
+ }
53
+ const replacedUrl = replaceUrlParam(url, params)
54
+ expect(replacedUrl).toBe('http://localhost/year/2024/month/2')
55
+ })
56
+
57
+ it('Should replace correctly when it has optional parameters', () => {
58
+ const url = 'http://localhost/something/:firstId/:secondId/:version?'
59
+ const params = {
60
+ firstId: '123',
61
+ secondId: '456',
62
+ version: undefined,
63
+ }
64
+ const replacedUrl = replaceUrlParam(url, params)
65
+ expect(replacedUrl).toBe('http://localhost/something/123/456')
66
+ })
67
+
68
+ it('Should not replace a param whose name is a prefix of another param', () => {
69
+ const url = 'http://localhost/:idType/:id'
70
+ const params = {
71
+ id: '1',
72
+ idType: '2',
73
+ }
74
+ const replacedUrl = replaceUrlParam(url, params)
75
+ expect(replacedUrl).toBe('http://localhost/2/1')
76
+ })
77
+
78
+ it('Should replace correctly when parameter value contains $ characters', () => {
79
+ expect(replaceUrlParam('http://localhost/items/:id', { id: 'item$&' })).toBe(
80
+ 'http://localhost/items/item$&'
81
+ )
82
+ expect(replaceUrlParam('http://localhost/items/:id', { id: '$100' })).toBe(
83
+ 'http://localhost/items/$100'
84
+ )
85
+ expect(replaceUrlParam('http://localhost/users/:id', { id: 'test$`' })).toBe(
86
+ 'http://localhost/users/test$`'
87
+ )
88
+ expect(replaceUrlParam('http://localhost/users/:id/posts', { id: "test$'" })).toBe(
89
+ "http://localhost/users/test$'/posts"
90
+ )
91
+ })
92
+ })
93
+
94
+ describe('buildSearchParams', () => {
95
+ it('Should build URLSearchParams correctly', () => {
96
+ const query = {
97
+ id: '123',
98
+ type: 'test',
99
+ tag: ['a', 'b'],
100
+ }
101
+ const searchParams = buildSearchParams(query)
102
+ expect(searchParams.toString()).toBe('id=123&type=test&tag=a&tag=b')
103
+ })
104
+
105
+ it('Should skip an undefined entry inside an array, as it does for a top-level value', () => {
106
+ // `['a', undefined, 'b']` used to serialise as `tag=a&tag=undefined&tag=b`,
107
+ // sending the literal string "undefined" to the server.
108
+ const searchParams = buildSearchParams({
109
+ tag: ['a', undefined as unknown as string, 'b'],
110
+ })
111
+ expect(searchParams.toString()).toBe('tag=a&tag=b')
112
+ })
113
+
114
+ it('Should keep an empty string in an array', () => {
115
+ const searchParams = buildSearchParams({ tag: ['a', '', 'b'] })
116
+ expect(searchParams.toString()).toBe('tag=a&tag=&tag=b')
117
+ })
118
+
119
+ it('Should drop an array whose entries are all undefined', () => {
120
+ const searchParams = buildSearchParams({
121
+ tag: [undefined, undefined] as unknown as string[],
122
+ })
123
+ expect(searchParams.toString()).toBe('')
124
+ })
125
+ })
126
+
127
+ describe('replaceUrlProtocol', () => {
128
+ it('Should replace http to ws', () => {
129
+ const url = 'http://localhost'
130
+ const newUrl = replaceUrlProtocol(url, 'ws')
131
+ expect(newUrl).toBe('ws://localhost')
132
+ })
133
+
134
+ it('Should replace https to wss', () => {
135
+ const url = 'https://localhost'
136
+ const newUrl = replaceUrlProtocol(url, 'ws')
137
+ expect(newUrl).toBe('wss://localhost')
138
+ })
139
+
140
+ it('Should replace ws to http', () => {
141
+ const url = 'ws://localhost'
142
+ const newUrl = replaceUrlProtocol(url, 'http')
143
+ expect(newUrl).toBe('http://localhost')
144
+ })
145
+
146
+ it('Should replace wss to https', () => {
147
+ const url = 'wss://localhost'
148
+ const newUrl = replaceUrlProtocol(url, 'http')
149
+ expect(newUrl).toBe('https://localhost')
150
+ })
151
+ })
152
+
153
+ describe('removeIndexString', () => {
154
+ it('Should remove last `/index` string', () => {
155
+ let url = 'http://localhost/index'
156
+ let newUrl = removeIndexString(url)
157
+ expect(newUrl).toBe('http://localhost/')
158
+
159
+ url = '/index'
160
+ newUrl = removeIndexString(url)
161
+ expect(newUrl).toBe('')
162
+
163
+ url = '/sub/index'
164
+ newUrl = removeIndexString(url)
165
+ expect(newUrl).toBe('/sub')
166
+
167
+ url = '/subindex'
168
+ newUrl = removeIndexString(url)
169
+ expect(newUrl).toBe('/subindex')
170
+ })
171
+
172
+ it('Should remove `/index` with query parameters', () => {
173
+ let url = 'http://localhost/index?page=123&limit=20'
174
+ let newUrl = removeIndexString(url)
175
+ expect(newUrl).toBe('http://localhost/?page=123&limit=20')
176
+
177
+ url = 'https://example.com/index?q=search'
178
+ newUrl = removeIndexString(url)
179
+ expect(newUrl).toBe('https://example.com/?q=search')
180
+
181
+ url = '/api/index?filter=test'
182
+ newUrl = removeIndexString(url)
183
+ expect(newUrl).toBe('/api?filter=test')
184
+
185
+ url = '/index?a=1&b=2&c=3'
186
+ newUrl = removeIndexString(url)
187
+ expect(newUrl).toBe('?a=1&b=2&c=3')
188
+ })
189
+ })
190
+
191
+ describe('deepMerge', () => {
192
+ it('should return the source object if the target object is not an object', () => {
193
+ const target = null
194
+ const source = 'not an object' as unknown as Record<string, unknown>
195
+ const result = deepMerge(target, source)
196
+ expect(result).toEqual(source)
197
+ })
198
+
199
+ it('should merge two objects with object properties', () => {
200
+ expect(
201
+ deepMerge(
202
+ { headers: { acryl: '1' }, timeout: 2, params: {} },
203
+ { headers: { acryl: '2', demo: 2 }, params: undefined }
204
+ )
205
+ ).toStrictEqual({
206
+ params: undefined,
207
+ headers: { acryl: '2', demo: 2 },
208
+ timeout: 2,
209
+ })
210
+ })
211
+ })
212
+
213
+ describe('parseResponse', async () => {
214
+ const _app = new App()
215
+ .get('/text', (c) => c.text('hi'))
216
+ .get('/json', (c) => c.json({ message: 'hi' }))
217
+ .get('/might-error-json', (c) => {
218
+ if (Math.random() > 0.5) {
219
+ return c.json({ error: 'error' }, 500)
220
+ }
221
+ return c.json({ data: [{ id: 1 }, { id: 2 }] })
222
+ })
223
+ .get('/might-error-mixed-json-text', (c) => {
224
+ if (Math.random() > 0.5) {
225
+ return c.text('500 Internal Server Error', 500)
226
+ }
227
+ return c.json({ message: 'Success' })
228
+ })
229
+ .get('/200-explicit', (c) => c.text('OK', 200))
230
+ .get('/404', (c) => c.text('404 Not Found', 404))
231
+ .get('/500', (c) => c.text('500 Internal Server Error', 500))
232
+ .get('/raw', (c) => {
233
+ c.header('content-type', '')
234
+ return c.body('hello')
235
+ })
236
+ .get('/rawUnknown', (c) => {
237
+ c.header('content-type', 'x/custom-type')
238
+ return c.body('hello')
239
+ })
240
+ .get('/rawBuffer', (c) => {
241
+ c.header('content-type', 'x/custom-type')
242
+ return c.body(new TextEncoder().encode('acryl'))
243
+ })
244
+
245
+ const client = hc<typeof _app>('http://localhost')
246
+
247
+ const server = setupServer(
248
+ http.get('http://localhost/text', () => {
249
+ return HttpResponse.text('hi')
250
+ }),
251
+ http.get('http://localhost/json', () => {
252
+ return HttpResponse.json({ message: 'hi' })
253
+ }),
254
+ http.get('http://localhost/might-error-json', () => {
255
+ if (Math.random() > 0.5) {
256
+ return HttpResponse.json({ error: 'error' }, { status: 500 })
257
+ }
258
+ return HttpResponse.json({ data: [{ id: 1 }, { id: 2 }] })
259
+ }),
260
+ http.get('http://localhost/might-error-mixed-json-text', () => {
261
+ if (Math.random() > 0.5) {
262
+ return HttpResponse.text('500 Internal Server Error', { status: 500 })
263
+ }
264
+ return HttpResponse.json({ message: 'Success' })
265
+ }),
266
+ http.get('http://localhost/200-explicit', () => {
267
+ return HttpResponse.text('OK', { status: 200 })
268
+ }),
269
+ http.get('http://localhost/404', () => {
270
+ return HttpResponse.text('404 Not Found', { status: 404 })
271
+ }),
272
+ http.get('http://localhost/500', () => {
273
+ return HttpResponse.text('500 Internal Server Error', { status: 500 })
274
+ }),
275
+ http.get('http://localhost/raw', () => {
276
+ return HttpResponse.text('hello', {
277
+ headers: {
278
+ 'content-type': '',
279
+ },
280
+ })
281
+ }),
282
+ http.get('http://localhost/rawUnknown', () => {
283
+ return HttpResponse.text('hello', {
284
+ headers: {
285
+ 'content-type': 'x/custom-type',
286
+ },
287
+ })
288
+ }),
289
+ http.get('http://localhost/rawBuffer', () => {
290
+ return HttpResponse.arrayBuffer(new TextEncoder().encode('acryl').buffer, {
291
+ headers: {
292
+ 'content-type': 'x/custom-type',
293
+ },
294
+ })
295
+ }),
296
+ http.get('http://localhost/noRoute', () => HttpResponse.error())
297
+ )
298
+
299
+ beforeAll(() => server.listen())
300
+ afterEach(() => server.resetHandlers())
301
+ afterAll(() => server.close())
302
+
303
+ await Promise.all([
304
+ it('should auto parse the text response - async fetch', async () => {
305
+ const result = await parseResponse(client.text.$get())
306
+ expect(result).toBe('hi')
307
+ type _verify = Expect<Equal<typeof result, 'hi'>>
308
+ }),
309
+ it('should auto parse the text response - sync fetch', async () => {
310
+ const result = await parseResponse(await client.text.$get())
311
+ expect(result).toBe('hi')
312
+ type _verify = Expect<Equal<typeof result, 'hi'>>
313
+ }),
314
+ it('should auto parse text response - explicit 200', async () => {
315
+ const result = await parseResponse(client['200-explicit'].$get())
316
+ expect(result).toBe('OK')
317
+ type _verify = Expect<Equal<typeof result, 'OK'>>
318
+ }),
319
+ it('should auto parse the json response - async fetch', async () => {
320
+ const result = await parseResponse(client.json.$get())
321
+ expect(result).toEqual({ message: 'hi' })
322
+ type _verify = Expect<Equal<typeof result, { message: string }>>
323
+ }),
324
+ it('should auto parse the json response - sync fetch', async () => {
325
+ const result = await parseResponse(await client.json.$get())
326
+ expect(result).toEqual({ message: 'hi' })
327
+ type _verify = Expect<Equal<typeof result, { message: string }>>
328
+ }),
329
+ it('should throw error when the response is not ok', async () => {
330
+ await expect(parseResponse(client['404'].$get())).rejects.toThrowError('404 Not Found')
331
+ }),
332
+ it('should parse as text for raw responses without content-type header', async () => {
333
+ const result = await parseResponse(client.raw.$get())
334
+ expect(result).toBe('hello')
335
+ type _verify = Expect<Equal<typeof result, 'hello'>>
336
+ }),
337
+ it('should parse as unknown string for raw buffer responses with unknown content-type header', async () => {
338
+ const result = await parseResponse(client.rawBuffer.$get())
339
+ expect(result).toMatchInlineSnapshot('"acryl"')
340
+ type _verify = Expect<Equal<typeof result, string>>
341
+ }),
342
+ it('should throw error matching snapshots', async () => {
343
+ // Defined 404 route
344
+ await expect(parseResponse(client['404'].$get())).rejects.toThrowErrorMatchingInlineSnapshot(
345
+ '[DetailedError: 404 Not Found]'
346
+ )
347
+
348
+ // Defined 500 route
349
+ await expect(parseResponse(client['500'].$get())).rejects.toThrowErrorMatchingInlineSnapshot(
350
+ '[DetailedError: 500 Internal Server Error]'
351
+ )
352
+
353
+ // Not defined route: MSW simulates a network error, so fetch itself rejects
354
+ // Note: the error in this test case is thrown at the `fetch` call (.$get()), not during the `parseResponse` call, so I think `parseResponse` should not try to catch and wrap it into a structured error, which could be inconsistent, if the user awaited the fetch.
355
+ await expect(
356
+ // @ts-expect-error noRoute is not defined
357
+ parseResponse(client['noRoute'].$get())
358
+ ).rejects.toThrowErrorMatchingInlineSnapshot('[TypeError: Failed to fetch]')
359
+ }),
360
+ it('(type-only) should bypass error responses in the result type inference - simple 404', async () => {
361
+ type ResultType = Awaited<
362
+ ReturnType<typeof parseResponse<Awaited<ReturnType<(typeof client)['404']['$get']>>>>
363
+ >
364
+ type _verify = Expect<Equal<Awaited<ResultType>, undefined>>
365
+ }),
366
+ it('(type-only) should bypass error responses in the result type inference - conditional - json', async () => {
367
+ type ResultType = Awaited<
368
+ ReturnType<
369
+ typeof parseResponse<Awaited<ReturnType<(typeof client)['might-error-json']['$get']>>>
370
+ >
371
+ >
372
+ type _verify = Expect<Equal<ResultType, { data: { id: number }[] }>>
373
+ }),
374
+ it('(type-only) should bypass error responses in the result type inference - conditional - mixed json/text', async () => {
375
+ type ResultType = Awaited<
376
+ ReturnType<
377
+ typeof parseResponse<
378
+ Awaited<ReturnType<(typeof client)['might-error-mixed-json-text']['$get']>>
379
+ >
380
+ >
381
+ >
382
+ type _verify = Expect<Equal<ResultType, { message: string }>>
383
+ }),
384
+ ])
385
+
386
+ it('should parse json response with _bodyInit when body is undefined', async () => {
387
+ const mockFetch = vi.fn().mockResolvedValue({
388
+ ok: true,
389
+ status: 200,
390
+ headers: new Headers({ 'content-type': 'application/json' }),
391
+ body: undefined,
392
+ _bodyInit: '{"message":"test"}',
393
+ json: async () => ({ message: 'test' }),
394
+ })
395
+
396
+ global.fetch = mockFetch
397
+
398
+ const mockClientResponse = {
399
+ $get: mockFetch,
400
+ }
401
+
402
+ const result = await parseResponse(mockClientResponse.$get())
403
+ expect(result).toEqual({ message: 'test' })
404
+ })
405
+ })
@@ -0,0 +1,117 @@
1
+ import type {
2
+ ClientErrorStatusCode,
3
+ ContentfulStatusCode,
4
+ ServerErrorStatusCode,
5
+ } from '../utils/http-status.ts'
6
+ import { fetchRP, DetailedError } from './fetch-result-please.ts'
7
+ import type { ClientResponse, FilterClientResponseByStatusCode, ObjectType } from './types.ts'
8
+
9
+ export { DetailedError }
10
+
11
+ export const mergePath = (base: string, path: string) => {
12
+ base = base.replace(/\/+$/, '')
13
+ base = base + '/'
14
+ path = path.replace(/^\/+/, '')
15
+ return base + path
16
+ }
17
+
18
+ export const replaceUrlParam = (urlString: string, params: Record<string, string | undefined>) => {
19
+ for (const [k, v] of Object.entries(params)) {
20
+ const reg = new RegExp('/:' + k + '(?:{[^/]+})?\\??(?=/|$)')
21
+ urlString = urlString.replace(reg, () => (v ? `/${v}` : ''))
22
+ }
23
+ return urlString
24
+ }
25
+
26
+ export const buildSearchParams = (query: Record<string, string | string[]>) => {
27
+ const searchParams = new URLSearchParams()
28
+
29
+ for (const [k, v] of Object.entries(query)) {
30
+ if (v === undefined) {
31
+ continue
32
+ }
33
+
34
+ if (Array.isArray(v)) {
35
+ for (const v2 of v) {
36
+ if (v2 === undefined) {
37
+ continue
38
+ }
39
+ searchParams.append(k, v2)
40
+ }
41
+ } else {
42
+ searchParams.set(k, v)
43
+ }
44
+ }
45
+
46
+ return searchParams
47
+ }
48
+
49
+ export const replaceUrlProtocol = (urlString: string, protocol: 'ws' | 'http') => {
50
+ switch (protocol) {
51
+ case 'ws':
52
+ return urlString.replace(/^http/, 'ws')
53
+ case 'http':
54
+ return urlString.replace(/^ws/, 'http')
55
+ }
56
+ }
57
+
58
+ export const removeIndexString = (urlString: string) => {
59
+ if (/^https?:\/\/[^\/]+?\/index(?=\?|$)/.test(urlString)) {
60
+ return urlString.replace(/\/index(?=\?|$)/, '/')
61
+ }
62
+ return urlString.replace(/\/index(?=\?|$)/, '')
63
+ }
64
+
65
+ function isObject(item: unknown): item is ObjectType {
66
+ return typeof item === 'object' && item !== null && !Array.isArray(item)
67
+ }
68
+
69
+ export function deepMerge<T>(target: T, source: Record<string, unknown>): T {
70
+ if (!isObject(target) && !isObject(source)) {
71
+ return source as T
72
+ }
73
+ const merged = { ...target } as ObjectType<T>
74
+
75
+ for (const key in source) {
76
+ const value = source[key]
77
+ if (isObject(merged[key]) && isObject(value)) {
78
+ merged[key] = deepMerge(merged[key], value)
79
+ } else {
80
+ merged[key] = value as T[keyof T] & T
81
+ }
82
+ }
83
+
84
+ return merged as T
85
+ }
86
+
87
+ /**
88
+ * Shortcut to get a consumable response from `hc`'s fetch calls (Response), with types inference.
89
+ *
90
+ * Smartly parse the response data, throwing a structured error if the response is not `ok`. ({@link DetailedError})
91
+ *
92
+ * @example const result = await parseResponse(client.posts.$get())
93
+ */
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ export async function parseResponse<T extends ClientResponse<any>>(
96
+ fetchRes: T | Promise<T>
97
+ ): Promise<
98
+ FilterClientResponseByStatusCode<
99
+ T,
100
+ Exclude<ContentfulStatusCode, ClientErrorStatusCode | ServerErrorStatusCode> // Filter out the error responses
101
+ > extends never
102
+ ? // Filtered responses does not include any contentful responses, exit with undefined
103
+ undefined
104
+ : // Filtered responses includes contentful responses, proceed to infer the type
105
+ FilterClientResponseByStatusCode<
106
+ T,
107
+ Exclude<ContentfulStatusCode, ClientErrorStatusCode | ServerErrorStatusCode>
108
+ > extends ClientResponse<infer RT, infer _, infer RF>
109
+ ? RF extends 'json'
110
+ ? RT
111
+ : RT extends string
112
+ ? RT
113
+ : string
114
+ : undefined
115
+ > {
116
+ return fetchRP(fetchRes)
117
+ }