acrylblends 0.6.3 → 0.7.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 (285) hide show
  1. package/README.md +4 -3
  2. package/docs/framework/README.md +2 -2
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/guides/jsx.md +51 -1
  5. package/docs/framework/helpers/ssg.md +3 -6
  6. package/docs/framework/middleware/builtin/jsx-renderer.md +0 -3
  7. package/docs/framework/upstream.json +2 -2
  8. package/lib/accepts.d.ts +1 -1
  9. package/lib/acryl-base.d.ts +1 -1
  10. package/lib/adapter.d.ts +1 -1
  11. package/lib/{app-wFwpg-bt.d.ts → app-D8riatvv.d.ts} +1 -1
  12. package/lib/{base-ddiVmiE7.js → base-NSN_SNv-.js} +1 -0
  13. package/lib/basic-auth.d.ts +1 -1
  14. package/lib/bearer-auth.d.ts +1 -1
  15. package/lib/body-limit.d.ts +1 -1
  16. package/lib/cache.d.ts +1 -1
  17. package/lib/cache.js +4 -4
  18. package/lib/{client-BHTr318g.js → client-DDLXwhBo.js} +2 -125
  19. package/lib/client.d.ts +2 -2
  20. package/lib/client.js +2 -1
  21. package/lib/combine.d.ts +1 -1
  22. package/lib/{components-DYZdxJIJ.js → components-JXVm45kK.js} +1 -1
  23. package/lib/{components-Ce5FRyHU.js → components-cEW3ovK0.js} +3 -3
  24. package/lib/compress.d.ts +1 -1
  25. package/lib/conninfo.d.ts +2 -2
  26. package/lib/{context-DVQBjuns.d.ts → context-DS3fYyG-.d.ts} +1 -1
  27. package/lib/context-storage.d.ts +1 -1
  28. package/lib/cookie.d.ts +1 -1
  29. package/lib/cors.d.ts +1 -1
  30. package/lib/csrf.d.ts +1 -1
  31. package/lib/dev.d.ts +2 -2
  32. package/lib/etag.d.ts +1 -1
  33. package/lib/factory.d.ts +2 -2
  34. package/lib/{hooks-Bq5q9IMl.js → hooks-w72iLeFR.js} +6 -6
  35. package/lib/{index-CUTfU69R.d.ts → index-Bb7YJKCq.d.ts} +2 -2
  36. package/lib/{index-CsvB-F9j.d.ts → index-BvFh1Gfx.d.ts} +1 -1
  37. package/lib/{index-Cqcdluyn.d.ts → index-CTy4N7ng.d.ts} +2 -2
  38. package/lib/index.d.ts +4 -4
  39. package/lib/ip-restriction.d.ts +2 -2
  40. package/lib/jsx/dom/client.js +1 -1
  41. package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
  42. package/lib/jsx/dom/jsx-runtime.js +1 -1
  43. package/lib/jsx/dom/server.js +2 -2
  44. package/lib/jsx/dom.js +4 -4
  45. package/lib/jsx/jsx-dev-runtime.js +1 -1
  46. package/lib/jsx/jsx-runtime.js +1 -1
  47. package/lib/jsx/streaming.js +1 -1
  48. package/lib/{jsx-dev-runtime-kAhR_4C7.js → jsx-dev-runtime-CWLRA2F3.js} +2 -2
  49. package/lib/jsx-renderer.d.ts +75 -0
  50. package/lib/jsx-renderer.js +99 -0
  51. package/lib/jsx.js +4 -4
  52. package/lib/jwk.d.ts +1 -1
  53. package/lib/jwt.d.ts +1 -1
  54. package/lib/language.d.ts +1 -1
  55. package/lib/logger.d.ts +1 -1
  56. package/lib/loopback-only.d.ts +1 -1
  57. package/lib/method-not-allowed.d.ts +2 -2
  58. package/lib/method-override.d.ts +2 -2
  59. package/lib/mount.d.ts +1 -1
  60. package/lib/node-server/conninfo.d.ts +1 -1
  61. package/lib/node-server/register.d.ts +1 -0
  62. package/lib/node-server/register.js +73 -0
  63. package/lib/node-server/serve-static.d.ts +1 -1
  64. package/lib/node-server/serve-static.js +1 -1
  65. package/lib/node-server.d.ts +1 -1
  66. package/lib/node-server.js +1 -1
  67. package/lib/powered-by.d.ts +1 -1
  68. package/lib/pretty-json.d.ts +1 -1
  69. package/lib/quick.d.ts +1 -1
  70. package/lib/request-id.d.ts +1 -1
  71. package/lib/request.d.ts +1 -1
  72. package/lib/route.d.ts +1 -1
  73. package/lib/schema-validator.d.ts +1 -1
  74. package/lib/secure-headers.d.ts +1 -1
  75. package/lib/{serve-static-Cw23shXv.js → serve-static-B14MF1Va.js} +1 -0
  76. package/lib/serve-static.d.ts +1 -1
  77. package/lib/ssg-BwjcA-Ge.js +389 -0
  78. package/lib/ssg.d.ts +156 -0
  79. package/lib/ssg.js +2 -0
  80. package/lib/streaming.d.ts +1 -1
  81. package/lib/testing.d.ts +3 -3
  82. package/lib/testing.js +1 -1
  83. package/lib/timeout.d.ts +1 -1
  84. package/lib/timing.d.ts +1 -1
  85. package/lib/tiny.d.ts +1 -1
  86. package/lib/trailing-slash.d.ts +1 -1
  87. package/lib/{types-nEL8VPDC.d.ts → types-Dv_nV2cv.d.ts} +1 -1
  88. package/lib/{types-CQiGmsWW.d.ts → types-zNxyEpG2.d.ts} +2 -2
  89. package/lib/types.d.ts +1 -1
  90. package/lib/utils/body.d.ts +1 -1
  91. package/lib/utils/ipaddr.d.ts +1 -1
  92. package/lib/utils-Cx61GFMC.js +125 -0
  93. package/lib/validator.d.ts +1 -1
  94. package/lib/ws.d.ts +1 -1
  95. package/package.json +13 -1
  96. package/plugins/acryl-inspect/upstream.json +1 -1
  97. package/plugins/acryl-node-server/src/register.ts +86 -0
  98. package/plugins/acryl-node-server/upstream.json +5 -3
  99. package/plugins/acryl-router/src/core/helper/ssg/index.ts +14 -0
  100. package/plugins/acryl-router/src/core/helper/ssg/middleware.ts +83 -0
  101. package/plugins/acryl-router/src/core/helper/ssg/plugins.ts +72 -0
  102. package/plugins/acryl-router/src/core/helper/ssg/ssg.ts +471 -0
  103. package/plugins/acryl-router/src/core/helper/ssg/utils.ts +118 -0
  104. package/plugins/acryl-router/src/core/jsx/dom/render.ts +6 -6
  105. package/plugins/acryl-router/src/core/middleware/cache/index.ts +4 -4
  106. package/plugins/acryl-router/src/core/middleware/jsx-renderer/index.ts +162 -0
  107. package/plugins/acryl-router/src/helpers/index.ts +1 -0
  108. package/plugins/acryl-router/src/middleware/index.ts +1 -0
  109. package/plugins/acryl-router/upstream.json +2 -2
  110. package/plugins/acryl-router-http/upstream.json +1 -1
  111. package/plugins/acryl-state/upstream.json +1 -1
  112. package/plugins/desktop/main.ts +4 -1
  113. package/plugins/desktop/upstream.json +1 -1
  114. package/plugins/desktop-web/main.ts +3 -1
  115. package/plugins/desktop-web/upstream.json +1 -1
  116. package/plugins/extensions/resolve.ts +4 -0
  117. package/shared/AGENTS.core.md +3 -0
  118. package/templates/agent/package.json +7 -3
  119. package/templates/agent/tsconfig.json +10 -2
  120. package/templates/blank/package.json +7 -3
  121. package/templates/blank/src/about.tsx +14 -0
  122. package/templates/blank/src/routes.ts +2 -0
  123. package/templates/blank/test/app.test.ts +15 -0
  124. package/templates/blank/tsconfig.json +3 -1
  125. package/templates/todo/package.json +7 -3
  126. package/templates/todo/tsconfig.json +3 -1
  127. package/templates/todo/upstream.json +1 -1
  128. package/plugins/acryl-inspect/tests/report.spec.ts +0 -69
  129. package/plugins/acryl-inspect/tests/service.spec.ts +0 -121
  130. package/plugins/acryl-node-server/tests/adapter/app.ts +0 -76
  131. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +0 -1
  132. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  133. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +0 -1
  134. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +0 -1
  135. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +0 -1
  136. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +0 -5
  137. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +0 -1
  138. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  139. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +0 -1
  140. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +0 -1
  141. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +0 -1
  142. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +0 -1
  143. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +0 -1
  144. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +0 -1
  145. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +0 -1
  146. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +0 -1
  147. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +0 -34
  148. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +0 -248
  149. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +0 -457
  150. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +0 -23
  151. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +0 -27
  152. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +0 -252
  153. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +0 -190
  154. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +0 -727
  155. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +0 -189
  156. package/plugins/acryl-node-server/tests/adapter/request.test.ts +0 -1230
  157. package/plugins/acryl-node-server/tests/adapter/response.test.ts +0 -285
  158. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +0 -849
  159. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +0 -790
  160. package/plugins/acryl-node-server/tests/adapter/server.test.ts +0 -1312
  161. package/plugins/acryl-node-server/tests/adapter/setup.ts +0 -16
  162. package/plugins/acryl-node-server/tests/adapter/url.test.ts +0 -76
  163. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +0 -23
  164. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +0 -75
  165. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +0 -235
  166. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +0 -260
  167. package/plugins/acryl-node-server/tests/server.spec.ts +0 -141
  168. package/plugins/acryl-router/src/core/app.test.ts +0 -3833
  169. package/plugins/acryl-router/src/core/client/client.test.ts +0 -2313
  170. package/plugins/acryl-router/src/core/client/types.test.ts +0 -149
  171. package/plugins/acryl-router/src/core/client/utils.test.ts +0 -405
  172. package/plugins/acryl-router/src/core/compose.test.ts +0 -751
  173. package/plugins/acryl-router/src/core/context.test.ts +0 -629
  174. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +0 -344
  175. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +0 -55
  176. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +0 -510
  177. package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +0 -506
  178. package/plugins/acryl-router/src/core/helper/css/index.test.tsx +0 -678
  179. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +0 -181
  180. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +0 -434
  181. package/plugins/acryl-router/src/core/helper/html/index.test.ts +0 -78
  182. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +0 -356
  183. package/plugins/acryl-router/src/core/helper/route/index.test.ts +0 -259
  184. package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +0 -557
  185. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +0 -128
  186. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +0 -34
  187. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +0 -42
  188. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +0 -124
  189. package/plugins/acryl-router/src/core/http-exception.test.ts +0 -45
  190. package/plugins/acryl-router/src/core/jsx/base.test.tsx +0 -97
  191. package/plugins/acryl-router/src/core/jsx/children.test.ts +0 -52
  192. package/plugins/acryl-router/src/core/jsx/components.test.tsx +0 -936
  193. package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +0 -655
  194. package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +0 -128
  195. package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +0 -330
  196. package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +0 -184
  197. package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +0 -149
  198. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +0 -172
  199. package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +0 -3681
  200. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +0 -1344
  201. package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +0 -199
  202. package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +0 -859
  203. package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +0 -40
  204. package/plugins/acryl-router/src/core/jsx/index.test.tsx +0 -1744
  205. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +0 -666
  206. package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +0 -85
  207. package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +0 -1281
  208. package/plugins/acryl-router/src/core/jsx/utils.test.ts +0 -366
  209. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +0 -434
  210. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +0 -1018
  211. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +0 -273
  212. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +0 -1211
  213. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +0 -355
  214. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +0 -535
  215. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +0 -43
  216. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +0 -532
  217. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +0 -534
  218. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +0 -21
  219. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +0 -503
  220. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +0 -217
  221. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +0 -1135
  222. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +0 -48
  223. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +0 -802
  224. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +0 -552
  225. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +0 -204
  226. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +0 -292
  227. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +0 -221
  228. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +0 -334
  229. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +0 -37
  230. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +0 -218
  231. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +0 -168
  232. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +0 -671
  233. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +0 -450
  234. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +0 -50
  235. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +0 -70
  236. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +0 -310
  237. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +0 -381
  238. package/plugins/acryl-router/src/core/preset/quick.test.ts +0 -42
  239. package/plugins/acryl-router/src/core/preset/tiny.test.ts +0 -42
  240. package/plugins/acryl-router/src/core/request.test.ts +0 -751
  241. package/plugins/acryl-router/src/core/router/common.case.test.ts +0 -1132
  242. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +0 -80
  243. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +0 -46
  244. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +0 -154
  245. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +0 -265
  246. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +0 -13
  247. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +0 -896
  248. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +0 -8
  249. package/plugins/acryl-router/src/core/types.test.ts +0 -4134
  250. package/plugins/acryl-router/src/core/utils/accept.test.ts +0 -299
  251. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +0 -56
  252. package/plugins/acryl-router/src/core/utils/body.test.ts +0 -496
  253. package/plugins/acryl-router/src/core/utils/buffer.test.ts +0 -147
  254. package/plugins/acryl-router/src/core/utils/color.test.ts +0 -23
  255. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +0 -69
  256. package/plugins/acryl-router/src/core/utils/cookie.test.ts +0 -460
  257. package/plugins/acryl-router/src/core/utils/crypto.test.ts +0 -43
  258. package/plugins/acryl-router/src/core/utils/encode.test.ts +0 -61
  259. package/plugins/acryl-router/src/core/utils/filepath.test.ts +0 -78
  260. package/plugins/acryl-router/src/core/utils/html.test.ts +0 -16
  261. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +0 -149
  262. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +0 -86
  263. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +0 -1788
  264. package/plugins/acryl-router/src/core/utils/mime.test.ts +0 -64
  265. package/plugins/acryl-router/src/core/utils/stream.test.ts +0 -212
  266. package/plugins/acryl-router/src/core/utils/types.test.ts +0 -295
  267. package/plugins/acryl-router/src/core/utils/url.test.ts +0 -384
  268. package/plugins/acryl-router/src/core/validator/utils.test.ts +0 -82
  269. package/plugins/acryl-router/src/core/validator/validator.test.ts +0 -1488
  270. package/plugins/acryl-router/tests/docs-examples.spec.ts +0 -152
  271. package/plugins/acryl-router/tests/jsx.spec.tsx +0 -63
  272. package/plugins/acryl-router/tests/live-install.spec.ts +0 -64
  273. package/plugins/acryl-router/tests/loader.spec.ts +0 -72
  274. package/plugins/acryl-router/tests/loopback-only.spec.ts +0 -80
  275. package/plugins/acryl-router/tests/no-dom/consumer.ts +0 -11
  276. package/plugins/acryl-router/tests/no-dom/tsconfig.json +0 -13
  277. package/plugins/acryl-router/tests/service.spec.ts +0 -426
  278. package/plugins/acryl-router/tests/shadow-state.spec.ts +0 -79
  279. package/plugins/acryl-router-http/tests/adapter.spec.ts +0 -174
  280. package/plugins/acryl-router-http/tests/stream.spec.ts +0 -133
  281. package/plugins/acryl-router-http/tests/surfaces.spec.ts +0 -101
  282. package/plugins/acryl-state/src/react.ts +0 -11
  283. package/plugins/acryl-state/tests/cell.spec.ts +0 -71
  284. package/plugins/acryl-state/tests/react.spec.ts +0 -39
  285. package/plugins/acryl-state/tests/service.spec.ts +0 -132
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @module
3
+ * JSX Renderer Middleware for Acryl.
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ import type { Context, PropsForRenderer } from '../../context.ts'
8
+ import { html, raw } from '../../helper/html/index.ts'
9
+ import { Fragment, createContext, jsx, useContext } from '../../jsx/index.ts'
10
+ import type { FC, Context as JSXContext, JSXNode, PropsWithChildren } from '../../jsx/index.ts'
11
+ import { renderToReadableStream } from '../../jsx/streaming.ts'
12
+ import type { Env, Input, MiddlewareHandler } from '../../types.ts'
13
+
14
+ export const RequestContext: JSXContext<Context<any, any, {}> | null> =
15
+ createContext<Context | null>(null)
16
+
17
+ type RendererOptions = {
18
+ docType?: boolean | string
19
+ stream?: boolean | Record<string, string>
20
+ }
21
+
22
+ type ComponentResult = Exclude<ReturnType<FC>, null>
23
+
24
+ type Component = (props: PropsForRenderer & { Layout: FC }, c: Context) => ComponentResult
25
+
26
+ type ComponentWithChildren = (
27
+ props: PropsWithChildren<PropsForRenderer & { Layout: FC }>,
28
+ c: Context
29
+ ) => ComponentResult
30
+
31
+ const createRenderer =
32
+ (
33
+ c: Context,
34
+ Layout: FC,
35
+ component?: Component,
36
+ options?: RendererOptions | ((c: Context) => RendererOptions)
37
+ ) =>
38
+ (children: JSXNode, props: PropsForRenderer) => {
39
+ options = typeof options === 'function' ? options(c) : options
40
+ const docType =
41
+ typeof options?.docType === 'string'
42
+ ? options.docType
43
+ : options?.docType === false
44
+ ? ''
45
+ : '<!DOCTYPE html>'
46
+
47
+ const currentLayout = component
48
+ ? jsx(
49
+ (props: any) => component(props, c),
50
+ {
51
+ Layout,
52
+ ...(props as any),
53
+ },
54
+ children as any
55
+ )
56
+ : children
57
+
58
+ const body = html`${raw(docType)}${jsx(
59
+ RequestContext.Provider,
60
+ { value: c },
61
+ currentLayout as any
62
+ )}`
63
+
64
+ if (options?.stream) {
65
+ if (options.stream === true) {
66
+ c.header('Transfer-Encoding', 'chunked')
67
+ c.header('Content-Type', 'text/html; charset=UTF-8')
68
+ c.header('Content-Encoding', 'Identity')
69
+ } else {
70
+ for (const [key, value] of Object.entries(options.stream)) {
71
+ c.header(key, value)
72
+ }
73
+ }
74
+ return c.body(renderToReadableStream(body))
75
+ } else {
76
+ return c.html(body)
77
+ }
78
+ }
79
+
80
+ /**
81
+ * JSX Renderer Middleware for acryl.
82
+ *
83
+ *
84
+ * @param {ComponentWithChildren} [component] - The component to render, which can accept children and props.
85
+ * @param {RendererOptions} [options] - The options for the JSX renderer middleware.
86
+ * @param {boolean | string} [options.docType=true] - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.
87
+ * @param {boolean | Record<string, string>} [options.stream=false] - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.
88
+ * @returns {MiddlewareHandler} The middleware handler function.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const app = new Acryl()
93
+ *
94
+ * app.get(
95
+ * '/page/*',
96
+ * jsxRenderer(({ children }) => {
97
+ * return (
98
+ * <html>
99
+ * <body>
100
+ * <header>Menu</header>
101
+ * <div>{children}</div>
102
+ * </body>
103
+ * </html>
104
+ * )
105
+ * })
106
+ * )
107
+ *
108
+ * app.get('/page/about', (c) => {
109
+ * return c.render(<h1>About me!</h1>)
110
+ * })
111
+ * ```
112
+ */
113
+ export const jsxRenderer = <E extends Env = Env>(
114
+ component?: ComponentWithChildren,
115
+ options?: RendererOptions | ((c: Context<E>) => RendererOptions)
116
+ ): MiddlewareHandler =>
117
+ function jsxRenderer(c, next) {
118
+ const Layout = (c.getLayout() ?? Fragment) as FC
119
+ if (component) {
120
+ c.setLayout((props) => {
121
+ return component({ ...props, Layout }, c)
122
+ })
123
+ }
124
+ c.setRenderer(createRenderer(c, Layout, component, options) as any)
125
+ return next()
126
+ }
127
+
128
+ /**
129
+ * useRequestContext for Acryl.
130
+ *
131
+ * @template E - The environment type.
132
+ * @template P - The parameter type.
133
+ * @template I - The input type.
134
+ * @returns {Context<E, P, I>} An instance of Context.
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * const RequestUrlBadge: FC = () => {
139
+ * const c = useRequestContext()
140
+ * return <b>{c.req.url}</b>
141
+ * }
142
+ *
143
+ * app.get('/page/info', (c) => {
144
+ * return c.render(
145
+ * <div>
146
+ * You are accessing: <RequestUrlBadge />
147
+ * </div>
148
+ * )
149
+ * })
150
+ * ```
151
+ */
152
+ export const useRequestContext = <
153
+ E extends Env = any,
154
+ P extends string = any,
155
+ I extends Input = {},
156
+ >(): Context<E, P, I> => {
157
+ const c = useContext(RequestContext)
158
+ if (!c) {
159
+ throw new Error('RequestContext is not provided.')
160
+ }
161
+ return c
162
+ }
@@ -10,6 +10,7 @@ export { proxy } from '../core/helper/proxy/index.ts'
10
10
  export { getRouterName, inspectRoutes, showRoutes } from '../core/helper/dev/index.ts'
11
11
  export { matchedRoutes, routePath, baseRoutePath, basePath } from '../core/helper/route/index.ts'
12
12
  export { testClient } from '../core/helper/testing/index.ts'
13
+ export { defaultPlugin, disableSSG, isSSGContext, onlySSG, redirectPlugin, ssgParams, toSSG, X_ACRYL_DISABLE_SSG_HEADER_KEY, type SSGPlugin, type ToSSGOptions } from '../core/helper/ssg/index.ts'
13
14
  export { stream, streamSSE, streamText, SSEStreamingApi, type SSEMessage } from '../core/helper/streaming/index.ts'
14
15
  export { validator, type ValidationFunction } from '../core/validator/index.ts'
15
16
  export { schemaValidator, type StandardSchema } from './schema-validator.ts'
@@ -8,6 +8,7 @@ export { contextStorage, getContext, tryGetContext } from '../core/middleware/co
8
8
  export { cors } from '../core/middleware/cors/index.ts'
9
9
  export { csrf } from '../core/middleware/csrf/index.ts'
10
10
  export { etag } from '../core/middleware/etag/index.ts'
11
+ export { jsxRenderer, RequestContext, useRequestContext } from '../core/middleware/jsx-renderer/index.ts'
11
12
  export { jwk } from '../core/middleware/jwk/index.ts'
12
13
  export { AlgorithmTypes, decode, jwt, sign, verify, verifyWithJwks, type JwtVariables } from '../core/middleware/jwt/index.ts'
13
14
  export { ipRestriction, type IPRestrictionRule, type IPRestrictionRules } from '../core/middleware/ip-restriction/index.ts'
@@ -2,7 +2,7 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-router",
5
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
5
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -10,7 +10,7 @@
10
10
  "LICENSE"
11
11
  ],
12
12
  "rewrittenSpecifiers": 6,
13
- "digest": "sha256:141895acbc03bfea20b4142356a0614361f83a0beca0a989ae141b5f877f399d",
13
+ "digest": "sha256:dde4e173c7004c7aadd3d96866e65b29230c31562a4fab9e186fd4499821282b",
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
  },
@@ -2,7 +2,7 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-router-http",
5
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
5
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -2,7 +2,7 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-state",
5
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
5
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -10,7 +10,8 @@ import { mkdirSync, readFileSync } from 'node:fs'
10
10
  import { join } from 'node:path'
11
11
  import { fileURLToPath } from 'node:url'
12
12
  import { app, BrowserWindow, shell } from 'electron'
13
- import { type App, createApp } from '../../app.ts'
13
+ import type { App } from '../../app.ts'
14
+ import '../acryl-node-server/src/register.ts'
14
15
  import { selectInstance } from '../instance/index.ts'
15
16
  import { createDesktopShutdown, installShutdownRequests } from './shutdown.ts'
16
17
  import { resolveDesktopUserDataOverride } from './user-data.ts'
@@ -63,6 +64,8 @@ if (!app.requestSingleInstanceLock()) {
63
64
  })
64
65
 
65
66
  void app.whenReady().then(async () => {
67
+ // The hook above is registered before the app's modules are loaded, so the app may have .tsx pages: they are loaded here, not as a static import.
68
+ const { createApp } = await import('../../app.ts')
66
69
  running = await createApp(chosen)
67
70
  const origin = new URL(running.url).origin
68
71
  window = new BrowserWindow(windowOptions({ title: chosen.name }))
@@ -5,7 +5,7 @@
5
5
  "apps/acryl-desktop/src/shell/desktop-user-data.ts": "user-data.ts",
6
6
  "apps/acryl-desktop/src/shell/shutdown.ts": "shutdown.ts"
7
7
  },
8
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
8
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
9
9
  },
10
10
  "rewrittenSpecifiers": 0,
11
11
  "digest": "sha256:7dfe960a8bbb476c35540d2202a7aaa62b33492c2ac3e34314e2ecfca45f32f2"
@@ -12,7 +12,7 @@ import { join } from 'node:path'
12
12
  import { fileURLToPath } from 'node:url'
13
13
  import { serve } from 'acrylblends/node-server'
14
14
  import { app, BrowserWindow, shell } from 'electron'
15
- import acrylApp from '../../app.ts'
15
+ import 'acrylblends/node-server/register'
16
16
  import { createDesktopShutdown, installShutdownRequests } from './shutdown.ts'
17
17
  import { resolveDesktopUserDataOverride } from './user-data.ts'
18
18
  import { windowOptions } from './window.ts'
@@ -66,6 +66,8 @@ if (!app.requestSingleInstanceLock()) {
66
66
  })
67
67
 
68
68
  void app.whenReady().then(async () => {
69
+ // The hook above is registered before the app's modules are loaded, so the app may have .tsx pages: they are loaded here, not as a static import.
70
+ const { default: acrylApp } = await import('../../app.ts')
69
71
  const port = await new Promise<number>((resolve) => {
70
72
  server = serve(
71
73
  { fetch: acrylApp.fetch, port: 0, hostname: '127.0.0.1' },
@@ -5,7 +5,7 @@
5
5
  "apps/acryl-desktop/src/shell/desktop-user-data.ts": "user-data.ts",
6
6
  "apps/acryl-desktop/src/shell/shutdown.ts": "shutdown.ts"
7
7
  },
8
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
8
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
9
9
  },
10
10
  "rewrittenSpecifiers": 0,
11
11
  "digest": "sha256:7dfe960a8bbb476c35540d2202a7aaa62b33492c2ac3e34314e2ecfca45f32f2"
@@ -68,6 +68,10 @@ export function frameworkSpecifiers(): Record<string, string> {
68
68
  'http-exception': 'index.ts',
69
69
  types: 'index.ts',
70
70
  client: 'client.ts',
71
+ jsx: 'core/jsx/index.ts',
72
+ 'jsx/jsx-runtime': 'core/jsx/jsx-runtime.ts',
73
+ 'jsx/jsx-dev-runtime': 'core/jsx/jsx-dev-runtime.ts',
74
+ 'jsx/streaming': 'core/jsx/streaming.ts',
71
75
  }
72
76
  for (const name of MIDDLEWARE) map[name] = 'middleware/index.ts'
73
77
  for (const name of HELPERS) map[name] = 'helpers/index.ts'
@@ -15,6 +15,9 @@ The docs write `import { Acryl } from 'acrylblends'` and `from 'acrylblends/<sub
15
15
  - `./plugins/acryl-router/src/index.ts` for `Acryl`, `Context`, `HTTPException`, `connectionOf`, `getConnInfo` and the types;
16
16
  - `./plugins/acryl-router/src/middleware/index.ts` for every middleware (`cors`, `bodyLimit`, `trimTrailingSlash`, `loopbackOnly`, ...);
17
17
  - `./plugins/acryl-router/src/helpers/index.ts` for the helpers and validators (`streamSSE`, `schemaValidator`, `validator`, cookies, `testClient`, ...).
18
+ - `./plugins/acryl-router/src/core/jsx/index.ts` for `acrylblends/jsx` (`jsx`, `Fragment`, the types), and `.../core/jsx/streaming.ts` for `acrylblends/jsx/streaming`.
19
+
20
+ **JSX: write `.tsx`.** The scripts in `package.json` run Node.js with `--import ./src/plugins/acryl-node-server/src/register.ts`, which compiles `.tsx` files with this app's own `typescript`; `tsconfig.json` sets `jsx: react-jsx` and `jsxImportSource: #acryl-jsx`, which `package.json`'s `imports` maps to the vendored runtime in `src/plugins/acryl-router`. See `src/about.tsx` (blank template) for a page and `test/app.test.ts` for how it is tested. Render a component with `.toString()` and return it with `c.html(...)`; import `jsx`, `Fragment` and the types from `./plugins/acryl-router/src/core/jsx/index.ts` when you need them. A command that starts the app without those scripts (a bare `node src/main.ts`) cannot load a `.tsx` file. Without a build step you can write the call JSX compiles to instead: `jsx('h1', { class: 'title' }, 'Hello')`, children after the props.
18
21
 
19
22
  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
23
  deprecated name of `Acryl`.
@@ -3,13 +3,17 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
+ "imports": {
7
+ "#acryl-jsx/jsx-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-runtime.ts",
8
+ "#acryl-jsx/jsx-dev-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts"
9
+ },
6
10
  "engines": {
7
11
  "node": ">=22.19.0"
8
12
  },
9
13
  "scripts": {
10
- "start": "node src/main.ts",
11
- "dev": "node --watch src/main.ts",
12
- "test": "node --test",
14
+ "start": "node --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
15
+ "dev": "node --watch --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
16
+ "test": "node --import ./src/plugins/acryl-node-server/src/register.ts --test \"test/**/*.test.{ts,tsx}\"",
13
17
  "check": "tsc --noEmit",
14
18
  "lock": "node src/plugins/manifest/lock.ts",
15
19
  "save": "node src/plugins/save/cli.ts",
@@ -55,8 +55,16 @@
55
55
  "acrylblends/ws": ["./src/plugins/acryl-router/src/helpers/index.ts"],
56
56
  "acryl-router": ["./src/plugins/acryl-router/src/index.ts"],
57
57
  "acryl-router/middleware": ["./src/plugins/acryl-router/src/middleware/index.ts"],
58
- "acryl-router/helpers": ["./src/plugins/acryl-router/src/helpers/index.ts"]
59
- }
58
+ "acryl-router/helpers": ["./src/plugins/acryl-router/src/helpers/index.ts"],
59
+ "acrylblends/jsx": ["./src/plugins/acryl-router/src/core/jsx/index.ts"],
60
+ "acrylblends/jsx/jsx-runtime": ["./src/plugins/acryl-router/src/core/jsx/jsx-runtime.ts"],
61
+ "acrylblends/jsx/jsx-dev-runtime": [
62
+ "./src/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts"
63
+ ],
64
+ "acrylblends/jsx/streaming": ["./src/plugins/acryl-router/src/core/jsx/streaming.ts"]
65
+ },
66
+ "jsx": "react-jsx",
67
+ "jsxImportSource": "#acryl-jsx"
60
68
  },
61
69
  "include": ["src", "test", "extensions"]
62
70
  }
@@ -3,13 +3,17 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
+ "imports": {
7
+ "#acryl-jsx/jsx-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-runtime.ts",
8
+ "#acryl-jsx/jsx-dev-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts"
9
+ },
6
10
  "engines": {
7
11
  "node": ">=22.19.0"
8
12
  },
9
13
  "scripts": {
10
- "start": "node src/main.ts",
11
- "dev": "node --watch src/main.ts",
12
- "test": "node --test",
14
+ "start": "node --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
15
+ "dev": "node --watch --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
16
+ "test": "node --import ./src/plugins/acryl-node-server/src/register.ts --test \"test/**/*.test.{ts,tsx}\"",
13
17
  "check": "tsc --noEmit",
14
18
  "lock": "node src/plugins/manifest/lock.ts",
15
19
  "save": "node src/plugins/save/cli.ts",
@@ -0,0 +1,14 @@
1
+ /** A page written in JSX: the scripts in package.json run Node.js with the vendored register hook (src/plugins/acryl-node-server/src/register.ts), which compiles .tsx with this app's own typescript. */
2
+ const About = () => (
3
+ <main>
4
+ <h1>About</h1>
5
+ <p>Rendered on the server with the JSX runtime in src/plugins/acryl-router.</p>
6
+ </main>
7
+ )
8
+
9
+ export const aboutPage = (): string => (<About />).toString()
10
+
11
+ /** Throws on purpose: the template's test checks that the stack names this file, so a failure in your own pages points at the .tsx line. */
12
+ export const failingPage = (): string => {
13
+ throw new Error('a page failed')
14
+ }
@@ -1,4 +1,5 @@
1
1
  import type { Context } from '@deepseek-ai/cordis'
2
+ import { aboutPage } from './about.tsx'
2
3
  import { Acryl } from './plugins/acryl-router/src/index.ts'
3
4
 
4
5
  export const APP_NAME = '__APP_NAME__'
@@ -11,6 +12,7 @@ export const routes = {
11
12
  const app = new Acryl()
12
13
  .get('/', (c) => c.json({ app: APP_NAME, ok: true }))
13
14
  .get('/health', (c) => c.json({ ok: true }))
15
+ .get('/about', (c) => c.html(aboutPage()))
14
16
  ctx.router.route('/', app)
15
17
  },
16
18
  }
@@ -29,6 +29,21 @@ test('serves the index route', () =>
29
29
  assert.deepEqual(await response.json(), { app: APP_NAME, ok: true })
30
30
  }))
31
31
 
32
+ test('renders a .tsx page, and an error in it names the .tsx line', () =>
33
+ withApp(async (app) => {
34
+ const response = await fetch(`${app.url}/about`)
35
+ assert.equal(response.status, 200)
36
+ assert.match(await response.text(), /<main><h1>About<\/h1>/)
37
+ const { failingPage } = await import('../src/about.tsx')
38
+ let stack = ''
39
+ try {
40
+ failingPage()
41
+ } catch (error) {
42
+ stack = String((error as Error).stack)
43
+ }
44
+ assert.match(stack, /about\.tsx:\d+/)
45
+ }))
46
+
32
47
  test('answers health checks and 404 for unknown paths', () =>
33
48
  withApp(async (app) => {
34
49
  assert.equal((await fetch(`${app.url}/health`)).status, 200)
@@ -11,7 +11,9 @@
11
11
  "allowImportingTsExtensions": true,
12
12
  "noEmit": true,
13
13
  "skipLibCheck": true,
14
- "types": ["node"]
14
+ "types": ["node"],
15
+ "jsx": "react-jsx",
16
+ "jsxImportSource": "#acryl-jsx"
15
17
  },
16
18
  "include": ["src", "test"]
17
19
  }
@@ -3,13 +3,17 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
+ "imports": {
7
+ "#acryl-jsx/jsx-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-runtime.ts",
8
+ "#acryl-jsx/jsx-dev-runtime": "./src/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts"
9
+ },
6
10
  "engines": {
7
11
  "node": ">=22.19.0"
8
12
  },
9
13
  "scripts": {
10
- "start": "node src/main.ts",
11
- "dev": "node --watch src/main.ts",
12
- "test": "node --test",
14
+ "start": "node --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
15
+ "dev": "node --watch --import ./src/plugins/acryl-node-server/src/register.ts src/main.ts",
16
+ "test": "node --import ./src/plugins/acryl-node-server/src/register.ts --test \"test/**/*.test.{ts,tsx}\"",
13
17
  "check": "tsc --noEmit",
14
18
  "lock": "node src/plugins/manifest/lock.ts",
15
19
  "save": "node src/plugins/save/cli.ts",
@@ -11,7 +11,9 @@
11
11
  "allowImportingTsExtensions": true,
12
12
  "noEmit": true,
13
13
  "skipLibCheck": true,
14
- "types": ["node"]
14
+ "types": ["node"],
15
+ "jsx": "react-jsx",
16
+ "jsxImportSource": "#acryl-jsx"
15
17
  },
16
18
  "include": ["src", "test"]
17
19
  }
@@ -5,7 +5,7 @@
5
5
  "examples/acryl-todo/src/index.ts": "src/todo.ts",
6
6
  "examples/acryl-todo/src/page.ts": "src/page.ts"
7
7
  },
8
- "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
8
+ "commit": "7bba3ed0420d87e61d8256fa60614d22af734c8f"
9
9
  },
10
10
  "rewrittenSpecifiers": 4,
11
11
  "digest": "sha256:9093704776563001f7f472f94cc5c2fdd79206342c1cb59c11fce62aa74df3ed"
@@ -1,69 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { explain, renderReports, reportFiber, stateName, type FiberView } from '../src/report.ts'
3
-
4
- function fiber(over: Partial<FiberView> & { effects?: FiberView['getEffects'] extends () => infer R ? R : never } = {}): FiberView {
5
- const { effects = [], ...rest } = over
6
- return { state: 2, inject: {}, runtime: { name: 'demo' }, getEffects: () => effects, ...rest }
7
- }
8
-
9
- describe('reportFiber', () => {
10
- it('sorts effects into provides, mounts with their routes, and everything else, including nested ones', () => {
11
- const report = reportFiber(fiber({
12
- inject: { router: null, acrylSettings: null },
13
- effects: [
14
- { label: 'ctx.provide("things")', children: [] },
15
- { label: 'acryl-router: route /api', children: [
16
- { label: 'acryl-router: serves ALL /api/*', children: [] },
17
- { label: 'acryl-router: serves GET /api/things/:id', children: [] },
18
- ] },
19
- { label: 'acryl-router: route /api/things', children: [
20
- { label: 'acryl-router: serves POST /api/things', children: [] },
21
- { label: 'inner timer', children: [] },
22
- ] },
23
- { label: 'ctx.on("internal/status")', children: [] },
24
- ],
25
- }))
26
- expect(report).toEqual({
27
- name: 'demo',
28
- state: 'ACTIVE',
29
- requires: ['acrylSettings', 'router'],
30
- provides: ['things'],
31
- mounts: ['/api', '/api/things'],
32
- routes: [{ method: 'ALL', path: '/api/*' }, { method: 'GET', path: '/api/things/:id' }, { method: 'POST', path: '/api/things' }],
33
- other: ['inner timer', 'ctx.on("internal/status")'],
34
- removedOnUnload: 5,
35
- })
36
- })
37
-
38
- it('names the state and an anonymous plugin', () => {
39
- expect(stateName(0)).toBe('PENDING')
40
- expect(stateName(2)).toBe('ACTIVE')
41
- expect(stateName(5)).toBe('UNLOADING')
42
- expect(reportFiber(fiber({ runtime: null })).name).toBe('anonymous')
43
- })
44
- })
45
-
46
- describe('explain', () => {
47
- it('says what a plugin needs, adds and removes on unload', () => {
48
- const text = explain(reportFiber(fiber({
49
- inject: { router: null },
50
- effects: [{ label: 'acryl-router: route /', children: [{ label: 'acryl-router: serves GET /a', children: [] }] }],
51
- })))
52
- expect(text).toContain('demo (ACTIVE)')
53
- expect(text).toContain('needs: router')
54
- expect(text).toContain('routes: GET /a')
55
- expect(text).toContain('unloading: removes 1 registration and nothing else')
56
- })
57
-
58
- it('says a pending plugin is waiting for its services', () => {
59
- const text = explain(reportFiber(fiber({ state: 0, inject: { router: null, webServer: null } })))
60
- expect(text).toContain('demo (PENDING)')
61
- expect(text).toContain('it starts when router, webServer are available')
62
- })
63
-
64
- it('renders several plugins as blocks', () => {
65
- const a = reportFiber(fiber({ runtime: { name: 'a' } }))
66
- const b = reportFiber(fiber({ runtime: { name: 'b' } }))
67
- expect(renderReports([a, b]).split('\n\n')).toHaveLength(2)
68
- })
69
- })