@mbws/plugin-sdk 0.3.0 → 0.3.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/dist/config.d.ts +1 -0
- package/dist/manifest.d.ts +4 -2
- package/dist/manifest.js +4 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/vite.js +77 -27
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -94,6 +94,7 @@ declare const UserConfigSchema: z.ZodObject<{
|
|
|
94
94
|
name: z.ZodString;
|
|
95
95
|
entry: z.ZodOptional<z.ZodString>;
|
|
96
96
|
devPath: z.ZodOptional<z.ZodString>;
|
|
97
|
+
url: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
97
98
|
}, z.core.$strip>>>;
|
|
98
99
|
devKey: z.ZodOptional<z.ZodString>;
|
|
99
100
|
apiBaseUrl: z.ZodOptional<z.ZodString>;
|
package/dist/manifest.d.ts
CHANGED
|
@@ -48,14 +48,16 @@ export declare const AttachmentDeclSchema: z.ZodObject<{
|
|
|
48
48
|
export type AttachmentDecl = z.output<typeof AttachmentDeclSchema>;
|
|
49
49
|
/**
|
|
50
50
|
* 开发者侧的附件引用(mbws.config.ts 可填形态)——platforms 由构建解析填充。
|
|
51
|
-
* devPath 是 dev-only
|
|
52
|
-
*
|
|
51
|
+
* devPath 是 dev-only 的本机路径覆盖(线上还没有的新版本附件指到本机开发),不进产物。
|
|
52
|
+
* url 是 dev 下载直链(暂由开发者提供官方地址;自建附件中心上线后改走 name+version
|
|
53
|
+
* 解析):string = 全平台同地址,record = 按平台键(darwin-arm64 等),不进产物。
|
|
53
54
|
*/
|
|
54
55
|
export declare const AttachmentRefSchema: z.ZodObject<{
|
|
55
56
|
version: z.ZodString;
|
|
56
57
|
name: z.ZodString;
|
|
57
58
|
entry: z.ZodOptional<z.ZodString>;
|
|
58
59
|
devPath: z.ZodOptional<z.ZodString>;
|
|
60
|
+
url: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
59
61
|
}, z.core.$strip>;
|
|
60
62
|
export type AttachmentRef = z.output<typeof AttachmentRefSchema>;
|
|
61
63
|
export declare const ManifestSchema: z.ZodObject<{
|
package/dist/manifest.js
CHANGED
|
@@ -72,11 +72,13 @@ export const AttachmentDeclSchema = z.object({
|
|
|
72
72
|
});
|
|
73
73
|
/**
|
|
74
74
|
* 开发者侧的附件引用(mbws.config.ts 可填形态)——platforms 由构建解析填充。
|
|
75
|
-
* devPath 是 dev-only
|
|
76
|
-
*
|
|
75
|
+
* devPath 是 dev-only 的本机路径覆盖(线上还没有的新版本附件指到本机开发),不进产物。
|
|
76
|
+
* url 是 dev 下载直链(暂由开发者提供官方地址;自建附件中心上线后改走 name+version
|
|
77
|
+
* 解析):string = 全平台同地址,record = 按平台键(darwin-arm64 等),不进产物。
|
|
77
78
|
*/
|
|
78
79
|
export const AttachmentRefSchema = AttachmentDeclSchema.omit({ platforms: true }).extend({
|
|
79
80
|
devPath: z.string().optional(),
|
|
81
|
+
url: z.union([z.string(), z.record(z.string(), z.string())]).optional(),
|
|
80
82
|
});
|
|
81
83
|
/**
|
|
82
84
|
* 权限声明,两种语法(CSP connect-src 与权限预览文案的推导输入,设计稿 §6.5):
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/vite.js
CHANGED
|
@@ -18,6 +18,8 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
18
18
|
import crypto from "node:crypto";
|
|
19
19
|
import fs from "node:fs";
|
|
20
20
|
import path from "node:path";
|
|
21
|
+
import { pipeline } from "node:stream/promises";
|
|
22
|
+
import zlib from "node:zlib";
|
|
21
23
|
import { buildManifest, resolveAttachmentRefs } from "./config.js";
|
|
22
24
|
import { generateContractTypes } from "./schema-types.js";
|
|
23
25
|
// 契约类型生成经本子路径暴露(Node 端工具链用;依赖 prettier,不进根入口)
|
|
@@ -245,10 +247,41 @@ const inflightDevAttachments = new Map();
|
|
|
245
247
|
*/
|
|
246
248
|
const devAttachmentResolves = new Map();
|
|
247
249
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
* 流式下载到文件:边下边算 sha256(不整包进内存),每 5MB 报一次进度行。
|
|
251
|
+
* sizeHint 已知(库 resolve 下发)报「x / y MB」,直链未知报「x MB」。返回 sha256。
|
|
252
|
+
*/
|
|
253
|
+
async function downloadToFile(url, dest, log, sizeHint) {
|
|
254
|
+
const response = await fetch(url);
|
|
255
|
+
if (!response.ok || !response.body)
|
|
256
|
+
throw new Error(`下载 HTTP ${response.status}`);
|
|
257
|
+
const hash = crypto.createHash("sha256");
|
|
258
|
+
const out = fs.createWriteStream(dest);
|
|
259
|
+
let received = 0;
|
|
260
|
+
let lastReported = 0;
|
|
261
|
+
// Node fetch 的 body 是 async iterable
|
|
262
|
+
for await (const chunk of response.body) {
|
|
263
|
+
const bytes = Buffer.from(chunk);
|
|
264
|
+
hash.update(bytes);
|
|
265
|
+
out.write(bytes);
|
|
266
|
+
received += bytes.byteLength;
|
|
267
|
+
if (received - lastReported >= 5 * 1e6) {
|
|
268
|
+
lastReported = received;
|
|
269
|
+
log(sizeHint != null
|
|
270
|
+
? `[mbws:dev] 下载中 ${Math.round(received / 1e6)} / ${Math.round(sizeHint / 1e6)} MB`
|
|
271
|
+
: `[mbws:dev] 下载中 ${Math.round(received / 1e6)} MB`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
await new Promise((resolve, reject) => out.end((error) => (error ? reject(error) : resolve())));
|
|
275
|
+
return hash.digest("hex");
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* 确保附件在本地就绪(两条来源,优先级:url 直链 > 官方附件库 resolve):
|
|
279
|
+
* - url 直链(暂由开发者提供官方地址):无 sha256,缓存目录不带 hash 层
|
|
280
|
+
* (`.mbws/attachments/<name>@<version>/`,同 version 重传视为修正);
|
|
281
|
+
* 按后缀分派 tar.gz/zip 解包、.gz 单文件解压、其余当裸二进制。
|
|
282
|
+
* - 官方附件库:resolve 端点拿 url/sha256/size,内容寻址缓存
|
|
283
|
+
* `.mbws/attachments/<name>@<version>/<sha256>/`,下载后 sha256 校验 + tar -xf。
|
|
284
|
+
* 附件未声明 / 无 url 且库未登记返回 null(调用方回 501);下载/校验/解包失败抛错。
|
|
252
285
|
* log 收下载进度行(调用方转 NDJSON 事件流)。
|
|
253
286
|
*/
|
|
254
287
|
async function ensureLibraryAttachment(config, root, name, log) {
|
|
@@ -261,6 +294,44 @@ async function ensureLibraryAttachment(config, root, name, log) {
|
|
|
261
294
|
if (!ref)
|
|
262
295
|
return null;
|
|
263
296
|
const platform = currentAttachmentPlatform();
|
|
297
|
+
// win 平台包内入口带 .exe 后缀(publish 脚本布局),显式 entry 原样用
|
|
298
|
+
const entry = ref.entry ?? `${name}${platform.startsWith("win") ? ".exe" : ""}`;
|
|
299
|
+
// —— url 直链分支(开发者提供的官方地址)——
|
|
300
|
+
const directUrl = typeof ref.url === "string" ? ref.url : ref.url?.[platform];
|
|
301
|
+
if (directUrl) {
|
|
302
|
+
const dir = path.join(root, DEV_ATTACHMENT_CACHE, `${name}@${ref.version}`);
|
|
303
|
+
const entryPath = path.join(dir, entry);
|
|
304
|
+
if (fs.existsSync(entryPath))
|
|
305
|
+
return entryPath;
|
|
306
|
+
log(`[mbws:dev] 下载附件 ${name}@${ref.version}(${platform} 直链,无 hash 校验)`);
|
|
307
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
308
|
+
const tmpPath = path.join(dir, "download.tmp");
|
|
309
|
+
try {
|
|
310
|
+
await downloadToFile(directUrl, tmpPath, log);
|
|
311
|
+
const lower = directUrl.toLowerCase();
|
|
312
|
+
if (/\.(tar\.gz|tgz|zip)$/.test(lower)) {
|
|
313
|
+
const extracted = spawnSync("tar", ["-xf", tmpPath, "-C", dir]);
|
|
314
|
+
if (extracted.status !== 0) {
|
|
315
|
+
throw new Error(`解包失败:${extracted.stderr?.toString().trim() || `tar exit ${extracted.status}`}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else if (/\.gz$/.test(lower)) {
|
|
319
|
+
await pipeline(fs.createReadStream(tmpPath), zlib.createGunzip(), fs.createWriteStream(entryPath));
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
fs.copyFileSync(tmpPath, entryPath);
|
|
323
|
+
}
|
|
324
|
+
if (!fs.existsSync(entryPath))
|
|
325
|
+
throw new Error(`解包后未见入口 ${entry}`);
|
|
326
|
+
fs.chmodSync(entryPath, 0o755);
|
|
327
|
+
log(`[mbws:dev] 附件 ${name}@${ref.version} 就绪(已缓存,后续零下载)`);
|
|
328
|
+
return entryPath;
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
fs.rmSync(tmpPath, { force: true });
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// —— 官方附件库分支 ——
|
|
264
335
|
const resolveKey = `${name}@${ref.version}`;
|
|
265
336
|
let resolved = devAttachmentResolves.get(resolveKey);
|
|
266
337
|
if (!resolved) {
|
|
@@ -278,8 +349,6 @@ async function ensureLibraryAttachment(config, root, name, log) {
|
|
|
278
349
|
return null;
|
|
279
350
|
}
|
|
280
351
|
}
|
|
281
|
-
// win 平台包内入口带 .exe 后缀(publish 脚本布局),显式 entry 原样用
|
|
282
|
-
const entry = ref.entry ?? `${name}${platform.startsWith("win") ? ".exe" : ""}`;
|
|
283
352
|
const dir = path.join(root, DEV_ATTACHMENT_CACHE, `${name}@${ref.version}`, resolved.sha256);
|
|
284
353
|
const entryPath = path.join(dir, entry);
|
|
285
354
|
if (fs.existsSync(entryPath))
|
|
@@ -288,26 +357,7 @@ async function ensureLibraryAttachment(config, root, name, log) {
|
|
|
288
357
|
fs.mkdirSync(dir, { recursive: true });
|
|
289
358
|
const tmpPath = path.join(dir, `download.${resolved.archive}`);
|
|
290
359
|
try {
|
|
291
|
-
const
|
|
292
|
-
if (!response.ok || !response.body)
|
|
293
|
-
throw new Error(`下载 HTTP ${response.status}`);
|
|
294
|
-
const hash = crypto.createHash("sha256");
|
|
295
|
-
const out = fs.createWriteStream(tmpPath);
|
|
296
|
-
let received = 0;
|
|
297
|
-
let lastReported = 0;
|
|
298
|
-
// Node fetch 的 body 是 async iterable:流式落盘 + 边下边算 hash(不整包进内存)
|
|
299
|
-
for await (const chunk of response.body) {
|
|
300
|
-
const bytes = Buffer.from(chunk);
|
|
301
|
-
hash.update(bytes);
|
|
302
|
-
out.write(bytes);
|
|
303
|
-
received += bytes.byteLength;
|
|
304
|
-
if (received - lastReported >= 5 * 1e6) {
|
|
305
|
-
lastReported = received;
|
|
306
|
-
log(`[mbws:dev] 下载中 ${Math.round(received / 1e6)} / ${Math.round(resolved.size / 1e6)} MB`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
await new Promise((resolve, reject) => out.end((error) => (error ? reject(error) : resolve())));
|
|
310
|
-
const sha256 = hash.digest("hex");
|
|
360
|
+
const sha256 = await downloadToFile(resolved.url, tmpPath, log, resolved.size);
|
|
311
361
|
if (sha256 !== resolved.sha256) {
|
|
312
362
|
throw new Error(`sha256 不符(期望 ${resolved.sha256},实得 ${sha256})`);
|
|
313
363
|
}
|
|
@@ -375,7 +425,7 @@ async function handleDevExec(config, root, req, res) {
|
|
|
375
425
|
res.statusCode = 501;
|
|
376
426
|
res.end(JSON.stringify({
|
|
377
427
|
message: declared
|
|
378
|
-
? `附件 ${attachment}
|
|
428
|
+
? `附件 ${attachment} 无 url 直链且未在官方附件库登记当前平台产物(或后端不可达);可配 attachments 的 url 直链 / devPath / env MBWS_DEV_ATTACHMENT_${attachment.replace(/-/g, "_").toUpperCase()}`
|
|
379
429
|
: `mbws.config.ts 的 attachments 未声明附件 ${attachment}(dev 自动下载依赖声明);本机覆盖可配该项 devPath / env MBWS_DEV_ATTACHMENT_${attachment.replace(/-/g, "_").toUpperCase()}`,
|
|
380
430
|
}));
|
|
381
431
|
return;
|