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