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.
- package/README.md +11 -6
- package/docs/framework/README.md +3 -2
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/api/presets.md +0 -3
- package/docs/framework/cordis/acryl-in-a-cordis-app.md +9 -0
- package/docs/framework/getting-started/basic.md +5 -4
- package/docs/framework/getting-started/desktop.md +41 -0
- package/docs/framework/guides/jsx-dom.md +0 -3
- package/docs/framework/guides/jsx.md +1 -4
- package/docs/framework/guides/middleware.md +1 -1
- package/docs/framework/helpers/cookie.md +1 -1
- package/docs/framework/helpers/css.md +0 -3
- package/docs/framework/helpers/dev.md +0 -3
- package/docs/framework/helpers/jwt.md +1 -1
- package/docs/framework/helpers/proxy.md +0 -3
- package/docs/framework/middleware/builtin/basic-auth.md +6 -6
- package/docs/framework/middleware/builtin/cache.md +0 -3
- package/docs/framework/middleware/builtin/combine.md +1 -1
- package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
- package/docs/framework/middleware/builtin/logger.md +1 -1
- package/docs/framework/middleware/builtin/mount.md +0 -3
- package/docs/framework/upstream.json +3 -3
- package/lib/accepts.d.ts +1 -1
- package/lib/acryl-base.d.ts +1 -1
- package/lib/adapter.d.ts +1 -1
- package/lib/{app-CmAYW1Al.d.ts → app-wFwpg-bt.d.ts} +1 -1
- package/lib/base-BpQy2Rk7.d.ts +783 -0
- package/lib/base-ddiVmiE7.js +721 -0
- package/lib/basic-auth.d.ts +1 -1
- package/lib/bearer-auth.d.ts +1 -1
- package/lib/body-limit.d.ts +1 -1
- package/lib/cache.d.ts +43 -0
- package/lib/cache.js +169 -0
- package/lib/client.d.ts +2 -2
- package/lib/combine.d.ts +1 -1
- package/lib/common-D8Z4JRCw.d.ts +46 -0
- package/lib/components-Ce5FRyHU.js +268 -0
- package/lib/components-DYZdxJIJ.js +24 -0
- package/lib/compress.d.ts +1 -1
- package/lib/conninfo.d.ts +2 -2
- package/lib/constants-BR9jM9BC.js +9 -0
- package/lib/{context-Bm7rI-oK.d.ts → context-DVQBjuns.d.ts} +1 -1
- package/lib/context-DxFdY_un.d.ts +250 -0
- package/lib/context-storage.d.ts +1 -1
- package/lib/{cookie-ClMaKDQf.d.ts → cookie-CCelEqky.d.ts} +1 -1
- package/lib/cookie.d.ts +3 -3
- package/lib/cors.d.ts +1 -1
- package/lib/csrf.d.ts +1 -1
- package/lib/css-D2jb7X8b.js +320 -0
- package/lib/css.d.ts +82 -0
- package/lib/css.js +134 -0
- package/lib/dev.d.ts +19 -0
- package/lib/dev.js +50 -0
- package/lib/etag.d.ts +1 -1
- package/lib/factory.d.ts +2 -2
- package/lib/hooks-Bq5q9IMl.js +762 -0
- package/lib/html-SllAe0YT.d.ts +46 -0
- package/lib/html.d.ts +1 -1
- package/lib/index-C850MeBA.d.ts +94 -0
- package/lib/{index-oOClm_Xk.d.ts → index-CUTfU69R.d.ts} +3 -3
- package/lib/{index-B-3F4wt2.d.ts → index-Cqcdluyn.d.ts} +2 -2
- package/lib/{index-UTBmM3GX.d.ts → index-CsvB-F9j.d.ts} +2 -2
- package/lib/index.d.ts +4 -4
- package/lib/ip-restriction.d.ts +2 -2
- package/lib/jsx/dom/client.d.ts +30 -0
- package/lib/jsx/dom/client.js +49 -0
- package/lib/jsx/dom/css.d.ts +84 -0
- package/lib/jsx/dom/css.js +2 -0
- package/lib/jsx/dom/jsx-dev-runtime.d.ts +3 -0
- package/lib/jsx/dom/jsx-dev-runtime.js +2 -0
- package/lib/jsx/dom/jsx-runtime.d.ts +3 -0
- package/lib/jsx/dom/jsx-runtime.js +2 -0
- package/lib/jsx/dom/server.d.ts +105 -0
- package/lib/jsx/dom/server.js +37 -0
- package/lib/jsx/dom.d.ts +5 -0
- package/lib/jsx/dom.js +74 -0
- package/lib/jsx/jsx-dev-runtime.d.ts +6 -0
- package/lib/jsx/jsx-dev-runtime.js +14 -0
- package/lib/jsx/jsx-runtime.d.ts +10 -0
- package/lib/jsx/jsx-runtime.js +30 -0
- package/lib/jsx/streaming.d.ts +2 -0
- package/lib/jsx/streaming.js +2 -0
- package/lib/jsx-dev-runtime-B22O-Npk.d.ts +7 -0
- package/lib/jsx-dev-runtime-kAhR_4C7.js +354 -0
- package/lib/jsx-runtime-BVVgDSdq.d.ts +1 -0
- package/lib/jsx.d.ts +3 -0
- package/lib/jsx.js +47 -0
- package/lib/jwk.d.ts +4 -4
- package/lib/{jwt-Dg493Tai.d.ts → jwt-BARhotDz.d.ts} +1 -1
- package/lib/jwt.d.ts +4 -4
- package/lib/language.d.ts +1 -1
- package/lib/linear-router-C3FPib6h.js +96 -0
- package/lib/logger.d.ts +1 -1
- package/lib/loopback-only.d.ts +1 -1
- package/lib/method-not-allowed.d.ts +2 -2
- package/lib/method-override.d.ts +2 -2
- package/lib/mount.d.ts +44 -0
- package/lib/mount.js +67 -0
- package/lib/node-server/conninfo.d.ts +1 -1
- package/lib/node-server/serve-static.d.ts +1 -1
- package/lib/node-server/serve-static.js +1 -1
- package/lib/node-server.d.ts +1 -1
- package/lib/node-server.js +1 -1
- package/lib/pattern-router-HZxjDGEQ.js +41 -0
- package/lib/powered-by.d.ts +1 -1
- package/lib/pretty-json.d.ts +1 -1
- package/lib/proxy.d.ts +72 -0
- package/lib/proxy.js +121 -0
- package/lib/quick.d.ts +8 -0
- package/lib/quick.js +17 -0
- package/lib/request-id.d.ts +1 -1
- package/lib/request.d.ts +1 -1
- package/lib/route.d.ts +1 -1
- package/lib/router/linear-router.js +1 -95
- package/lib/router/pattern-router.js +1 -40
- package/lib/schema-validator.d.ts +1 -1
- package/lib/secure-headers.d.ts +1 -1
- package/lib/{serve-static-Dw_m6KxR.js → serve-static-Cw23shXv.js} +1 -0
- package/lib/serve-static.d.ts +1 -1
- package/lib/streaming.d.ts +1 -1
- package/lib/testing.d.ts +4 -4
- package/lib/timeout.d.ts +1 -1
- package/lib/timing.d.ts +1 -1
- package/lib/tiny.d.ts +8 -0
- package/lib/tiny.js +15 -0
- package/lib/trailing-slash.d.ts +1 -1
- package/lib/{types-CHesD1KG.d.ts → types-CQiGmsWW.d.ts} +3 -3
- package/lib/{types-CwrQjlaM.d.ts → types-Lqx5BxQF.d.ts} +10 -1
- package/lib/{types-CDO6I3B0.d.ts → types-nEL8VPDC.d.ts} +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/utils/body.d.ts +1 -1
- package/lib/utils/cookie.d.ts +1 -1
- package/lib/utils/crypto.d.ts +1 -1
- package/lib/utils/html.d.ts +1 -45
- package/lib/utils/ipaddr.d.ts +1 -1
- package/lib/utils/jwt.d.ts +1 -1
- package/lib/utils/types.d.ts +2 -2
- package/lib/validator.d.ts +2 -2
- package/lib/ws.d.ts +1 -1
- package/package.json +69 -1
- package/plugins/acryl-inspect/upstream.json +1 -1
- package/plugins/acryl-node-server/upstream.json +1 -1
- package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +506 -0
- package/plugins/acryl-router/src/core/helper/css/common.ts +337 -0
- package/plugins/acryl-router/src/core/helper/css/index.test.tsx +678 -0
- package/plugins/acryl-router/src/core/helper/css/index.ts +262 -0
- package/plugins/acryl-router/src/core/helper/dev/index.test.ts +181 -0
- package/plugins/acryl-router/src/core/helper/dev/index.ts +79 -0
- package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +356 -0
- package/plugins/acryl-router/src/core/helper/proxy/index.ts +203 -0
- package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +557 -0
- package/plugins/acryl-router/src/core/jsx/base.test.tsx +97 -0
- package/plugins/acryl-router/src/core/jsx/base.ts +490 -0
- package/plugins/acryl-router/src/core/jsx/children.test.ts +52 -0
- package/plugins/acryl-router/src/core/jsx/children.ts +20 -0
- package/plugins/acryl-router/src/core/jsx/components.test.tsx +936 -0
- package/plugins/acryl-router/src/core/jsx/components.ts +257 -0
- package/plugins/acryl-router/src/core/jsx/constants.ts +6 -0
- package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +655 -0
- package/plugins/acryl-router/src/core/jsx/context.ts +266 -0
- package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +128 -0
- package/plugins/acryl-router/src/core/jsx/dom/client.ts +89 -0
- package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +330 -0
- package/plugins/acryl-router/src/core/jsx/dom/components.ts +39 -0
- package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +184 -0
- package/plugins/acryl-router/src/core/jsx/dom/context.ts +52 -0
- package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +149 -0
- package/plugins/acryl-router/src/core/jsx/dom/css.ts +263 -0
- package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +172 -0
- package/plugins/acryl-router/src/core/jsx/dom/hooks/index.ts +91 -0
- package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +3681 -0
- package/plugins/acryl-router/src/core/jsx/dom/index.ts +170 -0
- package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +1344 -0
- package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.ts +438 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.ts +23 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.ts +8 -0
- package/plugins/acryl-router/src/core/jsx/dom/render.ts +879 -0
- package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +199 -0
- package/plugins/acryl-router/src/core/jsx/dom/server.ts +76 -0
- package/plugins/acryl-router/src/core/jsx/dom/utils.ts +7 -0
- package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +859 -0
- package/plugins/acryl-router/src/core/jsx/hooks/index.ts +437 -0
- package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +40 -0
- package/plugins/acryl-router/src/core/jsx/index.test.tsx +1744 -0
- package/plugins/acryl-router/src/core/jsx/index.ts +115 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.ts +23 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +666 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.ts +210 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-elements.ts +938 -0
- package/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts +26 -0
- package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +85 -0
- package/plugins/acryl-router/src/core/jsx/jsx-runtime.ts +51 -0
- package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +1281 -0
- package/plugins/acryl-router/src/core/jsx/streaming.ts +231 -0
- package/plugins/acryl-router/src/core/jsx/types.ts +41 -0
- package/plugins/acryl-router/src/core/jsx/utils.test.ts +366 -0
- package/plugins/acryl-router/src/core/jsx/utils.ts +202 -0
- package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +1211 -0
- package/plugins/acryl-router/src/core/middleware/cache/index.ts +323 -0
- package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +334 -0
- package/plugins/acryl-router/src/core/middleware/mount/index.ts +108 -0
- package/plugins/acryl-router/src/core/preset/quick.test.ts +42 -0
- package/plugins/acryl-router/src/core/preset/quick.ts +24 -0
- package/plugins/acryl-router/src/core/preset/tiny.test.ts +42 -0
- package/plugins/acryl-router/src/core/preset/tiny.ts +20 -0
- package/plugins/acryl-router/src/core/utils/types.ts +9 -0
- package/plugins/acryl-router/src/helpers/index.ts +3 -0
- package/plugins/acryl-router/src/middleware/index.ts +2 -0
- package/plugins/acryl-router/src/service.ts +22 -5
- package/plugins/acryl-router/tests/jsx.spec.tsx +63 -0
- package/plugins/acryl-router/upstream.json +3 -3
- package/plugins/acryl-router-http/upstream.json +1 -1
- package/plugins/acryl-state/upstream.json +1 -1
- package/plugins/desktop/upstream.json +1 -1
- package/plugins/desktop-web/upstream.json +1 -1
- package/plugins/save/plugin.json +1 -1
- 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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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:
|
|
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 =
|
|
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": "
|
|
5
|
+
"commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
|
|
6
6
|
},
|
|
7
7
|
"vendored": [
|
|
8
8
|
"src",
|
|
9
9
|
"tests",
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
|
-
"rewrittenSpecifiers":
|
|
13
|
-
"digest": "sha256:
|
|
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
|
},
|
|
@@ -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": "
|
|
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": "
|
|
8
|
+
"commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
|
|
9
9
|
},
|
|
10
10
|
"rewrittenSpecifiers": 0,
|
|
11
11
|
"digest": "sha256:7dfe960a8bbb476c35540d2202a7aaa62b33492c2ac3e34314e2ecfca45f32f2"
|
package/plugins/save/plugin.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"provides": [],
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@deepseek-ai/cordis": "4.0.4",
|
|
9
|
-
"@webboxes/app-persistence": "0.1.
|
|
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": "
|
|
8
|
+
"commit": "60491f81b7346d1f3867fa01ee4e2caffc7baf47"
|
|
9
9
|
},
|
|
10
10
|
"rewrittenSpecifiers": 4,
|
|
11
11
|
"digest": "sha256:9093704776563001f7f472f94cc5c2fdd79206342c1cb59c11fce62aa74df3ed"
|