@actiondock/core 2.7.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.
Files changed (236) hide show
  1. package/README.md +61 -68
  2. package/dist/catalog/action-catalog.d.ts +56 -0
  3. package/dist/catalog/action-catalog.js +202 -0
  4. package/dist/catalog/discovery.d.ts +60 -0
  5. package/dist/catalog/discovery.js +119 -0
  6. package/dist/catalog/graph.d.ts +190 -0
  7. package/dist/catalog/graph.js +589 -0
  8. package/dist/catalog/index.d.ts +5 -5
  9. package/dist/catalog/index.js +5 -5
  10. package/dist/catalog/resolve-action.d.ts +43 -0
  11. package/dist/catalog/resolve-action.js +119 -0
  12. package/dist/catalog/resolve-playbook.d.ts +26 -0
  13. package/dist/catalog/resolve-playbook.js +114 -0
  14. package/dist/doctor/checks/project.js +27 -8
  15. package/dist/doctor/checks/registry.js +2 -2
  16. package/dist/doctor/checks/runtime.js +34 -1
  17. package/dist/errors.d.ts +102 -10
  18. package/dist/errors.js +103 -10
  19. package/dist/execution/service.d.ts +18 -16
  20. package/dist/execution/service.js +183 -252
  21. package/dist/execution/types.d.ts +25 -69
  22. package/dist/execution/types.js +2 -1
  23. package/dist/filter/intent.d.ts +8 -9
  24. package/dist/filter/intent.js +49 -10
  25. package/dist/graph/index.d.ts +4 -0
  26. package/dist/graph/index.js +4 -0
  27. package/dist/host/host.d.ts +74 -32
  28. package/dist/host/host.js +585 -336
  29. package/dist/host/routing.d.ts +15 -48
  30. package/dist/host/routing.js +90 -153
  31. package/dist/host/types.d.ts +50 -17
  32. package/dist/index.d.ts +21 -24
  33. package/dist/index.js +19 -23
  34. package/dist/input/advice.d.ts +5 -1
  35. package/dist/input/advice.js +163 -214
  36. package/dist/input/describe.d.ts +1 -1
  37. package/dist/input/flat-errors.d.ts +5 -6
  38. package/dist/input/flat-errors.js +6 -6
  39. package/dist/input/flat-materializer.js +42 -44
  40. package/dist/invocation/index.d.ts +2 -0
  41. package/dist/invocation/index.js +2 -0
  42. package/dist/invocation/policy.d.ts +157 -0
  43. package/dist/invocation/policy.js +231 -0
  44. package/dist/invocation/types.d.ts +172 -0
  45. package/dist/invocation/types.js +97 -0
  46. package/dist/ipc/diagnostic.d.ts +0 -12
  47. package/dist/ipc/diagnostic.js +0 -21
  48. package/dist/ipc/host.d.ts +4 -4
  49. package/dist/ipc/host.js +44 -47
  50. package/dist/ipc/index.d.ts +1 -1
  51. package/dist/ipc/index.js +1 -1
  52. package/dist/ipc/service.d.ts +40 -0
  53. package/dist/ipc/service.js +349 -0
  54. package/dist/ipc/types.d.ts +21 -15
  55. package/dist/node/index.d.ts +1 -0
  56. package/dist/node/index.js +1 -0
  57. package/dist/node/module-loader.d.ts +63 -0
  58. package/dist/node/module-loader.js +112 -0
  59. package/dist/package/index.d.ts +23 -0
  60. package/dist/package/index.js +18 -0
  61. package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
  62. package/dist/{app/app.js → package/runtime.js} +140 -95
  63. package/dist/{app → package}/static-index.js +58 -41
  64. package/dist/package/storage-view.d.ts +13 -0
  65. package/dist/package/storage-view.js +22 -0
  66. package/dist/{app → package}/types.d.ts +76 -57
  67. package/dist/package/types.js +22 -0
  68. package/dist/platform/index.d.ts +1 -1
  69. package/dist/platform/index.js +1 -1
  70. package/dist/platform/node.d.ts +48 -0
  71. package/dist/platform/node.js +96 -0
  72. package/dist/platform/types.d.ts +0 -9
  73. package/dist/process/control-arbiter.d.ts +2 -1
  74. package/dist/process/control-arbiter.js +1 -2
  75. package/dist/process/driver.d.ts +9 -8
  76. package/dist/process/driver.js +11 -22
  77. package/dist/process/index.d.ts +2 -0
  78. package/dist/process/index.js +2 -0
  79. package/dist/process/managed-record.d.ts +2 -2
  80. package/dist/process/process-driver.d.ts +109 -0
  81. package/dist/process/process-driver.js +650 -0
  82. package/dist/process/process-executor.d.ts +47 -0
  83. package/dist/process/process-executor.js +296 -0
  84. package/dist/process/process-manager.js +48 -26
  85. package/dist/process/run-executor.js +12 -12
  86. package/dist/profile/client-actions.js +2 -2
  87. package/dist/profile/client-health.js +2 -2
  88. package/dist/profile/client-query.js +5 -6
  89. package/dist/profile/client-transport.d.ts +19 -17
  90. package/dist/profile/client-transport.js +47 -80
  91. package/dist/profile/client.d.ts +2 -2
  92. package/dist/profile/client.js +1 -1
  93. package/dist/profile/index.d.ts +1 -0
  94. package/dist/profile/index.js +1 -0
  95. package/dist/profile/manager.d.ts +5 -0
  96. package/dist/profile/manager.js +41 -6
  97. package/dist/project/closure.js +2 -2
  98. package/dist/project/index.d.ts +8 -1
  99. package/dist/project/index.js +10 -1
  100. package/dist/project/init.js +2 -2
  101. package/dist/project/loader.d.ts +1 -1
  102. package/dist/project/loader.js +26 -29
  103. package/dist/project/transactions.js +5 -10
  104. package/dist/registry/index.d.ts +3 -1
  105. package/dist/registry/index.js +2 -1
  106. package/dist/registry/lock.d.ts +28 -7
  107. package/dist/registry/lock.js +136 -16
  108. package/dist/registry/registry.d.ts +1 -5
  109. package/dist/registry/registry.js +1 -53
  110. package/dist/registry/scan.d.ts +0 -15
  111. package/dist/registry/scan.js +0 -59
  112. package/dist/registry/store.d.ts +42 -0
  113. package/dist/registry/store.js +43 -0
  114. package/dist/registry/types.d.ts +0 -24
  115. package/dist/runtime/action-collection.d.ts +1 -1
  116. package/dist/runtime/action-registry.d.ts +0 -4
  117. package/dist/runtime/action-registry.js +0 -7
  118. package/dist/runtime/context.js +5 -11
  119. package/dist/runtime/events.js +3 -6
  120. package/dist/runtime/identity.d.ts +22 -0
  121. package/dist/runtime/identity.js +10 -0
  122. package/dist/runtime/index.d.ts +1 -2
  123. package/dist/runtime/index.js +1 -2
  124. package/dist/runtime/module-loader.d.ts +2 -34
  125. package/dist/runtime/module-loader.js +1 -16
  126. package/dist/runtime/process.d.ts +6 -24
  127. package/dist/runtime/process.js +1 -118
  128. package/dist/runtime/run-persistence.js +2 -5
  129. package/dist/runtime/runner.d.ts +33 -93
  130. package/dist/runtime/runner.js +132 -364
  131. package/dist/runtime/standalone.d.ts +23 -8
  132. package/dist/runtime/standalone.js +100 -147
  133. package/dist/server/body.d.ts +16 -8
  134. package/dist/server/body.js +33 -16
  135. package/dist/server/dispatcher.d.ts +6 -10
  136. package/dist/server/dispatcher.js +24 -32
  137. package/dist/server/http-server.d.ts +87 -0
  138. package/dist/server/http-server.js +304 -0
  139. package/dist/server/index.d.ts +11 -0
  140. package/dist/server/index.js +10 -0
  141. package/dist/server/mcp-endpoint.d.ts +61 -0
  142. package/dist/server/mcp-endpoint.js +118 -0
  143. package/dist/server/routes/actions.js +34 -28
  144. package/dist/server/routes/common.d.ts +10 -14
  145. package/dist/server/routes/common.js +32 -56
  146. package/dist/server/routes/config.js +54 -64
  147. package/dist/server/routes/doctor.d.ts +1 -1
  148. package/dist/server/routes/doctor.js +10 -18
  149. package/dist/server/routes/health.d.ts +1 -1
  150. package/dist/server/routes/health.js +2 -3
  151. package/dist/server/routes/info.d.ts +2 -2
  152. package/dist/server/routes/info.js +12 -13
  153. package/dist/server/routes/playbooks.js +16 -29
  154. package/dist/server/routes/runs.js +95 -117
  155. package/dist/server/routes/state.js +63 -62
  156. package/dist/server/server.d.ts +2 -2
  157. package/dist/server/server.js +43 -227
  158. package/dist/server/types.d.ts +8 -19
  159. package/dist/service/factory.d.ts +12 -0
  160. package/dist/service/factory.js +85 -0
  161. package/dist/{target → service}/index.d.ts +1 -1
  162. package/dist/{target → service}/index.js +1 -1
  163. package/dist/service/local.d.ts +27 -0
  164. package/dist/service/local.js +138 -0
  165. package/dist/{target → service}/remote-errors.d.ts +3 -6
  166. package/dist/service/remote-errors.js +38 -0
  167. package/dist/{target → service}/remote-polling.d.ts +2 -2
  168. package/dist/{target → service}/remote-polling.js +8 -8
  169. package/dist/service/remote.d.ts +34 -0
  170. package/dist/service/remote.js +634 -0
  171. package/dist/service/sse-stream.d.ts +24 -0
  172. package/dist/service/sse-stream.js +139 -0
  173. package/dist/service/types.d.ts +272 -0
  174. package/dist/service/types.js +32 -0
  175. package/dist/storage/data-dir-lock.js +10 -5
  176. package/dist/storage/driver.d.ts +2 -1
  177. package/dist/storage/driver.js +3 -52
  178. package/dist/storage/index.d.ts +1 -0
  179. package/dist/storage/index.js +1 -0
  180. package/dist/storage/lock-core.d.ts +2 -6
  181. package/dist/storage/lock-core.js +4 -17
  182. package/dist/storage/params.d.ts +2 -8
  183. package/dist/storage/params.js +2 -8
  184. package/dist/storage/sqlite-driver.d.ts +40 -0
  185. package/dist/storage/sqlite-driver.js +116 -0
  186. package/dist/storage/sqlite.js +21 -6
  187. package/dist/storage/types.d.ts +4 -4
  188. package/dist/storage/types.js +2 -2
  189. package/dist/utils/index.d.ts +53 -0
  190. package/dist/utils/index.js +99 -4
  191. package/dist/utils/process.d.ts +10 -0
  192. package/dist/utils/process.js +21 -0
  193. package/dist/version.d.ts +1 -1
  194. package/dist/version.js +1 -1
  195. package/package.json +41 -3
  196. package/dist/app/index.d.ts +0 -2
  197. package/dist/app/index.js +0 -2
  198. package/dist/app/types.js +0 -1
  199. package/dist/catalog/action-index.d.ts +0 -9
  200. package/dist/catalog/action-index.js +0 -95
  201. package/dist/catalog/action-resolver.d.ts +0 -20
  202. package/dist/catalog/action-resolver.js +0 -95
  203. package/dist/catalog/location-registry.d.ts +0 -15
  204. package/dist/catalog/location-registry.js +0 -138
  205. package/dist/catalog/package-catalog.d.ts +0 -7
  206. package/dist/catalog/package-catalog.js +0 -77
  207. package/dist/catalog/types.d.ts +0 -68
  208. package/dist/catalog/types.js +0 -1
  209. package/dist/export/index.d.ts +0 -1
  210. package/dist/export/index.js +0 -1
  211. package/dist/export/templates.d.ts +0 -71
  212. package/dist/export/templates.js +0 -635
  213. package/dist/ipc/target.d.ts +0 -74
  214. package/dist/ipc/target.js +0 -365
  215. package/dist/platform/default.d.ts +0 -38
  216. package/dist/platform/default.js +0 -78
  217. package/dist/project/resolver.d.ts +0 -116
  218. package/dist/project/resolver.js +0 -376
  219. package/dist/registry/resolve.d.ts +0 -62
  220. package/dist/registry/resolve.js +0 -195
  221. package/dist/runtime/execution-manager.d.ts +0 -48
  222. package/dist/runtime/execution-manager.js +0 -66
  223. package/dist/runtime/package-runner-factory.d.ts +0 -82
  224. package/dist/runtime/package-runner-factory.js +0 -186
  225. package/dist/target/local.d.ts +0 -53
  226. package/dist/target/local.js +0 -349
  227. package/dist/target/remote-errors.js +0 -51
  228. package/dist/target/remote.d.ts +0 -86
  229. package/dist/target/remote.js +0 -818
  230. package/dist/target/target.d.ts +0 -6
  231. package/dist/target/target.js +0 -37
  232. package/dist/target/types.d.ts +0 -261
  233. package/dist/target/types.js +0 -35
  234. /package/dist/{app → package}/static-index.d.ts +0 -0
  235. /package/dist/{target → service}/sse-parser.d.ts +0 -0
  236. /package/dist/{target → service}/sse-parser.js +0 -0
@@ -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
+ }
@@ -1,14 +1,13 @@
1
- import { randomUUID } from "node:crypto";
2
- import { ActionResolver } from "../../catalog/action-resolver.js";
1
+ import { parseActionRef } from "../../catalog/resolve-action.js";
3
2
  import { filterByIntent } from "../../filter/index.js";
4
- import { ACTION_NOT_FOUND, ACTION_TIMEOUT, IDEMPOTENCY_CONFLICT, INPUT_VALIDATION_FAILED, PACKAGE_NOT_FOUND } from "../../errors.js";
3
+ import { ACTION_EXECUTION_ERROR, ACTION_NOT_FOUND, ACTION_START_FAILED, ACTION_TIMEOUT, ACTIONS_LIST_ERROR, IDEMPOTENCY_CONFLICT, INPUT_VALIDATION_FAILED, INVALID_JSON, PACKAGE_FORBIDDEN, PACKAGE_NOT_FOUND, REQUEST_TOO_LARGE, } from "../../errors.js";
5
4
  import { InvalidJsonError, readJsonBody, RequestTooLargeError } from "../body.js";
6
5
  import { getSubPath, jsonResponse } from "./common.js";
7
6
  /**
8
7
  * 处理 Action 相关的 HTTP 路由(列表、规范查询、同步执行与异步启动)。
9
8
  */
10
9
  export async function handleActionsRoutes(ctx) {
11
- const { req, url, pathname, corsHeaders, options, target } = ctx;
10
+ const { req, url, pathname, corsHeaders, options, service } = ctx;
12
11
  const subpath = getSubPath(pathname);
13
12
  // 1. Actions List: GET /api/v2/actions, GET /actions
14
13
  if (subpath === "/actions" && req.method === "GET") {
@@ -18,7 +17,7 @@ export async function handleActionsRoutes(ctx) {
18
17
  const targetPkg = url.searchParams.get("package") || url.searchParams.get("packageId") || undefined;
19
18
  const prefix = url.searchParams.get("prefix") || undefined;
20
19
  const tags = url.searchParams.getAll("tag");
21
- let actions = await target.listActions({
20
+ let actions = await service.discovery.listActions({
22
21
  query,
23
22
  prefix,
24
23
  tags: tags.length > 0 ? tags : undefined,
@@ -37,7 +36,7 @@ export async function handleActionsRoutes(ctx) {
37
36
  catch (err) {
38
37
  return jsonResponse({
39
38
  ok: false,
40
- error: { code: "ACTIONS_LIST_ERROR", message: err.message },
39
+ error: { code: ACTIONS_LIST_ERROR, message: err.message },
41
40
  }, 500, corsHeaders);
42
41
  }
43
42
  }
@@ -51,7 +50,7 @@ export async function handleActionsRoutes(ctx) {
51
50
  return jsonResponse({
52
51
  ok: false,
53
52
  error: {
54
- code: "PACKAGE_FORBIDDEN",
53
+ code: PACKAGE_FORBIDDEN,
55
54
  message: `Package '${packageId}' is not in the allowed package list`,
56
55
  },
57
56
  }, 403, corsHeaders);
@@ -59,7 +58,7 @@ export async function handleActionsRoutes(ctx) {
59
58
  }
60
59
  const ref = `${packageId}/${actionId}`;
61
60
  try {
62
- const spec = await target.describeAction(ref);
61
+ const spec = await service.discovery.describeAction(ref);
63
62
  return jsonResponse(spec, 200, corsHeaders);
64
63
  }
65
64
  catch (err) {
@@ -77,13 +76,13 @@ export async function handleActionsRoutes(ctx) {
77
76
  if (actionShowMatch && req.method === "GET") {
78
77
  const actionId = decodeURIComponent(actionShowMatch[1]);
79
78
  try {
80
- const parsed = ActionResolver.parseRef(actionId);
79
+ const parsed = parseActionRef(actionId);
81
80
  if (parsed.packageId && options.packageAllowlist && options.packageAllowlist.length > 0) {
82
81
  if (!options.packageAllowlist.includes(parsed.packageId)) {
83
82
  return jsonResponse({
84
83
  ok: false,
85
84
  error: {
86
- code: "PACKAGE_FORBIDDEN",
85
+ code: PACKAGE_FORBIDDEN,
87
86
  message: `Package '${parsed.packageId}' is not in the allowed package list`,
88
87
  },
89
88
  }, 403, corsHeaders);
@@ -92,14 +91,14 @@ export async function handleActionsRoutes(ctx) {
92
91
  }
93
92
  catch { }
94
93
  try {
95
- const spec = await target.describeAction(actionId);
94
+ const spec = await service.discovery.describeAction(actionId);
96
95
  if (options.packageAllowlist &&
97
96
  options.packageAllowlist.length > 0 &&
98
97
  (!spec.packageId || !options.packageAllowlist.includes(spec.packageId))) {
99
98
  return jsonResponse({
100
99
  ok: false,
101
100
  error: {
102
- code: "PACKAGE_FORBIDDEN",
101
+ code: PACKAGE_FORBIDDEN,
103
102
  message: `Package '${spec.packageId}' is not in the allowed package list`,
104
103
  },
105
104
  }, 403, corsHeaders);
@@ -138,7 +137,7 @@ export async function handleActionsRoutes(ctx) {
138
137
  actionRef = decodeURIComponent(shortRunMatch[1]);
139
138
  endpointMode = shortRunMatch[2];
140
139
  try {
141
- const parsed = ActionResolver.parseRef(actionRef);
140
+ const parsed = parseActionRef(actionRef);
142
141
  pkgId = parsed.packageId;
143
142
  }
144
143
  catch { }
@@ -147,7 +146,7 @@ export async function handleActionsRoutes(ctx) {
147
146
  if (options.packageAllowlist && options.packageAllowlist.length > 0) {
148
147
  if (!pkgId) {
149
148
  try {
150
- const spec = await target.describeAction(actionRef);
149
+ const spec = await service.discovery.describeAction(actionRef);
151
150
  pkgId = spec?.packageId;
152
151
  }
153
152
  catch { }
@@ -155,9 +154,9 @@ export async function handleActionsRoutes(ctx) {
155
154
  if (!pkgId || !options.packageAllowlist.includes(pkgId)) {
156
155
  return jsonResponse({
157
156
  ok: false,
158
- runId: randomUUID(),
157
+ runId: "",
159
158
  error: {
160
- code: "PACKAGE_FORBIDDEN",
159
+ code: PACKAGE_FORBIDDEN,
161
160
  message: pkgId
162
161
  ? `Package '${pkgId}' is not in the allowed package list`
163
162
  : `Action '${actionRef}' does not belong to any allowed package`,
@@ -173,21 +172,21 @@ export async function handleActionsRoutes(ctx) {
173
172
  if (err instanceof RequestTooLargeError) {
174
173
  return jsonResponse({
175
174
  ok: false,
176
- runId: randomUUID(),
177
- error: { code: "REQUEST_TOO_LARGE", message: err.message },
175
+ runId: "",
176
+ error: { code: REQUEST_TOO_LARGE, message: err.message },
178
177
  }, 413, corsHeaders);
179
178
  }
180
179
  if (err instanceof InvalidJsonError) {
181
180
  return jsonResponse({
182
181
  ok: false,
183
- runId: randomUUID(),
184
- error: { code: "INVALID_JSON", message: err.message },
182
+ runId: "",
183
+ error: { code: INVALID_JSON, message: err.message },
185
184
  }, 400, corsHeaders);
186
185
  }
187
186
  return jsonResponse({
188
187
  ok: false,
189
- runId: randomUUID(),
190
- error: { code: "INVALID_JSON", message: `Failed to parse request body: ${err.message}` },
188
+ runId: "",
189
+ error: { code: INVALID_JSON, message: `Failed to parse request body: ${err.message}` },
191
190
  }, 400, corsHeaders);
192
191
  }
193
192
  const isAsync = endpointMode === "start" ||
@@ -205,9 +204,16 @@ export async function handleActionsRoutes(ctx) {
205
204
  body?.requestId ||
206
205
  body?.execution?.requestId ||
207
206
  undefined;
207
+ let actionRefObj;
208
+ try {
209
+ actionRefObj = parseActionRef(actionRef);
210
+ }
211
+ catch {
212
+ actionRefObj = { actionId: actionRef };
213
+ }
208
214
  if (isAsync) {
209
215
  try {
210
- const ticket = await target.startAction(actionRef, input, {
216
+ const ticket = await service.execution.start(actionRefObj, input, {
211
217
  timeoutMs,
212
218
  config: configOverrides,
213
219
  requestId,
@@ -236,9 +242,9 @@ export async function handleActionsRoutes(ctx) {
236
242
  }
237
243
  return jsonResponse({
238
244
  ok: false,
239
- runId: randomUUID(),
245
+ runId: "",
240
246
  error: {
241
- code: "ACTION_START_FAILED",
247
+ code: ACTION_START_FAILED,
242
248
  message: err.message || String(err),
243
249
  },
244
250
  }, 500, corsHeaders);
@@ -246,7 +252,7 @@ export async function handleActionsRoutes(ctx) {
246
252
  }
247
253
  // 同步执行模式
248
254
  try {
249
- const result = await target.runAction(actionRef, input, {
255
+ const result = await service.execution.run(actionRefObj, input, {
250
256
  signal: req.signal,
251
257
  timeoutMs,
252
258
  config: configOverrides,
@@ -286,9 +292,9 @@ export async function handleActionsRoutes(ctx) {
286
292
  }
287
293
  return jsonResponse({
288
294
  ok: false,
289
- runId: randomUUID(),
295
+ runId: "",
290
296
  error: {
291
- code: "ACTION_EXECUTION_ERROR",
297
+ code: ACTION_EXECUTION_ERROR,
292
298
  message: err.message || String(err),
293
299
  },
294
300
  }, 500, corsHeaders);
@@ -1,6 +1,5 @@
1
- import type { ActionDockApp } from "../../app/types.js";
2
- import type { ActionDockHost } from "../../host/types.js";
3
- import type { ActionDockTarget } from "../../target/types.js";
1
+ import type { PackageInfo } from "../../package/types.js";
2
+ import type { ActionDockService } from "../../service/types.js";
4
3
  import type { ServerOptions } from "../types.js";
5
4
  /**
6
5
  * 路由处理统一上下文对象。
@@ -12,8 +11,7 @@ export interface RouteContext {
12
11
  corsHeaders: Record<string, string>;
13
12
  projectRoot: string | null;
14
13
  customHome?: string;
15
- host?: ActionDockHost;
16
- target: ActionDockTarget;
14
+ service: ActionDockService;
17
15
  options: ServerOptions;
18
16
  }
19
17
  /**
@@ -21,27 +19,25 @@ export interface RouteContext {
21
19
  */
22
20
  export declare function jsonResponse(data: unknown, status?: number, corsHeaders?: Record<string, string>): Response;
23
21
  /**
24
- * 剥离标准版本前缀 (/api/v2/ 与兼容的 /api/v1/),获取相对路由子路径。
22
+ * 剥离标准版本前缀 (/api/v2/),获取相对路由子路径。
25
23
  */
26
24
  export declare function getSubPath(pathname: string): string;
25
+ import { ActionDockError } from "../../errors.js";
27
26
  /**
28
27
  * 包未列入白名单拒绝访问异常。
29
28
  */
30
- export declare class PackageNotAllowedError extends Error {
29
+ export declare class PackageNotAllowedError extends ActionDockError {
31
30
  status: number;
32
31
  statusCode: number;
33
- code: string;
34
32
  constructor(packageId: string);
35
33
  }
36
34
  /**
37
35
  * 校验目标 packageId 是否属于允许包白名单。
38
36
  * 当 options.packageAllowlist 存在且目标 packageId 不在白名单中时抛出 403 PACKAGE_NOT_ALLOWED 异常。
39
37
  */
40
- export declare function assertPackageAllowed(packageId: string | undefined | null, options?: {
41
- packageAllowlist?: string[];
42
- }): void;
38
+ export declare function assertPackageAllowed(packageId: string, options?: ServerOptions): void;
43
39
  /**
44
- * 从 Host 或 Target 中依据 packageId 解析对应的 ActionDockApp 实例。
45
- * 若提供了 options,过滤或优先选择白名单内的 app。
40
+ * 解析并确定生效的目标 packageId。
41
+ * 遵循严格的解析规则与白名单检查。
46
42
  */
47
- export declare function resolveAppForPackage(packageIdOrPath: string | undefined, host?: ActionDockHost, target?: ActionDockTarget, options?: ServerOptions): ActionDockApp;
43
+ export declare function resolveTargetPackageId(packages: PackageInfo[], requestedPackageId?: string, options?: ServerOptions): string;
@@ -12,27 +12,25 @@ export function jsonResponse(data, status = 200, corsHeaders = {}) {
12
12
  });
13
13
  }
14
14
  /**
15
- * 剥离标准版本前缀 (/api/v2/ 与兼容的 /api/v1/),获取相对路由子路径。
15
+ * 剥离标准版本前缀 (/api/v2/),获取相对路由子路径。
16
16
  */
17
17
  export function getSubPath(pathname) {
18
18
  if (pathname.startsWith("/api/v2/")) {
19
19
  return pathname.slice(7);
20
20
  }
21
- if (pathname.startsWith("/api/v1/")) {
22
- return pathname.slice(7);
23
- }
24
21
  return pathname;
25
22
  }
23
+ import { ActionDockError, PACKAGE_NOT_FOUND, PACKAGE_NOT_ALLOWED } from "../../errors.js";
26
24
  /**
27
25
  * 包未列入白名单拒绝访问异常。
28
26
  */
29
- export class PackageNotAllowedError extends Error {
27
+ export class PackageNotAllowedError extends ActionDockError {
30
28
  status = 403;
31
29
  statusCode = 403;
32
- code = "PACKAGE_NOT_ALLOWED";
33
30
  constructor(packageId) {
34
- super(`Package '${packageId}' is not in the allowed package list`);
31
+ super(PACKAGE_NOT_ALLOWED, `Package '${packageId}' is not in the allowed package list`);
35
32
  this.name = "PackageNotAllowedError";
33
+ Object.setPrototypeOf(this, PackageNotAllowedError.prototype);
36
34
  }
37
35
  }
38
36
  /**
@@ -42,63 +40,41 @@ export class PackageNotAllowedError extends Error {
42
40
  export function assertPackageAllowed(packageId, options) {
43
41
  if (options?.packageAllowlist &&
44
42
  Array.isArray(options.packageAllowlist) &&
45
- options.packageAllowlist.length > 0) {
46
- if (!packageId || !options.packageAllowlist.includes(packageId)) {
47
- throw new PackageNotAllowedError(packageId || "");
48
- }
43
+ options.packageAllowlist.length > 0 &&
44
+ !options.packageAllowlist.includes(packageId)) {
45
+ throw new PackageNotAllowedError(packageId);
49
46
  }
50
47
  }
51
48
  /**
52
- * 从 Host 或 Target 中依据 packageId 解析对应的 ActionDockApp 实例。
53
- * 若提供了 options,过滤或优先选择白名单内的 app。
49
+ * 解析并确定生效的目标 packageId。
50
+ * 遵循严格的解析规则与白名单检查。
54
51
  */
55
- export function resolveAppForPackage(packageIdOrPath, host, target, options) {
56
- if (packageIdOrPath) {
57
- assertPackageAllowed(packageIdOrPath, options);
58
- assertValidPackageId(packageIdOrPath);
59
- if (host) {
60
- const app = host.getApp(packageIdOrPath);
61
- if (app)
62
- return app;
63
- }
64
- const innerTarget = target?.unwrap?.();
65
- if (innerTarget && "packageId" in innerTarget && innerTarget.packageId === packageIdOrPath) {
66
- return innerTarget;
52
+ export function resolveTargetPackageId(packages, requestedPackageId, options) {
53
+ if (requestedPackageId) {
54
+ if (requestedPackageId === "global") {
55
+ return "global";
67
56
  }
68
- if (innerTarget && "getApp" in innerTarget) {
69
- const app = innerTarget.getApp(packageIdOrPath);
70
- if (app)
71
- return app;
57
+ assertValidPackageId(requestedPackageId);
58
+ assertPackageAllowed(requestedPackageId, options);
59
+ const matched = packages.find((p) => p.id === requestedPackageId || p.packageRoot === requestedPackageId);
60
+ if (!matched) {
61
+ throw new ActionDockError(PACKAGE_NOT_FOUND, `Unknown or unregistered package: '${requestedPackageId}'`);
72
62
  }
73
- throw new Error(`Unknown or unregistered package: '${packageIdOrPath}'`);
63
+ return matched.id;
74
64
  }
75
- if (host) {
76
- const apps = host.listApps();
77
- if (options?.packageAllowlist &&
78
- Array.isArray(options.packageAllowlist) &&
79
- options.packageAllowlist.length > 0) {
80
- const allowedApp = apps.find((a) => options.packageAllowlist.includes(a.packageId));
81
- if (allowedApp)
82
- return allowedApp;
83
- }
84
- if (apps.length > 0)
85
- return apps[0];
65
+ let targetId;
66
+ if (options?.packageAllowlist &&
67
+ Array.isArray(options.packageAllowlist) &&
68
+ options.packageAllowlist.length > 0) {
69
+ const allowed = packages.find((p) => options.packageAllowlist.includes(p.id));
70
+ targetId = allowed ? allowed.id : (packages[0]?.id || "");
86
71
  }
87
- const innerTarget = target?.unwrap?.();
88
- if (innerTarget && "listApps" in innerTarget) {
89
- const apps = innerTarget.listApps();
90
- if (options?.packageAllowlist &&
91
- Array.isArray(options.packageAllowlist) &&
92
- options.packageAllowlist.length > 0) {
93
- const allowedApp = apps.find((a) => options.packageAllowlist.includes(a.packageId));
94
- if (allowedApp)
95
- return allowedApp;
96
- }
97
- if (apps.length > 0)
98
- return apps[0];
72
+ else if (packages.length > 0) {
73
+ targetId = packages[0].id;
99
74
  }
100
- if (innerTarget && "packageId" in innerTarget) {
101
- return innerTarget;
75
+ else {
76
+ throw new ActionDockError(PACKAGE_NOT_FOUND, "No registered package found in service");
102
77
  }
103
- throw new Error("No registered package found in host or target");
78
+ assertPackageAllowed(targetId, options);
79
+ return targetId;
104
80
  }