acrylblends 0.6.1 → 0.6.3

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 (217) hide show
  1. package/README.md +11 -6
  2. package/docs/framework/README.md +3 -2
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/api/presets.md +0 -3
  5. package/docs/framework/cordis/acryl-in-a-cordis-app.md +9 -0
  6. package/docs/framework/getting-started/basic.md +5 -4
  7. package/docs/framework/getting-started/desktop.md +41 -0
  8. package/docs/framework/guides/jsx-dom.md +0 -3
  9. package/docs/framework/guides/jsx.md +1 -4
  10. package/docs/framework/guides/middleware.md +1 -1
  11. package/docs/framework/helpers/cookie.md +1 -1
  12. package/docs/framework/helpers/css.md +0 -3
  13. package/docs/framework/helpers/dev.md +0 -3
  14. package/docs/framework/helpers/jwt.md +1 -1
  15. package/docs/framework/helpers/proxy.md +0 -3
  16. package/docs/framework/middleware/builtin/basic-auth.md +6 -6
  17. package/docs/framework/middleware/builtin/cache.md +0 -3
  18. package/docs/framework/middleware/builtin/combine.md +1 -1
  19. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  20. package/docs/framework/middleware/builtin/logger.md +1 -1
  21. package/docs/framework/middleware/builtin/mount.md +0 -3
  22. package/docs/framework/upstream.json +3 -3
  23. package/lib/accepts.d.ts +1 -1
  24. package/lib/acryl-base.d.ts +1 -1
  25. package/lib/adapter.d.ts +1 -1
  26. package/lib/{app-CmAYW1Al.d.ts → app-wFwpg-bt.d.ts} +1 -1
  27. package/lib/base-BpQy2Rk7.d.ts +783 -0
  28. package/lib/base-ddiVmiE7.js +721 -0
  29. package/lib/basic-auth.d.ts +1 -1
  30. package/lib/bearer-auth.d.ts +1 -1
  31. package/lib/body-limit.d.ts +1 -1
  32. package/lib/cache.d.ts +43 -0
  33. package/lib/cache.js +169 -0
  34. package/lib/client.d.ts +2 -2
  35. package/lib/combine.d.ts +1 -1
  36. package/lib/common-D8Z4JRCw.d.ts +46 -0
  37. package/lib/components-Ce5FRyHU.js +268 -0
  38. package/lib/components-DYZdxJIJ.js +24 -0
  39. package/lib/compress.d.ts +1 -1
  40. package/lib/conninfo.d.ts +2 -2
  41. package/lib/constants-BR9jM9BC.js +9 -0
  42. package/lib/{context-Bm7rI-oK.d.ts → context-DVQBjuns.d.ts} +1 -1
  43. package/lib/context-DxFdY_un.d.ts +250 -0
  44. package/lib/context-storage.d.ts +1 -1
  45. package/lib/{cookie-ClMaKDQf.d.ts → cookie-CCelEqky.d.ts} +1 -1
  46. package/lib/cookie.d.ts +3 -3
  47. package/lib/cors.d.ts +1 -1
  48. package/lib/csrf.d.ts +1 -1
  49. package/lib/css-D2jb7X8b.js +320 -0
  50. package/lib/css.d.ts +82 -0
  51. package/lib/css.js +134 -0
  52. package/lib/dev.d.ts +19 -0
  53. package/lib/dev.js +50 -0
  54. package/lib/etag.d.ts +1 -1
  55. package/lib/factory.d.ts +2 -2
  56. package/lib/hooks-Bq5q9IMl.js +762 -0
  57. package/lib/html-SllAe0YT.d.ts +46 -0
  58. package/lib/html.d.ts +1 -1
  59. package/lib/index-C850MeBA.d.ts +94 -0
  60. package/lib/{index-oOClm_Xk.d.ts → index-CUTfU69R.d.ts} +3 -3
  61. package/lib/{index-B-3F4wt2.d.ts → index-Cqcdluyn.d.ts} +2 -2
  62. package/lib/{index-UTBmM3GX.d.ts → index-CsvB-F9j.d.ts} +2 -2
  63. package/lib/index.d.ts +4 -4
  64. package/lib/ip-restriction.d.ts +2 -2
  65. package/lib/jsx/dom/client.d.ts +30 -0
  66. package/lib/jsx/dom/client.js +49 -0
  67. package/lib/jsx/dom/css.d.ts +84 -0
  68. package/lib/jsx/dom/css.js +2 -0
  69. package/lib/jsx/dom/jsx-dev-runtime.d.ts +3 -0
  70. package/lib/jsx/dom/jsx-dev-runtime.js +2 -0
  71. package/lib/jsx/dom/jsx-runtime.d.ts +3 -0
  72. package/lib/jsx/dom/jsx-runtime.js +2 -0
  73. package/lib/jsx/dom/server.d.ts +105 -0
  74. package/lib/jsx/dom/server.js +37 -0
  75. package/lib/jsx/dom.d.ts +5 -0
  76. package/lib/jsx/dom.js +74 -0
  77. package/lib/jsx/jsx-dev-runtime.d.ts +6 -0
  78. package/lib/jsx/jsx-dev-runtime.js +14 -0
  79. package/lib/jsx/jsx-runtime.d.ts +10 -0
  80. package/lib/jsx/jsx-runtime.js +30 -0
  81. package/lib/jsx/streaming.d.ts +2 -0
  82. package/lib/jsx/streaming.js +2 -0
  83. package/lib/jsx-dev-runtime-B22O-Npk.d.ts +7 -0
  84. package/lib/jsx-dev-runtime-kAhR_4C7.js +354 -0
  85. package/lib/jsx-runtime-BVVgDSdq.d.ts +1 -0
  86. package/lib/jsx.d.ts +3 -0
  87. package/lib/jsx.js +47 -0
  88. package/lib/jwk.d.ts +4 -4
  89. package/lib/{jwt-Dg493Tai.d.ts → jwt-BARhotDz.d.ts} +1 -1
  90. package/lib/jwt.d.ts +4 -4
  91. package/lib/language.d.ts +1 -1
  92. package/lib/linear-router-C3FPib6h.js +96 -0
  93. package/lib/logger.d.ts +1 -1
  94. package/lib/loopback-only.d.ts +1 -1
  95. package/lib/method-not-allowed.d.ts +2 -2
  96. package/lib/method-override.d.ts +2 -2
  97. package/lib/mount.d.ts +44 -0
  98. package/lib/mount.js +67 -0
  99. package/lib/node-server/conninfo.d.ts +1 -1
  100. package/lib/node-server/serve-static.d.ts +1 -1
  101. package/lib/node-server/serve-static.js +1 -1
  102. package/lib/node-server.d.ts +1 -1
  103. package/lib/node-server.js +1 -1
  104. package/lib/pattern-router-HZxjDGEQ.js +41 -0
  105. package/lib/powered-by.d.ts +1 -1
  106. package/lib/pretty-json.d.ts +1 -1
  107. package/lib/proxy.d.ts +72 -0
  108. package/lib/proxy.js +121 -0
  109. package/lib/quick.d.ts +8 -0
  110. package/lib/quick.js +17 -0
  111. package/lib/request-id.d.ts +1 -1
  112. package/lib/request.d.ts +1 -1
  113. package/lib/route.d.ts +1 -1
  114. package/lib/router/linear-router.js +1 -95
  115. package/lib/router/pattern-router.js +1 -40
  116. package/lib/schema-validator.d.ts +1 -1
  117. package/lib/secure-headers.d.ts +1 -1
  118. package/lib/{serve-static-Dw_m6KxR.js → serve-static-Cw23shXv.js} +1 -0
  119. package/lib/serve-static.d.ts +1 -1
  120. package/lib/streaming.d.ts +1 -1
  121. package/lib/testing.d.ts +4 -4
  122. package/lib/timeout.d.ts +1 -1
  123. package/lib/timing.d.ts +1 -1
  124. package/lib/tiny.d.ts +8 -0
  125. package/lib/tiny.js +15 -0
  126. package/lib/trailing-slash.d.ts +1 -1
  127. package/lib/{types-CHesD1KG.d.ts → types-CQiGmsWW.d.ts} +3 -3
  128. package/lib/{types-CwrQjlaM.d.ts → types-Lqx5BxQF.d.ts} +10 -1
  129. package/lib/{types-CDO6I3B0.d.ts → types-nEL8VPDC.d.ts} +1 -1
  130. package/lib/types.d.ts +1 -1
  131. package/lib/utils/body.d.ts +1 -1
  132. package/lib/utils/cookie.d.ts +1 -1
  133. package/lib/utils/crypto.d.ts +1 -1
  134. package/lib/utils/html.d.ts +1 -45
  135. package/lib/utils/ipaddr.d.ts +1 -1
  136. package/lib/utils/jwt.d.ts +1 -1
  137. package/lib/utils/types.d.ts +2 -2
  138. package/lib/validator.d.ts +2 -2
  139. package/lib/ws.d.ts +1 -1
  140. package/package.json +69 -1
  141. package/plugins/acryl-inspect/upstream.json +1 -1
  142. package/plugins/acryl-node-server/upstream.json +1 -1
  143. package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +506 -0
  144. package/plugins/acryl-router/src/core/helper/css/common.ts +337 -0
  145. package/plugins/acryl-router/src/core/helper/css/index.test.tsx +678 -0
  146. package/plugins/acryl-router/src/core/helper/css/index.ts +262 -0
  147. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +181 -0
  148. package/plugins/acryl-router/src/core/helper/dev/index.ts +79 -0
  149. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +356 -0
  150. package/plugins/acryl-router/src/core/helper/proxy/index.ts +203 -0
  151. package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +557 -0
  152. package/plugins/acryl-router/src/core/jsx/base.test.tsx +97 -0
  153. package/plugins/acryl-router/src/core/jsx/base.ts +490 -0
  154. package/plugins/acryl-router/src/core/jsx/children.test.ts +52 -0
  155. package/plugins/acryl-router/src/core/jsx/children.ts +20 -0
  156. package/plugins/acryl-router/src/core/jsx/components.test.tsx +936 -0
  157. package/plugins/acryl-router/src/core/jsx/components.ts +257 -0
  158. package/plugins/acryl-router/src/core/jsx/constants.ts +6 -0
  159. package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +655 -0
  160. package/plugins/acryl-router/src/core/jsx/context.ts +266 -0
  161. package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +128 -0
  162. package/plugins/acryl-router/src/core/jsx/dom/client.ts +89 -0
  163. package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +330 -0
  164. package/plugins/acryl-router/src/core/jsx/dom/components.ts +39 -0
  165. package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +184 -0
  166. package/plugins/acryl-router/src/core/jsx/dom/context.ts +52 -0
  167. package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +149 -0
  168. package/plugins/acryl-router/src/core/jsx/dom/css.ts +263 -0
  169. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +172 -0
  170. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.ts +91 -0
  171. package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +3681 -0
  172. package/plugins/acryl-router/src/core/jsx/dom/index.ts +170 -0
  173. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +1344 -0
  174. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.ts +438 -0
  175. package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.ts +23 -0
  176. package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.ts +8 -0
  177. package/plugins/acryl-router/src/core/jsx/dom/render.ts +879 -0
  178. package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +199 -0
  179. package/plugins/acryl-router/src/core/jsx/dom/server.ts +76 -0
  180. package/plugins/acryl-router/src/core/jsx/dom/utils.ts +7 -0
  181. package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +859 -0
  182. package/plugins/acryl-router/src/core/jsx/hooks/index.ts +437 -0
  183. package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +40 -0
  184. package/plugins/acryl-router/src/core/jsx/index.test.tsx +1744 -0
  185. package/plugins/acryl-router/src/core/jsx/index.ts +115 -0
  186. package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.ts +23 -0
  187. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +666 -0
  188. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.ts +210 -0
  189. package/plugins/acryl-router/src/core/jsx/intrinsic-elements.ts +938 -0
  190. package/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts +26 -0
  191. package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +85 -0
  192. package/plugins/acryl-router/src/core/jsx/jsx-runtime.ts +51 -0
  193. package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +1281 -0
  194. package/plugins/acryl-router/src/core/jsx/streaming.ts +231 -0
  195. package/plugins/acryl-router/src/core/jsx/types.ts +41 -0
  196. package/plugins/acryl-router/src/core/jsx/utils.test.ts +366 -0
  197. package/plugins/acryl-router/src/core/jsx/utils.ts +202 -0
  198. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +1211 -0
  199. package/plugins/acryl-router/src/core/middleware/cache/index.ts +323 -0
  200. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +334 -0
  201. package/plugins/acryl-router/src/core/middleware/mount/index.ts +108 -0
  202. package/plugins/acryl-router/src/core/preset/quick.test.ts +42 -0
  203. package/plugins/acryl-router/src/core/preset/quick.ts +24 -0
  204. package/plugins/acryl-router/src/core/preset/tiny.test.ts +42 -0
  205. package/plugins/acryl-router/src/core/preset/tiny.ts +20 -0
  206. package/plugins/acryl-router/src/core/utils/types.ts +9 -0
  207. package/plugins/acryl-router/src/helpers/index.ts +3 -0
  208. package/plugins/acryl-router/src/middleware/index.ts +2 -0
  209. package/plugins/acryl-router/src/service.ts +22 -5
  210. package/plugins/acryl-router/tests/jsx.spec.tsx +63 -0
  211. package/plugins/acryl-router/upstream.json +3 -3
  212. package/plugins/acryl-router-http/upstream.json +1 -1
  213. package/plugins/acryl-state/upstream.json +1 -1
  214. package/plugins/desktop/upstream.json +1 -1
  215. package/plugins/desktop-web/upstream.json +1 -1
  216. package/plugins/save/plugin.json +1 -1
  217. package/templates/todo/upstream.json +1 -1
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @module
3
+ * Mount Helper for Acryl.
4
+ */
5
+
6
+ import type { Context, ExecutionContext } from '../../context.ts'
7
+ import { routePath } from '../../helper/route/index.ts'
8
+ import type { MiddlewareHandler } from '../../types.ts'
9
+
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ type ApplicationHandler = (request: Request, ...args: any) => Response | Promise<Response>
12
+ type MountOptionHandler = (c: Context) => unknown
13
+ type MountReplaceRequest = (originalRequest: Request) => Request
14
+ type MountOptions =
15
+ | MountOptionHandler
16
+ | {
17
+ optionHandler?: MountOptionHandler
18
+ replaceRequest?: MountReplaceRequest | false
19
+ }
20
+
21
+ const defaultReplaceRequest = (c: Context): Request => {
22
+ // e.g. `/another-app/*` (basePath is already merged) -> `/another-app`
23
+ const pathPrefix = routePath(c).replace(/\/\*$/, '')
24
+ const url = new URL(c.req.raw.url)
25
+ url.pathname = c.req.path.slice(pathPrefix.length) || '/'
26
+ return new Request(url, c.req.raw)
27
+ }
28
+
29
+ const defaultGetOptions = (c: Context): unknown[] => {
30
+ let executionContext: ExecutionContext | undefined = undefined
31
+ try {
32
+ executionContext = c.executionCtx
33
+ } catch {} // Do nothing
34
+ return [c.env, executionContext]
35
+ }
36
+
37
+ /**
38
+ * `mount()` allows you to mount applications built with other frameworks into your Acryl application.
39
+ *
40
+ *
41
+ * @param {Function} applicationHandler - other Request Handler
42
+ * @param {MountOptions} [options] - options of `mount()`
43
+ * @returns {MiddlewareHandler} handler to register with `app.all()`
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { Router as IttyRouter } from 'itty-router'
48
+ * import { Acryl } from 'acrylblends'
49
+ * import { mount } from 'acrylblends/mount'
50
+ * // Create itty-router application
51
+ * const ittyRouter = IttyRouter()
52
+ * // GET /itty-router/hello
53
+ * ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
54
+ *
55
+ * const app = new Acryl()
56
+ * app.all('/itty-router/*', mount(ittyRouter.handle))
57
+ * ```
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const app = new Acryl()
62
+ * // Send the request to another application without modification.
63
+ * app.all('/app/*', mount(anotherApp, {
64
+ * replaceRequest: (req) => req,
65
+ * }))
66
+ * ```
67
+ */
68
+ export const mount = (
69
+ applicationHandler: ApplicationHandler,
70
+ options?: MountOptions
71
+ ): MiddlewareHandler => {
72
+ // handle options
73
+ let replaceRequest: MountReplaceRequest | undefined
74
+ let optionHandler: MountOptionHandler | undefined
75
+ if (options) {
76
+ if (typeof options === 'function') {
77
+ optionHandler = options
78
+ } else {
79
+ optionHandler = options.optionHandler
80
+ if (options.replaceRequest === false) {
81
+ replaceRequest = (request) => request
82
+ } else {
83
+ replaceRequest = options.replaceRequest
84
+ }
85
+ }
86
+ }
87
+
88
+ // prepare handlers for request
89
+ const getOptions: (c: Context) => unknown[] = optionHandler
90
+ ? (c) => {
91
+ const options = optionHandler!(c)
92
+ return Array.isArray(options) ? options : [options]
93
+ }
94
+ : defaultGetOptions
95
+
96
+ return async (c, next) => {
97
+ const request = replaceRequest ? replaceRequest(c.req.raw) : defaultReplaceRequest(c)
98
+ const res = await applicationHandler(request, ...getOptions(c))
99
+
100
+ if (res) {
101
+ return res
102
+ }
103
+
104
+ await next()
105
+ }
106
+ }
107
+
108
+ export type { ApplicationHandler, MountOptionHandler, MountReplaceRequest, MountOptions }
@@ -0,0 +1,42 @@
1
+ import { getRouterName } from '../helper/dev/index.ts'
2
+ import { Acryl } from './quick.ts'
3
+
4
+ describe('acryl-router/quick preset', () => {
5
+ it('Should have SmartRouter + LinearRouter', async () => {
6
+ const app = new Acryl()
7
+ expect(getRouterName(app)).toBe('SmartRouter + LinearRouter')
8
+ })
9
+ })
10
+
11
+ describe('Generics for Bindings and Variables', () => {
12
+ interface CloudflareBindings {
13
+ MY_VARIABLE: string
14
+ }
15
+
16
+ it('Should not throw type errors', () => {
17
+ // @ts-expect-error Bindings should extend object
18
+ new Acryl<{
19
+ Bindings: number
20
+ }>()
21
+
22
+ const appWithInterface = new Acryl<{
23
+ Bindings: CloudflareBindings
24
+ }>()
25
+
26
+ appWithInterface.get('/', (c) => {
27
+ expectTypeOf(c.env.MY_VARIABLE).toMatchTypeOf<string>()
28
+ return c.text('/')
29
+ })
30
+
31
+ const appWithType = new Acryl<{
32
+ Bindings: {
33
+ foo: string
34
+ }
35
+ }>()
36
+
37
+ appWithType.get('/', (c) => {
38
+ expectTypeOf(c.env.foo).toMatchTypeOf<string>()
39
+ return c.text('Hello Acryl!')
40
+ })
41
+ })
42
+ })
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @module
3
+ * The preset that uses `LinearRouter`.
4
+ */
5
+
6
+ import { AcrylBase } from '../app-base.ts'
7
+ import type { AcrylOptions } from '../app-base.ts'
8
+ import { LinearRouter } from '../router/linear-router/index.ts'
9
+ import { SmartRouter } from '../router/smart-router/index.ts'
10
+ import { TrieRouter } from '../router/trie-router/index.ts'
11
+ import type { BlankEnv, BlankSchema, Env, Schema } from '../types.ts'
12
+
13
+ export class Acryl<
14
+ E extends Env = BlankEnv,
15
+ S extends Schema = BlankSchema,
16
+ BasePath extends string = '/',
17
+ > extends AcrylBase<E, S, BasePath> {
18
+ constructor(options: AcrylOptions<E> = {}) {
19
+ super(options)
20
+ this.router = new SmartRouter({
21
+ routers: [new LinearRouter(), new TrieRouter()],
22
+ })
23
+ }
24
+ }
@@ -0,0 +1,42 @@
1
+ import { getRouterName } from '../helper/dev/index.ts'
2
+ import { Acryl } from './tiny.ts'
3
+
4
+ describe('acryl-router/tiny preset', () => {
5
+ it('Should have PatternRouter', async () => {
6
+ const app = new Acryl()
7
+ expect(getRouterName(app)).toBe('PatternRouter')
8
+ })
9
+ })
10
+
11
+ describe('Generics for Bindings and Variables', () => {
12
+ interface CloudflareBindings {
13
+ MY_VARIABLE: string
14
+ }
15
+
16
+ it('Should not throw type errors', () => {
17
+ // @ts-expect-error Bindings should extend object
18
+ new Acryl<{
19
+ Bindings: number
20
+ }>()
21
+
22
+ const appWithInterface = new Acryl<{
23
+ Bindings: CloudflareBindings
24
+ }>()
25
+
26
+ appWithInterface.get('/', (c) => {
27
+ expectTypeOf(c.env.MY_VARIABLE).toMatchTypeOf<string>()
28
+ return c.text('/')
29
+ })
30
+
31
+ const appWithType = new Acryl<{
32
+ Bindings: {
33
+ foo: string
34
+ }
35
+ }>()
36
+
37
+ appWithType.get('/', (c) => {
38
+ expectTypeOf(c.env.foo).toMatchTypeOf<string>()
39
+ return c.text('Hello Acryl!')
40
+ })
41
+ })
42
+ })
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @module
3
+ * The preset that uses `PatternRouter`.
4
+ */
5
+
6
+ import { AcrylBase } from '../app-base.ts'
7
+ import type { AcrylOptions } from '../app-base.ts'
8
+ import { PatternRouter } from '../router/pattern-router/index.ts'
9
+ import type { BlankEnv, BlankSchema, Env, Schema } from '../types.ts'
10
+
11
+ export class Acryl<
12
+ E extends Env = BlankEnv,
13
+ S extends Schema = BlankSchema,
14
+ BasePath extends string = '/',
15
+ > extends AcrylBase<E, S, BasePath> {
16
+ constructor(options: AcrylOptions<E> = {}) {
17
+ super(options)
18
+ this.router = new PatternRouter()
19
+ }
20
+ }
@@ -125,6 +125,9 @@ export type BufferSource = ArrayBufferView<ArrayBuffer> | ArrayBuffer
125
125
  /** A Web Crypto key, named from the runtime's own `crypto` so the public types do not need the DOM library. */
126
126
  export type CryptoKey = Awaited<ReturnType<typeof crypto.subtle.importKey>>
127
127
 
128
+ /** What the Web `Headers` constructor accepts, named from the runtime's own `Headers` so the public types do not need the DOM library. */
129
+ export type HeadersInit = NonNullable<ConstructorParameters<typeof Headers>[0]>
130
+
128
131
  /** How a WebSocket hands binary data to `onmessage`; declared here so the public types do not need the DOM library. */
129
132
  export type BinaryType = 'arraybuffer' | 'blob'
130
133
 
@@ -163,3 +166,9 @@ export interface JsonWebKey {
163
166
  x?: string
164
167
  y?: string
165
168
  }
169
+
170
+ /**
171
+ * A DOM event type by its global name: the DOM library's own type when it is loaded (a browser project), otherwise the runtime's `Event`,
172
+ * so the JSX types (event handler props) do not need the DOM library on a server.
173
+ */
174
+ export type DomEvent<Name extends string> = typeof globalThis extends { readonly [K in Name]: { readonly prototype: infer E } } ? E : Event
@@ -4,7 +4,10 @@ export { accepts } from '../core/helper/accepts/index.ts'
4
4
  export { createFactory, createMiddleware, Factory } from '../core/helper/factory/index.ts'
5
5
  export { deleteCookie, generateCookie, generateSignedCookie, getCookie, getSignedCookie, setCookie, setSignedCookie } from '../core/helper/cookie/index.ts'
6
6
  export { getExtension, getMimeType, mimes, type BaseMime } from '../core/utils/mime.ts'
7
+ export { createCssContext, css, cx, keyframes, rawCssString, Style, viewTransition } from '../core/helper/css/index.ts'
7
8
  export { html, raw } from '../core/helper/html/index.ts'
9
+ export { proxy } from '../core/helper/proxy/index.ts'
10
+ export { getRouterName, inspectRoutes, showRoutes } from '../core/helper/dev/index.ts'
8
11
  export { matchedRoutes, routePath, baseRoutePath, basePath } from '../core/helper/route/index.ts'
9
12
  export { testClient } from '../core/helper/testing/index.ts'
10
13
  export { stream, streamSSE, streamText, SSEStreamingApi, type SSEMessage } from '../core/helper/streaming/index.ts'
@@ -1,6 +1,7 @@
1
1
  export { basicAuth } from '../core/middleware/basic-auth/index.ts'
2
2
  export { bearerAuth } from '../core/middleware/bearer-auth/index.ts'
3
3
  export { bodyLimit } from '../core/middleware/body-limit/index.ts'
4
+ export { cache } from '../core/middleware/cache/index.ts'
4
5
  export { every, except, some } from '../core/middleware/combine/index.ts'
5
6
  export { compress } from '../core/middleware/compress/index.ts'
6
7
  export { contextStorage, getContext, tryGetContext } from '../core/middleware/context-storage/index.ts'
@@ -14,6 +15,7 @@ export { detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, la
14
15
  export { logger } from '../core/middleware/logger/index.ts'
15
16
  export { methodNotAllowed } from '../core/middleware/method-not-allowed/index.ts'
16
17
  export { methodOverride } from '../core/middleware/method-override/index.ts'
18
+ export { mount } from '../core/middleware/mount/index.ts'
17
19
  export { poweredBy } from '../core/middleware/powered-by/index.ts'
18
20
  export { prettyJSON } from '../core/middleware/pretty-json/index.ts'
19
21
  export { requestId, type RequestIdVariables } from '../core/middleware/request-id/index.ts'
@@ -54,13 +54,30 @@ declare module '@deepseek-ai/cordis' {
54
54
  /** Stable Cordis plugin name, equal to the package name and the Loader row id. */
55
55
  export const name = 'acryl-router'
56
56
 
57
- // Any `Acryl`, whatever its Env and schema; the router only reads its routes.
58
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
- export type MountableApp = Acryl<any, any, any>
57
+ /**
58
+ * What {@link Router.route} takes: any app with routes, read structurally. An `Acryl` from this package qualifies, and so does one built from
59
+ * another copy of the framework (the published `acrylblends`), whose classes TypeScript would refuse nominally for their private members:
60
+ * mounting copies the app's routes (and keeps its own `onError`), which is all the router reads. Their handlers are then called with this
61
+ * router's `Context`, which has the same shape.
62
+ */
63
+ export interface MountableApp {
64
+ readonly routes: readonly MountableRoute[]
65
+ }
66
+
67
+ /** One route of a {@link MountableApp}, as the core lists it. A handler of any context type fits (`never` parameters accept every function). */
68
+ export interface MountableRoute {
69
+ readonly basePath: string
70
+ readonly path: string
71
+ readonly method: string
72
+ readonly handler: (c: never, next: never) => unknown
73
+ }
74
+
75
+ /** The core's `app.route` with a structural app: at run time it reads only the routes and the app's own error handler. */
76
+ const copyRoutes = (app: MountableApp): Acryl => new Acryl().route('/', app as unknown as Acryl)
60
77
 
61
78
  interface Mount {
62
79
  readonly path: string
63
- readonly app: MountableApp
80
+ readonly app: Acryl
64
81
  }
65
82
 
66
83
  interface RouterState {
@@ -161,7 +178,7 @@ export class Router extends Service {
161
178
  * mount's code a request is in. The core's `app.route` runs first so a sub-app's own `onError` still applies to its routes.
162
179
  */
163
180
  private snapshot(path: string, app: MountableApp): Mount {
164
- const copy = new Acryl().route('/', app)
181
+ const copy = copyRoutes(app)
165
182
  const tagged = new Acryl()
166
183
  const mount: Mount = { path, app: tagged }
167
184
  for (const route of copy.routes) {
@@ -0,0 +1,63 @@
1
+ /** @jsxImportSource acryl-router/jsx */
2
+ /**
3
+ * JSX in a Cordis plugin, set up as the docs say (`jsxImportSource: 'acryl-router/jsx'`, which resolves this package's built runtime): a page rendered with the ported JSX renderer and styled with the CSS helper, served through `ctx.router`, and a
4
+ * streamed page whose suspended part arrives after the shell. The ported suites cover the renderer itself; this covers the plugin seam.
5
+ */
6
+
7
+ import { Context } from '@deepseek-ai/cordis'
8
+ import { afterEach, describe, expect, it } from 'vitest'
9
+ import { css, Style } from '../src/helpers/index.ts'
10
+ import { Acryl, apply, name } from '../src/index.ts'
11
+ import { Suspense } from '../src/core/jsx/index.ts'
12
+ import { renderToReadableStream } from '../src/core/jsx/streaming.ts'
13
+
14
+ const contexts: Context[] = []
15
+ const settle = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0))
16
+ afterEach(async () => {
17
+ while (contexts.length > 0) await contexts.pop()?.fiber.dispose()
18
+ })
19
+
20
+ async function serve(app: Acryl): Promise<Context> {
21
+ const ctx = new Context()
22
+ contexts.push(ctx)
23
+ ctx.plugin({ name, apply })
24
+ ctx.plugin({ name: 'pages', inject: ['router'], apply(inner: Context) { inner.router.route('/pages', app) } })
25
+ await settle()
26
+ return ctx
27
+ }
28
+
29
+ describe('JSX through ctx.router', () => {
30
+ it('serves a page rendered from JSX, styled with the CSS helper', async () => {
31
+ const title = css`color: teal;`
32
+ const app = new Acryl().get('/', c => c.html(
33
+ <html>
34
+ <head><Style /></head>
35
+ <body><h1 class={title}>Acryl!</h1></body>
36
+ </html>,
37
+ ))
38
+ const ctx = await serve(app)
39
+
40
+ const response = await ctx.router.request('/pages')
41
+ expect(response.status).toBe(200)
42
+ expect(response.headers.get('content-type')).toBe('text/html; charset=UTF-8')
43
+ const page = await response.text()
44
+ expect(page).toMatch(/^<html><head><style id="acryl-css">\.css-\d+\{color:teal\}<\/style><\/head><body><h1 class="css-\d+">Acryl!<\/h1><\/body><\/html>$/u)
45
+ })
46
+
47
+ it('streams a page: the shell first, then the suspended part', async () => {
48
+ const Late = async () => { await new Promise(resolve => setTimeout(resolve, 10)); return <p>loaded</p> }
49
+ const page = <Suspense fallback={<p>loading</p>}><Late /></Suspense>
50
+ const app = new Acryl().get('/stream', c => c.body(renderToReadableStream(page), 200, {
51
+ 'content-type': 'text/html; charset=UTF-8',
52
+ }))
53
+ const ctx = await serve(app)
54
+
55
+ const response = await ctx.router.request('/pages/stream')
56
+ const reader = response.body!.pipeThrough(new TextDecoderStream()).getReader()
57
+ const chunks: string[] = []
58
+ for (let next = await reader.read(); !next.done; next = await reader.read()) chunks.push(next.value)
59
+ expect(chunks.length).toBeGreaterThan(1)
60
+ expect(chunks[0]).toContain('loading')
61
+ expect(chunks.join('')).toContain('loaded')
62
+ })
63
+ })
@@ -2,15 +2,15 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "plugins/acryl-router",
5
- "commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
5
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
9
9
  "tests",
10
10
  "LICENSE"
11
11
  ],
12
- "rewrittenSpecifiers": 4,
13
- "digest": "sha256:543a5ca99518eea1fe2e319b7708d62af34a6c24ab3daeb17dde48d67d319d6a",
12
+ "rewrittenSpecifiers": 6,
13
+ "digest": "sha256:141895acbc03bfea20b4142356a0614361f83a0beca0a989ae141b5f877f399d",
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": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
5
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
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": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
5
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
6
6
  },
7
7
  "vendored": [
8
8
  "src",
@@ -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": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
8
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
9
9
  },
10
10
  "rewrittenSpecifiers": 0,
11
11
  "digest": "sha256:7dfe960a8bbb476c35540d2202a7aaa62b33492c2ac3e34314e2ecfca45f32f2"
@@ -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": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
8
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
9
9
  },
10
10
  "rewrittenSpecifiers": 0,
11
11
  "digest": "sha256:7dfe960a8bbb476c35540d2202a7aaa62b33492c2ac3e34314e2ecfca45f32f2"
@@ -6,7 +6,7 @@
6
6
  "provides": [],
7
7
  "dependencies": {
8
8
  "@deepseek-ai/cordis": "4.0.4",
9
- "@webboxes/app-persistence": "0.1.0"
9
+ "@webboxes/app-persistence": "0.1.1"
10
10
  },
11
11
  "mount": "add a script \"save\": \"node src/plugins/save/cli.ts\" to package.json; mount the plugin to give the agent a save_app tool"
12
12
  }
@@ -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": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
8
+ "commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
9
9
  },
10
10
  "rewrittenSpecifiers": 4,
11
11
  "digest": "sha256:9093704776563001f7f472f94cc5c2fdd79206342c1cb59c11fce62aa74df3ed"