@actiondock/core 2.6.0 → 2.8.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 +61 -68
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +122 -10
- package/dist/errors.js +123 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -22
- package/dist/index.js +19 -21
- package/dist/input/advice.d.ts +104 -0
- package/dist/input/advice.js +716 -0
- package/dist/input/describe.d.ts +106 -0
- package/dist/input/describe.js +176 -0
- package/dist/input/file-input.d.ts +54 -0
- package/dist/input/file-input.js +124 -0
- package/dist/input/flat-decode.d.ts +11 -0
- package/dist/input/flat-decode.js +13 -0
- package/dist/input/flat-errors.d.ts +71 -0
- package/dist/input/flat-errors.js +87 -0
- package/dist/input/flat-materializer.d.ts +29 -0
- package/dist/input/flat-materializer.js +177 -0
- package/dist/input/flat-parser.d.ts +50 -0
- package/dist/input/flat-parser.js +169 -0
- package/dist/input/flat-predicates.d.ts +34 -0
- package/dist/input/flat-predicates.js +50 -0
- package/dist/input/index.d.ts +14 -0
- package/dist/input/index.js +14 -0
- package/dist/input/input-resolver.d.ts +63 -0
- package/dist/input/input-resolver.js +254 -0
- package/dist/input/json-depth-scanner.d.ts +17 -0
- package/dist/input/json-depth-scanner.js +49 -0
- package/dist/input/metadata.d.ts +99 -0
- package/dist/input/metadata.js +99 -0
- package/dist/input/stdin-input.d.ts +26 -0
- package/dist/input/stdin-input.js +125 -0
- package/dist/input/utf8.d.ts +19 -0
- package/dist/input/utf8.js +36 -0
- package/dist/input/validation-mapper.d.ts +27 -0
- package/dist/input/validation-mapper.js +144 -0
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/json/index.d.ts +1 -0
- package/dist/json/index.js +1 -0
- package/dist/json/value-validator.d.ts +88 -0
- package/dist/json/value-validator.js +330 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +3 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +48 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -103
- package/dist/runtime/runner.js +142 -404
- package/dist/runtime/standalone.d.ts +37 -9
- package/dist/runtime/standalone.js +195 -136
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.js +48 -54
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +10 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/routes/actions.js +34 -28
- package/dist/server/routes/common.d.ts +10 -14
- package/dist/server/routes/common.js +32 -56
- package/dist/server/routes/config.js +54 -64
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +10 -18
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +2 -3
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +12 -13
- package/dist/server/routes/playbooks.js +16 -29
- package/dist/server/routes/runs.js +95 -117
- package/dist/server/routes/state.js +63 -62
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +43 -227
- package/dist/server/types.d.ts +8 -19
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -623
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { createServer as createHttpsServer } from "node:https";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { pipeline } from "node:stream/promises";
|
|
6
|
+
import { BAD_REQUEST, SERVER_ERROR } from "../errors.js";
|
|
7
|
+
import { formatHostForUrl } from "./server.js";
|
|
8
|
+
/**
|
|
9
|
+
* 将 Node.js IncomingMessage 请求转化为标准的 Web Request 对象。
|
|
10
|
+
*/
|
|
11
|
+
export function createWebRequest(req, options) {
|
|
12
|
+
const protocol = req.socket?.encrypted ? "https" : "http";
|
|
13
|
+
const host = req.headers.host || "127.0.0.1";
|
|
14
|
+
let baseOrigin;
|
|
15
|
+
let res;
|
|
16
|
+
if (options) {
|
|
17
|
+
if ("writableFinished" in options || typeof options.writeHead === "function") {
|
|
18
|
+
res = options;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
baseOrigin = options.baseOrigin;
|
|
22
|
+
res = options.res;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!res && req.res) {
|
|
26
|
+
res = req.res;
|
|
27
|
+
}
|
|
28
|
+
baseOrigin = baseOrigin || `${protocol}://${host}`;
|
|
29
|
+
const url = new URL(req.url || "/", baseOrigin).href;
|
|
30
|
+
const headers = new Headers();
|
|
31
|
+
for (const [key, val] of Object.entries(req.headers)) {
|
|
32
|
+
if (val === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
if (Array.isArray(val)) {
|
|
35
|
+
for (const item of val) {
|
|
36
|
+
headers.append(key, item);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
headers.set(key, val);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const method = (req.method || "GET").toUpperCase();
|
|
44
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
45
|
+
const ac = new AbortController();
|
|
46
|
+
req.on("close", () => {
|
|
47
|
+
if (!req.complete) {
|
|
48
|
+
ac.abort(new Error("Request aborted by client"));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
if (res) {
|
|
52
|
+
res.on("close", () => {
|
|
53
|
+
if (!res.writableFinished) {
|
|
54
|
+
ac.abort(new Error("Request aborted by client"));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const init = {
|
|
59
|
+
method,
|
|
60
|
+
headers,
|
|
61
|
+
signal: ac.signal,
|
|
62
|
+
};
|
|
63
|
+
if (hasBody) {
|
|
64
|
+
const webStream = Readable.toWeb(req);
|
|
65
|
+
init.body = webStream;
|
|
66
|
+
init.duplex = "half";
|
|
67
|
+
}
|
|
68
|
+
return new Request(url, init);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 将标准的 Web Response 响应流式写回 Node.js ServerResponse 客户端输出。
|
|
72
|
+
*/
|
|
73
|
+
export async function sendWebResponse(webResponse, res) {
|
|
74
|
+
res.statusCode = webResponse.status;
|
|
75
|
+
if (webResponse.statusText) {
|
|
76
|
+
res.statusMessage = webResponse.statusText;
|
|
77
|
+
}
|
|
78
|
+
webResponse.headers.forEach((val, key) => {
|
|
79
|
+
if (key.toLowerCase() === "set-cookie") {
|
|
80
|
+
if (typeof webResponse.headers.getSetCookie === "function") {
|
|
81
|
+
res.setHeader("set-cookie", webResponse.headers.getSetCookie());
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
res.appendHeader("set-cookie", val);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
res.setHeader(key, val);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
if (!webResponse.body) {
|
|
92
|
+
res.end();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const nodeStream = Readable.fromWeb(webResponse.body);
|
|
96
|
+
try {
|
|
97
|
+
await pipeline(nodeStream, res);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (err?.code !== "ERR_STREAM_PREMATURE_CLOSE") {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 创建适用于 Node.js 原生 http.createServer 的请求监听函数。
|
|
107
|
+
*/
|
|
108
|
+
export function createRequestListener(handler, options) {
|
|
109
|
+
return (req, res) => {
|
|
110
|
+
let webReq;
|
|
111
|
+
try {
|
|
112
|
+
webReq = createWebRequest(req, { ...options, res });
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (!res.headersSent) {
|
|
116
|
+
res.statusCode = 400;
|
|
117
|
+
res.setHeader("Content-Type", "application/json");
|
|
118
|
+
res.end(JSON.stringify({
|
|
119
|
+
ok: false,
|
|
120
|
+
error: {
|
|
121
|
+
code: BAD_REQUEST,
|
|
122
|
+
message: err?.message || String(err),
|
|
123
|
+
},
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
res.destroy(err);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
Promise.resolve()
|
|
132
|
+
.then(() => handler(webReq))
|
|
133
|
+
.then((webRes) => sendWebResponse(webRes, res))
|
|
134
|
+
.catch((err) => {
|
|
135
|
+
if (!res.headersSent) {
|
|
136
|
+
res.statusCode = 500;
|
|
137
|
+
res.setHeader("Content-Type", "application/json");
|
|
138
|
+
res.end(JSON.stringify({
|
|
139
|
+
ok: false,
|
|
140
|
+
error: {
|
|
141
|
+
code: SERVER_ERROR,
|
|
142
|
+
message: err?.message || String(err),
|
|
143
|
+
},
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
res.destroy(err);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 基于 Node.js node:http 的轻量级 HTTP 服务端封装。
|
|
154
|
+
* 接收 Node HTTP 请求并转化为标准 Web Request,支持 Web Response 流式输出。
|
|
155
|
+
*/
|
|
156
|
+
export class NodeHttpServer {
|
|
157
|
+
server;
|
|
158
|
+
listening = false;
|
|
159
|
+
portNumber = 0;
|
|
160
|
+
hostAddress = "127.0.0.1";
|
|
161
|
+
tlsOptions;
|
|
162
|
+
persistentErrorHandler;
|
|
163
|
+
constructor(optionsOrHandler) {
|
|
164
|
+
const handler = typeof optionsOrHandler === "function"
|
|
165
|
+
? optionsOrHandler
|
|
166
|
+
: optionsOrHandler.fetch;
|
|
167
|
+
const baseOrigin = typeof optionsOrHandler === "object"
|
|
168
|
+
? optionsOrHandler.baseOrigin
|
|
169
|
+
: undefined;
|
|
170
|
+
const tls = typeof optionsOrHandler === "object"
|
|
171
|
+
? optionsOrHandler.tls
|
|
172
|
+
: undefined;
|
|
173
|
+
this.tlsOptions = tls;
|
|
174
|
+
const requestListener = createRequestListener(handler, { baseOrigin });
|
|
175
|
+
if (tls) {
|
|
176
|
+
let cert = tls.cert;
|
|
177
|
+
if (!cert && tls.certPath) {
|
|
178
|
+
cert = readFileSync(tls.certPath);
|
|
179
|
+
}
|
|
180
|
+
let key = tls.key;
|
|
181
|
+
if (!key && tls.keyPath) {
|
|
182
|
+
key = readFileSync(tls.keyPath);
|
|
183
|
+
}
|
|
184
|
+
const httpsOptions = { cert, key };
|
|
185
|
+
if (tls.ca)
|
|
186
|
+
httpsOptions.ca = tls.ca;
|
|
187
|
+
if (tls.passphrase)
|
|
188
|
+
httpsOptions.passphrase = tls.passphrase;
|
|
189
|
+
this.server = createHttpsServer(httpsOptions, requestListener);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
this.server = createServer(requestListener);
|
|
193
|
+
}
|
|
194
|
+
if (typeof optionsOrHandler === "object") {
|
|
195
|
+
if (optionsOrHandler.port !== undefined) {
|
|
196
|
+
this.portNumber = optionsOrHandler.port;
|
|
197
|
+
}
|
|
198
|
+
if (optionsOrHandler.host !== undefined) {
|
|
199
|
+
this.hostAddress = optionsOrHandler.host;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 底层原生 Node.js http.Server / https.Server 实例。
|
|
205
|
+
*/
|
|
206
|
+
get rawServer() {
|
|
207
|
+
return this.server;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* 绑定的监听端口号。
|
|
211
|
+
*/
|
|
212
|
+
get port() {
|
|
213
|
+
return this.portNumber;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* 绑定的主机地址。
|
|
217
|
+
*/
|
|
218
|
+
get host() {
|
|
219
|
+
return this.hostAddress;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 完整的 HTTP 访问基础路径。
|
|
223
|
+
*/
|
|
224
|
+
get url() {
|
|
225
|
+
const protocol = this.tlsOptions ? "https" : "http";
|
|
226
|
+
return `${protocol}://${formatHostForUrl(this.hostAddress)}:${this.portNumber}`;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 服务端当前是否正在监听连接。
|
|
230
|
+
*/
|
|
231
|
+
get isListening() {
|
|
232
|
+
return this.listening;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 启动监听。若未显式传入端口,则默认使用实例配置或随机可用端口(0)。
|
|
236
|
+
*/
|
|
237
|
+
async listen(port, host) {
|
|
238
|
+
const targetPort = port ?? this.portNumber ?? 0;
|
|
239
|
+
const targetHost = host ?? this.hostAddress ?? "127.0.0.1";
|
|
240
|
+
if (!this.persistentErrorHandler) {
|
|
241
|
+
this.persistentErrorHandler = (err) => {
|
|
242
|
+
console.error("[NodeHttpServer] unexpected server error:", err);
|
|
243
|
+
};
|
|
244
|
+
this.server.on("error", this.persistentErrorHandler);
|
|
245
|
+
}
|
|
246
|
+
return new Promise((resolve, reject) => {
|
|
247
|
+
const onListenError = (err) => {
|
|
248
|
+
this.server.removeListener("error", onListenError);
|
|
249
|
+
reject(err);
|
|
250
|
+
};
|
|
251
|
+
this.server.once("error", onListenError);
|
|
252
|
+
this.server.listen(targetPort, targetHost, () => {
|
|
253
|
+
this.server.removeListener("error", onListenError);
|
|
254
|
+
const addr = this.server.address();
|
|
255
|
+
if (addr && typeof addr === "object") {
|
|
256
|
+
this.portNumber = addr.port;
|
|
257
|
+
this.hostAddress = addr.address === "::" ? "127.0.0.1" : addr.address;
|
|
258
|
+
}
|
|
259
|
+
this.listening = true;
|
|
260
|
+
resolve({
|
|
261
|
+
port: this.portNumber,
|
|
262
|
+
host: this.hostAddress,
|
|
263
|
+
url: this.url,
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 优雅关闭服务端并释放端口与活动连接。
|
|
270
|
+
*/
|
|
271
|
+
async close() {
|
|
272
|
+
if (!this.listening) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (this.persistentErrorHandler) {
|
|
276
|
+
this.server.removeListener("error", this.persistentErrorHandler);
|
|
277
|
+
this.persistentErrorHandler = undefined;
|
|
278
|
+
}
|
|
279
|
+
return new Promise((resolve, reject) => {
|
|
280
|
+
this.server.close((err) => {
|
|
281
|
+
this.listening = false;
|
|
282
|
+
if (err)
|
|
283
|
+
reject(err);
|
|
284
|
+
else
|
|
285
|
+
resolve();
|
|
286
|
+
});
|
|
287
|
+
this.server.closeAllConnections?.();
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 停止服务端监听(兼容 stop 契约)。
|
|
292
|
+
*/
|
|
293
|
+
async stop() {
|
|
294
|
+
return this.close();
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 便捷工厂方法:创建并启动监听。
|
|
298
|
+
*/
|
|
299
|
+
static async start(optionsOrHandler, port, host) {
|
|
300
|
+
const server = new NodeHttpServer(optionsOrHandler);
|
|
301
|
+
await server.listen(port, host);
|
|
302
|
+
return server;
|
|
303
|
+
}
|
|
304
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -3,4 +3,15 @@ export * from "./security.js";
|
|
|
3
3
|
export * from "./body.js";
|
|
4
4
|
export * from "./routes/index.js";
|
|
5
5
|
export * from "./server.js";
|
|
6
|
+
export * from "./mcp-endpoint.js";
|
|
6
7
|
export * from "./dispatcher.js";
|
|
8
|
+
export * from "./http-server.js";
|
|
9
|
+
export { serveParentIpc } from "../ipc/host.js";
|
|
10
|
+
export { IpcActionDockService } from "../ipc/service.js";
|
|
11
|
+
export type { IpcServiceOptions } from "../ipc/types.js";
|
|
12
|
+
export { parseDuration } from "../utils/index.js";
|
|
13
|
+
export type { ActionDockHost, ActionDockHostOptions, } from "../host/types.js";
|
|
14
|
+
export { createActionDockHost, DefaultActionDockHost, } from "../host/host.js";
|
|
15
|
+
export { LocalActionDockService, } from "../service/local.js";
|
|
16
|
+
export { RemoteActionDockService, } from "../service/remote.js";
|
|
17
|
+
export { ExitCode, StandaloneDispatcher, type StandaloneDispatcherOptions, type InvocationControl, runStandaloneProcess, } from "../runtime/standalone.js";
|
package/dist/server/index.js
CHANGED
|
@@ -3,4 +3,14 @@ export * from "./security.js";
|
|
|
3
3
|
export * from "./body.js";
|
|
4
4
|
export * from "./routes/index.js";
|
|
5
5
|
export * from "./server.js";
|
|
6
|
+
export * from "./mcp-endpoint.js";
|
|
6
7
|
export * from "./dispatcher.js";
|
|
8
|
+
export * from "./http-server.js";
|
|
9
|
+
export { serveParentIpc } from "../ipc/host.js";
|
|
10
|
+
export { IpcActionDockService } from "../ipc/service.js";
|
|
11
|
+
export { parseDuration } from "../utils/index.js";
|
|
12
|
+
export { createActionDockHost, DefaultActionDockHost, } from "../host/host.js";
|
|
13
|
+
export { LocalActionDockService, } from "../service/local.js";
|
|
14
|
+
export { RemoteActionDockService, } from "../service/remote.js";
|
|
15
|
+
// 独立进程分发器与退出控制
|
|
16
|
+
export { ExitCode, StandaloneDispatcher, runStandaloneProcess, } from "../runtime/standalone.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享 MCP 端点处理器工厂配置选项。
|
|
3
|
+
*
|
|
4
|
+
* 覆盖 core 网关与 mcp 独立 HTTP 服务双方共同消费的配置面:
|
|
5
|
+
* - token 与 allowQueryToken 决定 Bearer 鉴权(含查询参数放行开关);
|
|
6
|
+
* - corsOrigins 决定跨域响应头解析;
|
|
7
|
+
* - maxBodyBytes 决定请求体有界读取上限(防 DoS);
|
|
8
|
+
* - corsApplyMode 决定 MCP 响应的 CORS 头部应用方式。
|
|
9
|
+
*/
|
|
10
|
+
export interface McpEndpointHandlerOptions {
|
|
11
|
+
/** 服务端预期的 Bearer Token(未配置时默认放行) */
|
|
12
|
+
token?: string;
|
|
13
|
+
/** 是否允许通过 URL 查询参数携带 Token(默认 false) */
|
|
14
|
+
allowQueryToken?: boolean;
|
|
15
|
+
/** 允许跨域请求的 CORS Origin 白名单列表 */
|
|
16
|
+
corsOrigins?: string[];
|
|
17
|
+
/** 最大允许的请求体字节限制(默认 1 MiB,防 DoS) */
|
|
18
|
+
maxBodyBytes?: number;
|
|
19
|
+
/** MCP 响应的 CORS 头部应用模式(默认 inherit 透传响应原头部) */
|
|
20
|
+
corsApplyMode?: McpCorsApplyMode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* MCP 委托处理器契约。
|
|
24
|
+
* 接收经限流重建后的标准 Request,返回 MCP 协议响应;
|
|
25
|
+
* 返回 null / undefined 表示委托方未处理,交回调用方继续后续路由。
|
|
26
|
+
*/
|
|
27
|
+
export type McpDelegateHandler = (req: Request) => Promise<Response | null | undefined> | Response | null | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* 构造 MCP 响应的 CORS 头部回写规则。
|
|
30
|
+
* - inherit:透传 MCP 响应自身头部(core 网关行为);
|
|
31
|
+
* - merge:将解析出的 CORS 头部合并覆盖到 MCP 响应(mcp 独立服务行为)。
|
|
32
|
+
*/
|
|
33
|
+
export type McpCorsApplyMode = "inherit" | "merge";
|
|
34
|
+
/**
|
|
35
|
+
* 共享 MCP 端点处理器契约。
|
|
36
|
+
*
|
|
37
|
+
* 返回 Response 表示已完整处理;返回 null / undefined 表示委托方未处理,
|
|
38
|
+
* 交回调用方继续后续路由分发。
|
|
39
|
+
*/
|
|
40
|
+
export type McpEndpointHandler = (req: Request) => Promise<Response | null | undefined>;
|
|
41
|
+
/**
|
|
42
|
+
* 构造可复用的 MCP 端点处理器。
|
|
43
|
+
*
|
|
44
|
+
* 统一承载 core 网关端点与 mcp 独立 HTTP 服务共同遵循的请求处理子序列:
|
|
45
|
+
* verifyBearerToken 鉴权(401 标准 JSON)→ readBodyWithLimit 有界读取
|
|
46
|
+
* (413 处理)→ 委托 MCP 处理器 → 按 corsApplyMode 应用 CORS 头部。
|
|
47
|
+
*
|
|
48
|
+
* CORS 头部解析与 OPTIONS 预检由外层路由分发统一承担(两端点在健康检查、
|
|
49
|
+
* 全局鉴权等前置路由上存在形态差异,不宜在此收敛);本处理器聚焦 MCP
|
|
50
|
+
* 端点自身的鉴权与请求体防护序列。
|
|
51
|
+
*
|
|
52
|
+
* 鉴权失败响应默认产出 core 网关标准错误形态;需要 JSON-RPC 错误形态的
|
|
53
|
+
* 调用方(如 mcp 独立服务)可通过 unauthorizedResponse 定制。
|
|
54
|
+
*
|
|
55
|
+
* @param delegate MCP 委托处理器(接收限流重建后的 Request)
|
|
56
|
+
* @param options 端点配置选项
|
|
57
|
+
*/
|
|
58
|
+
export declare function createMcpEndpointHandler(delegate: McpDelegateHandler, options?: McpEndpointHandlerOptions & {
|
|
59
|
+
/** 鉴权失败响应构造(默认产出 core 网关标准 401 JSON) */
|
|
60
|
+
unauthorizedResponse?: (corsHeaders: Record<string, string>) => Response;
|
|
61
|
+
}): McpEndpointHandler;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { UNAUTHORIZED, REQUEST_TOO_LARGE } from "../errors.js";
|
|
2
|
+
import { jsonResponse } from "./routes/common.js";
|
|
3
|
+
import { DEFAULT_MAX_BODY_BYTES, readBodyWithLimit, RequestTooLargeError } from "./body.js";
|
|
4
|
+
import { resolveCorsHeaders, verifyBearerToken } from "./security.js";
|
|
5
|
+
/**
|
|
6
|
+
* 构造 413 Payload Too Large JSON 响应。
|
|
7
|
+
*/
|
|
8
|
+
function requestTooLargeResponse(corsHeaders) {
|
|
9
|
+
return jsonResponse({
|
|
10
|
+
ok: false,
|
|
11
|
+
error: {
|
|
12
|
+
code: REQUEST_TOO_LARGE,
|
|
13
|
+
message: "Request body exceeds maximum allowed size",
|
|
14
|
+
},
|
|
15
|
+
}, 413, corsHeaders);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 有界读取请求体并重建 Request。
|
|
19
|
+
*
|
|
20
|
+
* 读取与超限判定统一复用 body 域的 readBodyWithLimit 单一事实源;
|
|
21
|
+
* 超限时返回 null 表示应回退 413 响应,由调用方构造错误响应。
|
|
22
|
+
* 空请求体保持 body 为 undefined,与 core 网关历史行为逐字节一致。
|
|
23
|
+
*
|
|
24
|
+
* @param req 原始请求
|
|
25
|
+
* @param maxBytes 单次请求体允许的最大字节数
|
|
26
|
+
* @returns 重建后的请求;体积超限时返回 null
|
|
27
|
+
*/
|
|
28
|
+
async function rebuildRequestWithLimit(req, maxBytes) {
|
|
29
|
+
let merged;
|
|
30
|
+
try {
|
|
31
|
+
merged = await readBodyWithLimit(req, { maxBytes });
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (err instanceof RequestTooLargeError) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
const bodyInit = merged.byteLength > 0 ? new Blob([merged]) : undefined;
|
|
40
|
+
return new Request(req.url, {
|
|
41
|
+
method: req.method,
|
|
42
|
+
headers: req.headers,
|
|
43
|
+
body: bodyInit,
|
|
44
|
+
signal: req.signal,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 按指定模式为 MCP 响应附加 CORS 头部。
|
|
49
|
+
*
|
|
50
|
+
* @param response MCP 委托处理器返回的原始响应
|
|
51
|
+
* @param corsHeaders 本次请求解析出的 CORS 响应头
|
|
52
|
+
* @param mode CORS 头部应用模式(默认 inherit 透传)
|
|
53
|
+
*/
|
|
54
|
+
function applyCorsToResponse(response, corsHeaders, mode) {
|
|
55
|
+
if (mode !== "merge" || Object.keys(corsHeaders).length === 0) {
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
58
|
+
const newHeaders = new Headers(response.headers);
|
|
59
|
+
for (const [k, v] of Object.entries(corsHeaders)) {
|
|
60
|
+
newHeaders.set(k, String(v));
|
|
61
|
+
}
|
|
62
|
+
return new Response(response.body, {
|
|
63
|
+
status: response.status,
|
|
64
|
+
statusText: response.statusText,
|
|
65
|
+
headers: newHeaders,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 构造可复用的 MCP 端点处理器。
|
|
70
|
+
*
|
|
71
|
+
* 统一承载 core 网关端点与 mcp 独立 HTTP 服务共同遵循的请求处理子序列:
|
|
72
|
+
* verifyBearerToken 鉴权(401 标准 JSON)→ readBodyWithLimit 有界读取
|
|
73
|
+
* (413 处理)→ 委托 MCP 处理器 → 按 corsApplyMode 应用 CORS 头部。
|
|
74
|
+
*
|
|
75
|
+
* CORS 头部解析与 OPTIONS 预检由外层路由分发统一承担(两端点在健康检查、
|
|
76
|
+
* 全局鉴权等前置路由上存在形态差异,不宜在此收敛);本处理器聚焦 MCP
|
|
77
|
+
* 端点自身的鉴权与请求体防护序列。
|
|
78
|
+
*
|
|
79
|
+
* 鉴权失败响应默认产出 core 网关标准错误形态;需要 JSON-RPC 错误形态的
|
|
80
|
+
* 调用方(如 mcp 独立服务)可通过 unauthorizedResponse 定制。
|
|
81
|
+
*
|
|
82
|
+
* @param delegate MCP 委托处理器(接收限流重建后的 Request)
|
|
83
|
+
* @param options 端点配置选项
|
|
84
|
+
*/
|
|
85
|
+
export function createMcpEndpointHandler(delegate, options = {}) {
|
|
86
|
+
const { token, allowQueryToken, corsOrigins, maxBodyBytes, unauthorizedResponse, } = options;
|
|
87
|
+
const maxBytes = maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
88
|
+
const verifyOptions = { allowQueryToken };
|
|
89
|
+
return async (req) => {
|
|
90
|
+
const origin = req.headers.get("origin");
|
|
91
|
+
const corsHeaders = resolveCorsHeaders(origin, corsOrigins);
|
|
92
|
+
// Bearer Token 鉴权拦截
|
|
93
|
+
if (!verifyBearerToken(req, token, verifyOptions)) {
|
|
94
|
+
return (unauthorizedResponse?.(corsHeaders) ??
|
|
95
|
+
jsonResponse({
|
|
96
|
+
ok: false,
|
|
97
|
+
error: {
|
|
98
|
+
code: UNAUTHORIZED,
|
|
99
|
+
message: "Invalid or missing Bearer token",
|
|
100
|
+
},
|
|
101
|
+
}, 401, corsHeaders));
|
|
102
|
+
}
|
|
103
|
+
// 请求体体积限制保护(复用 body 域有界读取单一事实源)
|
|
104
|
+
let mcpReq = req;
|
|
105
|
+
if (req.body && req.method !== "GET" && req.method !== "HEAD") {
|
|
106
|
+
const rebuilt = await rebuildRequestWithLimit(req, maxBytes);
|
|
107
|
+
if (!rebuilt) {
|
|
108
|
+
return requestTooLargeResponse(corsHeaders);
|
|
109
|
+
}
|
|
110
|
+
mcpReq = rebuilt;
|
|
111
|
+
}
|
|
112
|
+
const mcpRes = await delegate(mcpReq);
|
|
113
|
+
if (mcpRes) {
|
|
114
|
+
return applyCorsToResponse(mcpRes, corsHeaders, options.corsApplyMode ?? "inherit");
|
|
115
|
+
}
|
|
116
|
+
return mcpRes;
|
|
117
|
+
};
|
|
118
|
+
}
|