acrylblends 1.0.4 → 1.0.5

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 (238) hide show
  1. package/docs/framework/agents/index.md +6 -4
  2. package/lib/accept-CNNHu4Cf.js +193 -0
  3. package/lib/{accepts-XBuZPVRI.js → accepts-Btq83xPd.js} +1 -1
  4. package/lib/accepts.js +1 -1
  5. package/lib/acryl-base.js +1 -331
  6. package/lib/adapter-CaZ6FZUU.js +37 -0
  7. package/lib/adapter.js +1 -36
  8. package/lib/{app-BM0rTCp7.js → app-CQcGWjrk.js} +4 -4
  9. package/lib/app-base-CpRMZL4v.js +332 -0
  10. package/lib/{base-NSN_SNv-.js → base-D_6kfOr-.js} +1 -1
  11. package/lib/basic-auth-C0HTRpXh.js +20 -0
  12. package/lib/basic-auth-DFLflXNe.js +95 -0
  13. package/lib/basic-auth.js +1 -94
  14. package/lib/bearer-auth-Cwxt-vgS.js +94 -0
  15. package/lib/bearer-auth.js +1 -93
  16. package/lib/body-D7f4e7w_.js +94 -0
  17. package/lib/body-limit-WmIjWRLt.js +66 -0
  18. package/lib/body-limit.js +1 -65
  19. package/lib/buffer-CkEOJCcY.js +51 -0
  20. package/lib/bun.js +3 -3
  21. package/lib/cache-B0bHH7s5.js +169 -0
  22. package/lib/cache.js +1 -168
  23. package/lib/{client-DDLXwhBo.js → client-BrMFnMEd.js} +1 -1
  24. package/lib/{client-modules-CLvWOjbd.js → client-modules-drj4mjhj.js} +4 -4
  25. package/lib/client.js +1 -1
  26. package/lib/color-COa3DplO.js +37 -0
  27. package/lib/combine-TWuGdcbC.js +137 -0
  28. package/lib/combine.js +1 -136
  29. package/lib/{components-cEW3ovK0.js → components-B2ka9Ax1.js} +4 -4
  30. package/lib/{components-JXVm45kK.js → components-PVXwaOaC.js} +2 -2
  31. package/lib/compress-BzWqsHF1.js +79 -0
  32. package/lib/compress-C-9vK4B2.d.ts +11 -0
  33. package/lib/compress-DCyrrQ5D.js +11 -0
  34. package/lib/compress.d.ts +1 -1
  35. package/lib/compress.js +2 -78
  36. package/lib/concurrent-DrF3d2c-.js +30 -0
  37. package/lib/conninfo-BCROmdnf.d.ts +11 -0
  38. package/lib/conninfo-CWJwieh4.js +19 -0
  39. package/lib/constants-CBSEudrb.js +7 -0
  40. package/lib/{context-DDO0cfuP.js → context-CkOh7Ygv.js} +2 -2
  41. package/lib/context-storage-iuPoI_CR.js +52 -0
  42. package/lib/context-storage.js +1 -51
  43. package/lib/cookie-B1LlkzOe.js +125 -0
  44. package/lib/cookie-BHIduy2T.js +82 -0
  45. package/lib/cookie.js +1 -81
  46. package/lib/cordis/db-sqlite.d.ts +1 -1
  47. package/lib/cordis/door.d.ts +9 -1
  48. package/lib/cordis/door.js +39 -8
  49. package/lib/cordis/inspect.js +4 -4
  50. package/lib/cordis/kv-db.d.ts +1 -1
  51. package/lib/cordis/kv-db.js +1 -1
  52. package/lib/cordis/kv-json.d.ts +1 -1
  53. package/lib/cordis/kv-json.js +1 -1
  54. package/lib/cordis/node-server.d.ts +1 -1
  55. package/lib/cordis/node-server.js +3 -116
  56. package/lib/cordis/router-http.js +2 -2
  57. package/lib/cordis/router.js +4 -4
  58. package/lib/cordis/state.js +7 -7
  59. package/lib/{core-CaY8XDZ6.js → core-BOu1jYua.js} +1 -1
  60. package/lib/cors-CbAQ-8qU.js +106 -0
  61. package/lib/cors.js +1 -105
  62. package/lib/crypto-iVP-N-tS.js +34 -0
  63. package/lib/csrf-DqqOZtgy.js +101 -0
  64. package/lib/csrf.js +1 -100
  65. package/lib/css-C5CPVMvM.js +134 -0
  66. package/lib/css.js +2 -133
  67. package/lib/db/sqlite.d.ts +1 -25
  68. package/lib/dev-CLgu-JRe.js +50 -0
  69. package/lib/dev.js +1 -49
  70. package/lib/dom-YjND9Jt3.js +74 -0
  71. package/lib/door/host.js +1 -1
  72. package/lib/door/page.js +1 -1
  73. package/lib/door/protocol.js +1 -212
  74. package/lib/encode-BhbNLrjp.js +33 -0
  75. package/lib/factory-CLdSf-xS.js +30 -0
  76. package/lib/factory.js +1 -29
  77. package/lib/handler-C0wZ0KwO.js +12 -0
  78. package/lib/helpers-BEjcdbgw.js +5 -0
  79. package/lib/{hooks-w72iLeFR.js → hooks-CfC07ri0.js} +1 -1
  80. package/lib/html-CgNa89xw.js +31 -0
  81. package/lib/html-DGExBFNg.js +103 -0
  82. package/lib/html.d.ts +2 -5
  83. package/lib/html.js +2 -30
  84. package/lib/http-exception-MjWkT89V.js +54 -0
  85. package/lib/http-exception.js +1 -53
  86. package/lib/index-dAzQsJG9.d.ts +6 -0
  87. package/lib/index.js +3 -3
  88. package/lib/ip-restriction-jKtKCRM_.js +166 -0
  89. package/lib/ip-restriction.js +1 -165
  90. package/lib/ipaddr-DCoIo528.js +238 -0
  91. package/lib/jsx/dom/client.js +1 -1
  92. package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
  93. package/lib/jsx/dom/jsx-runtime.js +2 -1
  94. package/lib/jsx/dom/server.js +3 -3
  95. package/lib/jsx/dom.js +5 -73
  96. package/lib/jsx/jsx-dev-runtime.d.ts +2 -5
  97. package/lib/jsx/jsx-dev-runtime.js +2 -13
  98. package/lib/jsx/jsx-runtime.d.ts +2 -2
  99. package/lib/jsx/jsx-runtime.js +4 -4
  100. package/lib/jsx/streaming.js +1 -1
  101. package/lib/jsx-CUQgttxU.js +47 -0
  102. package/lib/jsx-dev-runtime-B4WTyq8r.js +14 -0
  103. package/lib/{jsx-dev-runtime-CWLRA2F3.js → jsx-dev-runtime-BLfA-EhI.js} +2 -2
  104. package/lib/jsx-dev-runtime-CGt4kNYr.d.ts +6 -0
  105. package/lib/jsx-renderer-CfifM4hT.js +99 -0
  106. package/lib/jsx-renderer.js +1 -98
  107. package/lib/jsx-runtime-COCRWBJ9.js +2 -0
  108. package/lib/jsx.js +5 -46
  109. package/lib/{jwk-LkzeoaU8.js → jwk-CDPpYQpD.js} +3 -3
  110. package/lib/jwk.js +1 -1
  111. package/lib/{jwt-BGJBw5AF.js → jwt-BXoIA2fQ.js} +2 -2
  112. package/lib/{jwt-CskdhEW9.js → jwt-lyS4Q3mT.js} +3 -3
  113. package/lib/jwt.js +2 -2
  114. package/lib/kv/db.d.ts +1 -10
  115. package/lib/kv/db.js +1 -56
  116. package/lib/kv/json.d.ts +1 -9
  117. package/lib/kv/json.js +1 -223
  118. package/lib/{language-D9a4zqvn.js → language-DeGRtLJt.js} +2 -2
  119. package/lib/language.js +1 -1
  120. package/lib/{linear-router-C3FPib6h.js → linear-router-CmZn_JLV.js} +2 -2
  121. package/lib/logger-Ckxu8diz.js +54 -0
  122. package/lib/logger.js +1 -53
  123. package/lib/loopback-only-BbasoF7R.js +90 -0
  124. package/lib/loopback-only.js +1 -89
  125. package/lib/method-not-allowed-TO2_hnfl.js +82 -0
  126. package/lib/method-not-allowed.js +1 -81
  127. package/lib/method-override-DnZKfJbV.js +103 -0
  128. package/lib/method-override.js +1 -102
  129. package/lib/middleware-BfG_fp8P.js +12 -0
  130. package/lib/mime-BnScXkQn.js +77 -0
  131. package/lib/mount-QkK_3NtJ.js +67 -0
  132. package/lib/mount.js +1 -66
  133. package/lib/node-server/conninfo.d.ts +1 -10
  134. package/lib/node-server/conninfo.js +1 -18
  135. package/lib/node-server/register.js +25 -2
  136. package/lib/node-server/serve-static.d.ts +1 -17
  137. package/lib/node-server/serve-static.js +1 -1
  138. package/lib/node-server.d.ts +2 -2
  139. package/lib/node-server.js +4 -4
  140. package/lib/open-BqK4D2Wn.d.ts +11 -0
  141. package/lib/open-But9E2rL.js +57 -0
  142. package/lib/open-CULVJgOc.d.ts +12 -0
  143. package/lib/open-Dp4sxspc.js +224 -0
  144. package/lib/open-T7kgbO2O.d.ts +27 -0
  145. package/lib/{pattern-router-HZxjDGEQ.js → pattern-router-CJBecJBd.js} +1 -1
  146. package/lib/powered-by-CXQNjNIX.js +24 -0
  147. package/lib/powered-by.js +1 -23
  148. package/lib/pretty-json-CeC1yvYt.js +39 -0
  149. package/lib/pretty-json.js +1 -38
  150. package/lib/protocol-Dt0AZBOz.js +213 -0
  151. package/lib/proxy-C2w_mH7k.js +121 -0
  152. package/lib/proxy.js +1 -120
  153. package/lib/quick.js +4 -4
  154. package/lib/{reg-exp-router-DC1R3qoY.js → reg-exp-router-C_WV84eV.js} +2 -2
  155. package/lib/request-DvMgGtlW.js +323 -0
  156. package/lib/request.js +1 -322
  157. package/lib/route-D8m-a2I1.js +126 -0
  158. package/lib/route.js +1 -125
  159. package/lib/router/linear-router.js +1 -1
  160. package/lib/router/pattern-router.js +1 -1
  161. package/lib/router/reg-exp-router.js +1 -1
  162. package/lib/router/smart-router.js +1 -1
  163. package/lib/router/trie-router.js +1 -1
  164. package/lib/router-Be_o6nFu.js +35 -0
  165. package/lib/router.js +1 -34
  166. package/lib/schema-validator-EK3cUUCt.js +22 -0
  167. package/lib/schema-validator.js +1 -21
  168. package/lib/{secure-headers-mP3j6Hm6.js → secure-headers-C5ZOcXqk.js} +1 -1
  169. package/lib/secure-headers.js +1 -1
  170. package/lib/serve-static-B7sqnftW.d.ts +18 -0
  171. package/lib/{serve-static-3uo_9rjF.js → serve-static-C1Nkj_xB.js} +2 -2
  172. package/lib/{serve-static-Cp5adzGo.js → serve-static-EiJf1zkO.js} +4 -4
  173. package/lib/serve-static.js +1 -1
  174. package/lib/{smart-router-C5CZ5XSM.js → smart-router-BjxkDQCE.js} +1 -1
  175. package/lib/{snapshot-text-BLz8nlSc.js → snapshot-text-Bbx43mN0.js} +9 -9
  176. package/lib/{src-dy3Fk9tA.js → src-BTBm4OPD.js} +6 -6
  177. package/lib/src-LX0E4ec4.js +117 -0
  178. package/lib/{ssg-BwjcA-Ge.js → ssg-BEl7MHqg.js} +5 -5
  179. package/lib/ssg.js +1 -1
  180. package/lib/stream-CzM_SHkq.js +88 -0
  181. package/lib/{streaming-DHST3Scg.js → streaming-BlDaph8U.js} +3 -3
  182. package/lib/streaming.js +1 -1
  183. package/lib/{test-websocket-D8WWqE5G.js → test-websocket-BLeEvybj.js} +2 -2
  184. package/lib/testing-BQx5T_UX.js +17 -0
  185. package/lib/testing.js +1 -16
  186. package/lib/timeout-FeqZ9A-0.js +42 -0
  187. package/lib/timeout.js +1 -41
  188. package/lib/tiny.js +2 -2
  189. package/lib/trailing-slash-DwTx-1sk.js +85 -0
  190. package/lib/trailing-slash.js +1 -84
  191. package/lib/{trie-router-CfFbapzL.js → trie-router-JydLKUa2.js} +2 -2
  192. package/lib/url-BPh4d6j-.js +197 -0
  193. package/lib/utils/accept.js +1 -192
  194. package/lib/utils/basic-auth.js +1 -19
  195. package/lib/utils/body.js +1 -93
  196. package/lib/utils/buffer.js +1 -50
  197. package/lib/utils/color.js +1 -36
  198. package/lib/utils/compress.d.ts +1 -10
  199. package/lib/utils/compress.js +1 -10
  200. package/lib/utils/concurrent.js +1 -29
  201. package/lib/utils/constants.js +1 -6
  202. package/lib/utils/cookie.js +1 -124
  203. package/lib/utils/crypto.js +1 -33
  204. package/lib/utils/encode.js +1 -32
  205. package/lib/utils/handler.js +1 -11
  206. package/lib/utils/html.js +1 -102
  207. package/lib/utils/ipaddr.js +1 -237
  208. package/lib/utils/jwt.js +1 -1
  209. package/lib/utils/mime.js +1 -76
  210. package/lib/utils/stream.js +1 -87
  211. package/lib/utils/url.js +1 -196
  212. package/lib/{validator-D84mq-dO.js → validator-Btiyt5VJ.js} +3 -3
  213. package/lib/validator.js +1 -1
  214. package/lib/websocket-DsyBIKVA.js +56 -0
  215. package/lib/ws.js +1 -55
  216. package/package.json +1 -1
  217. package/plugins/acryl-door/src/host/chat-tools.ts +2 -0
  218. package/plugins/acryl-door/src/host/door.ts +19 -2
  219. package/plugins/acryl-door/src/index.ts +15 -2
  220. package/plugins/acryl-node-server/src/register.ts +29 -2
  221. package/plugins/agent/model.ts +6 -1
  222. package/plugins/agent/tools.ts +12 -2
  223. package/plugins/agent-panel/client/describe.ts +44 -0
  224. package/plugins/agent-panel/client/main.ts +4 -1
  225. package/plugins/agent-panel/index.ts +22 -10
  226. package/plugins/desktop/attach.ts +72 -0
  227. package/plugins/desktop/main.ts +17 -4
  228. package/plugins/extensions/index.ts +3 -4
  229. package/plugins/extensions/stage.ts +33 -5
  230. package/plugins/openai/index.ts +1 -1
  231. package/templates/agent/AGENTS.md +2 -0
  232. package/templates/agent/blend.yaml +4 -1
  233. package/templates/agent/src/app.ts +2 -0
  234. package/templates/agent/src/routes.ts +1 -1
  235. package/templates/agent/template.json +1 -0
  236. package/templates/agent/test/builder.test.ts +26 -21
  237. package/lib/helpers-CvTauQT5.js +0 -5
  238. package/lib/middleware-CPQ8himN.js +0 -12
package/lib/utils/mime.js CHANGED
@@ -1,77 +1,2 @@
1
- //#region ../../plugins/acryl-router/src/core/utils/mime.ts
2
- /**
3
- * @module
4
- * MIME utility.
5
- */
6
- const getMimeType = (filename, mimes = baseMimes) => {
7
- const match = filename.match(/\.([a-zA-Z0-9]+?)$/);
8
- if (!match) return;
9
- return mimes[match[1].toLowerCase()];
10
- };
11
- const getExtension = (mimeType) => {
12
- const baseType = mimeType.split(";", 1)[0].trim();
13
- for (const ext in baseMimes) {
14
- const stored = baseMimes[ext];
15
- if (stored === mimeType || stored.split(";", 1)[0].trim() === baseType) return ext;
16
- }
17
- };
18
- const baseMimes = {
19
- aac: "audio/aac",
20
- avi: "video/x-msvideo",
21
- avif: "image/avif",
22
- av1: "video/av1",
23
- bin: "application/octet-stream",
24
- bmp: "image/bmp",
25
- css: "text/css; charset=utf-8",
26
- csv: "text/csv; charset=utf-8",
27
- eot: "application/vnd.ms-fontobject",
28
- epub: "application/epub+zip",
29
- gif: "image/gif",
30
- gz: "application/gzip",
31
- htm: "text/html; charset=utf-8",
32
- html: "text/html; charset=utf-8",
33
- ico: "image/x-icon",
34
- ics: "text/calendar; charset=utf-8",
35
- jpeg: "image/jpeg",
36
- jpg: "image/jpeg",
37
- js: "text/javascript; charset=utf-8",
38
- json: "application/json",
39
- jsonld: "application/ld+json",
40
- map: "application/json",
41
- mid: "audio/x-midi",
42
- midi: "audio/x-midi",
43
- mjs: "text/javascript; charset=utf-8",
44
- mp3: "audio/mpeg",
45
- mp4: "video/mp4",
46
- mpeg: "video/mpeg",
47
- oga: "audio/ogg",
48
- ogv: "video/ogg",
49
- ogx: "application/ogg",
50
- opus: "audio/opus",
51
- otf: "font/otf",
52
- pdf: "application/pdf",
53
- png: "image/png",
54
- rtf: "application/rtf",
55
- svg: "image/svg+xml; charset=utf-8",
56
- tif: "image/tiff",
57
- tiff: "image/tiff",
58
- ts: "video/mp2t",
59
- ttf: "font/ttf",
60
- txt: "text/plain; charset=utf-8",
61
- wasm: "application/wasm",
62
- webm: "video/webm",
63
- weba: "audio/webm",
64
- webmanifest: "application/manifest+json",
65
- webp: "image/webp",
66
- woff: "font/woff",
67
- woff2: "font/woff2",
68
- xhtml: "application/xhtml+xml; charset=utf-8",
69
- xml: "application/xml; charset=utf-8",
70
- zip: "application/zip",
71
- "3gp": "video/3gpp",
72
- "3g2": "video/3gpp2",
73
- gltf: "model/gltf+json",
74
- glb: "model/gltf-binary"
75
- };
76
- //#endregion
1
+ import { n as getExtension, r as getMimeType, t as baseMimes } from "../mime-BnScXkQn.js";
77
2
  export { getExtension, getMimeType, baseMimes as mimes };
@@ -1,88 +1,2 @@
1
- //#region ../../plugins/acryl-router/src/core/utils/stream.ts
2
- /**
3
- * @module
4
- * Stream utility.
5
- */
6
- var StreamingApi = class {
7
- writer;
8
- encoder;
9
- writable;
10
- abortSubscribers = [];
11
- responseReadable;
12
- /**
13
- * Whether the stream has been aborted.
14
- */
15
- aborted = false;
16
- /**
17
- * Whether the stream has been closed normally.
18
- */
19
- closed = false;
20
- constructor(writable, _readable) {
21
- this.writable = writable;
22
- this.writer = writable.getWriter();
23
- this.encoder = new TextEncoder();
24
- const reader = _readable.getReader();
25
- this.abortSubscribers.push(async () => {
26
- await reader.cancel();
27
- });
28
- this.responseReadable = new ReadableStream({
29
- async pull(controller) {
30
- const { done, value } = await reader.read();
31
- done ? controller.close() : controller.enqueue(value);
32
- },
33
- cancel: () => {
34
- if (!this.closed) this.abort();
35
- }
36
- });
37
- }
38
- async write(input) {
39
- try {
40
- if (typeof input === "string") input = this.encoder.encode(input);
41
- await this.writer.write(input);
42
- } catch {}
43
- return this;
44
- }
45
- async writeln(input) {
46
- await this.write(input + "\n");
47
- return this;
48
- }
49
- sleep(ms) {
50
- return new Promise((res) => setTimeout(res, ms));
51
- }
52
- async close() {
53
- this.closed = true;
54
- try {
55
- await this.writer.close();
56
- } catch {}
57
- }
58
- async pipe(body) {
59
- this.writer.releaseLock();
60
- try {
61
- await body.pipeTo(this.writable, {
62
- preventClose: true,
63
- preventAbort: true
64
- });
65
- } finally {
66
- this.writer = this.writable.getWriter();
67
- }
68
- }
69
- onAbort(listener) {
70
- this.abortSubscribers.push(listener);
71
- }
72
- /**
73
- * Abort the stream.
74
- * You can call this method when stream is aborted by external event.
75
- */
76
- abort() {
77
- if (!this.aborted) {
78
- this.aborted = true;
79
- this.abortSubscribers.forEach((subscriber) => {
80
- try {
81
- Promise.resolve(subscriber()).catch(() => {});
82
- } catch {}
83
- });
84
- }
85
- }
86
- };
87
- //#endregion
1
+ import { t as StreamingApi } from "../stream-CzM_SHkq.js";
88
2
  export { StreamingApi };
package/lib/utils/url.js CHANGED
@@ -1,197 +1,2 @@
1
- //#region ../../plugins/acryl-router/src/core/utils/url.ts
2
- const splitPath = (path) => {
3
- const paths = path.split("/");
4
- if (paths[0] === "") paths.shift();
5
- return paths;
6
- };
7
- const splitRoutingPath = (routePath) => {
8
- const { groups, path } = extractGroupsFromPath(routePath);
9
- const paths = splitPath(path);
10
- return replaceGroupMarks(paths, groups);
11
- };
12
- const extractGroupsFromPath = (path) => {
13
- const groups = [];
14
- path = path.replace(/\{[^}]+\}/g, (match, index) => {
15
- const mark = `@${index}`;
16
- groups.push([mark, match]);
17
- return mark;
18
- });
19
- return {
20
- groups,
21
- path
22
- };
23
- };
24
- const replaceGroupMarks = (paths, groups) => {
25
- for (let i = groups.length - 1; i >= 0; i--) {
26
- const [mark] = groups[i];
27
- for (let j = paths.length - 1; j >= 0; j--) if (paths[j].includes(mark)) {
28
- paths[j] = paths[j].replace(mark, groups[i][1]);
29
- break;
30
- }
31
- }
32
- return paths;
33
- };
34
- const patternCache = {};
35
- const getPattern = (label, next) => {
36
- if (label === "*") return "*";
37
- const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
38
- if (match) {
39
- const cacheKey = `${label}#${next}`;
40
- if (!patternCache[cacheKey]) if (match[2]) patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
41
- cacheKey,
42
- match[1],
43
- new RegExp(`^${match[2]}(?=/${next})`)
44
- ] : [
45
- label,
46
- match[1],
47
- new RegExp(`^${match[2]}$`)
48
- ];
49
- else patternCache[cacheKey] = [
50
- label,
51
- match[1],
52
- true
53
- ];
54
- return patternCache[cacheKey];
55
- }
56
- return null;
57
- };
58
- const tryDecode = (str, decoder) => {
59
- try {
60
- return decoder(str);
61
- } catch {
62
- return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
63
- try {
64
- return decoder(match);
65
- } catch {
66
- return match;
67
- }
68
- });
69
- }
70
- };
71
- /**
72
- * Try to apply decodeURI() to given string.
73
- * If it fails, skip invalid percent encoding or invalid UTF-8 sequences, and apply decodeURI() to the rest as much as possible.
74
- * @param str The string to decode.
75
- * @returns The decoded string that sometimes contains undecodable percent encoding.
76
- * @example
77
- * tryDecodeURI('Hello%20World') // 'Hello World'
78
- * tryDecodeURI('Hello%20World/%A4%A2') // 'Hello World/%A4%A2'
79
- */
80
- const tryDecodeURI = (str) => tryDecode(str, decodeURI);
81
- const getPath = (request) => {
82
- const url = request.url;
83
- const start = url.indexOf("/", url.indexOf(":") + 4);
84
- let i = start;
85
- for (; i < url.length; i++) {
86
- const charCode = url.charCodeAt(i);
87
- if (charCode === 37) {
88
- const queryIndex = url.indexOf("?", i);
89
- const hashIndex = url.indexOf("#", i);
90
- const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
91
- const path = url.slice(start, end);
92
- return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
93
- } else if (charCode === 63 || charCode === 35) break;
94
- }
95
- return url.slice(start, i);
96
- };
97
- /**
98
- * @deprecated
99
- * Use the `URL` API instead.
100
- */
101
- const getQueryStrings = (url) => {
102
- const queryIndex = url.indexOf("?", 8);
103
- if (queryIndex === -1) return "";
104
- const hashIndex = url.indexOf("#", 8);
105
- return hashIndex === -1 ? url.slice(queryIndex) : queryIndex < hashIndex ? url.slice(queryIndex, hashIndex) : "";
106
- };
107
- const getPathNoStrict = (request) => {
108
- const result = getPath(request);
109
- return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
110
- };
111
- /**
112
- * Merge paths.
113
- * @param {string[]} ...paths - The paths to merge.
114
- * @returns {string} The merged path.
115
- * @example
116
- * mergePath('/api', '/users') // '/api/users'
117
- * mergePath('/api/', '/users') // '/api/users'
118
- * mergePath('/api', '/') // '/api'
119
- * mergePath('/api/', '/') // '/api/'
120
- */
121
- const mergePath = (base, sub, ...rest) => {
122
- if (rest.length) sub = mergePath(sub, ...rest);
123
- return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
124
- };
125
- const checkOptionalParameter = (path) => {
126
- if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
127
- const segments = path.split("/");
128
- const results = [];
129
- let basePath = "";
130
- segments.forEach((segment) => {
131
- if (segment !== "" && !/\:/.test(segment)) basePath += "/" + segment;
132
- else if (/\:/.test(segment)) if (segment.charCodeAt(segment.length - 1) === 63) {
133
- if (results.length === 0 && basePath === "") results.push("/");
134
- else results.push(basePath);
135
- const optionalSegment = segment.slice(0, -1);
136
- basePath += "/" + optionalSegment;
137
- results.push(basePath);
138
- } else basePath += "/" + segment;
139
- });
140
- return results.filter((v, i, a) => a.indexOf(v) === i);
141
- };
142
- const tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
143
- const _decodeURI = (value) => {
144
- if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
145
- return tryDecodeURIComponent(value);
146
- };
147
- const _getQueryParam = (url, key, multiple) => {
148
- const hashIndex = url.indexOf("#", 8);
149
- if (hashIndex !== -1) url = url.slice(0, hashIndex);
150
- let encoded;
151
- if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
152
- let keyIndex = url.indexOf("?", 8);
153
- if (keyIndex === -1) return;
154
- if (!url.startsWith(key, keyIndex + 1)) keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
155
- while (keyIndex !== -1) {
156
- const trailingKeyCode = url.charCodeAt(keyIndex + key.length + 1);
157
- if (trailingKeyCode === 61) {
158
- const valueIndex = keyIndex + key.length + 2;
159
- const endIndex = url.indexOf("&", valueIndex);
160
- return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
161
- } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) return "";
162
- keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
163
- }
164
- encoded = /[%+]/.test(url);
165
- if (!encoded) return;
166
- }
167
- const results = Object.create(null);
168
- encoded ??= /[%+]/.test(url);
169
- let keyIndex = url.indexOf("?", 8);
170
- while (keyIndex !== -1) {
171
- const nextKeyIndex = url.indexOf("&", keyIndex + 1);
172
- let valueIndex = url.indexOf("=", keyIndex);
173
- if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
174
- let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
175
- if (encoded) name = _decodeURI(name);
176
- keyIndex = nextKeyIndex;
177
- if (name === "") continue;
178
- let value;
179
- if (valueIndex === -1) value = "";
180
- else {
181
- value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
182
- if (encoded) value = _decodeURI(value);
183
- }
184
- if (multiple) {
185
- if (!(results[name] && Array.isArray(results[name]))) results[name] = [];
186
- results[name].push(value);
187
- } else results[name] ??= value;
188
- }
189
- return key ? results[key] : results;
190
- };
191
- const getQueryParam = _getQueryParam;
192
- const getQueryParams = (url, key) => {
193
- return _getQueryParam(url, key, true);
194
- };
195
- const decodeURIComponent_ = decodeURIComponent;
196
- //#endregion
1
+ import { a as getPattern, c as getQueryStrings, d as splitRoutingPath, f as tryDecode, i as getPathNoStrict, l as mergePath, m as tryDecodeURIComponent, n as decodeURIComponent_, o as getQueryParam, p as tryDecodeURI, r as getPath, s as getQueryParams, t as checkOptionalParameter, u as splitPath } from "../url-BPh4d6j-.js";
197
2
  export { checkOptionalParameter, decodeURIComponent_, getPath, getPathNoStrict, getPattern, getQueryParam, getQueryParams, getQueryStrings, mergePath, splitPath, splitRoutingPath, tryDecode, tryDecodeURI, tryDecodeURIComponent };
@@ -1,6 +1,6 @@
1
- import { HTTPException } from "./http-exception.js";
2
- import { bufferToFormData } from "./utils/buffer.js";
3
- import { getCookie } from "./cookie.js";
1
+ import { t as HTTPException } from "./http-exception-MjWkT89V.js";
2
+ import { t as bufferToFormData } from "./buffer-CkEOJCcY.js";
3
+ import { i as getCookie } from "./cookie-BHIduy2T.js";
4
4
  //#region ../../plugins/acryl-router/src/core/validator/validator.ts
5
5
  const jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/i;
6
6
  const multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/i;
package/lib/validator.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as validator } from "./validator-D84mq-dO.js";
1
+ import { t as validator } from "./validator-Btiyt5VJ.js";
2
2
  export { validator };
@@ -0,0 +1,56 @@
1
+ //#region ../../plugins/acryl-router/src/core/helper/websocket/index.ts
2
+ /**
3
+ * A context for controlling WebSockets
4
+ */
5
+ var WSContext = class {
6
+ #init;
7
+ constructor(init) {
8
+ this.#init = init;
9
+ this.raw = init.raw;
10
+ this.url = init.url ? new URL(init.url) : null;
11
+ this.protocol = init.protocol ?? null;
12
+ }
13
+ send(source, options) {
14
+ this.#init.send(source, options ?? {});
15
+ }
16
+ raw;
17
+ binaryType = "arraybuffer";
18
+ get readyState() {
19
+ return this.#init.readyState;
20
+ }
21
+ get bufferedAmount() {
22
+ return this.#init.bufferedAmount ?? 0;
23
+ }
24
+ url;
25
+ protocol;
26
+ close(code, reason) {
27
+ this.#init.close(code, reason);
28
+ }
29
+ };
30
+ const createWSMessageEvent = (source) => {
31
+ return new MessageEvent("message", { data: source });
32
+ };
33
+ /**
34
+ * Create a WebSocket adapter/helper
35
+ */
36
+ const defineWebSocketHelper = (handler) => {
37
+ return ((...args) => {
38
+ if (typeof args[0] === "function") {
39
+ const [createEvents, options] = args;
40
+ return async function upgradeWebSocket(c, next) {
41
+ const result = await handler(c, await createEvents(c), options);
42
+ if (result) return result;
43
+ await next();
44
+ };
45
+ } else {
46
+ const [c, events, options] = args;
47
+ return (async () => {
48
+ const upgraded = await handler(c, events, options);
49
+ if (!upgraded) throw new Error("Failed to upgrade WebSocket");
50
+ return upgraded;
51
+ })();
52
+ }
53
+ });
54
+ };
55
+ //#endregion
56
+ export { createWSMessageEvent as n, defineWebSocketHelper as r, WSContext as t };
package/lib/ws.js CHANGED
@@ -1,56 +1,2 @@
1
- //#region ../../plugins/acryl-router/src/core/helper/websocket/index.ts
2
- /**
3
- * A context for controlling WebSockets
4
- */
5
- var WSContext = class {
6
- #init;
7
- constructor(init) {
8
- this.#init = init;
9
- this.raw = init.raw;
10
- this.url = init.url ? new URL(init.url) : null;
11
- this.protocol = init.protocol ?? null;
12
- }
13
- send(source, options) {
14
- this.#init.send(source, options ?? {});
15
- }
16
- raw;
17
- binaryType = "arraybuffer";
18
- get readyState() {
19
- return this.#init.readyState;
20
- }
21
- get bufferedAmount() {
22
- return this.#init.bufferedAmount ?? 0;
23
- }
24
- url;
25
- protocol;
26
- close(code, reason) {
27
- this.#init.close(code, reason);
28
- }
29
- };
30
- const createWSMessageEvent = (source) => {
31
- return new MessageEvent("message", { data: source });
32
- };
33
- /**
34
- * Create a WebSocket adapter/helper
35
- */
36
- const defineWebSocketHelper = (handler) => {
37
- return ((...args) => {
38
- if (typeof args[0] === "function") {
39
- const [createEvents, options] = args;
40
- return async function upgradeWebSocket(c, next) {
41
- const result = await handler(c, await createEvents(c), options);
42
- if (result) return result;
43
- await next();
44
- };
45
- } else {
46
- const [c, events, options] = args;
47
- return (async () => {
48
- const upgraded = await handler(c, events, options);
49
- if (!upgraded) throw new Error("Failed to upgrade WebSocket");
50
- return upgraded;
51
- })();
52
- }
53
- });
54
- };
55
- //#endregion
1
+ import { n as createWSMessageEvent, r as defineWebSocketHelper, t as WSContext } from "./websocket-DsyBIKVA.js";
56
2
  export { WSContext, createWSMessageEvent, defineWebSocketHelper };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acrylblends",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "The Acryl web framework (import { Acryl } from \"acrylblends\") and the acrylblends command that scaffolds Cordis apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,6 +20,8 @@ export function registerChatTools(tools: ToolsPort, door: Door): () => void {
20
20
  for (const verb of VERBS) {
21
21
  removers.push(tools.register(chatToolName(verb), {
22
22
  description: VERB_SPECS[verb].description,
23
+ // The model is told which fields the verb takes (an `act` needs its `op`), the same schema MCP lists.
24
+ parameters: VERB_SPECS[verb].arguments as unknown as Readonly<Record<string, unknown>>,
23
25
  run: async (input: unknown) => {
24
26
  try {
25
27
  return (await door.run(verb, input ?? {}, running.signal)).text
@@ -35,7 +35,7 @@ export interface ExtensionsPort {
35
35
  /** The slice of acrylblends' `tools` registry (the `agent` plugin's) the tool verbs use, and where the built-in chat finds the verbs. */
36
36
  export interface ToolsPort {
37
37
  /** @returns the function that removes the tool. @throws when the name is taken. */
38
- register(name: string, tool: { readonly description: string; run(input: unknown): unknown }): () => void
38
+ register(name: string, tool: { readonly description: string; readonly parameters?: Readonly<Record<string, unknown>>; run(input: unknown): unknown }): () => void
39
39
  list(): ReadonlyArray<{ readonly name: string; readonly description: string }>
40
40
  call(name: string, input: unknown): Promise<unknown>
41
41
  }
@@ -148,7 +148,24 @@ export class Door {
148
148
  answer = { ok: true, detail: request.op === 'reload' ? 'reloading' : `going to ${request.path}` }
149
149
  }
150
150
  if (!await back) throw new UiControlError('timeout', request.op === 'reload' ? 'the page did not come back after the reload' : `the page did not come back after going to ${request.path}: is there a page at that path, and does it load the door's script?`)
151
- return { ...answer, detail: `${answer.detail ?? 'done'}; the page is back: look again` }
151
+ const landed = request.op === 'navigate' ? await this.statusAt(request.path) : undefined
152
+ return { ...answer, detail: `${answer.detail ?? 'done'}${landed === undefined ? '' : `; ${landed}`}; the page is back: look again` }
153
+ }
154
+
155
+ /**
156
+ * What the app answers at a path the page was sent to, so an agent that mistyped one is told ("404 at /nope") and not left to find out from a page it did not expect.
157
+ * A second GET of the same path (a page is read-only); nothing when the app has no address or does not answer in time.
158
+ */
159
+ private async statusAt(path: string): Promise<string | undefined> {
160
+ const base = this.deps.app.url
161
+ if (base === undefined) return undefined
162
+ try {
163
+ const response = await fetch(new URL(path, base), { headers: { accept: 'text/html' }, signal: AbortSignal.timeout(3000) })
164
+ await response.body?.cancel()
165
+ return response.ok ? `${response.status} at ${path}` : `${response.status} at ${path}: the app serves no page there, look at what is shown and navigate to a path it does`
166
+ } catch {
167
+ return undefined
168
+ }
152
169
  }
153
170
 
154
171
  private parse(input: Record<string, unknown>): UiRequest {
@@ -94,6 +94,13 @@ function loopbackUrl(url: string): string {
94
94
  return parsed.origin
95
95
  }
96
96
 
97
+ const escapeHtml = (text: string): string => text.replace(/[&<>"']/gu, char => `&#${char.charCodeAt(0)};`)
98
+
99
+ /** The page of a path the app does not serve, development only: what is missing, a way back, and the door's script. */
100
+ export function notFoundPage(path: string, scriptTag: string): string {
101
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>404 Not Found</title></head><body><main><h1>404 Not Found</h1><p>This app has no page at <code>${escapeHtml(path)}</code>.</p><p><a href="/">Back to the app</a></p></main>${scriptTag}</body></html>`
102
+ }
103
+
97
104
  export function apply(ctx: Context, rawConfig: Config = {}): void {
98
105
  const config = Config(rawConfig)
99
106
  // Development only: nothing is started, mounted or written in production, or when switched off.
@@ -124,9 +131,15 @@ export function apply(ctx: Context, rawConfig: Config = {}): void {
124
131
  // The page script on every HTML page the app answers, whenever its plugin was mounted (the pages of a plugin that loaded at boot, before this one, included): a page an agent writes
125
132
  // can be looked at and driven without anyone adding the tag. A page that already carries it (the templates' own pages) is left as it is. Development only, like the rest of the door.
126
133
  const tag = `<script type="module" src="${DOOR_PREFIX}/page.js"></script>`
127
- const addScript = async (c: { res: Response }, next: () => Promise<void>): Promise<void> => {
134
+ const addScript = async (c: { res: Response; req: { path: string; header(name: string): string | undefined } }, next: () => Promise<void>): Promise<void> => {
128
135
  await next()
129
- if (!(c.res.headers.get('content-type') ?? '').includes('text/html')) return
136
+ if (!(c.res.headers.get('content-type') ?? '').includes('text/html')) {
137
+ // A path the app does not serve, opened as a page: the browser would show a bare "404 Not Found" with no script, and the window would be left where nothing can look at it or
138
+ // act on it (an agent that mistypes a path would need a person to bring the window back). The page says what is missing, carries the script, and keeps the 404.
139
+ if (c.res.status === 404 && (c.req.header('accept') ?? '').includes('text/html') && !(c.res.headers.get('content-type') ?? '').includes('json'))
140
+ c.res = new Response(notFoundPage(c.req.path, tag), { status: 404, headers: { 'content-type': 'text/html; charset=utf-8' } })
141
+ return
142
+ }
130
143
  const html = await c.res.text()
131
144
  const headers = new Headers(c.res.headers)
132
145
  headers.delete('content-length')
@@ -7,9 +7,9 @@
7
7
  * `typescript` is loaded from the app, on the first JSX file only; the framework itself has no dependencies.
8
8
  */
9
9
 
10
+ import { existsSync, readFileSync } from 'node:fs'
10
11
  import { registerHooks } from 'node:module'
11
- import { readFileSync } from 'node:fs'
12
- import { fileURLToPath } from 'node:url'
12
+ import { fileURLToPath, pathToFileURL } from 'node:url'
13
13
  import { compileModule } from './transpile.ts'
14
14
 
15
15
  /** The JSX runtime the docs set up; an app's tsconfig.json (or a file's own `@jsxImportSource` pragma) chooses another. */
@@ -27,3 +27,30 @@ registerHooks({
27
27
  return { format: 'module', source, shortCircuit: true }
28
28
  },
29
29
  })
30
+
31
+ /**
32
+ * The framework's names for a file of the app: in an app the framework plugins are source under `plugins/`, not packages, so `acrylblends`, `acrylblends/body-limit` or `acryl-router`
33
+ * have nowhere to resolve from. A plugin installed while the app runs gets them from the extensions plugin; a plugin that is a ROW of `blend.yaml` is imported by `src/app.ts` before
34
+ * any of that exists, so the same names are resolved here, in the preload every `dev`, `start` and `test` script runs. Only a name that Node cannot resolve itself, only for the
35
+ * app's own files (never for something in `node_modules`), and only in an app that has the framework as vendored source: the published package resolves its own names.
36
+ */
37
+ const plugins = new URL('../../', import.meta.url)
38
+ const appRoot = new URL('../', plugins).href
39
+ const resolver = new URL('extensions/resolve.ts', plugins)
40
+ if (existsSync(fileURLToPath(new URL('acryl-router/src/index.ts', plugins))) && existsSync(fileURLToPath(resolver))) {
41
+ const { routerAliases } = (await import(resolver.href)) as { routerAliases(): Record<string, string> }
42
+ const aliases = routerAliases()
43
+ registerHooks({
44
+ resolve(specifier, context, nextResolve) {
45
+ try {
46
+ return nextResolve(specifier, context)
47
+ } catch (error) {
48
+ const alias = aliases[specifier]
49
+ const parent = context.parentURL
50
+ if (alias !== undefined && parent?.startsWith(appRoot) && !parent.includes('/node_modules/'))
51
+ return nextResolve(pathToFileURL(alias).href, context)
52
+ throw error
53
+ }
54
+ },
55
+ })
56
+ }
@@ -21,7 +21,12 @@ export interface ModelInput {
21
21
  readonly reasoning?: string
22
22
  }>
23
23
  /** The tools the model may call. */
24
- readonly tools?: ReadonlyArray<{ readonly name: string; readonly description: string }>
24
+ readonly tools?: ReadonlyArray<{
25
+ readonly name: string
26
+ readonly description: string
27
+ /** The JSON Schema of the tool's input, when it has one. */
28
+ readonly parameters?: Readonly<Record<string, unknown>>
29
+ }>
25
30
  /** Aborts when the run is cancelled: a provider that can stop its request passes this on. */
26
31
  readonly signal?: AbortSignal
27
32
  }
@@ -3,6 +3,8 @@ import type { Context } from '@deepseek-ai/cordis'
3
3
  /** One tool: what it does (for the model) and how to run it. */
4
4
  export interface Tool {
5
5
  readonly description: string
6
+ /** The JSON Schema of the input (an object schema), sent to a real model so it knows which fields the tool takes. A tool without one takes any object. */
7
+ readonly parameters?: Readonly<Record<string, unknown>>
6
8
  /** `options.signal` aborts when the run is cancelled; a tool that can stop its work listens to it. */
7
9
  run(input: unknown, options?: { signal?: AbortSignal }): unknown | Promise<unknown>
8
10
  }
@@ -11,7 +13,11 @@ export interface Tool {
11
13
  export interface Tools {
12
14
  /** Register a tool. Returns the function that removes it. */
13
15
  register(name: string, tool: Tool): () => void
14
- list(): Array<{ name: string; description: string }>
16
+ list(): Array<{
17
+ name: string
18
+ description: string
19
+ parameters?: Readonly<Record<string, unknown>>
20
+ }>
15
21
  call(name: string, input: unknown, options?: { signal?: AbortSignal }): Promise<unknown>
16
22
  }
17
23
 
@@ -31,7 +37,11 @@ export function tools(ctx: Context) {
31
37
  return () => void table.delete(name)
32
38
  },
33
39
  list: () =>
34
- [...table.entries()].map(([name, tool]) => ({ name, description: tool.description })),
40
+ [...table.entries()].map(([name, tool]) => ({
41
+ name,
42
+ description: tool.description,
43
+ ...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),
44
+ })),
35
45
  async call(name, input, options) {
36
46
  const tool = table.get(name)
37
47
  if (!tool) throw new Error(`unknown tool "${name}"`)