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,154 @@
1
+ import { METHOD_NAME_ALL } from '../../router.ts'
2
+ import { runTest } from '../common.case.test.ts'
3
+ import { buildInitParams, serializeInitParams, PreparedRegExpRouter } from './prepared-router.ts'
4
+
5
+ describe('PreparedRegExpRouter', async () => {
6
+ runTest({
7
+ skip: [
8
+ {
9
+ reason: 'UnsupportedPath',
10
+ tests: [
11
+ 'Duplicate param name > parent',
12
+ 'Duplicate param name > child',
13
+ 'Capture Group > Complex capturing group > GET request',
14
+ 'Capture complex multiple directories > GET /part1/middle-b/latest',
15
+ 'Capture complex multiple directories > GET /part1/middle-b/end-c/latest',
16
+ 'Complex > Parameter with {.*} regexp',
17
+ ],
18
+ },
19
+ {
20
+ reason:
21
+ 'This route can not be added with `:label` to PreparedRegExpRouter. This is ambiguous',
22
+ tests: ['Including slashes > GET /js/main.js'],
23
+ },
24
+ ],
25
+ newRouter: <T>() => {
26
+ let router: PreparedRegExpRouter<T>
27
+ const routes: [string, string, T][] = []
28
+ return {
29
+ name: 'PreparedRegExpRouterBuilder',
30
+ add: (method: string, path: string, handler: T) => {
31
+ routes.push([method, path, handler])
32
+ },
33
+ match: (method: string, path: string) => {
34
+ if (!router) {
35
+ const serialized = serializeInitParams(
36
+ buildInitParams({
37
+ paths: routes.map((r) => r[1]),
38
+ })
39
+ )
40
+ const params = eval(serialized) as ConstructorParameters<typeof PreparedRegExpRouter<T>>
41
+ router = new PreparedRegExpRouter<T>(...params)
42
+
43
+ for (const route of routes) {
44
+ router.add(...route)
45
+ }
46
+ }
47
+ return router.match(method, path)
48
+ },
49
+ }
50
+ },
51
+ })
52
+
53
+ describe('add()', () => {
54
+ it('should add a route', () => {
55
+ const params = buildInitParams({
56
+ paths: ['/hello'],
57
+ })
58
+ const router = new PreparedRegExpRouter(...params)
59
+ router.add('GET', '/hello', 'get hello')
60
+ expect(router.match('GET', '/hello')).toEqual([[['get hello', {}]], []])
61
+ })
62
+
63
+ it('should throw an error if the path is not pre-registered', () => {
64
+ const params = buildInitParams({
65
+ paths: ['/hello'],
66
+ })
67
+ const router = new PreparedRegExpRouter(...params)
68
+ expect(() => router.add('GET', '/unknown', 'get hello')).toThrowError()
69
+ })
70
+ })
71
+ })
72
+
73
+ describe('buildInitParams() and serializeInitParams()', () => {
74
+ it('should build empty init params', () => {
75
+ const params = buildInitParams({
76
+ paths: [],
77
+ })
78
+ expect(params).toEqual([{ [METHOD_NAME_ALL]: [/^$/, [], {}] }, {}])
79
+ expect((0, eval)(serializeInitParams(params))).toEqual(params)
80
+ })
81
+
82
+ it('should build init params with one static path', () => {
83
+ const params = buildInitParams({
84
+ paths: ['/hello'],
85
+ })
86
+ expect(params).toEqual([
87
+ {
88
+ [METHOD_NAME_ALL]: [
89
+ /^$/,
90
+ [],
91
+ {
92
+ '/hello': [[], []],
93
+ },
94
+ ],
95
+ },
96
+ {
97
+ '/hello': [[['']]],
98
+ },
99
+ ])
100
+ expect((0, eval)(serializeInitParams(params))).toEqual(params)
101
+ })
102
+
103
+ it('should build init params with paths with params', () => {
104
+ const params = buildInitParams({
105
+ paths: ['/hello/:name', '/hello/:name/posts/:postId'],
106
+ })
107
+ expect(params).toEqual([
108
+ {
109
+ [METHOD_NAME_ALL]: [/^\/hello\/([^/]+)(?:$()|\/posts\/([^/]+)$())/, [0, 0, [], 0, []], {}],
110
+ },
111
+ {
112
+ '/hello/:name': [[[2], { name: 1 }]],
113
+ '/hello/:name/posts/:postId': [[[4], { name: 1, postId: 3 }]],
114
+ },
115
+ ])
116
+ expect((0, eval)(serializeInitParams(params))).toEqual(params)
117
+ })
118
+
119
+ it('should build init params with wildcard', () => {
120
+ const params = buildInitParams({
121
+ paths: ['*'],
122
+ })
123
+ expect(params).toEqual([
124
+ {
125
+ [METHOD_NAME_ALL]: [/^.*$()/, [0, []], {}],
126
+ },
127
+ {},
128
+ ])
129
+ expect((0, eval)(serializeInitParams(params))).toEqual(params)
130
+ })
131
+
132
+ it('should build init params with complex path', () => {
133
+ const params = buildInitParams({
134
+ paths: ['/hello', '/hello/:name', '/hello/:name/posts/:postId', '*'],
135
+ })
136
+ expect(params).toEqual([
137
+ {
138
+ [METHOD_NAME_ALL]: [
139
+ /^(?:\/hello\/([^/]+)(?:$()|\/posts\/([^/]+)$())|.*$())/,
140
+ [0, 0, [], 0, [], []],
141
+ {
142
+ '/hello': [[], []],
143
+ },
144
+ ],
145
+ },
146
+ {
147
+ '/hello': [[['']]],
148
+ '/hello/:name': [[[2], { name: 1 }]],
149
+ '/hello/:name/posts/:postId': [[[4], { name: 1, postId: 3 }]],
150
+ },
151
+ ])
152
+ expect((0, eval)(serializeInitParams(params))).toEqual(params)
153
+ })
154
+ })
@@ -0,0 +1,165 @@
1
+ import type { ParamIndexMap, Result, Router } from '../../router.ts'
2
+ import { METHOD_NAME_ALL } from '../../router.ts'
3
+ import type { HandlerData, Matcher, MatcherMap, StaticMap } from './matcher.ts'
4
+ import { match, emptyParam } from './matcher.ts'
5
+ import { RegExpRouter } from './router.ts'
6
+
7
+ type RelocateMap = Record<string, ([(number | string)[], ParamIndexMap] | [(number | string)[]])[]>
8
+
9
+ export class PreparedRegExpRouter<T> implements Router<T> {
10
+ name: string = 'PreparedRegExpRouter'
11
+ #matchers: MatcherMap<T>
12
+ #relocateMap: RelocateMap
13
+
14
+ constructor(matchers: MatcherMap<T>, relocateMap: RelocateMap) {
15
+ this.#matchers = matchers
16
+ this.#relocateMap = relocateMap
17
+ }
18
+
19
+ #addWildcard(method: string, handlerData: [T, ParamIndexMap]) {
20
+ const matcher = this.#matchers[method] as Matcher<T>
21
+ matcher[1].forEach((list) => list && list.push(handlerData))
22
+ Object.values(matcher[2]).forEach((list) => (list[0] as [T, ParamIndexMap][]).push(handlerData))
23
+ }
24
+
25
+ #addPath(
26
+ method: string,
27
+ path: string,
28
+ handler: T,
29
+ indexes: (number | string)[],
30
+ map: ParamIndexMap | undefined
31
+ ) {
32
+ const matcher = this.#matchers[method] as Matcher<T>
33
+ if (!map) {
34
+ // assumed to be a static route
35
+ matcher[2][path][0].push([handler, {}])
36
+ } else {
37
+ indexes.forEach((index) => {
38
+ if (typeof index === 'number') {
39
+ matcher[1][index].push([handler, map])
40
+ } else {
41
+ ;(matcher[2][index || path][0] as [T, ParamIndexMap][]).push([handler, map])
42
+ }
43
+ })
44
+ }
45
+ }
46
+
47
+ add(method: string, path: string, handler: T) {
48
+ if (!this.#matchers[method]) {
49
+ const all = this.#matchers[METHOD_NAME_ALL] as Matcher<T>
50
+ const staticMap = {} as StaticMap<T>
51
+ for (const key in all[2]) {
52
+ staticMap[key] = [all[2][key][0].slice(), emptyParam] as Result<T>
53
+ }
54
+ this.#matchers[method] = [
55
+ all[0],
56
+ all[1].map((list) => (Array.isArray(list) ? list.slice() : 0)) as HandlerData<T>[],
57
+ staticMap,
58
+ ]
59
+ }
60
+
61
+ if (path === '/*' || path === '*') {
62
+ const handlerData: [T, ParamIndexMap] = [handler, {}]
63
+ if (method === METHOD_NAME_ALL) {
64
+ for (const m in this.#matchers) {
65
+ this.#addWildcard(m, handlerData)
66
+ }
67
+ } else {
68
+ this.#addWildcard(method, handlerData)
69
+ }
70
+ return
71
+ }
72
+
73
+ const data = this.#relocateMap[path]
74
+ if (!data) {
75
+ throw new Error(`Path ${path} is not registered`)
76
+ }
77
+ for (const [indexes, map] of data) {
78
+ if (method === METHOD_NAME_ALL) {
79
+ for (const m in this.#matchers) {
80
+ this.#addPath(m, path, handler, indexes, map)
81
+ }
82
+ } else {
83
+ this.#addPath(method, path, handler, indexes, map)
84
+ }
85
+ }
86
+ }
87
+
88
+ protected buildAllMatchers(): MatcherMap<T> {
89
+ return this.#matchers
90
+ }
91
+
92
+ match: typeof match<Router<T>, T> = match
93
+ }
94
+
95
+ export const buildInitParams: (params: {
96
+ paths: string[]
97
+ }) => ConstructorParameters<typeof PreparedRegExpRouter> = ({ paths }) => {
98
+ const RegExpRouterWithMatcherExport = class<T> extends RegExpRouter<T> {
99
+ buildAndExportAllMatchers() {
100
+ return this.buildAllMatchers()
101
+ }
102
+ }
103
+ const router = new RegExpRouterWithMatcherExport<string>()
104
+ for (const path of paths) {
105
+ router.add(METHOD_NAME_ALL, path, path)
106
+ }
107
+
108
+ const matchers = router.buildAndExportAllMatchers()
109
+ const all = matchers[METHOD_NAME_ALL] as Matcher<string>
110
+
111
+ const relocateMap: RelocateMap = {}
112
+ for (const path of paths) {
113
+ if (path === '/*' || path === '*') {
114
+ continue
115
+ }
116
+ all[1].forEach((list, i) => {
117
+ list.forEach(([p, map]) => {
118
+ if (p === path) {
119
+ if (relocateMap[path]) {
120
+ relocateMap[path][0][1] = {
121
+ ...relocateMap[path][0][1],
122
+ ...map,
123
+ }
124
+ } else {
125
+ relocateMap[path] = [[[], map]]
126
+ }
127
+ if (relocateMap[path][0][0].findIndex((j) => j === i) === -1) {
128
+ relocateMap[path][0][0].push(i)
129
+ }
130
+ }
131
+ })
132
+ })
133
+ for (const path2 in all[2]) {
134
+ all[2][path2][0].forEach(([p]) => {
135
+ if (p === path) {
136
+ relocateMap[path] ||= [[[]]]
137
+ const value = path2 === path ? '' : path2
138
+ if (relocateMap[path][0][0].findIndex((v) => v === value) === -1) {
139
+ relocateMap[path][0][0].push(value)
140
+ }
141
+ }
142
+ })
143
+ }
144
+ }
145
+
146
+ for (let i = 0, len = all[1].length; i < len; i++) {
147
+ all[1][i] = all[1][i] ? [] : (0 as unknown as HandlerData<string>)
148
+ }
149
+ for (const path in all[2]) {
150
+ all[2][path][0] = []
151
+ }
152
+
153
+ return [matchers, relocateMap]
154
+ }
155
+
156
+ export const serializeInitParams: (
157
+ params: ConstructorParameters<typeof PreparedRegExpRouter>
158
+ ) => string = ([matchers, relocateMap]) => {
159
+ // Embed the regular expression as a result of `toString()` so that it can be evaluated as JavaScript.
160
+ const matchersStr = JSON.stringify(matchers, (_, value) =>
161
+ value instanceof RegExp ? `##${value.toString()}##` : value
162
+ ).replace(/"##(.+?)##"/g, (_, str) => str.replace(/\\\\/g, '\\'))
163
+ const relocateMapStr = JSON.stringify(relocateMap)
164
+ return `[${matchersStr},${relocateMapStr}]`
165
+ }
@@ -0,0 +1,265 @@
1
+ import type { ParamIndexMap, ParamStash } from '../../router.ts'
2
+ import { UnsupportedPathError } from '../../router.ts'
3
+ import { runTest } from '../common.case.test.ts'
4
+ import { RegExpRouter } from './router.ts'
5
+
6
+ describe('RegExpRouter', () => {
7
+ runTest({
8
+ skip: [
9
+ {
10
+ reason: 'UnsupportedPath',
11
+ tests: [
12
+ 'Duplicate param name > parent',
13
+ 'Duplicate param name > child',
14
+ 'Capture Group > Complex capturing group > GET request',
15
+ 'Capture complex multiple directories > GET /part1/middle-b/latest',
16
+ 'Capture complex multiple directories > GET /part1/middle-b/end-c/latest',
17
+ 'Complex > Parameter with {.*} regexp',
18
+ ],
19
+ },
20
+ {
21
+ reason: 'This route can not be added with `:label` to RegExpRouter. This is ambiguous',
22
+ tests: ['Including slashes > GET /js/main.js'],
23
+ },
24
+ ],
25
+ newRouter: () => new RegExpRouter(),
26
+ })
27
+
28
+ describe('Return value type', () => {
29
+ it('Should return [[T, ParamIndexMap][], ParamStash]', () => {
30
+ const router = new RegExpRouter<string>()
31
+ router.add('GET', '/posts/:id', 'get post')
32
+
33
+ const [res, stash] = router.match('GET', '/posts/1')
34
+ expect(res.length).toBe(1)
35
+ expect(res).toEqual([['get post', { id: 1 }]])
36
+ expect((stash as ParamStash)[1]).toBe('1')
37
+ })
38
+ })
39
+
40
+ describe('UnsupportedPathError', () => {
41
+ describe('Ambiguous', () => {
42
+ it('GET /entry/:name', () => {
43
+ const router = new RegExpRouter<string>()
44
+ router.add('GET', '/:user/entries', 'get user entries')
45
+ expect(() => {
46
+ router.add('GET', '/entry/:name', 'get entry')
47
+ }).toThrowError(UnsupportedPathError)
48
+ })
49
+ })
50
+
51
+ describe('Multiple handlers with different label', () => {
52
+ it('GET /:class/:id', () => {
53
+ const router = new RegExpRouter<string>()
54
+ router.add('GET', '/:type/:id', ':type')
55
+ expect(() => {
56
+ router.add('GET', '/:class/:id', ':class')
57
+ }).toThrowError(UnsupportedPathError)
58
+ })
59
+ })
60
+
61
+ it('parent', () => {
62
+ const router = new RegExpRouter<string>()
63
+ router.add('GET', '/:id/:action', 'foo')
64
+ expect(() => {
65
+ router.add('GET', '/posts/:id', 'bar')
66
+ }).toThrowError(UnsupportedPathError)
67
+ })
68
+
69
+ it('child', () => {
70
+ const router = new RegExpRouter<string>()
71
+ router.add('GET', '/posts/:id', 'foo')
72
+ expect(() => {
73
+ router.add('GET', '/:id/:action', 'bar')
74
+ }).toThrowError(UnsupportedPathError)
75
+ })
76
+
77
+ describe('static and dynamic', () => {
78
+ it('static first', () => {
79
+ const router = new RegExpRouter<string>()
80
+ router.add('GET', '/reg-exp/router', 'foo')
81
+ expect(() => {
82
+ router.add('GET', '/reg-exp/:id', 'bar')
83
+ }).toThrowError(UnsupportedPathError)
84
+ })
85
+
86
+ it('long label', () => {
87
+ const router = new RegExpRouter<string>()
88
+ router.add('GET', '/reg-exp/router', 'foo')
89
+ expect(() => {
90
+ router.add('GET', '/reg-exp/:service', 'bar')
91
+ }).toThrowError(UnsupportedPathError)
92
+ })
93
+
94
+ it('dynamic first', () => {
95
+ const router = new RegExpRouter<string>()
96
+ router.add('GET', '/reg-exp/:id', 'bar')
97
+ expect(() => {
98
+ router.add('GET', '/reg-exp/router', 'foo')
99
+ }).toThrowError(UnsupportedPathError)
100
+ })
101
+ })
102
+
103
+ it('different regular expression', () => {
104
+ const router = new RegExpRouter<string>()
105
+ router.add('GET', '/:id/:action{create|update}', 'foo')
106
+ expect(() => {
107
+ router.add('GET', '/:id/:action{delete}', 'bar')
108
+ }).toThrowError(UnsupportedPathError)
109
+ })
110
+
111
+ it('ALL route added after a specific-method route', () => {
112
+ const router = new RegExpRouter<string>()
113
+ router.add('GET', '/foo/:a', 'foo')
114
+ expect(() => {
115
+ router.add('ALL', '/foo/:b', 'bar')
116
+ }).toThrowError(UnsupportedPathError)
117
+ })
118
+
119
+ it('specific-method route added after an ALL route', () => {
120
+ const router = new RegExpRouter<string>()
121
+ router.add('ALL', '/reg-exp/router', 'foo')
122
+
123
+ expect(() => {
124
+ router.add('GET', '/reg-exp/:id', 'bar')
125
+ }).toThrowError(UnsupportedPathError)
126
+ })
127
+
128
+ it('different methods do not conflict', () => {
129
+ const router = new RegExpRouter<string>()
130
+ router.add('GET', '/reg-exp/router', 'foo')
131
+ router.add('POST', '/reg-exp/:id', 'bar')
132
+
133
+ expect(router.match('GET', '/reg-exp/router')[0][0][0]).toBe('foo')
134
+ expect(router.match('POST', '/reg-exp/router')[0][0][0]).toBe('bar')
135
+ })
136
+
137
+ describe('Capture Group', () => {
138
+ describe('Complex capturing group', () => {
139
+ it('GET request', () => {
140
+ const router = new RegExpRouter<string>()
141
+ expect(() => {
142
+ router.add('GET', '/foo/:capture{ba(r|z)}', 'ok')
143
+ }).toThrowError(UnsupportedPathError)
144
+ })
145
+ })
146
+ })
147
+ })
148
+
149
+ describe('Wildcard after label', () => {
150
+ it('Should be able to add a tail wildcard after a label', () => {
151
+ const router = new RegExpRouter<string>()
152
+ router.add('GET', '/api/:x', 'label')
153
+ router.add('GET', '/api/*', 'wildcard')
154
+
155
+ const [res] = router.match('GET', '/api/foo')
156
+ expect(res.length).toBe(2)
157
+ expect(res[0][0]).toBe('label')
158
+ expect(res[1][0]).toBe('wildcard')
159
+ })
160
+
161
+ it('Should prioritize the only wildcard over the tail wildcard regardless of the order', () => {
162
+ for (const paths of [
163
+ ['/a*', '/a/*'],
164
+ ['/a/*', '/a*'],
165
+ ]) {
166
+ const router = new RegExpRouter<string>()
167
+ for (const path of paths) {
168
+ router.add('GET', path, path)
169
+ }
170
+ const [res] = router.match('GET', '/a')
171
+ expect(res[0][0]).toBe('/a*')
172
+ }
173
+ })
174
+ })
175
+
176
+ describe('Single character regexp pattern', () => {
177
+ it('Should capture a param even if a static path created the node first', () => {
178
+ const router = new RegExpRouter<string>()
179
+ router.add('GET', '/a/c', 'static')
180
+ router.add('GET', '/:x{a}/b', 'pattern')
181
+
182
+ const [res, stash] = router.match('GET', '/a/b')
183
+ expect(res.length).toBe(1)
184
+ expect(res[0][0]).toBe('pattern')
185
+ expect((stash as ParamStash)[(res[0][1] as ParamIndexMap)['x']]).toBe('a')
186
+ })
187
+
188
+ it('Should throw an error when a pattern terminal conflicts with a static terminal', () => {
189
+ for (const paths of [
190
+ ['/a', '/:x{a}'],
191
+ ['/:x{a}', '/a'],
192
+ ]) {
193
+ const router = new RegExpRouter<string>()
194
+ router.add('GET', paths[0], paths[0])
195
+ expect(() => {
196
+ router.add('GET', paths[1], paths[1])
197
+ }).toThrowError(UnsupportedPathError)
198
+ }
199
+ })
200
+
201
+ it('Should coexist with static paths regardless of the order', () => {
202
+ for (const paths of [
203
+ ['/foo/bar', '/:y{b}'],
204
+ ['/:y{b}', '/foo/bar'],
205
+ ]) {
206
+ const router = new RegExpRouter<string>()
207
+ for (const path of paths) {
208
+ router.add('GET', path, path)
209
+ }
210
+ expect(router.match('GET', '/foo/bar')[0][0][0]).toBe('/foo/bar')
211
+ expect(router.match('GET', '/b')[0][0][0]).toBe('/:y{b}')
212
+ }
213
+ })
214
+
215
+ it('Should coexist with dynamic paths regardless of the order', () => {
216
+ for (const paths of [
217
+ ['/foo/:p', '/:x{a}'],
218
+ ['/:x{a}', '/foo/:p'],
219
+ ]) {
220
+ const router = new RegExpRouter<string>()
221
+ for (const path of paths) {
222
+ router.add('GET', path, path)
223
+ }
224
+ expect(router.match('GET', '/a')[0][0][0]).toBe('/:x{a}')
225
+ expect(router.match('GET', '/foo/v')[0][0][0]).toBe('/foo/:p')
226
+ }
227
+ })
228
+
229
+ it('Should throw an error for a single meta character pattern', () => {
230
+ const router = new RegExpRouter<string>()
231
+ expect(() => {
232
+ router.add('GET', '/:x{.}', 'meta')
233
+ }).toThrowError(UnsupportedPathError)
234
+ })
235
+ })
236
+
237
+ describe('Capture a param of a label node created by a middle wildcard', () => {
238
+ it('Should capture the param', () => {
239
+ const router = new RegExpRouter<string>()
240
+ router.add('GET', '/w/*/x', 'wildcard')
241
+ router.add('GET', '/w/:id/y', 'label')
242
+
243
+ const [res, stash] = router.match('GET', '/w/123/y')
244
+ expect(res.length).toBe(1)
245
+ expect(res[0][0]).toBe('label')
246
+ expect((stash as ParamStash)[(res[0][1] as ParamIndexMap)['id']]).toBe('123')
247
+ })
248
+ })
249
+
250
+ describe('Static path including a colon in the middle', () => {
251
+ it('Should be treated as a static path', () => {
252
+ for (const paths of [
253
+ ['/v1/name:activate', '/v1/name2'],
254
+ ['/v1/name2', '/v1/name:activate'],
255
+ ]) {
256
+ const router = new RegExpRouter<string>()
257
+ for (const path of paths) {
258
+ router.add('GET', path, path)
259
+ }
260
+ expect(router.match('GET', '/v1/name:activate')[0][0][0]).toBe('/v1/name:activate')
261
+ expect(router.match('GET', '/v1/name2')[0][0][0]).toBe('/v1/name2')
262
+ }
263
+ })
264
+ })
265
+ })