@mbws/plugin-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/client.d.ts +99 -0
- package/dist/client.js +210 -0
- package/dist/config.d.ts +112 -0
- package/dist/config.js +61 -0
- package/dist/contract.d.ts +41 -0
- package/dist/contract.js +68 -0
- package/dist/dev-mock.d.ts +12 -0
- package/dist/dev-mock.js +59 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +26 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/manifest.d.ts +65 -0
- package/dist/manifest.js +90 -0
- package/dist/protocol.d.ts +127 -0
- package/dist/protocol.js +142 -0
- package/dist/uuid.d.ts +10 -0
- package/dist/uuid.js +17 -0
- package/dist/version.d.ts +15 -0
- package/dist/version.js +15 -0
- package/package.json +33 -0
package/dist/dev-mock.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { fetchContract } from "./contract.js";
|
|
2
|
+
/**
|
|
3
|
+
* 创建 dev mock 客户端。四个固定命名空间全部构造(dev 无授权语义),
|
|
4
|
+
* panel 生命周期面上报/应答均无宿主可收,no-op 即可。
|
|
5
|
+
*/
|
|
6
|
+
export function createDevMockMbws() {
|
|
7
|
+
return {
|
|
8
|
+
data: {
|
|
9
|
+
read: async (key) => {
|
|
10
|
+
try {
|
|
11
|
+
const response = await fetch(new URL(`samples/${key}.json`, document.baseURI));
|
|
12
|
+
if (!response.ok)
|
|
13
|
+
return undefined;
|
|
14
|
+
return (await response.json());
|
|
15
|
+
}
|
|
16
|
+
catch (_error) {
|
|
17
|
+
console.warn(`[mbws:dev] samples/${key}.json 读取失败,回 undefined`);
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
blob: async (key) => {
|
|
22
|
+
console.info(`[mbws:dev] data.blob(${key}) no-op`);
|
|
23
|
+
return { url: `dev://samples/${key}` };
|
|
24
|
+
},
|
|
25
|
+
apply: async (outputs) => {
|
|
26
|
+
console.info("[mbws:dev] apply(不入库)", outputs);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
runtime: {
|
|
30
|
+
progress: async () => { },
|
|
31
|
+
log: async (...args) => {
|
|
32
|
+
console.info("[mbws:dev] log", ...args);
|
|
33
|
+
},
|
|
34
|
+
signal: () => new AbortController().signal,
|
|
35
|
+
},
|
|
36
|
+
storage: {
|
|
37
|
+
get: async () => undefined,
|
|
38
|
+
set: async () => { },
|
|
39
|
+
},
|
|
40
|
+
ui: {
|
|
41
|
+
confirm: async (opts) => {
|
|
42
|
+
console.info(`[mbws:dev] ui.confirm:${opts.title ?? ""} ${opts.message}`);
|
|
43
|
+
return true;
|
|
44
|
+
},
|
|
45
|
+
toast: async (message) => {
|
|
46
|
+
console.info(`[mbws:dev] ui.toast:${message}`);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
panel: {
|
|
50
|
+
resize: () => { },
|
|
51
|
+
onBeforeClose: () => { },
|
|
52
|
+
replyBeforeClose: () => { },
|
|
53
|
+
},
|
|
54
|
+
// 契约面不走 mock:dev 下同样 HTTP 直连服务端拉真值(samples 夹具只有 data.read)
|
|
55
|
+
contract: {
|
|
56
|
+
get: (opts = {}) => fetchContract(opts),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mbws 协议错误码(v1)。
|
|
3
|
+
*
|
|
4
|
+
* 用于 `mbws:reject` 消息的 `error.code`,以及宿主 broker 侧的审计归类。
|
|
5
|
+
* 错误码集合是协议契约的一部分:只增不改语义,破坏性变更随 PROTOCOL_VERSION 大版本走。
|
|
6
|
+
*/
|
|
7
|
+
export declare const MBWS_ERROR_CODES: {
|
|
8
|
+
/** 调用参数不符合方法签名(ns/method 存在但 args 不合法) */
|
|
9
|
+
readonly E_INVALID_ARGS: "E_INVALID_ARGS";
|
|
10
|
+
/** 调用了命名空间下不存在的方法 */
|
|
11
|
+
readonly E_UNKNOWN_METHOD: "E_UNKNOWN_METHOD";
|
|
12
|
+
/** manifest 未声明该权限,或用户/宿主未授予(broker 独立校验的第一道拒) */
|
|
13
|
+
readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
|
|
14
|
+
/** 配额超限(AI 次数/费用、指令预算、wall-clock 超时等) */
|
|
15
|
+
readonly E_QUOTA_EXCEEDED: "E_QUOTA_EXCEEDED";
|
|
16
|
+
/** apply 写回被 write gate 拒绝(key 越界 / outputSchema 校验失败 / 显式拒未知字段) */
|
|
17
|
+
readonly E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED";
|
|
18
|
+
/** 依赖的能力包未安装或版本不满足 */
|
|
19
|
+
readonly E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE";
|
|
20
|
+
/** 调用超时(宿主侧 wall-clock 预算) */
|
|
21
|
+
readonly E_TIMEOUT: "E_TIMEOUT";
|
|
22
|
+
/** 被取消(对齐 ffmpeg-cancel 语义,runtime.signal 触发后的在途调用收尾) */
|
|
23
|
+
readonly E_CANCELLED: "E_CANCELLED";
|
|
24
|
+
/** 消息本身违反协议(缺 v、未知 type、方向错误) */
|
|
25
|
+
readonly E_PROTOCOL_VIOLATION: "E_PROTOCOL_VIOLATION";
|
|
26
|
+
};
|
|
27
|
+
export type MbwsErrorCode = (typeof MBWS_ERROR_CODES)[keyof typeof MBWS_ERROR_CODES];
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mbws 协议错误码(v1)。
|
|
3
|
+
*
|
|
4
|
+
* 用于 `mbws:reject` 消息的 `error.code`,以及宿主 broker 侧的审计归类。
|
|
5
|
+
* 错误码集合是协议契约的一部分:只增不改语义,破坏性变更随 PROTOCOL_VERSION 大版本走。
|
|
6
|
+
*/
|
|
7
|
+
export const MBWS_ERROR_CODES = {
|
|
8
|
+
/** 调用参数不符合方法签名(ns/method 存在但 args 不合法) */
|
|
9
|
+
E_INVALID_ARGS: "E_INVALID_ARGS",
|
|
10
|
+
/** 调用了命名空间下不存在的方法 */
|
|
11
|
+
E_UNKNOWN_METHOD: "E_UNKNOWN_METHOD",
|
|
12
|
+
/** manifest 未声明该权限,或用户/宿主未授予(broker 独立校验的第一道拒) */
|
|
13
|
+
E_PERMISSION_DENIED: "E_PERMISSION_DENIED",
|
|
14
|
+
/** 配额超限(AI 次数/费用、指令预算、wall-clock 超时等) */
|
|
15
|
+
E_QUOTA_EXCEEDED: "E_QUOTA_EXCEEDED",
|
|
16
|
+
/** apply 写回被 write gate 拒绝(key 越界 / outputSchema 校验失败 / 显式拒未知字段) */
|
|
17
|
+
E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED",
|
|
18
|
+
/** 依赖的能力包未安装或版本不满足 */
|
|
19
|
+
E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE",
|
|
20
|
+
/** 调用超时(宿主侧 wall-clock 预算) */
|
|
21
|
+
E_TIMEOUT: "E_TIMEOUT",
|
|
22
|
+
/** 被取消(对齐 ffmpeg-cancel 语义,runtime.signal 触发后的在途调用收尾) */
|
|
23
|
+
E_CANCELLED: "E_CANCELLED",
|
|
24
|
+
/** 消息本身违反协议(缺 v、未知 type、方向错误) */
|
|
25
|
+
E_PROTOCOL_VIOLATION: "E_PROTOCOL_VIOLATION",
|
|
26
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mbws/plugin-sdk —— Moye 加工工具插件平台的契约与 SDK 包。
|
|
3
|
+
*
|
|
4
|
+
* M1:契约基座(manifest / 协议消息族 / 错误码 / 版本常量)。
|
|
5
|
+
* M2:createMbws() 工厂与 dev mock。
|
|
6
|
+
* 后续里程碑在此包内扩展:CLI dev/build/sign(M4)、fns/DSL(M4)。
|
|
7
|
+
*/
|
|
8
|
+
export * from "./client.js";
|
|
9
|
+
export * from "./config.js";
|
|
10
|
+
export * from "./contract.js";
|
|
11
|
+
export * from "./dev-mock.js";
|
|
12
|
+
export * from "./errors.js";
|
|
13
|
+
export * from "./manifest.js";
|
|
14
|
+
export * from "./protocol.js";
|
|
15
|
+
export * from "./uuid.js";
|
|
16
|
+
export * from "./version.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mbws/plugin-sdk —— Moye 加工工具插件平台的契约与 SDK 包。
|
|
3
|
+
*
|
|
4
|
+
* M1:契约基座(manifest / 协议消息族 / 错误码 / 版本常量)。
|
|
5
|
+
* M2:createMbws() 工厂与 dev mock。
|
|
6
|
+
* 后续里程碑在此包内扩展:CLI dev/build/sign(M4)、fns/DSL(M4)。
|
|
7
|
+
*/
|
|
8
|
+
export * from "./client.js";
|
|
9
|
+
export * from "./config.js";
|
|
10
|
+
export * from "./contract.js";
|
|
11
|
+
export * from "./dev-mock.js";
|
|
12
|
+
export * from "./errors.js";
|
|
13
|
+
export * from "./manifest.js";
|
|
14
|
+
export * from "./protocol.js";
|
|
15
|
+
export * from "./uuid.js";
|
|
16
|
+
export * from "./version.js";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件 manifest(合同)契约——设计稿 §3.2 的代码定稿。
|
|
3
|
+
*
|
|
4
|
+
* manifest 是插件与宿主之间唯一的静态合同:权限声明、能力依赖、自动化形态、入口组件。
|
|
5
|
+
* 宿主(broker / write gate / CSP 推导 / 权限预览文案)全部以此为数据源,逐字段强校验。
|
|
6
|
+
* 注意 I/O 契约不在其列——数据结构唯一权威在服务端(spec 引用 + 按编号实时派生),
|
|
7
|
+
* manifest 只留静态装载合同,不落地会过期的契约快照。
|
|
8
|
+
*
|
|
9
|
+
* 字段对齐三方现有事实:
|
|
10
|
+
* - 前端 `ActionDefinition`(automation/inputs/outputs/paramsSchema 语义同源)
|
|
11
|
+
* - spec 侧 `RecordActionEntry`(x-action 声明只引用 id+键映射,结构锁定在 manifest)
|
|
12
|
+
* - 后端 `validate_record_actions`(outputs 键集一致性校验的权威在 manifest.outputs)
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
/**
|
|
16
|
+
* 任意 JSON 值(递归)。inputs/outputs/paramsSchema 的叶子都是 JSON Schema 对象,
|
|
17
|
+
* 结构宽容透传(含 `x-modality`/`x-mime`/`x-storage`/`x-field-name` 等扩展键),
|
|
18
|
+
* 语义校验交给 write gate 的 outputSchema 校验,不在这里重复。
|
|
19
|
+
*/
|
|
20
|
+
type Json = null | boolean | number | string | Json[] | {
|
|
21
|
+
[key: string]: Json;
|
|
22
|
+
};
|
|
23
|
+
export declare const ManifestSchema: z.ZodObject<{
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
version: z.ZodString;
|
|
26
|
+
artifactVersion: z.ZodLiteral<1>;
|
|
27
|
+
kind: z.ZodEnum<{
|
|
28
|
+
producer: "producer";
|
|
29
|
+
validator: "validator";
|
|
30
|
+
}>;
|
|
31
|
+
inputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodType<Json, unknown, z.core.$ZodTypeInternals<Json, unknown>>>]>>>;
|
|
32
|
+
outputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodType<Json, unknown, z.core.$ZodTypeInternals<Json, unknown>>>]>>>;
|
|
33
|
+
paramsSchema: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodType<Json, unknown, z.core.$ZodTypeInternals<Json, unknown>>>]>>;
|
|
34
|
+
requiresCapabilities: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
35
|
+
permissions: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
36
|
+
automation: z.ZodEnum<{
|
|
37
|
+
batchable: "batchable";
|
|
38
|
+
"interactive-only": "interactive-only";
|
|
39
|
+
}>;
|
|
40
|
+
components: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
panel: z.ZodOptional<z.ZodString>;
|
|
42
|
+
viewer: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
sdk: z.ZodOptional<z.ZodString>;
|
|
45
|
+
meta: z.ZodObject<{
|
|
46
|
+
title: z.ZodString;
|
|
47
|
+
description: z.ZodString;
|
|
48
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
49
|
+
vendor: z.ZodOptional<z.ZodString>;
|
|
50
|
+
screenshots: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type Manifest = z.output<typeof ManifestSchema>;
|
|
54
|
+
export interface ManifestValidationOk {
|
|
55
|
+
ok: true;
|
|
56
|
+
manifest: Manifest;
|
|
57
|
+
}
|
|
58
|
+
export interface ManifestValidationErr {
|
|
59
|
+
ok: false;
|
|
60
|
+
errors: string[];
|
|
61
|
+
}
|
|
62
|
+
export type ManifestValidation = ManifestValidationOk | ManifestValidationErr;
|
|
63
|
+
/** 校验 manifest:宽容入口(任意 unknown),失败返回逐字段错误清单而不抛异常。 */
|
|
64
|
+
export declare function validateManifest(input: unknown): ManifestValidation;
|
|
65
|
+
export {};
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件 manifest(合同)契约——设计稿 §3.2 的代码定稿。
|
|
3
|
+
*
|
|
4
|
+
* manifest 是插件与宿主之间唯一的静态合同:权限声明、能力依赖、自动化形态、入口组件。
|
|
5
|
+
* 宿主(broker / write gate / CSP 推导 / 权限预览文案)全部以此为数据源,逐字段强校验。
|
|
6
|
+
* 注意 I/O 契约不在其列——数据结构唯一权威在服务端(spec 引用 + 按编号实时派生),
|
|
7
|
+
* manifest 只留静态装载合同,不落地会过期的契约快照。
|
|
8
|
+
*
|
|
9
|
+
* 字段对齐三方现有事实:
|
|
10
|
+
* - 前端 `ActionDefinition`(automation/inputs/outputs/paramsSchema 语义同源)
|
|
11
|
+
* - spec 侧 `RecordActionEntry`(x-action 声明只引用 id+键映射,结构锁定在 manifest)
|
|
12
|
+
* - 后端 `validate_record_actions`(outputs 键集一致性校验的权威在 manifest.outputs)
|
|
13
|
+
*/
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { ARTIFACT_VERSION } from "./version.js";
|
|
16
|
+
const jsonValue = z.lazy(() => z.union([
|
|
17
|
+
z.null(),
|
|
18
|
+
z.boolean(),
|
|
19
|
+
z.number(),
|
|
20
|
+
z.string(),
|
|
21
|
+
z.array(jsonValue),
|
|
22
|
+
z.record(z.string(), jsonValue),
|
|
23
|
+
]));
|
|
24
|
+
/** JSON Schema 根节点:对象或布尔(`true`/`false` 是合法的空 schema)。 */
|
|
25
|
+
const JsonSchemaValue = z.union([z.boolean(), z.record(z.string(), jsonValue)]);
|
|
26
|
+
/**
|
|
27
|
+
* 插件 id:小写字母数字 + 短横线/点分段。信任级用前缀约定(schema 不硬分,registry 赋级):
|
|
28
|
+
* `internal.*` 项目组 / `org.*` 企业白名单 / `3p.*` 市场上架 / 无前缀或 `dev.*` 仅本机开发。
|
|
29
|
+
*/
|
|
30
|
+
const PLUGIN_ID_RE = /^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)*$/;
|
|
31
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/;
|
|
32
|
+
/** 能力依赖:`<域>.<名>` 可带版本约束,如 `media.ffmpeg@>=7`。 */
|
|
33
|
+
const CAPABILITY_RE = /^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+(@.+)?$/;
|
|
34
|
+
/**
|
|
35
|
+
* 权限声明,两种语法(CSP connect-src 与权限预览文案的推导输入,设计稿 §6.5):
|
|
36
|
+
* - `ai.<purpose>`:走项目 AI 中心的调用(如 `ai.ocr`)
|
|
37
|
+
* - `net:<host>`:插件自有 key 直连的外部域名(如 `net:api.vendor.example.com`)
|
|
38
|
+
*/
|
|
39
|
+
const PERMISSION_RE = /^(ai\.[a-z][a-z0-9-]*|net:[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$)/;
|
|
40
|
+
export const ManifestSchema = z.object({
|
|
41
|
+
/** I/O 契约锚点:spec 的 x-action 钉的是 id,同 id 多实现竞争 UX(设计稿 §3.4) */
|
|
42
|
+
id: z.string().regex(PLUGIN_ID_RE),
|
|
43
|
+
version: z.string().regex(SEMVER_RE),
|
|
44
|
+
/** 产物格式版本:宿主按版本兼容加载,升版本 = 破坏性变更 */
|
|
45
|
+
artifactVersion: z.literal(ARTIFACT_VERSION),
|
|
46
|
+
/** producer=加工插件(本文档主体);validator=检测插件(另案,此处仅收枚举) */
|
|
47
|
+
kind: z.enum(["producer", "validator"]),
|
|
48
|
+
/**
|
|
49
|
+
* 输入/输出契约:可选——数据结构唯一权威在服务端(按插件编号实时派生),
|
|
50
|
+
* manifest 是静态装载合同,不落地会过期的契约快照(写了也没人负责更新)。
|
|
51
|
+
* 留 optional 兼容存量产物;插件运行期/宿主 write gate 一律经 by-plugin 拉实时值。
|
|
52
|
+
*/
|
|
53
|
+
inputs: z.record(z.string(), JsonSchemaValue).optional(),
|
|
54
|
+
outputs: z.record(z.string(), JsonSchemaValue).optional(),
|
|
55
|
+
/** 参数位约束:宿主据此渲染参数表单(插件零 UI 代码即有参数面板) */
|
|
56
|
+
paramsSchema: JsonSchemaValue.optional(),
|
|
57
|
+
/** 能力依赖:机器未装/未授则 `mbws.caps.*` 命名空间不存在 */
|
|
58
|
+
requiresCapabilities: z.array(z.string().regex(CAPABILITY_RE)).default([]),
|
|
59
|
+
/** 权限逐条授予:consent 列表与 CSP 白名单的推导源 */
|
|
60
|
+
permissions: z.array(z.string().regex(PERMISSION_RE)).default([]),
|
|
61
|
+
/** interactive-only 不进入批量/自动驱动 */
|
|
62
|
+
automation: z.enum(["batchable", "interactive-only"]),
|
|
63
|
+
/** 产物组件的 html 相对路径,缺省 `panel.html` / `viewer.html` */
|
|
64
|
+
components: z
|
|
65
|
+
.object({
|
|
66
|
+
panel: z.string().optional(),
|
|
67
|
+
viewer: z.string().optional(),
|
|
68
|
+
})
|
|
69
|
+
.optional(),
|
|
70
|
+
/** build 写入的 SDK 版本(版本闸门用),手写无效——市场发布时以构建器写入为准 */
|
|
71
|
+
sdk: z.string().optional(),
|
|
72
|
+
meta: z.object({
|
|
73
|
+
title: z.string().min(1),
|
|
74
|
+
description: z.string().min(1),
|
|
75
|
+
icon: z.string().optional(),
|
|
76
|
+
vendor: z.string().optional(),
|
|
77
|
+
screenshots: z.array(z.string()).optional(),
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
/** 校验 manifest:宽容入口(任意 unknown),失败返回逐字段错误清单而不抛异常。 */
|
|
81
|
+
export function validateManifest(input) {
|
|
82
|
+
const parsed = ManifestSchema.safeParse(input);
|
|
83
|
+
if (parsed.success) {
|
|
84
|
+
return { ok: true, manifest: parsed.data };
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
errors: parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mbws 协议 v1 消息族——设计稿 §6.6 的代码定稿。
|
|
3
|
+
*
|
|
4
|
+
* 统一 envelope:`{ v: 1, type, ...payload }`。`v` 是协议版本,每条消息必带、
|
|
5
|
+
* 与 PROTOCOL_VERSION 不符的消息按协议违规直接拒绝(不静默兼容)。
|
|
6
|
+
*
|
|
7
|
+
* 方向约定(防线在宿主 broker 对每条进入消息独立校验,本模块只是契约形状):
|
|
8
|
+
* - plugin → host:调用(mbws:invoke)、生命周期上报(panel:ready / panel:resize / panel:before-close-reply / mbws:init-ack)
|
|
9
|
+
* - host → plugin:握手(mbws:init)、调用结果(mbws:resolve / mbws:reject)、事件(mbws:event)、
|
|
10
|
+
* 生命周期询问(panel:before-close)
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { type MbwsErrorCode } from "./errors.js";
|
|
14
|
+
/**
|
|
15
|
+
* 调用命名空间白名单。data/runtime/storage/ui 是协议固定面;
|
|
16
|
+
* `caps.*` 由已装且已授予的能力包动态注册(如 `caps.video`),协议面不硬编码能力包 API。
|
|
17
|
+
*/
|
|
18
|
+
export declare const MBWS_NAMESPACES: readonly ["data", "runtime", "storage", "ui"];
|
|
19
|
+
/** 宿主 → 插件事件种类(设计稿 §6.6:progress / log / cancel / theme) */
|
|
20
|
+
export declare const MBWS_EVENT_KINDS: readonly ["progress", "log", "cancel", "theme"];
|
|
21
|
+
export declare const MbwsMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
22
|
+
v: z.ZodLiteral<1>;
|
|
23
|
+
type: z.ZodLiteral<"mbws:invoke">;
|
|
24
|
+
callId: z.ZodString;
|
|
25
|
+
ns: z.ZodString;
|
|
26
|
+
method: z.ZodString;
|
|
27
|
+
args: z.ZodOptional<z.ZodUnknown>;
|
|
28
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
29
|
+
v: z.ZodLiteral<1>;
|
|
30
|
+
type: z.ZodLiteral<"mbws:init">;
|
|
31
|
+
protocolVersion: z.ZodLiteral<1>;
|
|
32
|
+
grants: z.ZodArray<z.ZodString>;
|
|
33
|
+
theme: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
34
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
35
|
+
v: z.ZodLiteral<1>;
|
|
36
|
+
type: z.ZodLiteral<"mbws:init-ack">;
|
|
37
|
+
sdkVersion: z.ZodString;
|
|
38
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
39
|
+
v: z.ZodLiteral<1>;
|
|
40
|
+
type: z.ZodLiteral<"mbws:resolve">;
|
|
41
|
+
callId: z.ZodString;
|
|
42
|
+
value: z.ZodOptional<z.ZodUnknown>;
|
|
43
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
44
|
+
v: z.ZodLiteral<1>;
|
|
45
|
+
type: z.ZodLiteral<"mbws:reject">;
|
|
46
|
+
callId: z.ZodString;
|
|
47
|
+
error: z.ZodObject<{
|
|
48
|
+
code: z.ZodEnum<{
|
|
49
|
+
readonly E_INVALID_ARGS: "E_INVALID_ARGS";
|
|
50
|
+
readonly E_UNKNOWN_METHOD: "E_UNKNOWN_METHOD";
|
|
51
|
+
readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
|
|
52
|
+
readonly E_QUOTA_EXCEEDED: "E_QUOTA_EXCEEDED";
|
|
53
|
+
readonly E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED";
|
|
54
|
+
readonly E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE";
|
|
55
|
+
readonly E_TIMEOUT: "E_TIMEOUT";
|
|
56
|
+
readonly E_CANCELLED: "E_CANCELLED";
|
|
57
|
+
readonly E_PROTOCOL_VIOLATION: "E_PROTOCOL_VIOLATION";
|
|
58
|
+
}>;
|
|
59
|
+
message: z.ZodOptional<z.ZodString>;
|
|
60
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
63
|
+
v: z.ZodLiteral<1>;
|
|
64
|
+
type: z.ZodLiteral<"mbws:event">;
|
|
65
|
+
event: z.ZodEnum<{
|
|
66
|
+
progress: "progress";
|
|
67
|
+
log: "log";
|
|
68
|
+
cancel: "cancel";
|
|
69
|
+
theme: "theme";
|
|
70
|
+
}>;
|
|
71
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
72
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
73
|
+
v: z.ZodLiteral<1>;
|
|
74
|
+
type: z.ZodLiteral<"panel:ready">;
|
|
75
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
76
|
+
v: z.ZodLiteral<1>;
|
|
77
|
+
type: z.ZodLiteral<"panel:resize">;
|
|
78
|
+
height: z.ZodNumber;
|
|
79
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
80
|
+
v: z.ZodLiteral<1>;
|
|
81
|
+
type: z.ZodLiteral<"panel:before-close">;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
v: z.ZodLiteral<1>;
|
|
84
|
+
type: z.ZodLiteral<"panel:before-close-reply">;
|
|
85
|
+
dirty: z.ZodBoolean;
|
|
86
|
+
}, z.core.$strip>], "type">;
|
|
87
|
+
export type MbwsMessage = z.output<typeof MbwsMessageSchema>;
|
|
88
|
+
/** 消息方向表:契约形状层即可判定,broker 在此之上再做权限/配额校验 */
|
|
89
|
+
export declare const MESSAGE_DIRECTION: {
|
|
90
|
+
readonly "mbws:invoke": "plugin-to-host";
|
|
91
|
+
readonly "mbws:init": "host-to-plugin";
|
|
92
|
+
readonly "mbws:init-ack": "plugin-to-host";
|
|
93
|
+
readonly "mbws:resolve": "host-to-plugin";
|
|
94
|
+
readonly "mbws:reject": "host-to-plugin";
|
|
95
|
+
readonly "mbws:event": "host-to-plugin";
|
|
96
|
+
readonly "panel:ready": "plugin-to-host";
|
|
97
|
+
readonly "panel:resize": "plugin-to-host";
|
|
98
|
+
readonly "panel:before-close": "host-to-plugin";
|
|
99
|
+
readonly "panel:before-close-reply": "plugin-to-host";
|
|
100
|
+
};
|
|
101
|
+
export type MessageDirection = (typeof MESSAGE_DIRECTION)[keyof typeof MESSAGE_DIRECTION];
|
|
102
|
+
export declare function isPluginToHost(message: MbwsMessage): boolean;
|
|
103
|
+
export declare function isHostToPlugin(message: MbwsMessage): boolean;
|
|
104
|
+
/** 各 variant 守卫(窄化用,形状已由 discriminatedUnion 保证 type 判别) */
|
|
105
|
+
export declare function isMbwsInvoke(message: MbwsMessage): message is Extract<MbwsMessage, {
|
|
106
|
+
type: "mbws:invoke";
|
|
107
|
+
}>;
|
|
108
|
+
export declare function isMbwsResolve(message: MbwsMessage): message is Extract<MbwsMessage, {
|
|
109
|
+
type: "mbws:resolve";
|
|
110
|
+
}>;
|
|
111
|
+
export declare function isMbwsReject(message: MbwsMessage): message is Extract<MbwsMessage, {
|
|
112
|
+
type: "mbws:reject";
|
|
113
|
+
}>;
|
|
114
|
+
export declare function isMbwsEvent(message: MbwsMessage): message is Extract<MbwsMessage, {
|
|
115
|
+
type: "mbws:event";
|
|
116
|
+
}>;
|
|
117
|
+
/** reject 错误载荷(resolve 失败路径的规范形状) */
|
|
118
|
+
export type MbwsErrorPayload = {
|
|
119
|
+
code: MbwsErrorCode;
|
|
120
|
+
message?: string;
|
|
121
|
+
data?: unknown;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* 宽容解析:任意 unknown → 合法消息或 null。
|
|
125
|
+
* 线上收到的 postMessage 数据可能是任何东西,解析失败由调用方决定处置(记审计/静默丢弃)。
|
|
126
|
+
*/
|
|
127
|
+
export declare function parseMbwsMessage(input: unknown): MbwsMessage | null;
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mbws 协议 v1 消息族——设计稿 §6.6 的代码定稿。
|
|
3
|
+
*
|
|
4
|
+
* 统一 envelope:`{ v: 1, type, ...payload }`。`v` 是协议版本,每条消息必带、
|
|
5
|
+
* 与 PROTOCOL_VERSION 不符的消息按协议违规直接拒绝(不静默兼容)。
|
|
6
|
+
*
|
|
7
|
+
* 方向约定(防线在宿主 broker 对每条进入消息独立校验,本模块只是契约形状):
|
|
8
|
+
* - plugin → host:调用(mbws:invoke)、生命周期上报(panel:ready / panel:resize / panel:before-close-reply / mbws:init-ack)
|
|
9
|
+
* - host → plugin:握手(mbws:init)、调用结果(mbws:resolve / mbws:reject)、事件(mbws:event)、
|
|
10
|
+
* 生命周期询问(panel:before-close)
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { MBWS_ERROR_CODES } from "./errors.js";
|
|
14
|
+
import { PROTOCOL_VERSION } from "./version.js";
|
|
15
|
+
/**
|
|
16
|
+
* 调用命名空间白名单。data/runtime/storage/ui 是协议固定面;
|
|
17
|
+
* `caps.*` 由已装且已授予的能力包动态注册(如 `caps.video`),协议面不硬编码能力包 API。
|
|
18
|
+
*/
|
|
19
|
+
export const MBWS_NAMESPACES = ["data", "runtime", "storage", "ui"];
|
|
20
|
+
const NS_RE = /^(data|runtime|storage|ui|caps(\.[a-z0-9-]+)?)$/;
|
|
21
|
+
const nsField = z.string().regex(NS_RE);
|
|
22
|
+
/** 宿主 → 插件事件种类(设计稿 §6.6:progress / log / cancel / theme) */
|
|
23
|
+
export const MBWS_EVENT_KINDS = ["progress", "log", "cancel", "theme"];
|
|
24
|
+
const InvokeMessage = z.object({
|
|
25
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
26
|
+
type: z.literal("mbws:invoke"),
|
|
27
|
+
/** 调用流水号:resolve/reject 按此配对 */
|
|
28
|
+
callId: z.string().min(1),
|
|
29
|
+
ns: nsField,
|
|
30
|
+
method: z.string().min(1),
|
|
31
|
+
args: z.unknown().optional(),
|
|
32
|
+
});
|
|
33
|
+
const InitMessage = z.object({
|
|
34
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
35
|
+
type: z.literal("mbws:init"),
|
|
36
|
+
/** 宿主侧协议版本(与 v 冗余校验,防中转篡改) */
|
|
37
|
+
protocolVersion: z.literal(PROTOCOL_VERSION),
|
|
38
|
+
/** 本次授予的能力清单:客户端只构造已授予的命名空间(按授权构造) */
|
|
39
|
+
grants: z.array(z.string()),
|
|
40
|
+
/** 主题 token 表(CSS 自定义属性 → 值),插件侧写入 :root 跟随宿主主题 */
|
|
41
|
+
theme: z.record(z.string(), z.string()).optional(),
|
|
42
|
+
});
|
|
43
|
+
const InitAckMessage = z.object({
|
|
44
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
45
|
+
type: z.literal("mbws:init-ack"),
|
|
46
|
+
/** SDK 版本(审计用;与 manifest.sdk 交叉核对) */
|
|
47
|
+
sdkVersion: z.string().min(1),
|
|
48
|
+
});
|
|
49
|
+
const ResolveMessage = z.object({
|
|
50
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
51
|
+
type: z.literal("mbws:resolve"),
|
|
52
|
+
callId: z.string().min(1),
|
|
53
|
+
value: z.unknown().optional(),
|
|
54
|
+
});
|
|
55
|
+
const RejectMessage = z.object({
|
|
56
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
57
|
+
type: z.literal("mbws:reject"),
|
|
58
|
+
callId: z.string().min(1),
|
|
59
|
+
error: z.object({
|
|
60
|
+
code: z.enum(MBWS_ERROR_CODES),
|
|
61
|
+
message: z.string().optional(),
|
|
62
|
+
data: z.unknown().optional(),
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
const EventMessage = z.object({
|
|
66
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
67
|
+
type: z.literal("mbws:event"),
|
|
68
|
+
event: z.enum(MBWS_EVENT_KINDS),
|
|
69
|
+
payload: z.unknown().optional(),
|
|
70
|
+
});
|
|
71
|
+
const PanelReadyMessage = z.object({
|
|
72
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
73
|
+
type: z.literal("panel:ready"),
|
|
74
|
+
});
|
|
75
|
+
const PanelResizeMessage = z.object({
|
|
76
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
77
|
+
type: z.literal("panel:resize"),
|
|
78
|
+
/** 面板期望高度(px),宿主 clamp(自适应布局) */
|
|
79
|
+
height: z.number().positive(),
|
|
80
|
+
});
|
|
81
|
+
const PanelBeforeCloseMessage = z.object({
|
|
82
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
83
|
+
type: z.literal("panel:before-close"),
|
|
84
|
+
});
|
|
85
|
+
const PanelBeforeCloseReplyMessage = z.object({
|
|
86
|
+
v: z.literal(PROTOCOL_VERSION),
|
|
87
|
+
type: z.literal("panel:before-close-reply"),
|
|
88
|
+
/** true = 有未保存修改,宿主先弹确认再关;不答则直接关 */
|
|
89
|
+
dirty: z.boolean(),
|
|
90
|
+
});
|
|
91
|
+
export const MbwsMessageSchema = z.discriminatedUnion("type", [
|
|
92
|
+
InvokeMessage,
|
|
93
|
+
InitMessage,
|
|
94
|
+
InitAckMessage,
|
|
95
|
+
ResolveMessage,
|
|
96
|
+
RejectMessage,
|
|
97
|
+
EventMessage,
|
|
98
|
+
PanelReadyMessage,
|
|
99
|
+
PanelResizeMessage,
|
|
100
|
+
PanelBeforeCloseMessage,
|
|
101
|
+
PanelBeforeCloseReplyMessage,
|
|
102
|
+
]);
|
|
103
|
+
/** 消息方向表:契约形状层即可判定,broker 在此之上再做权限/配额校验 */
|
|
104
|
+
export const MESSAGE_DIRECTION = {
|
|
105
|
+
"mbws:invoke": "plugin-to-host",
|
|
106
|
+
"mbws:init": "host-to-plugin",
|
|
107
|
+
"mbws:init-ack": "plugin-to-host",
|
|
108
|
+
"mbws:resolve": "host-to-plugin",
|
|
109
|
+
"mbws:reject": "host-to-plugin",
|
|
110
|
+
"mbws:event": "host-to-plugin",
|
|
111
|
+
"panel:ready": "plugin-to-host",
|
|
112
|
+
"panel:resize": "plugin-to-host",
|
|
113
|
+
"panel:before-close": "host-to-plugin",
|
|
114
|
+
"panel:before-close-reply": "plugin-to-host",
|
|
115
|
+
};
|
|
116
|
+
export function isPluginToHost(message) {
|
|
117
|
+
return MESSAGE_DIRECTION[message.type] === "plugin-to-host";
|
|
118
|
+
}
|
|
119
|
+
export function isHostToPlugin(message) {
|
|
120
|
+
return MESSAGE_DIRECTION[message.type] === "host-to-plugin";
|
|
121
|
+
}
|
|
122
|
+
/** 各 variant 守卫(窄化用,形状已由 discriminatedUnion 保证 type 判别) */
|
|
123
|
+
export function isMbwsInvoke(message) {
|
|
124
|
+
return message.type === "mbws:invoke";
|
|
125
|
+
}
|
|
126
|
+
export function isMbwsResolve(message) {
|
|
127
|
+
return message.type === "mbws:resolve";
|
|
128
|
+
}
|
|
129
|
+
export function isMbwsReject(message) {
|
|
130
|
+
return message.type === "mbws:reject";
|
|
131
|
+
}
|
|
132
|
+
export function isMbwsEvent(message) {
|
|
133
|
+
return message.type === "mbws:event";
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 宽容解析:任意 unknown → 合法消息或 null。
|
|
137
|
+
* 线上收到的 postMessage 数据可能是任何东西,解析失败由调用方决定处置(记审计/静默丢弃)。
|
|
138
|
+
*/
|
|
139
|
+
export function parseMbwsMessage(input) {
|
|
140
|
+
const parsed = MbwsMessageSchema.safeParse(input);
|
|
141
|
+
return parsed.success ? parsed.data : null;
|
|
142
|
+
}
|
package/dist/uuid.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uuid 生成(RFC 4122 v4 格式)。
|
|
3
|
+
*
|
|
4
|
+
* 统一走 `crypto.getRandomValues`,**不用 `crypto.randomUUID`**——后者仅安全上下文
|
|
5
|
+
* 可用(插件面板经 http 的 registry 代理装载即缺失,dev 环境实测踩坑),前者任何
|
|
6
|
+
* 上下文都有。SDK 内需要 uuid 的一律从这里拿,禁止再手写 `crypto.randomUUID`。
|
|
7
|
+
* 实现与 @mbws/components 的 lib/uuid.ts 同款(SDK 零依赖独立发包,不能引包)。
|
|
8
|
+
*/
|
|
9
|
+
/** 生成 RFC 4122 v4 格式 uuid(xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)。 */
|
|
10
|
+
export declare function uuid(): string;
|
package/dist/uuid.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uuid 生成(RFC 4122 v4 格式)。
|
|
3
|
+
*
|
|
4
|
+
* 统一走 `crypto.getRandomValues`,**不用 `crypto.randomUUID`**——后者仅安全上下文
|
|
5
|
+
* 可用(插件面板经 http 的 registry 代理装载即缺失,dev 环境实测踩坑),前者任何
|
|
6
|
+
* 上下文都有。SDK 内需要 uuid 的一律从这里拿,禁止再手写 `crypto.randomUUID`。
|
|
7
|
+
* 实现与 @mbws/components 的 lib/uuid.ts 同款(SDK 零依赖独立发包,不能引包)。
|
|
8
|
+
*/
|
|
9
|
+
/** 生成 RFC 4122 v4 格式 uuid(xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)。 */
|
|
10
|
+
export function uuid() {
|
|
11
|
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
12
|
+
// version 4 + RFC variant 位固定,其余随机
|
|
13
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
14
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
15
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
16
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 平台版本常量——宿主与 SDK 共享的单一事实源。
|
|
3
|
+
*
|
|
4
|
+
* - ARTIFACT_VERSION:`.mbws-plugin` 产物格式版本(manifest.artifactVersion)。
|
|
5
|
+
* 宿主按此值决定兼容加载策略;升版本 = 产物结构破坏性变更,必须随宿主大版本走。
|
|
6
|
+
* - PROTOCOL_VERSION:mbws 协议(§6.6 消息族)版本。每条消息 envelope 都带 `v` 字段,
|
|
7
|
+
* 与此值不符的消息按协议违规直接拒绝(不静默兼容)。
|
|
8
|
+
*/
|
|
9
|
+
export declare const ARTIFACT_VERSION: 1;
|
|
10
|
+
export declare const PROTOCOL_VERSION: 1;
|
|
11
|
+
/**
|
|
12
|
+
* SDK 自身版本(与 package.json version 保持一致)。
|
|
13
|
+
* init-ack 上报给宿主做审计,与 manifest.sdk(build 写入)交叉核对。
|
|
14
|
+
*/
|
|
15
|
+
export declare const SDK_VERSION = "0.0.1";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 平台版本常量——宿主与 SDK 共享的单一事实源。
|
|
3
|
+
*
|
|
4
|
+
* - ARTIFACT_VERSION:`.mbws-plugin` 产物格式版本(manifest.artifactVersion)。
|
|
5
|
+
* 宿主按此值决定兼容加载策略;升版本 = 产物结构破坏性变更,必须随宿主大版本走。
|
|
6
|
+
* - PROTOCOL_VERSION:mbws 协议(§6.6 消息族)版本。每条消息 envelope 都带 `v` 字段,
|
|
7
|
+
* 与此值不符的消息按协议违规直接拒绝(不静默兼容)。
|
|
8
|
+
*/
|
|
9
|
+
export const ARTIFACT_VERSION = 1;
|
|
10
|
+
export const PROTOCOL_VERSION = 1;
|
|
11
|
+
/**
|
|
12
|
+
* SDK 自身版本(与 package.json version 保持一致)。
|
|
13
|
+
* init-ack 上报给宿主做审计,与 manifest.sdk(build 写入)交叉核对。
|
|
14
|
+
*/
|
|
15
|
+
export const SDK_VERSION = "0.0.1";
|