@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 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'];
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
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
@@ -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";
@@ -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;AAE5B,cAAc,UAAU,CAAC;AAGzB,cAAc,iBAAiB,CAAC;AAGhC,eAAO,MAAM,cAAc,EAAG,OAAgB,CAAC;AAC/C,eAAO,MAAM,mBAAmB,EAAG,OAAgB,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
@@ -10,6 +10,7 @@ export * from './capability.js';
10
10
  export * from './workflow.js';
11
11
  export * from './event.js';
12
12
  export * from './plugin.js';
13
+ export * from './exif.js';
13
14
  // MCP manifest 类型(见 docs/AI生态冲击调整方案.md §6.1)
14
15
  export * from './mcp.js';
15
16
  // Zod 校验器
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
  /** 日志 */
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -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.ZodString;
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: string;
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: string;
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
- /** 校验 Workflow JSON。
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 declare function validateWorkflow(data: unknown): z.SafeParseError<{
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: string;
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: string;
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";
@@ -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;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4G7C;AAED,yBAAyB;AACzB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;GAEnD"}
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"}
@@ -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: z.string(),
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: z.enum(['image', 'video', 'audio', 'pdf', 'text', 'data', 'unknown', 'archive']),
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
- /** 校验 Workflow JSON。
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);
@@ -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.0-beta.0",
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
@@ -11,6 +11,7 @@ export * from './capability.js';
11
11
  export * from './workflow.js';
12
12
  export * from './event.js';
13
13
  export * from './plugin.js';
14
+ export * from './exif.js';
14
15
  // MCP manifest 类型(见 docs/AI生态冲击调整方案.md §6.1)
15
16
  export * from './mcp.js';
16
17
 
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: z.string(),
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: z.enum(['image', 'video', 'audio', 'pdf', 'text', 'data', 'unknown', 'archive']),
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
- /** 校验 Workflow JSON。
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 function validateWorkflow(data: unknown) {
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);