@actiondock/core 2.10.0 → 2.11.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 +1 -2
- package/dist/catalog/action-catalog.js +3 -33
- package/dist/catalog/discovery.d.ts +0 -3
- package/dist/catalog/discovery.js +4 -4
- package/dist/catalog/graph.d.ts +0 -4
- package/dist/catalog/graph.js +8 -14
- package/dist/{profile/client-actions.d.ts → client/actions.d.ts} +1 -1
- package/dist/{profile/client-actions.js → client/actions.js} +2 -8
- package/dist/{profile/client-config.d.ts → client/config.d.ts} +1 -1
- package/dist/{profile/client-config.js → client/config.js} +1 -1
- package/dist/client/dispatcher.d.ts +4 -0
- package/dist/client/dispatcher.js +21 -0
- package/dist/client/health.d.ts +38 -0
- package/dist/{profile/client-health.js → client/health.js} +9 -6
- package/dist/client/index.d.ts +16 -0
- package/dist/client/index.js +20 -0
- package/dist/{profile/client-playbooks.d.ts → client/playbooks.d.ts} +1 -1
- package/dist/{profile/client-playbooks.js → client/playbooks.js} +1 -1
- package/dist/{profile/client-runs.d.ts → client/runs.d.ts} +4 -2
- package/dist/{profile/client-runs.js → client/runs.js} +7 -1
- package/dist/{profile/client-state.d.ts → client/state.d.ts} +1 -1
- package/dist/{profile/client-state.js → client/state.js} +1 -1
- package/dist/{profile/client-transport.d.ts → client/transport.d.ts} +29 -10
- package/dist/{profile/client-transport.js → client/transport.js} +125 -35
- package/dist/doctor/checks/index.d.ts +1 -1
- package/dist/doctor/checks/index.js +1 -1
- package/dist/doctor/checks/project.js +20 -88
- package/dist/doctor/checks/runtime.d.ts +0 -4
- package/dist/doctor/checks/runtime.js +0 -28
- package/dist/doctor/doctor.js +1 -2
- package/dist/errors.d.ts +53 -3
- package/dist/errors.js +53 -3
- package/dist/execution/service.d.ts +55 -37
- package/dist/execution/service.js +601 -212
- package/dist/execution/types.d.ts +24 -5
- package/dist/host/host.d.ts +42 -22
- package/dist/host/host.js +562 -149
- package/dist/host/routing.js +6 -6
- package/dist/host/types.d.ts +25 -13
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/input/advice.d.ts +0 -44
- package/dist/input/advice.js +7 -141
- package/dist/input/flat-materializer.js +1 -1
- package/dist/input/flat-parser.js +1 -1
- package/dist/input/index.d.ts +0 -1
- package/dist/input/index.js +0 -1
- package/dist/input/input-resolver.js +1 -1
- package/dist/input/validation-mapper.d.ts +1 -1
- package/dist/ipc/diagnostic.d.ts +8 -21
- package/dist/ipc/diagnostic.js +24 -57
- package/dist/ipc/host.js +21 -7
- package/dist/ipc/service.d.ts +14 -0
- package/dist/ipc/service.js +132 -26
- package/dist/ipc/types.d.ts +0 -4
- package/dist/package/index.d.ts +4 -5
- package/dist/package/index.js +1 -2
- package/dist/package/runtime.d.ts +94 -23
- package/dist/package/runtime.js +628 -274
- package/dist/package/static-index.d.ts +3 -6
- package/dist/package/static-index.js +11 -40
- package/dist/package/types.d.ts +19 -4
- package/dist/platform/index.d.ts +2 -1
- package/dist/platform/index.js +2 -1
- package/dist/platform/loader-hook.d.ts +32 -0
- package/dist/platform/loader-hook.js +90 -0
- package/dist/{node → platform}/module-loader.d.ts +13 -0
- package/dist/{node → platform}/module-loader.js +51 -4
- package/dist/platform/node.d.ts +19 -8
- package/dist/platform/node.js +50 -20
- package/dist/platform/types.d.ts +7 -47
- package/dist/process/context-process.d.ts +3 -18
- package/dist/process/context-process.js +3 -44
- package/dist/process/control.d.ts +21 -0
- package/dist/process/control.js +34 -0
- package/dist/process/converters.d.ts +23 -0
- package/dist/process/converters.js +92 -0
- package/dist/process/cursor.js +2 -22
- package/dist/process/{diagnostics-sink.d.ts → diagnostics.d.ts} +0 -7
- package/dist/process/{diagnostics-sink.js → diagnostics.js} +6 -8
- package/dist/process/index.d.ts +1 -3
- package/dist/process/index.js +1 -3
- package/dist/process/input-dispatcher.d.ts +4 -13
- package/dist/process/input-dispatcher.js +48 -69
- package/dist/process/managed-record.d.ts +3 -31
- package/dist/process/metadata-store.d.ts +0 -41
- package/dist/process/metadata-store.js +2 -341
- package/dist/process/process-driver.js +2 -2
- package/dist/process/process-manager.d.ts +8 -50
- package/dist/process/process-manager.js +28 -417
- package/dist/process/quotas.d.ts +14 -0
- package/dist/process/quotas.js +29 -0
- package/dist/process/run-executor.js +0 -1
- package/dist/process/terminal-output-cache.d.ts +20 -34
- package/dist/process/terminal-output-cache.js +43 -64
- package/dist/profile/index.d.ts +1 -2
- package/dist/profile/index.js +1 -2
- package/dist/profile/manager.d.ts +2 -4
- package/dist/profile/manager.js +10 -40
- package/dist/profile/types.d.ts +1 -17
- package/dist/project/digest.d.ts +5 -1
- package/dist/project/digest.js +81 -219
- package/dist/project/index.d.ts +4 -5
- package/dist/project/index.js +4 -5
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +3 -3
- package/dist/project/loader.js +72 -50
- package/dist/project/lockfile.js +6 -5
- package/dist/project/manifest.js +5 -4
- package/dist/project/transactions.d.ts +4 -42
- package/dist/project/transactions.js +83 -138
- package/dist/project/types-generator.js +2 -1
- package/dist/project/types.d.ts +2 -0
- package/dist/registry/index.d.ts +0 -1
- package/dist/registry/index.js +0 -1
- package/dist/registry/lock.d.ts +2 -11
- package/dist/registry/lock.js +14 -183
- package/dist/registry/registry.d.ts +1 -6
- package/dist/registry/registry.js +5 -17
- package/dist/runtime/action-registry.d.ts +1 -5
- package/dist/runtime/action-registry.js +0 -12
- package/dist/runtime/context.js +2 -2
- package/dist/runtime/events.d.ts +11 -50
- package/dist/runtime/events.js +88 -368
- package/dist/runtime/index.d.ts +0 -4
- package/dist/runtime/index.js +0 -4
- package/dist/runtime/run-persistence.d.ts +2 -0
- package/dist/runtime/run-persistence.js +2 -1
- package/dist/runtime/standalone-commands.d.ts +18 -0
- package/dist/runtime/standalone-commands.js +466 -0
- package/dist/runtime/standalone-help.d.ts +20 -0
- package/dist/runtime/standalone-help.js +72 -0
- package/dist/runtime/standalone.d.ts +1 -44
- package/dist/runtime/standalone.js +32 -573
- package/dist/schema/validator.d.ts +2 -2
- package/dist/schema/validator.js +2 -9
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +0 -2
- package/dist/server/routes/actions.js +1 -1
- package/dist/server/routes/info.js +1 -1
- package/dist/server/routes/playbooks.js +1 -1
- package/dist/server/routes/runs.js +123 -16
- package/dist/server/routes/state.js +43 -18
- package/dist/server/security.d.ts +1 -1
- package/dist/server/security.js +2 -2
- package/dist/server/server.js +3 -7
- package/dist/service/factory.js +4 -3
- package/dist/service/index.d.ts +1 -1
- package/dist/service/index.js +1 -1
- package/dist/service/remote-errors.d.ts +1 -1
- package/dist/service/remote-errors.js +6 -6
- package/dist/service/remote-polling.d.ts +3 -0
- package/dist/service/remote-polling.js +10 -5
- package/dist/service/remote.d.ts +5 -1
- package/dist/service/remote.js +108 -17
- package/dist/service/sse-stream.js +2 -2
- package/dist/service/types.d.ts +22 -19
- package/dist/service/types.js +1 -24
- package/dist/storage/clock.d.ts +1 -1
- package/dist/storage/clock.js +1 -1
- package/dist/storage/data-dir-lock.d.ts +10 -22
- package/dist/storage/data-dir-lock.js +28 -56
- package/dist/storage/file-lock.d.ts +64 -0
- package/dist/storage/file-lock.js +447 -0
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +5 -4
- package/dist/storage/run-liveness.d.ts +48 -0
- package/dist/storage/run-liveness.js +44 -0
- package/dist/storage/sqlite-config.d.ts +16 -0
- package/dist/storage/sqlite-config.js +59 -0
- package/dist/storage/sqlite-driver.d.ts +3 -1
- package/dist/storage/sqlite-driver.js +14 -4
- package/dist/storage/sqlite-events.d.ts +13 -0
- package/dist/storage/sqlite-events.js +48 -0
- package/dist/storage/sqlite-runs.d.ts +107 -0
- package/dist/storage/sqlite-runs.js +622 -0
- package/dist/storage/sqlite-schema.d.ts +5 -0
- package/dist/storage/sqlite-schema.js +143 -0
- package/dist/storage/sqlite-state.d.ts +33 -0
- package/dist/storage/sqlite-state.js +270 -0
- package/dist/storage/sqlite.d.ts +30 -57
- package/dist/storage/sqlite.js +84 -741
- package/dist/storage/types.d.ts +35 -2
- package/dist/utils/index.d.ts +18 -14
- package/dist/utils/index.js +37 -29
- package/dist/utils/semver.d.ts +18 -0
- package/dist/utils/semver.js +19 -0
- package/dist/utils/warning.d.ts +1 -0
- package/dist/utils/warning.js +52 -0
- package/dist/{json/value-validator.d.ts → value-validator.d.ts} +9 -0
- package/dist/value-validator.js +330 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -12
- package/dist/execution/index.d.ts +0 -2
- package/dist/execution/index.js +0 -2
- package/dist/filter/index.d.ts +0 -1
- package/dist/filter/index.js +0 -1
- package/dist/graph/index.d.ts +0 -4
- package/dist/graph/index.js +0 -4
- package/dist/input/metadata.d.ts +0 -99
- package/dist/input/metadata.js +0 -99
- package/dist/invocation/index.d.ts +0 -2
- package/dist/invocation/index.js +0 -2
- package/dist/ipc/index.d.ts +0 -4
- package/dist/ipc/index.js +0 -4
- package/dist/json/index.d.ts +0 -1
- package/dist/json/index.js +0 -1
- package/dist/json/value-validator.js +0 -330
- package/dist/node/index.d.ts +0 -1
- package/dist/node/index.js +0 -1
- package/dist/platform/node-fs.d.ts +0 -37
- package/dist/platform/node-fs.js +0 -81
- package/dist/process/control-arbiter.d.ts +0 -108
- package/dist/process/control-arbiter.js +0 -250
- package/dist/process/process-executor.d.ts +0 -47
- package/dist/process/process-executor.js +0 -296
- package/dist/profile/client-health.d.ts +0 -14
- package/dist/profile/client-query.d.ts +0 -30
- package/dist/profile/client-query.js +0 -69
- package/dist/profile/client.d.ts +0 -26
- package/dist/profile/client.js +0 -31
- package/dist/project/closure.d.ts +0 -25
- package/dist/project/closure.js +0 -74
- package/dist/registry/store.d.ts +0 -42
- package/dist/registry/store.js +0 -43
- package/dist/runtime/clock.d.ts +0 -7
- package/dist/runtime/clock.js +0 -7
- package/dist/runtime/module-loader.d.ts +0 -2
- package/dist/runtime/module-loader.js +0 -1
- package/dist/runtime/process.d.ts +0 -8
- package/dist/runtime/process.js +0 -1
- package/dist/runtime/runner.d.ts +0 -234
- package/dist/runtime/runner.js +0 -609
- package/dist/schema/index.d.ts +0 -1
- package/dist/schema/index.js +0 -1
- package/dist/server/dispatcher.d.ts +0 -25
- package/dist/server/dispatcher.js +0 -54
- package/dist/service/local.d.ts +0 -27
- package/dist/service/local.js +0 -141
- package/dist/storage/driver.d.ts +0 -10
- package/dist/storage/driver.js +0 -10
- package/dist/storage/lazy.d.ts +0 -8
- package/dist/storage/lazy.js +0 -45
- package/dist/storage/lock-core.d.ts +0 -158
- package/dist/storage/lock-core.js +0 -872
- package/dist/utils/net.d.ts +0 -10
- package/dist/utils/net.js +0 -16
- package/dist/utils/process.d.ts +0 -10
- package/dist/utils/process.js +0 -21
- /package/dist/{filter → utils}/intent.d.ts +0 -0
- /package/dist/{filter → utils}/intent.js +0 -0
package/dist/storage/types.d.ts
CHANGED
|
@@ -200,7 +200,16 @@ export interface RuntimeStorage {
|
|
|
200
200
|
actionId?: string;
|
|
201
201
|
status?: string;
|
|
202
202
|
limit?: number;
|
|
203
|
+
offset?: number;
|
|
203
204
|
}): RunRecord[];
|
|
205
|
+
/** 统计符合条件的运行记录总数 */
|
|
206
|
+
countRuns?(options?: {
|
|
207
|
+
actionId?: string;
|
|
208
|
+
status?: string;
|
|
209
|
+
requestIds?: string[];
|
|
210
|
+
}): number;
|
|
211
|
+
/** 查询单条运行记录并补齐幂等请求标识关联(详情路径专用) */
|
|
212
|
+
getRunWithRequestId?(id: string): RunRecord | null;
|
|
204
213
|
clearRuns(options?: {
|
|
205
214
|
actionId?: string;
|
|
206
215
|
status?: string;
|
|
@@ -210,14 +219,38 @@ export interface RuntimeStorage {
|
|
|
210
219
|
/** 按保留策略清理过期及超额的终态运行记录(基于时间与数量策略) */
|
|
211
220
|
cleanExpiredRuns?(policy?: RunsRetentionPolicy): number;
|
|
212
221
|
/**
|
|
213
|
-
*
|
|
222
|
+
* 收敛死亡宿主遗留的非终态运行任务(含无会话标识的遗留非终态记录),
|
|
214
223
|
* 统一收敛为 interrupted。历史别名 recoverRunningRuns 已合并至本方法。
|
|
224
|
+
*
|
|
225
|
+
* 判定依据是宿主存活而不是会话归属:仅收割进程探测失败或心跳过期的记录,
|
|
226
|
+
* 无法确认死亡时保守保留,避免误杀并发进程的在途任务。
|
|
215
227
|
*/
|
|
216
|
-
recoverDeadSessionRuns?(currentHostSessionId?: string
|
|
228
|
+
recoverDeadSessionRuns?(currentHostSessionId?: string, options?: {
|
|
229
|
+
probe?: import("./run-liveness.js").ProcessLivenessProbe;
|
|
230
|
+
}): number | Promise<number>;
|
|
231
|
+
/** 刷新在途运行记录的心跳时间戳(供执行宿主周期性调用,支撑存活判定) */
|
|
232
|
+
touchRunHeartbeat?(runIds: string[]): number;
|
|
217
233
|
/** 确保底层存储与 Schema 初始化完成 */
|
|
218
234
|
ensureInitialized?(): Promise<void>;
|
|
219
235
|
checkAndRecordIdempotency?(record: IdempotencyRecord): IdempotencyCheckResult;
|
|
220
236
|
getIdempotencyRecord?(ownerId: string, actionRef: string, requestId: string): IdempotencyRecord | undefined;
|
|
237
|
+
/**
|
|
238
|
+
* 按客户端幂等请求标识批量反查运行记录(仅限当前包范围)。
|
|
239
|
+
*
|
|
240
|
+
* 不按 ownerId 隔离:查询方(CLI 旁观视图)与写入方(后台派工进程)分属
|
|
241
|
+
* 不同宿主会话,ownerId 天然不一致;requestId 本身即跨进程全局唯一的外部
|
|
242
|
+
* 事实源,包维度隔离已提供足够边界。
|
|
243
|
+
*/
|
|
244
|
+
listRunsByRequestIds?(requestIds: string[]): RunRecord[];
|
|
245
|
+
/** 按客户端幂等请求标识反查关联运行记录总数 */
|
|
246
|
+
countRunsByRequestIds?(requestIds: string[], options?: {
|
|
247
|
+
actionId?: string;
|
|
248
|
+
status?: string;
|
|
249
|
+
}): number;
|
|
250
|
+
/** 反查运行记录关联的幂等请求标识映射(仅限当前包范围,无关联时不含对应键) */
|
|
251
|
+
getRunRequestIds?(runIds: string[]): Record<string, string>;
|
|
252
|
+
appendEvent?(eventType: string, payload: unknown): void;
|
|
253
|
+
queryEvents?(eventType?: string): any[];
|
|
221
254
|
/** 关闭底层 SQLite 数据库连接并释放句柄 */
|
|
222
255
|
close(): void | Promise<void>;
|
|
223
256
|
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
export { isLoopbackHost } from "./net.js";
|
|
2
|
-
export { isProcessAlive } from "./process.js";
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
2
|
+
* 检查指定的主机地址是否为本地回环接口(Loopback Host)。
|
|
3
|
+
* 支持 127.0.0.1, localhost, ::1 等形式。
|
|
4
|
+
*
|
|
5
|
+
* @param host 主机名或 IP 字符串
|
|
5
6
|
*/
|
|
6
|
-
export
|
|
7
|
-
major: number;
|
|
8
|
-
minor: number;
|
|
9
|
-
patch: number;
|
|
10
|
-
prerelease?: string;
|
|
11
|
-
}
|
|
7
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
12
8
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
9
|
+
* 检查目标进程是否处于存活状态(跨域通用谓词单一事实源)。
|
|
10
|
+
*
|
|
11
|
+
* 基于 process.kill(pid, 0) 探测:无异常视为存活;ESRCH(进程不存在)
|
|
12
|
+
* 视为已死;其他异常(如 EPERM,权限不足但进程存在)保守视为存活,
|
|
13
|
+
* 避免权限受限环境下误判他人持有进程死亡而抢占其锁。
|
|
14
|
+
*
|
|
15
|
+
* @param pid 待检测的进程标识符
|
|
16
16
|
*/
|
|
17
|
-
export declare function
|
|
17
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
18
|
+
/** 转引独立的语义化版本纯函数,保持既有公共导出面。 */
|
|
19
|
+
export type { SemVer } from "./semver.js";
|
|
20
|
+
export { parseSemVer } from "./semver.js";
|
|
18
21
|
/**
|
|
19
22
|
* 目录遍历条目描述。
|
|
20
23
|
*/
|
|
@@ -53,7 +56,7 @@ export interface TraverseDirectoryOptions {
|
|
|
53
56
|
*/
|
|
54
57
|
export declare function traverseDirectory(root: string, options?: TraverseDirectoryOptions): TraverseDirectoryEntry[];
|
|
55
58
|
/**
|
|
56
|
-
*
|
|
59
|
+
* 安全查找可执行文件绝对物理路径。
|
|
57
60
|
*
|
|
58
61
|
* 注意:本函数为同步实现,内部同步遍历 PATH 逐个探测物理文件存在性;
|
|
59
62
|
* 当前全部调用方(doctor 体检与测试 CLI 桥)均为同步链路,serve 链路未使用本函数,
|
|
@@ -101,3 +104,4 @@ export declare function assertPathWithinRoot(rootDir: string, targetPath: string
|
|
|
101
104
|
* Backwards-compatible alias for assertPathWithinRoot targeting project roots.
|
|
102
105
|
*/
|
|
103
106
|
export declare function assertWithinProjectRoot(projectRoot: string, subDir: string, fieldName: string): void;
|
|
107
|
+
export { suppressExperimentalWarnings } from "./warning.js";
|
package/dist/utils/index.js
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
1
|
import { existsSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
-
import { ActionDockError, INVALID_PACKAGE_ID, PATH_TRAVERSAL } from "../errors.js";
|
|
5
|
-
export { isLoopbackHost } from "./net.js";
|
|
6
|
-
export { isProcessAlive } from "./process.js";
|
|
4
|
+
import { ActionDockError, INVALID_ARGUMENT, INVALID_PACKAGE_ID, PATH_TRAVERSAL } from "../errors.js";
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* 检查指定的主机地址是否为本地回环接口(Loopback Host)。
|
|
7
|
+
* 支持 127.0.0.1, localhost, ::1 等形式。
|
|
8
|
+
*
|
|
9
|
+
* @param host 主机名或 IP 字符串
|
|
11
10
|
*/
|
|
12
|
-
export function
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
export function isLoopbackHost(host) {
|
|
12
|
+
const trimmed = host.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
13
|
+
return (trimmed === "127.0.0.1" ||
|
|
14
|
+
trimmed === "::1" ||
|
|
15
|
+
trimmed === "localhost" ||
|
|
16
|
+
trimmed === "0:0:0:0:0:0:0:1");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 检查目标进程是否处于存活状态(跨域通用谓词单一事实源)。
|
|
20
|
+
*
|
|
21
|
+
* 基于 process.kill(pid, 0) 探测:无异常视为存活;ESRCH(进程不存在)
|
|
22
|
+
* 视为已死;其他异常(如 EPERM,权限不足但进程存在)保守视为存活,
|
|
23
|
+
* 避免权限受限环境下误判他人持有进程死亡而抢占其锁。
|
|
24
|
+
*
|
|
25
|
+
* @param pid 待检测的进程标识符
|
|
26
|
+
*/
|
|
27
|
+
export function isProcessAlive(pid) {
|
|
28
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
process.kill(pid, 0);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
return err?.code !== "ESRCH";
|
|
37
|
+
}
|
|
22
38
|
}
|
|
39
|
+
export { parseSemVer } from "./semver.js";
|
|
23
40
|
/**
|
|
24
41
|
* 递归遍历目录的单一事实源实现(同步)。
|
|
25
42
|
*
|
|
@@ -98,23 +115,13 @@ export function traverseDirectory(root, options = {}) {
|
|
|
98
115
|
return results;
|
|
99
116
|
}
|
|
100
117
|
/**
|
|
101
|
-
*
|
|
118
|
+
* 安全查找可执行文件绝对物理路径。
|
|
102
119
|
*
|
|
103
120
|
* 注意:本函数为同步实现,内部同步遍历 PATH 逐个探测物理文件存在性;
|
|
104
121
|
* 当前全部调用方(doctor 体检与测试 CLI 桥)均为同步链路,serve 链路未使用本函数,
|
|
105
122
|
* 因此暂不提供异步版本。若后续异步链路需要,应另行新增异步实现而非改造本函数。
|
|
106
123
|
*/
|
|
107
124
|
export function findExecutable(command) {
|
|
108
|
-
if (typeof globalThis.Bun !== "undefined" && typeof globalThis.Bun.which === "function") {
|
|
109
|
-
try {
|
|
110
|
-
const bPath = globalThis.Bun.which(command);
|
|
111
|
-
if (bPath)
|
|
112
|
-
return bPath;
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
// ignore
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
125
|
const hasPathSep = command.includes("/") || command.includes("\\");
|
|
119
126
|
if (hasPathSep) {
|
|
120
127
|
return existsSync(command) ? command : null;
|
|
@@ -150,7 +157,7 @@ export function parseDuration(input) {
|
|
|
150
157
|
}
|
|
151
158
|
const match = str.match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);
|
|
152
159
|
if (!match) {
|
|
153
|
-
throw new
|
|
160
|
+
throw new ActionDockError(INVALID_ARGUMENT, `Invalid duration format: '${input}'. Supported formats: 500ms, 30s, 5m, 1h`);
|
|
154
161
|
}
|
|
155
162
|
const val = parseFloat(match[1]);
|
|
156
163
|
const unit = match[2].toLowerCase();
|
|
@@ -270,7 +277,8 @@ export function assertPathWithinRoot(rootDir, targetPath, fieldName = "path") {
|
|
|
270
277
|
*/
|
|
271
278
|
export function assertWithinProjectRoot(projectRoot, subDir, fieldName) {
|
|
272
279
|
if (isAbsolute(subDir)) {
|
|
273
|
-
throw new
|
|
280
|
+
throw new ActionDockError(INVALID_ARGUMENT, `'${fieldName}' cannot be an absolute path: ${subDir}`);
|
|
274
281
|
}
|
|
275
282
|
assertPathWithinRoot(projectRoot, subDir, fieldName);
|
|
276
283
|
}
|
|
284
|
+
export { suppressExperimentalWarnings } from "./warning.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 语义化版本元数据结构。
|
|
3
|
+
*/
|
|
4
|
+
export interface SemVer {
|
|
5
|
+
major: number;
|
|
6
|
+
minor: number;
|
|
7
|
+
patch: number;
|
|
8
|
+
prerelease?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 解析基础 SemVer 版本字符串(单一事实源)。
|
|
12
|
+
* 仅接受可选 v/= 前缀的严格三段式语义化版本,可携带预发布后缀;
|
|
13
|
+
* 其余形态(两段式、非数值等)返回 null,由调用方自行兜底。
|
|
14
|
+
*
|
|
15
|
+
* 本模块不依赖任何 Node 内建与 core 领域模块,可在无 loader 的原生
|
|
16
|
+
* Node 直接以 .ts 形态导入(工程脚本域复用此处单一事实源)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseSemVer(v: string): SemVer | null;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析基础 SemVer 版本字符串(单一事实源)。
|
|
3
|
+
* 仅接受可选 v/= 前缀的严格三段式语义化版本,可携带预发布后缀;
|
|
4
|
+
* 其余形态(两段式、非数值等)返回 null,由调用方自行兜底。
|
|
5
|
+
*
|
|
6
|
+
* 本模块不依赖任何 Node 内建与 core 领域模块,可在无 loader 的原生
|
|
7
|
+
* Node 直接以 .ts 形态导入(工程脚本域复用此处单一事实源)。
|
|
8
|
+
*/
|
|
9
|
+
export function parseSemVer(v) {
|
|
10
|
+
const match = v.trim().replace(/^[v=]/, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
|
|
11
|
+
if (!match)
|
|
12
|
+
return null;
|
|
13
|
+
return {
|
|
14
|
+
major: parseInt(match[1], 10),
|
|
15
|
+
minor: parseInt(match[2], 10),
|
|
16
|
+
patch: parseInt(match[3], 10),
|
|
17
|
+
prerelease: match[4],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function suppressExperimentalWarnings(): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 全局禁用 Node.js 所有的 ExperimentalWarning 实验性特性警告。
|
|
3
|
+
* 跨所有 Node.js 运行版本,不区分具体特性(如 SQLite、类型擦除等),
|
|
4
|
+
* 在进程级别统一静默全部实验性警告,同时完整保留废弃警告与运行期异常。
|
|
5
|
+
*
|
|
6
|
+
* 逃生通道:当环境变量 ACTIONDOCK_SILENCE_WARNINGS 显式设置为 "0" 时,放弃静默以供深度调试排查。
|
|
7
|
+
*/
|
|
8
|
+
const kExperimentalWarningSuppressed = Symbol.for("actiondock.experimental_warning_suppressed");
|
|
9
|
+
export function suppressExperimentalWarnings() {
|
|
10
|
+
// 逃生通道:支持开发者显式禁用静默逻辑,确保排障透明度
|
|
11
|
+
if (process.env.ACTIONDOCK_SILENCE_WARNINGS === "0") {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const globalObj = globalThis;
|
|
15
|
+
if (globalObj[kExperimentalWarningSuppressed]) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
globalObj[kExperimentalWarningSuppressed] = true;
|
|
19
|
+
// 1. 拦截 process.emitWarning 源头
|
|
20
|
+
const originalEmitWarning = process.emitWarning;
|
|
21
|
+
if (typeof originalEmitWarning === "function") {
|
|
22
|
+
process.emitWarning = function (warning, ...args) {
|
|
23
|
+
if (typeof warning === "string") {
|
|
24
|
+
const type = typeof args[0] === "string" ? args[0] : args[0]?.type || args[1];
|
|
25
|
+
if (type === "ExperimentalWarning") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if (warning) {
|
|
30
|
+
const warnObj = warning;
|
|
31
|
+
if (warnObj.name === "ExperimentalWarning" || warnObj.type === "ExperimentalWarning") {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return Reflect.apply(originalEmitWarning, process, [warning, ...args]);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// 2. 包装进程级 warning 事件分发器,作为双层防护
|
|
39
|
+
const originalListeners = process.listeners("warning");
|
|
40
|
+
process.removeAllListeners("warning");
|
|
41
|
+
process.on("warning", (warning) => {
|
|
42
|
+
const warnObj = warning;
|
|
43
|
+
if (warnObj.name === "ExperimentalWarning" || warnObj.type === "ExperimentalWarning") {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
for (const listener of originalListeners) {
|
|
47
|
+
listener.call(process, warning);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// 模块被引入时立即自执行
|
|
52
|
+
suppressExperimentalWarnings();
|
|
@@ -79,6 +79,15 @@ export declare function validateJsonValue(value: unknown, options?: ValidateJson
|
|
|
79
79
|
* @returns 校验结果对象
|
|
80
80
|
*/
|
|
81
81
|
export declare function validateActionInputValue(value: unknown, options?: ValidateActionInputOptions): ActionInputValidationResult;
|
|
82
|
+
/**
|
|
83
|
+
* 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
|
|
84
|
+
* 针对环路对象与有向无环图(DAG)保证安全遍历且具有深度上限防御。
|
|
85
|
+
*
|
|
86
|
+
* @param data 待检查的目标数据
|
|
87
|
+
* @param maxDepth 最大允许嵌套深度(默认 256)
|
|
88
|
+
* @returns 若存在危险键名则返回 true,否则返回 false
|
|
89
|
+
*/
|
|
90
|
+
export declare function hasDangerousKeys(data: unknown, maxDepth?: number): boolean;
|
|
82
91
|
/**
|
|
83
92
|
* 断言值必须为合法的 Canonical JSON 兼容结构,若非法则抛出 TypeError。
|
|
84
93
|
*
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { isForbiddenActionInputPropertyName } from "./input/flat-predicates.js";
|
|
2
|
+
/** 默认 JSON 最大嵌套深度限制(防止恶意超深结构) */
|
|
3
|
+
export const DEFAULT_MAX_JSON_DEPTH = 256;
|
|
4
|
+
/** 最大安全递归调用栈深度,防止超大自定义 maxDepth 导致栈溢出 */
|
|
5
|
+
const MAX_SAFE_RECURSION_DEPTH = 2048;
|
|
6
|
+
/**
|
|
7
|
+
* 按照 RFC 6901 转义单个 JSON Pointer 路径段。
|
|
8
|
+
*
|
|
9
|
+
* @param segment 路径段(属性名或数组索引)
|
|
10
|
+
* @returns 转义后的路径段
|
|
11
|
+
*/
|
|
12
|
+
export function escapeJsonPointerSegment(segment) {
|
|
13
|
+
return String(segment).replace(/~/g, "~0").replace(/\//g, "~1");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 将路径段追加到基础 RFC 6901 JSON Pointer 路径后。
|
|
17
|
+
*
|
|
18
|
+
* @param basePath 基础路径
|
|
19
|
+
* @param segment 待追加的路径段
|
|
20
|
+
* @returns 拼接后的 JSON Pointer
|
|
21
|
+
*/
|
|
22
|
+
export function appendJsonPointer(basePath, segment) {
|
|
23
|
+
return `${basePath}/${escapeJsonPointerSegment(segment)}`;
|
|
24
|
+
}
|
|
25
|
+
function walkJsonValue(val, depth, path, maxDepth, ancestors, checkForbidden) {
|
|
26
|
+
if (val === null || typeof val === "boolean" || typeof val === "string") {
|
|
27
|
+
return { valid: true };
|
|
28
|
+
}
|
|
29
|
+
if (typeof val === "number") {
|
|
30
|
+
if (!Number.isFinite(val) || Number.isNaN(val)) {
|
|
31
|
+
return {
|
|
32
|
+
valid: false,
|
|
33
|
+
kind: "json-value",
|
|
34
|
+
code: "NON_FINITE_NUMBER",
|
|
35
|
+
reason: `Number is non-finite or NaN (${val})`,
|
|
36
|
+
path,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return { valid: true };
|
|
40
|
+
}
|
|
41
|
+
if (typeof val === "undefined") {
|
|
42
|
+
return {
|
|
43
|
+
valid: false,
|
|
44
|
+
kind: "json-value",
|
|
45
|
+
code: "UNDEFINED_JSON_VALUE",
|
|
46
|
+
reason: "Undefined value is not allowed in JSON",
|
|
47
|
+
path,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (typeof val === "function" ||
|
|
51
|
+
typeof val === "symbol" ||
|
|
52
|
+
typeof val === "bigint") {
|
|
53
|
+
return {
|
|
54
|
+
valid: false,
|
|
55
|
+
kind: "json-value",
|
|
56
|
+
code: "UNSUPPORTED_JSON_TYPE",
|
|
57
|
+
reason: `Unsupported JSON type '${typeof val}'`,
|
|
58
|
+
path,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (typeof val === "object") {
|
|
62
|
+
if (depth > maxDepth || depth > MAX_SAFE_RECURSION_DEPTH) {
|
|
63
|
+
return {
|
|
64
|
+
valid: false,
|
|
65
|
+
kind: "json-value",
|
|
66
|
+
code: "MAX_JSON_DEPTH",
|
|
67
|
+
reason: `Max JSON depth limit (${maxDepth}) exceeded`,
|
|
68
|
+
path,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (ancestors.has(val)) {
|
|
72
|
+
return {
|
|
73
|
+
valid: false,
|
|
74
|
+
kind: "json-value",
|
|
75
|
+
code: "CIRCULAR_REFERENCE",
|
|
76
|
+
reason: "Circular reference detected in object structure",
|
|
77
|
+
path,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
if (Array.isArray(val)) {
|
|
82
|
+
if (Object.getPrototypeOf(val) !== Array.prototype) {
|
|
83
|
+
return {
|
|
84
|
+
valid: false,
|
|
85
|
+
kind: "json-value",
|
|
86
|
+
code: "INVALID_JSON_OBJECT",
|
|
87
|
+
reason: "Array prototype must be Array.prototype",
|
|
88
|
+
path,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// 稀疏数组(存在 hole)不是合法 JSON 结构
|
|
92
|
+
for (let i = 0; i < val.length; i++) {
|
|
93
|
+
if (!(i in val)) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
kind: "json-value",
|
|
97
|
+
code: "INVALID_JSON_OBJECT",
|
|
98
|
+
reason: `Sparse array (hole at index ${i}) is not allowed in JSON`,
|
|
99
|
+
path: appendJsonPointer(path, i),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 数组只允许索引元素,拒绝额外字符串属性或 Symbol 属性(忽略不可枚举的内建属性如 length)
|
|
104
|
+
const extraKeys = Reflect.ownKeys(val).filter((k) => {
|
|
105
|
+
if (typeof k === "symbol")
|
|
106
|
+
return true;
|
|
107
|
+
if (!/^\d+$/.test(k) || Number(k) >= val.length) {
|
|
108
|
+
const desc = Object.getOwnPropertyDescriptor(val, k);
|
|
109
|
+
// 不可枚举属性(如数组内建 length)不视为额外属性
|
|
110
|
+
return desc?.enumerable === true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
});
|
|
114
|
+
if (extraKeys.length > 0) {
|
|
115
|
+
return {
|
|
116
|
+
valid: false,
|
|
117
|
+
kind: "json-value",
|
|
118
|
+
code: "INVALID_JSON_OBJECT",
|
|
119
|
+
reason: "Arrays must not carry extra properties beyond indexed elements",
|
|
120
|
+
path,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
ancestors.add(val);
|
|
124
|
+
try {
|
|
125
|
+
for (let i = 0; i < val.length; i++) {
|
|
126
|
+
const res = walkJsonValue(val[i], depth + 1, appendJsonPointer(path, i), maxDepth, ancestors, checkForbidden);
|
|
127
|
+
if (!res.valid)
|
|
128
|
+
return res;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
ancestors.delete(val);
|
|
133
|
+
}
|
|
134
|
+
return { valid: true };
|
|
135
|
+
}
|
|
136
|
+
const proto = Object.getPrototypeOf(val);
|
|
137
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
138
|
+
return {
|
|
139
|
+
valid: false,
|
|
140
|
+
kind: "json-value",
|
|
141
|
+
code: "INVALID_JSON_OBJECT",
|
|
142
|
+
reason: "Object prototype must be Object.prototype or null",
|
|
143
|
+
path,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const ownKeys = Reflect.ownKeys(val);
|
|
147
|
+
if (checkForbidden) {
|
|
148
|
+
for (let i = 0; i < ownKeys.length; i++) {
|
|
149
|
+
const key = ownKeys[i];
|
|
150
|
+
if (typeof key === "string" && isForbiddenActionInputPropertyName(key)) {
|
|
151
|
+
return {
|
|
152
|
+
valid: false,
|
|
153
|
+
kind: "input-policy",
|
|
154
|
+
code: "FORBIDDEN_PROPERTY",
|
|
155
|
+
property: key,
|
|
156
|
+
path: appendJsonPointer(path, key),
|
|
157
|
+
reason: `Forbidden property "${key}" is not allowed in Action input`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
ancestors.add(val);
|
|
163
|
+
try {
|
|
164
|
+
for (let i = 0; i < ownKeys.length; i++) {
|
|
165
|
+
const key = ownKeys[i];
|
|
166
|
+
if (typeof key !== "string") {
|
|
167
|
+
return {
|
|
168
|
+
valid: false,
|
|
169
|
+
kind: "json-value",
|
|
170
|
+
code: "INVALID_JSON_OBJECT",
|
|
171
|
+
reason: "Symbol-keyed properties are not allowed in JSON object",
|
|
172
|
+
path: appendJsonPointer(path, String(key)),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const propPath = appendJsonPointer(path, key);
|
|
176
|
+
const desc = Object.getOwnPropertyDescriptor(val, key);
|
|
177
|
+
if (!desc)
|
|
178
|
+
continue;
|
|
179
|
+
if (desc.get !== undefined || desc.set !== undefined) {
|
|
180
|
+
return {
|
|
181
|
+
valid: false,
|
|
182
|
+
kind: "json-value",
|
|
183
|
+
code: "INVALID_JSON_OBJECT",
|
|
184
|
+
reason: `Accessor properties (getters/setters) are not allowed for key "${key}"`,
|
|
185
|
+
path: propPath,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (!desc.enumerable) {
|
|
189
|
+
return {
|
|
190
|
+
valid: false,
|
|
191
|
+
kind: "json-value",
|
|
192
|
+
code: "INVALID_JSON_OBJECT",
|
|
193
|
+
reason: `Non-enumerable properties are not allowed for key "${key}"`,
|
|
194
|
+
path: propPath,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (desc.value === undefined) {
|
|
198
|
+
return {
|
|
199
|
+
valid: false,
|
|
200
|
+
kind: "json-value",
|
|
201
|
+
code: "UNDEFINED_JSON_VALUE",
|
|
202
|
+
reason: `Undefined value is not allowed for key "${key}"`,
|
|
203
|
+
path: propPath,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const res = walkJsonValue(desc.value, depth + 1, propPath, maxDepth, ancestors, checkForbidden);
|
|
207
|
+
if (!res.valid)
|
|
208
|
+
return res;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
ancestors.delete(val);
|
|
213
|
+
}
|
|
214
|
+
return { valid: true };
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
return {
|
|
218
|
+
valid: false,
|
|
219
|
+
kind: "json-value",
|
|
220
|
+
code: "INVALID_JSON_OBJECT",
|
|
221
|
+
reason: `Failed to inspect object: ${err instanceof Error ? err.message : String(err)}`,
|
|
222
|
+
path,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return { valid: true };
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 校验值是否为合法的 Canonical JSON 兼容结构。
|
|
230
|
+
*
|
|
231
|
+
* @param value 待校验的目标值
|
|
232
|
+
* @param options 校验配置选项
|
|
233
|
+
* @returns 校验结果对象
|
|
234
|
+
*/
|
|
235
|
+
export function validateJsonValue(value, options) {
|
|
236
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_MAX_JSON_DEPTH;
|
|
237
|
+
const res = walkJsonValue(value, 0, "", maxDepth, new Set(), false);
|
|
238
|
+
if (res.valid) {
|
|
239
|
+
return { valid: true };
|
|
240
|
+
}
|
|
241
|
+
if (res.kind !== "input-policy") {
|
|
242
|
+
return {
|
|
243
|
+
valid: false,
|
|
244
|
+
code: res.code,
|
|
245
|
+
reason: res.reason,
|
|
246
|
+
path: res.path,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
valid: false,
|
|
251
|
+
code: "INVALID_JSON_OBJECT",
|
|
252
|
+
reason: res.reason,
|
|
253
|
+
path: res.path,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 校验 Action 输入值是否满足 Canonical JsonValue 规范且符合 ActionDock 安全策略。
|
|
258
|
+
* 在遍历过程中递归检查是否存在禁止属性(__proto__、constructor、prototype)。
|
|
259
|
+
*
|
|
260
|
+
* @param value 待校验的 Action 输入值
|
|
261
|
+
* @param options 校验配置选项
|
|
262
|
+
* @returns 校验结果对象
|
|
263
|
+
*/
|
|
264
|
+
export function validateActionInputValue(value, options) {
|
|
265
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_MAX_JSON_DEPTH;
|
|
266
|
+
return walkJsonValue(value, 0, "", maxDepth, new Set(), true);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
|
|
270
|
+
* 针对环路对象与有向无环图(DAG)保证安全遍历且具有深度上限防御。
|
|
271
|
+
*
|
|
272
|
+
* @param data 待检查的目标数据
|
|
273
|
+
* @param maxDepth 最大允许嵌套深度(默认 256)
|
|
274
|
+
* @returns 若存在危险键名则返回 true,否则返回 false
|
|
275
|
+
*/
|
|
276
|
+
export function hasDangerousKeys(data, maxDepth = DEFAULT_MAX_JSON_DEPTH) {
|
|
277
|
+
const visited = new Set();
|
|
278
|
+
function scan(val, depth) {
|
|
279
|
+
if (!val || typeof val !== "object" || depth > maxDepth) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (visited.has(val)) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
visited.add(val);
|
|
286
|
+
try {
|
|
287
|
+
if (Array.isArray(val)) {
|
|
288
|
+
for (let i = 0; i < val.length; i++) {
|
|
289
|
+
if (scan(val[i], depth + 1))
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
const keys = Reflect.ownKeys(val);
|
|
295
|
+
for (let i = 0; i < keys.length; i++) {
|
|
296
|
+
const k = keys[i];
|
|
297
|
+
if (typeof k === "string" && isForbiddenActionInputPropertyName(k)) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
for (let i = 0; i < keys.length; i++) {
|
|
302
|
+
const k = keys[i];
|
|
303
|
+
if (typeof k === "string") {
|
|
304
|
+
const desc = Object.getOwnPropertyDescriptor(val, k);
|
|
305
|
+
if (desc && desc.value !== undefined) {
|
|
306
|
+
if (scan(desc.value, depth + 1))
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
return scan(data, 0);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 断言值必须为合法的 Canonical JSON 兼容结构,若非法则抛出 TypeError。
|
|
321
|
+
*
|
|
322
|
+
* @param value 待断言的目标值
|
|
323
|
+
* @param options 校验配置选项
|
|
324
|
+
*/
|
|
325
|
+
export function assertJsonValue(value, options) {
|
|
326
|
+
const result = validateJsonValue(value, options);
|
|
327
|
+
if (!result.valid) {
|
|
328
|
+
throw new TypeError(`Invalid JSON value: ${result.reason}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED