acrylblends 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +325 -0
  3. package/docs/framework/README.md +51 -51
  4. package/docs/framework/UPSTREAM.md +1 -1
  5. package/docs/framework/agents/index.md +24 -0
  6. package/docs/framework/api/acryl.md +259 -0
  7. package/docs/framework/api/context.md +527 -0
  8. package/docs/framework/api/exception.md +80 -0
  9. package/docs/framework/api/index.md +12 -0
  10. package/docs/framework/api/presets.md +65 -0
  11. package/docs/framework/api/request.md +396 -0
  12. package/docs/framework/api/routing.md +303 -0
  13. package/docs/framework/{api-summary.md → api/summary.md} +19 -17
  14. package/docs/framework/concepts/benchmarks.md +26 -0
  15. package/docs/framework/concepts/developer-experience.md +5 -0
  16. package/docs/framework/concepts/middleware.md +21 -0
  17. package/docs/framework/concepts/motivation.md +14 -0
  18. package/docs/framework/concepts/routers.md +63 -0
  19. package/docs/framework/concepts/stacks.md +235 -0
  20. package/docs/framework/concepts/web-standard.md +37 -0
  21. package/docs/framework/{getting-started.md → cordis/acryl-in-a-cordis-app.md} +16 -16
  22. package/docs/framework/{concepts.md → cordis/concepts.md} +2 -2
  23. package/docs/framework/cordis/middleware.md +8 -0
  24. package/docs/framework/{migration-from-0-3.md → cordis/migration-from-0-3.md} +16 -13
  25. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  26. package/docs/framework/{migration-from-dsh-webserver.md → cordis/migration-from-dsh-webserver.md} +13 -7
  27. package/docs/framework/{routing.md → cordis/mounting.md} +5 -108
  28. package/docs/framework/{node-server.md → cordis/node-server.md} +4 -4
  29. package/docs/framework/{surfaces.md → cordis/surfaces.md} +2 -2
  30. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  31. package/docs/framework/{validation.md → cordis/validation.md} +9 -9
  32. package/docs/framework/getting-started/basic.md +196 -0
  33. package/docs/framework/getting-started/bun.md +221 -0
  34. package/docs/framework/getting-started/nodejs.md +344 -0
  35. package/docs/framework/getting-started/other-runtimes.md +23 -0
  36. package/docs/framework/guides/best-practices.md +231 -0
  37. package/docs/framework/guides/create-acrylblends.md +79 -0
  38. package/docs/framework/guides/examples.md +3 -0
  39. package/docs/framework/guides/faq.md +19 -0
  40. package/docs/framework/guides/helpers.md +33 -0
  41. package/docs/framework/guides/jsx-dom.md +299 -0
  42. package/docs/framework/guides/jsx.md +440 -0
  43. package/docs/framework/guides/middleware.md +253 -0
  44. package/docs/framework/guides/rpc.md +886 -0
  45. package/docs/framework/guides/testing.md +133 -0
  46. package/docs/framework/guides/validation.md +383 -0
  47. package/docs/framework/helpers/accepts.md +60 -0
  48. package/docs/framework/helpers/adapter.md +87 -0
  49. package/docs/framework/helpers/conninfo.md +112 -0
  50. package/docs/framework/helpers/cookie.md +232 -0
  51. package/docs/framework/helpers/css.md +285 -0
  52. package/docs/framework/helpers/dev.md +67 -0
  53. package/docs/framework/helpers/factory.md +180 -0
  54. package/docs/framework/helpers/html.md +123 -0
  55. package/docs/framework/helpers/jwt.md +184 -0
  56. package/docs/framework/helpers/proxy.md +118 -0
  57. package/docs/framework/helpers/route.md +143 -0
  58. package/docs/framework/helpers/ssg.md +393 -0
  59. package/docs/framework/helpers/streaming.md +119 -0
  60. package/docs/framework/helpers/testing.md +101 -0
  61. package/docs/framework/helpers/websocket.md +215 -0
  62. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  63. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  64. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  65. package/docs/framework/middleware/builtin/cache.md +122 -0
  66. package/docs/framework/middleware/builtin/combine.md +94 -0
  67. package/docs/framework/middleware/builtin/compress.md +59 -0
  68. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  69. package/docs/framework/middleware/builtin/cors.md +135 -0
  70. package/docs/framework/middleware/builtin/csrf.md +105 -0
  71. package/docs/framework/middleware/builtin/etag.md +54 -0
  72. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  73. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  74. package/docs/framework/middleware/builtin/jwk.md +192 -0
  75. package/docs/framework/middleware/builtin/jwt.md +145 -0
  76. package/docs/framework/middleware/builtin/language.md +232 -0
  77. package/docs/framework/middleware/builtin/logger.md +74 -0
  78. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  79. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  80. package/docs/framework/middleware/builtin/method-override.md +80 -0
  81. package/docs/framework/middleware/builtin/mount.md +106 -0
  82. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  83. package/docs/framework/middleware/builtin/request-id.md +94 -0
  84. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  85. package/docs/framework/middleware/builtin/timeout.md +98 -0
  86. package/docs/framework/middleware/builtin/timing.md +101 -0
  87. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  88. package/docs/framework/middleware/third-party.md +4 -0
  89. package/docs/framework/upstream.json +3 -3
  90. package/lib/accepts-XBuZPVRI.js +52 -0
  91. package/lib/accepts.d.ts +33 -0
  92. package/lib/accepts.js +2 -0
  93. package/lib/acryl-base.d.ts +2 -0
  94. package/lib/acryl-base.js +332 -0
  95. package/lib/adapter.d.ts +12 -0
  96. package/lib/adapter.js +37 -0
  97. package/lib/app-BM0rTCp7.js +26 -0
  98. package/lib/app-CmAYW1Al.d.ts +21 -0
  99. package/lib/basic-auth.d.ts +72 -0
  100. package/lib/basic-auth.js +95 -0
  101. package/lib/bearer-auth.d.ts +89 -0
  102. package/lib/bearer-auth.js +94 -0
  103. package/lib/body-limit.d.ts +42 -0
  104. package/lib/body-limit.js +66 -0
  105. package/lib/client-BHTr318g.js +266 -0
  106. package/lib/client.d.ts +3 -0
  107. package/lib/client.js +2 -0
  108. package/lib/combine.d.ts +85 -0
  109. package/lib/combine.js +137 -0
  110. package/lib/compose-BuW2B6PZ.js +50 -0
  111. package/lib/compress.d.ts +38 -0
  112. package/lib/compress.js +79 -0
  113. package/lib/connection-C7xgP1hP.js +24 -0
  114. package/lib/conninfo.d.ts +25 -0
  115. package/lib/conninfo.js +2 -0
  116. package/lib/constants-Dy7ZvN1H.js +4 -0
  117. package/lib/context-Bm7rI-oK.d.ts +1234 -0
  118. package/lib/context-DDO0cfuP.js +365 -0
  119. package/lib/context-storage.d.ts +38 -0
  120. package/lib/context-storage.js +52 -0
  121. package/lib/cookie-ClMaKDQf.d.ts +40 -0
  122. package/lib/cookie.d.ts +24 -0
  123. package/lib/cookie.js +82 -0
  124. package/lib/cors.d.ts +52 -0
  125. package/lib/cors.js +106 -0
  126. package/lib/csrf.d.ts +75 -0
  127. package/lib/csrf.js +101 -0
  128. package/lib/etag.d.ts +40 -0
  129. package/lib/etag.js +135 -0
  130. package/lib/factory.d.ts +35 -0
  131. package/lib/factory.js +30 -0
  132. package/lib/headers-tu2YYN8T.d.ts +11 -0
  133. package/lib/html.d.ts +6 -0
  134. package/lib/html.js +31 -0
  135. package/lib/http-exception.d.ts +57 -0
  136. package/lib/http-exception.js +54 -0
  137. package/lib/http-status-DaAwGAFL.d.ts +35 -0
  138. package/lib/index-B-3F4wt2.d.ts +12 -0
  139. package/lib/index-UTBmM3GX.d.ts +68 -0
  140. package/lib/index-oOClm_Xk.d.ts +45 -0
  141. package/lib/index.d.ts +5 -0
  142. package/lib/index.js +28 -0
  143. package/lib/ip-restriction.d.ts +68 -0
  144. package/lib/ip-restriction.js +166 -0
  145. package/lib/jwk.d.ts +52 -0
  146. package/lib/jwk.js +117 -0
  147. package/lib/jwt-BGJBw5AF.js +403 -0
  148. package/lib/jwt-Dg493Tai.d.ts +51 -0
  149. package/lib/jwt.d.ts +72 -0
  150. package/lib/jwt.js +115 -0
  151. package/lib/language.d.ts +88 -0
  152. package/lib/language.js +198 -0
  153. package/lib/logger.d.ts +22 -0
  154. package/lib/logger.js +54 -0
  155. package/lib/loopback-only.d.ts +45 -0
  156. package/lib/loopback-only.js +90 -0
  157. package/lib/method-not-allowed.d.ts +47 -0
  158. package/lib/method-not-allowed.js +82 -0
  159. package/lib/method-override.d.ts +46 -0
  160. package/lib/method-override.js +103 -0
  161. package/lib/mime-BQOYHl-l.d.ts +72 -0
  162. package/lib/node-server/conninfo.d.ts +11 -0
  163. package/lib/node-server/conninfo.js +19 -0
  164. package/lib/node-server/serve-static.d.ts +19 -0
  165. package/lib/node-server/serve-static.js +2 -0
  166. package/lib/node-server.d.ts +103 -0
  167. package/lib/node-server.js +1325 -0
  168. package/lib/powered-by.d.ts +28 -0
  169. package/lib/powered-by.js +24 -0
  170. package/lib/pretty-json.d.ts +40 -0
  171. package/lib/pretty-json.js +39 -0
  172. package/lib/reg-exp-router-DC1R3qoY.js +363 -0
  173. package/lib/request-id.d.ts +45 -0
  174. package/lib/request-id.js +34 -0
  175. package/lib/request.d.ts +2 -0
  176. package/lib/request.js +323 -0
  177. package/lib/route.d.ts +78 -0
  178. package/lib/route.js +126 -0
  179. package/lib/router/linear-router.d.ts +11 -0
  180. package/lib/router/linear-router.js +96 -0
  181. package/lib/router/pattern-router.d.ts +11 -0
  182. package/lib/router/pattern-router.js +41 -0
  183. package/lib/router/reg-exp-router.d.ts +35 -0
  184. package/lib/router/reg-exp-router.js +2 -0
  185. package/lib/router/smart-router.d.ts +15 -0
  186. package/lib/router/smart-router.js +2 -0
  187. package/lib/router/trie-router.d.ts +11 -0
  188. package/lib/router/trie-router.js +2 -0
  189. package/lib/router-CvUxUTOq.d.ts +99 -0
  190. package/lib/router.d.ts +2 -0
  191. package/lib/router.js +35 -0
  192. package/lib/schema-validator.d.ts +28 -0
  193. package/lib/schema-validator.js +22 -0
  194. package/lib/secure-headers.d.ts +125 -0
  195. package/lib/secure-headers.js +163 -0
  196. package/lib/serve-static-Dw_m6KxR.js +213 -0
  197. package/lib/serve-static.d.ts +31 -0
  198. package/lib/serve-static.js +77 -0
  199. package/lib/smart-router-C5CZ5XSM.js +49 -0
  200. package/lib/stream-CPdqZ0Fp.d.ts +34 -0
  201. package/lib/streaming-DHST3Scg.js +96 -0
  202. package/lib/streaming.d.ts +23 -0
  203. package/lib/streaming.js +2 -0
  204. package/lib/testing.d.ts +10 -0
  205. package/lib/testing.js +17 -0
  206. package/lib/timeout.d.ts +30 -0
  207. package/lib/timeout.js +42 -0
  208. package/lib/timing.d.ts +130 -0
  209. package/lib/timing.js +183 -0
  210. package/lib/trailing-slash.d.ts +91 -0
  211. package/lib/trailing-slash.js +85 -0
  212. package/lib/trie-router-CfFbapzL.js +146 -0
  213. package/lib/types-CDO6I3B0.d.ts +40 -0
  214. package/lib/types-CHesD1KG.d.ts +195 -0
  215. package/lib/types-CwrQjlaM.d.ts +105 -0
  216. package/lib/types-DR95J00T.d.ts +29 -0
  217. package/lib/types.d.ts +2 -0
  218. package/lib/types.js +4 -0
  219. package/lib/utils/accept.d.ts +9 -0
  220. package/lib/utils/accept.js +193 -0
  221. package/lib/utils/basic-auth.d.ts +8 -0
  222. package/lib/utils/basic-auth.js +20 -0
  223. package/lib/utils/body.d.ts +2 -0
  224. package/lib/utils/body.js +94 -0
  225. package/lib/utils/buffer.d.ts +19 -0
  226. package/lib/utils/buffer.js +51 -0
  227. package/lib/utils/color.d.ts +24 -0
  228. package/lib/utils/color.js +37 -0
  229. package/lib/utils/compress.d.ts +11 -0
  230. package/lib/utils/compress.js +11 -0
  231. package/lib/utils/concurrent.d.ts +17 -0
  232. package/lib/utils/concurrent.js +30 -0
  233. package/lib/utils/constants.d.ts +7 -0
  234. package/lib/utils/constants.js +7 -0
  235. package/lib/utils/cookie.d.ts +2 -0
  236. package/lib/utils/cookie.js +125 -0
  237. package/lib/utils/crypto.d.ts +14 -0
  238. package/lib/utils/crypto.js +34 -0
  239. package/lib/utils/encode.d.ts +11 -0
  240. package/lib/utils/encode.js +33 -0
  241. package/lib/utils/filepath.d.ts +14 -0
  242. package/lib/utils/filepath.js +25 -0
  243. package/lib/utils/handler.d.ts +9 -0
  244. package/lib/utils/handler.js +12 -0
  245. package/lib/utils/headers.d.ts +2 -0
  246. package/lib/utils/headers.js +1 -0
  247. package/lib/utils/html.d.ts +46 -0
  248. package/lib/utils/html.js +103 -0
  249. package/lib/utils/http-status.d.ts +2 -0
  250. package/lib/utils/http-status.js +1 -0
  251. package/lib/utils/ipaddr.d.ts +56 -0
  252. package/lib/utils/ipaddr.js +238 -0
  253. package/lib/utils/jwt.d.ts +24 -0
  254. package/lib/utils/jwt.js +2 -0
  255. package/lib/utils/mime.d.ts +2 -0
  256. package/lib/utils/mime.js +77 -0
  257. package/lib/utils/stream.d.ts +2 -0
  258. package/lib/utils/stream.js +88 -0
  259. package/lib/utils/types.d.ts +2 -0
  260. package/lib/utils/types.js +1 -0
  261. package/lib/utils/url.d.ts +46 -0
  262. package/lib/utils/url.js +197 -0
  263. package/lib/utils-dw8lxqjL.js +4 -0
  264. package/lib/validator-D84mq-dO.js +65 -0
  265. package/lib/validator.d.ts +42 -0
  266. package/lib/validator.js +2 -0
  267. package/lib/ws.d.ts +2 -0
  268. package/lib/ws.js +53 -0
  269. package/package.json +312 -14
  270. package/plugins/acryl-inspect/src/service.ts +2 -2
  271. package/plugins/acryl-inspect/tests/service.spec.ts +3 -3
  272. package/plugins/acryl-inspect/upstream.json +2 -2
  273. package/plugins/acryl-node-server/tests/adapter/app.ts +2 -2
  274. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -1
  275. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -1
  276. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +2 -2
  277. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +4 -4
  278. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +5 -5
  279. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +2 -2
  280. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +20 -20
  281. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +2 -2
  282. package/plugins/acryl-node-server/tests/adapter/server.test.ts +60 -50
  283. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +4 -4
  284. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +9 -9
  285. package/plugins/acryl-node-server/tests/server.spec.ts +6 -6
  286. package/plugins/acryl-node-server/upstream.json +2 -2
  287. package/plugins/acryl-router/src/client.ts +1 -1
  288. package/plugins/acryl-router/src/connection.ts +2 -2
  289. package/plugins/acryl-router/src/core/app-base.ts +29 -29
  290. package/plugins/acryl-router/src/core/app.test.ts +175 -175
  291. package/plugins/acryl-router/src/core/app.ts +8 -8
  292. package/plugins/acryl-router/src/core/client/client.test.ts +76 -76
  293. package/plugins/acryl-router/src/core/client/client.ts +2 -2
  294. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +1 -1
  295. package/plugins/acryl-router/src/core/client/index.ts +1 -1
  296. package/plugins/acryl-router/src/core/client/types.test.ts +6 -6
  297. package/plugins/acryl-router/src/core/client/types.ts +16 -16
  298. package/plugins/acryl-router/src/core/client/utils.test.ts +2 -2
  299. package/plugins/acryl-router/src/core/context.test.ts +4 -4
  300. package/plugins/acryl-router/src/core/context.ts +6 -6
  301. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +3 -3
  302. package/plugins/acryl-router/src/core/helper/accepts/index.ts +1 -1
  303. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +6 -6
  304. package/plugins/acryl-router/src/core/helper/adapter/index.ts +1 -1
  305. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +1 -1
  306. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +8 -8
  307. package/plugins/acryl-router/src/core/helper/cookie/index.ts +1 -1
  308. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +9 -9
  309. package/plugins/acryl-router/src/core/helper/factory/index.ts +10 -10
  310. package/plugins/acryl-router/src/core/helper/html/index.test.ts +4 -4
  311. package/plugins/acryl-router/src/core/helper/html/index.ts +1 -1
  312. package/plugins/acryl-router/src/core/helper/route/index.test.ts +7 -7
  313. package/plugins/acryl-router/src/core/helper/route/index.ts +8 -8
  314. package/plugins/acryl-router/src/core/helper/streaming/index.ts +1 -1
  315. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +6 -6
  316. package/plugins/acryl-router/src/core/helper/testing/index.ts +4 -4
  317. package/plugins/acryl-router/src/core/helper/websocket/index.ts +2 -1
  318. package/plugins/acryl-router/src/core/http-exception.ts +1 -1
  319. package/plugins/acryl-router/src/core/index.ts +9 -9
  320. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +6 -6
  321. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +3 -3
  322. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +5 -5
  323. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +3 -3
  324. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +6 -6
  325. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +3 -3
  326. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +9 -9
  327. package/plugins/acryl-router/src/core/middleware/combine/index.ts +7 -7
  328. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +9 -9
  329. package/plugins/acryl-router/src/core/middleware/compress/index.ts +3 -3
  330. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +5 -5
  331. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +4 -4
  332. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +7 -7
  333. package/plugins/acryl-router/src/core/middleware/cors/index.ts +3 -3
  334. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +10 -10
  335. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +3 -3
  336. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +42 -42
  337. package/plugins/acryl-router/src/core/middleware/etag/index.ts +4 -4
  338. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +4 -4
  339. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +6 -6
  340. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +16 -16
  341. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +7 -6
  342. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +16 -16
  343. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +4 -3
  344. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +3 -3
  345. package/plugins/acryl-router/src/core/middleware/language/language.ts +3 -3
  346. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +5 -5
  347. package/plugins/acryl-router/src/core/middleware/logger/index.ts +4 -4
  348. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +24 -24
  349. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +8 -8
  350. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +5 -5
  351. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +6 -6
  352. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +4 -4
  353. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +6 -6
  354. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +30 -30
  355. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +4 -4
  356. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +15 -15
  357. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +3 -3
  358. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +35 -35
  359. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +3 -3
  360. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +23 -23
  361. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +1 -1
  362. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +2 -2
  363. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +3 -3
  364. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +14 -14
  365. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +3 -3
  366. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +7 -7
  367. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +7 -7
  368. package/plugins/acryl-router/src/core/request.test.ts +42 -42
  369. package/plugins/acryl-router/src/core/request.ts +6 -6
  370. package/plugins/acryl-router/src/core/router/linear-router/index.ts +1 -1
  371. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +1 -1
  372. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +1 -1
  373. package/plugins/acryl-router/src/core/router/smart-router/index.ts +1 -1
  374. package/plugins/acryl-router/src/core/router/trie-router/index.ts +1 -1
  375. package/plugins/acryl-router/src/core/types.test.ts +115 -115
  376. package/plugins/acryl-router/src/core/types.ts +72 -72
  377. package/plugins/acryl-router/src/core/utils/body.ts +8 -8
  378. package/plugins/acryl-router/src/core/utils/html.ts +1 -1
  379. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +3 -3
  380. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +2 -2
  381. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +3 -3
  382. package/plugins/acryl-router/src/core/utils/jwt/types.ts +1 -1
  383. package/plugins/acryl-router/src/core/utils/types.ts +42 -0
  384. package/plugins/acryl-router/src/core/utils/url.test.ts +2 -2
  385. package/plugins/acryl-router/src/core/validator/index.ts +1 -1
  386. package/plugins/acryl-router/src/core/validator/validator.test.ts +28 -28
  387. package/plugins/acryl-router/src/deprecated.ts +15 -0
  388. package/plugins/acryl-router/src/index.ts +3 -2
  389. package/plugins/acryl-router/src/service.ts +10 -10
  390. package/plugins/acryl-router/tests/docs-examples.spec.ts +11 -11
  391. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  392. package/plugins/acryl-router/tests/loader.spec.ts +3 -3
  393. package/plugins/acryl-router/tests/loopback-only.spec.ts +4 -4
  394. package/plugins/acryl-router/tests/no-dom/consumer.ts +11 -0
  395. package/plugins/acryl-router/tests/no-dom/tsconfig.json +13 -0
  396. package/plugins/acryl-router/tests/service.spec.ts +23 -23
  397. package/plugins/acryl-router/upstream.json +3 -3
  398. package/plugins/acryl-router-http/tests/adapter.spec.ts +3 -3
  399. package/plugins/acryl-router-http/tests/surfaces.spec.ts +2 -2
  400. package/plugins/acryl-router-http/upstream.json +2 -2
  401. package/plugins/acryl-state/src/service.ts +2 -2
  402. package/plugins/acryl-state/upstream.json +2 -2
  403. package/plugins/builder/script.ts +2 -2
  404. package/plugins/extensions/resolve.ts +70 -10
  405. package/plugins/openai/prompt.ts +5 -5
  406. package/shared/AGENTS.core.md +16 -9
  407. package/templates/agent/src/routes.ts +2 -2
  408. package/templates/agent/test/model.test.ts +2 -2
  409. package/templates/agent/tsconfig.json +40 -0
  410. package/templates/blank/src/routes.ts +2 -2
  411. package/templates/todo/src/todo.ts +2 -2
  412. package/templates/todo/upstream.json +2 -2
  413. package/docs/framework/context.md +0 -129
  414. package/docs/framework/helpers.md +0 -118
  415. package/docs/framework/middleware.md +0 -154
  416. package/docs/framework/request.md +0 -106
  417. /package/docs/framework/{plugin-lifecycle.md → cordis/plugin-lifecycle.md} +0 -0
@@ -6,9 +6,10 @@ One page with the calls an ordinary app uses, each linked to the page that expla
6
6
 
7
7
  ```ts
8
8
  import type { Context } from '@deepseek-ai/cordis'
9
- import { App } from 'acryl-router'
10
- import { trimTrailingSlash } from 'acryl-router/middleware'
11
- import { schemaValidator, streamSSE, type StandardSchema } from 'acryl-router/helpers'
9
+ import { Acryl } from 'acrylblends'
10
+ import { trimTrailingSlash } from 'acrylblends/trailing-slash'
11
+ import { schemaValidator, type StandardSchema } from 'acrylblends/schema-validator'
12
+ import { streamSSE } from 'acrylblends/streaming'
12
13
  import type {} from 'acryl-state'
13
14
 
14
15
  export const name = 'orders' // the package name and the Loader row id
@@ -26,7 +27,7 @@ const NewOrder: StandardSchema<{ item: string }> = {
26
27
 
27
28
  export function apply(ctx: Context): void {
28
29
  const orders = ctx.state.cell<Order[]>('orders.list', [])
29
- const app = new App()
30
+ const app = new Acryl()
30
31
  .use(trimTrailingSlash())
31
32
  .get('/', c => c.json(orders.get()))
32
33
  .post('/', schemaValidator('json', NewOrder), c => {
@@ -45,11 +46,11 @@ export function apply(ctx: Context): void {
45
46
  }
46
47
  ```
47
48
 
48
- ## `App` ([Routing](./routing.md))
49
+ ## `Acryl` ([Routing](../api/routing.md))
49
50
 
50
51
  | Call | Does |
51
52
  | --- | --- |
52
- | `new App()` | an application: a route table plus middleware |
53
+ | `new Acryl()` | an application: a route table plus middleware |
53
54
  | `.get / .post / .put / .patch / .delete / .options (path, ...handlers)` | a route; handlers before the last are middleware for that route |
54
55
  | `.all(path, ...)`, `.on(methods, path, ...)` | any method, or a list of methods |
55
56
  | `.use([path], ...middleware)` | middleware for every route below `path` (all routes without it), registered before the routes it wraps |
@@ -60,9 +61,9 @@ export function apply(ctx: Context): void {
60
61
  | `.fetch(request)` | the app as a fetch handler |
61
62
 
62
63
  Paths: `/posts/:id` (parameter), `/posts/:id?` (optional), `/files/*` (wildcard), `/:name{[a-z]+}` (pattern). `/a` and `/a/` are different
63
- paths: see [Trailing slashes](./routing.md#trailing-slashes).
64
+ paths: see [Trailing slashes](../api/routing.md#trailing-slashes).
64
65
 
65
- ## The handler context `c` ([Context](./context.md))
66
+ ## The handler context `c` ([Context](../api/context.md))
66
67
 
67
68
  | Call | Does |
68
69
  | --- | --- |
@@ -78,7 +79,7 @@ paths: see [Trailing slashes](./routing.md#trailing-slashes).
78
79
  | `connectionOf(c)` / `getConnInfo(c)` | the caller's address and the local port, when a transport supplied them |
79
80
  | `throw new HTTPException(status, { message })` | stop with that status from anywhere in the chain |
80
81
 
81
- ## The request `c.req` ([Request](./request.md))
82
+ ## The request `c.req` ([Request](../api/request.md))
82
83
 
83
84
  | Call | Gives |
84
85
  | --- | --- |
@@ -89,10 +90,11 @@ paths: see [Trailing slashes](./routing.md#trailing-slashes).
89
90
  | `c.req.valid(target)` | the value a validator checked, typed by its schema |
90
91
  | `c.req.method`, `c.req.path`, `c.req.url`, `c.req.raw` | the method, path, full URL and the Web `Request` |
91
92
 
92
- ## Validation ([Validation](./validation.md))
93
+ ## Validation ([Validation](../cordis/validation.md))
93
94
 
94
95
  ```ts
95
- import { schemaValidator, validator } from 'acryl-router/helpers'
96
+ import { schemaValidator } from 'acrylblends/schema-validator'
97
+ import { validator } from 'acrylblends/validator'
96
98
  app.post('/', schemaValidator('json', Schema), c => c.json(c.req.valid('json')))
97
99
  ```
98
100
 
@@ -101,9 +103,9 @@ app.post('/', schemaValidator('json', Schema), c => c.json(c.req.valid('json')))
101
103
  - A failure is 400 `{ error: 'invalid <target>', issues: [{ message, path }] }`; `path` is dotted, and `""` when the issue has none.
102
104
  - The `json` target reads the body only with a JSON `Content-Type`; otherwise the schema sees `{}`.
103
105
  - `validator(target, (value, c) => valueOrResponse)` is the same middleware with a function instead of a schema.
104
- - Put `bodyLimit({ maxSize })` from `acryl-router/middleware` in front on routes open to untrusted callers.
106
+ - Put `bodyLimit({ maxSize })` from `acrylblends/body-limit` in front on routes open to untrusted callers.
105
107
 
106
- ## Streaming ([Helpers](./helpers.md))
108
+ ## Streaming ([Helpers](../guides/helpers.md))
107
109
 
108
110
  | Call | Does |
109
111
  | --- | --- |
@@ -123,16 +125,16 @@ Do not start timers inside a handler for keep-alives; let the plugin own one tim
123
125
  | `ctx.router.request(path, init?)`, `ctx.router.fetch(request)` | `router` | call the mounted routes in process (terminal UI, tests, other plugins) |
124
126
  | `ctx.router.onError(handler)`, `ctx.router.notFound(handler)` | `router` | router-wide error and not-found answers, owned by the caller |
125
127
  | `ctx.routerHttp.mount(prefix)` | `routerHttp` (`acryl-router-http`) | inside the ACRYL Host: serve a router prefix on the Host's web server (Web and Desktop). Use it through `ctx.inject(['routerHttp'], ...)` so the app also runs where there is no Host |
126
- | `ctx.nodeServer.url`, `ctx.nodeServer.port` | `nodeServer` (`acryl-node-server`) | without the Host: one Node server for the whole router; options `hostname` (`127.0.0.1`), `port` (`0`), `scan` (`20`). See [Node server](./node-server.md) |
128
+ | `ctx.nodeServer.url`, `ctx.nodeServer.port` | `nodeServer` (`acryl-node-server`) | without the Host: one Node server for the whole router; options `hostname` (`127.0.0.1`), `port` (`0`), `scan` (`20`). See [Node server](../cordis/node-server.md) |
127
129
  | `ctx.state.cell(key, initial)` | `state` (`acryl-state`) | a writable cell owned by the plugin: `get()`, `set(value)`, `update(fn)`, `subscribe(fn)` returning an unsubscribe |
128
130
  | `ctx.state.derive(key, [cells], fn)` | `state` | a read-only cell computed from others |
129
131
  | `GET /api/state/:key`, `GET /api/state/:key/events` | `state` | each cell over the router, read-only; `useCell(cell)` from `acryl-state/react` in a React page |
130
132
 
131
133
  Everything a plugin registers this way (mounts, cells, handlers) goes away when the plugin unloads, and comes back once when it reloads:
132
- see [Plugin lifecycle and disposal](./plugin-lifecycle.md).
134
+ see [Plugin lifecycle and disposal](../cordis/plugin-lifecycle.md).
133
135
 
134
- ## Middleware ([Middleware](./middleware.md))
136
+ ## Middleware ([Middleware](../concepts/middleware.md))
135
137
 
136
- From `acryl-router/middleware`: `bodyLimit`, `cors`, `csrf`, `secureHeaders`, `etag`, `compress`, `logger`, `requestId`, `timeout`,
138
+ Each from its own subpath (`acrylblends/body-limit`, `acrylblends/cors`, ...): `bodyLimit`, `cors`, `csrf`, `secureHeaders`, `etag`, `compress`, `logger`, `requestId`, `timeout`,
137
139
  `bearerAuth`, `basicAuth`, `jwt`, `jwk`, `ipRestriction`, `methodNotAllowed`, `trimTrailingSlash`, `appendTrailingSlash`, `some` /
138
140
  `every` / `except`, and ACRYL's `loopbackOnly` for private loopback routes.
@@ -0,0 +1,26 @@
1
+ # Benchmarks
2
+
3
+ > **Not yet measured.** The routers in the framework are designed for different situations (see [Routers](routers.md)), but benchmark results for Acryl itself have not been
4
+ > produced yet, and this page does not quote anyone else's numbers as ours. When Acryl has its own reproducible benchmark suite, its scripts and results will be here.
5
+
6
+ To compare routers on your own workload today, register your routes on an `Acryl` app with each router and time `app.request()` for the paths you care about:
7
+
8
+ ```ts twoslash
9
+ import { Acryl } from 'acrylblends'
10
+ import { RegExpRouter } from 'acrylblends/router/reg-exp-router'
11
+ import { TrieRouter } from 'acrylblends/router/trie-router'
12
+
13
+ const routes = ['/', '/users/:id', '/posts/:id/comments']
14
+
15
+ const apps = {
16
+ RegExpRouter: new Acryl({ router: new RegExpRouter() }),
17
+ TrieRouter: new Acryl({ router: new TrieRouter() }),
18
+ }
19
+
20
+ for (const [name, app] of Object.entries(apps)) {
21
+ for (const path of routes) app.get(path, (c) => c.text('ok'))
22
+ const start = performance.now()
23
+ for (let i = 0; i < 100_000; i++) await app.request('/users/42')
24
+ console.log(name, Math.round(performance.now() - start), 'ms')
25
+ }
26
+ ```
@@ -0,0 +1,5 @@
1
+ # Developer Experience
2
+
3
+ To create a great application, we need great development experience.
4
+ Fortunately, we can write applications for Node.js and Bun in TypeScript without having the need to transpile it to JavaScript.
5
+ Acryl is written in TypeScript and can make applications type-safe.
@@ -0,0 +1,21 @@
1
+ # Middleware
2
+
3
+ We call the primitive that returns `Response` as "Handler".
4
+ "Middleware" is executed before and after the Handler and handles the `Request` and `Response`.
5
+ It's like an onion structure.
6
+
7
+ For example, we can write the middleware to add the "X-Response-Time" header as follows.
8
+
9
+ ```ts twoslash
10
+ import { Acryl } from 'acrylblends'
11
+ const app = new Acryl()
12
+ // ---cut---
13
+ app.use(async (c, next) => {
14
+ const start = performance.now()
15
+ await next()
16
+ const end = performance.now()
17
+ c.res.headers.set('X-Response-Time', `${end - start}`)
18
+ })
19
+ ```
20
+
21
+ With this simple method, we can write our own custom middleware and we can use the built-in or third party middleware.
@@ -0,0 +1,14 @@
1
+ # Philosophy
2
+
3
+ ## Motivation
4
+
5
+ A web application should not be written twice because it runs in two places. Acryl builds on the Web Standard APIs (`Request`, `Response`, `fetch`, `URL`, streams), so a
6
+ handler written once runs on Node.js (and experimentally Bun), in a test with no socket, and inside a Cordis app.
7
+
8
+ Three ideas follow from that:
9
+
10
+ - **The handler is a function over Web Standards.** There is no runtime object to import, so there is nothing to replace when the runtime changes. See
11
+ [Web Standards](web-standard.md).
12
+ - **A plugin owns what it mounts.** Inside a Cordis app an application is mounted by a plugin and disappears when that plugin unloads, which is what lets an agent add,
13
+ update and remove features while the app runs. See [Plugin lifecycle](../cordis/plugin-lifecycle.md).
14
+ - **The documentation travels with the app.** A generated app contains these pages, so a person or a coding agent working in the folder reads the API from the folder.
@@ -0,0 +1,63 @@
1
+ # Routers
2
+
3
+ The router decides which handler answers a request. Acryl has five routers behind one API, and an `Acryl` app uses `SmartRouter` unless you choose another.
4
+
5
+ | Router | Import | Built for |
6
+ | --- | --- | --- |
7
+ | `SmartRouter` | `acrylblends/router/smart-router` | the default: it picks from the routers it is given, by the routes registered |
8
+ | `RegExpRouter` | `acrylblends/router/reg-exp-router` | matching all routes with one regular expression built before dispatch |
9
+ | `TrieRouter` | `acrylblends/router/trie-router` | all route patterns, with a trie tree and no linear loop |
10
+ | `LinearRouter` | `acrylblends/router/linear-router` | applications that register routes at every start, because registration compiles nothing |
11
+ | `PatternRouter` | `acrylblends/router/pattern-router` | the smallest implementation |
12
+
13
+ ## RegExpRouter
14
+
15
+ **RegExpRouter** turns the route patterns into one large regular expression and gets the result with one match. It is not the kind of "RegExp router" that tries each
16
+ route's expression in a loop, so matching does not repeat for every route.
17
+
18
+ It does not support every routing pattern, so it is normally combined with a router that does, through `SmartRouter`.
19
+
20
+ ## TrieRouter
21
+
22
+ **TrieRouter** uses a trie tree, and like RegExpRouter it does not loop over the routes. It supports all patterns.
23
+
24
+ ## SmartRouter
25
+
26
+ **SmartRouter** is for using several routers. It infers, from the routes registered, which of the routers it was given can serve them, and keeps using that one. An `Acryl`
27
+ app defaults to:
28
+
29
+ ```ts twoslash
30
+ import { Acryl } from 'acrylblends'
31
+ import { RegExpRouter } from 'acrylblends/router/reg-exp-router'
32
+ import { SmartRouter } from 'acrylblends/router/smart-router'
33
+ import { TrieRouter } from 'acrylblends/router/trie-router'
34
+
35
+ const app = new Acryl({
36
+ router: new SmartRouter({ routers: [new RegExpRouter(), new TrieRouter()] }),
37
+ })
38
+ ```
39
+
40
+ ## LinearRouter
41
+
42
+ **LinearRouter** registers a route without compiling anything, by keeping the routes in a list and matching them in order. Registration is cheap and matching is linear in
43
+ the number of routes, so it suits an environment that builds the application at every start and serves few requests.
44
+
45
+ ```ts twoslash
46
+ import { Acryl } from 'acrylblends'
47
+ import { LinearRouter } from 'acrylblends/router/linear-router'
48
+
49
+ const app = new Acryl({ router: new LinearRouter() })
50
+ ```
51
+
52
+ ## PatternRouter
53
+
54
+ **PatternRouter** is the smallest of the routers: it adds a pattern and matches it, and nothing else. Choose it when size matters more than anything else.
55
+
56
+ ```ts twoslash
57
+ import { Acryl } from 'acrylblends'
58
+ import { PatternRouter } from 'acrylblends/router/pattern-router'
59
+
60
+ const app = new Acryl({ router: new PatternRouter() })
61
+ ```
62
+
63
+ How the routers compare on your workload is for you to measure; see [Benchmarks](benchmarks.md).
@@ -0,0 +1,235 @@
1
+ # Acryl Stacks
2
+
3
+ Acryl makes easy things easy and hard things easy.
4
+ It is suitable for not just only returning JSON, but it's also great for building the full-stack application including REST API servers and the client.
5
+
6
+ ## RPC
7
+
8
+ Acryl's RPC feature allows you to share API specs with little change to your code.
9
+ The client generated by `hc` will read the spec and access the endpoint type-safety.
10
+
11
+ The following libraries make it possible.
12
+
13
+ - Acryl - API Server
14
+ - [Zod](https://zod.dev) - Validator
15
+ - Zod Validator Middleware
16
+ - `hc` - HTTP Client
17
+
18
+ We can call the set of these components the **Acryl Stack**.
19
+ Now let's create an API server and a client with it.
20
+
21
+ ## Writing API
22
+
23
+ First, write an endpoint that receives a GET request and returns JSON.
24
+
25
+ ```ts twoslash
26
+ import { Acryl } from 'acrylblends'
27
+
28
+ const app = new Acryl()
29
+
30
+ app.get('/hello', (c) => {
31
+ return c.json({
32
+ message: `Hello!`,
33
+ })
34
+ })
35
+ ```
36
+
37
+ ## Validation with Zod
38
+
39
+ Validate with Zod to receive the value of the query parameter.
40
+
41
+ ```ts
42
+ import { schemaValidator } from 'acrylblends/schema-validator'
43
+ import * as z from 'zod'
44
+
45
+ app.get(
46
+ '/hello',
47
+ schemaValidator(
48
+ 'query',
49
+ z.object({
50
+ name: z.string(),
51
+ })
52
+ ),
53
+ (c) => {
54
+ const { name } = c.req.valid('query')
55
+ return c.json({
56
+ message: `Hello! ${name}`,
57
+ })
58
+ }
59
+ )
60
+ ```
61
+
62
+ ## Sharing the Types
63
+
64
+ To emit an endpoint specification, export its type.
65
+
66
+ > **Warning.**
67
+ > For the RPC to infer routes correctly, all included methods must be chained, and the endpoint or app type must be inferred from a declared variable. For more, see [Best Practices for RPC](../guides/best-practices.md#if-you-want-to-use-rpc-features).
68
+ >
69
+
70
+ ```ts
71
+ const route = app.get(
72
+ '/hello',
73
+ schemaValidator(
74
+ 'query',
75
+ z.object({
76
+ name: z.string(),
77
+ })
78
+ ),
79
+ (c) => {
80
+ const { name } = c.req.valid('query')
81
+ return c.json({
82
+ message: `Hello! ${name}`,
83
+ })
84
+ }
85
+ )
86
+
87
+ export type AppType = typeof route
88
+ ```
89
+
90
+ ## Client
91
+
92
+ Next, The client-side implementation.
93
+ Create a client object by passing the `AppType` type to `hc` as generics.
94
+ Then, magically, completion works and the endpoint path and request type are suggested.
95
+
96
+ ```ts
97
+ import type { AppType } from './server'
98
+ import { hc } from 'acrylblends/client'
99
+
100
+ const client = hc<AppType>('/api')
101
+ const res = await client.hello.$get({
102
+ query: {
103
+ name: 'Acryl',
104
+ },
105
+ })
106
+ ```
107
+
108
+ The `Response` is compatible with the fetch API, but the data that can be retrieved with `json()` has a type.
109
+
110
+ ```ts
111
+ const data = await res.json()
112
+ console.log(`${data.message}`)
113
+ ```
114
+
115
+ Sharing API specifications means that you can be aware of server-side changes.
116
+
117
+ ## With React
118
+
119
+ You can create an application with a React front-end using the typed client.
120
+
121
+ The API server.
122
+
123
+ ```ts
124
+ // src/index.ts
125
+ import { Acryl } from 'acrylblends'
126
+ import * as z from 'zod'
127
+ import { schemaValidator } from 'acrylblends/schema-validator'
128
+
129
+ const schema = z.object({
130
+ id: z.string(),
131
+ title: z.string(),
132
+ })
133
+
134
+ type Todo = z.infer<typeof schema>
135
+
136
+ const todos: Todo[] = []
137
+
138
+ const api = new Acryl()
139
+ .post('/todo', schemaValidator('form', schema), (c) => {
140
+ const todo = c.req.valid('form')
141
+ todos.push(todo)
142
+ return c.json({
143
+ message: 'created!',
144
+ })
145
+ })
146
+ .get('/todo', (c) => {
147
+ return c.json({
148
+ todos,
149
+ })
150
+ })
151
+
152
+ export type AppType = typeof api
153
+
154
+ const app = new Acryl()
155
+ app.route('/api', api)
156
+
157
+ export default app
158
+ ```
159
+
160
+ The client with React and React Query.
161
+
162
+ ```tsx
163
+ // src/App.tsx
164
+ import {
165
+ useQuery,
166
+ useMutation,
167
+ QueryClient,
168
+ QueryClientProvider,
169
+ } from '@tanstack/react-query'
170
+ import type { AppType } from '../functions/api/[[route]]'
171
+ import { hc, InferResponseType, InferRequestType } from 'acrylblends/client'
172
+
173
+ const queryClient = new QueryClient()
174
+ const client = hc<AppType>('/api')
175
+
176
+ export default function App() {
177
+ return (
178
+ <QueryClientProvider client={queryClient}>
179
+ <Todos />
180
+ </QueryClientProvider>
181
+ )
182
+ }
183
+
184
+ const Todos = () => {
185
+ const query = useQuery({
186
+ queryKey: ['todos'],
187
+ queryFn: async () => {
188
+ const res = await client.todo.$get()
189
+ return await res.json()
190
+ },
191
+ })
192
+
193
+ const $post = client.todo.$post
194
+
195
+ const mutation = useMutation<
196
+ InferResponseType<typeof $post>,
197
+ Error,
198
+ InferRequestType<typeof $post>['form']
199
+ >({
200
+ mutationFn: async (todo) => {
201
+ const res = await $post({
202
+ form: todo,
203
+ })
204
+ return await res.json()
205
+ },
206
+ onSuccess: async () => {
207
+ queryClient.invalidateQueries({ queryKey: ['todos'] })
208
+ },
209
+ onError: (error) => {
210
+ console.log(error)
211
+ },
212
+ })
213
+
214
+ return (
215
+ <div>
216
+ <button
217
+ onClick={() => {
218
+ mutation.mutate({
219
+ id: Date.now().toString(),
220
+ title: 'Write code',
221
+ })
222
+ }}
223
+ >
224
+ Add Todo
225
+ </button>
226
+
227
+ <ul>
228
+ {query.data?.todos.map((todo) => (
229
+ <li key={todo.id}>{todo.title}</li>
230
+ ))}
231
+ </ul>
232
+ </div>
233
+ )
234
+ }
235
+ ```
@@ -0,0 +1,37 @@
1
+ # Web Standards
2
+
3
+ Acryl uses only **Web Standards** like Fetch.
4
+ They were originally used in the `fetch` function and consist of basic objects that handle HTTP requests and responses.
5
+ In addition to `Requests` and `Responses`, there are `URL`, `URLSearchParam`, `Headers` and others.
6
+
7
+ Cloudflare Workers, Deno, and Bun also are built upon Web Standards.
8
+ For example, a server that returns "Hello World" could be written as below. This could run on Cloudflare Workers and Bun.
9
+
10
+ ```ts twoslash
11
+ export default {
12
+ async fetch() {
13
+ return new Response('Hello World')
14
+ },
15
+ }
16
+ ```
17
+
18
+ Acryl uses only Web Standards, which means that Acryl can run on any runtime that supports them.
19
+ In addition, we have a Node.js adapter. Acryl runs on these runtimes:
20
+
21
+ - Cloudflare Workers (`workerd`)
22
+ - Deno
23
+ - Bun
24
+ - Fastly Compute
25
+ - AWS Lambda
26
+ - Node.js
27
+ - Vercel (edge-light)
28
+ - WebAssembly (w/ [WebAssembly System Interface (WASI)][wasi] via [`wasi:http`][wasi-http])
29
+
30
+ It also works on Netlify and other platforms.
31
+ The same code runs on all platforms.
32
+
33
+ Cloudflare Workers, Deno, Shopify, and others launched [WinterCG](https://wintercg.org) to discuss the possibility of using the Web Standards to enable "web-interoperability".
34
+ Acryl will follow their steps and go for **the Standard of the Web Standards**.
35
+
36
+ [wasi]: https://github.com/WebAssembly/wasi
37
+ [wasi-http]: https://github.com/WebAssembly/wasi-http
@@ -1,31 +1,31 @@
1
- # Getting started
1
+ # Acryl in a Cordis app
2
2
 
3
- The ACRYL Framework puts its application model inside Cordis. You build an ordinary `App`, register routes and middleware on it, then
3
+ The ACRYL Framework puts its application model inside Cordis. You build an ordinary `Acryl`, register routes and middleware on it, then
4
4
  mount that app from a Cordis plugin.
5
5
 
6
6
  ## The mental model
7
7
 
8
8
  There are two layers:
9
9
 
10
- 1. **Application layer** - `App`, handlers, middleware, context, requests, responses, validation and helpers. This is the ACRYL
10
+ 1. **Application layer** - `Acryl`, handlers, middleware, context, requests, responses, validation and helpers. This is the ACRYL
11
11
  application API.
12
12
  2. **Cordis layer** - plugins, services, injection, effects and disposal. This decides when an application exists and which surface can
13
13
  reach it.
14
14
 
15
- A route therefore has two owners. The `App` owns the route table. The plugin that mounted the app owns the mount for as long as its
15
+ A route therefore has two owners. The `Acryl` owns the route table. The plugin that mounted the app owns the mount for as long as its
16
16
  Cordis fiber is active.
17
17
 
18
18
  ## A minimal plugin
19
19
 
20
20
  ```ts
21
21
  import type { Context } from '@deepseek-ai/cordis'
22
- import { App } from 'acryl-router'
22
+ import { Acryl } from 'acrylblends'
23
23
 
24
24
  export const name = 'todo' // equals the package name and the Loader row id
25
25
  export const inject = ['router'] // PENDING until a router exists
26
26
 
27
27
  export function apply(ctx: Context): void {
28
- const app = new App()
28
+ const app = new Acryl()
29
29
  .get('/', c => c.json({ ok: true }))
30
30
  .get('/todos/:id', c => c.json({ id: c.req.param('id') }))
31
31
 
@@ -48,14 +48,14 @@ export function apply(ctx: Context): void {
48
48
  `/todo/` is the first thing people type, and by default it is not found: the router treats `/todo` and `/todo/` as two paths. Choose
49
49
  one of these, in this order of preference:
50
50
 
51
- - **Redirect in your app** (what `examples/acryl-todo` does): add `trimTrailingSlash()` from `acryl-router/middleware` to the app.
51
+ - **Redirect in your app** (what `examples/acryl-todo` does): add `trimTrailingSlash()` from `acrylblends/trailing-slash` to the app.
52
52
  A GET or HEAD that would be a 404 and ends in `/` gets a 301 to the same path without it, so `/todo/` reaches the page and every
53
53
  route keeps one canonical path. Other methods are not redirected: `POST /todo/api/` stays a 404.
54
54
 
55
55
  ```ts
56
- import { trimTrailingSlash } from 'acryl-router/middleware'
56
+ import { trimTrailingSlash } from 'acrylblends/trailing-slash'
57
57
 
58
- const app = new App()
58
+ const app = new Acryl()
59
59
  .use(trimTrailingSlash())
60
60
  .get('/', c => c.json({ ok: true }))
61
61
  ```
@@ -64,9 +64,9 @@ one of these, in this order of preference:
64
64
  mounted app, with no redirect. It is the app's composition that sets it (the Blueprint or profile that owns the router row), not one
65
65
  plugin, because it changes every other plugin's routes too.
66
66
 
67
- `new App({ strict: false })` does not help once the app is mounted: the router composes every mount into its own root app, and only the
68
- router's `trailingSlash` setting decides. `strict: false` applies to an `App` you serve yourself (`app.fetch`, `app.request`). Details
69
- and a measured table: [Routing and mounting](./routing.md#trailing-slashes).
67
+ `new Acryl({ strict: false })` does not help once the app is mounted: the router composes every mount into its own root app, and only the
68
+ router's `trailingSlash` setting decides. `strict: false` applies to an `Acryl` you serve yourself (`app.fetch`, `app.request`). Details
69
+ and a measured table: [Routing and mounting](../api/routing.md#trailing-slashes).
70
70
 
71
71
  The mount belongs to the plugin that made it: `route` registers it as a Cordis effect of the caller, so when the plugin unloads the
72
72
  routes disappear, and a reload mounts the app again without duplicating routes. `route` also returns a function that removes the mount
@@ -79,7 +79,7 @@ Finish building the app before you mount it: the router copies the app's routes
79
79
  Middleware is registered on the app before the routes it should wrap:
80
80
 
81
81
  ```ts
82
- const app = new App()
82
+ const app = new Acryl()
83
83
  .use(async (c, next) => {
84
84
  const started = Date.now()
85
85
  await next()
@@ -89,7 +89,7 @@ const app = new App()
89
89
  ```
90
90
 
91
91
  Use middleware for authentication, logging, CORS, compression, request IDs and other behavior that should wrap more than one handler.
92
- The built-in set is listed in [Middleware](./middleware.md).
92
+ The built-in set is listed in [Middleware](../concepts/middleware.md).
93
93
 
94
94
  ## Run the same app on a surface
95
95
 
@@ -141,6 +141,6 @@ expect(await response.json()).toEqual({ id: '42' })
141
141
  ## Next
142
142
 
143
143
  - [Core concepts](./concepts.md)
144
- - [Routing and mounting](./routing.md)
145
- - [Context](./context.md)
144
+ - [Routing and mounting](../api/routing.md)
145
+ - [Context](../api/context.md)
146
146
  - [Plugin lifecycle and disposal](./plugin-lifecycle.md)
@@ -3,9 +3,9 @@
3
3
  The framework's request-handling model is designed so every extension point belongs to a Cordis plugin. This page explains the pieces
4
4
  before the API reference.
5
5
 
6
- ## App
6
+ ## Acryl
7
7
 
8
- An `App` is a self-contained ACRYL application. It owns:
8
+ An `Acryl` is a self-contained ACRYL application. It owns:
9
9
 
10
10
  - routes;
11
11
  - middleware;
@@ -0,0 +1,8 @@
1
+ # Middleware in Cordis
2
+
3
+ Middleware belongs to an `Acryl`; it is not a separate Cordis registration, and it disappears with the mount that serves it. A plugin may
4
+ build middleware from an injected service, but resources the middleware uses (timers, watchers, connections) are acquired in the plugin's
5
+ `ctx.effect()` and only the finished middleware goes into the app. Do not start timers, watchers or sockets from a handler.
6
+
7
+ Middleware an app registers with a path wraps the matching routes of every later mount too (an app mounted at `/` with
8
+ `app.use('/todo/*', ...)` wraps a plugin mounted at `/todo`), so a host can put a guard in front of other plugins by mounting first.