acrylblends 0.3.0 → 0.4.1

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 (341) hide show
  1. package/dist/index.d.ts +6 -1
  2. package/dist/index.js +84 -5
  3. package/dist/index.js.map +1 -1
  4. package/docs/framework/LICENSE +23 -0
  5. package/docs/framework/README.md +63 -0
  6. package/docs/framework/UPSTREAM.md +3 -0
  7. package/docs/framework/api-summary.md +138 -0
  8. package/docs/framework/concepts.md +105 -0
  9. package/docs/framework/context.md +129 -0
  10. package/docs/framework/getting-started.md +146 -0
  11. package/docs/framework/helpers.md +118 -0
  12. package/docs/framework/middleware.md +154 -0
  13. package/docs/framework/migration-from-0-3.md +108 -0
  14. package/docs/framework/migration-from-dsh-webserver.md +103 -0
  15. package/docs/framework/node-server.md +75 -0
  16. package/docs/framework/plugin-lifecycle.md +111 -0
  17. package/docs/framework/request.md +106 -0
  18. package/docs/framework/routing.md +188 -0
  19. package/docs/framework/surfaces.md +71 -0
  20. package/docs/framework/upstream.json +9 -0
  21. package/docs/framework/validation.md +135 -0
  22. package/package.json +4 -2
  23. package/plugins/acryl-inspect/plugin.json +2 -1
  24. package/plugins/acryl-inspect/src/report.ts +21 -13
  25. package/plugins/acryl-inspect/src/service.ts +9 -7
  26. package/plugins/acryl-inspect/tests/report.spec.ts +13 -8
  27. package/plugins/acryl-inspect/tests/service.spec.ts +11 -10
  28. package/plugins/acryl-inspect/upstream.json +2 -2
  29. package/plugins/acryl-node-server/LICENSE +26 -0
  30. package/plugins/acryl-node-server/plugin.json +2 -1
  31. package/plugins/acryl-node-server/src/adapter/conninfo.ts +23 -0
  32. package/plugins/acryl-node-server/src/adapter/early-hints.ts +55 -0
  33. package/plugins/acryl-node-server/src/adapter/error.ts +11 -0
  34. package/plugins/acryl-node-server/src/adapter/headers.ts +249 -0
  35. package/plugins/acryl-node-server/src/adapter/index.ts +6 -0
  36. package/plugins/acryl-node-server/src/adapter/listener.ts +540 -0
  37. package/plugins/acryl-node-server/src/adapter/request.ts +797 -0
  38. package/plugins/acryl-node-server/src/adapter/response.ts +186 -0
  39. package/plugins/acryl-node-server/src/adapter/serve-static.ts +238 -0
  40. package/plugins/acryl-node-server/src/adapter/server.ts +36 -0
  41. package/plugins/acryl-node-server/src/adapter/types.ts +82 -0
  42. package/plugins/acryl-node-server/src/adapter/url.ts +42 -0
  43. package/plugins/acryl-node-server/src/adapter/utils/response/constants.ts +1 -0
  44. package/plugins/acryl-node-server/src/adapter/utils/response.ts +4 -0
  45. package/plugins/acryl-node-server/src/adapter/utils/stream.ts +88 -0
  46. package/plugins/acryl-node-server/src/adapter/utils.ts +96 -0
  47. package/plugins/acryl-node-server/src/adapter/websocket-types.ts +45 -0
  48. package/plugins/acryl-node-server/src/adapter/websocket.ts +375 -0
  49. package/plugins/acryl-node-server/src/index.ts +19 -6
  50. package/plugins/acryl-node-server/tests/adapter/app.ts +76 -0
  51. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +1 -0
  52. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  53. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +1 -0
  54. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -0
  55. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +1 -0
  56. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +5 -0
  57. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +1 -0
  58. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  59. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -0
  60. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +1 -0
  61. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +1 -0
  62. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +1 -0
  63. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +1 -0
  64. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +1 -0
  65. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +1 -0
  66. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +1 -0
  67. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +34 -0
  68. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +248 -0
  69. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +457 -0
  70. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +23 -0
  71. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +27 -0
  72. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +252 -0
  73. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +190 -0
  74. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +727 -0
  75. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +189 -0
  76. package/plugins/acryl-node-server/tests/adapter/request.test.ts +1230 -0
  77. package/plugins/acryl-node-server/tests/adapter/response.test.ts +285 -0
  78. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +849 -0
  79. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +790 -0
  80. package/plugins/acryl-node-server/tests/adapter/server.test.ts +1302 -0
  81. package/plugins/acryl-node-server/tests/adapter/setup.ts +16 -0
  82. package/plugins/acryl-node-server/tests/adapter/url.test.ts +76 -0
  83. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +23 -0
  84. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +75 -0
  85. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +235 -0
  86. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +260 -0
  87. package/plugins/acryl-node-server/tests/server.spec.ts +44 -8
  88. package/plugins/acryl-node-server/upstream.json +3 -3
  89. package/plugins/acryl-router/LICENSE +26 -0
  90. package/plugins/acryl-router/plugin.json +2 -1
  91. package/plugins/acryl-router/src/client.ts +2 -0
  92. package/plugins/acryl-router/src/connection.ts +42 -0
  93. package/plugins/acryl-router/src/core/app-base.ts +544 -0
  94. package/plugins/acryl-router/src/core/app.test.ts +3833 -0
  95. package/plugins/acryl-router/src/core/app.ts +34 -0
  96. package/plugins/acryl-router/src/core/client/client.test.ts +2313 -0
  97. package/plugins/acryl-router/src/core/client/client.ts +249 -0
  98. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +95 -0
  99. package/plugins/acryl-router/src/core/client/index.ts +17 -0
  100. package/plugins/acryl-router/src/core/client/types.test.ts +149 -0
  101. package/plugins/acryl-router/src/core/client/types.ts +393 -0
  102. package/plugins/acryl-router/src/core/client/utils.test.ts +405 -0
  103. package/plugins/acryl-router/src/core/client/utils.ts +117 -0
  104. package/plugins/acryl-router/src/core/compose.test.ts +751 -0
  105. package/plugins/acryl-router/src/core/compose.ts +73 -0
  106. package/plugins/acryl-router/src/core/context.test.ts +629 -0
  107. package/plugins/acryl-router/src/core/context.ts +781 -0
  108. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +344 -0
  109. package/plugins/acryl-router/src/core/helper/accepts/accepts.ts +96 -0
  110. package/plugins/acryl-router/src/core/helper/accepts/index.ts +6 -0
  111. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +55 -0
  112. package/plugins/acryl-router/src/core/helper/adapter/index.ts +90 -0
  113. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +6 -0
  114. package/plugins/acryl-router/src/core/helper/conninfo/types.ts +45 -0
  115. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +510 -0
  116. package/plugins/acryl-router/src/core/helper/cookie/index.ts +146 -0
  117. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +434 -0
  118. package/plugins/acryl-router/src/core/helper/factory/index.ts +375 -0
  119. package/plugins/acryl-router/src/core/helper/html/index.test.ts +78 -0
  120. package/plugins/acryl-router/src/core/helper/html/index.ts +57 -0
  121. package/plugins/acryl-router/src/core/helper/route/index.test.ts +259 -0
  122. package/plugins/acryl-router/src/core/helper/route/index.ts +144 -0
  123. package/plugins/acryl-router/src/core/helper/streaming/index.ts +9 -0
  124. package/plugins/acryl-router/src/core/helper/streaming/sse.ts +101 -0
  125. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +128 -0
  126. package/plugins/acryl-router/src/core/helper/streaming/stream.ts +45 -0
  127. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +34 -0
  128. package/plugins/acryl-router/src/core/helper/streaming/text.ts +15 -0
  129. package/plugins/acryl-router/src/core/helper/streaming/utils.ts +11 -0
  130. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +42 -0
  131. package/plugins/acryl-router/src/core/helper/testing/index.ts +28 -0
  132. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +124 -0
  133. package/plugins/acryl-router/src/core/helper/websocket/index.ts +140 -0
  134. package/plugins/acryl-router/src/core/http-exception.test.ts +45 -0
  135. package/plugins/acryl-router/src/core/http-exception.ts +77 -0
  136. package/plugins/acryl-router/src/core/index.ts +53 -0
  137. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +434 -0
  138. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +152 -0
  139. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +1018 -0
  140. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +220 -0
  141. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +273 -0
  142. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +110 -0
  143. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +355 -0
  144. package/plugins/acryl-router/src/core/middleware/combine/index.ts +171 -0
  145. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +535 -0
  146. package/plugins/acryl-router/src/core/middleware/compress/index.ts +142 -0
  147. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +43 -0
  148. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +58 -0
  149. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +532 -0
  150. package/plugins/acryl-router/src/core/middleware/cors/index.ts +163 -0
  151. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +534 -0
  152. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +150 -0
  153. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +21 -0
  154. package/plugins/acryl-router/src/core/middleware/etag/digest.ts +95 -0
  155. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +503 -0
  156. package/plugins/acryl-router/src/core/middleware/etag/index.ts +135 -0
  157. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +217 -0
  158. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +278 -0
  159. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +1135 -0
  160. package/plugins/acryl-router/src/core/middleware/jwk/index.ts +1 -0
  161. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +195 -0
  162. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +48 -0
  163. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +802 -0
  164. package/plugins/acryl-router/src/core/middleware/jwt/index.ts +9 -0
  165. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +189 -0
  166. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +552 -0
  167. package/plugins/acryl-router/src/core/middleware/language/index.ts +12 -0
  168. package/plugins/acryl-router/src/core/middleware/language/language.ts +314 -0
  169. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +204 -0
  170. package/plugins/acryl-router/src/core/middleware/logger/index.ts +95 -0
  171. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +292 -0
  172. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +141 -0
  173. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +221 -0
  174. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +147 -0
  175. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +37 -0
  176. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +35 -0
  177. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +218 -0
  178. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +67 -0
  179. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +168 -0
  180. package/plugins/acryl-router/src/core/middleware/request-id/index.ts +7 -0
  181. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +59 -0
  182. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +671 -0
  183. package/plugins/acryl-router/src/core/middleware/secure-headers/index.ts +8 -0
  184. package/plugins/acryl-router/src/core/middleware/secure-headers/permissions-policy.ts +101 -0
  185. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +340 -0
  186. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +450 -0
  187. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +135 -0
  188. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +50 -0
  189. package/plugins/acryl-router/src/core/middleware/serve-static/path.ts +25 -0
  190. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +70 -0
  191. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +58 -0
  192. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +310 -0
  193. package/plugins/acryl-router/src/core/middleware/timing/index.ts +8 -0
  194. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +256 -0
  195. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +381 -0
  196. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +156 -0
  197. package/plugins/acryl-router/src/core/request/constants.ts +1 -0
  198. package/plugins/acryl-router/src/core/request.test.ts +751 -0
  199. package/plugins/acryl-router/src/core/request.ts +502 -0
  200. package/plugins/acryl-router/src/core/router/common.case.test.ts +1132 -0
  201. package/plugins/acryl-router/src/core/router/linear-router/index.ts +6 -0
  202. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +80 -0
  203. package/plugins/acryl-router/src/core/router/linear-router/router.ts +152 -0
  204. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +6 -0
  205. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +46 -0
  206. package/plugins/acryl-router/src/core/router/pattern-router/router.ts +54 -0
  207. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +7 -0
  208. package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.ts +33 -0
  209. package/plugins/acryl-router/src/core/router/reg-exp-router/node.ts +170 -0
  210. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +154 -0
  211. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.ts +165 -0
  212. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +265 -0
  213. package/plugins/acryl-router/src/core/router/reg-exp-router/router.ts +174 -0
  214. package/plugins/acryl-router/src/core/router/reg-exp-router/trie.ts +84 -0
  215. package/plugins/acryl-router/src/core/router/smart-router/index.ts +6 -0
  216. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +13 -0
  217. package/plugins/acryl-router/src/core/router/smart-router/router.ts +70 -0
  218. package/plugins/acryl-router/src/core/router/trie-router/index.ts +6 -0
  219. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +896 -0
  220. package/plugins/acryl-router/src/core/router/trie-router/node.ts +221 -0
  221. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +8 -0
  222. package/plugins/acryl-router/src/core/router/trie-router/router.ts +18 -0
  223. package/plugins/acryl-router/src/core/router/utils.ts +1 -0
  224. package/plugins/acryl-router/src/core/router.ts +103 -0
  225. package/plugins/acryl-router/src/core/types.test.ts +4134 -0
  226. package/plugins/acryl-router/src/core/types.ts +2782 -0
  227. package/plugins/acryl-router/src/core/utils/accept.test.ts +299 -0
  228. package/plugins/acryl-router/src/core/utils/accept.ts +268 -0
  229. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +56 -0
  230. package/plugins/acryl-router/src/core/utils/basic-auth.ts +26 -0
  231. package/plugins/acryl-router/src/core/utils/body.test.ts +496 -0
  232. package/plugins/acryl-router/src/core/utils/body.ts +263 -0
  233. package/plugins/acryl-router/src/core/utils/buffer.test.ts +147 -0
  234. package/plugins/acryl-router/src/core/utils/buffer.ts +117 -0
  235. package/plugins/acryl-router/src/core/utils/color.test.ts +23 -0
  236. package/plugins/acryl-router/src/core/utils/color.ts +56 -0
  237. package/plugins/acryl-router/src/core/utils/compress.ts +10 -0
  238. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +69 -0
  239. package/plugins/acryl-router/src/core/utils/concurrent.ts +55 -0
  240. package/plugins/acryl-router/src/core/utils/constants.ts +4 -0
  241. package/plugins/acryl-router/src/core/utils/cookie.test.ts +460 -0
  242. package/plugins/acryl-router/src/core/utils/cookie.ts +281 -0
  243. package/plugins/acryl-router/src/core/utils/crypto.test.ts +43 -0
  244. package/plugins/acryl-router/src/core/utils/crypto.ts +58 -0
  245. package/plugins/acryl-router/src/core/utils/encode.test.ts +61 -0
  246. package/plugins/acryl-router/src/core/utils/encode.ts +34 -0
  247. package/plugins/acryl-router/src/core/utils/filepath.test.ts +78 -0
  248. package/plugins/acryl-router/src/core/utils/filepath.ts +60 -0
  249. package/plugins/acryl-router/src/core/utils/handler.ts +15 -0
  250. package/plugins/acryl-router/src/core/utils/headers.ts +355 -0
  251. package/plugins/acryl-router/src/core/utils/html.test.ts +16 -0
  252. package/plugins/acryl-router/src/core/utils/html.ts +182 -0
  253. package/plugins/acryl-router/src/core/utils/http-status.ts +72 -0
  254. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +149 -0
  255. package/plugins/acryl-router/src/core/utils/ipaddr.ts +374 -0
  256. package/plugins/acryl-router/src/core/utils/jwt/index.ts +7 -0
  257. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +86 -0
  258. package/plugins/acryl-router/src/core/utils/jwt/jwa.ts +38 -0
  259. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +235 -0
  260. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +1788 -0
  261. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +292 -0
  262. package/plugins/acryl-router/src/core/utils/jwt/types.ts +157 -0
  263. package/plugins/acryl-router/src/core/utils/jwt/utf8.ts +7 -0
  264. package/plugins/acryl-router/src/core/utils/mime.test.ts +64 -0
  265. package/plugins/acryl-router/src/core/utils/mime.ts +94 -0
  266. package/plugins/acryl-router/src/core/utils/stream.test.ts +212 -0
  267. package/plugins/acryl-router/src/core/utils/stream.ts +107 -0
  268. package/plugins/acryl-router/src/core/utils/types.test.ts +295 -0
  269. package/plugins/acryl-router/src/core/utils/types.ts +123 -0
  270. package/plugins/acryl-router/src/core/utils/url.test.ts +384 -0
  271. package/plugins/acryl-router/src/core/utils/url.ts +337 -0
  272. package/plugins/acryl-router/src/core/validator/index.ts +8 -0
  273. package/plugins/acryl-router/src/core/validator/utils.test.ts +82 -0
  274. package/plugins/acryl-router/src/core/validator/utils.ts +69 -0
  275. package/plugins/acryl-router/src/core/validator/validator.test.ts +1488 -0
  276. package/plugins/acryl-router/src/core/validator/validator.ts +185 -0
  277. package/plugins/acryl-router/src/helpers/index.ts +13 -3
  278. package/plugins/acryl-router/src/helpers/schema-validator.ts +35 -0
  279. package/plugins/acryl-router/src/index.ts +6 -6
  280. package/plugins/acryl-router/src/middleware/index.ts +25 -6
  281. package/plugins/acryl-router/src/middleware/loopback-only.ts +53 -14
  282. package/plugins/acryl-router/src/service.ts +262 -64
  283. package/plugins/acryl-router/tests/docs-examples.spec.ts +152 -0
  284. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  285. package/plugins/acryl-router/tests/loader.spec.ts +3 -2
  286. package/plugins/acryl-router/tests/loopback-only.spec.ts +80 -0
  287. package/plugins/acryl-router/tests/service.spec.ts +281 -66
  288. package/plugins/acryl-router/tests/shadow-state.spec.ts +79 -0
  289. package/plugins/acryl-router/upstream.json +2 -2
  290. package/plugins/acryl-router-http/plugin.json +2 -1
  291. package/plugins/acryl-router-http/src/bridge.ts +3 -1
  292. package/plugins/acryl-router-http/tests/adapter.spec.ts +16 -12
  293. package/plugins/acryl-router-http/tests/surfaces.spec.ts +12 -10
  294. package/plugins/acryl-router-http/upstream.json +3 -3
  295. package/plugins/acryl-state/NOTICE +30 -0
  296. package/plugins/acryl-state/plugin.json +1 -1
  297. package/plugins/acryl-state/src/cell.ts +1 -1
  298. package/plugins/acryl-state/src/service.ts +33 -15
  299. package/plugins/acryl-state/upstream.json +6 -4
  300. package/plugins/builder/script.ts +4 -7
  301. package/plugins/extensions/index.ts +6 -5
  302. package/plugins/extensions/resolve.ts +28 -3
  303. package/plugins/openai/prompt.ts +9 -7
  304. package/plugins/tsconfig.json +5 -4
  305. package/shared/AGENTS.core.md +54 -0
  306. package/templates/agent/AGENTS.md +6 -0
  307. package/templates/agent/README.md +2 -2
  308. package/templates/agent/blend.yaml +1 -1
  309. package/templates/agent/src/routes.ts +37 -27
  310. package/templates/agent/test/model.test.ts +2 -1
  311. package/templates/agent/tsconfig.json +8 -5
  312. package/templates/blank/AGENTS.md +5 -0
  313. package/templates/blank/README.md +1 -1
  314. package/templates/blank/src/routes.ts +6 -4
  315. package/templates/blank/tsconfig.json +2 -4
  316. package/templates/todo/AGENTS.md +5 -0
  317. package/templates/todo/src/page.ts +1 -1
  318. package/templates/todo/src/todo.ts +58 -29
  319. package/templates/todo/tsconfig.json +2 -4
  320. package/templates/todo/upstream.json +2 -2
  321. package/plugins/acryl-router/src/compose.ts +0 -21
  322. package/plugins/acryl-router/src/context.ts +0 -59
  323. package/plugins/acryl-router/src/helpers/read-body.ts +0 -59
  324. package/plugins/acryl-router/src/helpers/sse.ts +0 -83
  325. package/plugins/acryl-router/src/helpers/validate.ts +0 -44
  326. package/plugins/acryl-router/src/http-error.ts +0 -21
  327. package/plugins/acryl-router/src/middleware/body-limit.ts +0 -25
  328. package/plugins/acryl-router/src/middleware/cors.ts +0 -46
  329. package/plugins/acryl-router/src/middleware/logger.ts +0 -21
  330. package/plugins/acryl-router/src/middleware/request-id.ts +0 -24
  331. package/plugins/acryl-router/src/middleware/secure-headers.ts +0 -23
  332. package/plugins/acryl-router/src/pattern.ts +0 -89
  333. package/plugins/acryl-router/src/registrar.ts +0 -90
  334. package/plugins/acryl-router/src/table.ts +0 -156
  335. package/plugins/acryl-router/src/types.ts +0 -73
  336. package/plugins/acryl-router/src/util.ts +0 -23
  337. package/plugins/acryl-router/tests/api.spec.ts +0 -223
  338. package/plugins/acryl-router/tests/conformance.ts +0 -170
  339. package/plugins/acryl-router/tests/helpers.spec.ts +0 -172
  340. package/plugins/acryl-router/tests/middleware.spec.ts +0 -183
  341. package/plugins/acryl-router/tests/table.spec.ts +0 -47
@@ -0,0 +1,344 @@
1
+ import { App } from '../../index.ts'
2
+ import { parseAccept } from '../../utils/accept.ts'
3
+ import type { AcceptHeader } from '../../utils/headers.ts'
4
+ import type { Accept, acceptsConfig, acceptsOptions } from './accepts.ts'
5
+ import { accepts, defaultMatch } from './accepts.ts'
6
+
7
+ describe('parseAccept', () => {
8
+ test('should parse accept header', () => {
9
+ const acceptHeader =
10
+ 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8;level=1;foo=bar'
11
+ const accepts = parseAccept(acceptHeader)
12
+ expect(accepts).toEqual([
13
+ { type: 'text/html', params: {}, q: 1 },
14
+ { type: 'application/xhtml+xml', params: {}, q: 1 },
15
+ { type: 'image/webp', params: {}, q: 1 },
16
+ { type: 'application/xml', params: { q: '0.9' }, q: 0.9 },
17
+ { type: '*/*', params: { q: '0.8', level: '1', foo: 'bar' }, q: 0.8 },
18
+ ])
19
+ })
20
+ })
21
+
22
+ describe('defaultMatch', () => {
23
+ test('should return default support', () => {
24
+ const accepts: Accept[] = [
25
+ { type: 'text/html', params: {}, q: 1 },
26
+ { type: 'application/xhtml+xml', params: {}, q: 1 },
27
+ { type: 'application/xml', params: { q: '0.9' }, q: 0.9 },
28
+ { type: 'image/webp', params: {}, q: 1 },
29
+ { type: '*/*', params: { q: '0.8' }, q: 0.8 },
30
+ ]
31
+ const config: acceptsConfig = {
32
+ header: 'Accept',
33
+ supports: ['text/html'],
34
+ default: 'text/html',
35
+ }
36
+ const result = defaultMatch(accepts, config)
37
+ expect(result).toBe('text/html')
38
+ })
39
+ })
40
+
41
+ describe('accepts', () => {
42
+ test('should return matched support', () => {
43
+ const c = {
44
+ req: {
45
+ header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
46
+ },
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ } as any
49
+ const options: acceptsConfig = {
50
+ header: 'Accept',
51
+ supports: ['application/xml', 'text/html'],
52
+ default: 'application/json',
53
+ }
54
+ const result = accepts(c, options)
55
+ expect(result).toBe('text/html')
56
+ })
57
+
58
+ test('should return default support if no matched support', () => {
59
+ const c = {
60
+ req: {
61
+ header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
62
+ },
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ } as any
65
+ const options: acceptsConfig = {
66
+ header: 'Accept',
67
+ supports: ['application/json'],
68
+ default: 'text/html',
69
+ }
70
+ const result = accepts(c, options)
71
+ expect(result).toBe('text/html')
72
+ })
73
+
74
+ test('should match wildcard subtype application/*', () => {
75
+ const c = {
76
+ req: {
77
+ header: () => 'application/*',
78
+ },
79
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
80
+ } as any
81
+ const options: acceptsConfig = {
82
+ header: 'Accept',
83
+ supports: ['application/json', 'text/html'],
84
+ default: 'text/html',
85
+ }
86
+ const result = accepts(c, options)
87
+ expect(result).toBe('application/json')
88
+ })
89
+
90
+ test('should return default support for global wildcard */*', () => {
91
+ const c = {
92
+ req: {
93
+ header: () => 'text/plain, */*;q=0.5',
94
+ },
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ } as any
97
+ const options: acceptsConfig = {
98
+ header: 'Accept',
99
+ supports: ['application/json'],
100
+ default: 'text/html',
101
+ }
102
+ const result = accepts(c, options)
103
+ expect(result).toBe('text/html')
104
+ })
105
+
106
+ test('should return default support for single asterisk wildcard *', () => {
107
+ const c = {
108
+ req: {
109
+ header: () => '*',
110
+ },
111
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+ } as any
113
+ const options: acceptsConfig = {
114
+ header: 'Accept-Encoding',
115
+ supports: ['gzip', 'deflate'],
116
+ default: 'identity',
117
+ }
118
+ const result = accepts(c, options)
119
+ expect(result).toBe('identity')
120
+ })
121
+
122
+ test('should prefer exact match over wildcard match at same quality factor', () => {
123
+ const c = {
124
+ req: {
125
+ header: () => '*/*, application/json',
126
+ },
127
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
+ } as any
129
+ const options: acceptsConfig = {
130
+ header: 'Accept',
131
+ supports: ['text/html', 'application/json'],
132
+ default: 'text/html',
133
+ }
134
+ const result = accepts(c, options)
135
+ expect(result).toBe('application/json')
136
+ })
137
+
138
+ test('should match subtype wildcard while global wildcard falls through to default', () => {
139
+ const c = {
140
+ req: {
141
+ header: () => '*/*, text/*',
142
+ },
143
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
+ } as any
145
+ const options: acceptsConfig = {
146
+ header: 'Accept',
147
+ supports: ['application/json', 'text/plain'],
148
+ default: 'application/json',
149
+ }
150
+ const result = accepts(c, options)
151
+ expect(result).toBe('text/plain')
152
+ })
153
+
154
+ test('should return default support if no accept header', () => {
155
+ const c = {
156
+ req: {
157
+ header: () => undefined,
158
+ },
159
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ } as any
161
+ const options: acceptsConfig = {
162
+ header: 'Accept',
163
+ supports: ['application/json'],
164
+ default: 'text/html',
165
+ }
166
+ const result = accepts(c, options)
167
+ expect(result).toBe('text/html')
168
+ })
169
+
170
+ test('should return matched support with custom match function', () => {
171
+ const c = {
172
+ req: {
173
+ header: () => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
174
+ },
175
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
176
+ } as any
177
+ // this match function will return the least q value
178
+ const match = (accepts: Accept[], config: acceptsConfig) => {
179
+ const { supports, default: defaultSupport } = config
180
+ const accept = accepts
181
+ .sort((a, b) => a.q - b.q)
182
+ .find((accept) => supports.includes(accept.type))
183
+ return accept ? accept.type : defaultSupport
184
+ }
185
+ const options: acceptsOptions = {
186
+ header: 'Accept',
187
+ supports: ['application/xml', 'text/html'],
188
+ default: 'application/json',
189
+ match,
190
+ }
191
+ const result = accepts(c, options)
192
+ expect(result).toBe('application/xml')
193
+ })
194
+
195
+ test('should not match entries explicitly rejected with q=0', () => {
196
+ const c = {
197
+ req: {
198
+ header: () => 'application/json;q=0',
199
+ },
200
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
201
+ } as any
202
+ const options: acceptsConfig = {
203
+ header: 'Accept',
204
+ supports: ['application/json'],
205
+ default: 'text/html',
206
+ }
207
+ const result = accepts(c, options)
208
+ expect(result).toBe('text/html')
209
+ })
210
+
211
+ test('should skip q=0 entries and match the remaining ones', () => {
212
+ const c = {
213
+ req: {
214
+ header: () => 'text/html;q=0.5, application/json;q=0',
215
+ },
216
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
+ } as any
218
+ const options: acceptsConfig = {
219
+ header: 'Accept',
220
+ supports: ['application/json'],
221
+ default: 'application/octet-stream',
222
+ }
223
+ const result = accepts(c, options)
224
+ expect(result).toBe('application/octet-stream')
225
+ })
226
+
227
+ test('should not match a subtype wildcard the client rejected with q=0', () => {
228
+ const c = {
229
+ req: {
230
+ header: () => 'application/*;q=0',
231
+ },
232
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
233
+ } as any
234
+ const options: acceptsConfig = {
235
+ header: 'Accept',
236
+ supports: ['application/json'],
237
+ default: 'text/html',
238
+ }
239
+ const result = accepts(c, options)
240
+ expect(result).toBe('text/html')
241
+ })
242
+
243
+ describe('case insensitivity', () => {
244
+ const pick = (header: AcceptHeader, value: string, supports: string[]) => {
245
+ const c = {
246
+ req: { header: () => value },
247
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
248
+ } as any
249
+ return accepts(c, { header, supports, default: 'DEFAULT' })
250
+ }
251
+
252
+ // Media types are case-insensitive (RFC 9110 §8.3.1)
253
+ test.each(['text/html', 'TEXT/HTML', 'Text/Html', 'text/HTML'])(
254
+ 'Accept: %s matches text/html',
255
+ (value) => {
256
+ expect(pick('Accept', value, ['text/html'])).toBe('text/html')
257
+ }
258
+ )
259
+
260
+ test('a case-different subtype wildcard still matches', () => {
261
+ expect(pick('Accept', 'TEXT/*', ['text/html'])).toBe('text/html')
262
+ })
263
+
264
+ // Language tags are case-insensitive (RFC 4647 §2.1)
265
+ test.each(['en-US', 'EN-US', 'en-us', 'En-Us'])(
266
+ 'Accept-Language: %s matches en-US',
267
+ (value) => {
268
+ expect(pick('Accept-Language', value, ['en-US'])).toBe('en-US')
269
+ }
270
+ )
271
+
272
+ test('a case-different entry with q=0 is still not acceptable', () => {
273
+ expect(pick('Accept-Language', 'EN;q=0', ['en'])).toBe('DEFAULT')
274
+ })
275
+ })
276
+ })
277
+
278
+ describe('Usage', () => {
279
+ test('decide compression by Accept-Encoding header', async () => {
280
+ const app = new App()
281
+ app.get('/compressed', async (c) => {
282
+ const encoding = accepts(c, {
283
+ header: 'Accept-Encoding',
284
+ supports: ['gzip', 'deflate'],
285
+ default: 'identity',
286
+ })
287
+ const COMPRESS_DATA = 'COMPRESS_DATA'
288
+ const readable = new ReadableStream({
289
+ start(controller) {
290
+ controller.enqueue(new TextEncoder().encode(COMPRESS_DATA))
291
+ controller.close()
292
+ },
293
+ })
294
+
295
+ if (encoding === 'gzip') {
296
+ c.header('Content-Encoding', 'gzip')
297
+ return c.body(readable.pipeThrough(new CompressionStream('gzip')))
298
+ }
299
+ if (encoding === 'deflate') {
300
+ c.header('Content-Encoding', 'deflate')
301
+ return c.body(readable.pipeThrough(new CompressionStream('deflate')))
302
+ }
303
+
304
+ c.body(COMPRESS_DATA)
305
+ })
306
+
307
+ const req1 = await app.request('/compressed', { headers: { 'Accept-Encoding': 'deflate' } })
308
+ const req2 = await app.request('/compressed', { headers: { 'Accept-Encoding': 'gzip' } })
309
+ const req3 = await app.request('/compressed', {
310
+ headers: { 'Accept-Encoding': 'gzip;q=0.5,deflate' },
311
+ })
312
+ const req4 = await app.request('/compressed', { headers: { 'Accept-Encoding': 'br' } })
313
+
314
+ expect(req1.headers.get('Content-Encoding')).toBe('deflate')
315
+ expect(req2.headers.get('Content-Encoding')).toBe('gzip')
316
+ expect(req3.headers.get('Content-Encoding')).toBe('deflate')
317
+ expect(req4.headers.get('Content-Encoding')).toBeNull()
318
+ })
319
+
320
+ test('decide language by Accept-Language header', async () => {
321
+ const app = new App()
322
+ const SUPPORTED_LANGS = ['en', 'ja', 'zh']
323
+ app.get('/*', async (c) => {
324
+ const lang = accepts(c, {
325
+ header: 'Accept-Language',
326
+ supports: SUPPORTED_LANGS,
327
+ default: 'en',
328
+ })
329
+ const isLangedPath = SUPPORTED_LANGS.some((l) => c.req.path.startsWith(`/${l}`))
330
+ if (isLangedPath) {
331
+ return c.body(`lang: ${lang}`)
332
+ }
333
+
334
+ return c.redirect(`/${lang}${c.req.path}`)
335
+ })
336
+
337
+ const req1 = await app.request('/foo', { headers: { 'Accept-Language': 'en=0.8,ja' } })
338
+ const req2 = await app.request('/en/foo', { headers: { 'Accept-Language': 'en' } })
339
+
340
+ expect(req1.status).toBe(302)
341
+ expect(req1.headers.get('Location')).toBe('/ja/foo')
342
+ expect(await req2.text()).toBe('lang: en')
343
+ })
344
+ })
@@ -0,0 +1,96 @@
1
+ import type { Context } from '../../context.ts'
2
+ import { parseAccept } from '../../utils/accept.ts'
3
+ import type { AcceptHeader } from '../../utils/headers.ts'
4
+
5
+ export interface Accept {
6
+ type: string
7
+ params: Record<string, string>
8
+ q: number
9
+ }
10
+
11
+ export interface acceptsConfig {
12
+ header: AcceptHeader
13
+ supports: string[]
14
+ default: string
15
+ }
16
+
17
+ export interface acceptsOptions extends acceptsConfig {
18
+ match?: (accepts: Accept[], config: acceptsConfig) => string
19
+ }
20
+
21
+ const matchType = (acceptType: string, supportedType: string): boolean => {
22
+ // Media types and language tags are both case-insensitive (RFC 9110 §8.3.1,
23
+ // RFC 4647 §2.1), so compare them case-folded. `defaultMatch` returns the
24
+ // caller's own `supports` entry, so its casing is preserved.
25
+ const accept = acceptType.toLowerCase()
26
+ const supported = supportedType.toLowerCase()
27
+
28
+ if (accept === supported) {
29
+ return true
30
+ }
31
+ if (accept === '*/*' || accept === '*') {
32
+ return false
33
+ }
34
+ if (accept.endsWith('/*')) {
35
+ const [acceptMain] = accept.split('/')
36
+ const [supportedMain] = supported.split('/')
37
+ return acceptMain === supportedMain
38
+ }
39
+ return false
40
+ }
41
+
42
+ const getSpecificity = (type: string): number => {
43
+ if (type === '*/*' || type === '*') {
44
+ return 1
45
+ }
46
+ if (type.endsWith('/*')) {
47
+ return 2
48
+ }
49
+ return 3
50
+ }
51
+
52
+ export const defaultMatch = (accepts: Accept[], config: acceptsConfig): string => {
53
+ const { supports, default: defaultSupport } = config
54
+ // A quality value of 0 means "not acceptable" (RFC 9110 §12.5.1), so such
55
+ // entries must never match, the same rule the compress middleware applies.
56
+ const sortedAccepts = accepts
57
+ .filter((accept) => accept.q > 0)
58
+ .sort((a, b) => {
59
+ if (b.q !== a.q) {
60
+ return b.q - a.q
61
+ }
62
+ return getSpecificity(b.type) - getSpecificity(a.type)
63
+ })
64
+
65
+ for (const accept of sortedAccepts) {
66
+ const matched = supports.find((supported) => matchType(accept.type, supported))
67
+ if (matched) {
68
+ return matched
69
+ }
70
+ }
71
+ return defaultSupport
72
+ }
73
+
74
+ /**
75
+ * Match the accept header with the given options.
76
+ * @example
77
+ * ```ts
78
+ * app.get('/users', (c) => {
79
+ * const lang = accepts(c, {
80
+ * header: 'Accept-Language',
81
+ * supports: ['en', 'zh'],
82
+ * default: 'en',
83
+ * })
84
+ * })
85
+ * ```
86
+ */
87
+ export const accepts = (c: Context, options: acceptsOptions): string => {
88
+ const acceptHeader = c.req.header(options.header)
89
+ if (!acceptHeader) {
90
+ return options.default
91
+ }
92
+ const accepts = parseAccept(acceptHeader)
93
+ const match = options.match || defaultMatch
94
+
95
+ return match(accepts, options)
96
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @module
3
+ * Accepts Helper for App.
4
+ */
5
+
6
+ export { accepts } from './accepts.ts'
@@ -0,0 +1,55 @@
1
+ import { env, getRuntimeKey } from './index.ts'
2
+ import { App } from '../../app.ts'
3
+
4
+ describe('getRuntimeKey', () => {
5
+ it('Should return the current runtime key', () => {
6
+ // Now, using the `bun run test` command.
7
+ // But `vitest` depending Node.js will run this test so the RuntimeKey will be `node`.
8
+ expect(getRuntimeKey()).toBe('node')
9
+ })
10
+ })
11
+
12
+ describe('env', () => {
13
+ describe('Types', () => {
14
+ type Env = {
15
+ Bindings: {
16
+ MY_VAR: string
17
+ }
18
+ }
19
+
20
+ it('Should not throw type errors with env has generics', () => {
21
+ const app = new App()
22
+ app.get('/var', (c) => {
23
+ const { MY_VAR } = env<{ MY_VAR: string }>(c)
24
+ expectTypeOf<string>(MY_VAR)
25
+ return c.json({
26
+ var: MY_VAR,
27
+ })
28
+ })
29
+ })
30
+
31
+ it('Should not throw type errors with App has generics', () => {
32
+ const app = new App<Env>()
33
+
34
+ app.get('/var', (c) => {
35
+ const { MY_VAR } = env(c)
36
+ expectTypeOf<string>(MY_VAR)
37
+ return c.json({
38
+ var: MY_VAR,
39
+ })
40
+ })
41
+ })
42
+
43
+ it('Should not throw type errors with env and App have generics', () => {
44
+ const app = new App<Env>()
45
+
46
+ app.get('/var', (c) => {
47
+ const { MY_VAR } = env<{ MY_VAR: string }>(c)
48
+ expectTypeOf<string>(MY_VAR)
49
+ return c.json({
50
+ var: MY_VAR,
51
+ })
52
+ })
53
+ })
54
+ })
55
+ })
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @module
3
+ * Adapter Helper for App.
4
+ */
5
+
6
+ import type { Context } from '../../context.ts'
7
+
8
+ export type Runtime = 'node' | 'deno' | 'bun' | 'workerd' | 'fastly' | 'edge-light' | 'other'
9
+
10
+ export const env = <
11
+ T extends Record<string, unknown>,
12
+ C extends Context = Context<{
13
+ Bindings: T
14
+ }>,
15
+ >(
16
+ c: T extends Record<string, unknown> ? Context : C,
17
+ runtime?: Runtime
18
+ ): T & C['env'] => {
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ const global = globalThis as any
21
+ const globalEnv = global?.process?.env as T
22
+
23
+ runtime ??= getRuntimeKey()
24
+
25
+ const runtimeEnvHandlers: Record<string, () => T> = {
26
+ bun: () => globalEnv,
27
+ node: () => globalEnv,
28
+ 'edge-light': () => globalEnv,
29
+ deno: () => {
30
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
31
+ // @ts-ignore
32
+ return Deno.env.toObject() as T
33
+ },
34
+ workerd: () => c.env,
35
+ // On Fastly Compute, you can use the ConfigStore to manage user-defined data.
36
+ fastly: () => ({}) as T,
37
+ other: () => ({}) as T,
38
+ }
39
+
40
+ return runtimeEnvHandlers[runtime]()
41
+ }
42
+
43
+ export const knownUserAgents: Partial<Record<Runtime, string>> = {
44
+ deno: 'Deno',
45
+ bun: 'Bun',
46
+ workerd: 'Cloudflare-Workers',
47
+ node: 'Node.js',
48
+ }
49
+
50
+ export const getRuntimeKey = (): Runtime => {
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ const global = globalThis as any
53
+
54
+ // check if the current runtime supports navigator.userAgent
55
+ const userAgentSupported =
56
+ typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string'
57
+
58
+ // if supported, check the user agent
59
+ if (userAgentSupported) {
60
+ for (const [runtimeKey, userAgent] of Object.entries(knownUserAgents)) {
61
+ if (checkUserAgentEquals(userAgent)) {
62
+ return runtimeKey as Runtime
63
+ }
64
+ }
65
+ }
66
+
67
+ // check if running on Edge Runtime
68
+ if (typeof global?.EdgeRuntime === 'string') {
69
+ return 'edge-light'
70
+ }
71
+
72
+ // check if running on Fastly
73
+ if (global?.fastly !== undefined) {
74
+ return 'fastly'
75
+ }
76
+
77
+ // userAgent isn't supported before Node v21.1.0; so fallback to the old way
78
+ if (global?.process?.release?.name === 'node') {
79
+ return 'node'
80
+ }
81
+
82
+ // couldn't detect the runtime
83
+ return 'other'
84
+ }
85
+
86
+ export const checkUserAgentEquals = (platform: string): boolean => {
87
+ const userAgent = navigator.userAgent
88
+
89
+ return userAgent.startsWith(platform)
90
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @module
3
+ * ConnInfo Helper for App.
4
+ */
5
+
6
+ export type { AddressType, NetAddrInfo, ConnInfo, GetConnInfo } from './types.ts'
@@ -0,0 +1,45 @@
1
+ import type { Context } from '../../context.ts'
2
+
3
+ export type AddressType = 'IPv6' | 'IPv4' | undefined
4
+
5
+ export type NetAddrInfo = {
6
+ /**
7
+ * Transport protocol type
8
+ */
9
+ transport?: 'tcp' | 'udp'
10
+ /**
11
+ * Transport port number
12
+ */
13
+ port?: number
14
+
15
+ address?: string
16
+ addressType?: AddressType
17
+ } & (
18
+ | {
19
+ /**
20
+ * Host name such as IP Addr
21
+ */
22
+ address: string
23
+
24
+ /**
25
+ * Host name type
26
+ */
27
+ addressType: AddressType
28
+ }
29
+ | {}
30
+ )
31
+
32
+ /**
33
+ * HTTP Connection information
34
+ */
35
+ export interface ConnInfo {
36
+ /**
37
+ * Remote information
38
+ */
39
+ remote: NetAddrInfo
40
+ }
41
+
42
+ /**
43
+ * Helper type
44
+ */
45
+ export type GetConnInfo = (c: Context) => ConnInfo