acrylblends 1.0.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/index.d.ts +60 -2
- package/dist/index.js +1992 -33
- package/dist/index.js.map +1 -1
- package/docs/framework/agents/index.md +1 -1
- package/docs/framework/api/summary.md +1 -1
- package/docs/framework/getting-started/desktop.md +23 -4
- package/docs/framework/guides/create-acrylblends.md +1 -1
- package/docs/framework/guides/production.md +20 -0
- package/docs/framework/workshop/README.md +174 -285
- package/docs/framework/workshop/facilitator.md +81 -90
- package/legacy/README.md +9 -0
- package/legacy/agent/157ce3db1112/src/app.ts +98 -0
- package/legacy/agent/157ce3db1112/src/routes.ts +63 -0
- package/legacy/agent/24c681a00fca/src/app.ts +160 -0
- package/legacy/agent/24c681a00fca/src/routes.ts +83 -0
- package/legacy/agent/2e790da977b2/src/app.ts +98 -0
- package/legacy/agent/2e790da977b2/src/routes.ts +63 -0
- package/legacy/agent/6307045545dc/src/app.ts +168 -0
- package/legacy/agent/6307045545dc/src/routes.ts +83 -0
- package/legacy/agent/6a5fb9c15c53/src/app.ts +158 -0
- package/legacy/agent/6a5fb9c15c53/src/routes.ts +83 -0
- package/legacy/agent/71fb54a5a942/src/app.ts +111 -0
- package/legacy/agent/71fb54a5a942/src/routes.ts +63 -0
- package/legacy/agent/74ece148269c/src/app.ts +168 -0
- package/legacy/agent/74ece148269c/src/routes.ts +93 -0
- package/legacy/agent/855359304707/src/app.ts +168 -0
- package/legacy/agent/855359304707/src/routes.ts +126 -0
- package/legacy/agent/b5ef3c786ae4/src/app.ts +127 -0
- package/legacy/agent/b5ef3c786ae4/src/routes.ts +76 -0
- package/legacy/agent/c2f30958043b/src/app.ts +98 -0
- package/legacy/agent/c2f30958043b/src/routes.ts +53 -0
- package/legacy/blank/5a91c558af22/src/routes.ts +18 -0
- package/legacy/blank/9c650cf52bf3/src/routes.ts +14 -0
- package/legacy/blank/aea589283445/src/routes.ts +16 -0
- package/legacy/blank/b2cbb759c889/src/routes.ts +16 -0
- package/legacy/blank/d6d371c9a65e/src/routes.ts +18 -0
- package/legacy/chat/7076cc821e2c/src/app.ts +72 -0
- package/legacy/chat/7076cc821e2c/src/routes.ts +13 -0
- package/legacy/chat/7dbe6d5170df/src/app.ts +107 -0
- package/legacy/chat/7dbe6d5170df/src/routes.ts +19 -0
- package/legacy/chat/a9a9ab44c58e/src/app.ts +107 -0
- package/legacy/chat/a9a9ab44c58e/src/routes.ts +15 -0
- package/legacy/chat/f20ad9a51b06/src/app.ts +106 -0
- package/legacy/chat/f20ad9a51b06/src/routes.ts +15 -0
- package/legacy/layouts.json +524 -0
- package/legacy/nodejs/1d477f37aaf4/src/app.ts +92 -0
- package/legacy/nodejs/1d477f37aaf4/src/routes.ts +40 -0
- package/legacy/nodejs/b1bd9462496c/src/app.ts +61 -0
- package/legacy/nodejs/b1bd9462496c/src/routes.ts +37 -0
- package/legacy/nodejs/d5bab75076ef/src/app.ts +95 -0
- package/legacy/nodejs/d5bab75076ef/src/routes.ts +40 -0
- package/legacy/notes/4edc36949c15/src/app.ts +107 -0
- package/legacy/notes/4edc36949c15/src/routes.ts +14 -0
- package/legacy/notes/6cab2d09747c/src/app.ts +72 -0
- package/legacy/notes/6cab2d09747c/src/routes.ts +12 -0
- package/legacy/notes/7ca2dfed623a/src/app.ts +106 -0
- package/legacy/notes/7ca2dfed623a/src/routes.ts +14 -0
- package/legacy/todo/02e613b3625c/src/app.ts +71 -0
- package/legacy/todo/02e613b3625c/src/todo.ts +123 -0
- package/legacy/todo/45694a8d9e15/src/app.ts +71 -0
- package/legacy/todo/45694a8d9e15/src/todo.ts +96 -0
- package/legacy/todo/5923d3a6099f/src/app.ts +71 -0
- package/legacy/todo/5923d3a6099f/src/todo.ts +125 -0
- package/legacy/todo/849a18d66dc1/src/app.ts +91 -0
- package/legacy/todo/849a18d66dc1/src/todo.ts +125 -0
- package/legacy/todo/8e64211312f3/src/app.ts +71 -0
- package/legacy/todo/8e64211312f3/src/todo.ts +125 -0
- package/legacy/todo/b79078a87565/src/app.ts +71 -0
- package/legacy/todo/b79078a87565/src/todo.ts +125 -0
- package/lib/{audit-Dw-siYTp.d.ts → audit-Bok_UNCn.d.ts} +41 -6
- package/lib/{client-modules-drj4mjhj.js → client-modules-Bkdr83jO.js} +1 -1
- package/lib/cordis/door.d.ts +44 -7
- package/lib/cordis/door.js +214 -60
- package/lib/cordis/inspect.js +1 -1
- package/lib/cordis/node-server.d.ts +101 -3
- package/lib/cordis/node-server.js +3 -3
- package/lib/cordis/router-http.d.ts +7 -1
- package/lib/cordis/router-http.js +44 -3
- package/lib/cordis/router.d.ts +1 -1
- package/lib/cordis/router.js +1 -1
- package/lib/cordis/state.d.ts +3 -2
- package/lib/cordis/state.js +371 -7
- package/lib/door/host.d.ts +2 -2
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +20 -1
- package/lib/door/page.js +75 -14
- package/lib/door/protocol.d.ts +1 -1
- package/lib/drivers.d.ts +10 -1
- package/lib/{index-DMOtA-NJ.d.ts → index-DGq7H0lb.d.ts} +11 -1
- package/lib/node-server.d.ts +7 -1
- package/lib/node-server.js +2 -2
- package/lib/{protocol-a2aqrp2X.d.ts → protocol-BeIYCgTo.d.ts} +4 -0
- package/lib/{snapshot-text-BfEbEOjA.js → snapshot-text-CXTnjxGx.js} +121 -9
- package/lib/src-CtkIX_Gg.js +427 -0
- package/lib/{src-BTBm4OPD.js → src-iBJ2ysV9.js} +77 -14
- package/lib/{test-websocket-BLeEvybj.js → test-websocket-CQOSvBth.js} +17 -7
- package/lib/{test-websocket-DyeS50Tr.d.ts → test-websocket-GUTAkFQT.d.ts} +3 -1
- package/package.json +2 -1
- package/plugins/acryl-door/src/host/channel.ts +124 -9
- package/plugins/acryl-door/src/host/chat-tools.ts +8 -6
- package/plugins/acryl-door/src/host/door-file.ts +7 -2
- package/plugins/acryl-door/src/host/door.ts +58 -23
- package/plugins/acryl-door/src/host/page-routes.ts +3 -1
- package/plugins/acryl-door/src/host/page-socket.ts +18 -8
- package/plugins/acryl-door/src/host/verbs.ts +3 -0
- package/plugins/acryl-door/src/index.ts +166 -29
- package/plugins/acryl-door/src/page/base.ts +32 -0
- package/plugins/acryl-door/src/page/channel.ts +11 -1
- package/plugins/acryl-door/src/page/driver/accessibility.ts +11 -0
- package/plugins/acryl-door/src/page/driver/actions.ts +4 -0
- package/plugins/acryl-door/src/page/driver/driver.ts +49 -7
- package/plugins/acryl-door/src/page/driver/snapshot.ts +5 -2
- package/plugins/acryl-door/src/page/index.ts +46 -2
- package/plugins/acryl-door/src/page/indicator.ts +14 -6
- package/plugins/acryl-door/src/page/outline.ts +56 -0
- package/plugins/acryl-door/src/page/protocol.ts +4 -0
- package/plugins/acryl-door/src/page/snapshot-text.ts +2 -1
- package/plugins/acryl-node-server/src/adapter/listener.ts +4 -0
- package/plugins/acryl-node-server/src/adapter/raw.ts +18 -0
- package/plugins/acryl-node-server/src/adapter/websocket.ts +15 -9
- package/plugins/acryl-node-server/src/client-modules.ts +7 -1
- package/plugins/acryl-node-server/src/index.ts +304 -16
- package/plugins/acryl-node-server/src/upgrade-hub.ts +2 -2
- package/plugins/acryl-page/plugin.json +12 -0
- package/plugins/acryl-page/src/index.ts +163 -0
- package/plugins/acryl-router/src/service.ts +77 -14
- package/plugins/acryl-router-http/src/index.ts +15 -1
- package/plugins/acryl-router-http/src/serve.ts +31 -0
- package/plugins/acryl-state/plugin.json +4 -3
- package/plugins/acryl-state/src/client-source.ts +244 -0
- package/plugins/acryl-state/src/service.ts +33 -6
- package/plugins/acryl-state/src/socket.ts +96 -0
- package/plugins/acryl-web-server/plugin.json +14 -0
- package/plugins/acryl-web-server/src/index.ts +164 -0
- package/plugins/agent/agent.ts +38 -7
- package/plugins/agent/index.ts +1 -1
- package/plugins/agent/model.ts +10 -2
- package/plugins/agent/tools.ts +9 -3
- package/plugins/agent-panel/client/describe.ts +57 -0
- package/plugins/agent-panel/client/driver-pick.ts +22 -0
- package/plugins/agent-panel/client/frame.ts +51 -0
- package/plugins/agent-panel/client/main.ts +343 -81
- package/plugins/agent-panel/drivers.ts +7 -2
- package/plugins/agent-panel/headless.ts +5 -2
- package/plugins/agent-panel/index.ts +187 -61
- package/plugins/agent-panel/mount.ts +27 -0
- package/plugins/agent-panel/visitors.ts +231 -0
- package/plugins/desktop/frame.ts +231 -0
- package/plugins/desktop/launch.ts +44 -9
- package/plugins/desktop/main.ts +100 -32
- package/plugins/desktop/window.ts +21 -4
- package/plugins/driver-pty/client/terminal.ts +4 -1
- package/plugins/driver-pty/index.ts +38 -11
- package/plugins/driver-pty/spawn.ts +38 -0
- package/plugins/driver-pty/terminal.ts +2 -0
- package/plugins/extensions/index.ts +26 -1
- package/plugins/extensions/resolve.ts +13 -0
- package/plugins/feedback/client.d.ts +22 -0
- package/plugins/feedback/client.js +471 -0
- package/plugins/feedback/index.ts +143 -0
- package/plugins/feedback/plugin.json +11 -0
- package/plugins/feedback/store.ts +307 -0
- package/plugins/home/index.ts +122 -0
- package/plugins/home/plugin.json +11 -0
- package/plugins/instance/index.ts +12 -3
- package/plugins/manifest/app-plugins.ts +86 -0
- package/plugins/manifest/index.ts +12 -2
- package/plugins/manifest/snapshot.ts +275 -0
- package/plugins/openai/index.ts +64 -5
- package/plugins/openai/prompt.ts +23 -0
- package/shared/AGENTS.core.md +36 -16
- package/shared/skills/acryl-add-ui/SKILL.md +19 -0
- package/shared/skills/acryl-app/SKILL.md +13 -0
- package/shared/skills/acryl-build-plugin/SKILL.md +22 -0
- package/shared/skills/acryl-change-plugin/SKILL.md +14 -0
- package/shared/skills/acryl-diagnose-plugin/SKILL.md +13 -0
- package/shared/skills/acryl-fix-plugin/SKILL.md +13 -0
- package/shared/skills/acryl-remove-plugin/SKILL.md +12 -0
- package/shared/skills/acryl-share-plugin/SKILL.md +16 -0
- package/shared/skills/cordis-plugin/SKILL.md +26 -0
- package/templates/agent/AGENTS.md +4 -2
- package/templates/agent/blend.yaml +4 -0
- package/templates/agent/gitignore +1 -0
- package/templates/agent/package.json +1 -0
- package/templates/agent/src/app.ts +150 -33
- package/templates/agent/src/frame.ts +17 -0
- package/templates/agent/src/main.ts +5 -3
- package/templates/agent/src/routes.ts +73 -21
- package/templates/agent/template.json +2 -0
- package/templates/agent/test/app.test.ts +83 -5
- package/templates/blank/AGENTS.md +3 -2
- package/templates/blank/blend.yaml +11 -0
- package/templates/blank/gitignore +1 -0
- package/templates/blank/package.json +1 -0
- package/templates/blank/src/app.ts +100 -29
- package/templates/blank/src/door.ts +7 -0
- package/templates/blank/src/first-page.ts +5 -0
- package/templates/blank/src/frame.ts +17 -0
- package/templates/blank/src/routes.ts +65 -8
- package/templates/blank/template.json +14 -1
- package/templates/blank/test/app.test.ts +103 -16
- package/templates/chat/blend.yaml +2 -1
- package/templates/chat/gitignore +1 -0
- package/templates/chat/package.json +1 -0
- package/templates/chat/src/app.ts +72 -22
- package/templates/chat/src/chat-app.ts +11 -2
- package/templates/chat/src/client/chat.tsx +4 -2
- package/templates/chat/src/frame.ts +17 -0
- package/templates/chat/src/main.ts +1 -6
- package/templates/chat/src/page.tsx +6 -4
- package/templates/chat/src/routes.ts +14 -4
- package/templates/chat/src/runtime.ts +9 -3
- package/templates/chat/template.json +3 -1
- package/templates/chat/test/chat.test.ts +46 -1
- package/templates/chat/test/server.test.ts +17 -3
- package/templates/nodejs/blend.yaml +2 -1
- package/templates/nodejs/gitignore +1 -0
- package/templates/nodejs/package.json +1 -0
- package/templates/nodejs/src/app.ts +76 -21
- package/templates/nodejs/src/frame.ts +17 -0
- package/templates/nodejs/src/main.ts +1 -6
- package/templates/nodejs/src/page.tsx +3 -3
- package/templates/nodejs/src/routes.ts +32 -13
- package/templates/nodejs/template.json +3 -1
- package/templates/nodejs/test/app.test.ts +38 -3
- package/templates/nodejs/test/server.test.ts +17 -3
- package/templates/notes/blend.yaml +2 -1
- package/templates/notes/gitignore +1 -0
- package/templates/notes/package.json +1 -0
- package/templates/notes/src/app.ts +72 -22
- package/templates/notes/src/frame.ts +17 -0
- package/templates/notes/src/main.ts +1 -6
- package/templates/notes/src/notes-app.ts +24 -17
- package/templates/notes/src/routes.ts +11 -4
- package/templates/notes/src/runtime.ts +9 -3
- package/templates/notes/src/views.tsx +26 -17
- package/templates/notes/template.json +3 -1
- package/templates/notes/test/notes.test.ts +39 -1
- package/templates/notes/test/server.test.ts +17 -3
- package/templates/todo/blend.yaml +3 -0
- package/templates/todo/gitignore +1 -0
- package/templates/todo/package.json +1 -0
- package/templates/todo/src/app.ts +81 -27
- package/templates/todo/src/door.ts +7 -0
- package/templates/todo/src/frame.ts +17 -0
- package/templates/todo/src/page.ts +13 -6
- package/templates/todo/src/todo.ts +18 -6
- package/templates/todo/template.json +11 -1
- package/templates/todo/test/todo.test.ts +67 -9
- package/lib/src-LX0E4ec4.js +0 -117
- package/shared/SKILL.md +0 -14
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as ConnectionInfo } from "../connection-ZLEso7XL.js";
|
|
2
|
+
import { c as UpgradeHubOptions, i as testWebSocket, l as UpgradeRouter, n as TestWebSocketOptions, o as UpgradeEmitter, p as WebSocketLike, r as TestWebSocketResult, s as UpgradeHub, t as TestSocket, u as RequestError } from "../test-websocket-GUTAkFQT.js";
|
|
2
3
|
import { n as UpgradeWebSocket } from "../index-C-SklY6u.js";
|
|
3
4
|
import { n as serveStatic, t as ServeStaticOptions } from "../serve-static-B7sqnftW.js";
|
|
5
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
6
|
+
import { Duplex } from "node:stream";
|
|
4
7
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
5
8
|
import z from "@deepseek-ai/schemastery";
|
|
6
9
|
|
|
@@ -8,6 +11,24 @@ import z from "@deepseek-ai/schemastery";
|
|
|
8
11
|
/** Stable Cordis plugin name, equal to the package name and the Loader row id. */
|
|
9
12
|
declare const name = "acryl-node-server";
|
|
10
13
|
declare const inject: string[];
|
|
14
|
+
/** A raw node handler: the request and response are the platform's, and the adapter writes nothing for them. */
|
|
15
|
+
interface RawRoute {
|
|
16
|
+
readonly kind: 'prefix' | 'exact';
|
|
17
|
+
readonly path: string;
|
|
18
|
+
readonly handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** A raw upgrade handler: the socket is the handler's once the path matches; the router never sees the upgrade. */
|
|
21
|
+
interface RawUpgradeRoute {
|
|
22
|
+
readonly path: string;
|
|
23
|
+
readonly handler: (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Answer a request before raw routes and the router, or pass it on with `undefined`. The callback runs synchronously, so a request no gate answers still
|
|
27
|
+
* reaches a raw route's sentinel synchronously; a gate that needs the router (a host keeping an app's URLs in scope under a prefix, the ACRYL frame's canvas)
|
|
28
|
+
* returns its promise, and the adapter handles that like the router's own answer. `connection` carries the socket facts, which a router mount needs to check
|
|
29
|
+
* the peer and the real port.
|
|
30
|
+
*/
|
|
31
|
+
type RequestGate = (request: Request, connection: ConnectionInfo) => Response | Promise<Response> | undefined;
|
|
11
32
|
interface Config {
|
|
12
33
|
hostname: string;
|
|
13
34
|
port: number;
|
|
@@ -22,28 +43,105 @@ declare module '@deepseek-ai/cordis' {
|
|
|
22
43
|
nodeServer: NodeServer;
|
|
23
44
|
}
|
|
24
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Milliseconds a request already in flight, or an upgraded socket's own owner, may finish once the server stops taking new work. A save during a
|
|
48
|
+
* restart must not be cut; a stream that never ends must not hold the stop open.
|
|
49
|
+
*/
|
|
50
|
+
declare const STOP_GRACE_MS = 2000;
|
|
25
51
|
declare class NodeServer extends Service {
|
|
26
52
|
readonly hostname: string;
|
|
27
53
|
readonly config: Config;
|
|
28
54
|
private readonly server;
|
|
55
|
+
private readonly router;
|
|
29
56
|
private hub;
|
|
30
57
|
private bound;
|
|
58
|
+
/** The one stop this server runs: a second call (the disposer after an explicit stop) waits on the same promise. */
|
|
59
|
+
private stopping;
|
|
60
|
+
/** Requests whose response has not finished yet: the stop waits for them before their sockets are cut. */
|
|
61
|
+
private active;
|
|
62
|
+
/** Upgraded sockets this server handed out (WebSockets): neither close() nor closeAllConnections() reaches them, so the stop tracks them itself. */
|
|
63
|
+
private readonly upgraded;
|
|
64
|
+
/** Raw routes registered by the host's compatibility layer (see {@link registerRaw}). */
|
|
65
|
+
private readonly rawExact;
|
|
66
|
+
private readonly rawPrefix;
|
|
67
|
+
private readonly rawUpgrades;
|
|
68
|
+
/** Gates registered by a host that maps an app's URLs (see {@link NodeServer.gate}); they run in the order they were added. */
|
|
69
|
+
private readonly gates;
|
|
70
|
+
/** One raw dispatch per upgrade request: a second listener (or a re-added one) must never emit the same request again. */
|
|
71
|
+
private readonly rawUpgradeSeen;
|
|
31
72
|
constructor(ctx: Context, config: Config);
|
|
73
|
+
/**
|
|
74
|
+
* Stop serving, gracefully, and resolve once the port is free: no new connections; requests already in flight may finish (a stream that never ends is
|
|
75
|
+
* cut) within {@link STOP_GRACE_MS}; each upgraded socket's owner closes it with a close frame first, and what is left is destroyed. Idempotent - the
|
|
76
|
+
* disposer calls it.
|
|
77
|
+
*
|
|
78
|
+
* Calling this BEFORE the rest of the app is disposed is what makes the grace count: the router has its own disposal, and it aborts in-flight requests
|
|
79
|
+
* and ends their bodies by design, concurrently with every other disposer (Cordis runs them together). A launcher that disposes the context directly
|
|
80
|
+
* therefore cuts the request this drains; a launcher that stops the server first lets it answer, then disposes.
|
|
81
|
+
*/
|
|
82
|
+
stop(): Promise<void>;
|
|
83
|
+
private closeGracefully;
|
|
84
|
+
/**
|
|
85
|
+
* Wait, bounded, until no request is in flight and no upgraded socket is left; true when both reached zero inside the bound. Every pass sweeps idle
|
|
86
|
+
* keep-alive sockets again: the single sweep `close()` does misses one that becomes idle after its request finished, and such a socket would otherwise
|
|
87
|
+
* hold the stop to its deadline.
|
|
88
|
+
*/
|
|
89
|
+
private settleStop;
|
|
90
|
+
/**
|
|
91
|
+
* Serve a raw node handler at `path`, beside the router: `exact` matches the pathname only, `prefix` the path and everything below it. The
|
|
92
|
+
* handler gets the platform's `IncomingMessage`/`ServerResponse` and owns the response; the router is not run for it. A path already served
|
|
93
|
+
* throws. The returned remover restores the path (the server itself goes on serving the rest).
|
|
94
|
+
*/
|
|
95
|
+
registerRaw(route: RawRoute): () => void;
|
|
96
|
+
/**
|
|
97
|
+
* Answer matching requests before raw routes and the router, so a host can keep an app's URLs in scope under a prefix (the frame's canvas). A gate runs
|
|
98
|
+
* synchronously and can answer with a promise (see {@link RequestGate}); gates run in the order they were added, and the returned remover takes this one back.
|
|
99
|
+
*/
|
|
100
|
+
gate(handler: RequestGate): () => void;
|
|
101
|
+
/**
|
|
102
|
+
* A gate's asynchronous answer: run the request it was given through the router, in the adapter's request form (a gate never makes one itself), with the
|
|
103
|
+
* socket facts. The raw routes do not run for that request.
|
|
104
|
+
*/
|
|
105
|
+
throughRouter(request: Request, connection?: ConnectionInfo): Promise<Response>;
|
|
106
|
+
/**
|
|
107
|
+
* Claim an upgrade path for a raw node handler: the handler receives `(req, socket, head)` and from then on owns the socket. The router's
|
|
108
|
+
* WebSocket handling never sees a claimed upgrade. A path already claimed throws; the remover releases the claim. The transport's one raw
|
|
109
|
+
* listener exists for the server's whole lifetime and consults this registry, so claims coming and going never add or remove a listener.
|
|
110
|
+
*/
|
|
111
|
+
registerRawUpgrade(route: RawUpgradeRoute): () => void;
|
|
112
|
+
/** The raw handler for a request: an exact path first, then the longest matching prefix. */
|
|
113
|
+
private rawFor;
|
|
32
114
|
/**
|
|
33
115
|
* `upgradeWebSocket` for the plugin that asks (call it once, in `apply`): `app.get('/ws', upgrade((c) => ({ onMessage(event, ws) { ... } })))`. Checks go in ordinary middleware on the
|
|
34
116
|
* route, and a handler that returns a `Response` refuses the upgrade with that status before any handshake. Every socket it accepts belongs to the calling plugin: when the plugin
|
|
35
117
|
* unloads they are closed with 1001 within `websocket.grace` and the handler sees `close` once. Pass `{ textOnly: true }` to drop binary frames. Needs the `ws` package.
|
|
36
118
|
*/
|
|
37
119
|
upgrades(): UpgradeWebSocket<WebSocketLike>;
|
|
120
|
+
/** How many `upgrade` listeners the transport holds (raw plus router setups); a test asserts it does not grow across claim changes. */
|
|
121
|
+
get upgradeListenerCount(): number;
|
|
38
122
|
/** How many WebSocket connections are open now. */
|
|
39
123
|
get sockets(): number;
|
|
40
124
|
/** The port in use, 0 before the server listens. */
|
|
41
125
|
get port(): number;
|
|
42
126
|
/** The address clients use. */
|
|
43
127
|
get url(): string;
|
|
44
|
-
/** Bind, scanning past taken ports. */
|
|
128
|
+
/** Bind, scanning past taken ports and past the ports a browser refuses. */
|
|
45
129
|
listen(): Promise<void>;
|
|
46
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* The ports every Fetch client refuses to connect to: the Fetch standard's bad ports (https://fetch.spec.whatwg.org/#port-blocking). Chromium
|
|
133
|
+
* refuses a page on one (ERR_UNSAFE_PORT) and Node's fetch answers "bad port"; the list below is the one Node 24 reports, probed port by port
|
|
134
|
+
* on 2026-11-03 (82 ports, 1 to 10080). An app's stable port is hashed into 3100..3999, and 3659 is on the list: without this rule one app in
|
|
135
|
+
* 900 would come up on an address no browser may open, which the frame gate caught that day (verify-frame-token was refused at 3659).
|
|
136
|
+
*/
|
|
137
|
+
declare const RESTRICTED_PORTS: ReadonlySet<number>;
|
|
138
|
+
/** Whether a browser refuses to open this port. */
|
|
139
|
+
declare function isRestrictedPort(port: number): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* The ports `listen` may try, in order: `port` with at most `scan` further ones, without the ports a browser refuses. Port 0 stays alone: the
|
|
142
|
+
* system chooses it, and the ports it hands out are above the restricted range.
|
|
143
|
+
*/
|
|
144
|
+
declare function portCandidates(port: number, scan: number): number[];
|
|
47
145
|
/**
|
|
48
146
|
* Whether a failed bind means "this port, try the next one". A port another socket holds answers `EADDRINUSE` everywhere. On Windows a port
|
|
49
147
|
* inside a range the system reserves (Hyper-V, WSL and Docker exclude ranges, `netsh interface ipv4 show excludedportrange`) answers
|
|
@@ -54,4 +152,4 @@ declare function isPortUnavailable(error: unknown, platform?: NodeJS.Platform):
|
|
|
54
152
|
/** Loads once the server listens, so a plugin that injects `nodeServer` can rely on `url`. A failure to bind fails the plugin. */
|
|
55
153
|
declare function apply(ctx: Context, config?: Partial<Config>): Promise<void>;
|
|
56
154
|
//#endregion
|
|
57
|
-
export { Config, NodeServer, RequestError, type ServeStaticOptions, type TestSocket, type TestWebSocketOptions, type TestWebSocketResult, UpgradeEmitter, UpgradeHub, type UpgradeHubOptions, type UpgradeRouter, apply, inject, isPortUnavailable, name, serveStatic, testWebSocket };
|
|
155
|
+
export { Config, NodeServer, RESTRICTED_PORTS, RawRoute, RawUpgradeRoute, RequestError, RequestGate, STOP_GRACE_MS, type ServeStaticOptions, type TestSocket, type TestWebSocketOptions, type TestWebSocketResult, UpgradeEmitter, UpgradeHub, type UpgradeHubOptions, type UpgradeRouter, apply, inject, isPortUnavailable, isRestrictedPort, name, portCandidates, serveStatic, testWebSocket };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as RequestError, n as UpgradeEmitter, r as UpgradeHub, t as testWebSocket } from "../test-websocket-CQOSvBth.js";
|
|
2
2
|
import { t as serveStatic } from "../serve-static-C1Nkj_xB.js";
|
|
3
|
-
import { a as
|
|
4
|
-
export { Config, NodeServer, RequestError, UpgradeEmitter, UpgradeHub, apply, inject, isPortUnavailable, name, serveStatic, testWebSocket };
|
|
3
|
+
import { a as apply, c as isRestrictedPort, i as STOP_GRACE_MS, l as name, n as NodeServer, o as inject, r as RESTRICTED_PORTS, s as isPortUnavailable, t as Config, u as portCandidates } from "../src-CtkIX_Gg.js";
|
|
4
|
+
export { Config, NodeServer, RESTRICTED_PORTS, RequestError, STOP_GRACE_MS, UpgradeEmitter, UpgradeHub, apply, inject, isPortUnavailable, isRestrictedPort, name, portCandidates, serveStatic, testWebSocket };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as UpgradeWebSocket } from "../index-C-SklY6u.js";
|
|
2
|
-
import { i as RouterHttpService } from "../index-
|
|
2
|
+
import { i as RouterHttpService } from "../index-DGq7H0lb.js";
|
|
3
3
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
4
4
|
import { Duplex } from "node:stream";
|
|
5
5
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
@@ -52,6 +52,10 @@ declare class RouterHttp extends Service implements RouterHttpService {
|
|
|
52
52
|
private readonly router;
|
|
53
53
|
private readonly web;
|
|
54
54
|
private hub;
|
|
55
|
+
/** One upgrade helper per calling context: a fresh wrapper per call made every service event look like an owner change. */
|
|
56
|
+
private readonly upgradeHelpers;
|
|
57
|
+
/** A stable identity for this service instance's hub: a caller that must recognize the same owner across calls keys on this, not on a helper. */
|
|
58
|
+
private readonly hubIdentity;
|
|
55
59
|
/** The adapter's own context: the hub lives as long as the adapter, whichever plugin asked for it first (`this.ctx` is the caller's). */
|
|
56
60
|
private readonly home;
|
|
57
61
|
private readonly upgradesIn;
|
|
@@ -69,6 +73,8 @@ declare class RouterHttp extends Service implements RouterHttpService {
|
|
|
69
73
|
* `upgradeWebSocket` for the calling plugin: the sockets its routes accept are closed with 1001 when it unloads. Needs the `ws` package.
|
|
70
74
|
* The route must be on a path the plugin mounted with `upgrade: [path]`.
|
|
71
75
|
*/
|
|
76
|
+
/** Stable for this service's lifetime; a re-provided adapter has a new one, which is how a caller sees a new owner. */
|
|
77
|
+
hubToken(): object;
|
|
72
78
|
upgrades(): UpgradeWebSocket;
|
|
73
79
|
/** How many WebSocket connections are open now. */
|
|
74
80
|
get sockets(): number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as UpgradeEmitter, r as UpgradeHub } from "../test-websocket-
|
|
2
|
-
import "../src-
|
|
1
|
+
import { n as UpgradeEmitter, r as UpgradeHub } from "../test-websocket-CQOSvBth.js";
|
|
2
|
+
import "../src-CtkIX_Gg.js";
|
|
3
3
|
import { Readable } from "node:stream";
|
|
4
4
|
import { Service } from "@deepseek-ai/cordis";
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
@@ -59,6 +59,33 @@ async function sendResponse(res, response, method) {
|
|
|
59
59
|
}
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region ../../plugins/acryl-router-http/src/serve.ts
|
|
62
|
+
/** How long a refusal waits for a request body the handler never read. */
|
|
63
|
+
const REQUEST_BODY_SETTLE_MS = 1e3;
|
|
64
|
+
/**
|
|
65
|
+
* Read and discard a request body the handler left unread (a guard's 403, a 415, a body over its limit), so the client can finish sending and
|
|
66
|
+
* read the answer. Ending a response while request data is still arriving makes Node close the socket with that data pending, and the peer sees a
|
|
67
|
+
* reset instead of the answer: reliably on Windows (the workspace git worktree test's read ECONNRESET) and on other systems under load. Bounded:
|
|
68
|
+
* a client that stops sending waits at most `ms`, then loses the socket as before.
|
|
69
|
+
*/
|
|
70
|
+
function settleRequestBody(req, ms = REQUEST_BODY_SETTLE_MS) {
|
|
71
|
+
if (req.readableEnded || req.destroyed) return Promise.resolve();
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
let timer;
|
|
74
|
+
const done = () => {
|
|
75
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
76
|
+
req.off("end", done);
|
|
77
|
+
req.off("close", done);
|
|
78
|
+
req.off("error", done);
|
|
79
|
+
resolve();
|
|
80
|
+
};
|
|
81
|
+
timer = setTimeout(done, ms);
|
|
82
|
+
timer.unref?.();
|
|
83
|
+
req.once("end", done);
|
|
84
|
+
req.once("close", done);
|
|
85
|
+
req.once("error", done);
|
|
86
|
+
req.resume();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
62
89
|
/**
|
|
63
90
|
* Serve one node request through the router and write the result. The request's abort signal fires when the client
|
|
64
91
|
* disconnects before the response finished; the socket's peer address and local port travel as connection info, never in the request.
|
|
@@ -78,6 +105,7 @@ async function serve(router, req, res) {
|
|
|
78
105
|
} catch {
|
|
79
106
|
response = new Response("Internal Server Error", { status: 500 });
|
|
80
107
|
}
|
|
108
|
+
if (method !== "GET" && method !== "HEAD") await settleRequestBody(req);
|
|
81
109
|
await sendResponse(res, response, method);
|
|
82
110
|
}
|
|
83
111
|
//#endregion
|
|
@@ -91,6 +119,10 @@ var RouterHttp = class extends Service {
|
|
|
91
119
|
router;
|
|
92
120
|
web;
|
|
93
121
|
hub;
|
|
122
|
+
/** One upgrade helper per calling context: a fresh wrapper per call made every service event look like an owner change. */
|
|
123
|
+
upgradeHelpers = /* @__PURE__ */ new WeakMap();
|
|
124
|
+
/** A stable identity for this service instance's hub: a caller that must recognize the same owner across calls keys on this, not on a helper. */
|
|
125
|
+
hubIdentity = {};
|
|
94
126
|
/** The adapter's own context: the hub lives as long as the adapter, whichever plugin asked for it first (`this.ctx` is the caller's). */
|
|
95
127
|
home;
|
|
96
128
|
upgradesIn = new UpgradeEmitter();
|
|
@@ -141,8 +173,17 @@ var RouterHttp = class extends Service {
|
|
|
141
173
|
* `upgradeWebSocket` for the calling plugin: the sockets its routes accept are closed with 1001 when it unloads. Needs the `ws` package.
|
|
142
174
|
* The route must be on a path the plugin mounted with `upgrade: [path]`.
|
|
143
175
|
*/
|
|
176
|
+
/** Stable for this service's lifetime; a re-provided adapter has a new one, which is how a caller sees a new owner. */
|
|
177
|
+
hubToken() {
|
|
178
|
+
return this.hubIdentity;
|
|
179
|
+
}
|
|
144
180
|
upgrades() {
|
|
145
|
-
|
|
181
|
+
const owner = this.ctx;
|
|
182
|
+
const cached = this.upgradeHelpers.get(owner);
|
|
183
|
+
if (cached !== void 0) return cached;
|
|
184
|
+
const created = this.ensureHub().upgradeWebSocketFor(owner);
|
|
185
|
+
this.upgradeHelpers.set(owner, created);
|
|
186
|
+
return created;
|
|
146
187
|
}
|
|
147
188
|
/** How many WebSocket connections are open now. */
|
|
148
189
|
get sockets() {
|
package/lib/cordis/router.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { B as NotFoundHandler, L as MiddlewareHandler, O as Handler, Q as Valida
|
|
|
2
2
|
import { c as StatusCode, n as ContentfulStatusCode } from "../http-status-DaAwGAFL.js";
|
|
3
3
|
import { a as getConnInfo, i as connectionOf, n as RouterBindings, r as RouterEnv, t as ConnectionInfo } from "../connection-ZLEso7XL.js";
|
|
4
4
|
import { t as Acryl } from "../app-D8riatvv.js";
|
|
5
|
-
import { a as TrailingSlash, i as RouterHttpService, n as MountableApp, o as apply, r as Router, s as name, t as Config } from "../index-
|
|
5
|
+
import { a as TrailingSlash, i as RouterHttpService, n as MountableApp, o as apply, r as Router, s as name, t as Config } from "../index-DGq7H0lb.js";
|
|
6
6
|
import { t as HTTPException } from "../http-exception-kpGJkmpi.js";
|
|
7
7
|
export { Acryl, type AcrylRequest, Config, type ConnectionInfo, type ContentfulStatusCode, Context, type ContextRenderer, type ContextVariableMap, type Env, type ErrorHandler, type ExecutionContext, HTTPException, type Handler, type Input, type MiddlewareHandler, type MountableApp, type Next, type NotFoundHandler, type NotFoundResponse, Router, type RouterBindings, type RouterEnv, type RouterHttpService, type Schema, type StatusCode, type ToSchema, type TrailingSlash, type TypedResponse, type ValidationTargets, apply, connectionOf, getConnInfo, name };
|
package/lib/cordis/router.js
CHANGED
|
@@ -2,5 +2,5 @@ import { t as HTTPException } from "../http-exception-MjWkT89V.js";
|
|
|
2
2
|
import { t as Context } from "../context-CkOh7Ygv.js";
|
|
3
3
|
import { t as Acryl } from "../app-CQcGWjrk.js";
|
|
4
4
|
import { n as getConnInfo, t as connectionOf } from "../connection-C7xgP1hP.js";
|
|
5
|
-
import { i as name, n as Router, r as apply, t as Config } from "../src-
|
|
5
|
+
import { i as name, n as Router, r as apply, t as Config } from "../src-iBJ2ysV9.js";
|
|
6
6
|
export { Acryl, Config, Context, HTTPException, Router, apply, connectionOf, getConnInfo, name };
|
package/lib/cordis/state.d.ts
CHANGED
|
@@ -24,9 +24,10 @@ declare class State extends Service {
|
|
|
24
24
|
keys(): string[];
|
|
25
25
|
/**
|
|
26
26
|
* The current value of `key` as a server-sent event stream: the value now, then one event per change, until the client cancels or the router
|
|
27
|
-
* is disposed (both abort the stream). A comment line goes out every 15 seconds so proxies and browsers keep an idle stream open.
|
|
27
|
+
* is disposed (both abort the stream). A comment line goes out every 15 seconds so proxies and browsers keep an idle stream open. A string value travels as it is; with `json`
|
|
28
|
+
* (the `?json=1` of the browser client) every value is JSON, so `"12"` and `12` can be told apart.
|
|
28
29
|
*/
|
|
29
|
-
stream(key: string, c: Context$1): Response | undefined;
|
|
30
|
+
stream(key: string, c: Context$1, json?: boolean): Response | undefined;
|
|
30
31
|
}
|
|
31
32
|
declare function apply(ctx: Context): void;
|
|
32
33
|
//#endregion
|