@lokvis/schema 0.1.0 → 0.2.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/LICENSE +21 -0
- package/dist/capability.d.ts +9 -0
- package/dist/capability.d.ts.map +1 -1
- package/dist/event.d.ts +56 -0
- package/dist/event.d.ts.map +1 -1
- package/dist/exif.d.ts +53 -0
- package/dist/exif.d.ts.map +1 -0
- package/dist/exif.js +52 -0
- package/dist/exif.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +33 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/validators.d.ts +85 -40
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +213 -5
- package/dist/validators.js.map +1 -1
- package/package.json +2 -1
- package/src/capability.ts +9 -0
- package/src/event.ts +71 -2
- package/src/exif.ts +90 -0
- package/src/index.ts +1 -0
- package/src/plugin.ts +36 -1
- package/src/validators.ts +274 -5
package/dist/validators.js
CHANGED
|
@@ -13,6 +13,30 @@ export const assetTypeSchema = z.enum([
|
|
|
13
13
|
'data',
|
|
14
14
|
'unknown',
|
|
15
15
|
]);
|
|
16
|
+
/** W10: Workflow 分类枚举(与 WorkflowCategory 类型对齐) */
|
|
17
|
+
export const workflowCategorySchema = z.enum([
|
|
18
|
+
'image',
|
|
19
|
+
'video',
|
|
20
|
+
'audio',
|
|
21
|
+
'pdf',
|
|
22
|
+
'ai',
|
|
23
|
+
'data',
|
|
24
|
+
'developer',
|
|
25
|
+
'ecommerce',
|
|
26
|
+
'content-creation',
|
|
27
|
+
'other',
|
|
28
|
+
]);
|
|
29
|
+
/** W10: Workflow 输出类型枚举(含 archive 用于打包下载场景) */
|
|
30
|
+
export const workflowOutputTypeSchema = z.enum([
|
|
31
|
+
'image',
|
|
32
|
+
'video',
|
|
33
|
+
'audio',
|
|
34
|
+
'pdf',
|
|
35
|
+
'text',
|
|
36
|
+
'data',
|
|
37
|
+
'unknown',
|
|
38
|
+
'archive',
|
|
39
|
+
]);
|
|
16
40
|
export const assetMetadataSchema = z.object({
|
|
17
41
|
mimeType: z.string(),
|
|
18
42
|
size: z.number().nonnegative(),
|
|
@@ -42,7 +66,7 @@ export const workflowSchema = z.object({
|
|
|
42
66
|
name: z.string(),
|
|
43
67
|
description: z.string(),
|
|
44
68
|
author: z.object({ id: z.string(), name: z.string() }),
|
|
45
|
-
category:
|
|
69
|
+
category: workflowCategorySchema,
|
|
46
70
|
tags: z.array(z.string()),
|
|
47
71
|
nodes: z.array(workflowNodeSchema),
|
|
48
72
|
edges: z.array(workflowEdgeSchema),
|
|
@@ -53,7 +77,7 @@ export const workflowSchema = z.object({
|
|
|
53
77
|
accept: z.array(z.string()).optional(),
|
|
54
78
|
}),
|
|
55
79
|
outputs: z.object({
|
|
56
|
-
type:
|
|
80
|
+
type: workflowOutputTypeSchema,
|
|
57
81
|
format: z.string().optional(),
|
|
58
82
|
}),
|
|
59
83
|
official: z.boolean().optional(),
|
|
@@ -72,9 +96,193 @@ export const pluginManifestSchema = z.object({
|
|
|
72
96
|
engines: z.object({ 'lokvis-runtime': z.string() }),
|
|
73
97
|
permissions: z.array(z.string()),
|
|
74
98
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
export function validateWorkflow(data, options) {
|
|
100
|
+
const parsed = workflowSchema.safeParse(data);
|
|
101
|
+
if (!parsed.success) {
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
const wf = parsed.data;
|
|
105
|
+
const errors = [];
|
|
106
|
+
// 0. W10.2: 节点数上限校验(可选)
|
|
107
|
+
if (options?.maxSteps !== undefined && wf.nodes.length > options.maxSteps) {
|
|
108
|
+
errors.push(`Workflow has ${wf.nodes.length} nodes, exceeds max ${options.maxSteps}.`);
|
|
109
|
+
}
|
|
110
|
+
// 1. 保留字哨兵:禁止 __input__ / __output__ 出现在 nodes 或 edges
|
|
111
|
+
// (executor 不支持哨兵节点,输入资产注入到入度 0 的首节点)
|
|
112
|
+
const RESERVED_IDS = new Set(['__input__', '__output__', '__start__', '__end__']);
|
|
113
|
+
for (const node of wf.nodes) {
|
|
114
|
+
if (RESERVED_IDS.has(node.id)) {
|
|
115
|
+
errors.push(`Node id "${node.id}" is reserved; use a non-reserved id.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const edge of wf.edges) {
|
|
119
|
+
if (RESERVED_IDS.has(edge.from)) {
|
|
120
|
+
errors.push(`Edge from "${edge.from}" references a reserved sentinel id; ` +
|
|
121
|
+
`the executor injects input assets into the first in-degree-0 node, ` +
|
|
122
|
+
`no explicit __input__ edge is needed.`);
|
|
123
|
+
}
|
|
124
|
+
if (RESERVED_IDS.has(edge.to)) {
|
|
125
|
+
errors.push(`Edge to "${edge.to}" references a reserved sentinel id.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// 2. node id 唯一性
|
|
129
|
+
const seenIds = new Set();
|
|
130
|
+
for (const node of wf.nodes) {
|
|
131
|
+
if (seenIds.has(node.id)) {
|
|
132
|
+
errors.push(`Duplicate node id: "${node.id}".`);
|
|
133
|
+
}
|
|
134
|
+
seenIds.add(node.id);
|
|
135
|
+
}
|
|
136
|
+
// 3. edge.from / edge.to 必须引用已声明节点
|
|
137
|
+
const nodeIds = new Set(wf.nodes.map((n) => n.id));
|
|
138
|
+
for (const edge of wf.edges) {
|
|
139
|
+
if (!nodeIds.has(edge.from)) {
|
|
140
|
+
errors.push(`Edge from "${edge.from}" to "${edge.to}" references unknown source node "${edge.from}".`);
|
|
141
|
+
}
|
|
142
|
+
if (!nodeIds.has(edge.to)) {
|
|
143
|
+
errors.push(`Edge from "${edge.from}" to "${edge.to}" references unknown target node "${edge.to}".`);
|
|
144
|
+
}
|
|
145
|
+
if (edge.from === edge.to) {
|
|
146
|
+
errors.push(`Edge from "${edge.from}" to itself is a self-loop (cycle).`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 4. DAG 合法性:无环(拓扑排序能覆盖所有节点)
|
|
150
|
+
if (errors.length === 0) {
|
|
151
|
+
const inDegree = new Map();
|
|
152
|
+
const adjacency = new Map();
|
|
153
|
+
for (const node of wf.nodes) {
|
|
154
|
+
inDegree.set(node.id, 0);
|
|
155
|
+
adjacency.set(node.id, []);
|
|
156
|
+
}
|
|
157
|
+
for (const edge of wf.edges) {
|
|
158
|
+
inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
|
|
159
|
+
adjacency.get(edge.from)?.push(edge.to);
|
|
160
|
+
}
|
|
161
|
+
const queue = [];
|
|
162
|
+
for (const [id, deg] of inDegree) {
|
|
163
|
+
if (deg === 0)
|
|
164
|
+
queue.push(id);
|
|
165
|
+
}
|
|
166
|
+
let visited = 0;
|
|
167
|
+
while (queue.length > 0) {
|
|
168
|
+
const id = queue.shift();
|
|
169
|
+
// 循环条件 queue.length > 0 保证 shift 必返回元素;
|
|
170
|
+
// 显式检查以满足 noUncheckedIndexedAccess,并在不变量被打破时跳出
|
|
171
|
+
if (id === undefined)
|
|
172
|
+
break;
|
|
173
|
+
visited++;
|
|
174
|
+
for (const next of adjacency.get(id) ?? []) {
|
|
175
|
+
const newDeg = (inDegree.get(next) ?? 0) - 1;
|
|
176
|
+
inDegree.set(next, newDeg);
|
|
177
|
+
if (newDeg === 0)
|
|
178
|
+
queue.push(next);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (visited !== wf.nodes.length) {
|
|
182
|
+
errors.push(`Workflow contains a cycle: only ${visited}/${wf.nodes.length} nodes are reachable.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 5. W10.2: capability 兼容性校验(可选,仅在 resolveCapability 提供时)
|
|
186
|
+
// 检查相邻节点(通过 edge 连接)的 outputTypes 与下一节点的 inputTypes 是否有交集。
|
|
187
|
+
// - 线性链:edge.from → edge.to,from 节点的 outputTypes 与 to 节点的 inputTypes 交集为空则报错
|
|
188
|
+
// - 输入节点(入度 0)的 inputTypes 与 workflow.inputs.type 兼容性
|
|
189
|
+
// - 输出节点(出度 0)的 outputTypes 与 workflow.outputs.type 兼容性
|
|
190
|
+
if (options?.resolveCapability && errors.length === 0) {
|
|
191
|
+
validateCapabilityCompatibility(wf, options.resolveCapability, errors);
|
|
192
|
+
}
|
|
193
|
+
if (errors.length > 0) {
|
|
194
|
+
return {
|
|
195
|
+
success: false,
|
|
196
|
+
error: {
|
|
197
|
+
issues: errors.map((message) => ({
|
|
198
|
+
code: 'custom',
|
|
199
|
+
message,
|
|
200
|
+
path: [],
|
|
201
|
+
})),
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return { success: true, data: wf };
|
|
206
|
+
}
|
|
207
|
+
/** W10.2: capability 兼容性校验内部实现 */
|
|
208
|
+
function validateCapabilityCompatibility(wf, resolveCapability, errors) {
|
|
209
|
+
// 计算每个节点的入度/出度,识别输入/输出节点
|
|
210
|
+
const inDegree = new Map();
|
|
211
|
+
const outDegree = new Map();
|
|
212
|
+
for (const node of wf.nodes) {
|
|
213
|
+
inDegree.set(node.id, 0);
|
|
214
|
+
outDegree.set(node.id, 0);
|
|
215
|
+
}
|
|
216
|
+
for (const edge of wf.edges) {
|
|
217
|
+
inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
|
|
218
|
+
outDegree.set(edge.from, (outDegree.get(edge.from) ?? 0) + 1);
|
|
219
|
+
}
|
|
220
|
+
// 缓存每个节点的 capability 声明
|
|
221
|
+
const capCache = new Map();
|
|
222
|
+
const getCap = (node) => {
|
|
223
|
+
if (!node.capability)
|
|
224
|
+
return undefined;
|
|
225
|
+
if (capCache.has(node.capability))
|
|
226
|
+
return capCache.get(node.capability);
|
|
227
|
+
const cap = resolveCapability(node.capability);
|
|
228
|
+
capCache.set(node.capability, cap);
|
|
229
|
+
return cap;
|
|
230
|
+
};
|
|
231
|
+
// 5a. 输入节点(入度 0)的 inputTypes 与 workflow.inputs.type 兼容
|
|
232
|
+
for (const node of wf.nodes) {
|
|
233
|
+
if ((inDegree.get(node.id) ?? 0) > 0)
|
|
234
|
+
continue;
|
|
235
|
+
const cap = getCap(node);
|
|
236
|
+
// 未注册的 capability 不静默跳过:在 schema 层显式报错,避免用户得到"校验通过"
|
|
237
|
+
// 的假象,运行时才报错。resolveCapability 未提供时(getCap 始终返回 undefined)
|
|
238
|
+
// 整个 capability 兼容性校验跳过(向后兼容,见 5d 兜底)。
|
|
239
|
+
if (!cap) {
|
|
240
|
+
if (node.capability) {
|
|
241
|
+
errors.push(`Node "${node.id}" references unknown capability "${node.capability}". ` +
|
|
242
|
+
`Capability is not registered in the registry.`);
|
|
243
|
+
}
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const inputTypeMatches = cap.inputTypes.includes(wf.inputs.type);
|
|
247
|
+
if (!inputTypeMatches) {
|
|
248
|
+
errors.push(`Node "${node.id}" (capability "${node.capability}") expects input types ` +
|
|
249
|
+
`[${cap.inputTypes.join(', ')}], but workflow input is "${wf.inputs.type}".`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// 5b. 相邻节点:from 的 outputTypes 与 to 的 inputTypes 必须有交集
|
|
253
|
+
for (const edge of wf.edges) {
|
|
254
|
+
const fromNode = wf.nodes.find((n) => n.id === edge.from);
|
|
255
|
+
const toNode = wf.nodes.find((n) => n.id === edge.to);
|
|
256
|
+
if (!fromNode || !toNode)
|
|
257
|
+
continue;
|
|
258
|
+
const fromCap = getCap(fromNode);
|
|
259
|
+
const toCap = getCap(toNode);
|
|
260
|
+
if (!fromCap || !toCap)
|
|
261
|
+
continue; // 5a 已报告未注册 capability,此处不重复
|
|
262
|
+
const compatible = fromCap.outputTypes.some((t) => toCap.inputTypes.includes(t));
|
|
263
|
+
if (!compatible) {
|
|
264
|
+
errors.push(`Capability mismatch on edge "${edge.from}" → "${edge.to}": ` +
|
|
265
|
+
`"${fromNode.capability}" outputs [${fromCap.outputTypes.join(', ')}], ` +
|
|
266
|
+
`but "${toNode.capability}" accepts [${toCap.inputTypes.join(', ')}].`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// 5c. 输出节点(出度 0)的 outputTypes 与 workflow.outputs.type 兼容
|
|
270
|
+
// (archive 类型输出允许任意类型,用于打包下载场景)
|
|
271
|
+
for (const node of wf.nodes) {
|
|
272
|
+
if ((outDegree.get(node.id) ?? 0) > 0)
|
|
273
|
+
continue;
|
|
274
|
+
const cap = getCap(node);
|
|
275
|
+
if (!cap)
|
|
276
|
+
continue; // 5a 已报告未注册 capability,此处不重复
|
|
277
|
+
const outputType = wf.outputs.type;
|
|
278
|
+
if (outputType === 'archive')
|
|
279
|
+
continue;
|
|
280
|
+
const outputTypeMatches = cap.outputTypes.includes(outputType);
|
|
281
|
+
if (!outputTypeMatches) {
|
|
282
|
+
errors.push(`Node "${node.id}" (capability "${node.capability}") produces output types ` +
|
|
283
|
+
`[${cap.outputTypes.join(', ')}], but workflow output is "${outputType}".`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
78
286
|
}
|
|
79
287
|
/** 校验 Plugin Manifest */
|
|
80
288
|
export function validatePluginManifest(data) {
|
package/dist/validators.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC;IACpC,OAAO;IACP,OAAO;IACP,OAAO;IACP,KAAK;IACL,MAAM;IACN,MAAM;IACN,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;IAC9B,UAAU,EAAE,CAAC;SACV,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;SACvE,QAAQ,EAAE;IACb,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IAC7C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;CACnB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC7C,8CAA8C;IAC9C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC,MAAM,CACP,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAC1G,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAC3C,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;CACf,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QAChD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;KACvC,CAAC;IACF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACtF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC9B,CAAC;IACF,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACnD,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAEH,uBAAuB;AACvB,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,OAAO,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,sBAAsB,CAAC,IAAa;IAClD,OAAO,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC"}
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokvis/schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Lokvis Schema - Workflow / Asset / Plugin type definitions and validators",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
7
8
|
"main": "./dist/index.js",
|
|
8
9
|
"module": "./dist/index.js",
|
|
9
10
|
"types": "./dist/index.d.ts",
|
package/src/capability.ts
CHANGED
|
@@ -83,6 +83,15 @@ export interface CapabilityImplementation {
|
|
|
83
83
|
capability: CapabilityName;
|
|
84
84
|
/** 实现该能力的引擎名 */
|
|
85
85
|
engine: string;
|
|
86
|
+
/**
|
|
87
|
+
* 实现状态:
|
|
88
|
+
* - `'stable'`(默认):可正常执行
|
|
89
|
+
* - `'stub'`:占位实现,调用 execute 会抛出异常
|
|
90
|
+
*
|
|
91
|
+
* CapabilityRegistry.resolve() 会跳过 stub 实现,
|
|
92
|
+
* 避免运行时出现 "not implemented" 错误。
|
|
93
|
+
*/
|
|
94
|
+
status?: 'stable' | 'stub';
|
|
86
95
|
/**
|
|
87
96
|
* 该引擎的性能等级(可选)。缺省时使用能力声明的 performance。
|
|
88
97
|
* 用于 EngineSelectionStrategy('fastest'/'balanced')排序选择。
|
package/src/event.ts
CHANGED
|
@@ -8,6 +8,23 @@ import type { Asset, AssetId, AssetMetadata } from './asset.js';
|
|
|
8
8
|
import type { Workflow, WorkflowResult } from './workflow.js';
|
|
9
9
|
import type { HistoryEntry } from './asset.js';
|
|
10
10
|
|
|
11
|
+
/** 批量项状态(对应 BatchProcessor 内部状态机) */
|
|
12
|
+
export type BatchItemStatus =
|
|
13
|
+
| 'pending'
|
|
14
|
+
| 'processing'
|
|
15
|
+
| 'completed'
|
|
16
|
+
| 'failed'
|
|
17
|
+
| 'cancelled';
|
|
18
|
+
|
|
19
|
+
/** 批量作业状态 */
|
|
20
|
+
export type BatchJobStatus =
|
|
21
|
+
| 'queued'
|
|
22
|
+
| 'running'
|
|
23
|
+
| 'paused'
|
|
24
|
+
| 'completed'
|
|
25
|
+
| 'cancelled'
|
|
26
|
+
| 'failed';
|
|
27
|
+
|
|
11
28
|
/** Lokvis 标准事件类型联合 */
|
|
12
29
|
export type LokvisEvent =
|
|
13
30
|
| { type: 'asset:imported'; assetId: AssetId; metadata: AssetMetadata }
|
|
@@ -39,9 +56,61 @@ export type LokvisEvent =
|
|
|
39
56
|
format: string;
|
|
40
57
|
size: number;
|
|
41
58
|
}
|
|
42
|
-
| {
|
|
59
|
+
| {
|
|
60
|
+
type: 'history:changed';
|
|
61
|
+
workflowId: string;
|
|
62
|
+
entries: HistoryEntry[];
|
|
63
|
+
/** 当前游标(指向最后一条已应用的 entry;-1 表示无已应用条目) */
|
|
64
|
+
currentIndex: number;
|
|
65
|
+
}
|
|
43
66
|
| { type: 'capability:registered'; capability: string; engine: string }
|
|
44
|
-
| { type: 'plugin:loaded'; name: string; version: string }
|
|
67
|
+
| { type: 'plugin:loaded'; name: string; version: string }
|
|
68
|
+
// ─── 批量作业事件(W6.3)─────────────────────────────────
|
|
69
|
+
| { type: 'batch:started'; jobId: string; total: number }
|
|
70
|
+
| {
|
|
71
|
+
type: 'batch:item:started';
|
|
72
|
+
jobId: string;
|
|
73
|
+
itemId: string;
|
|
74
|
+
index: number;
|
|
75
|
+
total: number;
|
|
76
|
+
}
|
|
77
|
+
| {
|
|
78
|
+
type: 'batch:item:finished';
|
|
79
|
+
jobId: string;
|
|
80
|
+
itemId: string;
|
|
81
|
+
index: number;
|
|
82
|
+
total: number;
|
|
83
|
+
outputAssetId: AssetId;
|
|
84
|
+
duration: number;
|
|
85
|
+
}
|
|
86
|
+
| {
|
|
87
|
+
type: 'batch:item:failed';
|
|
88
|
+
jobId: string;
|
|
89
|
+
itemId: string;
|
|
90
|
+
index: number;
|
|
91
|
+
total: number;
|
|
92
|
+
error: Error;
|
|
93
|
+
/** 已重试次数(达到 maxRetries 后才发 failed 事件) */
|
|
94
|
+
attempts: number;
|
|
95
|
+
}
|
|
96
|
+
| {
|
|
97
|
+
type: 'batch:progress';
|
|
98
|
+
jobId: string;
|
|
99
|
+
completed: number;
|
|
100
|
+
failed: number;
|
|
101
|
+
total: number;
|
|
102
|
+
}
|
|
103
|
+
| {
|
|
104
|
+
type: 'batch:completed';
|
|
105
|
+
jobId: string;
|
|
106
|
+
total: number;
|
|
107
|
+
completed: number;
|
|
108
|
+
failed: number;
|
|
109
|
+
duration: number;
|
|
110
|
+
}
|
|
111
|
+
| { type: 'batch:cancelled'; jobId: string; cancelled: number }
|
|
112
|
+
| { type: 'batch:paused'; jobId: string }
|
|
113
|
+
| { type: 'batch:resumed'; jobId: string };
|
|
45
114
|
|
|
46
115
|
/** 所有事件类型字面量 */
|
|
47
116
|
export type LokvisEventType = LokvisEvent['type'];
|
package/src/exif.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EXIF 元数据类型与格式化(W7.3/7.4)
|
|
3
|
+
*
|
|
4
|
+
* 类型分两层:
|
|
5
|
+
* - `ExifData`:面向 UI / Runtime 的公共类型,只含结构化字段,**无 raw**
|
|
6
|
+
* - `RawExifData`:Plugin 内部类型,extends ExifData,额外含 `raw`(exifr 原始解析对象)
|
|
7
|
+
*
|
|
8
|
+
* 拆分原因(长期方案):UI 缓存 ExifData 时无需手动剔除 raw 字段,
|
|
9
|
+
* 避免每个消费者都要做 `{...data, raw: undefined}` 的 patch 操作。
|
|
10
|
+
* Plugin 在返回前把 RawExifData 收窄为 ExifData(丢弃 raw)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 面向 UI / Runtime 的 EXIF 结构化数据。
|
|
15
|
+
* 不含 raw 字段 —— raw 仅在 Plugin 内部用于调试 / 高级展示,
|
|
16
|
+
* 不会传递到 UI 层(避免大对象在缓存中累积)。
|
|
17
|
+
*/
|
|
18
|
+
export interface ExifData {
|
|
19
|
+
make?: string;
|
|
20
|
+
model?: string;
|
|
21
|
+
lensModel?: string;
|
|
22
|
+
dateTimeOriginal?: string;
|
|
23
|
+
iso?: number;
|
|
24
|
+
fNumber?: number;
|
|
25
|
+
exposureTime?: number;
|
|
26
|
+
focalLength?: number;
|
|
27
|
+
exposureCompensation?: number;
|
|
28
|
+
whiteBalance?: string;
|
|
29
|
+
gpsLatitude?: number;
|
|
30
|
+
gpsLongitude?: number;
|
|
31
|
+
gpsAltitude?: number;
|
|
32
|
+
orientation?: number;
|
|
33
|
+
software?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Plugin 内部使用的完整 EXIF 数据,extends ExifData 并附加 raw 字段。
|
|
38
|
+
* raw 保留 exifr.parse 返回的原始对象,供调试或未来高级面板使用。
|
|
39
|
+
* Plugin 在通过 MetadataReader 返回给 Runtime 时,应丢弃 raw(收窄为 ExifData)。
|
|
40
|
+
*/
|
|
41
|
+
export interface RawExifData extends ExifData {
|
|
42
|
+
/** exifr.parse 返回的原始对象(未筛选) */
|
|
43
|
+
raw?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** EXIF 面板的单行展示数据 */
|
|
47
|
+
export interface ExifRow {
|
|
48
|
+
label: string;
|
|
49
|
+
value: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 把 ExifData 格式化为 UI 展示用的行列表。
|
|
54
|
+
* 纯函数,放 schema 层供 UI 直接调用,避免 UI 跨层依赖 plugin / engine。
|
|
55
|
+
*/
|
|
56
|
+
export function formatExifRows(exif: ExifData): ExifRow[] {
|
|
57
|
+
const rows: ExifRow[] = [];
|
|
58
|
+
const push = (label: string, value: string | undefined): void => {
|
|
59
|
+
if (value !== undefined && value !== '') rows.push({ label, value });
|
|
60
|
+
};
|
|
61
|
+
push('Camera', exif.make && exif.model ? `${exif.make} ${exif.model}` : exif.make ?? exif.model);
|
|
62
|
+
push('Lens', exif.lensModel);
|
|
63
|
+
push('Date', exif.dateTimeOriginal);
|
|
64
|
+
push('ISO', exif.iso !== undefined ? `ISO ${exif.iso}` : undefined);
|
|
65
|
+
push('Aperture', exif.fNumber !== undefined ? `f/${exif.fNumber}` : undefined);
|
|
66
|
+
push('Shutter', exif.exposureTime !== undefined ? formatShutterSpeed(exif.exposureTime) : undefined);
|
|
67
|
+
push('Focal Length', exif.focalLength !== undefined ? `${exif.focalLength}mm` : undefined);
|
|
68
|
+
push('Exposure Comp.', exif.exposureCompensation !== undefined ? `${exif.exposureCompensation} EV` : undefined);
|
|
69
|
+
push('White Balance', exif.whiteBalance);
|
|
70
|
+
push('Software', exif.software);
|
|
71
|
+
if (exif.gpsLatitude !== undefined && exif.gpsLongitude !== undefined) {
|
|
72
|
+
push('GPS', `${exif.gpsLatitude.toFixed(6)}, ${exif.gpsLongitude.toFixed(6)}`);
|
|
73
|
+
if (exif.gpsAltitude !== undefined) {
|
|
74
|
+
push('GPS Altitude', `${exif.gpsAltitude.toFixed(1)} m`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
push('Orientation', exif.orientation !== undefined ? `${exif.orientation}` : undefined);
|
|
78
|
+
return rows;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 格式化快门速度:
|
|
83
|
+
* - >= 1s 直接显示秒数(如 "2s")
|
|
84
|
+
* - < 1s 转为分数(如 1/250s)
|
|
85
|
+
*/
|
|
86
|
+
function formatShutterSpeed(seconds: number): string {
|
|
87
|
+
if (seconds >= 1) return `${seconds}s`;
|
|
88
|
+
const denominator = Math.round(1 / seconds);
|
|
89
|
+
return `1/${denominator}s`;
|
|
90
|
+
}
|
package/src/index.ts
CHANGED
package/src/plugin.ts
CHANGED
|
@@ -60,6 +60,30 @@ export interface PanelDefinition {
|
|
|
60
60
|
show?: (context: { selectedAssets: string[] }) => boolean;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 元数据读取函数(依赖反转)。
|
|
65
|
+
*
|
|
66
|
+
* 某些 Plugin 能力本质是"元数据查询"而非"资产变换"(如 EXIF 读取:
|
|
67
|
+
* Blob → ExifData),既不符合 Engine 层 Blob↔Blob 约束,也不符合
|
|
68
|
+
* CapabilityImplementation 的 Asset[]→Asset[] 契约。这类能力通过
|
|
69
|
+
* MetadataReader 注册:Plugin 提供读取函数,Runtime 持有引用并按名调用。
|
|
70
|
+
*
|
|
71
|
+
* 与 registerCapability 的区别:
|
|
72
|
+
* - registerCapability:注册变换能力(Asset→Asset),走 WorkflowExecutor
|
|
73
|
+
* - registerMetadataReader:注册查询函数(Asset→T),走 Runtime 直接调用
|
|
74
|
+
*
|
|
75
|
+
* 优点(相对 Capability execute + data Asset 序列化方案):
|
|
76
|
+
* - 无需创建临时 data Asset(避免手动 removeAsset 清理 / 泄漏)
|
|
77
|
+
* - 无 JSON marshal/unmarshal 开销
|
|
78
|
+
* - 类型直接透传(ExifData),无需序列化
|
|
79
|
+
*
|
|
80
|
+
* @param asset 输入资产
|
|
81
|
+
* @returns 读取结果;无数据 / 解析失败返回 null
|
|
82
|
+
*/
|
|
83
|
+
export type MetadataReader<T = unknown> = (
|
|
84
|
+
asset: import('./asset.js').Asset
|
|
85
|
+
) => Promise<T | null>;
|
|
86
|
+
|
|
63
87
|
/**
|
|
64
88
|
* Plugin 上下文(Plugin 能访问的全部 API)
|
|
65
89
|
*
|
|
@@ -90,8 +114,19 @@ export interface PluginContext {
|
|
|
90
114
|
};
|
|
91
115
|
/** 事件总线 */
|
|
92
116
|
eventBus: import('./event.js').EventBus;
|
|
93
|
-
/** 注册能力实现 */
|
|
117
|
+
/** 注册能力实现(变换:Asset→Asset) */
|
|
94
118
|
registerCapability(impl: CapabilityImplementation): void;
|
|
119
|
+
/**
|
|
120
|
+
* 注册元数据读取函数(查询:Asset→T)。
|
|
121
|
+
*
|
|
122
|
+
* 用于非变换类能力(如 EXIF 读取)。Runtime 持有 reader 引用,
|
|
123
|
+
* UI 通过 runtime.readAssetExif(id) 间接调用,不直接依赖 Plugin / Engine。
|
|
124
|
+
* 同名 reader 重复注册时覆盖前者(支持热更新)。
|
|
125
|
+
*
|
|
126
|
+
* @param name 读取器名称,约定与能力名对齐(如 'image.read-exif')
|
|
127
|
+
* @param reader 读取函数
|
|
128
|
+
*/
|
|
129
|
+
registerMetadataReader<T>(name: string, reader: MetadataReader<T>): void;
|
|
95
130
|
/** 注册 UI Panel */
|
|
96
131
|
registerPanel(panel: PanelDefinition): void;
|
|
97
132
|
/** 日志 */
|