acrylblends 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/LICENSE +73 -0
  2. package/docs/framework/README.md +51 -51
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/agents/index.md +24 -0
  5. package/docs/framework/api/acryl.md +259 -0
  6. package/docs/framework/api/context.md +527 -0
  7. package/docs/framework/api/exception.md +80 -0
  8. package/docs/framework/api/index.md +12 -0
  9. package/docs/framework/api/presets.md +65 -0
  10. package/docs/framework/api/request.md +396 -0
  11. package/docs/framework/api/routing.md +303 -0
  12. package/docs/framework/{api-summary.md → api/summary.md} +19 -17
  13. package/docs/framework/concepts/benchmarks.md +26 -0
  14. package/docs/framework/concepts/developer-experience.md +5 -0
  15. package/docs/framework/concepts/middleware.md +21 -0
  16. package/docs/framework/concepts/motivation.md +14 -0
  17. package/docs/framework/concepts/routers.md +63 -0
  18. package/docs/framework/concepts/stacks.md +235 -0
  19. package/docs/framework/concepts/web-standard.md +37 -0
  20. package/docs/framework/{getting-started.md → cordis/acryl-in-a-cordis-app.md} +16 -16
  21. package/docs/framework/{concepts.md → cordis/concepts.md} +2 -2
  22. package/docs/framework/cordis/middleware.md +8 -0
  23. package/docs/framework/{migration-from-0-3.md → cordis/migration-from-0-3.md} +16 -13
  24. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  25. package/docs/framework/{migration-from-dsh-webserver.md → cordis/migration-from-dsh-webserver.md} +7 -7
  26. package/docs/framework/{routing.md → cordis/mounting.md} +5 -108
  27. package/docs/framework/{node-server.md → cordis/node-server.md} +4 -4
  28. package/docs/framework/{surfaces.md → cordis/surfaces.md} +2 -2
  29. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  30. package/docs/framework/{validation.md → cordis/validation.md} +9 -9
  31. package/docs/framework/getting-started/basic.md +196 -0
  32. package/docs/framework/getting-started/bun.md +221 -0
  33. package/docs/framework/getting-started/nodejs.md +344 -0
  34. package/docs/framework/getting-started/other-runtimes.md +23 -0
  35. package/docs/framework/guides/best-practices.md +231 -0
  36. package/docs/framework/guides/create-acrylblends.md +79 -0
  37. package/docs/framework/guides/examples.md +3 -0
  38. package/docs/framework/guides/faq.md +19 -0
  39. package/docs/framework/guides/helpers.md +33 -0
  40. package/docs/framework/guides/jsx-dom.md +299 -0
  41. package/docs/framework/guides/jsx.md +440 -0
  42. package/docs/framework/guides/middleware.md +253 -0
  43. package/docs/framework/guides/rpc.md +886 -0
  44. package/docs/framework/guides/testing.md +133 -0
  45. package/docs/framework/guides/validation.md +383 -0
  46. package/docs/framework/helpers/accepts.md +60 -0
  47. package/docs/framework/helpers/adapter.md +87 -0
  48. package/docs/framework/helpers/conninfo.md +112 -0
  49. package/docs/framework/helpers/cookie.md +232 -0
  50. package/docs/framework/helpers/css.md +285 -0
  51. package/docs/framework/helpers/dev.md +67 -0
  52. package/docs/framework/helpers/factory.md +180 -0
  53. package/docs/framework/helpers/html.md +123 -0
  54. package/docs/framework/helpers/jwt.md +184 -0
  55. package/docs/framework/helpers/proxy.md +118 -0
  56. package/docs/framework/helpers/route.md +143 -0
  57. package/docs/framework/helpers/ssg.md +393 -0
  58. package/docs/framework/helpers/streaming.md +119 -0
  59. package/docs/framework/helpers/testing.md +101 -0
  60. package/docs/framework/helpers/websocket.md +215 -0
  61. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  62. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  63. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  64. package/docs/framework/middleware/builtin/cache.md +122 -0
  65. package/docs/framework/middleware/builtin/combine.md +94 -0
  66. package/docs/framework/middleware/builtin/compress.md +59 -0
  67. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  68. package/docs/framework/middleware/builtin/cors.md +135 -0
  69. package/docs/framework/middleware/builtin/csrf.md +105 -0
  70. package/docs/framework/middleware/builtin/etag.md +54 -0
  71. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  72. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  73. package/docs/framework/middleware/builtin/jwk.md +192 -0
  74. package/docs/framework/middleware/builtin/jwt.md +145 -0
  75. package/docs/framework/middleware/builtin/language.md +232 -0
  76. package/docs/framework/middleware/builtin/logger.md +74 -0
  77. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  78. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  79. package/docs/framework/middleware/builtin/method-override.md +80 -0
  80. package/docs/framework/middleware/builtin/mount.md +106 -0
  81. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  82. package/docs/framework/middleware/builtin/request-id.md +94 -0
  83. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  84. package/docs/framework/middleware/builtin/timeout.md +98 -0
  85. package/docs/framework/middleware/builtin/timing.md +101 -0
  86. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  87. package/docs/framework/middleware/third-party.md +4 -0
  88. package/docs/framework/upstream.json +3 -3
  89. package/lib/accepts-XBuZPVRI.js +52 -0
  90. package/lib/accepts.d.ts +33 -0
  91. package/lib/accepts.js +2 -0
  92. package/lib/acryl-base.d.ts +2 -0
  93. package/lib/acryl-base.js +332 -0
  94. package/lib/adapter.d.ts +12 -0
  95. package/lib/adapter.js +37 -0
  96. package/lib/app-BM0rTCp7.js +26 -0
  97. package/lib/app-CmAYW1Al.d.ts +21 -0
  98. package/lib/basic-auth.d.ts +72 -0
  99. package/lib/basic-auth.js +95 -0
  100. package/lib/bearer-auth.d.ts +89 -0
  101. package/lib/bearer-auth.js +94 -0
  102. package/lib/body-limit.d.ts +42 -0
  103. package/lib/body-limit.js +66 -0
  104. package/lib/client-BHTr318g.js +266 -0
  105. package/lib/client.d.ts +3 -0
  106. package/lib/client.js +2 -0
  107. package/lib/combine.d.ts +85 -0
  108. package/lib/combine.js +137 -0
  109. package/lib/compose-BuW2B6PZ.js +50 -0
  110. package/lib/compress.d.ts +38 -0
  111. package/lib/compress.js +79 -0
  112. package/lib/connection-C7xgP1hP.js +24 -0
  113. package/lib/conninfo.d.ts +25 -0
  114. package/lib/conninfo.js +2 -0
  115. package/lib/constants-Dy7ZvN1H.js +4 -0
  116. package/lib/context-Bm7rI-oK.d.ts +1234 -0
  117. package/lib/context-DDO0cfuP.js +365 -0
  118. package/lib/context-storage.d.ts +38 -0
  119. package/lib/context-storage.js +52 -0
  120. package/lib/cookie-ClMaKDQf.d.ts +40 -0
  121. package/lib/cookie.d.ts +24 -0
  122. package/lib/cookie.js +82 -0
  123. package/lib/cors.d.ts +52 -0
  124. package/lib/cors.js +106 -0
  125. package/lib/csrf.d.ts +75 -0
  126. package/lib/csrf.js +101 -0
  127. package/lib/etag.d.ts +40 -0
  128. package/lib/etag.js +135 -0
  129. package/lib/factory.d.ts +35 -0
  130. package/lib/factory.js +30 -0
  131. package/lib/headers-tu2YYN8T.d.ts +11 -0
  132. package/lib/html.d.ts +6 -0
  133. package/lib/html.js +31 -0
  134. package/lib/http-exception.d.ts +57 -0
  135. package/lib/http-exception.js +54 -0
  136. package/lib/http-status-DaAwGAFL.d.ts +35 -0
  137. package/lib/index-B-3F4wt2.d.ts +12 -0
  138. package/lib/index-UTBmM3GX.d.ts +68 -0
  139. package/lib/index-oOClm_Xk.d.ts +45 -0
  140. package/lib/index.d.ts +5 -0
  141. package/lib/index.js +28 -0
  142. package/lib/ip-restriction.d.ts +68 -0
  143. package/lib/ip-restriction.js +166 -0
  144. package/lib/jwk.d.ts +52 -0
  145. package/lib/jwk.js +117 -0
  146. package/lib/jwt-BGJBw5AF.js +403 -0
  147. package/lib/jwt-Dg493Tai.d.ts +51 -0
  148. package/lib/jwt.d.ts +72 -0
  149. package/lib/jwt.js +115 -0
  150. package/lib/language.d.ts +88 -0
  151. package/lib/language.js +198 -0
  152. package/lib/logger.d.ts +22 -0
  153. package/lib/logger.js +54 -0
  154. package/lib/loopback-only.d.ts +45 -0
  155. package/lib/loopback-only.js +90 -0
  156. package/lib/method-not-allowed.d.ts +47 -0
  157. package/lib/method-not-allowed.js +82 -0
  158. package/lib/method-override.d.ts +46 -0
  159. package/lib/method-override.js +103 -0
  160. package/lib/mime-BQOYHl-l.d.ts +72 -0
  161. package/lib/node-server/conninfo.d.ts +11 -0
  162. package/lib/node-server/conninfo.js +19 -0
  163. package/lib/node-server/serve-static.d.ts +19 -0
  164. package/lib/node-server/serve-static.js +2 -0
  165. package/lib/node-server.d.ts +103 -0
  166. package/lib/node-server.js +1325 -0
  167. package/lib/powered-by.d.ts +28 -0
  168. package/lib/powered-by.js +24 -0
  169. package/lib/pretty-json.d.ts +40 -0
  170. package/lib/pretty-json.js +39 -0
  171. package/lib/reg-exp-router-DC1R3qoY.js +363 -0
  172. package/lib/request-id.d.ts +45 -0
  173. package/lib/request-id.js +34 -0
  174. package/lib/request.d.ts +2 -0
  175. package/lib/request.js +323 -0
  176. package/lib/route.d.ts +78 -0
  177. package/lib/route.js +126 -0
  178. package/lib/router/linear-router.d.ts +11 -0
  179. package/lib/router/linear-router.js +96 -0
  180. package/lib/router/pattern-router.d.ts +11 -0
  181. package/lib/router/pattern-router.js +41 -0
  182. package/lib/router/reg-exp-router.d.ts +35 -0
  183. package/lib/router/reg-exp-router.js +2 -0
  184. package/lib/router/smart-router.d.ts +15 -0
  185. package/lib/router/smart-router.js +2 -0
  186. package/lib/router/trie-router.d.ts +11 -0
  187. package/lib/router/trie-router.js +2 -0
  188. package/lib/router-CvUxUTOq.d.ts +99 -0
  189. package/lib/router.d.ts +2 -0
  190. package/lib/router.js +35 -0
  191. package/lib/schema-validator.d.ts +28 -0
  192. package/lib/schema-validator.js +22 -0
  193. package/lib/secure-headers.d.ts +125 -0
  194. package/lib/secure-headers.js +163 -0
  195. package/lib/serve-static-Dw_m6KxR.js +213 -0
  196. package/lib/serve-static.d.ts +31 -0
  197. package/lib/serve-static.js +77 -0
  198. package/lib/smart-router-C5CZ5XSM.js +49 -0
  199. package/lib/stream-CPdqZ0Fp.d.ts +34 -0
  200. package/lib/streaming-DHST3Scg.js +96 -0
  201. package/lib/streaming.d.ts +23 -0
  202. package/lib/streaming.js +2 -0
  203. package/lib/testing.d.ts +10 -0
  204. package/lib/testing.js +17 -0
  205. package/lib/timeout.d.ts +30 -0
  206. package/lib/timeout.js +42 -0
  207. package/lib/timing.d.ts +130 -0
  208. package/lib/timing.js +183 -0
  209. package/lib/trailing-slash.d.ts +91 -0
  210. package/lib/trailing-slash.js +85 -0
  211. package/lib/trie-router-CfFbapzL.js +146 -0
  212. package/lib/types-CDO6I3B0.d.ts +40 -0
  213. package/lib/types-CHesD1KG.d.ts +195 -0
  214. package/lib/types-CwrQjlaM.d.ts +105 -0
  215. package/lib/types-DR95J00T.d.ts +29 -0
  216. package/lib/types.d.ts +2 -0
  217. package/lib/types.js +4 -0
  218. package/lib/utils/accept.d.ts +9 -0
  219. package/lib/utils/accept.js +193 -0
  220. package/lib/utils/basic-auth.d.ts +8 -0
  221. package/lib/utils/basic-auth.js +20 -0
  222. package/lib/utils/body.d.ts +2 -0
  223. package/lib/utils/body.js +94 -0
  224. package/lib/utils/buffer.d.ts +19 -0
  225. package/lib/utils/buffer.js +51 -0
  226. package/lib/utils/color.d.ts +24 -0
  227. package/lib/utils/color.js +37 -0
  228. package/lib/utils/compress.d.ts +11 -0
  229. package/lib/utils/compress.js +11 -0
  230. package/lib/utils/concurrent.d.ts +17 -0
  231. package/lib/utils/concurrent.js +30 -0
  232. package/lib/utils/constants.d.ts +7 -0
  233. package/lib/utils/constants.js +7 -0
  234. package/lib/utils/cookie.d.ts +2 -0
  235. package/lib/utils/cookie.js +125 -0
  236. package/lib/utils/crypto.d.ts +14 -0
  237. package/lib/utils/crypto.js +34 -0
  238. package/lib/utils/encode.d.ts +11 -0
  239. package/lib/utils/encode.js +33 -0
  240. package/lib/utils/filepath.d.ts +14 -0
  241. package/lib/utils/filepath.js +25 -0
  242. package/lib/utils/handler.d.ts +9 -0
  243. package/lib/utils/handler.js +12 -0
  244. package/lib/utils/headers.d.ts +2 -0
  245. package/lib/utils/headers.js +1 -0
  246. package/lib/utils/html.d.ts +46 -0
  247. package/lib/utils/html.js +103 -0
  248. package/lib/utils/http-status.d.ts +2 -0
  249. package/lib/utils/http-status.js +1 -0
  250. package/lib/utils/ipaddr.d.ts +56 -0
  251. package/lib/utils/ipaddr.js +238 -0
  252. package/lib/utils/jwt.d.ts +24 -0
  253. package/lib/utils/jwt.js +2 -0
  254. package/lib/utils/mime.d.ts +2 -0
  255. package/lib/utils/mime.js +77 -0
  256. package/lib/utils/stream.d.ts +2 -0
  257. package/lib/utils/stream.js +88 -0
  258. package/lib/utils/types.d.ts +2 -0
  259. package/lib/utils/types.js +1 -0
  260. package/lib/utils/url.d.ts +46 -0
  261. package/lib/utils/url.js +197 -0
  262. package/lib/utils-dw8lxqjL.js +4 -0
  263. package/lib/validator-D84mq-dO.js +65 -0
  264. package/lib/validator.d.ts +42 -0
  265. package/lib/validator.js +2 -0
  266. package/lib/ws.d.ts +2 -0
  267. package/lib/ws.js +53 -0
  268. package/package.json +312 -14
  269. package/plugins/acryl-inspect/src/service.ts +2 -2
  270. package/plugins/acryl-inspect/tests/service.spec.ts +3 -3
  271. package/plugins/acryl-inspect/upstream.json +2 -2
  272. package/plugins/acryl-node-server/tests/adapter/app.ts +2 -2
  273. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -1
  274. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -1
  275. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +2 -2
  276. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +4 -4
  277. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +5 -5
  278. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +2 -2
  279. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +20 -20
  280. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +2 -2
  281. package/plugins/acryl-node-server/tests/adapter/server.test.ts +50 -50
  282. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +4 -4
  283. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +9 -9
  284. package/plugins/acryl-node-server/tests/server.spec.ts +6 -6
  285. package/plugins/acryl-node-server/upstream.json +2 -2
  286. package/plugins/acryl-router/src/client.ts +1 -1
  287. package/plugins/acryl-router/src/connection.ts +2 -2
  288. package/plugins/acryl-router/src/core/app-base.ts +29 -29
  289. package/plugins/acryl-router/src/core/app.test.ts +175 -175
  290. package/plugins/acryl-router/src/core/app.ts +8 -8
  291. package/plugins/acryl-router/src/core/client/client.test.ts +76 -76
  292. package/plugins/acryl-router/src/core/client/client.ts +2 -2
  293. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +1 -1
  294. package/plugins/acryl-router/src/core/client/index.ts +1 -1
  295. package/plugins/acryl-router/src/core/client/types.test.ts +6 -6
  296. package/plugins/acryl-router/src/core/client/types.ts +16 -16
  297. package/plugins/acryl-router/src/core/client/utils.test.ts +2 -2
  298. package/plugins/acryl-router/src/core/context.test.ts +4 -4
  299. package/plugins/acryl-router/src/core/context.ts +6 -6
  300. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +3 -3
  301. package/plugins/acryl-router/src/core/helper/accepts/index.ts +1 -1
  302. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +6 -6
  303. package/plugins/acryl-router/src/core/helper/adapter/index.ts +1 -1
  304. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +1 -1
  305. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +8 -8
  306. package/plugins/acryl-router/src/core/helper/cookie/index.ts +1 -1
  307. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +9 -9
  308. package/plugins/acryl-router/src/core/helper/factory/index.ts +10 -10
  309. package/plugins/acryl-router/src/core/helper/html/index.test.ts +4 -4
  310. package/plugins/acryl-router/src/core/helper/html/index.ts +1 -1
  311. package/plugins/acryl-router/src/core/helper/route/index.test.ts +7 -7
  312. package/plugins/acryl-router/src/core/helper/route/index.ts +8 -8
  313. package/plugins/acryl-router/src/core/helper/streaming/index.ts +1 -1
  314. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +6 -6
  315. package/plugins/acryl-router/src/core/helper/testing/index.ts +4 -4
  316. package/plugins/acryl-router/src/core/helper/websocket/index.ts +2 -1
  317. package/plugins/acryl-router/src/core/http-exception.ts +1 -1
  318. package/plugins/acryl-router/src/core/index.ts +9 -9
  319. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +6 -6
  320. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +3 -3
  321. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +5 -5
  322. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +3 -3
  323. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +6 -6
  324. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +3 -3
  325. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +9 -9
  326. package/plugins/acryl-router/src/core/middleware/combine/index.ts +7 -7
  327. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +9 -9
  328. package/plugins/acryl-router/src/core/middleware/compress/index.ts +3 -3
  329. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +5 -5
  330. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +4 -4
  331. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +7 -7
  332. package/plugins/acryl-router/src/core/middleware/cors/index.ts +3 -3
  333. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +10 -10
  334. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +3 -3
  335. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +42 -42
  336. package/plugins/acryl-router/src/core/middleware/etag/index.ts +4 -4
  337. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +4 -4
  338. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +6 -6
  339. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +16 -16
  340. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +7 -6
  341. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +16 -16
  342. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +4 -3
  343. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +3 -3
  344. package/plugins/acryl-router/src/core/middleware/language/language.ts +3 -3
  345. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +5 -5
  346. package/plugins/acryl-router/src/core/middleware/logger/index.ts +4 -4
  347. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +24 -24
  348. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +8 -8
  349. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +5 -5
  350. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +6 -6
  351. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +4 -4
  352. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +6 -6
  353. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +30 -30
  354. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +4 -4
  355. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +15 -15
  356. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +3 -3
  357. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +35 -35
  358. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +3 -3
  359. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +23 -23
  360. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +1 -1
  361. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +2 -2
  362. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +3 -3
  363. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +14 -14
  364. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +3 -3
  365. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +7 -7
  366. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +7 -7
  367. package/plugins/acryl-router/src/core/request.test.ts +42 -42
  368. package/plugins/acryl-router/src/core/request.ts +6 -6
  369. package/plugins/acryl-router/src/core/router/linear-router/index.ts +1 -1
  370. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +1 -1
  371. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +1 -1
  372. package/plugins/acryl-router/src/core/router/smart-router/index.ts +1 -1
  373. package/plugins/acryl-router/src/core/router/trie-router/index.ts +1 -1
  374. package/plugins/acryl-router/src/core/types.test.ts +115 -115
  375. package/plugins/acryl-router/src/core/types.ts +72 -72
  376. package/plugins/acryl-router/src/core/utils/body.ts +8 -8
  377. package/plugins/acryl-router/src/core/utils/html.ts +1 -1
  378. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +3 -3
  379. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +2 -2
  380. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +3 -3
  381. package/plugins/acryl-router/src/core/utils/jwt/types.ts +1 -1
  382. package/plugins/acryl-router/src/core/utils/types.ts +42 -0
  383. package/plugins/acryl-router/src/core/utils/url.test.ts +2 -2
  384. package/plugins/acryl-router/src/core/validator/index.ts +1 -1
  385. package/plugins/acryl-router/src/core/validator/validator.test.ts +28 -28
  386. package/plugins/acryl-router/src/deprecated.ts +15 -0
  387. package/plugins/acryl-router/src/index.ts +3 -2
  388. package/plugins/acryl-router/src/service.ts +10 -10
  389. package/plugins/acryl-router/tests/docs-examples.spec.ts +11 -11
  390. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  391. package/plugins/acryl-router/tests/loader.spec.ts +3 -3
  392. package/plugins/acryl-router/tests/loopback-only.spec.ts +4 -4
  393. package/plugins/acryl-router/tests/no-dom/consumer.ts +11 -0
  394. package/plugins/acryl-router/tests/no-dom/tsconfig.json +13 -0
  395. package/plugins/acryl-router/tests/service.spec.ts +23 -23
  396. package/plugins/acryl-router/upstream.json +3 -3
  397. package/plugins/acryl-router-http/tests/adapter.spec.ts +3 -3
  398. package/plugins/acryl-router-http/tests/surfaces.spec.ts +2 -2
  399. package/plugins/acryl-router-http/upstream.json +2 -2
  400. package/plugins/acryl-state/src/service.ts +2 -2
  401. package/plugins/acryl-state/upstream.json +2 -2
  402. package/plugins/builder/script.ts +2 -2
  403. package/plugins/extensions/resolve.ts +70 -10
  404. package/plugins/openai/prompt.ts +5 -5
  405. package/shared/AGENTS.core.md +16 -9
  406. package/templates/agent/src/routes.ts +2 -2
  407. package/templates/agent/test/model.test.ts +2 -2
  408. package/templates/agent/tsconfig.json +40 -0
  409. package/templates/blank/src/routes.ts +2 -2
  410. package/templates/todo/src/todo.ts +2 -2
  411. package/templates/todo/upstream.json +2 -2
  412. package/docs/framework/context.md +0 -129
  413. package/docs/framework/helpers.md +0 -118
  414. package/docs/framework/middleware.md +0 -154
  415. package/docs/framework/request.md +0 -106
  416. /package/docs/framework/{plugin-lifecycle.md → cordis/plugin-lifecycle.md} +0 -0
@@ -5,8 +5,8 @@
5
5
  "examples/acryl-todo/src/index.ts": "src/todo.ts",
6
6
  "examples/acryl-todo/src/page.ts": "src/page.ts"
7
7
  },
8
- "commit": "64e7c9d2e787f74b2da82492644fbbb46a601074"
8
+ "commit": "f5151e7f0c4de3b81bddb5cc686b5ef329e48e1c"
9
9
  },
10
10
  "rewrittenSpecifiers": 4,
11
- "digest": "sha256:b62b5167344084f7ac03c8286923f92419a4ab41c5d8235adb3247d983807aca"
11
+ "digest": "sha256:9093704776563001f7f472f94cc5c2fdd79206342c1cb59c11fce62aa74df3ed"
12
12
  }
@@ -1,129 +0,0 @@
1
- # Context
2
-
3
- Every handler and middleware receives a context, normally named `c`. The context connects the current request, the response being built,
4
- route data, transport information and work that must finish after the response. It lives for one request.
5
-
6
- ## Return a response
7
-
8
- ```ts
9
- app.get('/text', c => c.text('Hello'))
10
- app.get('/json', c => c.json({ ok: true }))
11
- app.get('/html', c => c.html('<h1>Hello</h1>'))
12
- app.get('/empty', c => c.body(null, 204))
13
- app.get('/raw', () => new Response('Good morning!'))
14
- app.get('/notfound', c => c.notFound())
15
- app.get('/redirect', c => c.redirect('/')) // 302
16
- app.get('/moved', c => c.redirect('/', 301))
17
- ```
18
-
19
- Set the status and headers before or with the body:
20
-
21
- ```ts
22
- app.post('/posts', c => {
23
- c.status(201)
24
- c.header('X-Message', 'created')
25
- return c.json({ created: true })
26
- })
27
-
28
- app.get('/welcome', c => c.body('Thank you for coming', 201, { 'X-Message': 'Hello!', 'Content-Type': 'text/plain' }))
29
- ```
30
-
31
- ## The response on the way out
32
-
33
- Middleware can read or replace the response after `next()`:
34
-
35
- ```ts
36
- app.use(async (c, next) => {
37
- await next()
38
- c.res.headers.append('X-Debug', 'Debug message')
39
- })
40
- ```
41
-
42
- ## Read request data
43
-
44
- The request object is `c.req`:
45
-
46
- ```ts
47
- const id = c.req.param('id')
48
- const search = c.req.query('q')
49
- const agent = c.req.header('User-Agent')
50
- ```
51
-
52
- See [Request](./request.md) for bodies, repeated values and validated input.
53
-
54
- ## Store request-local values
55
-
56
- `c.set` and `c.get` (or `c.var.name`) pass data from middleware to handlers. Declare the variables as the app's type parameter so both
57
- sides agree:
58
-
59
- ```ts
60
- const app = new App<{ Variables: { requestId: string } }>()
61
-
62
- app.use(async (c, next) => {
63
- c.set('requestId', crypto.randomUUID())
64
- await next()
65
- })
66
-
67
- app.get('/', c => c.text(c.get('requestId')))
68
- ```
69
-
70
- These values live only for the current request. Do not use them as a cache or as application state. `createMiddleware` (from
71
- `acryl-router/helpers`) types a middleware that sets variables, and chained `.use(...)` calls accumulate their types; see
72
- [Middleware](./middleware.md).
73
-
74
- ## Transport facts
75
-
76
- `c.env` carries what the caller of the router supplied for this request. Under the router that is `{ connection }`: the socket's peer
77
- address and the real local port, filled by the HTTP adapter and empty for an in-process call. Transport facts never travel in headers.
78
-
79
- ```ts
80
- import { App, connectionOf, type RouterEnv } from 'acryl-router'
81
- import { getConnInfo } from 'acryl-router/helpers'
82
-
83
- const app = new App<RouterEnv>() // types c.env.connection
84
- app.get('/peer', c => c.json({
85
- connection: connectionOf(c), // { remoteAddress?, localPort? }
86
- info: getConnInfo(c), // the same peer in the core's conninfo shape, for middleware such as ipRestriction
87
- }))
88
- ```
89
-
90
- The same handler then runs over HTTP, in process or in a test, and reads an empty connection where there is no socket. Guards such as
91
- `loopbackOnly` refuse an empty one unless told otherwise.
92
-
93
- ## Cancellation and background work
94
-
95
- - `c.req.raw.signal` aborts when the caller goes away, when the plugin whose code is serving the request unloads, and when the router is
96
- disposed. Long work
97
- should pass it on (`fetch(url, { signal: c.req.raw.signal })`) or check it.
98
- - `c.executionCtx.waitUntil(promise)` keeps the request in flight until the promise settles, for work that continues after the response
99
- is returned.
100
-
101
- Both belong to the current request, and both end with their owner: see [Plugin lifecycle](./plugin-lifecycle.md#disposal-sequence).
102
-
103
- ## Errors and control flow
104
-
105
- Return a response for expected failures, or throw an `HTTPException`, which becomes its own response:
106
-
107
- ```ts
108
- import { HTTPException } from 'acryl-router'
109
-
110
- if (!todo) return c.json({ error: 'todo_not_found' }, 404)
111
- if (!allowed) throw new HTTPException(403, { message: 'not yours' })
112
- ```
113
-
114
- Anything else that is thrown goes to the app's `onError`, or to the router's when the app has none. A middleware's `await next()` never
115
- throws: the error has already become a response by then, and the error itself is in `c.error`:
116
-
117
- ```ts
118
- app.use(async (c, next) => {
119
- await next()
120
- if (c.error) report(c.error)
121
- })
122
- ```
123
-
124
- ## Context rules
125
-
126
- - Treat the context as request-local.
127
- - Do not retain it after the handler returns.
128
- - Do not put sockets, server objects or Cordis internals into context values for other plugins to discover accidentally.
129
- - Put cross-plugin capabilities in a declared Cordis service, not in `c.set`.
@@ -1,118 +0,0 @@
1
- # Helpers
2
-
3
- Helpers are small utilities an application should not have to rewrite. They are plain functions over the context, not Cordis services.
4
- Import them from `acryl-router/helpers`, except the typed client, which has its own entry, `acryl-router/client`.
5
-
6
- | Helper | Use |
7
- | --- | --- |
8
- | `stream`, `streamText`, `streamSSE` | streaming responses and server-sent events |
9
- | `getCookie`, `setCookie`, `deleteCookie`, `getSignedCookie`, `setSignedCookie`, `generateCookie`, `generateSignedCookie` | cookies |
10
- | `testClient` | a typed client that calls an app in process, for tests |
11
- | `validator`, `schemaValidator` | input validation, see [Validation](./validation.md) |
12
- | `createMiddleware`, `createFactory` | typed middleware and handlers that share variables |
13
- | `html`, `raw` | escaped HTML templates |
14
- | `accepts` | content negotiation from `Accept` headers |
15
- | `routePath`, `matchedRoutes`, `baseRoutePath`, `basePath` | the route a request matched |
16
- | `getConnInfo`, `connectionOf` | the peer and local port, see [Context](./context.md#transport-facts) |
17
- | `getMimeType`, `getExtension`, `mimes` | media types by file extension |
18
- | `defineWebSocketHelper`, `WSContext` and their types | the runtime-neutral WebSocket pieces an adapter builds on |
19
-
20
- JWT signing and verification (`sign`, `verify`, `decode`) live with the `jwt` middleware in `acryl-router/middleware`.
21
-
22
- ## Streaming
23
-
24
- ```ts
25
- import { stream, streamSSE, streamText } from 'acryl-router/helpers'
26
-
27
- app.get('/stream', c => stream(c, async stream => {
28
- stream.onAbort(() => console.log('aborted'))
29
- await stream.write(new Uint8Array([0x48, 0x69]))
30
- await stream.pipe(anotherReadableStream)
31
- }))
32
-
33
- app.get('/text', c => streamText(c, async stream => {
34
- await stream.writeln('Hello')
35
- await stream.sleep(1000)
36
- await stream.write('there')
37
- }))
38
- ```
39
-
40
- Server-sent events write one message at a time with `writeSSE`:
41
-
42
- ```ts
43
- app.get('/events', c => streamSSE(c, async stream => {
44
- let id = 0
45
- while (!stream.aborted) {
46
- await stream.writeSSE({ event: 'time', data: new Date().toISOString(), id: String(id++) })
47
- await stream.sleep(1000)
48
- }
49
- }))
50
- ```
51
-
52
- - The callback runs after the response is returned. When it throws, the optional third argument `onError(error, stream)` runs and the
53
- stream sends an `error` event before it closes.
54
- - There is no built-in keep-alive: send a comment or an event on a timer when a proxy closes idle connections.
55
- - When the plugin that serves the stream unloads, or the router is disposed, the router cancels the response body, so `onAbort` runs,
56
- `aborted` turns true and a loop that checks `stream.aborted` ends with its owner.
57
-
58
- ## Cookies
59
-
60
- ```ts
61
- import { deleteCookie, getCookie, getSignedCookie, setCookie, setSignedCookie } from 'acryl-router/helpers'
62
-
63
- app.get('/cookie', c => {
64
- setCookie(c, 'theme', 'dark', { path: '/', httpOnly: true, secure: true, sameSite: 'Strict', maxAge: 60 * 60 * 24 })
65
- const theme = getCookie(c, 'theme')
66
- const all = getCookie(c)
67
- deleteCookie(c, 'old')
68
- return c.json({ theme, all })
69
- })
70
-
71
- app.get('/signed', async c => {
72
- await setSignedCookie(c, 'session', 'value', secret)
73
- const session = await getSignedCookie(c, secret, 'session') // false when the signature does not match
74
- return c.json({ session })
75
- })
76
- ```
77
-
78
- `generateCookie` and `generateSignedCookie` return the `Set-Cookie` string without touching a context. The `__Secure-` and `__Host-`
79
- prefixes are available through `{ prefix: 'secure' }` and `{ prefix: 'host' }`, and the options are checked against their rules.
80
-
81
- ## Testing
82
-
83
- `app.request(path, init?)` calls an app in process and returns a `Response`. `testClient` adds the route types:
84
-
85
- ```ts
86
- import { testClient } from 'acryl-router/helpers'
87
-
88
- const app = new App()
89
- .get('/search', c => c.json({ query: c.req.query('q') }))
90
-
91
- const client = testClient(app)
92
- const response = await client.search.$get({ query: { q: 'cordis' } })
93
- expect(await response.json()).toEqual({ query: 'cordis' })
94
- ```
95
-
96
- The routes must be chained on one expression (as above) for their types to reach the client. Add a test through the Cordis router as well:
97
- an app test cannot prove the mount, the prefix or the disposal.
98
-
99
- ## The typed client
100
-
101
- `acryl-router/client` is the same client for a real server. It runs in a browser or any runtime with `fetch`, without Cordis:
102
-
103
- ```ts
104
- import { hc } from 'acryl-router/client'
105
- import type { SearchRoutes } from 'my-server' // the type of the chained app, exported by the server package
106
-
107
- const client = hc<SearchRoutes>('http://127.0.0.1:3290/search-app')
108
- const response = await client.search.$get({ query: { q: 'cordis' } })
109
- ```
110
-
111
- Export the app's type (`export type SearchRoutes = typeof app`) from the server package; the client imports only the type, never the
112
- server code.
113
-
114
- ## Not yet ported
115
-
116
- Proxying, a WebSocket upgrade under the router, JSX, static-site generation, CSS-in-JS and the cache helpers are later tasks (see
117
- `specs/047-framework-port/plan.md`). Add a missing helper to the framework as a ported, tested helper, not as private code in one
118
- application.
@@ -1,154 +0,0 @@
1
- # Middleware
2
-
3
- Middleware is code that runs around a handler. Use it for behavior shared by several routes: authentication, authorization, logging, CORS,
4
- caching, compression, request IDs and timing.
5
-
6
- ## Write middleware
7
-
8
- ```ts
9
- import type { MiddlewareHandler } from 'acryl-router'
10
-
11
- const timing: MiddlewareHandler = async (c, next) => {
12
- const started = performance.now()
13
- await next()
14
- c.header('X-Response-Time', String(Math.round(performance.now() - started)))
15
- }
16
-
17
- app.use(timing)
18
- ```
19
-
20
- `await next()` runs the remaining middleware and then the handler. Not calling it ends the chain, so middleware that refuses a request
21
- returns a response itself:
22
-
23
- ```ts
24
- const requireAdmin: MiddlewareHandler = async (c, next) => {
25
- if (!isAdmin(c)) return c.json({ error: 'forbidden' }, 403)
26
- await next()
27
- }
28
- ```
29
-
30
- Middleware does not return a response *and* call `next()`: after `next()` it changes `c.res` (or assigns a new `Response` to it) instead.
31
-
32
- Authentication establishes an identity; authorization decides whether that identity may do this. Keep them as separate middleware when
33
- their failure answers differ.
34
-
35
- ## Scope and order
36
-
37
- ```ts
38
- app.use(requestLogger) // every route of this app
39
- app.use('/admin/*', requireAdmin) // below a prefix
40
- app.on(['POST', 'PUT'], '/items/*', audit)
41
- ```
42
-
43
- Middleware runs in registration order and only wraps routes registered after it. The first middleware registered is the outermost: its code
44
- before `next()` runs first and its code after `next()` runs last.
45
-
46
- ## Share values with handlers
47
-
48
- `createMiddleware` types the variables a middleware sets, and the app picks them up when it is chained:
49
-
50
- ```ts
51
- import { createMiddleware } from 'acryl-router/helpers'
52
-
53
- const withUser = createMiddleware<{ Variables: { user: User } }>(async (c, next) => {
54
- c.set('user', await loadUser(c))
55
- await next()
56
- })
57
-
58
- const app = new App().use(withUser).get('/me', c => c.json(c.var.user))
59
- ```
60
-
61
- Only request-local values belong here. Shared services belong behind Cordis injection.
62
-
63
- ## Errors
64
-
65
- `await next()` does not throw. When a handler or later middleware throws, the error becomes a response first (an `HTTPException` its own,
66
- anything else through `onError`) and is left in `c.error`:
67
-
68
- ```ts
69
- app.use(async (c, next) => {
70
- await next()
71
- if (c.error) metrics.count('request_failed')
72
- })
73
- ```
74
-
75
- So a `try { await next() } catch` around `next()` never catches anything. Map domain errors to answers in `app.onError`:
76
-
77
- ```ts
78
- app.onError((error, c) => {
79
- if (error instanceof DomainError) return c.json({ error: error.code }, error.status)
80
- console.error(error)
81
- return c.json({ error: 'internal_error' }, 500)
82
- })
83
- ```
84
-
85
- ## Built-in middleware
86
-
87
- Import from `acryl-router/middleware`:
88
-
89
- | Middleware | What it does |
90
- | --- | --- |
91
- | `basicAuth`, `bearerAuth` | HTTP Basic and Bearer authentication |
92
- | `jwt`, `jwk` (with `sign`, `verify`, `decode`, `verifyWithJwks`) | JSON Web Token verification, from a secret or a key set |
93
- | `bodyLimit` | refuse a request body over a size, with 413, while it streams |
94
- | `cors` | CORS headers and preflight answers |
95
- | `csrf` | refuse a cross-site form submission by its `Origin` or `Sec-Fetch-Site` |
96
- | `secureHeaders` (with `NONCE`) | security headers, including a content security policy with nonces |
97
- | `ipRestriction` | allow or deny by the peer address (read through `getConnInfo`) |
98
- | `loopbackOnly` (with `loopbackAuthority`, `sameOrigin`) | only requests from this machine to this app; see below |
99
- | `compress` | gzip or deflate the response |
100
- | `etag` | ETag headers and 304 answers |
101
- | `logger` | one log line per request and response |
102
- | `requestId` | a request ID header and `c.var.requestId` |
103
- | `timing` (with `startTime`, `endTime`, `setMetric`, `wrapTime`) | `Server-Timing` headers |
104
- | `timeout` | answer with an error when a handler takes too long |
105
- | `prettyJSON` | indented JSON when the query asks for it |
106
- | `poweredBy` | an `X-Powered-By` header |
107
- | `methodNotAllowed({ app })` | 405 with an `Allow` header for a known path of `app` asked with another method |
108
- | `methodOverride` | take the method from a form field, header or query |
109
- | `trimTrailingSlash`, `appendTrailingSlash` | redirect to the canonical path |
110
- | `languageDetector` (with `detectFromPath`, `detectFromQuery`, `detectFromCookie`, `detectFromHeader`) | the request's language as a variable |
111
- | `contextStorage` (with `getContext`, `tryGetContext`) | the current context from code that is not given `c` |
112
- | `every`, `some`, `except` | combine middleware: all, the first that passes, or all except on some paths |
113
- | `serveStatic` | the runtime-neutral static file middleware; it needs a `getContent`. On Node use the one from `acryl-node-server` |
114
-
115
- ### loopbackOnly
116
-
117
- The guard for a local app's own routes, such as a control API a desktop window calls:
118
-
119
- ```ts
120
- import { loopbackOnly } from 'acryl-router/middleware'
121
-
122
- app.use('/control/*', loopbackOnly())
123
- ```
124
-
125
- A request passes only when:
126
-
127
- - the peer is a loopback address and arrived on the real local port, both read from the transport, never from a header;
128
- - the `Host` header names a loopback hostname (`127.0.0.1`, `localhost`, `[::1]`, or `hostnames`) with that port, which stops DNS
129
- rebinding;
130
- - for a request that changes things (not `GET`, `HEAD`, `OPTIONS`), any `Origin` is this same authority (`mutations: 'none'` turns this
131
- off).
132
-
133
- An in-process call has no socket and is refused unless `inProcess: 'allow'` says the host's own code may call it. Everything refused gets a
134
- 403.
135
-
136
- A private route that no other program on the machine may call either, such as a workspace's file and terminal routes, takes
137
- `callers: 'own-page'`:
138
-
139
- ```ts
140
- app.use('/api/workspace/*', loopbackOnly({ callers: 'own-page', hostnames: ['127.0.0.1'] }))
141
- ```
142
-
143
- Then every request must come from a page this app served: an `Origin` that is exactly this authority (with `Sec-Fetch-Site` absent or
144
- `same-origin`), or, for a read, which browsers often send without `Origin`, `Sec-Fetch-Site: same-origin` and a `Referer` from this
145
- authority. A script with no `Origin` is refused even for a read. `fromOwnPage(c, authority)` is the same check for middleware of your own.
146
-
147
- ## Middleware in Cordis
148
-
149
- Middleware belongs to an `App`; it is not a separate Cordis registration, and it disappears with the mount that serves it. A plugin may
150
- build middleware from an injected service, but resources the middleware uses (timers, watchers, connections) are acquired in the plugin's
151
- `ctx.effect()` and only the finished middleware goes into the app. Do not start timers, watchers or sockets from a handler.
152
-
153
- Middleware an app registers with a path wraps the matching routes of every later mount too (an app mounted at `/` with
154
- `app.use('/todo/*', ...)` wraps a plugin mounted at `/todo`), so a host can put a guard in front of other plugins by mounting first.
@@ -1,106 +0,0 @@
1
- # Request
2
-
3
- Handlers read input through `c.req`, a thin wrapper around the Web `Request`. The original is `c.req.raw`.
4
-
5
- ## Route parameters
6
-
7
- ```ts
8
- app.get('/entry/:id', c => {
9
- const id = c.req.param('id')
10
- return c.json({ id })
11
- })
12
-
13
- app.get('/entry/:id/comment/:commentId', c => {
14
- const { id, commentId } = c.req.param()
15
- return c.json({ id, commentId })
16
- })
17
- ```
18
-
19
- Named reads keep route contracts visible; read the whole map only when a generic logger or adapter needs it.
20
-
21
- ## Query strings
22
-
23
- ```ts
24
- const page = c.req.query('page') // one value
25
- const all = c.req.query() // every parameter, first value of each
26
- const tags = c.req.queries('tag') // repeated values: ?tag=work&tag=home
27
- ```
28
-
29
- Convert strings to numbers, booleans or dates at the application boundary and reject invalid values explicitly; a validator does both
30
- (see [Validation](./validation.md)).
31
-
32
- ## Headers
33
-
34
- ```ts
35
- const requestId = c.req.header('X-Request-Id')
36
- const headers = c.req.header() // every header, keys in lowercase
37
- ```
38
-
39
- Header names are case-insensitive for a named read. With no argument the record's keys are lowercase, so `c.req.header()['X-Foo']` is
40
- always undefined; read `c.req.header('X-Foo')` instead. Optional headers need a deliberate fallback; do not let a missing authentication
41
- header silently become an anonymous request unless that is the declared behavior.
42
-
43
- ## Bodies
44
-
45
- ```ts
46
- app.post('/entry', async c => {
47
- const body = await c.req.json() // application/json
48
- return c.json({ received: body }, 201)
49
- })
50
-
51
- await c.req.text()
52
- await c.req.arrayBuffer()
53
- await c.req.blob()
54
- await c.req.formData()
55
- await c.req.parseBody() // multipart/form-data or application/x-www-form-urlencoded
56
- ```
57
-
58
- The reads are cached, so a validator and the handler can both read the body. Read untrusted bodies behind `bodyLimit`, which refuses a body
59
- over the limit with 413 while it streams instead of after buffering it.
60
-
61
- ### Forms and uploads
62
-
63
- `parseBody()` returns `string | File` per field; the last one wins when a name repeats:
64
-
65
- ```ts
66
- const body = await c.req.parseBody()
67
- body['file'] // string | File
68
- const many = await c.req.parseBody({ all: true }) // repeated names become arrays
69
- many['files'] // (string | File)[] when several were sent
70
- const nested = await c.req.parseBody({ dot: true }) // obj.key1 -> { obj: { key1 } }
71
- ```
72
-
73
- A field named with a `[]` suffix (`files[]`) is always an array. Treat every uploaded file as untrusted: check its type, size and
74
- destination, and never use a caller-provided filename as a filesystem path without normalizing it and confining it to the intended
75
- directory.
76
-
77
- ## Validated input
78
-
79
- `c.req.valid(target)` returns what a validator for `json`, `form`, `query`, `header`, `cookie` or `param` produced, typed by it. See
80
- [Validation](./validation.md).
81
-
82
- ## Method, path and URL
83
-
84
- ```ts
85
- c.req.method // 'GET'
86
- c.req.path // '/about/me'
87
- c.req.url // 'http://127.0.0.1:3290/about/me'
88
- ```
89
-
90
- Do not parse the URL by hand to recover route parameters or query values the router already exposes. `routePath(c)` and
91
- `matchedRoutes(c)` from `acryl-router/helpers` give the registered path and the routes that matched.
92
-
93
- ## Raw Web Request
94
-
95
- ```ts
96
- const raw = c.req.raw
97
- const url = new URL(raw.url)
98
- ```
99
-
100
- Use the raw object for standards-based libraries, streaming bodies and signatures over the exact payload. Use `c.req` for normal
101
- application code.
102
-
103
- ## Request cancellation
104
-
105
- `c.req.raw.signal` aborts when the client goes away, when the plugin serving the request unloads and when the router is
106
- disposed. Work that ignores it can outlive the plugin that owns it; see [Context](./context.md#cancellation-and-background-work).