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
@@ -0,0 +1,143 @@
1
+ # Route Helper
2
+
3
+ The Route Helper provides enhanced routing information for debugging and middleware development. It allows you to access detailed information about matched routes and the current route being processed.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { Acryl } from 'acrylblends'
9
+ import {
10
+ matchedRoutes,
11
+ routePath,
12
+ baseRoutePath,
13
+ basePath,
14
+ } from 'acrylblends/route'
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Basic route information
20
+
21
+ ```ts
22
+ const app = new Acryl()
23
+
24
+ app.get('/posts/:id', (c) => {
25
+ const currentPath = routePath(c) // '/posts/:id'
26
+ const routes = matchedRoutes(c) // Array of matched routes
27
+
28
+ return c.json({
29
+ path: currentPath,
30
+ totalRoutes: routes.length,
31
+ })
32
+ })
33
+ ```
34
+
35
+ ### Working with sub-applications
36
+
37
+ ```ts
38
+ const app = new Acryl()
39
+ const apiApp = new Acryl()
40
+
41
+ apiApp.get('/posts/:id', (c) => {
42
+ return c.json({
43
+ routePath: routePath(c), // '/posts/:id'
44
+ baseRoutePath: baseRoutePath(c), // '/api'
45
+ basePath: basePath(c), // '/api' (with actual params)
46
+ })
47
+ })
48
+
49
+ app.route('/api', apiApp)
50
+ ```
51
+
52
+ ## `matchedRoutes()`
53
+
54
+ Returns an array of all routes that matched the current request, including middleware.
55
+
56
+ ```ts
57
+ app.all('/api/*', (c, next) => {
58
+ console.log('API middleware')
59
+ return next()
60
+ })
61
+
62
+ app.get('/api/users/:id', (c) => {
63
+ const routes = matchedRoutes(c)
64
+ // Returns: [
65
+ // { method: 'ALL', path: '/api/*', handler: [Function] },
66
+ // { method: 'GET', path: '/api/users/:id', handler: [Function] }
67
+ // ]
68
+ return c.json({ routes: routes.length })
69
+ })
70
+ ```
71
+
72
+ ## `routePath()`
73
+
74
+ Returns the route path pattern registered for the current handler.
75
+
76
+ ```ts
77
+ app.get('/posts/:id', (c) => {
78
+ console.log(routePath(c)) // '/posts/:id'
79
+ return c.text('Post details')
80
+ })
81
+ ```
82
+
83
+ ### Using with index parameter
84
+
85
+ You can optionally pass an index parameter to get the route path at a specific position, similar to `Array.prototype.at()`.
86
+
87
+ ```ts
88
+ app.all('/api/*', (c, next) => {
89
+ return next()
90
+ })
91
+
92
+ app.get('/api/users/:id', (c) => {
93
+ console.log(routePath(c, 0)) // '/api/*' (first matched route)
94
+ console.log(routePath(c, -1)) // '/api/users/:id' (last matched route)
95
+ return c.text('User details')
96
+ })
97
+ ```
98
+
99
+ ## `baseRoutePath()`
100
+
101
+ Returns the base path pattern of the current route as specified in routing.
102
+
103
+ ```ts
104
+ const subApp = new Acryl()
105
+ subApp.get('/posts/:id', (c) => {
106
+ return c.text(baseRoutePath(c)) // '/:sub'
107
+ })
108
+
109
+ app.route('/:sub', subApp)
110
+ ```
111
+
112
+ ### Using with index parameter
113
+
114
+ You can optionally pass an index parameter to get the base route path at a specific
115
+ position, similar to `Array.prototype.at()`.
116
+
117
+ ```ts
118
+ app.all('/api/*', (c, next) => {
119
+ return next()
120
+ })
121
+
122
+ const subApp = new Acryl()
123
+ subApp.get('/users/:id', (c) => {
124
+ console.log(baseRoutePath(c, 0)) // '/' (first matched route)
125
+ console.log(baseRoutePath(c, -1)) // '/api' (last matched route)
126
+ return c.text('User details')
127
+ })
128
+
129
+ app.route('/api', subApp)
130
+ ```
131
+
132
+ ## `basePath()`
133
+
134
+ Returns the base path with embedded parameters from the actual request.
135
+
136
+ ```ts
137
+ const subApp = new Acryl()
138
+ subApp.get('/posts/:id', (c) => {
139
+ return c.text(basePath(c)) // '/api' (for request to '/api/posts/123')
140
+ })
141
+
142
+ app.route('/:sub', subApp)
143
+ ```
@@ -0,0 +1,393 @@
1
+ # SSG Helper
2
+
3
+ > **Not yet available.** Static site generation (`acrylblends/ssg`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
+
5
+
6
+ SSG Helper generates a static site from your Acryl application. It will retrieve the contents of registered routes and save them as static files.
7
+
8
+ ## Usage
9
+
10
+ ### Manual
11
+
12
+ If you have a simple Acryl application like the following:
13
+
14
+ ```tsx
15
+ // index.tsx
16
+ const app = new Acryl()
17
+
18
+ app.get('/', (c) => c.html('Hello, World!'))
19
+
20
+ app.use('/about', async (c, next) => {
21
+ c.setRenderer((content) => {
22
+ return c.html(
23
+ <html>
24
+ <head />
25
+ <body>
26
+ <p>{content}</p>
27
+ </body>
28
+ </html>
29
+ )
30
+ })
31
+ await next()
32
+ })
33
+
34
+ app.get('/about', (c) => {
35
+ return c.render(
36
+ <>
37
+ <title>Acryl SSG Page</title>Hello!
38
+ </>
39
+ )
40
+ })
41
+
42
+ export default app
43
+ ```
44
+
45
+ For Node.js, create a build script like this:
46
+
47
+ ```ts
48
+ // build.ts
49
+ import app from './index'
50
+ import { toSSG } from 'acrylblends/ssg'
51
+ import fs from 'fs/promises'
52
+
53
+ toSSG(app, fs)
54
+ ```
55
+
56
+ By executing the script, the files will be output as follows:
57
+
58
+ ```bash
59
+ ls ./static
60
+ about.html index.html
61
+ ```
62
+
63
+ ### Vite Plugin
64
+
65
+ Using the `@acrylblends/vite-ssg` Vite Plugin, you can easily handle the process.
66
+
67
+ For more details, see here:
68
+
69
+ (not yet available)
70
+
71
+ ## toSSG
72
+
73
+ `toSSG` is the main function for generating static sites, taking an application and a filesystem module as arguments. It is based on the following:
74
+
75
+ ### Input
76
+
77
+ The arguments for toSSG are specified in ToSSGInterface.
78
+
79
+ ```ts
80
+ export interface ToSSGInterface {
81
+ (
82
+ app: Acryl,
83
+ fsModule: FileSystemModule,
84
+ options?: ToSSGOptions
85
+ ): Promise<ToSSGResult>
86
+ }
87
+ ```
88
+
89
+ - `app` specifies `new Acryl()` with registered routes.
90
+ - `fs` specifies the following object, assuming `node:fs/promise`.
91
+
92
+ ```ts
93
+ export interface FileSystemModule {
94
+ writeFile(path: string, data: string | Uint8Array): Promise<void>
95
+ mkdir(
96
+ path: string,
97
+ options: { recursive: boolean }
98
+ ): Promise<void | string>
99
+ }
100
+ ```
101
+
102
+ ### Using the adapter for Bun
103
+
104
+ On Bun, a `toSSG` function is provided by `acrylblends/bun` (not yet available).
105
+
106
+ ### Options
107
+
108
+ Options are specified in the ToSSGOptions interface.
109
+
110
+ ```ts
111
+ export interface ToSSGOptions {
112
+ dir?: string
113
+ concurrency?: number
114
+ extensionMap?: Record<string, string>
115
+ plugins?: SSGPlugin[]
116
+ }
117
+ ```
118
+
119
+ - `dir` is the output destination for Static files. The default value is `./static`.
120
+ - `concurrency` is the concurrent number of files to be generated at the same time. The default value is `2`.
121
+ - `extensionMap` is a map containing the `Content-Type` as a key and the string of the extension as a value. This is used to determine the file extension of the output file.
122
+ - `plugins` is an array of SSG plugins that extend the functionality of the static site generation process.
123
+
124
+ ### Output
125
+
126
+ `toSSG` returns the result in the following Result type.
127
+
128
+ ```ts
129
+ export interface ToSSGResult {
130
+ success: boolean
131
+ files: string[]
132
+ error?: Error
133
+ }
134
+ ```
135
+
136
+ ## Generate File
137
+
138
+ ### Route and Filename
139
+
140
+ The following rules apply to the registered route information and the generated file name. The default `./static` behaves as follows:
141
+
142
+ - `/` -> `./static/index.html`
143
+ - `/path` -> `./static/path.html`
144
+ - `/path/` -> `./static/path/index.html`
145
+
146
+ ### File Extension
147
+
148
+ The file extension depends on the `Content-Type` returned by each route. For example, responses from `c.html` are saved as `.html`.
149
+
150
+ If you want to customize the file extensions, set the `extensionMap` option.
151
+
152
+ ```ts
153
+ import { toSSG, defaultExtensionMap } from 'acrylblends/ssg'
154
+
155
+ // Save `application/x-html` content with `.html`
156
+ toSSG(app, fs, {
157
+ extensionMap: {
158
+ 'application/x-html': 'html',
159
+ ...defaultExtensionMap,
160
+ },
161
+ })
162
+ ```
163
+
164
+ Note that paths ending with a slash are saved as index.ext regardless of the extension.
165
+
166
+ ```ts
167
+ // save to ./static/html/index.html
168
+ app.get('/html/', (c) => c.html('html'))
169
+
170
+ // save to ./static/text/index.txt
171
+ app.get('/text/', (c) => c.text('text'))
172
+ ```
173
+
174
+ ## Middleware
175
+
176
+ Introducing built-in middleware that supports SSG.
177
+
178
+ ### ssgParams
179
+
180
+ You can use an API like `generateStaticParams` of Next.js.
181
+
182
+ Example:
183
+
184
+ ```ts
185
+ app.get(
186
+ '/shops/:id',
187
+ ssgParams(async () => {
188
+ const shops = await getShops()
189
+ return shops.map((shop) => ({ id: shop.id }))
190
+ }),
191
+ async (c) => {
192
+ const shop = await getShop(c.req.param('id'))
193
+ if (!shop) {
194
+ return c.notFound()
195
+ }
196
+ return c.render(
197
+ <div>
198
+ <h1>{shop.name}</h1>
199
+ </div>
200
+ )
201
+ }
202
+ )
203
+ ```
204
+
205
+ ### isSSGContext
206
+
207
+ `isSSGContext` is a helper function that returns `true` if the current application is running within the SSG context triggered by `toSSG`.
208
+
209
+ ```ts
210
+ app.get('/page', (c) => {
211
+ if (isSSGContext(c)) {
212
+ return c.text('This is generated by SSG')
213
+ }
214
+ return c.text('This is served dynamically')
215
+ })
216
+ ```
217
+
218
+ ### disableSSG
219
+
220
+ Routes with the `disableSSG` middleware set are excluded from static file generation by `toSSG`.
221
+
222
+ ```ts
223
+ app.get('/api', disableSSG(), (c) => c.text('an-api'))
224
+ ```
225
+
226
+ ### onlySSG
227
+
228
+ Routes with the `onlySSG` middleware set will be overridden by `c.notFound()` after `toSSG` execution.
229
+
230
+ ```ts
231
+ app.get('/static-page', onlySSG(), (c) => c.html(<h1>Welcome to my site</h1>))
232
+ ```
233
+
234
+ ## Plugins
235
+
236
+ Plugins allow you to extend the functionality of the static site generation process. They use hooks to customize the generation process at different stages.
237
+
238
+ ### Default Plugin
239
+
240
+ By default, `toSSG` uses `defaultPlugin` which skips non-200 status responses (like redirects, errors, or 404s). This prevents generating files for unsuccessful responses.
241
+
242
+ ```ts
243
+ import { toSSG, defaultPlugin } from 'acrylblends/ssg'
244
+
245
+ // defaultPlugin is automatically applied when no plugins specified
246
+ toSSG(app, fs)
247
+
248
+ // Equivalent to:
249
+ toSSG(app, fs, { plugins: [defaultPlugin] })
250
+ ```
251
+
252
+ If you specify custom plugins, `defaultPlugin` is **not** automatically included. To keep the default behavior while adding custom plugins, explicitly include it:
253
+
254
+ ```ts
255
+ toSSG(app, fs, {
256
+ plugins: [defaultPlugin, myCustomPlugin],
257
+ })
258
+ ```
259
+
260
+ ### Redirect Plugin
261
+
262
+ The `redirectPlugin` generates HTML redirect pages for routes that return HTTP redirect responses (301, 302, 303, 307, 308). The generated HTML includes a `<meta http-equiv="refresh">` tag and a canonical link.
263
+
264
+ ```ts
265
+ import { toSSG, redirectPlugin, defaultPlugin } from 'acrylblends/ssg'
266
+
267
+ toSSG(app, fs, {
268
+ plugins: [redirectPlugin(), defaultPlugin()],
269
+ })
270
+ ```
271
+
272
+ For example, if your app has:
273
+
274
+ ```ts
275
+ app.get('/old', (c) => c.redirect('/new'))
276
+ ```
277
+
278
+ The `redirectPlugin` will generate an HTML file at `/old.html` with a meta refresh redirect to `/new`.
279
+
280
+ > [!NOTE]
281
+ > When used with `defaultPlugin`, place `redirectPlugin` **before** `defaultPlugin`. Since `defaultPlugin` skips non-200 responses, placing it first would prevent `redirectPlugin` from processing redirect responses.
282
+
283
+ ### Hook Types
284
+
285
+ Plugins can use the following hooks to customize the `toSSG` process:
286
+
287
+ ```ts
288
+ export type BeforeRequestHook = (req: Request) => Request | false
289
+ export type AfterResponseHook = (res: Response) => Response | false
290
+ export type AfterGenerateHook = (
291
+ result: ToSSGResult
292
+ ) => void | Promise<void>
293
+ ```
294
+
295
+ - **BeforeRequestHook**: Called before processing each request. Return `false` to skip the route.
296
+ - **AfterResponseHook**: Called after receiving each response. Return `false` to skip file generation.
297
+ - **AfterGenerateHook**: Called after the entire generation process completes.
298
+
299
+ ### Plugin Interface
300
+
301
+ ```ts
302
+ export interface SSGPlugin {
303
+ beforeRequestHook?: BeforeRequestHook | BeforeRequestHook[]
304
+ afterResponseHook?: AfterResponseHook | AfterResponseHook[]
305
+ afterGenerateHook?: AfterGenerateHook | AfterGenerateHook[]
306
+ }
307
+ ```
308
+
309
+ ### Basic Plugin Examples
310
+
311
+ Filter only GET requests:
312
+
313
+ ```ts
314
+ const getOnlyPlugin: SSGPlugin = {
315
+ beforeRequestHook: (req) => {
316
+ if (req.method === 'GET') {
317
+ return req
318
+ }
319
+ return false
320
+ },
321
+ }
322
+ ```
323
+
324
+ Filter by status code:
325
+
326
+ ```ts
327
+ const statusFilterPlugin: SSGPlugin = {
328
+ afterResponseHook: (res) => {
329
+ if (res.status === 200 || res.status === 500) {
330
+ return res
331
+ }
332
+ return false
333
+ },
334
+ }
335
+ ```
336
+
337
+ Log generated files:
338
+
339
+ ```ts
340
+ const logFilesPlugin: SSGPlugin = {
341
+ afterGenerateHook: (result) => {
342
+ if (result.files) {
343
+ result.files.forEach((file) => console.log(file))
344
+ }
345
+ },
346
+ }
347
+ ```
348
+
349
+ ### Advanced Plugin Example
350
+
351
+ Here's an example of creating a sitemap plugin that generates a `sitemap.xml` file:
352
+
353
+ ```ts
354
+ // plugins.ts
355
+ import fs from 'node:fs/promises'
356
+ import path from 'node:path'
357
+ import type { SSGPlugin } from 'acrylblends/ssg'
358
+ import { DEFAULT_OUTPUT_DIR } from 'acrylblends/ssg'
359
+
360
+ export const sitemapPlugin = (baseURL: string): SSGPlugin => {
361
+ return {
362
+ afterGenerateHook: (result, fsModule, options) => {
363
+ const outputDir = options?.dir ?? DEFAULT_OUTPUT_DIR
364
+ const filePath = path.join(outputDir, 'sitemap.xml')
365
+ const urls = result.files.map((file) =>
366
+ new URL(file, baseURL).toString()
367
+ )
368
+ const siteMapText = `<?xml version="1.0" encoding="UTF-8"?>
369
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
370
+ ${urls.map((url) => `<url><loc>${url}</loc></url>`).join('\n')}
371
+ </urlset>`
372
+ fsModule.writeFile(filePath, siteMapText)
373
+ },
374
+ }
375
+ }
376
+ ```
377
+
378
+ Applying plugins:
379
+
380
+ ```ts
381
+ import app from './index'
382
+ import { toSSG } from 'acrylblends/ssg'
383
+ import { sitemapPlugin } from './plugins'
384
+
385
+ toSSG(app, fs, {
386
+ plugins: [
387
+ getOnlyPlugin,
388
+ statusFilterPlugin,
389
+ logFilesPlugin,
390
+ sitemapPlugin('https://example.com'),
391
+ ],
392
+ })
393
+ ```
@@ -0,0 +1,119 @@
1
+ # Streaming Helper
2
+
3
+ The Streaming Helper provides methods for streaming responses.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { Acryl } from 'acrylblends'
9
+ import { stream, streamText, streamSSE } from 'acrylblends/streaming'
10
+ ```
11
+
12
+ ## `stream()`
13
+
14
+ It returns a simple streaming response as `Response` object.
15
+
16
+ ```ts
17
+ app.get('/stream', (c) => {
18
+ return stream(c, async (stream) => {
19
+ // Write a process to be executed when aborted.
20
+ stream.onAbort(() => {
21
+ console.log('Aborted!')
22
+ })
23
+ // Write a Uint8Array.
24
+ await stream.write(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]))
25
+ // Pipe a readable stream.
26
+ await stream.pipe(anotherReadableStream)
27
+ })
28
+ })
29
+ ```
30
+
31
+ ## `streamText()`
32
+
33
+ It returns a streaming response with `Content-Type: text/plain`, `Transfer-Encoding: chunked`, and `X-Content-Type-Options: nosniff` headers.
34
+
35
+ ```ts
36
+ app.get('/streamText', (c) => {
37
+ return streamText(c, async (stream) => {
38
+ // Write a text with a new line ('\n').
39
+ await stream.writeln('Hello')
40
+ // Wait 1 second.
41
+ await stream.sleep(1000)
42
+ // Write a text without a new line.
43
+ await stream.write(`Acryl!`)
44
+ })
45
+ })
46
+ ```
47
+
48
+ **Warning.**
49
+
50
+ If you are developing an application for Cloudflare Workers, streaming may not work well on Wrangler. If so, add `Identity` for `Content-Encoding` header.
51
+
52
+ ```ts
53
+ app.get('/streamText', (c) => {
54
+ c.header('Content-Encoding', 'Identity')
55
+ return streamText(c, async (stream) => {
56
+ // ...
57
+ })
58
+ })
59
+ ```
60
+
61
+ ## `streamSSE()`
62
+
63
+ It allows you to stream Server-Sent Events (SSE) seamlessly.
64
+
65
+ ```ts
66
+ const app = new Acryl()
67
+ let id = 0
68
+
69
+ app.get('/sse', async (c) => {
70
+ return streamSSE(c, async (stream) => {
71
+ while (!stream.aborted) {
72
+ const message = `It is ${new Date().toISOString()}`
73
+ await stream.writeSSE({
74
+ data: message,
75
+ event: 'time-update',
76
+ id: String(id++),
77
+ })
78
+ await stream.sleep(1000)
79
+ }
80
+ })
81
+ })
82
+ ```
83
+
84
+ ## Error Handling
85
+
86
+ The third argument of the streaming helper is an error handler.
87
+ This argument is optional, if you don't specify it, the error will be output as a console error.
88
+
89
+ ```ts
90
+ app.get('/stream', (c) => {
91
+ return stream(
92
+ c,
93
+ async (stream) => {
94
+ // Write a process to be executed when aborted.
95
+ stream.onAbort(() => {
96
+ console.log('Aborted!')
97
+ })
98
+ // Write a Uint8Array.
99
+ await stream.write(
100
+ new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f])
101
+ )
102
+ // Pipe a readable stream.
103
+ await stream.pipe(anotherReadableStream)
104
+ },
105
+ (err, stream) => {
106
+ stream.writeln('An error occurred!')
107
+ console.error(err)
108
+ }
109
+ )
110
+ })
111
+ ```
112
+
113
+ The stream will be automatically closed after the callbacks are executed.
114
+
115
+ > **Warning.**
116
+ > If the callback function of the streaming helper throws an error, the `onError` event of Acryl will not be triggered.
117
+ >
118
+ > `onError` is a hook to handle errors before the response is sent and overwrite the response. However, when the callback function is executed, the stream has already started, so it cannot be overwritten.
119
+ >