weapp-vite 7.2.2 → 7.4.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 +104 -6
- package/dist/adapters-BwnMMIZR.mjs +2 -0
- package/dist/auto-routes.mjs +1 -1
- package/dist/cli.mjs +635 -644
- package/dist/{config-JdEU9lCP.d.mts → config-Dbvj5yK7.d.mts} +446 -15
- package/dist/config.d.mts +2 -2
- package/dist/constants-WOsG3Eqd.mjs +85 -0
- package/dist/{createContext-403iJEyy.mjs → createContext-UOEgeYnA.mjs} +9550 -5921
- package/dist/dashboard/vite.d.mts +9 -0
- package/dist/dashboard/vite.mjs +44 -0
- package/dist/dashboard-BzaVesmQ.mjs +558 -0
- package/dist/dashboard.d.mts +2 -0
- package/dist/dashboard.mjs +2 -0
- package/dist/docs/README.md +104 -6
- package/dist/docs/getting-started.md +50 -1
- package/dist/docs/index.md +3 -1
- package/dist/docs/upload.md +189 -0
- package/dist/docs/weapp-config.md +348 -2
- package/dist/docs/wevu-authoring.md +19 -0
- package/dist/file-D19nbDoN.mjs +2 -0
- package/dist/{file-CfgcKGLR.mjs → file-giE9UMZa.mjs} +3 -86
- package/dist/getInstance-CYF1vl5l.mjs +2 -0
- package/dist/index-DbqVupg0.d.mts +246 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/json.d.mts +1 -1
- package/dist/mcp.d.mts +1 -1
- package/dist/platform-DTWs5QRi.mjs +175 -0
- package/dist/test.mjs +1 -1
- package/dist/types.d.mts +2 -2
- package/dist/upload-D0RcEWrq.mjs +403 -0
- package/dist/upload-worker.d.mts +1 -0
- package/dist/upload-worker.mjs +28 -0
- package/package.json +47 -25
- package/dist/file-BRwj-D25.mjs +0 -2
- package/dist/getInstance-BhkSNqVQ.mjs +0 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { t as AnalyzeDashboardDevframeController } from "../index-DbqVupg0.mjs";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
//#region src/dashboard/vite.d.ts
|
|
4
|
+
export interface AnalyzeDashboardPluginOptions {
|
|
5
|
+
base?: string;
|
|
6
|
+
}
|
|
7
|
+
/** 使用官方适配器挂载到现有 Vite DevTools;认证、Origin 与 MCP 策略由宿主负责。 */
|
|
8
|
+
export declare function createAnalyzeDashboardPlugin(controller: AnalyzeDashboardDevframeController, options?: AnalyzeDashboardPluginOptions): Plugin;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join } from "node:path";
|
|
3
|
+
import { createPluginFromDevframe } from "@vitejs/devtools-kit/node";
|
|
4
|
+
//#region src/dashboard/vite.ts
|
|
5
|
+
/** 使用官方适配器挂载到现有 Vite DevTools;认证、Origin 与 MCP 策略由宿主负责。 */
|
|
6
|
+
function createAnalyzeDashboardPlugin(controller, options = {}) {
|
|
7
|
+
const plugin = createPluginFromDevframe(controller.definition, { base: options.base === void 0 ? void 0 : `/${options.base}/`.replace(/\/+/g, "/") });
|
|
8
|
+
const devtools = plugin.devtools;
|
|
9
|
+
let activeHostConfig;
|
|
10
|
+
return {
|
|
11
|
+
...plugin,
|
|
12
|
+
apply: "serve",
|
|
13
|
+
devtools: {
|
|
14
|
+
...devtools,
|
|
15
|
+
async setup(ctx) {
|
|
16
|
+
let setupStarted = false;
|
|
17
|
+
try {
|
|
18
|
+
if (ctx.viteConfig.command !== "serve") return;
|
|
19
|
+
const clientAssets = controller.definition.clientAssets;
|
|
20
|
+
if (typeof clientAssets !== "string" || !isAbsolute(clientAssets) || !existsSync(join(clientAssets, "index.html"))) throw new Error("Dashboard Vite 插件需要已构建 clientAssets 的绝对目录,请先调用 resolveDashboardClientAssets。");
|
|
21
|
+
setupStarted = true;
|
|
22
|
+
await devtools.setup(ctx);
|
|
23
|
+
activeHostConfig = ctx.viteConfig;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!activeHostConfig || setupStarted) {
|
|
26
|
+
activeHostConfig = void 0;
|
|
27
|
+
controller.dispose();
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
async closeBundle(...args) {
|
|
34
|
+
if (this.environment.getTopLevelConfig() === activeHostConfig) {
|
|
35
|
+
activeHostConfig = void 0;
|
|
36
|
+
controller.dispose();
|
|
37
|
+
}
|
|
38
|
+
const closeBundle = plugin.closeBundle;
|
|
39
|
+
await (typeof closeBundle === "function" ? closeBundle : closeBundle?.handler)?.apply(this, args);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { createAnalyzeDashboardPlugin };
|
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import { t as VERSION } from "./constants-WOsG3Eqd.mjs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "pathe";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { Buffer } from "node:buffer";
|
|
8
|
+
import { defineDevframe, defineRpcFunction } from "devframe";
|
|
9
|
+
//#region src/dashboard/artifacts.ts
|
|
10
|
+
const MAX_DASHBOARD_FILE_CONTENT_BYTES = 2097152;
|
|
11
|
+
/** 保留同一次分析的产物内容,不读取或改写开发构建目录。 */
|
|
12
|
+
function createDashboardArtifactSnapshot() {
|
|
13
|
+
const files = /* @__PURE__ */ new Map();
|
|
14
|
+
let retainedBytes = 0;
|
|
15
|
+
return {
|
|
16
|
+
files,
|
|
17
|
+
capture(fileName, source) {
|
|
18
|
+
const key = fileName.replaceAll("\\", "/");
|
|
19
|
+
const previous = files.get(key);
|
|
20
|
+
if (previous?.content !== void 0) retainedBytes -= previous.size;
|
|
21
|
+
const size = typeof source === "string" ? Buffer.byteLength(source, "utf8") : source.byteLength;
|
|
22
|
+
if (size > 2097152) {
|
|
23
|
+
files.set(key, {
|
|
24
|
+
size,
|
|
25
|
+
error: `文件超过 ${MAX_DASHBOARD_FILE_CONTENT_BYTES} 字节,已拒绝读取。`
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (retainedBytes + size > 33554432) {
|
|
30
|
+
files.set(key, {
|
|
31
|
+
size,
|
|
32
|
+
error: "分析产物内容超过快照容量上限,已拒绝读取。"
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const content = typeof source === "string" ? source : Buffer.from(source.buffer, source.byteOffset, source.byteLength).toString("utf8");
|
|
37
|
+
files.set(key, {
|
|
38
|
+
content,
|
|
39
|
+
size
|
|
40
|
+
});
|
|
41
|
+
retainedBytes += size;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/dashboard/paths.ts
|
|
47
|
+
function normalizeDashboardRelativePath(value) {
|
|
48
|
+
return value.replaceAll("\\", "/");
|
|
49
|
+
}
|
|
50
|
+
function stripDashboardFileQuery(value) {
|
|
51
|
+
const queryIndex = value.indexOf("?");
|
|
52
|
+
return queryIndex === -1 ? value : value.slice(0, queryIndex);
|
|
53
|
+
}
|
|
54
|
+
function addDashboardAllowedPath(paths, value) {
|
|
55
|
+
if (!value || value.includes("\0")) return;
|
|
56
|
+
const normalizedPath = normalizeDashboardRelativePath(stripDashboardFileQuery(value));
|
|
57
|
+
if (!normalizedPath || path.isAbsolute(normalizedPath)) return;
|
|
58
|
+
paths.add(normalizedPath);
|
|
59
|
+
}
|
|
60
|
+
function addDashboardAllowedSourcePath(paths, value, rootKind) {
|
|
61
|
+
if (!value || value.includes("\0")) return;
|
|
62
|
+
const normalizedPath = normalizeDashboardRelativePath(stripDashboardFileQuery(value));
|
|
63
|
+
if (!normalizedPath || path.isAbsolute(normalizedPath)) return;
|
|
64
|
+
const rootKinds = paths.get(normalizedPath) ?? /* @__PURE__ */ new Set();
|
|
65
|
+
rootKinds.add(rootKind);
|
|
66
|
+
paths.set(normalizedPath, rootKinds);
|
|
67
|
+
}
|
|
68
|
+
function resolveDashboardSourceRootKind(sourceType) {
|
|
69
|
+
if (sourceType === "plugin") return "plugin";
|
|
70
|
+
if (sourceType === "workspace" || sourceType === "node_modules") return "project";
|
|
71
|
+
return "src";
|
|
72
|
+
}
|
|
73
|
+
function createDashboardContentAllowlist(result) {
|
|
74
|
+
const artifactPaths = /* @__PURE__ */ new Set();
|
|
75
|
+
const sourcePaths = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const packageReport of result.packages) for (const file of packageReport.files) {
|
|
77
|
+
addDashboardAllowedPath(artifactPaths, file.file);
|
|
78
|
+
const fileSourceType = file.sourceType ?? file.modules?.find((module) => module.source === file.source)?.sourceType;
|
|
79
|
+
addDashboardAllowedSourcePath(sourcePaths, file.source, resolveDashboardSourceRootKind(fileSourceType));
|
|
80
|
+
for (const module of file.modules ?? []) addDashboardAllowedSourcePath(sourcePaths, module.source, module.sourceType === "src" ? "src" : module.sourceType === "plugin" ? "plugin" : "project");
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
artifactPaths,
|
|
84
|
+
sourcePaths
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function resolveDashboardContentPath(root, requestPath, options) {
|
|
88
|
+
if (!root || !requestPath || requestPath.includes("\0")) return;
|
|
89
|
+
const normalizedRequestPath = normalizeDashboardRelativePath(stripDashboardFileQuery(requestPath));
|
|
90
|
+
if (path.isAbsolute(normalizedRequestPath) || !options.allowedPaths.has(normalizedRequestPath)) return;
|
|
91
|
+
const rootPath = path.resolve(root);
|
|
92
|
+
const absolutePath = path.resolve(rootPath, normalizedRequestPath);
|
|
93
|
+
const relativePath = path.relative(rootPath, absolutePath);
|
|
94
|
+
const allowParent = options.allowParent === true;
|
|
95
|
+
if (!relativePath || !allowParent && (relativePath.startsWith("..") || path.isAbsolute(relativePath))) return;
|
|
96
|
+
return {
|
|
97
|
+
absolutePath,
|
|
98
|
+
allowParent,
|
|
99
|
+
relativePath: allowParent ? normalizedRequestPath : normalizeDashboardRelativePath(relativePath),
|
|
100
|
+
rootPath
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function resolveDashboardSourceContentPaths(roots, requestPath, allowedPaths) {
|
|
104
|
+
const normalizedRequestPath = normalizeDashboardRelativePath(stripDashboardFileQuery(requestPath));
|
|
105
|
+
const rootKinds = allowedPaths.get(normalizedRequestPath);
|
|
106
|
+
if (!rootKinds || rootKinds.size !== 1) return [];
|
|
107
|
+
const [rootKind] = rootKinds;
|
|
108
|
+
if (rootKind === "project") {
|
|
109
|
+
const resolved = resolveDashboardContentPath(roots.projectRoot, normalizedRequestPath, {
|
|
110
|
+
allowParent: true,
|
|
111
|
+
allowedPaths: /* @__PURE__ */ new Set([normalizedRequestPath])
|
|
112
|
+
});
|
|
113
|
+
return resolved ? [resolved] : [];
|
|
114
|
+
}
|
|
115
|
+
if (rootKind === "plugin") {
|
|
116
|
+
if (!roots.pluginRoot) return [];
|
|
117
|
+
const pluginBase = path.basename(roots.pluginRoot);
|
|
118
|
+
if (normalizedRequestPath !== pluginBase && !normalizedRequestPath.startsWith(`${pluginBase}/`)) return [];
|
|
119
|
+
const pluginRelativePath = normalizedRequestPath === pluginBase ? "" : normalizedRequestPath.slice(pluginBase.length + 1);
|
|
120
|
+
const resolved = resolveDashboardContentPath(roots.pluginRoot, pluginRelativePath, { allowedPaths: /* @__PURE__ */ new Set([pluginRelativePath]) });
|
|
121
|
+
return resolved ? [{
|
|
122
|
+
...resolved,
|
|
123
|
+
relativePath: normalizedRequestPath
|
|
124
|
+
}] : [];
|
|
125
|
+
}
|
|
126
|
+
if (!roots.srcRoot) return [];
|
|
127
|
+
const candidates = (normalizedRequestPath.startsWith("src/") ? [normalizedRequestPath, normalizedRequestPath.slice(4)] : [normalizedRequestPath]).flatMap((relativePath) => {
|
|
128
|
+
const resolved = resolveDashboardContentPath(roots.srcRoot, relativePath, { allowedPaths: /* @__PURE__ */ new Set([relativePath]) });
|
|
129
|
+
return resolved ? [{
|
|
130
|
+
...resolved,
|
|
131
|
+
relativePath: normalizedRequestPath
|
|
132
|
+
}] : [];
|
|
133
|
+
});
|
|
134
|
+
return [...new Map(candidates.map((candidate) => [candidate.absolutePath, candidate])).values()];
|
|
135
|
+
}
|
|
136
|
+
function resolveDashboardArtifactPath(requestPath, allowedPaths) {
|
|
137
|
+
const normalizedPath = normalizeDashboardRelativePath(stripDashboardFileQuery(requestPath));
|
|
138
|
+
if (!normalizedPath || normalizedPath.includes("\0") || path.isAbsolute(normalizedPath) || path.posix.normalize(normalizedPath).startsWith("..") || !allowedPaths.has(normalizedPath)) return;
|
|
139
|
+
return normalizedPath;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/dashboard/content.ts
|
|
143
|
+
function isPathWithin(rootPath, targetPath) {
|
|
144
|
+
const relativePath = path.relative(rootPath, targetPath);
|
|
145
|
+
return !relativePath || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
146
|
+
}
|
|
147
|
+
function resolveInspectionRoot(resolved) {
|
|
148
|
+
let inspectionRoot = resolved.rootPath;
|
|
149
|
+
if (!resolved.allowParent) return inspectionRoot;
|
|
150
|
+
while (!isPathWithin(inspectionRoot, resolved.absolutePath)) {
|
|
151
|
+
const parent = path.dirname(inspectionRoot);
|
|
152
|
+
if (parent === inspectionRoot) return;
|
|
153
|
+
inspectionRoot = parent;
|
|
154
|
+
}
|
|
155
|
+
return inspectionRoot;
|
|
156
|
+
}
|
|
157
|
+
async function assertDashboardPathHasNoSymlink(resolved) {
|
|
158
|
+
const inspectionRoot = resolveInspectionRoot(resolved);
|
|
159
|
+
if (!inspectionRoot) throw new Error("文件路径超出允许范围。");
|
|
160
|
+
const relativePath = path.relative(inspectionRoot, resolved.absolutePath);
|
|
161
|
+
let currentPath = inspectionRoot;
|
|
162
|
+
for (const segment of relativePath.split(path.sep).filter(Boolean)) {
|
|
163
|
+
currentPath = path.join(currentPath, segment);
|
|
164
|
+
if ((await fs.promises.lstat(currentPath)).isSymbolicLink()) throw new Error("文件路径包含不允许的符号链接。");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function isSameOpenedFile(pathStat, handleStat) {
|
|
168
|
+
if (pathStat.dev !== handleStat.dev) return false;
|
|
169
|
+
return pathStat.ino === 0 || handleStat.ino === 0 || pathStat.ino === handleStat.ino;
|
|
170
|
+
}
|
|
171
|
+
async function openDashboardFile(resolved) {
|
|
172
|
+
await assertDashboardPathHasNoSymlink(resolved);
|
|
173
|
+
const flags = process.platform === "win32" ? fs.constants.O_RDONLY : fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW;
|
|
174
|
+
const handle = await fs.promises.open(resolved.absolutePath, flags);
|
|
175
|
+
try {
|
|
176
|
+
await assertDashboardPathHasNoSymlink(resolved);
|
|
177
|
+
const [pathStat, handleStat] = await Promise.all([fs.promises.stat(resolved.absolutePath), handle.stat()]);
|
|
178
|
+
if (!isSameOpenedFile(pathStat, handleStat)) throw new Error("文件路径在读取期间发生变化。");
|
|
179
|
+
return handle;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
await handle.close();
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function readDashboardFileHandle(handle) {
|
|
186
|
+
const stat = await handle.stat();
|
|
187
|
+
if (!stat.isFile()) throw new Error("目标路径不是文件。");
|
|
188
|
+
if (stat.size > 2097152) throw new Error(`文件超过 ${MAX_DASHBOARD_FILE_CONTENT_BYTES} 字节,已拒绝读取。`);
|
|
189
|
+
let content = Buffer.allocUnsafe(Math.min(Math.max(stat.size + 1, 1), 2097153));
|
|
190
|
+
let offset = 0;
|
|
191
|
+
while (true) {
|
|
192
|
+
if (offset === content.length) {
|
|
193
|
+
if (content.length === 2097153) throw new Error(`文件超过 ${MAX_DASHBOARD_FILE_CONTENT_BYTES} 字节,已拒绝读取。`);
|
|
194
|
+
const expanded = Buffer.allocUnsafe(Math.min(content.length * 2, 2097153));
|
|
195
|
+
content.copy(expanded, 0, 0, offset);
|
|
196
|
+
content = expanded;
|
|
197
|
+
}
|
|
198
|
+
const { bytesRead } = await handle.read(content, offset, content.length - offset, offset);
|
|
199
|
+
if (bytesRead === 0) break;
|
|
200
|
+
offset += bytesRead;
|
|
201
|
+
if (offset > 2097152) throw new Error(`文件超过 ${MAX_DASHBOARD_FILE_CONTENT_BYTES} 字节,已拒绝读取。`);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
content: content.subarray(0, offset).toString("utf8"),
|
|
205
|
+
size: offset
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function resolveDashboardFileLanguage(filePath) {
|
|
209
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
210
|
+
if ([
|
|
211
|
+
".js",
|
|
212
|
+
".mjs",
|
|
213
|
+
".cjs",
|
|
214
|
+
".wxs",
|
|
215
|
+
".sjs"
|
|
216
|
+
].includes(extension)) return "javascript";
|
|
217
|
+
if ([
|
|
218
|
+
".ts",
|
|
219
|
+
".mts",
|
|
220
|
+
".cts"
|
|
221
|
+
].includes(extension)) return "typescript";
|
|
222
|
+
if ([".json", ".map"].includes(extension)) return "json";
|
|
223
|
+
if ([
|
|
224
|
+
".css",
|
|
225
|
+
".wxss",
|
|
226
|
+
".scss",
|
|
227
|
+
".sass",
|
|
228
|
+
".less"
|
|
229
|
+
].includes(extension)) return "css";
|
|
230
|
+
if ([
|
|
231
|
+
".vue",
|
|
232
|
+
".wxml",
|
|
233
|
+
".html"
|
|
234
|
+
].includes(extension)) return "html";
|
|
235
|
+
return "plaintext";
|
|
236
|
+
}
|
|
237
|
+
function normalizeDashboardFileRequest(input) {
|
|
238
|
+
if (!input || typeof input !== "object" || !("kind" in input) || !("path" in input)) throw new Error("必须传入合法的 kind 和相对路径。");
|
|
239
|
+
const kind = input.kind;
|
|
240
|
+
const requestPath = input.path;
|
|
241
|
+
if (kind !== "source" && kind !== "artifact" || typeof requestPath !== "string") throw new Error("必须传入合法的 kind 和相对路径。");
|
|
242
|
+
return {
|
|
243
|
+
kind,
|
|
244
|
+
path: requestPath
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
async function readAllowedDashboardFile(input, roots, allowlist, artifacts) {
|
|
248
|
+
const request = normalizeDashboardFileRequest(input);
|
|
249
|
+
if (request.kind === "artifact") {
|
|
250
|
+
const filePath = resolveDashboardArtifactPath(request.path, allowlist.artifactPaths);
|
|
251
|
+
if (!filePath) throw new Error("必须传入合法的 kind 和相对路径。");
|
|
252
|
+
const file = artifacts.get(filePath);
|
|
253
|
+
if (!file) throw new Error("分析快照中没有此产物内容。");
|
|
254
|
+
if (file.error || file.content === void 0) throw new Error(file.error ?? "分析快照中没有此产物内容。");
|
|
255
|
+
return {
|
|
256
|
+
kind: request.kind,
|
|
257
|
+
path: filePath,
|
|
258
|
+
language: resolveDashboardFileLanguage(filePath),
|
|
259
|
+
size: file.size,
|
|
260
|
+
content: file.content
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const resolvedCandidates = resolveDashboardSourceContentPaths(roots, request.path, allowlist.sourcePaths);
|
|
264
|
+
if (resolvedCandidates.length === 0) throw new Error("必须传入合法的 kind 和相对路径。");
|
|
265
|
+
const openedCandidates = [];
|
|
266
|
+
try {
|
|
267
|
+
for (const resolved of resolvedCandidates) try {
|
|
268
|
+
openedCandidates.push({
|
|
269
|
+
handle: await openDashboardFile(resolved),
|
|
270
|
+
resolved
|
|
271
|
+
});
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if ((typeof error === "object" && error && "code" in error ? String(error.code) : "") !== "ENOENT") throw error;
|
|
274
|
+
}
|
|
275
|
+
if (openedCandidates.length === 0) throw new Error("文件不存在。");
|
|
276
|
+
if (openedCandidates.length > 1) throw new Error("源码路径存在多个候选文件,已拒绝读取。");
|
|
277
|
+
const [{ handle, resolved }] = openedCandidates;
|
|
278
|
+
const file = await readDashboardFileHandle(handle);
|
|
279
|
+
return {
|
|
280
|
+
kind: request.kind,
|
|
281
|
+
path: resolved.relativePath,
|
|
282
|
+
language: resolveDashboardFileLanguage(resolved.relativePath),
|
|
283
|
+
size: file.size,
|
|
284
|
+
content: file.content
|
|
285
|
+
};
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (error instanceof Error && (error.message === "文件不存在。" || error.message === "源码路径存在多个候选文件,已拒绝读取。" || error.message === "目标路径不是文件。" || error.message.startsWith("文件超过 ") || error.message.startsWith("文件路径"))) throw error;
|
|
288
|
+
throw new Error("读取文件失败。");
|
|
289
|
+
} finally {
|
|
290
|
+
await Promise.allSettled(openedCandidates.map((candidate) => candidate.handle.close()));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function createDashboardFileReader(roots, result, artifacts) {
|
|
294
|
+
let allowlist = createDashboardContentAllowlist(result);
|
|
295
|
+
let currentArtifacts = artifacts;
|
|
296
|
+
let disposed = false;
|
|
297
|
+
return {
|
|
298
|
+
read: async (input) => {
|
|
299
|
+
if (disposed || !currentArtifacts) throw new Error("Dashboard 文件读取会话已关闭。");
|
|
300
|
+
return await readAllowedDashboardFile(input, roots, allowlist, currentArtifacts);
|
|
301
|
+
},
|
|
302
|
+
update(nextResult, nextArtifacts) {
|
|
303
|
+
if (disposed) return;
|
|
304
|
+
allowlist = createDashboardContentAllowlist(nextResult);
|
|
305
|
+
currentArtifacts = nextArtifacts;
|
|
306
|
+
},
|
|
307
|
+
dispose() {
|
|
308
|
+
disposed = true;
|
|
309
|
+
currentArtifacts = void 0;
|
|
310
|
+
allowlist.artifactPaths.clear();
|
|
311
|
+
allowlist.sourcePaths.clear();
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/dashboard/events.ts
|
|
317
|
+
function createDashboardRuntimeEvent(input) {
|
|
318
|
+
return {
|
|
319
|
+
id: `dashboard:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`,
|
|
320
|
+
kind: input.kind,
|
|
321
|
+
level: input.level,
|
|
322
|
+
title: input.title,
|
|
323
|
+
detail: input.detail,
|
|
324
|
+
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("zh-CN", { hour12: false }),
|
|
325
|
+
source: input.source ?? "weapp-vite",
|
|
326
|
+
durationMs: input.durationMs,
|
|
327
|
+
tags: input.tags,
|
|
328
|
+
profile: input.profile
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function prependDashboardRuntimeEvents(current, inputs) {
|
|
332
|
+
return [...inputs.map(createDashboardRuntimeEvent), ...current].slice(0, 24);
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/dashboard/payload.ts
|
|
336
|
+
const MAX_DASHBOARD_ANALYZE_PAGE_CHARACTERS = 65536;
|
|
337
|
+
const STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE = "Analyze revision 已变化,请重新获取 Dashboard 状态。";
|
|
338
|
+
function serializeDashboardAnalyzePayload(result) {
|
|
339
|
+
const value = JSON.stringify(result);
|
|
340
|
+
return {
|
|
341
|
+
descriptor: {
|
|
342
|
+
characters: value.length,
|
|
343
|
+
hash: createHash("sha256").update(value).digest("hex"),
|
|
344
|
+
pages: Math.max(1, Math.ceil(value.length / MAX_DASHBOARD_ANALYZE_PAGE_CHARACTERS))
|
|
345
|
+
},
|
|
346
|
+
source: result,
|
|
347
|
+
value
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function serializeDashboardAnalyzeSnapshot(snapshot, cached) {
|
|
351
|
+
const previous = snapshot.previous ? cached?.current.source === snapshot.previous ? cached.current : cached?.previous?.source === snapshot.previous ? cached.previous : serializeDashboardAnalyzePayload(snapshot.previous) : null;
|
|
352
|
+
return {
|
|
353
|
+
current: cached?.current.source === snapshot.current ? cached.current : serializeDashboardAnalyzePayload(snapshot.current),
|
|
354
|
+
previous
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function normalizeAnalyzePageRequest(input) {
|
|
358
|
+
if (!input || typeof input !== "object") throw new Error("必须传入合法的 Analyze 分页请求。");
|
|
359
|
+
if (!("revision" in input) || !("target" in input) || !("index" in input)) throw new Error("必须传入合法的 Analyze 分页请求。");
|
|
360
|
+
const revision = input.revision;
|
|
361
|
+
const target = input.target;
|
|
362
|
+
const index = input.index;
|
|
363
|
+
if (typeof revision !== "number" || !Number.isSafeInteger(revision) || revision < 0 || target !== "current" && target !== "previous" || typeof index !== "number" || !Number.isSafeInteger(index) || index < 0) throw new Error("必须传入合法的 Analyze 分页请求。");
|
|
364
|
+
return {
|
|
365
|
+
revision,
|
|
366
|
+
target,
|
|
367
|
+
index
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function readDashboardAnalyzePage(input, revision, snapshot) {
|
|
371
|
+
const request = normalizeAnalyzePageRequest(input);
|
|
372
|
+
if (request.revision !== revision) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
373
|
+
const payload = request.target === "current" ? snapshot.current : snapshot.previous;
|
|
374
|
+
if (!payload || request.index >= payload.descriptor.pages) throw new Error("Analyze 分页不存在。");
|
|
375
|
+
const start = request.index * MAX_DASHBOARD_ANALYZE_PAGE_CHARACTERS;
|
|
376
|
+
return {
|
|
377
|
+
content: payload.value.slice(start, start + MAX_DASHBOARD_ANALYZE_PAGE_CHARACTERS),
|
|
378
|
+
descriptor: payload.descriptor,
|
|
379
|
+
index: request.index,
|
|
380
|
+
revision,
|
|
381
|
+
target: request.target
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/dashboard/assets.ts
|
|
386
|
+
const ANALYZE_DASHBOARD_PACKAGE_NAME = "@weapp-vite/dashboard";
|
|
387
|
+
const require = createRequire(import.meta.url);
|
|
388
|
+
function parseDashboardManifest(source) {
|
|
389
|
+
const parsed = JSON.parse(source);
|
|
390
|
+
const metadata = parsed && typeof parsed === "object" && "weappViteDashboard" in parsed ? parsed.weappViteDashboard : void 0;
|
|
391
|
+
if (!metadata || typeof metadata !== "object") return;
|
|
392
|
+
return { weappViteDashboard: {
|
|
393
|
+
devConfigFile: "devConfigFile" in metadata && typeof metadata.devConfigFile === "string" ? metadata.devConfigFile : void 0,
|
|
394
|
+
devRoot: "devRoot" in metadata && typeof metadata.devRoot === "string" ? metadata.devRoot : void 0,
|
|
395
|
+
distDir: "distDir" in metadata && typeof metadata.distDir === "string" ? metadata.distDir : void 0
|
|
396
|
+
} };
|
|
397
|
+
}
|
|
398
|
+
function resolveDashboardPackage(cwd) {
|
|
399
|
+
const resolvePaths = cwd && cwd !== process.cwd() ? [cwd, process.cwd()] : cwd ? [cwd] : void 0;
|
|
400
|
+
try {
|
|
401
|
+
const packageJsonPath = require.resolve(`${ANALYZE_DASHBOARD_PACKAGE_NAME}/package.json`, { paths: resolvePaths });
|
|
402
|
+
let manifest;
|
|
403
|
+
try {
|
|
404
|
+
manifest = parseDashboardManifest(fs.readFileSync(packageJsonPath, "utf8"));
|
|
405
|
+
} catch {
|
|
406
|
+
manifest = void 0;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
root: path.dirname(packageJsonPath),
|
|
410
|
+
manifest
|
|
411
|
+
};
|
|
412
|
+
} catch {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function resolveDashboardDistRoot(packageRoot, manifest) {
|
|
417
|
+
const root = path.resolve(packageRoot, manifest?.weappViteDashboard?.distDir ?? "dist");
|
|
418
|
+
return fs.existsSync(path.join(root, "index.html")) ? { root } : void 0;
|
|
419
|
+
}
|
|
420
|
+
function resolveDashboardDevRoot(packageRoot, manifest) {
|
|
421
|
+
const devRoot = manifest?.weappViteDashboard?.devRoot;
|
|
422
|
+
const devConfigFile = manifest?.weappViteDashboard?.devConfigFile;
|
|
423
|
+
if (!devRoot || !devConfigFile) return;
|
|
424
|
+
const root = path.resolve(packageRoot, devRoot);
|
|
425
|
+
const configFile = path.resolve(root, devConfigFile);
|
|
426
|
+
return fs.existsSync(root) && fs.existsSync(configFile) ? {
|
|
427
|
+
root,
|
|
428
|
+
configFile
|
|
429
|
+
} : void 0;
|
|
430
|
+
}
|
|
431
|
+
function resolveDashboardRoot(options) {
|
|
432
|
+
const resolved = resolveDashboardPackage(options.cwd);
|
|
433
|
+
if (!resolved) return;
|
|
434
|
+
return options.watch ? resolveDashboardDevRoot(resolved.root, resolved.manifest) ?? resolveDashboardDistRoot(resolved.root, resolved.manifest) : resolveDashboardDistRoot(resolved.root, resolved.manifest) ?? resolveDashboardDevRoot(resolved.root, resolved.manifest);
|
|
435
|
+
}
|
|
436
|
+
/** 定位可选仪表盘包的原生构建 SPA;未安装或尚未构建时返回 undefined。 */
|
|
437
|
+
function resolveDashboardClientAssets(cwd) {
|
|
438
|
+
const resolved = resolveDashboardPackage(cwd);
|
|
439
|
+
return resolved ? resolveDashboardDistRoot(resolved.root, resolved.manifest)?.root : void 0;
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/dashboard/index.ts
|
|
443
|
+
const DEVFRAME_ID = "weapp-vite";
|
|
444
|
+
/** 创建只读分析能力,不启动服务器,也不修改宿主的共享状态或认证策略。 */
|
|
445
|
+
function createAnalyzeDashboardDevframe({ snapshot: initialSnapshot, roots, initialEvents = [], clientAssets }) {
|
|
446
|
+
let revision = 0;
|
|
447
|
+
let snapshot = initialSnapshot;
|
|
448
|
+
let serializedSnapshot = serializeDashboardAnalyzeSnapshot(initialSnapshot);
|
|
449
|
+
let runtimeEvents = initialEvents.map(createDashboardRuntimeEvent);
|
|
450
|
+
let broadcastDashboardState;
|
|
451
|
+
const fileReader = createDashboardFileReader(roots, initialSnapshot.current, initialSnapshot.artifacts);
|
|
452
|
+
function getState() {
|
|
453
|
+
if (!serializedSnapshot) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
454
|
+
return {
|
|
455
|
+
analyze: {
|
|
456
|
+
current: serializedSnapshot.current.descriptor,
|
|
457
|
+
previous: serializedSnapshot.previous?.descriptor ?? null
|
|
458
|
+
},
|
|
459
|
+
revision,
|
|
460
|
+
runtimeEvents: [...runtimeEvents]
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const getDashboardState = defineRpcFunction({
|
|
464
|
+
name: "get-dashboard-state",
|
|
465
|
+
type: "query",
|
|
466
|
+
jsonSerializable: true,
|
|
467
|
+
handler: getState
|
|
468
|
+
});
|
|
469
|
+
const getAnalyzePage = defineRpcFunction({
|
|
470
|
+
name: "get-analyze-page",
|
|
471
|
+
type: "query",
|
|
472
|
+
jsonSerializable: true,
|
|
473
|
+
handler: (input) => {
|
|
474
|
+
if (!serializedSnapshot) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
475
|
+
return readDashboardAnalyzePage(input, revision, serializedSnapshot);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
const readDashboardFile = defineRpcFunction({
|
|
479
|
+
name: "read-dashboard-file",
|
|
480
|
+
type: "query",
|
|
481
|
+
jsonSerializable: true,
|
|
482
|
+
handler: async (input) => {
|
|
483
|
+
if (!input || typeof input !== "object" || !("revision" in input) || typeof input.revision !== "number" || !Number.isSafeInteger(input.revision) || input.revision < 0) throw new Error("必须传入合法的文件读取 revision。");
|
|
484
|
+
const requestedRevision = input.revision;
|
|
485
|
+
if (!snapshot || requestedRevision !== revision) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
486
|
+
const content = await fileReader.read(input);
|
|
487
|
+
if (!snapshot || requestedRevision !== revision) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
488
|
+
return content;
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
return {
|
|
492
|
+
definition: defineDevframe({
|
|
493
|
+
id: DEVFRAME_ID,
|
|
494
|
+
name: "weapp-vite",
|
|
495
|
+
version: VERSION,
|
|
496
|
+
packageName: "weapp-vite",
|
|
497
|
+
importMetaUrl: import.meta.url,
|
|
498
|
+
homepage: "https://vite.weapp.dev/",
|
|
499
|
+
description: "weapp-vite 构建分析与小程序开发工具。",
|
|
500
|
+
icon: "ph:rocket-launch-duotone",
|
|
501
|
+
capabilities: {
|
|
502
|
+
dev: true,
|
|
503
|
+
build: false
|
|
504
|
+
},
|
|
505
|
+
clientAssets,
|
|
506
|
+
async setup(ctx) {
|
|
507
|
+
if (!snapshot) throw new Error(STALE_DASHBOARD_ANALYZE_REVISION_MESSAGE);
|
|
508
|
+
const dashboard = ctx.scope(DEVFRAME_ID);
|
|
509
|
+
dashboard.rpc.register(getDashboardState);
|
|
510
|
+
dashboard.rpc.register(getAnalyzePage);
|
|
511
|
+
dashboard.rpc.register(readDashboardFile);
|
|
512
|
+
broadcastDashboardState = async () => {
|
|
513
|
+
await dashboard.rpc.broadcast({
|
|
514
|
+
method: "dashboard-state-updated",
|
|
515
|
+
args: [getState()],
|
|
516
|
+
event: true
|
|
517
|
+
});
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}),
|
|
521
|
+
async update(result, artifacts, previousResult) {
|
|
522
|
+
if (!snapshot) return;
|
|
523
|
+
const nextSnapshot = {
|
|
524
|
+
current: result,
|
|
525
|
+
previous: previousResult ?? snapshot.current,
|
|
526
|
+
artifacts
|
|
527
|
+
};
|
|
528
|
+
const nextSerialized = serializeDashboardAnalyzeSnapshot(nextSnapshot, serializedSnapshot);
|
|
529
|
+
fileReader.update(result, artifacts);
|
|
530
|
+
snapshot = nextSnapshot;
|
|
531
|
+
serializedSnapshot = nextSerialized;
|
|
532
|
+
revision += 1;
|
|
533
|
+
runtimeEvents = prependDashboardRuntimeEvents(runtimeEvents, [{
|
|
534
|
+
kind: "build",
|
|
535
|
+
level: "info",
|
|
536
|
+
title: "analyze payload refreshed",
|
|
537
|
+
detail: `已推送新的 analyze 结果,当前包含 ${result.packages.length} 个包与 ${result.modules.length} 个模块。`,
|
|
538
|
+
tags: ["analyze", "refresh"]
|
|
539
|
+
}]);
|
|
540
|
+
await broadcastDashboardState?.();
|
|
541
|
+
},
|
|
542
|
+
emitRuntimeEvents(events) {
|
|
543
|
+
if (!snapshot || events.length === 0) return;
|
|
544
|
+
runtimeEvents = prependDashboardRuntimeEvents(runtimeEvents, events);
|
|
545
|
+
broadcastDashboardState?.();
|
|
546
|
+
},
|
|
547
|
+
dispose() {
|
|
548
|
+
if (!snapshot) return;
|
|
549
|
+
snapshot = void 0;
|
|
550
|
+
serializedSnapshot = void 0;
|
|
551
|
+
runtimeEvents = [];
|
|
552
|
+
broadcastDashboardState = void 0;
|
|
553
|
+
fileReader.dispose();
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
//#endregion
|
|
558
|
+
export { createDashboardArtifactSnapshot as a, resolveDashboardRoot as i, ANALYZE_DASHBOARD_PACKAGE_NAME as n, resolveDashboardClientAssets as r, createAnalyzeDashboardDevframe as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as resolveDashboardClientAssets, c as DashboardContentRoots, d as createDashboardArtifactSnapshot, f as AnalyzeSubpackagesResult, i as createAnalyzeDashboardDevframe, l as DashboardArtifactFile, n as CreateAnalyzeDashboardDevframeOptions, o as DashboardRuntimeEventInput, r as DashboardAnalyzeSnapshot, s as DashboardRuntimeEventProfile, t as AnalyzeDashboardDevframeController, u as DashboardArtifactFiles } from "./index-DbqVupg0.mjs";
|
|
2
|
+
export { AnalyzeDashboardDevframeController, type AnalyzeSubpackagesResult, CreateAnalyzeDashboardDevframeOptions, DashboardAnalyzeSnapshot, type DashboardArtifactFile, type DashboardArtifactFiles, type DashboardContentRoots, type DashboardRuntimeEventInput, type DashboardRuntimeEventProfile, createAnalyzeDashboardDevframe, createDashboardArtifactSnapshot, resolveDashboardClientAssets };
|