acrylblends 0.6.2 → 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 +4 -1
- package/docs/framework/README.md +3 -2
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/cordis/acryl-in-a-cordis-app.md +6 -0
- package/docs/framework/getting-started/basic.md +1 -0
- package/docs/framework/getting-started/desktop.md +41 -0
- package/docs/framework/guides/jsx-dom.md +0 -3
- package/docs/framework/guides/jsx.md +0 -3
- package/docs/framework/helpers/css.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-BdrVHBlJ.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 +1 -1
- 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-B5Y1lLha.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-D9_nQbsM.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 +2 -2
- 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-m12zcmph.d.ts → index-CUTfU69R.d.ts} +3 -3
- package/lib/{index-DtEoak1i.d.ts → index-Cqcdluyn.d.ts} +2 -2
- package/lib/{index-Kqou8Fjh.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-BA65QhnJ.d.ts → jwt-BARhotDz.d.ts} +1 -1
- package/lib/jwt.d.ts +4 -4
- package/lib/language.d.ts +1 -1
- 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 +1 -1
- 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/powered-by.d.ts +1 -1
- package/lib/pretty-json.d.ts +1 -1
- package/lib/proxy.d.ts +1 -1
- package/lib/quick.d.ts +1 -1
- package/lib/request-id.d.ts +1 -1
- package/lib/request.d.ts +1 -1
- package/lib/route.d.ts +1 -1
- 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 +1 -1
- package/lib/trailing-slash.d.ts +1 -1
- package/lib/{types-Bd29gh2o.d.ts → types-CQiGmsWW.d.ts} +3 -3
- package/lib/{types-D9DEXMjE.d.ts → types-Lqx5BxQF.d.ts} +8 -1
- package/lib/{types-ZM9gIiKh.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 +45 -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/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/utils/types.ts +6 -0
- package/plugins/acryl-router/src/helpers/index.ts +1 -0
- 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,202 @@
|
|
|
1
|
+
const normalizeElementKeyMap: Map<string, string> = new Map([
|
|
2
|
+
['className', 'class'],
|
|
3
|
+
['htmlFor', 'for'],
|
|
4
|
+
['crossOrigin', 'crossorigin'],
|
|
5
|
+
['httpEquiv', 'http-equiv'],
|
|
6
|
+
['itemProp', 'itemprop'],
|
|
7
|
+
['fetchPriority', 'fetchpriority'],
|
|
8
|
+
['noModule', 'nomodule'],
|
|
9
|
+
['formAction', 'formaction'],
|
|
10
|
+
])
|
|
11
|
+
export const normalizeIntrinsicElementKey = (key: string): string =>
|
|
12
|
+
normalizeElementKeyMap.get(key) || key
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line no-control-regex
|
|
15
|
+
const invalidAttributeNameCharRe = /[\s"'<>/=`\\\x00-\x1f\x7f-\x9f]/
|
|
16
|
+
const validAttributeNameCache = new Set<string>()
|
|
17
|
+
const validAttributeNameCacheMax = 1024
|
|
18
|
+
// reject HTML parser-control tag starters ('!' for comments/doctype, '?' for
|
|
19
|
+
// processing instructions) in addition to the shared invalid-char set
|
|
20
|
+
// eslint-disable-next-line no-control-regex
|
|
21
|
+
const invalidTagNameCharRe = /^[!?]|[\s"'<>/=`\\\x00-\x1f\x7f-\x9f]/
|
|
22
|
+
const validTagNameCache = new Set<unknown>()
|
|
23
|
+
const validTagNameCacheMax = 256
|
|
24
|
+
|
|
25
|
+
const cacheValidName = (cache: Set<unknown>, max: number, name: string): void => {
|
|
26
|
+
if (cache.size >= max) {
|
|
27
|
+
cache.clear()
|
|
28
|
+
}
|
|
29
|
+
cache.add(name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const isValidTagName = (name: unknown): name is string => {
|
|
33
|
+
if (validTagNameCache.has(name)) {
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
if (typeof name !== 'string') {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
if (name.length === 0) {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
if (invalidTagNameCharRe.test(name)) {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
cacheValidName(validTagNameCache, validTagNameCacheMax, name)
|
|
46
|
+
return true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const isValidAttributeName = (name: string): boolean => {
|
|
50
|
+
if (validAttributeNameCache.has(name)) {
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
const len = name.length
|
|
54
|
+
if (len === 0) {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
for (let i = 0; i < len; i++) {
|
|
58
|
+
const c = name.charCodeAt(i)
|
|
59
|
+
if (
|
|
60
|
+
!(
|
|
61
|
+
(c >= 0x61 && c <= 0x7a) || // a-z
|
|
62
|
+
(c >= 0x41 && c <= 0x5a) || // A-Z
|
|
63
|
+
(c >= 0x30 && c <= 0x39) || // 0-9
|
|
64
|
+
c === 0x2d || // -
|
|
65
|
+
c === 0x5f || // _
|
|
66
|
+
c === 0x2e || // .
|
|
67
|
+
c === 0x3a // :
|
|
68
|
+
)
|
|
69
|
+
) {
|
|
70
|
+
// non-fast-path character found — fall back to regex for the full name
|
|
71
|
+
if (!invalidAttributeNameCharRe.test(name)) {
|
|
72
|
+
cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name)
|
|
73
|
+
return true
|
|
74
|
+
} else {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
cacheValidName(validAttributeNameCache, validAttributeNameCacheMax, name)
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// eslint-disable-next-line no-control-regex
|
|
84
|
+
const invalidStylePropertyNameCharRe = /[\s"'():;\\/\[\]{}\x00-\x1f\x7f-\x9f]/
|
|
85
|
+
const validStylePropertyNameCache = new Set<string>()
|
|
86
|
+
const validStylePropertyNameCacheMax = 1024
|
|
87
|
+
|
|
88
|
+
const isValidStylePropertyName = (name: string): boolean => {
|
|
89
|
+
if (validStylePropertyNameCache.has(name)) {
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
const len = name.length
|
|
93
|
+
if (len === 0) {
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
96
|
+
for (let i = 0; i < len; i++) {
|
|
97
|
+
const c = name.charCodeAt(i)
|
|
98
|
+
if (
|
|
99
|
+
!(
|
|
100
|
+
(c >= 0x61 && c <= 0x7a) || // a-z
|
|
101
|
+
(c >= 0x41 && c <= 0x5a) || // A-Z
|
|
102
|
+
(c >= 0x30 && c <= 0x39) || // 0-9
|
|
103
|
+
c === 0x2d || // -
|
|
104
|
+
c === 0x5f // _
|
|
105
|
+
)
|
|
106
|
+
) {
|
|
107
|
+
// non-fast-path character found — fall back to regex for the full name
|
|
108
|
+
if (!invalidStylePropertyNameCharRe.test(name)) {
|
|
109
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name)
|
|
110
|
+
return true
|
|
111
|
+
} else {
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
cacheValidName(validStylePropertyNameCache, validStylePropertyNameCacheMax, name)
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const unsafeStyleValueCharRe = /[;"'\\/\[\](){}]/
|
|
121
|
+
|
|
122
|
+
const hasUnsafeStyleValue = (value: string): boolean => {
|
|
123
|
+
if (!unsafeStyleValueCharRe.test(value)) {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let quote = 0
|
|
128
|
+
const blockStack: number[] = []
|
|
129
|
+
for (let i = 0, len = value.length; i < len; i++) {
|
|
130
|
+
const c = value.charCodeAt(i)
|
|
131
|
+
if (c === 0x5c) {
|
|
132
|
+
if (i === len - 1) {
|
|
133
|
+
return true
|
|
134
|
+
}
|
|
135
|
+
i++
|
|
136
|
+
} else if (quote !== 0) {
|
|
137
|
+
if (c === 0x0a || c === 0x0c || c === 0x0d) {
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
if (c === quote) {
|
|
141
|
+
quote = 0
|
|
142
|
+
}
|
|
143
|
+
} else if (c === 0x2f && value.charCodeAt(i + 1) === 0x2a) {
|
|
144
|
+
const end = value.indexOf('*/', i + 2)
|
|
145
|
+
if (end === -1) {
|
|
146
|
+
return true
|
|
147
|
+
}
|
|
148
|
+
i = end + 1
|
|
149
|
+
} else if (c === 0x22 || c === 0x27) {
|
|
150
|
+
quote = c
|
|
151
|
+
} else if (c === 0x28) {
|
|
152
|
+
blockStack.push(0x29)
|
|
153
|
+
} else if (c === 0x5b) {
|
|
154
|
+
blockStack.push(0x5d)
|
|
155
|
+
} else if (c === 0x7b || c === 0x7d) {
|
|
156
|
+
return true
|
|
157
|
+
} else if (c === 0x29 || c === 0x5d) {
|
|
158
|
+
if (blockStack[blockStack.length - 1] !== c) {
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
blockStack.pop()
|
|
162
|
+
} else if (c === 0x3b && blockStack.length === 0) {
|
|
163
|
+
return true
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return quote !== 0 || blockStack.length !== 0
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const styleObjectForEach = (
|
|
170
|
+
style: Record<string, unknown>,
|
|
171
|
+
fn: (key: string, value: string | null) => void
|
|
172
|
+
): void => {
|
|
173
|
+
for (const [k, v] of Object.entries(style)) {
|
|
174
|
+
const key =
|
|
175
|
+
k[0] === '-' || !/[A-Z]/.test(k)
|
|
176
|
+
? k // a CSS variable or a lowercase only property
|
|
177
|
+
: k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`) // a camelCase property. convert to kebab-case
|
|
178
|
+
if (!isValidStylePropertyName(key)) {
|
|
179
|
+
continue
|
|
180
|
+
}
|
|
181
|
+
if (v == null) {
|
|
182
|
+
fn(key, null)
|
|
183
|
+
continue
|
|
184
|
+
}
|
|
185
|
+
let value: string
|
|
186
|
+
if (typeof v === 'number') {
|
|
187
|
+
value = !key.match(
|
|
188
|
+
/^(?:a|border-im|column(?:-c|s)|flex(?:$|-[^b])|grid-(?!.*gap)(?:ar|[^a])|font-w|li|or|sca|st|ta|wido|z)|ty$/
|
|
189
|
+
)
|
|
190
|
+
? `${v}px`
|
|
191
|
+
: `${v}`
|
|
192
|
+
} else if (typeof v === 'string') {
|
|
193
|
+
if (hasUnsafeStyleValue(v)) {
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
value = v
|
|
197
|
+
} else {
|
|
198
|
+
continue
|
|
199
|
+
}
|
|
200
|
+
fn(key, value)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -166,3 +166,9 @@ export interface JsonWebKey {
|
|
|
166
166
|
x?: string
|
|
167
167
|
y?: string
|
|
168
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,6 +4,7 @@ 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'
|
|
8
9
|
export { proxy } from '../core/helper/proxy/index.ts'
|
|
9
10
|
export { getRouterName, inspectRoutes, showRoutes } from '../core/helper/dev/index.ts'
|
|
@@ -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"
|