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
@@ -1,17 +1,18 @@
1
1
  # Migration from 0.3
2
2
 
3
3
  0.3.0 had the framework's own small router API: routes registered one at a time on `ctx.router`, and a `RouteContext` with a few
4
- helpers. 0.4.0 replaces it with the ported application API: a plugin builds an `App` and mounts it. The old calls are removed, not kept
4
+ helpers. 0.4.0 replaces it with the ported application API: a plugin builds an `Acryl` and mounts it. The old calls are removed, not kept
5
5
  as aliases, so there is one way to write a route.
6
6
 
7
7
  ## Before and after
8
8
 
9
9
  0.3.0:
10
10
 
11
- ```ts
12
- import { HttpError } from 'acryl-router'
13
- import { readJson, streamSSE, valid, validate } from 'acryl-router/helpers'
14
- import { bodyLimit } from 'acryl-router/middleware'
11
+ ```ts no-check
12
+ import { HttpError } from 'acrylblends'
13
+ import { readJson, valid, validate } from 'acrylblends'
14
+ import { streamSSE } from 'acrylblends/streaming'
15
+ import { bodyLimit } from 'acrylblends/body-limit'
15
16
 
16
17
  export function apply(ctx: Context): void {
17
18
  const api = ctx.router.group('/todo')
@@ -33,12 +34,14 @@ export function apply(ctx: Context): void {
33
34
  0.4.0:
34
35
 
35
36
  ```ts
36
- import { App, HTTPException } from 'acryl-router'
37
- import { schemaValidator, streamSSE } from 'acryl-router/helpers'
38
- import { bodyLimit } from 'acryl-router/middleware'
37
+ import { Acryl } from 'acrylblends'
38
+ import { HTTPException } from 'acrylblends/http-exception'
39
+ import { schemaValidator } from 'acrylblends/schema-validator'
40
+ import { streamSSE } from 'acrylblends/streaming'
41
+ import { bodyLimit } from 'acrylblends/body-limit'
39
42
 
40
43
  export function apply(ctx: Context): void {
41
- const app = new App()
44
+ const app = new Acryl()
42
45
  .use(bodyLimit({ maxSize: 16 * 1024 }))
43
46
  .get('/todos/:id', c => {
44
47
  const todo = find(c.req.param('id'))
@@ -63,16 +66,16 @@ Public paths do not change: the mount path plus the app's route path is the old
63
66
 
64
67
  | 0.3.0 | 0.4.0 |
65
68
  | --- | --- |
66
- | `ctx.router.get/post/put/patch/delete/all/on(path, ...)` | the same methods on an `App`, then `ctx.router.route(prefix, app)` |
69
+ | `ctx.router.get/post/put/patch/delete/all/on(path, ...)` | the same methods on an `Acryl`, then `ctx.router.route(prefix, app)` |
67
70
  | `ctx.router.use(...)` | `app.use(...)` on the app it should wrap (or on an app mounted earlier, for a guard in front of other plugins) |
68
- | `ctx.router.group(prefix, ...middleware)` | one `App` per group mounted at `prefix`, or `app.route(prefix, sub)` / `app.basePath(prefix)` |
71
+ | `ctx.router.group(prefix, ...middleware)` | one `Acryl` per group mounted at `prefix`, or `app.route(prefix, sub)` / `app.basePath(prefix)` |
69
72
  | the remover each registration returned | the one remover `ctx.router.route` returns; the mount is owned by the calling plugin as before |
70
73
  | `ctx.router.onError`, `ctx.router.notFound` | unchanged; an app's own `app.onError` now also applies to its routes |
71
74
  | `c.param(name)`, `c.params` | `c.req.param(name)`, `c.req.param()` |
72
75
  | `c.query(name)`, `c.query()` | `c.req.query(name)`, `c.req.query()` (and `c.req.queries(name)` for repeated values) |
73
76
  | `c.url` | `new URL(c.req.url)`, or `c.req.path` |
74
77
  | `c.req` (the Web `Request`) | `c.req.raw`; `c.req` is now the request wrapper |
75
- | `c.connection` | `connectionOf(c)` (or `getConnInfo(c)`); type the app `new App<RouterEnv>()` to read `c.env.connection` |
78
+ | `c.connection` | `connectionOf(c)` (or `getConnInfo(c)`); type the app `new Acryl<RouterEnv>()` to read `c.env.connection` |
76
79
  | `c.signal` | `c.req.raw.signal` |
77
80
  | `c.waitUntil(task)` | `c.executionCtx.waitUntil(task)` |
78
81
  | `c.get(key)` / `c.set(key, value)` | unchanged, typed by the app's `Variables` (`c.var.key` also works) |
@@ -86,7 +89,7 @@ Public paths do not change: the mount path plus the app's route path is the old
86
89
  | the cleanup function `run` returned | `stream.onAbort(cleanup)`; the callback's end closes the stream |
87
90
  | a 405 with `Allow` for a known path and another method | 404 by default; add the `methodNotAllowed` middleware for 405 |
88
91
  | the `Middleware` type, `(c, next) => Response` | `MiddlewareHandler`, `async (c, next) => { await next() }`; change `c.res` after `next()` instead of returning it |
89
- | `logger`, `cors`, `requestId`, `secureHeaders`, `loopbackOnly` | same names in `acryl-router/middleware`; the first four now take the core's options |
92
+ | `logger`, `cors`, `requestId`, `secureHeaders`, `loopbackOnly` | same names, each from its own subpath (`acrylblends/logger`, `acrylblends/cors`, ...); the first four now take the core's options |
90
93
 
91
94
  ## Behavior changes to check
92
95
 
@@ -0,0 +1,14 @@
1
+ # Migration from 0.4
2
+
3
+ 0.5 gives the framework its public names: the application class is `Acryl` and the request class is `AcrylRequest`, the upstream names
4
+ with the project renamed. Everything else (`Context`, `HTTPException`, the middleware, the helpers, `ctx.router.route(path, app)`) is
5
+ unchanged.
6
+
7
+ | 0.4 | 0.5 |
8
+ | --- | --- |
9
+ | `import { App } from 'acryl-router'`, `new App()` | `import { Acryl } from 'acryl-router'`, `new Acryl()` |
10
+ | `AppRequest` | `AcrylRequest` |
11
+
12
+ `App` and `AppRequest` still work in 0.5, marked deprecated, and are removed in the next release. Code outside Cordis imports the same
13
+ names from the public package: `import { Acryl } from 'acrylblends'`, and each upstream subpath under it (`acrylblends/cors`,
14
+ `acrylblends/jwt`, `acrylblends/node-server`).
@@ -1,7 +1,7 @@
1
1
  # Migration from the DSH webServer
2
2
 
3
3
  ACRYL plugins have registered HTTP routes directly with the DSH `webServer` (or the Host's `acrylWeb` wrapper of it): one Node-style handler
4
- per exact path or prefix, with no middleware chain. The framework replaces that with an `App`, a mount, and Web-standard requests.
4
+ per exact path or prefix, with no middleware chain. The framework replaces that with an `Acryl`, a mount, and Web-standard requests.
5
5
 
6
6
  ## Before and after
7
7
 
@@ -24,12 +24,12 @@ export function apply(ctx: Context): void {
24
24
  After, it builds an app, mounts it, and asks the Host adapter to serve the prefix:
25
25
 
26
26
  ```ts
27
- import { App } from 'acryl-router'
27
+ import { Acryl } from 'acrylblends'
28
28
 
29
29
  export const inject = ['router']
30
30
 
31
31
  export function apply(ctx: Context): void {
32
- const app = new App().get('/health', c => c.json({ ok: true }))
32
+ const app = new Acryl().get('/health', c => c.json({ ok: true }))
33
33
  ctx.router.route('/api', app)
34
34
  ctx.inject(['routerHttp'], inner => { inner.routerHttp.mount('/api/health') })
35
35
  }
@@ -42,8 +42,8 @@ the route in process (`ctx.router.request('/api/health')`), which the old handle
42
42
 
43
43
  | webServer | Framework |
44
44
  | --- | --- |
45
- | `register({ kind: 'exact', path, handler })` | a route on an `App`, mounted with `ctx.router.route`; served with `routerHttp.mount(path)` |
46
- | `register({ kind: 'prefix', path, handler })` | an `App` mounted at `path` with its own routes below it |
45
+ | `register({ kind: 'exact', path, handler })` | a route on an `Acryl`, mounted with `ctx.router.route`; served with `routerHttp.mount(path)` |
46
+ | `register({ kind: 'prefix', path, handler })` | an `Acryl` mounted at `path` with its own routes below it |
47
47
  | `req.method` checks in the handler | `app.get`, `app.post`, ... (add `methodNotAllowed` for 405 answers) |
48
48
  | `new URL(req.url, ...)` and manual parsing | `c.req.param`, `c.req.query`, `c.req.header` |
49
49
  | reading the body stream by hand | `c.req.json()`, `c.req.parseBody()` behind `bodyLimit`, or a validator |
@@ -56,7 +56,7 @@ the route in process (`ctx.router.request('/api/health')`), which the old handle
56
56
 
57
57
  Move one capability at a time:
58
58
 
59
- 1. Build an `App` for the capability and move its handlers into it without changing their public answers.
59
+ 1. Build an `Acryl` for the capability and move its handlers into it without changing their public answers.
60
60
  2. Mount it with `ctx.router.route` and serve the same prefix with `routerHttp.mount`.
61
61
  3. Remove the direct `webServer` registration in the same change: the two cannot claim one prefix, `mount` throws.
62
62
  4. Test the route through the router (`ctx.router.request`) and over the Host, and unload and reload the plugin to confirm the route goes
@@ -71,7 +71,7 @@ per domain folder (`filesRoutes`, `gitRoutes`, `ptyRoutes`, ...), composes them
71
71
  result after the effect that builds its services, and serves the one prefix `/api/acryl-workspace`:
72
72
 
73
73
  ```ts
74
- const built: { api?: App } = {}
74
+ const built: { api?: Acryl } = {}
75
75
  ctx.effect(() => {
76
76
  // ... the PTY table, git, files, the project registry ...
77
77
  built.api = privateApi(filesRoutes(files, report), gitRoutes(git, report) /* , ... */)
@@ -1,109 +1,6 @@
1
- # Routing and mounting
1
+ # Mounting and trailing slashes
2
2
 
3
- Routing has two levels:
4
-
5
- 1. Routes inside an `App`.
6
- 2. Cordis mounts that place an `App` in the host at a base path.
7
-
8
- Keeping those levels separate lets application code stay portable while the host controls the public route space.
9
-
10
- ## HTTP methods
11
-
12
- ```ts
13
- app.get('/todos', listTodos)
14
- app.post('/todos', createTodo)
15
- app.put('/todos/:id', replaceTodo)
16
- app.patch('/todos/:id', updateTodo)
17
- app.delete('/todos/:id', deleteTodo)
18
- app.options('/todos', options)
19
- app.all('/health', health) // any method
20
- app.on('PURGE', '/cache', purge) // a custom method
21
- app.on(['PUT', 'DELETE'], '/post', handler)
22
- app.on('GET', ['/hello', '/en/hello'], handler)
23
- ```
24
-
25
- `HEAD` is answered from the `GET` route with the body removed. A known path asked with another method answers 404 like an unknown path;
26
- add the `methodNotAllowed` middleware to an app that should answer 405 with an `Allow` header instead.
27
-
28
- ```ts
29
- import { methodNotAllowed } from 'acryl-router/middleware'
30
-
31
- const app = new App()
32
- app.use(methodNotAllowed({ app })) // POST /item -> 405, Allow: GET, HEAD
33
- app.get('/item', c => c.text('item'))
34
- ```
35
-
36
- Routes can be chained, and a chained call without a path reuses the last one:
37
-
38
- ```ts
39
- app
40
- .get('/endpoint', c => c.text('GET /endpoint'))
41
- .post(c => c.text('POST /endpoint'))
42
- .delete(c => c.text('DELETE /endpoint'))
43
- ```
44
-
45
- Chaining also carries the route types, which the typed `testClient` and `acryl-router/client` read.
46
-
47
- ## Path parameters
48
-
49
- ```ts
50
- app.get('/users/:userId/todos/:todoId', c => {
51
- const { userId, todoId } = c.req.param()
52
- return c.json({ userId, todoId })
53
- })
54
-
55
- app.get('/api/animal/:type?', c => c.text('Animal!')) // optional: /api/animal and /api/animal/cat
56
- app.get('/post/:date{[0-9]+}/:title{[a-z]+}', handler) // constrained by a regular expression
57
- app.get('/posts/:filename{.+\\.png}', handler) // a parameter that includes slashes
58
- ```
59
-
60
- Prefer explicit routes over complex patterns when both express the same rule.
61
-
62
- ## Wildcards
63
-
64
- ```ts
65
- app.use('/admin/*', requireAdmin)
66
- app.get('/wild/*/card', c => c.text('GET /wild/*/card'))
67
- ```
68
-
69
- A wildcard is appropriate for a prefix boundary. It should not hide distinct resources that callers need to address independently.
70
-
71
- ## Priority
72
-
73
- Handlers and middleware run in registration order, and the first handler that returns a response ends the request:
74
-
75
- ```ts
76
- app.get('/book/a', c => c.text('a')) // GET /book/a -> a
77
- app.get('/book/:slug', c => c.text('common')) // GET /book/b -> common
78
- ```
79
-
80
- Put middleware above the handlers it should wrap and a fallback such as `app.get('*', ...)` below the others.
81
-
82
- ## Grouping related routes
83
-
84
- Build a smaller app for a feature, then place it inside another app:
85
-
86
- ```ts
87
- const todos = new App()
88
- todos.get('/', listTodos)
89
- todos.post('/', createTodo)
90
- todos.get('/:id', showTodo)
91
-
92
- const app = new App()
93
- app.route('/todos', todos)
94
- ```
95
-
96
- `route` copies the routes the sub-app has at that moment. Register them first: a route added to `todos` after `app.route(...)` is not
97
- part of `app`.
98
-
99
- ## Base paths
100
-
101
- ```ts
102
- const api = new App().basePath('/api/v1')
103
- api.get('/todos', listTodos) // GET /api/v1/todos
104
- ```
105
-
106
- Do not repeat a mount prefix both in `basePath` and in the outer mount unless the doubled path is deliberate.
3
+ How a Cordis plugin serves an `Acryl` app, what happens to errors and unknown paths, and how trailing slashes behave. For routing itself (methods, parameters, wildcards, grouping) see the [routing API](../api/routing.md).
107
4
 
108
5
  ## Mounting from Cordis
109
6
 
@@ -164,15 +61,15 @@ What each choice does for an app mounted at `/orders` with routes `/` and `/:id`
164
61
  | nothing (the default) | 200 | 404 | 200 | 404 |
165
62
  | `.use(trimTrailingSlash())` in the app | 200 | 301 to `/orders` | 200 | 301 to `/orders/42` |
166
63
  | `acryl-router` row config `trailingSlash: 'ignore'` | 200 | 200 | 200 | 200 |
167
- | `new App({ strict: false })` for the mounted app | 200 | 404 | 200 | 404 |
64
+ | `new Acryl({ strict: false })` for the mounted app | 200 | 404 | 200 | 404 |
168
65
 
169
- - **`trimTrailingSlash()`** (from `acryl-router/middleware`) is the choice a plugin makes for itself. It acts after the handlers: only
66
+ - **`trimTrailingSlash()`** (from `acrylblends/trailing-slash`) is the choice a plugin makes for itself. It acts after the handlers: only
170
67
  a GET or HEAD that would be a 404 and ends in `/` is redirected, so a path you did register with a trailing slash keeps working, and a
171
68
  POST, PUT, PATCH or DELETE to `/orders/` stays a 404. `trimTrailingSlash({ alwaysRedirect: true })` redirects before the handlers run,
172
69
  which a wildcard route (`/files/*`) needs. `appendTrailingSlash()` does the opposite, for an app whose canonical paths end in `/`.
173
70
  - **`trailingSlash: 'ignore'`** is the router's own setting and applies to every mount at once, without a redirect. Set it in the
174
71
  composition that owns the `acryl-router` row (the Blueprint or profile), not from one plugin.
175
- - **`strict: false`** on an `App` is the core's option and works for an app you serve yourself (`app.fetch`, `app.request`). It has no
72
+ - **`strict: false`** on an `Acryl` is the core's option and works for an app you serve yourself (`app.fetch`, `app.request`). It has no
176
73
  effect on a mounted app, because the router composes all mounts into one root app whose strictness comes from `trailingSlash`.
177
74
 
178
75
  `examples/acryl-todo` uses `trimTrailingSlash()`: `/todo/` sends the browser to `/todo`, and the API keeps one path per route.
@@ -10,7 +10,7 @@ The server is a Cordis plugin that provides the `nodeServer` service:
10
10
  ```ts
11
11
  import { Context } from '@deepseek-ai/cordis'
12
12
  import * as router from 'acryl-router'
13
- import * as nodeServer from 'acryl-node-server'
13
+ import * as nodeServer from 'acrylblends/node-server'
14
14
  import * as todo from './todo.ts'
15
15
 
16
16
  const root = new Context()
@@ -39,16 +39,16 @@ Every request goes to `ctx.router.fetch`, so routes appear and disappear as plug
39
39
 
40
40
  The adapter passes the socket's peer address and local port to the router as connection facts. Handlers read them through
41
41
  `connectionOf(c)` or `getConnInfo(c)` and never touch Node socket objects, so the same handler runs in process and through the Host. See
42
- [Context](./context.md#transport-facts).
42
+ [Context](../api/context.md#transport-facts).
43
43
 
44
44
  ## Static files
45
45
 
46
46
  The Node `serveStatic` reads files from disk:
47
47
 
48
48
  ```ts
49
- import { serveStatic } from 'acryl-node-server'
49
+ import { serveStatic } from 'acrylblends/node-server'
50
50
 
51
- const app = new App()
51
+ const app = new Acryl()
52
52
  .use('/assets/*', serveStatic({ root: './public' }))
53
53
  .get('/', serveStatic({ path: './public/index.html' }))
54
54
  ```
@@ -33,7 +33,7 @@ so a plugin cannot take over a Host route by mounting on it.
33
33
 
34
34
  Desktop runs the same Host inside Electron, and its window talks to the Host's web server on a loopback port. A plugin's routes therefore
35
35
  serve Desktop exactly as they serve Web, with no Desktop-specific code. Guard local control routes with `loopbackOnly` (see
36
- [Middleware](./middleware.md#loopbackonly)).
36
+ [Middleware](../concepts/middleware.md#loopbackonly)).
37
37
 
38
38
  A transport without a port, handing `ctx.router.fetch` to Electron's `protocol.handle`, needs no change to plugins and is a later task
39
39
  (`specs/047-framework-port/plan.md` T014).
@@ -57,7 +57,7 @@ host declares instead of assuming a network route exists.
57
57
 
58
58
  | Concern | Owner |
59
59
  | --- | --- |
60
- | Route handlers and middleware | the feature plugin's `App` |
60
+ | Route handlers and middleware | the feature plugin's `Acryl` |
61
61
  | Mount path and lifetime | the feature plugin, through `ctx.router.route` |
62
62
  | Socket and port | the Host (`acryl-router-http`) or `acryl-node-server` |
63
63
  | Terminal rendering and input | the terminal surface |
@@ -0,0 +1,57 @@
1
+ # Transport facts and cancellation
2
+
3
+ `c.env` carries what the caller of the router supplied for this request. Under the router that is `{ connection }`: the socket's peer
4
+ address and the real local port, filled by the HTTP adapter and empty for an in-process call. Transport facts never travel in headers.
5
+
6
+ ```ts
7
+ import { Acryl } from 'acrylblends'
8
+ import { connectionOf, type RouterEnv } from 'acrylblends/conninfo'
9
+ import { getConnInfo } from 'acrylblends/conninfo'
10
+
11
+ const app = new Acryl<RouterEnv>() // types c.env.connection
12
+ app.get('/peer', c => c.json({
13
+ connection: connectionOf(c), // { remoteAddress?, localPort? }
14
+ info: getConnInfo(c), // the same peer in the core's conninfo shape, for middleware such as ipRestriction
15
+ }))
16
+ ```
17
+
18
+ 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
19
+ `loopbackOnly` refuse an empty one unless told otherwise.
20
+
21
+ ## Cancellation and background work
22
+
23
+ - `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
24
+ disposed. Long work
25
+ should pass it on (`fetch(url, { signal: c.req.raw.signal })`) or check it.
26
+ - `c.executionCtx.waitUntil(promise)` keeps the request in flight until the promise settles, for work that continues after the response
27
+ is returned.
28
+
29
+ Both belong to the current request, and both end with their owner: see [Plugin lifecycle](./plugin-lifecycle.md#disposal-sequence).
30
+
31
+ ## Errors and control flow
32
+
33
+ Return a response for expected failures, or throw an `HTTPException`, which becomes its own response:
34
+
35
+ ```ts
36
+ import { HTTPException } from 'acrylblends/http-exception'
37
+
38
+ if (!todo) return c.json({ error: 'todo_not_found' }, 404)
39
+ if (!allowed) throw new HTTPException(403, { message: 'not yours' })
40
+ ```
41
+
42
+ 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
43
+ throws: the error has already become a response by then, and the error itself is in `c.error`:
44
+
45
+ ```ts
46
+ app.use(async (c, next) => {
47
+ await next()
48
+ if (c.error) report(c.error)
49
+ })
50
+ ```
51
+
52
+ ## Context rules
53
+
54
+ - Treat the context as request-local.
55
+ - Do not retain it after the handler returns.
56
+ - Do not put sockets, server objects or Cordis internals into context values for other plugins to discover accidentally.
57
+ - Put cross-plugin capabilities in a declared Cordis service, not in `c.set`.
@@ -7,15 +7,15 @@ Validate untrusted input at the route boundary. `schemaValidator` takes any [Sta
7
7
 
8
8
  ```ts
9
9
  import z from '@deepseek-ai/schemastery'
10
- import { App } from 'acryl-router'
11
- import { schemaValidator } from 'acryl-router/helpers'
10
+ import { Acryl } from 'acrylblends'
11
+ import { schemaValidator } from 'acrylblends/schema-validator'
12
12
 
13
13
  const NewTodo = z.object({
14
14
  title: z.string().required(),
15
15
  done: z.boolean().default(false),
16
16
  })
17
17
 
18
- const app = new App().post('/todos', schemaValidator('json', NewTodo), c => {
18
+ const app = new Acryl().post('/todos', schemaValidator('json', NewTodo), c => {
19
19
  const todo = c.req.valid('json') // typed by the schema's output
20
20
  return c.json({ todo }, 201)
21
21
  })
@@ -60,7 +60,7 @@ If you see a field error for a field the request clearly carries, check the requ
60
60
  explicitly can refuse other content types before the validator:
61
61
 
62
62
  ```ts
63
- import type { MiddlewareHandler } from 'acryl-router'
63
+ import type { MiddlewareHandler } from 'acrylblends'
64
64
 
65
65
  const jsonOnly: MiddlewareHandler = async (c, next) => {
66
66
  // The same types the json target reads: application/json and application/*+json, parameters allowed.
@@ -101,11 +101,11 @@ app.get('/todos/:id', schemaValidator('param', z.object({ id: z.natural() })), s
101
101
 
102
102
  ## The core validator
103
103
 
104
- `validator` (also from `acryl-router/helpers`) takes a function instead of a schema. Return the value the handler should see, or a
104
+ `validator` (from `acrylblends/validator`) takes a function instead of a schema. Return the value the handler should see, or a
105
105
  response to refuse:
106
106
 
107
107
  ```ts
108
- import { validator } from 'acryl-router/helpers'
108
+ import { validator } from 'acrylblends/validator'
109
109
 
110
110
  app.post('/posts', validator('form', (value, c) => {
111
111
  const body = value['body']
@@ -119,15 +119,15 @@ app.post('/posts', validator('form', (value, c) => {
119
119
  Validation reads the whole body. Put `bodyLimit` in front of a validator on any route open to untrusted callers:
120
120
 
121
121
  ```ts
122
- import { bodyLimit } from 'acryl-router/middleware'
122
+ import { bodyLimit } from 'acrylblends/body-limit'
123
123
 
124
124
  app.post('/todos', bodyLimit({ maxSize: 16 * 1024 }), schemaValidator('json', NewTodo), createTodo)
125
125
  ```
126
126
 
127
127
  ## Typed clients
128
128
 
129
- The validated input types flow into the route types, so the typed `testClient` and `acryl-router/client` check the request a caller sends.
130
- See [Helpers](./helpers.md#testing).
129
+ The validated input types flow into the route types, so the typed `testClient` and `acrylblends/client` check the request a caller sends.
130
+ See [Helpers](../guides/helpers.md#testing).
131
131
 
132
132
  ## What not to validate twice
133
133
 
@@ -0,0 +1,196 @@
1
+ # Getting Started
2
+
3
+ Using Acryl is easy. You set up the project, write code, develop with a local server, and run it. The same application code works on every verified runtime, with a different
4
+ entry point for each. This page shows the basic usage.
5
+
6
+ ## Starter
7
+
8
+ Starter templates are available for each runtime. Use the "create-acrylblends" command.
9
+
10
+ **npm**
11
+
12
+ ```sh
13
+ npm create acrylblends@latest my-app
14
+ ```
15
+
16
+ **yarn**
17
+
18
+ ```sh
19
+ yarn create acrylblends my-app
20
+ ```
21
+
22
+ **pnpm**
23
+
24
+ ```sh
25
+ pnpm create acrylblends@latest my-app
26
+ ```
27
+
28
+ **bun**
29
+
30
+ ```sh
31
+ bun create acrylblends@latest my-app
32
+ ```
33
+
34
+ You are asked which template you want:
35
+
36
+ ```
37
+ ? Which template do you want to use?
38
+ ❯ nodejs
39
+ bun (experimental)
40
+ acryl-app
41
+ ```
42
+
43
+ `nodejs` and `bun` (experimental) are a minimal Acryl application for that runtime. `acryl-app` is a Cordis app built from plugins, with an agent that can extend it while it
44
+ runs (see [Acryl in a Cordis app](../cordis/acryl-in-a-cordis-app.md)). Pass `--template` to skip the question, see [create-acrylblends](../guides/create-acrylblends.md).
45
+
46
+ The template is created in `my-app`: go to it, install the dependencies and start the local server.
47
+
48
+ ```sh
49
+ cd my-app
50
+ npm install
51
+ npm run dev
52
+ ```
53
+
54
+ ## Hello World
55
+
56
+ Write your first application in `src/index.ts`. The example below is a starter Acryl application.
57
+
58
+ The `import` and the final `export default` are the same on every runtime; what differs is how the runtime starts the app (see [Node.js](nodejs.md) and [Bun](bun.md)).
59
+
60
+ ```ts twoslash
61
+ import { Acryl } from 'acrylblends'
62
+
63
+ const app = new Acryl()
64
+
65
+ app.get('/', (c) => {
66
+ return c.text('Hello Acryl!')
67
+ })
68
+
69
+ export default app
70
+ ```
71
+
72
+ Start the development server and open the address it prints.
73
+
74
+ ## Return JSON
75
+
76
+ Returning JSON is also easy. The following handles a GET request to `/api/hello` and returns an `application/json` response.
77
+
78
+ ```ts twoslash
79
+ import { Acryl } from 'acrylblends'
80
+
81
+ const app = new Acryl()
82
+
83
+ app.get('/api/hello', (c) => {
84
+ return c.json({
85
+ ok: true,
86
+ message: 'Hello Acryl!',
87
+ })
88
+ })
89
+ ```
90
+
91
+ ## Request and Response
92
+
93
+ Getting a path parameter, a URL query value, and adding a response header is written as follows.
94
+
95
+ ```ts twoslash
96
+ import { Acryl } from 'acrylblends'
97
+
98
+ const app = new Acryl()
99
+
100
+ app.get('/posts/:id', (c) => {
101
+ const page = c.req.query('page')
102
+ const id = c.req.param('id')
103
+ c.header('X-Message', 'Hi!')
104
+ return c.text(`You want to see ${page} of ${id}`)
105
+ })
106
+ ```
107
+
108
+ POST, PUT and DELETE are handled the same way as GET.
109
+
110
+ ```ts twoslash
111
+ import { Acryl } from 'acrylblends'
112
+
113
+ const app = new Acryl()
114
+
115
+ app.post('/posts', (c) => c.text('Created!', 201))
116
+ app.delete('/posts/:id', (c) => c.text(`${c.req.param('id')} is deleted!`))
117
+ ```
118
+
119
+ ## Return HTML
120
+
121
+ Write HTML with [the html helper](../helpers/html.md):
122
+
123
+ ```ts twoslash
124
+ import { Acryl } from 'acrylblends'
125
+ import { html } from 'acrylblends/html'
126
+
127
+ const app = new Acryl()
128
+
129
+ app.get('/', (c) => {
130
+ const name = 'Acryl'
131
+ return c.html(html`<!doctype html><h1>Hello ${name}!</h1>`)
132
+ })
133
+ ```
134
+
135
+ [JSX](../guides/jsx.md) is not yet available.
136
+
137
+ ## Return raw Response
138
+
139
+ You can also return a raw Web Standard `Response`.
140
+
141
+ ```ts twoslash
142
+ import { Acryl } from 'acrylblends'
143
+
144
+ const app = new Acryl()
145
+
146
+ app.get('/', () => {
147
+ return new Response('Good morning!')
148
+ })
149
+ ```
150
+
151
+ ## Using Middleware
152
+
153
+ Middleware can do the hard work for you. For example, add Basic Authentication.
154
+
155
+ ```ts twoslash
156
+ import { Acryl } from 'acrylblends'
157
+ import { basicAuth } from 'acrylblends/basic-auth'
158
+
159
+ const app = new Acryl()
160
+
161
+ app.use(
162
+ '/admin/*',
163
+ basicAuth({
164
+ username: 'admin',
165
+ password: 'secret',
166
+ })
167
+ )
168
+
169
+ app.get('/admin', (c) => {
170
+ return c.text('You are authorized!')
171
+ })
172
+ ```
173
+
174
+ There are useful middleware included, such as Bearer and JWT authentication, CORS and ETag. See [Built-in middleware](../middleware/builtin/basic-auth.md).
175
+
176
+ ## Testing
177
+
178
+ An app is a function from `Request` to `Response`, so a test needs no server:
179
+
180
+ ```ts twoslash
181
+ import { Acryl } from 'acrylblends'
182
+
183
+ const app = new Acryl()
184
+ app.get('/', (c) => c.text('Hello Acryl!'))
185
+
186
+ const response = await app.request('/')
187
+ console.log(response.status, await response.text())
188
+ ```
189
+
190
+ See [Testing](../guides/testing.md).
191
+
192
+ ## Next
193
+
194
+ - [Node.js](nodejs.md) and [Bun](bun.md) (experimental)
195
+ - [Routing](../api/routing.md), [Context](../api/context.md) and [Request](../api/request.md)
196
+ - [Validation](../guides/validation.md)