@mbws/plugin-sdk 0.2.4 → 0.3.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/dist/dev-mock.js CHANGED
@@ -1,6 +1,97 @@
1
1
  import { fetchContract } from "./contract.js";
2
+ /** dev spawn:先试 dev 执行端点(真跑),失败退模拟 */
3
+ async function spawnDevJob(req) {
4
+ const session = { lineCbs: new Set(), waiters: [], settled: false };
5
+ const settle = (exitCode, stderrTail = "") => {
6
+ if (session.settled)
7
+ return;
8
+ session.settled = true;
9
+ session.result = { exitCode, stderrTail };
10
+ for (const w of session.waiters)
11
+ w.resolve(session.result);
12
+ session.waiters = [];
13
+ };
14
+ const emit = (lines) => {
15
+ for (const line of lines)
16
+ for (const cb of session.lineCbs)
17
+ cb(line);
18
+ };
19
+ let response = null;
20
+ try {
21
+ response = await fetch("/__mbws__/dev/exec", {
22
+ method: "POST",
23
+ headers: { "content-type": "application/json" },
24
+ body: JSON.stringify(req),
25
+ });
26
+ }
27
+ catch {
28
+ response = null;
29
+ }
30
+ if (response?.ok && response.body) {
31
+ // NDJSON 事件流:{kind:"lines",lines}|{kind:"exit",exitCode,stderrTail}
32
+ const reader = response.body.getReader();
33
+ const decoder = new TextDecoder();
34
+ let buffer = "";
35
+ const pump = async () => {
36
+ for (;;) {
37
+ const { done, value } = await reader.read();
38
+ if (done)
39
+ break;
40
+ buffer += decoder.decode(value, { stream: true });
41
+ let newlineAt = buffer.indexOf("\n");
42
+ while (newlineAt >= 0) {
43
+ const rawLine = buffer.slice(0, newlineAt);
44
+ buffer = buffer.slice(newlineAt + 1);
45
+ try {
46
+ const event = JSON.parse(rawLine);
47
+ if (event.kind === "lines" && event.lines)
48
+ emit(event.lines);
49
+ else if (event.kind === "exit")
50
+ settle(event.exitCode ?? -1, event.stderrTail ?? "");
51
+ }
52
+ catch {
53
+ // 非 JSON 行忽略
54
+ }
55
+ newlineAt = buffer.indexOf("\n");
56
+ }
57
+ }
58
+ // 流结束仍无 exit(进程被强杀等):按失败收尾
59
+ settle(-1, "dev 执行流意外结束");
60
+ };
61
+ void pump();
62
+ }
63
+ else {
64
+ console.info(`[mbws:dev] spawn(${req.attachment}) 无 dev 执行端点(非 vite dev 或未配本机附件)——模拟执行`);
65
+ setTimeout(() => {
66
+ emit([
67
+ { stream: "stdout", text: `[mbws:dev] simulated ${req.attachment} ${req.args.join(" ")}` },
68
+ ]);
69
+ settle(0);
70
+ }, 100);
71
+ }
72
+ return {
73
+ jobId: `dev-${Date.now()}-${Math.floor(Math.random() * 1e6)}`,
74
+ wait: () => {
75
+ if (session.settled && session.result)
76
+ return Promise.resolve(session.result);
77
+ return new Promise((resolve, reject) => session.waiters.push({ resolve, reject }));
78
+ },
79
+ cancel: async () => {
80
+ console.info("[mbws:dev] cancel(模拟环境无进程可杀)");
81
+ settle(-1, "cancelled");
82
+ },
83
+ onLine: (cb) => {
84
+ session.lineCbs.add(cb);
85
+ return () => session.lineCbs.delete(cb);
86
+ },
87
+ read: async (path) => {
88
+ console.info(`[mbws:dev] readFile(${path}) no-op`);
89
+ return null;
90
+ },
91
+ };
92
+ }
2
93
  /**
3
- * 创建 dev mock 客户端。四个固定命名空间全部构造(dev 无授权语义),
94
+ * 创建 dev mock 客户端。固定命名空间 + caps 全部构造(dev 无授权语义),
4
95
  * panel 生命周期面上报/应答均无宿主可收,no-op 即可。
5
96
  */
6
97
  export function createDevMockMbws() {
@@ -38,6 +129,52 @@ export function createDevMockMbws() {
38
129
  console.info(`[mbws:dev] ui.toast:${message}`);
39
130
  },
40
131
  },
132
+ caps: {
133
+ exec: {
134
+ ensureAttachment: async (name) => {
135
+ console.info(`[mbws:dev] ensureAttachment(${name})——dev 不预下载,spawn 时由 dev 中间件解析(attachments 声明的 devPath / MBWS_DEV_ATTACHMENT_${name.replace(/-/g, "_").toUpperCase()} 本机覆盖,否则按 attachments 声明自动从官方附件库下载缓存)`);
136
+ return { status: "ready", version: "dev", sha256: `dev-${name}` };
137
+ },
138
+ attachmentStatus: async (name) => ({ name, status: "ready" }),
139
+ localize: async (ref) => {
140
+ try {
141
+ const response = await fetch(`/__mbws__/dev/localize?ref=${encodeURIComponent(ref)}`);
142
+ if (response.ok)
143
+ return (await response.json());
144
+ }
145
+ catch {
146
+ // 非 dev server 场景,走兜底
147
+ }
148
+ const basename = ref.split("/").pop() ?? "input";
149
+ return { path: `samples/${basename}`, size: 0 };
150
+ },
151
+ spawn: (req) => spawnDevJob(req),
152
+ registerOutput: async (req) => {
153
+ console.info(`[mbws:dev] registerOutput(${req.filename})——假占位不入库`);
154
+ return { placeholder: `devlocal:${encodeURIComponent(req.filename)}` };
155
+ },
156
+ mediaUrl: async (ref) => {
157
+ try {
158
+ const response = await fetch(`/__mbws__/dev/localize?ref=${encodeURIComponent(ref)}`);
159
+ if (response.ok) {
160
+ const { path } = (await response.json());
161
+ return { url: `/__mbws__/dev/file?path=${encodeURIComponent(path)}` };
162
+ }
163
+ }
164
+ catch {
165
+ // 兜底走 dev:// 假地址
166
+ }
167
+ return { url: `dev://samples/${ref}` };
168
+ },
169
+ onAttachment: (_cb) => () => { },
170
+ },
171
+ uploads: {
172
+ status: async (placeholder) => {
173
+ console.info(`[mbws:dev] uploads.status(${placeholder})`);
174
+ return { status: "registered" };
175
+ },
176
+ },
177
+ },
41
178
  panel: {
42
179
  resize: () => { },
43
180
  onBeforeClose: () => { },
package/dist/errors.d.ts CHANGED
@@ -17,6 +17,10 @@ export declare const MBWS_ERROR_CODES: {
17
17
  readonly E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED";
18
18
  /** 依赖的能力包未安装或版本不满足 */
19
19
  readonly E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE";
20
+ /** 附件下载/校验/解包失败(网络错误、sha256 不符、解包路径穿越等) */
21
+ readonly E_ATTACHMENT_DOWNLOAD_FAILED: "E_ATTACHMENT_DOWNLOAD_FAILED";
22
+ /** 附件子进程非零退出(error.data 带 exitCode / stderrTail) */
23
+ readonly E_JOB_FAILED: "E_JOB_FAILED";
20
24
  /** 调用超时(宿主侧 wall-clock 预算) */
21
25
  readonly E_TIMEOUT: "E_TIMEOUT";
22
26
  /** 被取消(对齐 ffmpeg-cancel 语义,runtime.signal 触发后的在途调用收尾) */
package/dist/errors.js CHANGED
@@ -17,6 +17,10 @@ export const MBWS_ERROR_CODES = {
17
17
  E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED",
18
18
  /** 依赖的能力包未安装或版本不满足 */
19
19
  E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE",
20
+ /** 附件下载/校验/解包失败(网络错误、sha256 不符、解包路径穿越等) */
21
+ E_ATTACHMENT_DOWNLOAD_FAILED: "E_ATTACHMENT_DOWNLOAD_FAILED",
22
+ /** 附件子进程非零退出(error.data 带 exitCode / stderrTail) */
23
+ E_JOB_FAILED: "E_JOB_FAILED",
20
24
  /** 调用超时(宿主侧 wall-clock 预算) */
21
25
  E_TIMEOUT: "E_TIMEOUT",
22
26
  /** 被取消(对齐 ffmpeg-cancel 语义,runtime.signal 触发后的在途调用收尾) */
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * M2:createMbws() 工厂与 dev mock。
6
6
  * 后续里程碑在此包内扩展:CLI dev/build/sign(M4)、fns/DSL(M4)。
7
7
  */
8
+ export * from "./caps.js";
8
9
  export * from "./client.js";
9
10
  export * from "./config.js";
10
11
  export * from "./contract.js";
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * M2:createMbws() 工厂与 dev mock。
6
6
  * 后续里程碑在此包内扩展:CLI dev/build/sign(M4)、fns/DSL(M4)。
7
7
  */
8
+ export * from "./caps.js";
8
9
  export * from "./client.js";
9
10
  export * from "./config.js";
10
11
  export * from "./contract.js";
@@ -20,6 +20,44 @@ import { z } from "zod";
20
20
  type Json = null | boolean | number | string | Json[] | {
21
21
  [key: string]: Json;
22
22
  };
23
+ /**
24
+ * 支持的附件平台(process.platform + os.arch 映射)。
25
+ * linux-x64 留字段供未来,当前投放三桌面平台。
26
+ */
27
+ export declare const ATTACHMENT_PLATFORMS: readonly ["darwin-arm64", "darwin-x64", "win-x64", "linux-x64"];
28
+ export type AttachmentPlatform = (typeof ATTACHMENT_PLATFORMS)[number];
29
+ /** 宿主必配的平台集合(manifest 校验:三桌面平台缺一即拒)。 */
30
+ export declare const REQUIRED_ATTACHMENT_PLATFORMS: AttachmentPlatform[];
31
+ /**
32
+ * 附件声明(完整形态,进 manifest)。开发者侧只填 name/version 引用,
33
+ * platforms hash 由构建期从官方附件库 index 解析填充(单一权威在库)。
34
+ */
35
+ export declare const AttachmentDeclSchema: z.ZodObject<{
36
+ name: z.ZodString;
37
+ version: z.ZodString;
38
+ entry: z.ZodOptional<z.ZodString>;
39
+ platforms: z.ZodRecord<z.ZodString, z.ZodObject<{
40
+ sha256: z.ZodString;
41
+ size: z.ZodNumber;
42
+ archive: z.ZodDefault<z.ZodEnum<{
43
+ "tar.gz": "tar.gz";
44
+ zip: "zip";
45
+ }>>;
46
+ }, z.core.$strip>>;
47
+ }, z.core.$strip>;
48
+ export type AttachmentDecl = z.output<typeof AttachmentDeclSchema>;
49
+ /**
50
+ * 开发者侧的附件引用(mbws.config.ts 可填形态)——platforms 由构建解析填充。
51
+ * devPath 是 dev-only 的本机路径覆盖(线上还没有的新版本附件指到本机开发;
52
+ * 未填/路径不存在时 dev 自动按 name+version 从官方附件库下载缓存),不进产物。
53
+ */
54
+ export declare const AttachmentRefSchema: z.ZodObject<{
55
+ version: z.ZodString;
56
+ name: z.ZodString;
57
+ entry: z.ZodOptional<z.ZodString>;
58
+ devPath: z.ZodOptional<z.ZodString>;
59
+ }, z.core.$strip>;
60
+ export type AttachmentRef = z.output<typeof AttachmentRefSchema>;
23
61
  export declare const ManifestSchema: z.ZodObject<{
24
62
  id: z.ZodString;
25
63
  version: z.ZodString;
@@ -31,7 +69,19 @@ export declare const ManifestSchema: z.ZodObject<{
31
69
  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
70
  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
71
  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>>;
72
+ attachments: z.ZodDefault<z.ZodArray<z.ZodObject<{
73
+ name: z.ZodString;
74
+ version: z.ZodString;
75
+ entry: z.ZodOptional<z.ZodString>;
76
+ platforms: z.ZodRecord<z.ZodString, z.ZodObject<{
77
+ sha256: z.ZodString;
78
+ size: z.ZodNumber;
79
+ archive: z.ZodDefault<z.ZodEnum<{
80
+ "tar.gz": "tar.gz";
81
+ zip: "zip";
82
+ }>>;
83
+ }, z.core.$strip>>;
84
+ }, z.core.$strip>>>;
35
85
  permissions: z.ZodDefault<z.ZodArray<z.ZodString>>;
36
86
  automation: z.ZodEnum<{
37
87
  batchable: "batchable";
package/dist/manifest.js CHANGED
@@ -29,8 +29,55 @@ const JsonSchemaValue = z.union([z.boolean(), z.record(z.string(), jsonValue)]);
29
29
  */
30
30
  const PLUGIN_ID_RE = /^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)*$/;
31
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-]+)+(@.+)?$/;
32
+ /** 附件名:官方附件库唯一键,如 "ffmpeg" / "ffprobe"。 */
33
+ const ATTACHMENT_NAME_RE = /^[a-z][a-z0-9-]{1,63}$/;
34
+ /** 包内可执行入口文件名(无路径分隔,防穿越)。 */
35
+ const ATTACHMENT_ENTRY_RE = /^[^/\\]+$/;
36
+ /**
37
+ * 支持的附件平台(process.platform + os.arch 映射)。
38
+ * linux-x64 留字段供未来,当前投放三桌面平台。
39
+ */
40
+ export const ATTACHMENT_PLATFORMS = ["darwin-arm64", "darwin-x64", "win-x64", "linux-x64"];
41
+ /** 宿主必配的平台集合(manifest 校验:三桌面平台缺一即拒)。 */
42
+ export const REQUIRED_ATTACHMENT_PLATFORMS = [
43
+ "darwin-arm64",
44
+ "darwin-x64",
45
+ "win-x64",
46
+ ];
47
+ /** 附件平台描述:内容寻址键 + 展示/预算信息。 */
48
+ const AttachmentPlatformSchema = z.object({
49
+ /** 压缩包 sha256(hex)——内容寻址键 + 完整性校验,一切以 hash 为准 */
50
+ sha256: z.string().regex(/^[0-9a-f]{64}$/),
51
+ /** 压缩包字节数(consent「约 xx MB」与下载预算) */
52
+ size: z.number().int().positive(),
53
+ archive: z.enum(["tar.gz", "zip"]).default("tar.gz"),
54
+ });
55
+ /**
56
+ * 附件声明(完整形态,进 manifest)。开发者侧只填 name/version 引用,
57
+ * platforms hash 由构建期从官方附件库 index 解析填充(单一权威在库)。
58
+ */
59
+ export const AttachmentDeclSchema = z.object({
60
+ name: z.string().regex(ATTACHMENT_NAME_RE),
61
+ /** 官方附件库索引键;宿主下载校验一切以 sha256 为准 */
62
+ version: z.string().regex(SEMVER_RE),
63
+ /** 包内可执行入口,缺省 = name */
64
+ entry: z.string().regex(ATTACHMENT_ENTRY_RE).optional(),
65
+ // 宽松 record + refine:zod v4 的 z.record(enum) 会强制枚举键全量(linux-x64 误成必填)
66
+ platforms: z
67
+ .record(z.string(), AttachmentPlatformSchema)
68
+ .refine((p) => Object.keys(p).every((k) => ATTACHMENT_PLATFORMS.includes(k)), { message: `未知平台键(合法:${ATTACHMENT_PLATFORMS.join(" / ")})` })
69
+ .refine((p) => REQUIRED_ATTACHMENT_PLATFORMS.every((k) => p[k] != null), {
70
+ message: `附件平台必填:${REQUIRED_ATTACHMENT_PLATFORMS.join(" / ")}`,
71
+ }),
72
+ });
73
+ /**
74
+ * 开发者侧的附件引用(mbws.config.ts 可填形态)——platforms 由构建解析填充。
75
+ * devPath 是 dev-only 的本机路径覆盖(线上还没有的新版本附件指到本机开发;
76
+ * 未填/路径不存在时 dev 自动按 name+version 从官方附件库下载缓存),不进产物。
77
+ */
78
+ export const AttachmentRefSchema = AttachmentDeclSchema.omit({ platforms: true }).extend({
79
+ devPath: z.string().optional(),
80
+ });
34
81
  /**
35
82
  * 权限声明,两种语法(CSP connect-src 与权限预览文案的推导输入,设计稿 §6.5):
36
83
  * - `ai.<purpose>`:走项目 AI 中心的调用(如 `ai.ocr`)
@@ -54,8 +101,12 @@ export const ManifestSchema = z.object({
54
101
  outputs: z.record(z.string(), JsonSchemaValue).optional(),
55
102
  /** 参数位约束:宿主据此渲染参数表单(插件零 UI 代码即有参数面板) */
56
103
  paramsSchema: JsonSchemaValue.optional(),
57
- /** 能力依赖:机器未装/未授则 `mbws.caps.*` 命名空间不存在 */
58
- requiresCapabilities: z.array(z.string().regex(CAPABILITY_RE)).default([]),
104
+ /**
105
+ * 附件声明(二进制外挂,纯桌面端):宿主懒加载(首次使用按需下载、内容寻址共享),
106
+ * 插件经 caps.* 获得 shell 级执行权。有声明 → 桌面 only,web 宿主灰显。
107
+ * 取代旧 requiresCapabilities(typed 能力包模型已裁撤,见 docs/plan §7.6 偏离记录)。
108
+ */
109
+ attachments: z.array(AttachmentDeclSchema).max(8).default([]),
59
110
  /** 权限逐条授予:consent 列表与 CSP 白名单的推导源 */
60
111
  permissions: z.array(z.string().regex(PERMISSION_RE)).default([]),
61
112
  /** interactive-only 不进入批量/自动驱动 */
@@ -16,8 +16,11 @@ import { type MbwsErrorCode } from "./errors.js";
16
16
  * `caps.*` 由已装且已授予的能力包动态注册(如 `caps.video`),协议面不硬编码能力包 API。
17
17
  */
18
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"];
19
+ /**
20
+ * 宿主 插件事件种类(设计稿 §6.6:progress / log / cancel / theme + caps 长任务两族)。
21
+ * `job`:附件子进程行流/退出;`attachment`:附件下载进度/状态。payload 形状见 caps.ts。
22
+ */
23
+ export declare const MBWS_EVENT_KINDS: readonly ["progress", "log", "cancel", "theme", "job", "attachment"];
21
24
  export declare const MbwsMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
22
25
  v: z.ZodLiteral<1>;
23
26
  type: z.ZodLiteral<"mbws:invoke">;
@@ -52,6 +55,8 @@ export declare const MbwsMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
52
55
  readonly E_QUOTA_EXCEEDED: "E_QUOTA_EXCEEDED";
53
56
  readonly E_WRITE_GATE_REJECTED: "E_WRITE_GATE_REJECTED";
54
57
  readonly E_CAPABILITY_UNAVAILABLE: "E_CAPABILITY_UNAVAILABLE";
58
+ readonly E_ATTACHMENT_DOWNLOAD_FAILED: "E_ATTACHMENT_DOWNLOAD_FAILED";
59
+ readonly E_JOB_FAILED: "E_JOB_FAILED";
55
60
  readonly E_TIMEOUT: "E_TIMEOUT";
56
61
  readonly E_CANCELLED: "E_CANCELLED";
57
62
  readonly E_PROTOCOL_VIOLATION: "E_PROTOCOL_VIOLATION";
@@ -63,10 +68,12 @@ export declare const MbwsMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
63
68
  v: z.ZodLiteral<1>;
64
69
  type: z.ZodLiteral<"mbws:event">;
65
70
  event: z.ZodEnum<{
71
+ cancel: "cancel";
66
72
  progress: "progress";
67
73
  log: "log";
68
- cancel: "cancel";
69
74
  theme: "theme";
75
+ job: "job";
76
+ attachment: "attachment";
70
77
  }>;
71
78
  payload: z.ZodOptional<z.ZodUnknown>;
72
79
  }, z.core.$strip>, z.ZodObject<{
package/dist/protocol.js CHANGED
@@ -19,8 +19,18 @@ import { PROTOCOL_VERSION } from "./version.js";
19
19
  export const MBWS_NAMESPACES = ["data", "runtime", "storage", "ui"];
20
20
  const NS_RE = /^(data|runtime|storage|ui|caps(\.[a-z0-9-]+)?)$/;
21
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"];
22
+ /**
23
+ * 宿主 插件事件种类(设计稿 §6.6:progress / log / cancel / theme + caps 长任务两族)。
24
+ * `job`:附件子进程行流/退出;`attachment`:附件下载进度/状态。payload 形状见 caps.ts。
25
+ */
26
+ export const MBWS_EVENT_KINDS = [
27
+ "progress",
28
+ "log",
29
+ "cancel",
30
+ "theme",
31
+ "job",
32
+ "attachment",
33
+ ];
24
34
  const InvokeMessage = z.object({
25
35
  v: z.literal(PROTOCOL_VERSION),
26
36
  type: z.literal("mbws:invoke"),
package/dist/version.d.ts CHANGED
@@ -12,4 +12,4 @@ export declare const PROTOCOL_VERSION: 1;
12
12
  * SDK 自身版本(与 package.json version 保持一致)。
13
13
  * init-ack 上报给宿主做审计,与 manifest.sdk(build 写入)交叉核对。
14
14
  */
15
- export declare const SDK_VERSION = "0.2.4";
15
+ export declare const SDK_VERSION = "0.3.0";
package/dist/version.js CHANGED
@@ -12,4 +12,4 @@ export const PROTOCOL_VERSION = 1;
12
12
  * SDK 自身版本(与 package.json version 保持一致)。
13
13
  * init-ack 上报给宿主做审计,与 manifest.sdk(build 写入)交叉核对。
14
14
  */
15
- export const SDK_VERSION = "0.2.4";
15
+ export const SDK_VERSION = "0.3.0";
package/dist/vite.d.ts CHANGED
@@ -13,3 +13,14 @@ export interface MbwsVitePluginOptions {
13
13
  * 转发到真实后端——插件 dev 端口不在后端 CORS 白名单的问题由此消解。
14
14
  */
15
15
  export declare function mbwsVitePlugin(opts: MbwsVitePluginOptions): Plugin;
16
+ /** /__mbws__/<rest> → <apiBase>/<rest>:方法/头透传,响应状态码/content-type/body 透传 */
17
+ /**
18
+ * 当前进程 → 附件平台键(与 manifest 的 ATTACHMENT_PLATFORMS 同词表)。
19
+ */
20
+ export declare function currentAttachmentPlatform(): string;
21
+ /**
22
+ * dev 用附件本地覆盖:env MBWS_DEV_ATTACHMENT_<NAME>(名字大写、- → _)优先,
23
+ * 其次 attachments 声明里的 devPath(线上还没有的新版本指本机路径)。
24
+ * 未配置/路径不存在返回 null(走官方附件库自动下载)。
25
+ */
26
+ export declare function resolveDevAttachmentOverride(config: MbwsUserConfig, name: string): string | null;