@lokvis/runtime 0.2.2 → 0.4.2
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/dist/asset-store.d.ts +13 -0
- package/dist/asset-store.d.ts.map +1 -1
- package/dist/asset-store.js +15 -2
- package/dist/asset-store.js.map +1 -1
- package/dist/batch-processor.d.ts +32 -161
- package/dist/batch-processor.d.ts.map +1 -1
- package/dist/batch-processor.js +107 -333
- package/dist/batch-processor.js.map +1 -1
- package/dist/batch-progress.d.ts +94 -0
- package/dist/batch-progress.d.ts.map +1 -0
- package/dist/batch-progress.js +128 -0
- package/dist/batch-progress.js.map +1 -0
- package/dist/batch-scheduler.d.ts +70 -0
- package/dist/batch-scheduler.d.ts.map +1 -0
- package/dist/batch-scheduler.js +147 -0
- package/dist/batch-scheduler.js.map +1 -0
- package/dist/browser-detect.d.ts +115 -0
- package/dist/browser-detect.d.ts.map +1 -0
- package/dist/browser-detect.js +160 -0
- package/dist/browser-detect.js.map +1 -0
- package/dist/concurrency-controller.d.ts +31 -0
- package/dist/concurrency-controller.d.ts.map +1 -0
- package/dist/concurrency-controller.js +33 -0
- package/dist/concurrency-controller.js.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/executor.d.ts +9 -0
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +102 -48
- package/dist/executor.js.map +1 -1
- package/dist/history.d.ts.map +1 -1
- package/dist/history.js +3 -2
- package/dist/history.js.map +1 -1
- package/dist/idb-asset-store.d.ts.map +1 -1
- package/dist/idb-asset-store.js +6 -1
- package/dist/idb-asset-store.js.map +1 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -15
- package/dist/index.js.map +1 -1
- package/dist/managers/asset-manager.d.ts +114 -0
- package/dist/managers/asset-manager.d.ts.map +1 -0
- package/dist/managers/asset-manager.js +238 -0
- package/dist/managers/asset-manager.js.map +1 -0
- package/dist/managers/history-manager.d.ts +100 -0
- package/dist/managers/history-manager.d.ts.map +1 -0
- package/dist/managers/history-manager.js +296 -0
- package/dist/managers/history-manager.js.map +1 -0
- package/dist/managers/mcp-manifest-builder.d.ts +18 -0
- package/dist/managers/mcp-manifest-builder.d.ts.map +1 -0
- package/dist/managers/mcp-manifest-builder.js +99 -0
- package/dist/managers/mcp-manifest-builder.js.map +1 -0
- package/dist/managers/quota-manager.d.ts +42 -0
- package/dist/managers/quota-manager.d.ts.map +1 -0
- package/dist/managers/quota-manager.js +126 -0
- package/dist/managers/quota-manager.js.map +1 -0
- package/dist/managers/workflow-coordinator.d.ts +62 -0
- package/dist/managers/workflow-coordinator.d.ts.map +1 -0
- package/dist/managers/workflow-coordinator.js +125 -0
- package/dist/managers/workflow-coordinator.js.map +1 -0
- package/dist/opfs-asset-store.d.ts.map +1 -1
- package/dist/opfs-asset-store.js +12 -2
- package/dist/opfs-asset-store.js.map +1 -1
- package/dist/plugin-context.d.ts +35 -0
- package/dist/plugin-context.d.ts.map +1 -0
- package/dist/plugin-context.js +62 -0
- package/dist/plugin-context.js.map +1 -0
- package/dist/plugin-permissions.d.ts +99 -0
- package/dist/plugin-permissions.d.ts.map +1 -0
- package/dist/plugin-permissions.js +205 -0
- package/dist/plugin-permissions.js.map +1 -0
- package/dist/runtime-impl.d.ts +116 -0
- package/dist/runtime-impl.d.ts.map +1 -0
- package/dist/runtime-impl.js +270 -0
- package/dist/runtime-impl.js.map +1 -0
- package/dist/runtime.d.ts +10 -233
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +12 -978
- package/dist/runtime.js.map +1 -1
- package/dist/test-utils/fakes.d.ts +35 -0
- package/dist/test-utils/fakes.d.ts.map +1 -0
- package/dist/test-utils/fakes.js +60 -0
- package/dist/test-utils/fakes.js.map +1 -0
- package/dist/types.d.ts +113 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/worker-host.d.ts.map +1 -1
- package/dist/worker-host.js +32 -9
- package/dist/worker-host.js.map +1 -1
- package/dist/worker-protocol.d.ts +30 -0
- package/dist/worker-protocol.d.ts.map +1 -1
- package/dist/worker-protocol.js +24 -0
- package/dist/worker-protocol.js.map +1 -1
- package/package.json +2 -2
- package/src/asset-store.ts +32 -2
- package/src/batch-processor.ts +133 -510
- package/src/batch-progress.ts +228 -0
- package/src/batch-scheduler.ts +209 -0
- package/src/browser-detect.ts +221 -0
- package/src/concurrency-controller.ts +52 -0
- package/src/errors.ts +82 -0
- package/src/executor.ts +122 -55
- package/src/history.ts +3 -2
- package/src/idb-asset-store.ts +7 -1
- package/src/index.ts +50 -15
- package/src/managers/asset-manager.ts +259 -0
- package/src/managers/history-manager.ts +327 -0
- package/src/managers/mcp-manifest-builder.ts +108 -0
- package/src/managers/quota-manager.ts +149 -0
- package/src/managers/workflow-coordinator.ts +158 -0
- package/src/opfs-asset-store.ts +16 -2
- package/src/plugin-context.ts +87 -0
- package/src/plugin-permissions.ts +228 -0
- package/src/runtime-impl.ts +298 -0
- package/src/runtime.ts +16 -1116
- package/src/test-utils/fakes.ts +72 -0
- package/src/types.ts +116 -0
- package/src/worker-host.ts +35 -7
- package/src/worker-protocol.ts +47 -0
- package/dist/workflow-builder.d.ts +0 -124
- package/dist/workflow-builder.d.ts.map +0 -1
- package/dist/workflow-builder.js +0 -240
- package/dist/workflow-builder.js.map +0 -1
- package/src/workflow-builder.ts +0 -303
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Manager
|
|
3
|
+
*
|
|
4
|
+
* 从 runtime.ts 抽取的存储配额管理逻辑(W2.9)。
|
|
5
|
+
*
|
|
6
|
+
* 职责:用配额校验包裹 AssetStore,import/create 超限时抛 QuotaExceededError,
|
|
7
|
+
* 并维护运行中的已用字节数供 runtime.getStorageUsage O(1) 读取。
|
|
8
|
+
*
|
|
9
|
+
* 并发安全:import/create/remove 通过 promise 链串行化,避免 check 与 update
|
|
10
|
+
* 之间的 TOCTOU 窗口导致两个并发操作都基于旧 usage 通过校验或回退。
|
|
11
|
+
*/
|
|
12
|
+
/** 存储配额超限时抛出(W2.9) */
|
|
13
|
+
export class QuotaExceededError extends Error {
|
|
14
|
+
usage;
|
|
15
|
+
delta;
|
|
16
|
+
quota;
|
|
17
|
+
constructor(usage, delta, quota) {
|
|
18
|
+
super(`Storage quota exceeded: usage=${usage} + delta=${delta} > quota=${quota}`);
|
|
19
|
+
this.name = 'QuotaExceededError';
|
|
20
|
+
this.usage = usage;
|
|
21
|
+
this.delta = delta;
|
|
22
|
+
this.quota = quota;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 从 AssetSource 估算导入字节数用于配额预检。
|
|
27
|
+
* url/opfs 源大小未知,返回 0 跳过预检 —— 真实大小在 import 完成后
|
|
28
|
+
* 通过 `usage += asset.metadata.size` 补记到账面,后续操作仍受配额约束。
|
|
29
|
+
*/
|
|
30
|
+
export function estimateSourceSize(source) {
|
|
31
|
+
if (source.kind === 'file')
|
|
32
|
+
return source.file.size;
|
|
33
|
+
if (source.kind === 'blob')
|
|
34
|
+
return source.blob.size;
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 用配额校验包裹 AssetStore:import/create 超限抛 QuotaExceededError(W2.9)。
|
|
39
|
+
* 内部维护运行中的已用字节数,remove 时回退。
|
|
40
|
+
*
|
|
41
|
+
* 并发安全:import/create/remove 通过 promise 链串行化,避免 check 与 update
|
|
42
|
+
* 之间的 TOCTOU 窗口导致两个并发操作都基于旧 usage 通过校验或回退。
|
|
43
|
+
*/
|
|
44
|
+
export function wrapAssetStoreWithQuota(inner, quota) {
|
|
45
|
+
let usage = 0;
|
|
46
|
+
let initialized = false;
|
|
47
|
+
/** 串行化 import/create/remove 的 chain tail,确保 check-update 原子性 */
|
|
48
|
+
let chain = Promise.resolve();
|
|
49
|
+
async function ensureInit() {
|
|
50
|
+
if (initialized)
|
|
51
|
+
return;
|
|
52
|
+
const all = await inner.list();
|
|
53
|
+
usage = all.reduce((sum, a) => sum + a.metadata.size, 0);
|
|
54
|
+
initialized = true;
|
|
55
|
+
}
|
|
56
|
+
function assertQuota(delta) {
|
|
57
|
+
if (usage + delta > quota) {
|
|
58
|
+
throw new QuotaExceededError(usage, delta, quota);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** 将 import/create/remove 串行化:依次 await init → assert → inner op → update usage */
|
|
62
|
+
function runExclusive(op) {
|
|
63
|
+
const run = chain.then(op, op);
|
|
64
|
+
// chain 仅用于排队,不传播 rejection(避免一次失败阻塞后续)
|
|
65
|
+
chain = run.then(() => undefined, () => undefined);
|
|
66
|
+
return run;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
async import(source) {
|
|
70
|
+
return runExclusive(async () => {
|
|
71
|
+
await ensureInit();
|
|
72
|
+
assertQuota(estimateSourceSize(source));
|
|
73
|
+
const asset = await inner.import(source);
|
|
74
|
+
usage += asset.metadata.size;
|
|
75
|
+
return asset;
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
async get(id) {
|
|
79
|
+
return inner.get(id);
|
|
80
|
+
},
|
|
81
|
+
async getBlob(handle) {
|
|
82
|
+
return inner.getBlob(handle);
|
|
83
|
+
},
|
|
84
|
+
async remove(id) {
|
|
85
|
+
return runExclusive(async () => {
|
|
86
|
+
const existing = await inner.get(id);
|
|
87
|
+
await inner.remove(id);
|
|
88
|
+
if (existing) {
|
|
89
|
+
usage = Math.max(0, usage - existing.metadata.size);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
async list() {
|
|
94
|
+
return inner.list();
|
|
95
|
+
},
|
|
96
|
+
async create(blob, metadata, type) {
|
|
97
|
+
return runExclusive(async () => {
|
|
98
|
+
await ensureInit();
|
|
99
|
+
// m8 修复:配额预检与累加使用同一口径(metadata.size),
|
|
100
|
+
// 避免 blob.size 与 metadata.size 漂移导致账面与预检不一致
|
|
101
|
+
assertQuota(metadata.size);
|
|
102
|
+
const asset = await inner.create(blob, metadata, type);
|
|
103
|
+
usage += asset.metadata.size;
|
|
104
|
+
return asset;
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
/**
|
|
108
|
+
* m6 优化:暴露配额包装器内部维护的 usage(O(1)),
|
|
109
|
+
* 供 runtime.getStorageUsage 优先使用,避免每次 O(n) 全量 listAssets。
|
|
110
|
+
* 下划线前缀表"内部 API",非 AssetStore 接口一部分。
|
|
111
|
+
* 若 ensureInit 未完成,返回 -1 表示"未就绪",调用方 fallback 到 listAssets。
|
|
112
|
+
*/
|
|
113
|
+
_getQuotaUsage() {
|
|
114
|
+
return initialized ? usage : -1;
|
|
115
|
+
},
|
|
116
|
+
// W21.6: 透传 dispose 给 inner store,并重置内部 usage/initialized/chain,
|
|
117
|
+
// 确保 dispose 后的 wrapper 状态一致(尽管不建议 dispose 后继续使用)。
|
|
118
|
+
async dispose() {
|
|
119
|
+
usage = 0;
|
|
120
|
+
initialized = false;
|
|
121
|
+
chain = Promise.resolve();
|
|
122
|
+
await inner.dispose?.();
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=quota-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota-manager.js","sourceRoot":"","sources":["../../src/managers/quota-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Coordinator(W1.4 从 runtime.ts 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 工作流执行协调器,封装 run / cancel / pause / resume / disposeWorkflow 与
|
|
5
|
+
* status 状态机。run() 内部:validateWorkflow → historyManager 协调 →
|
|
6
|
+
* executor.execute → status 更新 → historyManager.recordRunResult。
|
|
7
|
+
*
|
|
8
|
+
* deps 注入 executor / capabilityRegistry / eventBus / historyManager,
|
|
9
|
+
* 不持有 Runtime 实例避免循环依赖。status 由本类持有,Runtime 通过 getter 查询。
|
|
10
|
+
*/
|
|
11
|
+
import type { Asset, AssetId } from '@lokvis/schema';
|
|
12
|
+
import type { Workflow, WorkflowResult } from '@lokvis/schema';
|
|
13
|
+
import type { EventBus } from '@lokvis/schema';
|
|
14
|
+
import type { WorkflowExecutor } from '../executor.js';
|
|
15
|
+
import type { CapabilityRegistry } from '../capability-registry.js';
|
|
16
|
+
import type { HistoryManager } from './history-manager.js';
|
|
17
|
+
import type { RunOptions, RuntimeStatus } from '../types.js';
|
|
18
|
+
export interface WorkflowCoordinatorDeps {
|
|
19
|
+
executor: WorkflowExecutor;
|
|
20
|
+
capabilityRegistry: CapabilityRegistry;
|
|
21
|
+
eventBus: EventBus;
|
|
22
|
+
historyManager: HistoryManager;
|
|
23
|
+
}
|
|
24
|
+
/** 工作流执行协调器,由 RuntimeImpl 持有并委托 */
|
|
25
|
+
export declare class WorkflowCoordinator {
|
|
26
|
+
private readonly deps;
|
|
27
|
+
private _status;
|
|
28
|
+
constructor(deps: WorkflowCoordinatorDeps);
|
|
29
|
+
get status(): RuntimeStatus;
|
|
30
|
+
/**
|
|
31
|
+
* 执行工作流:validateWorkflow → 历史栈准备 → executor.execute → 状态更新。
|
|
32
|
+
*
|
|
33
|
+
* Schema 层校验在 executor.execute 之前调用,让结构问题(保留字哨兵 __input__、
|
|
34
|
+
* 悬挂 edge、自环、重复 id、真环)在入口处暴露,错误信息精准,而非被 executor
|
|
35
|
+
* 拓扑排序误判为含糊的 "cycle"。三层防御的第 3 层(前两层:executor 防御性
|
|
36
|
+
* 校验 + 单元测试覆盖)。
|
|
37
|
+
*
|
|
38
|
+
* W10.2/W10.3 增强:
|
|
39
|
+
* - resolveCapability 回调注入 capability 兼容性校验(相邻节点
|
|
40
|
+
* outputTypes 与 inputTypes 必须有交集;输入/输出节点类型与
|
|
41
|
+
* workflow.inputs/outputs.type 兼容)
|
|
42
|
+
* - maxSteps: 5(由 MAX_WORKFLOW_STEPS 常量定义,M1 MVP 约束)
|
|
43
|
+
*/
|
|
44
|
+
run(workflow: Workflow, inputs: AssetId[] | Asset[], options?: RunOptions): Promise<WorkflowResult>;
|
|
45
|
+
cancel(workflowId: string): Promise<void>;
|
|
46
|
+
pause(workflowId: string): Promise<void>;
|
|
47
|
+
resume(workflowId: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* 销毁指定工作流的运行时状态(W2.8 内存治理)。
|
|
50
|
+
*
|
|
51
|
+
* 调用时机:ui-react 卸载 Workspace 组件 / 用户关闭工作流标签页。
|
|
52
|
+
* 行为:cancel 运行中执行 → historyManager.disposeHistory(reset 触发
|
|
53
|
+
* onEvict → assetStore.remove 回收历史 outputs 资产)。
|
|
54
|
+
*
|
|
55
|
+
* 修复 review 报告:原实现无清理入口,Workflow 组件卸载后 Map 中残留 entry,
|
|
56
|
+
* 长会话累积导致内存与 OPFS 空间双泄漏。
|
|
57
|
+
*/
|
|
58
|
+
disposeWorkflow(workflowId: string): Promise<void>;
|
|
59
|
+
/** 将输入归一化为 AssetId[](run() 入参可为 AssetId[] 或 Asset[]) */
|
|
60
|
+
private collectInputAssetIds;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=workflow-coordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-coordinator.d.ts","sourceRoot":"","sources":["../../src/managers/workflow-coordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,mCAAmC;AACnC,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,OAAO,CAAyB;gBAEX,IAAI,EAAE,uBAAuB;IAE1D,IAAI,MAAM,IAAI,aAAa,CAE1B;IAED;;;;;;;;;;;;;OAaG;IACG,GAAG,CACP,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAC3B,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,cAAc,CAAC;IAwDpB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;;;;;;;;OASG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,wDAAwD;YAC1C,oBAAoB;CASnC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Coordinator(W1.4 从 runtime.ts 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 工作流执行协调器,封装 run / cancel / pause / resume / disposeWorkflow 与
|
|
5
|
+
* status 状态机。run() 内部:validateWorkflow → historyManager 协调 →
|
|
6
|
+
* executor.execute → status 更新 → historyManager.recordRunResult。
|
|
7
|
+
*
|
|
8
|
+
* deps 注入 executor / capabilityRegistry / eventBus / historyManager,
|
|
9
|
+
* 不持有 Runtime 实例避免循环依赖。status 由本类持有,Runtime 通过 getter 查询。
|
|
10
|
+
*/
|
|
11
|
+
import { validateWorkflow, MAX_WORKFLOW_STEPS } from '@lokvis/schema';
|
|
12
|
+
/** 工作流执行协调器,由 RuntimeImpl 持有并委托 */
|
|
13
|
+
export class WorkflowCoordinator {
|
|
14
|
+
deps;
|
|
15
|
+
_status = 'idle';
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.deps = deps;
|
|
18
|
+
}
|
|
19
|
+
get status() {
|
|
20
|
+
return this._status;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 执行工作流:validateWorkflow → 历史栈准备 → executor.execute → 状态更新。
|
|
24
|
+
*
|
|
25
|
+
* Schema 层校验在 executor.execute 之前调用,让结构问题(保留字哨兵 __input__、
|
|
26
|
+
* 悬挂 edge、自环、重复 id、真环)在入口处暴露,错误信息精准,而非被 executor
|
|
27
|
+
* 拓扑排序误判为含糊的 "cycle"。三层防御的第 3 层(前两层:executor 防御性
|
|
28
|
+
* 校验 + 单元测试覆盖)。
|
|
29
|
+
*
|
|
30
|
+
* W10.2/W10.3 增强:
|
|
31
|
+
* - resolveCapability 回调注入 capability 兼容性校验(相邻节点
|
|
32
|
+
* outputTypes 与 inputTypes 必须有交集;输入/输出节点类型与
|
|
33
|
+
* workflow.inputs/outputs.type 兼容)
|
|
34
|
+
* - maxSteps: 5(由 MAX_WORKFLOW_STEPS 常量定义,M1 MVP 约束)
|
|
35
|
+
*/
|
|
36
|
+
async run(workflow, inputs, options) {
|
|
37
|
+
this._status = 'running';
|
|
38
|
+
const validation = validateWorkflow(workflow, {
|
|
39
|
+
maxSteps: MAX_WORKFLOW_STEPS,
|
|
40
|
+
resolveCapability: (name) => {
|
|
41
|
+
const cap = this.deps.capabilityRegistry.get(name);
|
|
42
|
+
if (!cap)
|
|
43
|
+
return undefined;
|
|
44
|
+
return {
|
|
45
|
+
inputTypes: cap.inputTypes,
|
|
46
|
+
outputTypes: cap.outputTypes,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
if (!validation.success) {
|
|
51
|
+
this._status = 'error';
|
|
52
|
+
const error = validation.error.issues.map((i) => i.message).join('; ');
|
|
53
|
+
const result = {
|
|
54
|
+
workflowId: workflow.id,
|
|
55
|
+
outputs: [],
|
|
56
|
+
duration: 0,
|
|
57
|
+
status: 'failed',
|
|
58
|
+
error,
|
|
59
|
+
};
|
|
60
|
+
this.deps.eventBus.emit({
|
|
61
|
+
type: 'workflow:completed',
|
|
62
|
+
workflowId: workflow.id,
|
|
63
|
+
result,
|
|
64
|
+
});
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
// 历史栈管理(委托 HistoryManager):
|
|
68
|
+
// - 默认:每次 run() 重置历史(重跑语义),并通过 onEvict 回收旧 outputs 资产
|
|
69
|
+
// - appendHistory:true:保留已有历史栈,支持跨次 undo/redo 链(如连续滤镜)
|
|
70
|
+
const inputIds = await this.collectInputAssetIds(inputs);
|
|
71
|
+
this.deps.historyManager.prepareForRun(workflow.id, inputIds, options?.appendHistory ?? false);
|
|
72
|
+
try {
|
|
73
|
+
const result = await this.deps.executor.execute(workflow, inputs);
|
|
74
|
+
this._status = result.status === 'failed' ? 'error' : 'idle';
|
|
75
|
+
// 成功完成后,记录最终输出为当前
|
|
76
|
+
if (result.status === 'completed') {
|
|
77
|
+
this.deps.historyManager.recordRunResult(workflow.id, result.outputs);
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
this._status = 'error';
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async cancel(workflowId) {
|
|
87
|
+
return this.deps.executor.cancel(workflowId);
|
|
88
|
+
}
|
|
89
|
+
async pause(workflowId) {
|
|
90
|
+
return this.deps.executor.pause(workflowId);
|
|
91
|
+
}
|
|
92
|
+
async resume(workflowId) {
|
|
93
|
+
return this.deps.executor.resume(workflowId);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 销毁指定工作流的运行时状态(W2.8 内存治理)。
|
|
97
|
+
*
|
|
98
|
+
* 调用时机:ui-react 卸载 Workspace 组件 / 用户关闭工作流标签页。
|
|
99
|
+
* 行为:cancel 运行中执行 → historyManager.disposeHistory(reset 触发
|
|
100
|
+
* onEvict → assetStore.remove 回收历史 outputs 资产)。
|
|
101
|
+
*
|
|
102
|
+
* 修复 review 报告:原实现无清理入口,Workflow 组件卸载后 Map 中残留 entry,
|
|
103
|
+
* 长会话累积导致内存与 OPFS 空间双泄漏。
|
|
104
|
+
*/
|
|
105
|
+
async disposeWorkflow(workflowId) {
|
|
106
|
+
await this.deps.executor.cancel(workflowId).catch((err) => {
|
|
107
|
+
// executor.cancel 对未运行的 workflowId 直接 return(不抛错),因此此处
|
|
108
|
+
// catch 到的都是真实错误(Worker 崩溃 / executor 异常 / abort 竞态)。
|
|
109
|
+
// TD-3.1 长期方案:真实错误用 error 级别记录,便于 Sentry 上报与调试。
|
|
110
|
+
console.error(`[lokvis] disposeWorkflow: cancel(${workflowId}) failed:`, err);
|
|
111
|
+
});
|
|
112
|
+
// TD-2.1:await disposeHistory 等待 persistHistory 落地,使调用方拿到确定结果
|
|
113
|
+
await this.deps.historyManager.disposeHistory(workflowId);
|
|
114
|
+
}
|
|
115
|
+
/** 将输入归一化为 AssetId[](run() 入参可为 AssetId[] 或 Asset[]) */
|
|
116
|
+
async collectInputAssetIds(inputs) {
|
|
117
|
+
if (inputs.length === 0)
|
|
118
|
+
return [];
|
|
119
|
+
if (typeof inputs[0] === 'string') {
|
|
120
|
+
return inputs;
|
|
121
|
+
}
|
|
122
|
+
return inputs.map((a) => a.id);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=workflow-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-coordinator.js","sourceRoot":"","sources":["../../src/managers/workflow-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opfs-asset-store.d.ts","sourceRoot":"","sources":["../src/opfs-asset-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"opfs-asset-store.d.ts","sourceRoot":"","sources":["../src/opfs-asset-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAUnD,wBAAwB;AACxB,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,2CAA2C;AAC3C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAKvC;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,EAAG,KAAK,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;gBAElC,IAAI,SAAyB;CAM1C;AAED,iBAAiB;AACjB,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,iCAAiC;IACjC,KAAK,EAAE,KAAK,CAAC;CACd;AAED,yBAAyB;AACzB,MAAM,WAAW,qBAAqB;IACpC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,sBAAsB;AACtB,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAwFD,2BAA2B;AAC3B,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,UAAU,CAAC,CAmGrB"}
|
package/dist/opfs-asset-store.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import Dexie, {} from 'dexie';
|
|
21
21
|
import { buildAsset, generateId, parseBlobPath, prepareImport, } from './asset-store.js';
|
|
22
22
|
import { isIdbSupported } from './idb-asset-store.js';
|
|
23
|
+
import { AssetBlobNotFoundError } from './errors.js';
|
|
23
24
|
/** OPFS 不可用或初始化失败时抛出 */
|
|
24
25
|
export class OpfsUnavailableError extends Error {
|
|
25
26
|
constructor(message) {
|
|
@@ -166,8 +167,10 @@ export async function createOpfsAssetStore(options = {}) {
|
|
|
166
167
|
fileHandle = await assetsDir.getFileHandle(fileName(id));
|
|
167
168
|
fileHandles.set(id, fileHandle);
|
|
168
169
|
}
|
|
169
|
-
catch {
|
|
170
|
-
|
|
170
|
+
catch (err) {
|
|
171
|
+
// 保留原始 error 作为 cause,调用方可据 err.cause instanceof DOMException
|
|
172
|
+
// 区分 NotFoundError(文件不存在)与权限/IO 错误
|
|
173
|
+
throw new AssetBlobNotFoundError(`Blob not found in OPFS for path: ${handle.path}`, { cause: err });
|
|
171
174
|
}
|
|
172
175
|
}
|
|
173
176
|
const file = await fileHandle.getFile();
|
|
@@ -201,6 +204,13 @@ export async function createOpfsAssetStore(options = {}) {
|
|
|
201
204
|
await persistMetadata(db, id, asset);
|
|
202
205
|
return asset;
|
|
203
206
|
},
|
|
207
|
+
// W21.6: 清空内存 Map + 关闭 Dexie 连接。
|
|
208
|
+
// OPFS 文件不删除(下次创建 store 时从 IndexedDB metadata 预加载恢复)。
|
|
209
|
+
async dispose() {
|
|
210
|
+
assets.clear();
|
|
211
|
+
fileHandles.clear();
|
|
212
|
+
db?.close();
|
|
213
|
+
},
|
|
204
214
|
};
|
|
205
215
|
}
|
|
206
216
|
//# sourceMappingURL=opfs-asset-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opfs-asset-store.js","sourceRoot":"","sources":["../src/opfs-asset-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAAc,MAAM,OAAO,CAAC;AAG1C,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"opfs-asset-store.js","sourceRoot":"","sources":["../src/opfs-asset-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Context Factory(W1.6 从 runtime.ts 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 构造受限 PluginContext,供 Runtime.installPlugin() 使用。Plugin 只看到
|
|
5
|
+
* 受限 Runtime API(getAsset/importAsset/getAssetBlob/createAsset/
|
|
6
|
+
* listCapabilities + eventBus + 注册器 + log),看不到 React/Redux/Cloud。
|
|
7
|
+
*
|
|
8
|
+
* registerMetadataReader 转发给 runtime._registerMetadataReader(依赖反转:
|
|
9
|
+
* Plugin 提供实现,Runtime 持有引用)。
|
|
10
|
+
*
|
|
11
|
+
* 错误契约:getAsset 在资产不存在时抛 AssetNotFoundError,
|
|
12
|
+
* SDK 的 fromLokvisError 经 instanceof 转换。
|
|
13
|
+
*/
|
|
14
|
+
import type { EventBus, MetadataReader, PluginContext, PluginPermissionSandbox as IPluginPermissionSandbox } from '@lokvis/schema';
|
|
15
|
+
import type { AssetStore } from './asset-store.js';
|
|
16
|
+
import type { CapabilityRegistry } from './capability-registry.js';
|
|
17
|
+
/**
|
|
18
|
+
* createPluginContext 需要从 Runtime 拿到的最小依赖。
|
|
19
|
+
* 避免直接依赖 LokvisRuntimeImpl(循环引用)。
|
|
20
|
+
*/
|
|
21
|
+
export interface PluginContextRuntimeDeps {
|
|
22
|
+
eventBus: EventBus;
|
|
23
|
+
assetStore: AssetStore;
|
|
24
|
+
capabilityRegistry: CapabilityRegistry;
|
|
25
|
+
registerMetadataReader(name: string, reader: MetadataReader): void;
|
|
26
|
+
/**
|
|
27
|
+
* 权限沙箱(W18.6)。由 runtime 构造并注入(基于 plugin.config.permissions),
|
|
28
|
+
* 用于在 PluginContext 上暴露 ctx.sandbox,并在 installPlugin() 期间应用
|
|
29
|
+
* network guard。
|
|
30
|
+
*/
|
|
31
|
+
sandbox: IPluginPermissionSandbox;
|
|
32
|
+
}
|
|
33
|
+
/** 构造受限 PluginContext(供 Runtime.installPlugin 调用)。 */
|
|
34
|
+
export declare function createPluginContext(pluginName: string, deps: PluginContextRuntimeDeps): PluginContext;
|
|
35
|
+
//# sourceMappingURL=plugin-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-context.d.ts","sourceRoot":"","sources":["../src/plugin-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,QAAQ,EAAE,cAAc,EAAmB,aAAa,EACxD,uBAAuB,IAAI,wBAAwB,EACpD,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACnE;;;;OAIG;IACH,OAAO,EAAE,wBAAwB,CAAC;CACnC;AAED,sDAAsD;AACtD,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,wBAAwB,GAC7B,aAAa,CA2Cf"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Context Factory(W1.6 从 runtime.ts 抽取)
|
|
3
|
+
*
|
|
4
|
+
* 构造受限 PluginContext,供 Runtime.installPlugin() 使用。Plugin 只看到
|
|
5
|
+
* 受限 Runtime API(getAsset/importAsset/getAssetBlob/createAsset/
|
|
6
|
+
* listCapabilities + eventBus + 注册器 + log),看不到 React/Redux/Cloud。
|
|
7
|
+
*
|
|
8
|
+
* registerMetadataReader 转发给 runtime._registerMetadataReader(依赖反转:
|
|
9
|
+
* Plugin 提供实现,Runtime 持有引用)。
|
|
10
|
+
*
|
|
11
|
+
* 错误契约:getAsset 在资产不存在时抛 AssetNotFoundError,
|
|
12
|
+
* SDK 的 fromLokvisError 经 instanceof 转换。
|
|
13
|
+
*/
|
|
14
|
+
import { AssetNotFoundError } from './errors.js';
|
|
15
|
+
/** 构造受限 PluginContext(供 Runtime.installPlugin 调用)。 */
|
|
16
|
+
export function createPluginContext(pluginName, deps) {
|
|
17
|
+
const { assetStore, capabilityRegistry } = deps;
|
|
18
|
+
return {
|
|
19
|
+
runtime: {
|
|
20
|
+
getAsset: async (id) => {
|
|
21
|
+
const asset = await assetStore.get(id);
|
|
22
|
+
if (!asset)
|
|
23
|
+
throw new AssetNotFoundError(id);
|
|
24
|
+
return asset;
|
|
25
|
+
},
|
|
26
|
+
importAsset: async (file) => {
|
|
27
|
+
// PluginContext.importAsset 接受 File | Blob,统一转为 AssetSource
|
|
28
|
+
if (file instanceof File) {
|
|
29
|
+
const asset = await assetStore.import({ kind: 'file', file });
|
|
30
|
+
return asset.id;
|
|
31
|
+
}
|
|
32
|
+
const asset = await assetStore.import({
|
|
33
|
+
kind: 'blob', blob: file, name: `blob_${Date.now()}`,
|
|
34
|
+
});
|
|
35
|
+
return asset.id;
|
|
36
|
+
},
|
|
37
|
+
getAssetBlob: (asset) => assetStore.getBlob(asset.blob),
|
|
38
|
+
createAsset: (blob, metadata, type) => assetStore.create(blob, metadata, type),
|
|
39
|
+
listCapabilities: async () => capabilityRegistry.list(),
|
|
40
|
+
},
|
|
41
|
+
eventBus: deps.eventBus,
|
|
42
|
+
registerCapability: (impl) => capabilityRegistry.registerImplementation(impl),
|
|
43
|
+
registerMetadataReader: (name, reader) => {
|
|
44
|
+
deps.registerMetadataReader(name, reader);
|
|
45
|
+
},
|
|
46
|
+
registerPanel: (panel) => {
|
|
47
|
+
// Panel 注册由 UI 层处理,这里仅记录日志
|
|
48
|
+
void panel;
|
|
49
|
+
},
|
|
50
|
+
sandbox: deps.sandbox,
|
|
51
|
+
log: (level, message) => {
|
|
52
|
+
const prefix = `[${pluginName}]`;
|
|
53
|
+
if (level === 'error')
|
|
54
|
+
console.error(`${prefix} ${message}`);
|
|
55
|
+
else if (level === 'warn')
|
|
56
|
+
console.warn(`${prefix} ${message}`);
|
|
57
|
+
else
|
|
58
|
+
console.log(`${prefix} ${message}`);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=plugin-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-context.js","sourceRoot":"","sources":["../src/plugin-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAmBjD,sDAAsD;AACtD,MAAM,UAAU,mBAAmB,CACjC,UAAkB,EAClB,IAA8B;IAE9B,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAChD,OAAO;QACL,OAAO,EAAE;YACP,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;gBACrB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACvC,IAAI,CAAC,KAAK;oBAAE,MAAM,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAC;gBAC7C,OAAO,KAAK,CAAC;YACf,CAAC;YACD,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBAC1B,4DAA4D;gBAC5D,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;oBACzB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC9D,OAAO,KAAK,CAAC,EAAE,CAAC;gBAClB,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC;oBACpC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE;iBACrD,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,CAAC;YACD,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YACvD,WAAW,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CACpC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC;YACzC,gBAAgB,EAAE,KAAK,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE;SACxD;QACD,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,kBAAkB,EAAE,CAAC,IAAI,EAAE,EAAE,CAC3B,kBAAkB,CAAC,sBAAsB,CAAC,IAAI,CAAC;QACjD,sBAAsB,EAAE,CAAI,IAAY,EAAE,MAAyB,EAAE,EAAE;YACrE,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAwB,CAAC,CAAC;QAC9D,CAAC;QACD,aAAa,EAAE,CAAC,KAAsB,EAAE,EAAE;YACxC,2BAA2B;YAC3B,KAAK,KAAK,CAAC;QACb,CAAC;QACD,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,UAAU,GAAG,CAAC;YACjC,IAAI,KAAK,KAAK,OAAO;gBAAE,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC;iBACxD,IAAI,KAAK,KAAK,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC;;gBAC3D,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin 权限沙箱(W18.6)
|
|
3
|
+
*
|
|
4
|
+
* 据插件 PluginConfig.permissions 声明提供:
|
|
5
|
+
* 1. 查询:`has(perm)` / `assertNetworkAllowed(reason)`
|
|
6
|
+
* 2. 主动守卫:`applyNetworkGuard()` 在 try/finally 中临时 monkey-patch
|
|
7
|
+
* fetch / XMLHttpRequest / WebSocket / EventSource,声明 network:none
|
|
8
|
+
* 时这些 API 调用立即抛 NetworkGuardError,restore 函数恢复原实现
|
|
9
|
+
*
|
|
10
|
+
* 设计取舍:
|
|
11
|
+
* - 真正的进程隔离(Realm / Worker / iframe sandbox)不在 W18.6 范围,
|
|
12
|
+
* 这里做 install-time monkey-patch,覆盖 99% 的网络
|
|
13
|
+
* 调用路径(原生 fetch / XHR / WebSocket / EventSource)
|
|
14
|
+
* - 沙箱**仅在 installPlugin() 期间生效**(applyNetworkGuard 在
|
|
15
|
+
* installPlugin 的 try/finally 中应用)。capability execute()
|
|
16
|
+
* 期间**不**应用 network guard —— execute 路径由 plugin 代码
|
|
17
|
+
* 自行据 ctx.sandbox.assertNetworkAllowed() 主动自检
|
|
18
|
+
* - 窗口外(如插件 setTimeout 异步调用)无法覆盖 —— 这是有意为之的
|
|
19
|
+
* "best-effort 守卫",plugin 作者应据 ctx.sandbox 自检再调用
|
|
20
|
+
* - 文件系统权限(filesystem:opfs / filesystem:local)目前仅做断言,
|
|
21
|
+
* 不 monkey-patch OPFS API(navigator.storage.getDirectory 等覆盖面
|
|
22
|
+
* 有限,留待后续 W18.x 加 strict mode 时补)
|
|
23
|
+
*
|
|
24
|
+
* @see docs/PROJECT_PLAN.md W18.6
|
|
25
|
+
*/
|
|
26
|
+
import type { PluginPermission, PluginPermissionSandbox as IPluginPermissionSandbox } from '@lokvis/schema';
|
|
27
|
+
/** 权限断言失败时抛出(声明 X 但未声明 Y 又调用 Y 时) */
|
|
28
|
+
export declare class PluginPermissionError extends Error {
|
|
29
|
+
readonly pluginName: string;
|
|
30
|
+
readonly permission: PluginPermission;
|
|
31
|
+
readonly reason: string;
|
|
32
|
+
constructor(pluginName: string, permission: PluginPermission, reason: string);
|
|
33
|
+
}
|
|
34
|
+
/** 网络守卫拦截时抛出(声明 network:none 又调网络 API 时) */
|
|
35
|
+
export declare class NetworkGuardError extends Error {
|
|
36
|
+
readonly pluginName: string;
|
|
37
|
+
readonly api: string;
|
|
38
|
+
constructor(pluginName: string, api: string);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 文件系统守卫拦截时抛出(预留未启用)。
|
|
42
|
+
*
|
|
43
|
+
* W18.6 的 filesystem 权限目前仅做 `assertFilesystemAllowed()` 主动断言
|
|
44
|
+
* (抛 `PluginPermissionError`),不 monkey-patch OPFS API。
|
|
45
|
+
* 此类预留给后续 W18.x strict mode(覆盖 navigator.storage / showOpenFilePicker
|
|
46
|
+
* 等 API)使用,当前为未启用的占位类,生产代码不会抛出此错误。
|
|
47
|
+
*/
|
|
48
|
+
export declare class FilesystemGuardError extends Error {
|
|
49
|
+
readonly pluginName: string;
|
|
50
|
+
readonly scope: 'opfs' | 'local';
|
|
51
|
+
constructor(pluginName: string, scope: 'opfs' | 'local');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Plugin 权限沙箱。
|
|
55
|
+
*
|
|
56
|
+
* 一个插件对应一个 sandbox 实例,生命周期与 installPlugin() 一致。
|
|
57
|
+
* applyNetworkGuard() 在 installPlugin 的 try/finally 中应用;
|
|
58
|
+
* capability execute() 路径不自动应用守卫(由 plugin 主动自检)。
|
|
59
|
+
*/
|
|
60
|
+
export declare class PluginPermissionSandbox implements IPluginPermissionSandbox {
|
|
61
|
+
readonly pluginName: string;
|
|
62
|
+
readonly declared: ReadonlySet<PluginPermission>;
|
|
63
|
+
constructor(pluginName: string, permissions: PluginPermission[] | undefined);
|
|
64
|
+
/** 是否声明了指定权限 */
|
|
65
|
+
has(perm: PluginPermission): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* 断言网络调用允许(声明 network:none 时抛错)。
|
|
68
|
+
*
|
|
69
|
+
* Plugin 在调用 fetch / XHR 等前可主动调用:
|
|
70
|
+
* ctx.sandbox.assertNetworkAllowed('loading model manifest')
|
|
71
|
+
* 若声明了 network:none,立即抛 PluginPermissionError;否则 no-op。
|
|
72
|
+
*/
|
|
73
|
+
assertNetworkAllowed(reason: string): void;
|
|
74
|
+
/**
|
|
75
|
+
* 断言文件系统访问允许(声明未含对应 filesystem:* 时抛错)。
|
|
76
|
+
*
|
|
77
|
+
* @param scope 'opfs'(OPFS 根目录访问)或 'local'(任意本地文件系统)
|
|
78
|
+
*/
|
|
79
|
+
assertFilesystemAllowed(scope: 'opfs' | 'local', reason: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* 应用网络守卫(network:none 声明时,monkey-patch fetch/XHR/WebSocket/
|
|
82
|
+
* EventSource 使其调用即抛 NetworkGuardError)。
|
|
83
|
+
*
|
|
84
|
+
* 返回 restore 函数,必须在 try/finally 中调用以恢复全局 API。
|
|
85
|
+
* 非限制插件(network:limited / network:full / 未声明)返回 no-op。
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const restore = sandbox.applyNetworkGuard();
|
|
90
|
+
* try {
|
|
91
|
+
* await plugin.install(ctx);
|
|
92
|
+
* } finally {
|
|
93
|
+
* restore();
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
applyNetworkGuard(): () => void;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=plugin-permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-permissions.d.ts","sourceRoot":"","sources":["../src/plugin-permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,IAAI,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE5G,qCAAqC;AACrC,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM;CAU7E;AAED,4CAA4C;AAC5C,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAS5C;AAED;;;;;;;GAOG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;gBAErB,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;CAUxD;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,YAAW,wBAAwB;IACtE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;gBAErC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,SAAS;IAK3E,gBAAgB;IAChB,GAAG,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO;IAIpC;;;;;;OAMG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM1C;;;;OAIG;IACH,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQtE;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,IAAI,MAAM,IAAI;CA6EhC"}
|