@lokvis/schema 0.2.0-beta.0 → 0.2.1
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/event.d.ts +54 -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 +33 -7
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +123 -9
- package/dist/validators.js.map +1 -1
- package/package.json +2 -1
- package/src/event.ts +64 -1
- package/src/exif.ts +90 -0
- package/src/index.ts +1 -0
- package/src/plugin.ts +36 -1
- package/src/validators.ts +163 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lokvis Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/event.d.ts
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
import type { Asset, AssetId, AssetMetadata } from './asset.js';
|
|
7
7
|
import type { Workflow, WorkflowResult } from './workflow.js';
|
|
8
8
|
import type { HistoryEntry } from './asset.js';
|
|
9
|
+
/** 批量项状态(对应 BatchProcessor 内部状态机) */
|
|
10
|
+
export type BatchItemStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled';
|
|
11
|
+
/** 批量作业状态 */
|
|
12
|
+
export type BatchJobStatus = 'queued' | 'running' | 'paused' | 'completed' | 'cancelled' | 'failed';
|
|
9
13
|
/** Lokvis 标准事件类型联合 */
|
|
10
14
|
export type LokvisEvent = {
|
|
11
15
|
type: 'asset:imported';
|
|
@@ -68,6 +72,56 @@ export type LokvisEvent = {
|
|
|
68
72
|
type: 'plugin:loaded';
|
|
69
73
|
name: string;
|
|
70
74
|
version: string;
|
|
75
|
+
} | {
|
|
76
|
+
type: 'batch:started';
|
|
77
|
+
jobId: string;
|
|
78
|
+
total: number;
|
|
79
|
+
} | {
|
|
80
|
+
type: 'batch:item:started';
|
|
81
|
+
jobId: string;
|
|
82
|
+
itemId: string;
|
|
83
|
+
index: number;
|
|
84
|
+
total: number;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'batch:item:finished';
|
|
87
|
+
jobId: string;
|
|
88
|
+
itemId: string;
|
|
89
|
+
index: number;
|
|
90
|
+
total: number;
|
|
91
|
+
outputAssetId: AssetId;
|
|
92
|
+
duration: number;
|
|
93
|
+
} | {
|
|
94
|
+
type: 'batch:item:failed';
|
|
95
|
+
jobId: string;
|
|
96
|
+
itemId: string;
|
|
97
|
+
index: number;
|
|
98
|
+
total: number;
|
|
99
|
+
error: Error;
|
|
100
|
+
/** 已重试次数(达到 maxRetries 后才发 failed 事件) */
|
|
101
|
+
attempts: number;
|
|
102
|
+
} | {
|
|
103
|
+
type: 'batch:progress';
|
|
104
|
+
jobId: string;
|
|
105
|
+
completed: number;
|
|
106
|
+
failed: number;
|
|
107
|
+
total: number;
|
|
108
|
+
} | {
|
|
109
|
+
type: 'batch:completed';
|
|
110
|
+
jobId: string;
|
|
111
|
+
total: number;
|
|
112
|
+
completed: number;
|
|
113
|
+
failed: number;
|
|
114
|
+
duration: number;
|
|
115
|
+
} | {
|
|
116
|
+
type: 'batch:cancelled';
|
|
117
|
+
jobId: string;
|
|
118
|
+
cancelled: number;
|
|
119
|
+
} | {
|
|
120
|
+
type: 'batch:paused';
|
|
121
|
+
jobId: string;
|
|
122
|
+
} | {
|
|
123
|
+
type: 'batch:resumed';
|
|
124
|
+
jobId: string;
|
|
71
125
|
};
|
|
72
126
|
/** 所有事件类型字面量 */
|
|
73
127
|
export type LokvisEventType = LokvisEvent['type'];
|
package/dist/event.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,sBAAsB;AACtB,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,GAC7E;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACd,GACD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC1E;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
|
package/dist/exif.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
* 面向 UI / Runtime 的 EXIF 结构化数据。
|
|
14
|
+
* 不含 raw 字段 —— raw 仅在 Plugin 内部用于调试 / 高级展示,
|
|
15
|
+
* 不会传递到 UI 层(避免大对象在缓存中累积)。
|
|
16
|
+
*/
|
|
17
|
+
export interface ExifData {
|
|
18
|
+
make?: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
lensModel?: string;
|
|
21
|
+
dateTimeOriginal?: string;
|
|
22
|
+
iso?: number;
|
|
23
|
+
fNumber?: number;
|
|
24
|
+
exposureTime?: number;
|
|
25
|
+
focalLength?: number;
|
|
26
|
+
exposureCompensation?: number;
|
|
27
|
+
whiteBalance?: string;
|
|
28
|
+
gpsLatitude?: number;
|
|
29
|
+
gpsLongitude?: number;
|
|
30
|
+
gpsAltitude?: number;
|
|
31
|
+
orientation?: number;
|
|
32
|
+
software?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Plugin 内部使用的完整 EXIF 数据,extends ExifData 并附加 raw 字段。
|
|
36
|
+
* raw 保留 exifr.parse 返回的原始对象,供调试或未来高级面板使用。
|
|
37
|
+
* Plugin 在通过 MetadataReader 返回给 Runtime 时,应丢弃 raw(收窄为 ExifData)。
|
|
38
|
+
*/
|
|
39
|
+
export interface RawExifData extends ExifData {
|
|
40
|
+
/** exifr.parse 返回的原始对象(未筛选) */
|
|
41
|
+
raw?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
/** EXIF 面板的单行展示数据 */
|
|
44
|
+
export interface ExifRow {
|
|
45
|
+
label: string;
|
|
46
|
+
value: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 把 ExifData 格式化为 UI 展示用的行列表。
|
|
50
|
+
* 纯函数,放 schema 层供 UI 直接调用,避免 UI 跨层依赖 plugin / engine。
|
|
51
|
+
*/
|
|
52
|
+
export declare function formatExifRows(exif: ExifData): ExifRow[];
|
|
53
|
+
//# sourceMappingURL=exif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exif.d.ts","sourceRoot":"","sources":["../src/exif.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,qBAAqB;AACrB,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAE,CAuBxD"}
|
package/dist/exif.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
* 把 ExifData 格式化为 UI 展示用的行列表。
|
|
14
|
+
* 纯函数,放 schema 层供 UI 直接调用,避免 UI 跨层依赖 plugin / engine。
|
|
15
|
+
*/
|
|
16
|
+
export function formatExifRows(exif) {
|
|
17
|
+
const rows = [];
|
|
18
|
+
const push = (label, value) => {
|
|
19
|
+
if (value !== undefined && value !== '')
|
|
20
|
+
rows.push({ label, value });
|
|
21
|
+
};
|
|
22
|
+
push('Camera', exif.make && exif.model ? `${exif.make} ${exif.model}` : exif.make ?? exif.model);
|
|
23
|
+
push('Lens', exif.lensModel);
|
|
24
|
+
push('Date', exif.dateTimeOriginal);
|
|
25
|
+
push('ISO', exif.iso !== undefined ? `ISO ${exif.iso}` : undefined);
|
|
26
|
+
push('Aperture', exif.fNumber !== undefined ? `f/${exif.fNumber}` : undefined);
|
|
27
|
+
push('Shutter', exif.exposureTime !== undefined ? formatShutterSpeed(exif.exposureTime) : undefined);
|
|
28
|
+
push('Focal Length', exif.focalLength !== undefined ? `${exif.focalLength}mm` : undefined);
|
|
29
|
+
push('Exposure Comp.', exif.exposureCompensation !== undefined ? `${exif.exposureCompensation} EV` : undefined);
|
|
30
|
+
push('White Balance', exif.whiteBalance);
|
|
31
|
+
push('Software', exif.software);
|
|
32
|
+
if (exif.gpsLatitude !== undefined && exif.gpsLongitude !== undefined) {
|
|
33
|
+
push('GPS', `${exif.gpsLatitude.toFixed(6)}, ${exif.gpsLongitude.toFixed(6)}`);
|
|
34
|
+
if (exif.gpsAltitude !== undefined) {
|
|
35
|
+
push('GPS Altitude', `${exif.gpsAltitude.toFixed(1)} m`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
push('Orientation', exif.orientation !== undefined ? `${exif.orientation}` : undefined);
|
|
39
|
+
return rows;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 格式化快门速度:
|
|
43
|
+
* - >= 1s 直接显示秒数(如 "2s")
|
|
44
|
+
* - < 1s 转为分数(如 1/250s)
|
|
45
|
+
*/
|
|
46
|
+
function formatShutterSpeed(seconds) {
|
|
47
|
+
if (seconds >= 1)
|
|
48
|
+
return `${seconds}s`;
|
|
49
|
+
const denominator = Math.round(1 / seconds);
|
|
50
|
+
return `1/${denominator}s`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=exif.js.map
|
package/dist/exif.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exif.js","sourceRoot":"","sources":["../src/exif.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAyCH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,KAAyB,EAAQ,EAAE;QAC9D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IACjG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC/E,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACrG,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3F,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,oBAAoB,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,oBAAoB,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAChH,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACtE,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/E,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACxF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,OAAe;IACzC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,GAAG,OAAO,GAAG,CAAC;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;IAC5C,OAAO,KAAK,WAAW,GAAG,CAAC;AAC7B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './capability.js';
|
|
|
9
9
|
export * from './workflow.js';
|
|
10
10
|
export * from './event.js';
|
|
11
11
|
export * from './plugin.js';
|
|
12
|
+
export * from './exif.js';
|
|
12
13
|
export * from './mcp.js';
|
|
13
14
|
export * from './validators.js';
|
|
14
15
|
export declare const SCHEMA_VERSION: "1.0.0";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAE1B,cAAc,UAAU,CAAC;AAGzB,cAAc,iBAAiB,CAAC;AAGhC,eAAO,MAAM,cAAc,EAAG,OAAgB,CAAC;AAC/C,eAAO,MAAM,mBAAmB,EAAG,OAAgB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO;AACP,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,6CAA6C;AAC7C,cAAc,UAAU,CAAC;AAEzB,UAAU;AACV,cAAc,iBAAiB,CAAC;AAEhC,OAAO;AACP,MAAM,CAAC,MAAM,cAAc,GAAG,OAAgB,CAAC;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO;AACP,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,6CAA6C;AAC7C,cAAc,UAAU,CAAC;AAEzB,UAAU;AACV,cAAc,iBAAiB,CAAC;AAEhC,OAAO;AACP,MAAM,CAAC,MAAM,cAAc,GAAG,OAAgB,CAAC;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAgB,CAAC"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -49,6 +49,27 @@ export interface PanelDefinition {
|
|
|
49
49
|
selectedAssets: string[];
|
|
50
50
|
}) => boolean;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* 元数据读取函数(依赖反转)。
|
|
54
|
+
*
|
|
55
|
+
* 某些 Plugin 能力本质是"元数据查询"而非"资产变换"(如 EXIF 读取:
|
|
56
|
+
* Blob → ExifData),既不符合 Engine 层 Blob↔Blob 约束,也不符合
|
|
57
|
+
* CapabilityImplementation 的 Asset[]→Asset[] 契约。这类能力通过
|
|
58
|
+
* MetadataReader 注册:Plugin 提供读取函数,Runtime 持有引用并按名调用。
|
|
59
|
+
*
|
|
60
|
+
* 与 registerCapability 的区别:
|
|
61
|
+
* - registerCapability:注册变换能力(Asset→Asset),走 WorkflowExecutor
|
|
62
|
+
* - registerMetadataReader:注册查询函数(Asset→T),走 Runtime 直接调用
|
|
63
|
+
*
|
|
64
|
+
* 优点(相对 Capability execute + data Asset 序列化方案):
|
|
65
|
+
* - 无需创建临时 data Asset(避免手动 removeAsset 清理 / 泄漏)
|
|
66
|
+
* - 无 JSON marshal/unmarshal 开销
|
|
67
|
+
* - 类型直接透传(ExifData),无需序列化
|
|
68
|
+
*
|
|
69
|
+
* @param asset 输入资产
|
|
70
|
+
* @returns 读取结果;无数据 / 解析失败返回 null
|
|
71
|
+
*/
|
|
72
|
+
export type MetadataReader<T = unknown> = (asset: import('./asset.js').Asset) => Promise<T | null>;
|
|
52
73
|
/**
|
|
53
74
|
* Plugin 上下文(Plugin 能访问的全部 API)
|
|
54
75
|
*
|
|
@@ -75,8 +96,19 @@ export interface PluginContext {
|
|
|
75
96
|
};
|
|
76
97
|
/** 事件总线 */
|
|
77
98
|
eventBus: import('./event.js').EventBus;
|
|
78
|
-
/** 注册能力实现 */
|
|
99
|
+
/** 注册能力实现(变换:Asset→Asset) */
|
|
79
100
|
registerCapability(impl: CapabilityImplementation): void;
|
|
101
|
+
/**
|
|
102
|
+
* 注册元数据读取函数(查询:Asset→T)。
|
|
103
|
+
*
|
|
104
|
+
* 用于非变换类能力(如 EXIF 读取)。Runtime 持有 reader 引用,
|
|
105
|
+
* UI 通过 runtime.readAssetExif(id) 间接调用,不直接依赖 Plugin / Engine。
|
|
106
|
+
* 同名 reader 重复注册时覆盖前者(支持热更新)。
|
|
107
|
+
*
|
|
108
|
+
* @param name 读取器名称,约定与能力名对齐(如 'image.read-exif')
|
|
109
|
+
* @param reader 读取函数
|
|
110
|
+
*/
|
|
111
|
+
registerMetadataReader<T>(name: string, reader: MetadataReader<T>): void;
|
|
80
112
|
/** 注册 UI Panel */
|
|
81
113
|
registerPanel(panel: PanelDefinition): void;
|
|
82
114
|
/** 日志 */
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,kBAAkB;AAClB,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,aAAa,GACb,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB;IACrB,OAAO,EAAE;QACP,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,WAAW;IACX,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,uBAAuB;AACvB,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,QAAQ,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;IACxD,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC;CAC3D;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,OAAO,EAAE;QACP,cAAc;QACd,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,CAAC,CAAC;QAC9D,yBAAyB;QACzB,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QACpD,4BAA4B;QAC5B,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,YAAY,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACnE,0BAA0B;QAC1B,WAAW,EAAE,CACX,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,OAAO,YAAY,EAAE,aAAa,EAC5C,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,KACjC,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,CAAC,CAAC;QACzC,gBAAgB;QAChB,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,iBAAiB,EAAE,UAAU,EAAE,CAAC,CAAC;KACzE,CAAC;IACF,WAAW;IACX,QAAQ,EAAE,OAAO,YAAY,EAAE,QAAQ,CAAC;IACxC,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,kBAAkB;AAClB,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,aAAa,GACb,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB;IACrB,OAAO,EAAE;QACP,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,WAAW;IACX,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,uBAAuB;AACvB,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,QAAQ,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;IACxD,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAAI,CACxC,KAAK,EAAE,OAAO,YAAY,EAAE,KAAK,KAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAEvB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,OAAO,EAAE;QACP,cAAc;QACd,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,CAAC,CAAC;QAC9D,yBAAyB;QACzB,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QACpD,4BAA4B;QAC5B,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,YAAY,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACnE,0BAA0B;QAC1B,WAAW,EAAE,CACX,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,OAAO,YAAY,EAAE,aAAa,EAC5C,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,KACjC,OAAO,CAAC,OAAO,YAAY,EAAE,KAAK,CAAC,CAAC;QACzC,gBAAgB;QAChB,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,iBAAiB,EAAE,UAAU,EAAE,CAAC,CAAC;KACzE,CAAC;IACF,WAAW;IACX,QAAQ,EAAE,OAAO,YAAY,EAAE,QAAQ,CAAC;IACxC,6BAA6B;IAC7B,kBAAkB,CAAC,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACzD;;;;;;;;;OASG;IACH,sBAAsB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACzE,kBAAkB;IAClB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,SAAS;IACT,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9D;AAED,2BAA2B;AAC3B,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/validators.d.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
export declare const assetTypeSchema: z.ZodEnum<["image", "video", "audio", "pdf", "text", "data", "unknown"]>;
|
|
8
|
+
/** W10: Workflow 分类枚举(与 WorkflowCategory 类型对齐) */
|
|
9
|
+
export declare const workflowCategorySchema: z.ZodEnum<["image", "video", "audio", "pdf", "ai", "data", "developer", "ecommerce", "content-creation", "other"]>;
|
|
10
|
+
/** W10: Workflow 输出类型枚举(含 archive 用于打包下载场景) */
|
|
11
|
+
export declare const workflowOutputTypeSchema: z.ZodEnum<["image", "video", "audio", "pdf", "text", "data", "unknown", "archive"]>;
|
|
8
12
|
export declare const assetMetadataSchema: z.ZodObject<{
|
|
9
13
|
mimeType: z.ZodString;
|
|
10
14
|
size: z.ZodNumber;
|
|
@@ -99,7 +103,7 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
99
103
|
id: string;
|
|
100
104
|
name: string;
|
|
101
105
|
}>;
|
|
102
|
-
category: z.
|
|
106
|
+
category: z.ZodEnum<["image", "video", "audio", "pdf", "ai", "data", "developer", "ecommerce", "content-creation", "other"]>;
|
|
103
107
|
tags: z.ZodArray<z.ZodString, "many">;
|
|
104
108
|
nodes: z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
105
109
|
id: z.ZodString;
|
|
@@ -180,7 +184,7 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
180
184
|
id: string;
|
|
181
185
|
name: string;
|
|
182
186
|
};
|
|
183
|
-
category:
|
|
187
|
+
category: "image" | "video" | "audio" | "pdf" | "data" | "ai" | "developer" | "ecommerce" | "content-creation" | "other";
|
|
184
188
|
tags: string[];
|
|
185
189
|
nodes: {
|
|
186
190
|
type: "load" | "transform" | "export";
|
|
@@ -216,7 +220,7 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
216
220
|
id: string;
|
|
217
221
|
name: string;
|
|
218
222
|
};
|
|
219
|
-
category:
|
|
223
|
+
category: "image" | "video" | "audio" | "pdf" | "data" | "ai" | "developer" | "ecommerce" | "content-creation" | "other";
|
|
220
224
|
tags: string[];
|
|
221
225
|
nodes: {
|
|
222
226
|
type: "load" | "transform" | "export";
|
|
@@ -288,13 +292,35 @@ export declare const pluginManifestSchema: z.ZodObject<{
|
|
|
288
292
|
permissions: string[];
|
|
289
293
|
icon?: string | undefined;
|
|
290
294
|
}>;
|
|
291
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* 校验 Workflow JSON。
|
|
292
297
|
*
|
|
293
298
|
* 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
|
|
294
299
|
* 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
|
|
295
300
|
* 现增加结构层校验,让错误在入口处暴露。
|
|
301
|
+
*
|
|
302
|
+
* W10.2 增强:新增 capability 兼容性校验(可选)。
|
|
303
|
+
* 通过 `options.resolveCapability` 回调查询 capability 的 inputTypes/outputTypes,
|
|
304
|
+
* 检查相邻节点的输出类型与下一节点的输入类型是否兼容。schema 包无法直接访问
|
|
305
|
+
* CapabilityRegistry,故采用回调注入模式(避免五层依赖违规)。
|
|
306
|
+
*
|
|
307
|
+
* @param data 待校验的 Workflow JSON
|
|
308
|
+
* @param options 可选项:
|
|
309
|
+
* - resolveCapability: (name: string) => Capability | undefined
|
|
310
|
+
* 返回 capability 声明;返回 undefined 时跳过该节点的兼容性校验(向后兼容)
|
|
311
|
+
* - maxSteps: number
|
|
312
|
+
* 最大节点数限制(默认不限制;W10 要求 5 步,调用方按需传入)
|
|
296
313
|
*/
|
|
297
|
-
export
|
|
314
|
+
export interface ValidateWorkflowOptions {
|
|
315
|
+
/** 查询 capability 声明的回调(返回 undefined 时跳过该节点校验) */
|
|
316
|
+
resolveCapability?: (name: string) => {
|
|
317
|
+
inputTypes: string[];
|
|
318
|
+
outputTypes: string[];
|
|
319
|
+
} | undefined;
|
|
320
|
+
/** 最大节点数限制(可选) */
|
|
321
|
+
maxSteps?: number;
|
|
322
|
+
}
|
|
323
|
+
export declare function validateWorkflow(data: unknown, options?: ValidateWorkflowOptions): z.SafeParseError<{
|
|
298
324
|
id: string;
|
|
299
325
|
version: string;
|
|
300
326
|
name: string;
|
|
@@ -303,7 +329,7 @@ export declare function validateWorkflow(data: unknown): z.SafeParseError<{
|
|
|
303
329
|
id: string;
|
|
304
330
|
name: string;
|
|
305
331
|
};
|
|
306
|
-
category:
|
|
332
|
+
category: "image" | "video" | "audio" | "pdf" | "data" | "ai" | "developer" | "ecommerce" | "content-creation" | "other";
|
|
307
333
|
tags: string[];
|
|
308
334
|
nodes: {
|
|
309
335
|
type: "load" | "transform" | "export";
|
|
@@ -351,7 +377,7 @@ export declare function validateWorkflow(data: unknown): z.SafeParseError<{
|
|
|
351
377
|
id: string;
|
|
352
378
|
name: string;
|
|
353
379
|
};
|
|
354
|
-
category:
|
|
380
|
+
category: "image" | "video" | "audio" | "pdf" | "data" | "ai" | "developer" | "ecommerce" | "content-creation" | "other";
|
|
355
381
|
tags: string[];
|
|
356
382
|
nodes: {
|
|
357
383
|
type: "load" | "transform" | "export";
|
package/dist/validators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe,0EAQ1B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW/B,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe,0EAQ1B,CAAC;AAEH,kDAAkD;AAClD,eAAO,MAAM,sBAAsB,oHAWjC,CAAC;AAEH,+CAA+C;AAC/C,eAAO,MAAM,wBAAwB,qFASnC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBzB,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW/B,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QACpC,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,GAAG,SAAS,CAAC;IACd,kBAAkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+HhF;AA4FD,yBAAyB;AACzB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;GAEnD"}
|
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,19 +96,17 @@ 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
|
-
* 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
|
|
78
|
-
* 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
|
|
79
|
-
* 现增加结构层校验,让错误在入口处暴露。
|
|
80
|
-
*/
|
|
81
|
-
export function validateWorkflow(data) {
|
|
99
|
+
export function validateWorkflow(data, options) {
|
|
82
100
|
const parsed = workflowSchema.safeParse(data);
|
|
83
101
|
if (!parsed.success) {
|
|
84
102
|
return parsed;
|
|
85
103
|
}
|
|
86
104
|
const wf = parsed.data;
|
|
87
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
|
+
}
|
|
88
110
|
// 1. 保留字哨兵:禁止 __input__ / __output__ 出现在 nodes 或 edges
|
|
89
111
|
// (executor 不支持哨兵节点,输入资产注入到入度 0 的首节点)
|
|
90
112
|
const RESERVED_IDS = new Set(['__input__', '__output__', '__start__', '__end__']);
|
|
@@ -144,6 +166,10 @@ export function validateWorkflow(data) {
|
|
|
144
166
|
let visited = 0;
|
|
145
167
|
while (queue.length > 0) {
|
|
146
168
|
const id = queue.shift();
|
|
169
|
+
// 循环条件 queue.length > 0 保证 shift 必返回元素;
|
|
170
|
+
// 显式检查以满足 noUncheckedIndexedAccess,并在不变量被打破时跳出
|
|
171
|
+
if (id === undefined)
|
|
172
|
+
break;
|
|
147
173
|
visited++;
|
|
148
174
|
for (const next of adjacency.get(id) ?? []) {
|
|
149
175
|
const newDeg = (inDegree.get(next) ?? 0) - 1;
|
|
@@ -156,6 +182,14 @@ export function validateWorkflow(data) {
|
|
|
156
182
|
errors.push(`Workflow contains a cycle: only ${visited}/${wf.nodes.length} nodes are reachable.`);
|
|
157
183
|
}
|
|
158
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
|
+
}
|
|
159
193
|
if (errors.length > 0) {
|
|
160
194
|
return {
|
|
161
195
|
success: false,
|
|
@@ -170,6 +204,86 @@ export function validateWorkflow(data) {
|
|
|
170
204
|
}
|
|
171
205
|
return { success: true, data: wf };
|
|
172
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
|
+
}
|
|
286
|
+
}
|
|
173
287
|
/** 校验 Plugin Manifest */
|
|
174
288
|
export function validatePluginManifest(data) {
|
|
175
289
|
return pluginManifestSchema.safeParse(data);
|
package/dist/validators.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"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"}
|
|
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.2.
|
|
3
|
+
"version": "0.2.1",
|
|
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/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 }
|
|
@@ -47,7 +64,53 @@ export type LokvisEvent =
|
|
|
47
64
|
currentIndex: number;
|
|
48
65
|
}
|
|
49
66
|
| { type: 'capability:registered'; capability: string; engine: string }
|
|
50
|
-
| { 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 };
|
|
51
114
|
|
|
52
115
|
/** 所有事件类型字面量 */
|
|
53
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
|
/** 日志 */
|
package/src/validators.ts
CHANGED
|
@@ -16,6 +16,32 @@ export const assetTypeSchema = z.enum([
|
|
|
16
16
|
'unknown',
|
|
17
17
|
]);
|
|
18
18
|
|
|
19
|
+
/** W10: Workflow 分类枚举(与 WorkflowCategory 类型对齐) */
|
|
20
|
+
export const workflowCategorySchema = z.enum([
|
|
21
|
+
'image',
|
|
22
|
+
'video',
|
|
23
|
+
'audio',
|
|
24
|
+
'pdf',
|
|
25
|
+
'ai',
|
|
26
|
+
'data',
|
|
27
|
+
'developer',
|
|
28
|
+
'ecommerce',
|
|
29
|
+
'content-creation',
|
|
30
|
+
'other',
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
/** W10: Workflow 输出类型枚举(含 archive 用于打包下载场景) */
|
|
34
|
+
export const workflowOutputTypeSchema = z.enum([
|
|
35
|
+
'image',
|
|
36
|
+
'video',
|
|
37
|
+
'audio',
|
|
38
|
+
'pdf',
|
|
39
|
+
'text',
|
|
40
|
+
'data',
|
|
41
|
+
'unknown',
|
|
42
|
+
'archive',
|
|
43
|
+
]);
|
|
44
|
+
|
|
19
45
|
export const assetMetadataSchema = z.object({
|
|
20
46
|
mimeType: z.string(),
|
|
21
47
|
size: z.number().nonnegative(),
|
|
@@ -51,7 +77,7 @@ export const workflowSchema = z.object({
|
|
|
51
77
|
name: z.string(),
|
|
52
78
|
description: z.string(),
|
|
53
79
|
author: z.object({ id: z.string(), name: z.string() }),
|
|
54
|
-
category:
|
|
80
|
+
category: workflowCategorySchema,
|
|
55
81
|
tags: z.array(z.string()),
|
|
56
82
|
nodes: z.array(workflowNodeSchema),
|
|
57
83
|
edges: z.array(workflowEdgeSchema),
|
|
@@ -62,7 +88,7 @@ export const workflowSchema = z.object({
|
|
|
62
88
|
accept: z.array(z.string()).optional(),
|
|
63
89
|
}),
|
|
64
90
|
outputs: z.object({
|
|
65
|
-
type:
|
|
91
|
+
type: workflowOutputTypeSchema,
|
|
66
92
|
format: z.string().optional(),
|
|
67
93
|
}),
|
|
68
94
|
official: z.boolean().optional(),
|
|
@@ -83,13 +109,36 @@ export const pluginManifestSchema = z.object({
|
|
|
83
109
|
permissions: z.array(z.string()),
|
|
84
110
|
});
|
|
85
111
|
|
|
86
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* 校验 Workflow JSON。
|
|
87
114
|
*
|
|
88
115
|
* 修复 review 报告:原实现仅做 Zod 形状校验,不检查 edge 引用、保留字、DAG 合法性,
|
|
89
116
|
* 导致 demo 用 `__input__` 哨兵边时 Zod 通过但 executor 抛 "cycle"。
|
|
90
117
|
* 现增加结构层校验,让错误在入口处暴露。
|
|
118
|
+
*
|
|
119
|
+
* W10.2 增强:新增 capability 兼容性校验(可选)。
|
|
120
|
+
* 通过 `options.resolveCapability` 回调查询 capability 的 inputTypes/outputTypes,
|
|
121
|
+
* 检查相邻节点的输出类型与下一节点的输入类型是否兼容。schema 包无法直接访问
|
|
122
|
+
* CapabilityRegistry,故采用回调注入模式(避免五层依赖违规)。
|
|
123
|
+
*
|
|
124
|
+
* @param data 待校验的 Workflow JSON
|
|
125
|
+
* @param options 可选项:
|
|
126
|
+
* - resolveCapability: (name: string) => Capability | undefined
|
|
127
|
+
* 返回 capability 声明;返回 undefined 时跳过该节点的兼容性校验(向后兼容)
|
|
128
|
+
* - maxSteps: number
|
|
129
|
+
* 最大节点数限制(默认不限制;W10 要求 5 步,调用方按需传入)
|
|
91
130
|
*/
|
|
92
|
-
export
|
|
131
|
+
export interface ValidateWorkflowOptions {
|
|
132
|
+
/** 查询 capability 声明的回调(返回 undefined 时跳过该节点校验) */
|
|
133
|
+
resolveCapability?: (name: string) => {
|
|
134
|
+
inputTypes: string[];
|
|
135
|
+
outputTypes: string[];
|
|
136
|
+
} | undefined;
|
|
137
|
+
/** 最大节点数限制(可选) */
|
|
138
|
+
maxSteps?: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function validateWorkflow(data: unknown, options?: ValidateWorkflowOptions) {
|
|
93
142
|
const parsed = workflowSchema.safeParse(data);
|
|
94
143
|
if (!parsed.success) {
|
|
95
144
|
return parsed;
|
|
@@ -98,6 +147,13 @@ export function validateWorkflow(data: unknown) {
|
|
|
98
147
|
const wf = parsed.data;
|
|
99
148
|
const errors: string[] = [];
|
|
100
149
|
|
|
150
|
+
// 0. W10.2: 节点数上限校验(可选)
|
|
151
|
+
if (options?.maxSteps !== undefined && wf.nodes.length > options.maxSteps) {
|
|
152
|
+
errors.push(
|
|
153
|
+
`Workflow has ${wf.nodes.length} nodes, exceeds max ${options.maxSteps}.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
101
157
|
// 1. 保留字哨兵:禁止 __input__ / __output__ 出现在 nodes 或 edges
|
|
102
158
|
// (executor 不支持哨兵节点,输入资产注入到入度 0 的首节点)
|
|
103
159
|
const RESERVED_IDS = new Set(['__input__', '__output__', '__start__', '__end__']);
|
|
@@ -168,7 +224,10 @@ export function validateWorkflow(data: unknown) {
|
|
|
168
224
|
}
|
|
169
225
|
let visited = 0;
|
|
170
226
|
while (queue.length > 0) {
|
|
171
|
-
const id = queue.shift()
|
|
227
|
+
const id = queue.shift();
|
|
228
|
+
// 循环条件 queue.length > 0 保证 shift 必返回元素;
|
|
229
|
+
// 显式检查以满足 noUncheckedIndexedAccess,并在不变量被打破时跳出
|
|
230
|
+
if (id === undefined) break;
|
|
172
231
|
visited++;
|
|
173
232
|
for (const next of adjacency.get(id) ?? []) {
|
|
174
233
|
const newDeg = (inDegree.get(next) ?? 0) - 1;
|
|
@@ -183,6 +242,15 @@ export function validateWorkflow(data: unknown) {
|
|
|
183
242
|
}
|
|
184
243
|
}
|
|
185
244
|
|
|
245
|
+
// 5. W10.2: capability 兼容性校验(可选,仅在 resolveCapability 提供时)
|
|
246
|
+
// 检查相邻节点(通过 edge 连接)的 outputTypes 与下一节点的 inputTypes 是否有交集。
|
|
247
|
+
// - 线性链:edge.from → edge.to,from 节点的 outputTypes 与 to 节点的 inputTypes 交集为空则报错
|
|
248
|
+
// - 输入节点(入度 0)的 inputTypes 与 workflow.inputs.type 兼容性
|
|
249
|
+
// - 输出节点(出度 0)的 outputTypes 与 workflow.outputs.type 兼容性
|
|
250
|
+
if (options?.resolveCapability && errors.length === 0) {
|
|
251
|
+
validateCapabilityCompatibility(wf, options.resolveCapability, errors);
|
|
252
|
+
}
|
|
253
|
+
|
|
186
254
|
if (errors.length > 0) {
|
|
187
255
|
return {
|
|
188
256
|
success: false as const,
|
|
@@ -199,6 +267,96 @@ export function validateWorkflow(data: unknown) {
|
|
|
199
267
|
return { success: true as const, data: wf };
|
|
200
268
|
}
|
|
201
269
|
|
|
270
|
+
/** W10.2: capability 兼容性校验内部实现 */
|
|
271
|
+
function validateCapabilityCompatibility(
|
|
272
|
+
wf: z.infer<typeof workflowSchema>,
|
|
273
|
+
resolveCapability: (name: string) => { inputTypes: string[]; outputTypes: string[] } | undefined,
|
|
274
|
+
errors: string[]
|
|
275
|
+
): void {
|
|
276
|
+
// 计算每个节点的入度/出度,识别输入/输出节点
|
|
277
|
+
const inDegree = new Map<string, number>();
|
|
278
|
+
const outDegree = new Map<string, number>();
|
|
279
|
+
for (const node of wf.nodes) {
|
|
280
|
+
inDegree.set(node.id, 0);
|
|
281
|
+
outDegree.set(node.id, 0);
|
|
282
|
+
}
|
|
283
|
+
for (const edge of wf.edges) {
|
|
284
|
+
inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
|
|
285
|
+
outDegree.set(edge.from, (outDegree.get(edge.from) ?? 0) + 1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 缓存每个节点的 capability 声明
|
|
289
|
+
const capCache = new Map<string, { inputTypes: string[]; outputTypes: string[] } | undefined>();
|
|
290
|
+
type InferredNode = z.infer<typeof workflowNodeSchema>;
|
|
291
|
+
const getCap = (node: InferredNode) => {
|
|
292
|
+
if (!node.capability) return undefined;
|
|
293
|
+
if (capCache.has(node.capability)) return capCache.get(node.capability);
|
|
294
|
+
const cap = resolveCapability(node.capability);
|
|
295
|
+
capCache.set(node.capability, cap);
|
|
296
|
+
return cap;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// 5a. 输入节点(入度 0)的 inputTypes 与 workflow.inputs.type 兼容
|
|
300
|
+
for (const node of wf.nodes) {
|
|
301
|
+
if ((inDegree.get(node.id) ?? 0) > 0) continue;
|
|
302
|
+
const cap = getCap(node);
|
|
303
|
+
// 未注册的 capability 不静默跳过:在 schema 层显式报错,避免用户得到"校验通过"
|
|
304
|
+
// 的假象,运行时才报错。resolveCapability 未提供时(getCap 始终返回 undefined)
|
|
305
|
+
// 整个 capability 兼容性校验跳过(向后兼容,见 5d 兜底)。
|
|
306
|
+
if (!cap) {
|
|
307
|
+
if (node.capability) {
|
|
308
|
+
errors.push(
|
|
309
|
+
`Node "${node.id}" references unknown capability "${node.capability}". ` +
|
|
310
|
+
`Capability is not registered in the registry.`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const inputTypeMatches = cap.inputTypes.includes(wf.inputs.type);
|
|
316
|
+
if (!inputTypeMatches) {
|
|
317
|
+
errors.push(
|
|
318
|
+
`Node "${node.id}" (capability "${node.capability}") expects input types ` +
|
|
319
|
+
`[${cap.inputTypes.join(', ')}], but workflow input is "${wf.inputs.type}".`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 5b. 相邻节点:from 的 outputTypes 与 to 的 inputTypes 必须有交集
|
|
325
|
+
for (const edge of wf.edges) {
|
|
326
|
+
const fromNode = wf.nodes.find((n) => n.id === edge.from);
|
|
327
|
+
const toNode = wf.nodes.find((n) => n.id === edge.to);
|
|
328
|
+
if (!fromNode || !toNode) continue;
|
|
329
|
+
const fromCap = getCap(fromNode);
|
|
330
|
+
const toCap = getCap(toNode);
|
|
331
|
+
if (!fromCap || !toCap) continue; // 5a 已报告未注册 capability,此处不重复
|
|
332
|
+
const compatible = fromCap.outputTypes.some((t) => toCap.inputTypes.includes(t));
|
|
333
|
+
if (!compatible) {
|
|
334
|
+
errors.push(
|
|
335
|
+
`Capability mismatch on edge "${edge.from}" → "${edge.to}": ` +
|
|
336
|
+
`"${fromNode.capability}" outputs [${fromCap.outputTypes.join(', ')}], ` +
|
|
337
|
+
`but "${toNode.capability}" accepts [${toCap.inputTypes.join(', ')}].`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 5c. 输出节点(出度 0)的 outputTypes 与 workflow.outputs.type 兼容
|
|
343
|
+
// (archive 类型输出允许任意类型,用于打包下载场景)
|
|
344
|
+
for (const node of wf.nodes) {
|
|
345
|
+
if ((outDegree.get(node.id) ?? 0) > 0) continue;
|
|
346
|
+
const cap = getCap(node);
|
|
347
|
+
if (!cap) continue; // 5a 已报告未注册 capability,此处不重复
|
|
348
|
+
const outputType = wf.outputs.type;
|
|
349
|
+
if (outputType === 'archive') continue;
|
|
350
|
+
const outputTypeMatches = cap.outputTypes.includes(outputType);
|
|
351
|
+
if (!outputTypeMatches) {
|
|
352
|
+
errors.push(
|
|
353
|
+
`Node "${node.id}" (capability "${node.capability}") produces output types ` +
|
|
354
|
+
`[${cap.outputTypes.join(', ')}], but workflow output is "${outputType}".`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
202
360
|
/** 校验 Plugin Manifest */
|
|
203
361
|
export function validatePluginManifest(data: unknown) {
|
|
204
362
|
return pluginManifestSchema.safeParse(data);
|