acrylblends 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/LICENSE +73 -0
  2. package/docs/framework/README.md +51 -51
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/agents/index.md +24 -0
  5. package/docs/framework/api/acryl.md +259 -0
  6. package/docs/framework/api/context.md +527 -0
  7. package/docs/framework/api/exception.md +80 -0
  8. package/docs/framework/api/index.md +12 -0
  9. package/docs/framework/api/presets.md +65 -0
  10. package/docs/framework/api/request.md +396 -0
  11. package/docs/framework/api/routing.md +303 -0
  12. package/docs/framework/{api-summary.md → api/summary.md} +19 -17
  13. package/docs/framework/concepts/benchmarks.md +26 -0
  14. package/docs/framework/concepts/developer-experience.md +5 -0
  15. package/docs/framework/concepts/middleware.md +21 -0
  16. package/docs/framework/concepts/motivation.md +14 -0
  17. package/docs/framework/concepts/routers.md +63 -0
  18. package/docs/framework/concepts/stacks.md +235 -0
  19. package/docs/framework/concepts/web-standard.md +37 -0
  20. package/docs/framework/{getting-started.md → cordis/acryl-in-a-cordis-app.md} +16 -16
  21. package/docs/framework/{concepts.md → cordis/concepts.md} +2 -2
  22. package/docs/framework/cordis/middleware.md +8 -0
  23. package/docs/framework/{migration-from-0-3.md → cordis/migration-from-0-3.md} +16 -13
  24. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  25. package/docs/framework/{migration-from-dsh-webserver.md → cordis/migration-from-dsh-webserver.md} +7 -7
  26. package/docs/framework/{routing.md → cordis/mounting.md} +5 -108
  27. package/docs/framework/{node-server.md → cordis/node-server.md} +4 -4
  28. package/docs/framework/{surfaces.md → cordis/surfaces.md} +2 -2
  29. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  30. package/docs/framework/{validation.md → cordis/validation.md} +9 -9
  31. package/docs/framework/getting-started/basic.md +196 -0
  32. package/docs/framework/getting-started/bun.md +221 -0
  33. package/docs/framework/getting-started/nodejs.md +344 -0
  34. package/docs/framework/getting-started/other-runtimes.md +23 -0
  35. package/docs/framework/guides/best-practices.md +231 -0
  36. package/docs/framework/guides/create-acrylblends.md +79 -0
  37. package/docs/framework/guides/examples.md +3 -0
  38. package/docs/framework/guides/faq.md +19 -0
  39. package/docs/framework/guides/helpers.md +33 -0
  40. package/docs/framework/guides/jsx-dom.md +299 -0
  41. package/docs/framework/guides/jsx.md +440 -0
  42. package/docs/framework/guides/middleware.md +253 -0
  43. package/docs/framework/guides/rpc.md +886 -0
  44. package/docs/framework/guides/testing.md +133 -0
  45. package/docs/framework/guides/validation.md +383 -0
  46. package/docs/framework/helpers/accepts.md +60 -0
  47. package/docs/framework/helpers/adapter.md +87 -0
  48. package/docs/framework/helpers/conninfo.md +112 -0
  49. package/docs/framework/helpers/cookie.md +232 -0
  50. package/docs/framework/helpers/css.md +285 -0
  51. package/docs/framework/helpers/dev.md +67 -0
  52. package/docs/framework/helpers/factory.md +180 -0
  53. package/docs/framework/helpers/html.md +123 -0
  54. package/docs/framework/helpers/jwt.md +184 -0
  55. package/docs/framework/helpers/proxy.md +118 -0
  56. package/docs/framework/helpers/route.md +143 -0
  57. package/docs/framework/helpers/ssg.md +393 -0
  58. package/docs/framework/helpers/streaming.md +119 -0
  59. package/docs/framework/helpers/testing.md +101 -0
  60. package/docs/framework/helpers/websocket.md +215 -0
  61. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  62. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  63. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  64. package/docs/framework/middleware/builtin/cache.md +122 -0
  65. package/docs/framework/middleware/builtin/combine.md +94 -0
  66. package/docs/framework/middleware/builtin/compress.md +59 -0
  67. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  68. package/docs/framework/middleware/builtin/cors.md +135 -0
  69. package/docs/framework/middleware/builtin/csrf.md +105 -0
  70. package/docs/framework/middleware/builtin/etag.md +54 -0
  71. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  72. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  73. package/docs/framework/middleware/builtin/jwk.md +192 -0
  74. package/docs/framework/middleware/builtin/jwt.md +145 -0
  75. package/docs/framework/middleware/builtin/language.md +232 -0
  76. package/docs/framework/middleware/builtin/logger.md +74 -0
  77. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  78. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  79. package/docs/framework/middleware/builtin/method-override.md +80 -0
  80. package/docs/framework/middleware/builtin/mount.md +106 -0
  81. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  82. package/docs/framework/middleware/builtin/request-id.md +94 -0
  83. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  84. package/docs/framework/middleware/builtin/timeout.md +98 -0
  85. package/docs/framework/middleware/builtin/timing.md +101 -0
  86. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  87. package/docs/framework/middleware/third-party.md +4 -0
  88. package/docs/framework/upstream.json +3 -3
  89. package/lib/accepts-XBuZPVRI.js +52 -0
  90. package/lib/accepts.d.ts +33 -0
  91. package/lib/accepts.js +2 -0
  92. package/lib/acryl-base.d.ts +2 -0
  93. package/lib/acryl-base.js +332 -0
  94. package/lib/adapter.d.ts +12 -0
  95. package/lib/adapter.js +37 -0
  96. package/lib/app-BM0rTCp7.js +26 -0
  97. package/lib/app-CmAYW1Al.d.ts +21 -0
  98. package/lib/basic-auth.d.ts +72 -0
  99. package/lib/basic-auth.js +95 -0
  100. package/lib/bearer-auth.d.ts +89 -0
  101. package/lib/bearer-auth.js +94 -0
  102. package/lib/body-limit.d.ts +42 -0
  103. package/lib/body-limit.js +66 -0
  104. package/lib/client-BHTr318g.js +266 -0
  105. package/lib/client.d.ts +3 -0
  106. package/lib/client.js +2 -0
  107. package/lib/combine.d.ts +85 -0
  108. package/lib/combine.js +137 -0
  109. package/lib/compose-BuW2B6PZ.js +50 -0
  110. package/lib/compress.d.ts +38 -0
  111. package/lib/compress.js +79 -0
  112. package/lib/connection-C7xgP1hP.js +24 -0
  113. package/lib/conninfo.d.ts +25 -0
  114. package/lib/conninfo.js +2 -0
  115. package/lib/constants-Dy7ZvN1H.js +4 -0
  116. package/lib/context-Bm7rI-oK.d.ts +1234 -0
  117. package/lib/context-DDO0cfuP.js +365 -0
  118. package/lib/context-storage.d.ts +38 -0
  119. package/lib/context-storage.js +52 -0
  120. package/lib/cookie-ClMaKDQf.d.ts +40 -0
  121. package/lib/cookie.d.ts +24 -0
  122. package/lib/cookie.js +82 -0
  123. package/lib/cors.d.ts +52 -0
  124. package/lib/cors.js +106 -0
  125. package/lib/csrf.d.ts +75 -0
  126. package/lib/csrf.js +101 -0
  127. package/lib/etag.d.ts +40 -0
  128. package/lib/etag.js +135 -0
  129. package/lib/factory.d.ts +35 -0
  130. package/lib/factory.js +30 -0
  131. package/lib/headers-tu2YYN8T.d.ts +11 -0
  132. package/lib/html.d.ts +6 -0
  133. package/lib/html.js +31 -0
  134. package/lib/http-exception.d.ts +57 -0
  135. package/lib/http-exception.js +54 -0
  136. package/lib/http-status-DaAwGAFL.d.ts +35 -0
  137. package/lib/index-B-3F4wt2.d.ts +12 -0
  138. package/lib/index-UTBmM3GX.d.ts +68 -0
  139. package/lib/index-oOClm_Xk.d.ts +45 -0
  140. package/lib/index.d.ts +5 -0
  141. package/lib/index.js +28 -0
  142. package/lib/ip-restriction.d.ts +68 -0
  143. package/lib/ip-restriction.js +166 -0
  144. package/lib/jwk.d.ts +52 -0
  145. package/lib/jwk.js +117 -0
  146. package/lib/jwt-BGJBw5AF.js +403 -0
  147. package/lib/jwt-Dg493Tai.d.ts +51 -0
  148. package/lib/jwt.d.ts +72 -0
  149. package/lib/jwt.js +115 -0
  150. package/lib/language.d.ts +88 -0
  151. package/lib/language.js +198 -0
  152. package/lib/logger.d.ts +22 -0
  153. package/lib/logger.js +54 -0
  154. package/lib/loopback-only.d.ts +45 -0
  155. package/lib/loopback-only.js +90 -0
  156. package/lib/method-not-allowed.d.ts +47 -0
  157. package/lib/method-not-allowed.js +82 -0
  158. package/lib/method-override.d.ts +46 -0
  159. package/lib/method-override.js +103 -0
  160. package/lib/mime-BQOYHl-l.d.ts +72 -0
  161. package/lib/node-server/conninfo.d.ts +11 -0
  162. package/lib/node-server/conninfo.js +19 -0
  163. package/lib/node-server/serve-static.d.ts +19 -0
  164. package/lib/node-server/serve-static.js +2 -0
  165. package/lib/node-server.d.ts +103 -0
  166. package/lib/node-server.js +1325 -0
  167. package/lib/powered-by.d.ts +28 -0
  168. package/lib/powered-by.js +24 -0
  169. package/lib/pretty-json.d.ts +40 -0
  170. package/lib/pretty-json.js +39 -0
  171. package/lib/reg-exp-router-DC1R3qoY.js +363 -0
  172. package/lib/request-id.d.ts +45 -0
  173. package/lib/request-id.js +34 -0
  174. package/lib/request.d.ts +2 -0
  175. package/lib/request.js +323 -0
  176. package/lib/route.d.ts +78 -0
  177. package/lib/route.js +126 -0
  178. package/lib/router/linear-router.d.ts +11 -0
  179. package/lib/router/linear-router.js +96 -0
  180. package/lib/router/pattern-router.d.ts +11 -0
  181. package/lib/router/pattern-router.js +41 -0
  182. package/lib/router/reg-exp-router.d.ts +35 -0
  183. package/lib/router/reg-exp-router.js +2 -0
  184. package/lib/router/smart-router.d.ts +15 -0
  185. package/lib/router/smart-router.js +2 -0
  186. package/lib/router/trie-router.d.ts +11 -0
  187. package/lib/router/trie-router.js +2 -0
  188. package/lib/router-CvUxUTOq.d.ts +99 -0
  189. package/lib/router.d.ts +2 -0
  190. package/lib/router.js +35 -0
  191. package/lib/schema-validator.d.ts +28 -0
  192. package/lib/schema-validator.js +22 -0
  193. package/lib/secure-headers.d.ts +125 -0
  194. package/lib/secure-headers.js +163 -0
  195. package/lib/serve-static-Dw_m6KxR.js +213 -0
  196. package/lib/serve-static.d.ts +31 -0
  197. package/lib/serve-static.js +77 -0
  198. package/lib/smart-router-C5CZ5XSM.js +49 -0
  199. package/lib/stream-CPdqZ0Fp.d.ts +34 -0
  200. package/lib/streaming-DHST3Scg.js +96 -0
  201. package/lib/streaming.d.ts +23 -0
  202. package/lib/streaming.js +2 -0
  203. package/lib/testing.d.ts +10 -0
  204. package/lib/testing.js +17 -0
  205. package/lib/timeout.d.ts +30 -0
  206. package/lib/timeout.js +42 -0
  207. package/lib/timing.d.ts +130 -0
  208. package/lib/timing.js +183 -0
  209. package/lib/trailing-slash.d.ts +91 -0
  210. package/lib/trailing-slash.js +85 -0
  211. package/lib/trie-router-CfFbapzL.js +146 -0
  212. package/lib/types-CDO6I3B0.d.ts +40 -0
  213. package/lib/types-CHesD1KG.d.ts +195 -0
  214. package/lib/types-CwrQjlaM.d.ts +105 -0
  215. package/lib/types-DR95J00T.d.ts +29 -0
  216. package/lib/types.d.ts +2 -0
  217. package/lib/types.js +4 -0
  218. package/lib/utils/accept.d.ts +9 -0
  219. package/lib/utils/accept.js +193 -0
  220. package/lib/utils/basic-auth.d.ts +8 -0
  221. package/lib/utils/basic-auth.js +20 -0
  222. package/lib/utils/body.d.ts +2 -0
  223. package/lib/utils/body.js +94 -0
  224. package/lib/utils/buffer.d.ts +19 -0
  225. package/lib/utils/buffer.js +51 -0
  226. package/lib/utils/color.d.ts +24 -0
  227. package/lib/utils/color.js +37 -0
  228. package/lib/utils/compress.d.ts +11 -0
  229. package/lib/utils/compress.js +11 -0
  230. package/lib/utils/concurrent.d.ts +17 -0
  231. package/lib/utils/concurrent.js +30 -0
  232. package/lib/utils/constants.d.ts +7 -0
  233. package/lib/utils/constants.js +7 -0
  234. package/lib/utils/cookie.d.ts +2 -0
  235. package/lib/utils/cookie.js +125 -0
  236. package/lib/utils/crypto.d.ts +14 -0
  237. package/lib/utils/crypto.js +34 -0
  238. package/lib/utils/encode.d.ts +11 -0
  239. package/lib/utils/encode.js +33 -0
  240. package/lib/utils/filepath.d.ts +14 -0
  241. package/lib/utils/filepath.js +25 -0
  242. package/lib/utils/handler.d.ts +9 -0
  243. package/lib/utils/handler.js +12 -0
  244. package/lib/utils/headers.d.ts +2 -0
  245. package/lib/utils/headers.js +1 -0
  246. package/lib/utils/html.d.ts +46 -0
  247. package/lib/utils/html.js +103 -0
  248. package/lib/utils/http-status.d.ts +2 -0
  249. package/lib/utils/http-status.js +1 -0
  250. package/lib/utils/ipaddr.d.ts +56 -0
  251. package/lib/utils/ipaddr.js +238 -0
  252. package/lib/utils/jwt.d.ts +24 -0
  253. package/lib/utils/jwt.js +2 -0
  254. package/lib/utils/mime.d.ts +2 -0
  255. package/lib/utils/mime.js +77 -0
  256. package/lib/utils/stream.d.ts +2 -0
  257. package/lib/utils/stream.js +88 -0
  258. package/lib/utils/types.d.ts +2 -0
  259. package/lib/utils/types.js +1 -0
  260. package/lib/utils/url.d.ts +46 -0
  261. package/lib/utils/url.js +197 -0
  262. package/lib/utils-dw8lxqjL.js +4 -0
  263. package/lib/validator-D84mq-dO.js +65 -0
  264. package/lib/validator.d.ts +42 -0
  265. package/lib/validator.js +2 -0
  266. package/lib/ws.d.ts +2 -0
  267. package/lib/ws.js +53 -0
  268. package/package.json +312 -14
  269. package/plugins/acryl-inspect/src/service.ts +2 -2
  270. package/plugins/acryl-inspect/tests/service.spec.ts +3 -3
  271. package/plugins/acryl-inspect/upstream.json +2 -2
  272. package/plugins/acryl-node-server/tests/adapter/app.ts +2 -2
  273. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -1
  274. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -1
  275. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +2 -2
  276. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +4 -4
  277. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +5 -5
  278. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +2 -2
  279. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +20 -20
  280. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +2 -2
  281. package/plugins/acryl-node-server/tests/adapter/server.test.ts +50 -50
  282. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +4 -4
  283. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +9 -9
  284. package/plugins/acryl-node-server/tests/server.spec.ts +6 -6
  285. package/plugins/acryl-node-server/upstream.json +2 -2
  286. package/plugins/acryl-router/src/client.ts +1 -1
  287. package/plugins/acryl-router/src/connection.ts +2 -2
  288. package/plugins/acryl-router/src/core/app-base.ts +29 -29
  289. package/plugins/acryl-router/src/core/app.test.ts +175 -175
  290. package/plugins/acryl-router/src/core/app.ts +8 -8
  291. package/plugins/acryl-router/src/core/client/client.test.ts +76 -76
  292. package/plugins/acryl-router/src/core/client/client.ts +2 -2
  293. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +1 -1
  294. package/plugins/acryl-router/src/core/client/index.ts +1 -1
  295. package/plugins/acryl-router/src/core/client/types.test.ts +6 -6
  296. package/plugins/acryl-router/src/core/client/types.ts +16 -16
  297. package/plugins/acryl-router/src/core/client/utils.test.ts +2 -2
  298. package/plugins/acryl-router/src/core/context.test.ts +4 -4
  299. package/plugins/acryl-router/src/core/context.ts +6 -6
  300. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +3 -3
  301. package/plugins/acryl-router/src/core/helper/accepts/index.ts +1 -1
  302. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +6 -6
  303. package/plugins/acryl-router/src/core/helper/adapter/index.ts +1 -1
  304. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +1 -1
  305. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +8 -8
  306. package/plugins/acryl-router/src/core/helper/cookie/index.ts +1 -1
  307. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +9 -9
  308. package/plugins/acryl-router/src/core/helper/factory/index.ts +10 -10
  309. package/plugins/acryl-router/src/core/helper/html/index.test.ts +4 -4
  310. package/plugins/acryl-router/src/core/helper/html/index.ts +1 -1
  311. package/plugins/acryl-router/src/core/helper/route/index.test.ts +7 -7
  312. package/plugins/acryl-router/src/core/helper/route/index.ts +8 -8
  313. package/plugins/acryl-router/src/core/helper/streaming/index.ts +1 -1
  314. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +6 -6
  315. package/plugins/acryl-router/src/core/helper/testing/index.ts +4 -4
  316. package/plugins/acryl-router/src/core/helper/websocket/index.ts +2 -1
  317. package/plugins/acryl-router/src/core/http-exception.ts +1 -1
  318. package/plugins/acryl-router/src/core/index.ts +9 -9
  319. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +6 -6
  320. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +3 -3
  321. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +5 -5
  322. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +3 -3
  323. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +6 -6
  324. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +3 -3
  325. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +9 -9
  326. package/plugins/acryl-router/src/core/middleware/combine/index.ts +7 -7
  327. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +9 -9
  328. package/plugins/acryl-router/src/core/middleware/compress/index.ts +3 -3
  329. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +5 -5
  330. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +4 -4
  331. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +7 -7
  332. package/plugins/acryl-router/src/core/middleware/cors/index.ts +3 -3
  333. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +10 -10
  334. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +3 -3
  335. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +42 -42
  336. package/plugins/acryl-router/src/core/middleware/etag/index.ts +4 -4
  337. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +4 -4
  338. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +6 -6
  339. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +16 -16
  340. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +7 -6
  341. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +16 -16
  342. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +4 -3
  343. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +3 -3
  344. package/plugins/acryl-router/src/core/middleware/language/language.ts +3 -3
  345. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +5 -5
  346. package/plugins/acryl-router/src/core/middleware/logger/index.ts +4 -4
  347. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +24 -24
  348. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +8 -8
  349. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +5 -5
  350. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +6 -6
  351. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +4 -4
  352. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +6 -6
  353. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +30 -30
  354. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +4 -4
  355. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +15 -15
  356. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +3 -3
  357. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +35 -35
  358. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +3 -3
  359. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +23 -23
  360. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +1 -1
  361. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +2 -2
  362. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +3 -3
  363. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +14 -14
  364. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +3 -3
  365. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +7 -7
  366. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +7 -7
  367. package/plugins/acryl-router/src/core/request.test.ts +42 -42
  368. package/plugins/acryl-router/src/core/request.ts +6 -6
  369. package/plugins/acryl-router/src/core/router/linear-router/index.ts +1 -1
  370. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +1 -1
  371. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +1 -1
  372. package/plugins/acryl-router/src/core/router/smart-router/index.ts +1 -1
  373. package/plugins/acryl-router/src/core/router/trie-router/index.ts +1 -1
  374. package/plugins/acryl-router/src/core/types.test.ts +115 -115
  375. package/plugins/acryl-router/src/core/types.ts +72 -72
  376. package/plugins/acryl-router/src/core/utils/body.ts +8 -8
  377. package/plugins/acryl-router/src/core/utils/html.ts +1 -1
  378. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +3 -3
  379. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +2 -2
  380. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +3 -3
  381. package/plugins/acryl-router/src/core/utils/jwt/types.ts +1 -1
  382. package/plugins/acryl-router/src/core/utils/types.ts +42 -0
  383. package/plugins/acryl-router/src/core/utils/url.test.ts +2 -2
  384. package/plugins/acryl-router/src/core/validator/index.ts +1 -1
  385. package/plugins/acryl-router/src/core/validator/validator.test.ts +28 -28
  386. package/plugins/acryl-router/src/deprecated.ts +15 -0
  387. package/plugins/acryl-router/src/index.ts +3 -2
  388. package/plugins/acryl-router/src/service.ts +10 -10
  389. package/plugins/acryl-router/tests/docs-examples.spec.ts +11 -11
  390. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  391. package/plugins/acryl-router/tests/loader.spec.ts +3 -3
  392. package/plugins/acryl-router/tests/loopback-only.spec.ts +4 -4
  393. package/plugins/acryl-router/tests/no-dom/consumer.ts +11 -0
  394. package/plugins/acryl-router/tests/no-dom/tsconfig.json +13 -0
  395. package/plugins/acryl-router/tests/service.spec.ts +23 -23
  396. package/plugins/acryl-router/upstream.json +3 -3
  397. package/plugins/acryl-router-http/tests/adapter.spec.ts +3 -3
  398. package/plugins/acryl-router-http/tests/surfaces.spec.ts +2 -2
  399. package/plugins/acryl-router-http/upstream.json +2 -2
  400. package/plugins/acryl-state/src/service.ts +2 -2
  401. package/plugins/acryl-state/upstream.json +2 -2
  402. package/plugins/builder/script.ts +2 -2
  403. package/plugins/extensions/resolve.ts +70 -10
  404. package/plugins/openai/prompt.ts +5 -5
  405. package/shared/AGENTS.core.md +16 -9
  406. package/templates/agent/src/routes.ts +2 -2
  407. package/templates/agent/test/model.test.ts +2 -2
  408. package/templates/agent/tsconfig.json +40 -0
  409. package/templates/blank/src/routes.ts +2 -2
  410. package/templates/todo/src/todo.ts +2 -2
  411. package/templates/todo/upstream.json +2 -2
  412. package/docs/framework/context.md +0 -129
  413. package/docs/framework/helpers.md +0 -118
  414. package/docs/framework/middleware.md +0 -154
  415. package/docs/framework/request.md +0 -106
  416. /package/docs/framework/{plugin-lifecycle.md → cordis/plugin-lifecycle.md} +0 -0
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2024",
4
+ "lib": ["ES2024"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "strict": true,
8
+ "exactOptionalPropertyTypes": true,
9
+ "noEmit": true,
10
+ "types": ["node"]
11
+ },
12
+ "files": ["consumer.ts"]
13
+ }
@@ -7,7 +7,7 @@
7
7
  import { Context, type FiberState } from '@deepseek-ai/cordis'
8
8
  import { afterEach, describe, expect, it } from 'vitest'
9
9
  import { streamSSE } from '../src/helpers/index.ts'
10
- import { apply, App, Config, connectionOf, HTTPException, name, type Router } from '../src/index.ts'
10
+ import { apply, Acryl, Config, connectionOf, HTTPException, name, type Router } from '../src/index.ts'
11
11
 
12
12
  const PENDING = 0 as FiberState.PENDING
13
13
  const ACTIVE = 2 as FiberState.ACTIVE
@@ -42,7 +42,7 @@ function consumer(path: string, label: string) {
42
42
  name: `consumer${label}`,
43
43
  inject: ['router'],
44
44
  apply(ctx: Context): void {
45
- ctx.router.route('/', new App().get(path, c => c.text(label)))
45
+ ctx.router.route('/', new Acryl().get(path, c => c.text(label)))
46
46
  },
47
47
  }
48
48
  }
@@ -52,7 +52,7 @@ const get = (router: Router, path: string): Promise<Response> => router.fetch(ne
52
52
  describe('acryl-router mounts', () => {
53
53
  it('serves a mounted app under its path, with the app\'s own routes, middleware and error handler', async () => {
54
54
  const { router } = await mountRouter()
55
- const api = new App()
55
+ const api = new Acryl()
56
56
  .use(async (c, next) => { await next(); c.header('x-api', 'yes') })
57
57
  .get('/items/:id', c => c.json({ id: c.req.param('id') }))
58
58
  .get('/boom', () => { throw new Error('boom') })
@@ -70,28 +70,28 @@ describe('acryl-router mounts', () => {
70
70
 
71
71
  it('removes a mount with its remover, idempotently, and keeps the others', async () => {
72
72
  const { router } = await mountRouter()
73
- const removeA = router.route('/', new App().get('/a', c => c.text('a')))
74
- router.route('/', new App().get('/b', c => c.text('b')))
73
+ const removeA = router.route('/', new Acryl().get('/a', c => c.text('a')))
74
+ router.route('/', new Acryl().get('/b', c => c.text('b')))
75
75
  expect((await get(router, '/a')).status).toBe(200)
76
76
  removeA()
77
77
  removeA()
78
78
  expect((await get(router, '/a')).status).toBe(404)
79
79
  expect(await (await get(router, '/b')).text()).toBe('b')
80
- router.route('/', new App().get('/a', c => c.text('a2')))
80
+ router.route('/', new Acryl().get('/a', c => c.text('a2')))
81
81
  expect(await (await get(router, '/a')).text()).toBe('a2')
82
82
  })
83
83
 
84
84
  it('runs mounts in the order they were made, so an earlier mount\'s middleware wraps a later mount\'s routes', async () => {
85
85
  const { router } = await mountRouter()
86
- router.route('/', new App().use('/guarded/*', async c => c.text('denied', 401)))
87
- router.route('/', new App().get('/guarded/x', c => c.text('secret')).get('/open', c => c.text('open')))
86
+ router.route('/', new Acryl().use('/guarded/*', async c => c.text('denied', 401)))
87
+ router.route('/', new Acryl().get('/guarded/x', c => c.text('secret')).get('/open', c => c.text('open')))
88
88
  expect((await get(router, '/guarded/x')).status).toBe(401)
89
89
  expect(await (await get(router, '/open')).text()).toBe('open')
90
90
  })
91
91
 
92
92
  it('takes one router-wide error handler and one not-found handler, owned by the caller', async () => {
93
93
  const { router } = await mountRouter()
94
- router.route('/', new App().get('/boom', () => { throw new Error('boom') }).get('/teapot', () => { throw new HTTPException(418, { message: 'short' }) }))
94
+ router.route('/', new Acryl().get('/boom', () => { throw new Error('boom') }).get('/teapot', () => { throw new HTTPException(418, { message: 'short' }) }))
95
95
  expect((await get(router, '/boom')).status).toBe(500)
96
96
  expect((await get(router, '/teapot')).status).toBe(418)
97
97
 
@@ -109,13 +109,13 @@ describe('acryl-router mounts', () => {
109
109
  const ctx = root()
110
110
  ctx.plugin(provider, { trailingSlash: 'ignore', disposeGraceMs: 2000 })
111
111
  await settle()
112
- ctx.router.route('/', new App().get('/a', c => c.text('a')))
112
+ ctx.router.route('/', new Acryl().get('/a', c => c.text('a')))
113
113
  expect((await get(ctx.router, '/a/')).status).toBe(200)
114
114
  })
115
115
 
116
116
  it('hands the transport\'s connection info to the handler and gives an in-process call an empty one', async () => {
117
117
  const { router } = await mountRouter()
118
- router.route('/', new App().get('/who', c => c.json({ remote: connectionOf(c).remoteAddress ?? null, port: connectionOf(c).localPort ?? null })))
118
+ router.route('/', new Acryl().get('/who', c => c.json({ remote: connectionOf(c).remoteAddress ?? null, port: connectionOf(c).localPort ?? null })))
119
119
  const over = await router.fetch(new Request('http://acryl.test/who'), { remoteAddress: '127.0.0.1', localPort: 4000 })
120
120
  expect(await over.json()).toEqual({ remote: '127.0.0.1', port: 4000 })
121
121
  const inProcess = await router.request('/who')
@@ -154,7 +154,7 @@ describe('acryl-router lifecycle through Cordis', () => {
154
154
 
155
155
  it('labels a mount by its path with one child per route, so no label grows with the app (an inspector caps label length)', async () => {
156
156
  const { ctx, router } = await mountRouter()
157
- const big = new App().use('/api/*', async (_c, next) => { await next() })
157
+ const big = new Acryl().use('/api/*', async (_c, next) => { await next() })
158
158
  for (let i = 0; i < 60; i += 1) big.get(`/api/a-fairly-long-resource-name-${String(i)}`, c => c.text('ok'))
159
159
  const fiber = ctx.plugin({ name: 'big', inject: ['router'], apply: (inner: Context) => { inner.router.route('/', big) } })
160
160
  await settle()
@@ -192,7 +192,7 @@ describe('acryl-router lifecycle through Cordis', () => {
192
192
 
193
193
  it('serves the routes an app had when it was mounted, whatever else changes later', async () => {
194
194
  const { ctx, router } = await mountRouter()
195
- const app = new App().get('/early', c => c.text('early'))
195
+ const app = new Acryl().get('/early', c => c.text('early'))
196
196
  router.route('/', app)
197
197
  app.get('/late', c => c.text('late'))
198
198
  expect((await get(router, '/early')).status).toBe(200)
@@ -223,7 +223,7 @@ describe('acryl-router lifecycle through Cordis', () => {
223
223
  name: 'counting',
224
224
  inject: ['router'],
225
225
  apply(inner: Context): void {
226
- inner.router.route('/', new App().use(async (_c, next) => { calls += 1; await next() }).get('/count', c => c.text(String(calls))))
226
+ inner.router.route('/', new Acryl().use(async (_c, next) => { calls += 1; await next() }).get('/count', c => c.text(String(calls))))
227
227
  },
228
228
  }
229
229
  for (let round = 0; round < 10; round += 1) {
@@ -261,7 +261,7 @@ describe('acryl-router lifecycle through Cordis', () => {
261
261
  await settle()
262
262
  const router = ctx.router
263
263
  let aborted = false
264
- router.route('/', new App().get('/slow', async c => {
264
+ router.route('/', new Acryl().get('/slow', async c => {
265
265
  await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { aborted = true; reject(new Error('aborted')) }, { once: true }) })
266
266
  return c.text('late')
267
267
  }))
@@ -278,7 +278,7 @@ describe('acryl-router lifecycle through Cordis', () => {
278
278
  it('forwards the caller\'s own abort to the handler signal', async () => {
279
279
  const { router } = await mountRouter()
280
280
  let seen = false
281
- router.route('/', new App().get('/slow', async c => {
281
+ router.route('/', new Acryl().get('/slow', async c => {
282
282
  await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { seen = true; reject(new Error('aborted')) }, { once: true }) })
283
283
  return c.text('x')
284
284
  }))
@@ -295,7 +295,7 @@ describe('acryl-router lifecycle through Cordis', () => {
295
295
  const fiber = ctx.plugin(provider, config)
296
296
  await settle()
297
297
  let cleaned = false
298
- ctx.router.route('/', new App().get('/events', c => streamSSE(c, async stream => {
298
+ ctx.router.route('/', new Acryl().get('/events', c => streamSSE(c, async stream => {
299
299
  stream.onAbort(() => { cleaned = true })
300
300
  await stream.writeSSE({ data: 'first' })
301
301
  while (!stream.aborted) await stream.sleep(10)
@@ -319,7 +319,7 @@ describe('acryl-router lifecycle through Cordis', () => {
319
319
  name: 'streaming',
320
320
  inject: ['router'],
321
321
  apply(inner: Context): void {
322
- inner.router.route('/', new App().get('/events', c => streamSSE(c, async stream => {
322
+ inner.router.route('/', new Acryl().get('/events', c => streamSSE(c, async stream => {
323
323
  stream.onAbort(() => { cleaned = true })
324
324
  await stream.writeSSE({ data: 'first' })
325
325
  while (!stream.aborted) await stream.sleep(10)
@@ -330,7 +330,7 @@ describe('acryl-router lifecycle through Cordis', () => {
330
330
  name: 'other',
331
331
  inject: ['router'],
332
332
  apply(inner: Context): void {
333
- inner.router.route('/', new App().get('/slow', async c => {
333
+ inner.router.route('/', new Acryl().get('/slow', async c => {
334
334
  c.req.raw.signal.addEventListener('abort', () => { otherAborted = true }, { once: true })
335
335
  await new Promise<void>(resolve => { release = resolve })
336
336
  return c.text('done')
@@ -361,7 +361,7 @@ describe('acryl-router lifecycle through Cordis', () => {
361
361
  name: 'guard',
362
362
  inject: ['router'],
363
363
  apply(inner: Context): void {
364
- inner.router.route('/', new App()
364
+ inner.router.route('/', new Acryl()
365
365
  .use('/held/*', async (c, next) => {
366
366
  c.req.raw.signal.addEventListener('abort', () => { guardAborted = true }, { once: true })
367
367
  await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { reject(new Error('aborted')) }, { once: true }) })
@@ -374,7 +374,7 @@ describe('acryl-router lifecycle through Cordis', () => {
374
374
  name: 'handler',
375
375
  inject: ['router'],
376
376
  apply(inner: Context): void {
377
- inner.router.route('/', new App()
377
+ inner.router.route('/', new Acryl()
378
378
  .get('/held/x', c => c.text('held'))
379
379
  .get('/passed/x', c => streamSSE(c, async stream => {
380
380
  stream.onAbort(() => { handlerAborted = true })
@@ -402,7 +402,7 @@ describe('acryl-router lifecycle through Cordis', () => {
402
402
  const fiber = ctx.plugin(provider, config)
403
403
  await settle()
404
404
  let finished = false
405
- ctx.router.route('/', new App().get('/later', c => {
405
+ ctx.router.route('/', new Acryl().get('/later', c => {
406
406
  c.executionCtx.waitUntil(new Promise<void>(resolve => { setTimeout(() => { finished = true; resolve() }, 30) }))
407
407
  return c.text('now')
408
408
  }))
@@ -416,7 +416,7 @@ describe('acryl-router lifecycle through Cordis', () => {
416
416
  const ctx = root()
417
417
  const fiber = ctx.plugin(provider, { trailingSlash: 'strict', disposeGraceMs: 30 })
418
418
  await settle()
419
- ctx.router.route('/', new App().get('/stuck', c => { c.executionCtx.waitUntil(new Promise(() => undefined)); return c.text('x') }))
419
+ ctx.router.route('/', new Acryl().get('/stuck', c => { c.executionCtx.waitUntil(new Promise(() => undefined)); return c.text('x') }))
420
420
  await get(ctx.router, '/stuck')
421
421
  const started = Date.now()
422
422
  await fiber.dispose()
@@ -2,15 +2,15 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-router",
5
- "commit": "64e7c9d2e787f74b2da82492644fbbb46a601074"
5
+ "commit": "f5151e7f0c4de3b81bddb5cc686b5ef329e48e1c"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
9
9
  "tests",
10
10
  "LICENSE"
11
11
  ],
12
- "rewrittenSpecifiers": 0,
13
- "digest": "sha256:9ad75d259a74b2a07fe1d8a269e7c83c30061acc90f8a1630e6049b68ba10aa3",
12
+ "rewrittenSpecifiers": 4,
13
+ "digest": "sha256:543a5ca99518eea1fe2e319b7708d62af34a6c24ab3daeb17dde48d67d319d6a",
14
14
  "testsNotRun": {
15
15
  "tests/loader.spec.ts": "loads the built lib/ entry through the real Loader; the library ships source and has no build"
16
16
  },
@@ -8,7 +8,7 @@ import { Context, type FiberState } from '@deepseek-ai/cordis'
8
8
  import WebServer from '@deepseek-ai/dsh-host-webserver'
9
9
  import { apply as routerApply, name as routerName } from '../../acryl-router/src/index.ts'
10
10
  import { afterEach, describe, expect, it } from 'vitest'
11
- import { App, connectionOf, type RouterHttpService } from '../../acryl-router/src/index.ts'
11
+ import { Acryl, connectionOf, type RouterHttpService } from '../../acryl-router/src/index.ts'
12
12
  import { methodNotAllowed } from '../../acryl-router/src/middleware/index.ts'
13
13
  import { apply, inject, name } from '../src/index.ts'
14
14
 
@@ -40,13 +40,13 @@ async function stack(): Promise<{ ctx: Context, base: () => string }> {
40
40
  return { ctx, base: () => `http://127.0.0.1:${String((ctx as unknown as { webServer: { port: number } }).webServer.port)}` }
41
41
  }
42
42
 
43
- function demo(prefix: string, extra?: (app: App) => void) {
43
+ function demo(prefix: string, extra?: (app: Acryl) => void) {
44
44
  return {
45
45
  name: `demo${prefix.replaceAll('/', '-')}`,
46
46
  inject: ['router', 'routerHttp'],
47
47
  apply(ctx: Context): void {
48
48
  ctx.routerHttp.mount(prefix)
49
- const app = new App()
49
+ const app = new Acryl()
50
50
  app.use(methodNotAllowed({ app }))
51
51
  app.get('/hello/:who', c => c.json({ hello: c.req.param('who'), q: c.req.query('q') ?? null, host: c.req.header('host') !== undefined }))
52
52
  app.post('/echo', async c => c.json({ got: await c.req.text(), type: c.req.header('content-type') ?? null }, 201))
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { Context } from '@deepseek-ai/cordis'
9
9
  import WebServer from '@deepseek-ai/dsh-host-webserver'
10
- import { App, apply as routerApply, name as routerName } from '../../acryl-router/src/index.ts'
10
+ import { Acryl, apply as routerApply, name as routerName } from '../../acryl-router/src/index.ts'
11
11
  import { afterEach, describe, expect, it } from 'vitest'
12
12
  import { apply as httpApply, inject as httpInject, name as httpName } from '../src/index.ts'
13
13
 
@@ -28,7 +28,7 @@ const notes = {
28
28
  inject: ['router'],
29
29
  apply(ctx: Context): void {
30
30
  const store = new Map<string, string>()
31
- const app = new App()
31
+ const app = new Acryl()
32
32
  .post('/:id', async c => {
33
33
  const text = await c.req.text()
34
34
  store.set(c.req.param('id'), text)
@@ -2,7 +2,7 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-router-http",
5
- "commit": "64e7c9d2e787f74b2da82492644fbbb46a601074"
5
+ "commit": "f5151e7f0c4de3b81bddb5cc686b5ef329e48e1c"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -10,7 +10,7 @@
10
10
  "LICENSE"
11
11
  ],
12
12
  "rewrittenSpecifiers": 7,
13
- "digest": "sha256:29ba7834cf9d29e9af2f4fac265c7e5e220e06da3346e65c29bcbae41fdfaf9e",
13
+ "digest": "sha256:394994528a104c8f788e2d911f8f940ff9f74e9c5a72835ea3ea751651aa9fbd",
14
14
  "testsNotRun": {
15
15
  "tests/adapter.spec.ts": "needs @deepseek-ai/dsh-host-webserver (the DSH web server); acryl-node-server has its own tests",
16
16
  "tests/stream.spec.ts": "needs @deepseek-ai/dsh-host-webserver (the DSH web server)",
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { Context, Service } from '@deepseek-ai/cordis'
9
- import { App, type Context as RequestContext } from '../../acryl-router/src/index.ts'
9
+ import { Acryl, type Context as RequestContext } from '../../acryl-router/src/index.ts'
10
10
  import { streamSSE } from '../../acryl-router/src/helpers/index.ts'
11
11
  import { loopbackOnly, methodNotAllowed } from '../../acryl-router/src/middleware/index.ts'
12
12
  import { createCell, createDerived, type Cell, type ReadonlyCell } from './cell.ts'
@@ -104,7 +104,7 @@ export function apply(ctx: Context): void {
104
104
  // The same cells on the router, read-only, for any surface; present only where a router is. A request over a socket must come from this machine to this
105
105
  // app; the terminal calls the router in process and is the host's own code.
106
106
  ctx.inject(['router'], inner => {
107
- const api = new App()
107
+ const api = new Acryl()
108
108
  api.use(loopbackOnly({ inProcess: 'allow' }), methodNotAllowed({ app: api }))
109
109
  .get('/', c => c.json({ keys: state.keys() }))
110
110
  .get('/:key', c => {
@@ -2,7 +2,7 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-state",
5
- "commit": "64e7c9d2e787f74b2da82492644fbbb46a601074"
5
+ "commit": "f5151e7f0c4de3b81bddb5cc686b5ef329e48e1c"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -11,7 +11,7 @@
11
11
  "NOTICE"
12
12
  ],
13
13
  "rewrittenSpecifiers": 4,
14
- "digest": "sha256:8feb067a67ea2628ff31a9fd2201361be4be5a8c217be3b7169277c0ce472b69",
14
+ "digest": "sha256:18df69d338a1928fc0f7497c14c245afb98f0c39d4fe6a24bda62bb845d96030",
15
15
  "testsNotRun": {
16
16
  "tests/react.spec.ts": "needs react and @testing-library/react, which generated apps do not install"
17
17
  },
@@ -18,7 +18,7 @@ const PATH = /^\/[a-z0-9/-]*$/
18
18
 
19
19
  export function routeSource(name: string, path: string, text: string): string {
20
20
  return `import type { Context } from '@deepseek-ai/cordis'
21
- import { App } from 'acryl-router'
21
+ import { Acryl } from 'acrylblends'
22
22
 
23
23
  /** Written by the builder: answers GET ${path}, and checks that it does before the install counts. */
24
24
  export const name = '${name}'
@@ -26,7 +26,7 @@ export const inject = ['router']
26
26
 
27
27
  export function apply(ctx: Context) {
28
28
  // The app is mounted through this plugin's context, so the route is removed when the plugin is unloaded.
29
- ctx.router.route('/', new App().get(${JSON.stringify(path)}, (c) => c.json({ text: ${JSON.stringify(text)} })))
29
+ ctx.router.route('/', new Acryl().get(${JSON.stringify(path)}, (c) => c.json({ text: ${JSON.stringify(text)} })))
30
30
  }
31
31
 
32
32
  export async function check(ctx: Context) {
@@ -12,21 +12,81 @@ import { registerHooks } from 'node:module'
12
12
  import { join } from 'node:path'
13
13
  import { fileURLToPath, pathToFileURL } from 'node:url'
14
14
 
15
+ const PACKAGE = 'acrylblends'
16
+
15
17
  const isBare = (specifier: string) => !/^[./]/.test(specifier) && !specifier.includes(':')
16
18
 
17
- /** The router's specifiers, as files of the vendored plugin that sits beside this one; empty when the app has no router. */
19
+ /**
20
+ * The framework's specifiers, as files of the vendored router plugin that sits beside this one. A plugin written while the app runs (by the agent, from the docs in the app)
21
+ * imports `acrylblends` and `acrylblends/<subpath>` as the docs write them; the old `acryl-router` names keep working. Empty when the app has no router.
22
+ */
23
+ const MIDDLEWARE = [
24
+ 'basic-auth',
25
+ 'bearer-auth',
26
+ 'body-limit',
27
+ 'combine',
28
+ 'compress',
29
+ 'context-storage',
30
+ 'cors',
31
+ 'csrf',
32
+ 'etag',
33
+ 'ip-restriction',
34
+ 'jwk',
35
+ 'jwt',
36
+ 'language',
37
+ 'logger',
38
+ 'loopback-only',
39
+ 'method-not-allowed',
40
+ 'method-override',
41
+ 'powered-by',
42
+ 'pretty-json',
43
+ 'request-id',
44
+ 'secure-headers',
45
+ 'serve-static',
46
+ 'timeout',
47
+ 'timing',
48
+ 'trailing-slash',
49
+ ]
50
+ const HELPERS = [
51
+ 'accepts',
52
+ 'cookie',
53
+ 'factory',
54
+ 'html',
55
+ 'route',
56
+ 'schema-validator',
57
+ 'streaming',
58
+ 'testing',
59
+ 'validator',
60
+ 'ws',
61
+ ]
62
+
63
+ /** The `acrylblends/...` names a plugin installed live may import, with the file each resolves to under `acryl-router/src`. */
64
+ export function frameworkSpecifiers(): Record<string, string> {
65
+ const map: Record<string, string> = {
66
+ '': 'index.ts',
67
+ conninfo: 'index.ts',
68
+ 'http-exception': 'index.ts',
69
+ types: 'index.ts',
70
+ client: 'client.ts',
71
+ }
72
+ for (const name of MIDDLEWARE) map[name] = 'middleware/index.ts'
73
+ for (const name of HELPERS) map[name] = 'helpers/index.ts'
74
+ return map
75
+ }
76
+
18
77
  export function routerAliases(): Record<string, string> {
19
78
  const src = new URL('../acryl-router/src/', import.meta.url)
20
- const files = {
21
- 'acryl-router': 'index.ts',
22
- 'acryl-router/middleware': 'middleware/index.ts',
23
- 'acryl-router/helpers': 'helpers/index.ts',
79
+ const aliases: Record<string, string> = {}
80
+ const add = (specifier: string, file: string) => {
81
+ const path = fileURLToPath(new URL(file, src))
82
+ if (existsSync(path)) aliases[specifier] = path
24
83
  }
25
- return Object.fromEntries(
26
- Object.entries(files)
27
- .map(([specifier, file]) => [specifier, fileURLToPath(new URL(file, src))] as const)
28
- .filter(([, path]) => existsSync(path)),
29
- )
84
+ for (const [sub, file] of Object.entries(frameworkSpecifiers()))
85
+ add(sub === '' ? PACKAGE : `${PACKAGE}/${sub}`, file)
86
+ add('acryl-router', 'index.ts')
87
+ add('acryl-router/middleware', 'middleware/index.ts')
88
+ add('acryl-router/helpers', 'helpers/index.ts')
89
+ return aliases
30
90
  }
31
91
 
32
92
  export function resolveFromApp(
@@ -10,20 +10,20 @@ To add a capability:
10
10
  A plugin's index.ts is TypeScript that Node runs directly (erasable syntax only: no enums, no parameter properties):
11
11
 
12
12
  import type { Context } from '@deepseek-ai/cordis'
13
- import { App } from 'acryl-router'
13
+ import { Acryl } from 'acrylblends'
14
14
  export const name = 'hello' // must equal the folder name
15
15
  export const inject = ['router'] // services it needs; it waits (pending) until they exist
16
16
  export function apply(ctx: Context) {
17
- ctx.router.route('/', new App().get('/hello', (c) => c.json({ text: 'Hello' }))) // removed when the plugin is unloaded
17
+ ctx.router.route('/', new Acryl().get('/hello', (c) => c.json({ text: 'Hello' }))) // removed when the plugin is unloaded
18
18
  }
19
19
  export async function check(ctx: Context) { // optional: must pass, or the install is rolled back
20
20
  const reply = await ctx.router.request('/hello')
21
21
  if (!reply.ok) throw new Error('GET /hello failed')
22
22
  }
23
23
 
24
- The router: build an App (import { App } from 'acryl-router'), register routes on it with app.get/post/put/patch/delete(path, handler) and mount it with
24
+ The router: build an Acryl app (import { Acryl } from 'acrylblends'), register routes on it with app.get/post/put/patch/delete(path, handler) and mount it with
25
25
  ctx.router.route(prefix, app). A path parameter is :id and is read with c.req.param('id'); c.json(body, status) answers JSON, c.text(...) answers text,
26
- await c.req.json() reads a JSON body, throw new HTTPException(404, { message }) (also from 'acryl-router') answers an error. Routes added to an app
26
+ await c.req.json() reads a JSON body, throw new HTTPException(404, { message }) (also from 'acrylblends') answers an error. Routes added to an app
27
27
  after route() are not served: build the whole app first. ctx.router.request('/path', { method: 'POST', body: ... }) calls a route in process (use it in
28
28
  check). The mount goes away when the plugin is unloaded.
29
29
 
@@ -32,6 +32,6 @@ host: it runs in a separate process that can read only its own folder. Files: in
32
32
  { "description": "what it does and its input", "examples": [ { "input": {...}, "output": {...} } ] }
33
33
  The examples are run in the sandbox at install and must match exactly, or the install is refused. Use write_plugin and install_plugin for tools too.
34
34
 
35
- Rules: import only relative files, node: built-ins, @deepseek-ai/cordis and acryl-router. Provide services with ctx.provide(name, value) and
35
+ Rules: import only relative files, node: built-ins, @deepseek-ai/cordis and acrylblends (and its subpaths such as acrylblends/cors, whose docs are in docs/framework). Provide services with ctx.provide(name, value) and
36
36
  use others with ctx.get(name). Put timers, listeners and routes inside ctx.effect(() => cleanup). Use list_plugins and
37
37
  read_plugin to see what exists. When you are done, answer in one or two plain sentences saying what you built.`
@@ -5,26 +5,33 @@ parameter properties). Every part of it is a Cordis plugin.
5
5
 
6
6
  ## The framework's API is in `docs/framework/`
7
7
 
8
- Start at `docs/framework/README.md`; `api-summary.md` is the one-page summary. Read before you write routes: `routing.md` (the `App`), `request.md` (`c.req`), `context.md` (`c`),
9
- `validation.md`, `helpers.md` (`streamSSE`), `middleware.md`, `plugin-lifecycle.md` (what a plugin owns and when it is unloaded) and
10
- `node-server.md`. The framework's source is vendored in `src/plugins/acryl-*/src`: read it, do not edit it (a change belongs in ACRYL, upstream).
11
- The docs write `from 'acryl-router'`; in this app that is `./plugins/acryl-router/src/index.ts` (relative to `src/`), `acryl-router/middleware`
12
- is `./plugins/acryl-router/src/middleware/index.ts` and `acryl-router/helpers` is `./plugins/acryl-router/src/helpers/index.ts`.
13
- A plugin written into `extensions/` while the app runs can import `acryl-router`, `acryl-router/middleware` and `acryl-router/helpers` by those names.
8
+ Start at `docs/framework/README.md`; `api/summary.md` is the one-page summary. Read before you write routes: `api/routing.md` (the `Acryl` app), `api/request.md` (`c.req`),
9
+ `api/context.md` (`c`), `cordis/validation.md` and `guides/validation.md`, `guides/helpers.md` (`streamSSE`), `concepts/middleware.md`, `cordis/plugin-lifecycle.md` (what a plugin
10
+ owns and when it is unloaded), `cordis/mounting.md` and `cordis/node-server.md`. Pages marked "not yet available" describe parts that are not in this app.
11
+
12
+ The docs write `import { Acryl } from 'acrylblends'` and `from 'acrylblends/<subpath>'`. In this app the framework is the vendored plugin source in `src/plugins/acryl-router/src`
13
+ (read it, do not edit it: a change belongs in ACRYL, upstream), so from a file in `src/` import:
14
+
15
+ - `./plugins/acryl-router/src/index.ts` for `Acryl`, `Context`, `HTTPException`, `connectionOf`, `getConnInfo` and the types;
16
+ - `./plugins/acryl-router/src/middleware/index.ts` for every middleware (`cors`, `bodyLimit`, `trimTrailingSlash`, `loopbackOnly`, ...);
17
+ - `./plugins/acryl-router/src/helpers/index.ts` for the helpers and validators (`streamSSE`, `schemaValidator`, `validator`, cookies, `testClient`, ...).
18
+
19
+ A plugin written into `extensions/` while the app runs may use the docs' own names instead: `acrylblends` and `acrylblends/<subpath>` resolve to the same files. `App` is the
20
+ deprecated name of `Acryl`.
14
21
 
15
22
  ## How a feature is built
16
23
 
17
- Routes are an ordinary `App` that a plugin mounts once with `ctx.router.route(prefix, app)`. The mount belongs to the plugin and goes away when it unloads.
24
+ Routes are an ordinary `Acryl` app that a plugin mounts once with `ctx.router.route(prefix, app)`. The mount belongs to the plugin and goes away when it unloads.
18
25
 
19
26
  ```ts
20
27
  import type { Context } from '@deepseek-ai/cordis'
21
- import { App, HTTPException } from './plugins/acryl-router/src/index.ts'
28
+ import { Acryl, HTTPException } from './plugins/acryl-router/src/index.ts'
22
29
  import { schemaValidator, type StandardSchema } from './plugins/acryl-router/src/helpers/index.ts'
23
30
 
24
31
  export const name = 'notes' // a plugin's name; blend.yaml refers to it
25
32
  export const inject = ['router'] // services it needs
26
33
  export function apply(ctx: Context) {
27
- const app = new App()
34
+ const app = new Acryl()
28
35
  .get('/', (c) => c.json({ ok: true }))
29
36
  .get('/:id', (c) => c.json({ id: c.req.param('id') }))
30
37
  .post('/', schemaValidator('json', NewNote), (c) => c.json(c.req.valid('json'), 201)) // NewNote is a Standard Schema
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '@deepseek-ai/cordis'
2
- import { App } from './plugins/acryl-router/src/index.ts'
2
+ import { Acryl } from './plugins/acryl-router/src/index.ts'
3
3
  import { bodyLimit } from './plugins/acryl-router/src/middleware/index.ts'
4
4
  import type {} from './plugins/agent/index.ts'
5
5
  import type {} from './plugins/extensions/index.ts'
@@ -23,7 +23,7 @@ export const routes = {
23
23
  const body = await c.req.json().catch(() => undefined)
24
24
  return typeof body === 'object' && body !== null ? (body as Record<string, unknown>) : {}
25
25
  }
26
- const app = new App()
26
+ const app = new Acryl()
27
27
  .use(bodyLimit({ maxSize: 64 * 1024 }))
28
28
  .get('/', (c) => c.json({ app: APP_NAME, ok: true }))
29
29
  .get('/health', (c) => c.json({ ok: true }))
@@ -10,12 +10,12 @@ import { pinnedInstance, withPort } from '../src/plugins/instance/index.ts'
10
10
 
11
11
  /** A plugin no scripted command knows: the model writes it from scratch. */
12
12
  const COUNTER = `import type { Context } from '@deepseek-ai/cordis'
13
- import { App } from 'acryl-router'
13
+ import { Acryl } from 'acrylblends'
14
14
  export const name = 'counter'
15
15
  export const inject = ['router']
16
16
  export function apply(ctx: Context) {
17
17
  let count = 0
18
- ctx.router.route('/', new App().get('/count', (c) => c.json({ count: ++count })))
18
+ ctx.router.route('/', new Acryl().get('/count', (c) => c.json({ count: ++count })))
19
19
  }
20
20
  `
21
21
 
@@ -13,6 +13,46 @@
13
13
  "skipLibCheck": true,
14
14
  "types": ["node"],
15
15
  "paths": {
16
+ "acrylblends": ["./src/plugins/acryl-router/src/index.ts"],
17
+ "acrylblends/conninfo": ["./src/plugins/acryl-router/src/index.ts"],
18
+ "acrylblends/http-exception": ["./src/plugins/acryl-router/src/index.ts"],
19
+ "acrylblends/types": ["./src/plugins/acryl-router/src/index.ts"],
20
+ "acrylblends/client": ["./src/plugins/acryl-router/src/client.ts"],
21
+ "acrylblends/basic-auth": ["./src/plugins/acryl-router/src/middleware/index.ts"],
22
+ "acrylblends/bearer-auth": ["./src/plugins/acryl-router/src/middleware/index.ts"],
23
+ "acrylblends/body-limit": ["./src/plugins/acryl-router/src/middleware/index.ts"],
24
+ "acrylblends/combine": ["./src/plugins/acryl-router/src/middleware/index.ts"],
25
+ "acrylblends/compress": ["./src/plugins/acryl-router/src/middleware/index.ts"],
26
+ "acrylblends/context-storage": ["./src/plugins/acryl-router/src/middleware/index.ts"],
27
+ "acrylblends/cors": ["./src/plugins/acryl-router/src/middleware/index.ts"],
28
+ "acrylblends/csrf": ["./src/plugins/acryl-router/src/middleware/index.ts"],
29
+ "acrylblends/etag": ["./src/plugins/acryl-router/src/middleware/index.ts"],
30
+ "acrylblends/ip-restriction": ["./src/plugins/acryl-router/src/middleware/index.ts"],
31
+ "acrylblends/jwk": ["./src/plugins/acryl-router/src/middleware/index.ts"],
32
+ "acrylblends/jwt": ["./src/plugins/acryl-router/src/middleware/index.ts"],
33
+ "acrylblends/language": ["./src/plugins/acryl-router/src/middleware/index.ts"],
34
+ "acrylblends/logger": ["./src/plugins/acryl-router/src/middleware/index.ts"],
35
+ "acrylblends/loopback-only": ["./src/plugins/acryl-router/src/middleware/index.ts"],
36
+ "acrylblends/method-not-allowed": ["./src/plugins/acryl-router/src/middleware/index.ts"],
37
+ "acrylblends/method-override": ["./src/plugins/acryl-router/src/middleware/index.ts"],
38
+ "acrylblends/powered-by": ["./src/plugins/acryl-router/src/middleware/index.ts"],
39
+ "acrylblends/pretty-json": ["./src/plugins/acryl-router/src/middleware/index.ts"],
40
+ "acrylblends/request-id": ["./src/plugins/acryl-router/src/middleware/index.ts"],
41
+ "acrylblends/secure-headers": ["./src/plugins/acryl-router/src/middleware/index.ts"],
42
+ "acrylblends/serve-static": ["./src/plugins/acryl-router/src/middleware/index.ts"],
43
+ "acrylblends/timeout": ["./src/plugins/acryl-router/src/middleware/index.ts"],
44
+ "acrylblends/timing": ["./src/plugins/acryl-router/src/middleware/index.ts"],
45
+ "acrylblends/trailing-slash": ["./src/plugins/acryl-router/src/middleware/index.ts"],
46
+ "acrylblends/accepts": ["./src/plugins/acryl-router/src/helpers/index.ts"],
47
+ "acrylblends/cookie": ["./src/plugins/acryl-router/src/helpers/index.ts"],
48
+ "acrylblends/factory": ["./src/plugins/acryl-router/src/helpers/index.ts"],
49
+ "acrylblends/html": ["./src/plugins/acryl-router/src/helpers/index.ts"],
50
+ "acrylblends/route": ["./src/plugins/acryl-router/src/helpers/index.ts"],
51
+ "acrylblends/schema-validator": ["./src/plugins/acryl-router/src/helpers/index.ts"],
52
+ "acrylblends/streaming": ["./src/plugins/acryl-router/src/helpers/index.ts"],
53
+ "acrylblends/testing": ["./src/plugins/acryl-router/src/helpers/index.ts"],
54
+ "acrylblends/validator": ["./src/plugins/acryl-router/src/helpers/index.ts"],
55
+ "acrylblends/ws": ["./src/plugins/acryl-router/src/helpers/index.ts"],
16
56
  "acryl-router": ["./src/plugins/acryl-router/src/index.ts"],
17
57
  "acryl-router/middleware": ["./src/plugins/acryl-router/src/middleware/index.ts"],
18
58
  "acryl-router/helpers": ["./src/plugins/acryl-router/src/helpers/index.ts"]
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '@deepseek-ai/cordis'
2
- import { App } from './plugins/acryl-router/src/index.ts'
2
+ import { Acryl } from './plugins/acryl-router/src/index.ts'
3
3
 
4
4
  export const APP_NAME = '__APP_NAME__'
5
5
 
@@ -8,7 +8,7 @@ export const routes = {
8
8
  name: 'routes',
9
9
  inject: ['router'],
10
10
  apply(ctx: Context) {
11
- const app = new App()
11
+ const app = new Acryl()
12
12
  .get('/', (c) => c.json({ app: APP_NAME, ok: true }))
13
13
  .get('/health', (c) => c.json({ ok: true }))
14
14
  ctx.router.route('/', app)
@@ -6,7 +6,7 @@
6
6
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
7
7
  import { dirname } from 'node:path'
8
8
  import type { Context } from '@deepseek-ai/cordis'
9
- import { App, HTTPException } from './plugins/acryl-router/src/index.ts'
9
+ import { Acryl, HTTPException } from './plugins/acryl-router/src/index.ts'
10
10
  import { bodyLimit, loopbackOnly, trimTrailingSlash } from './plugins/acryl-router/src/middleware/index.ts'
11
11
  import { schemaValidator, streamSSE, type StandardSchema } from './plugins/acryl-router/src/helpers/index.ts'
12
12
  import type {} from './plugins/acryl-state/src/index.ts'
@@ -86,7 +86,7 @@ export function apply(ctx: Context, config: Config = {}): void {
86
86
 
87
87
  // `/todo/` is what people type: trimTrailingSlash answers a GET for an unknown path ending in `/` with a 301 to the path without it,
88
88
  // so the page is found either way while each route keeps one canonical path (the router itself treats `/a` and `/a/` as different).
89
- const api = new App()
89
+ const api = new Acryl()
90
90
  .use(loopbackOnly({ inProcess: 'allow' }), bodyLimit({ maxSize: MAX_BODY_BYTES }), trimTrailingSlash())
91
91
  .get('/', c => c.html(PAGE))
92
92
  .get('/api', c => c.json(todos.get()))