@lark-apaas/coding-preset-vite-react 1.0.3-alpha.8 → 1.0.3

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.
@@ -1,23 +1,38 @@
1
1
  import type { Plugin } from 'vite';
2
2
  /**
3
- * 浏览器运行时日志收集 endpoint(jsPage 精简版)。
3
+ * 客户端日志收集 + 读取 + SSE 流式 endpoint
4
4
  *
5
- * jsPage 场景只需要一件事:把浏览器经 client-toolkit(-lite) logger 批量上报的日志落盘,
6
- * 供沙箱侧读取。因此本 plugin **只暴露一个接口**:
7
- * - `POST <basePath>/dev/logs/collect-batch` 数组批量 log → 追加写入 `<logDir>/<fileName>`
5
+ * 写入:
6
+ * - `POST <basePath>/dev/logs/collect` 单条 log(`{ message, ... }`)
7
+ * - `POST <basePath>/dev/logs/collect-batch` 数组批量 log
8
8
  *
9
- * **不提供** server-log 的 SSE 流(`/server-logs/stream`)、合并读(`/server-logs`)、单文件
10
- * 分页读(`/files/:fileName`)以及单条 `collect` —— 那些是 fullstack 后端(rspack preset +
11
- * `@lark-apaas/fullstack-toolkits`)的能力,依赖 server.log / trace.log / *.std.log,jsPage
12
- * 既不产出也无消费者(lite 的 batch-logger 只打 `/dev/logs/collect-batch`)。
9
+ * 读取:
10
+ * - `GET <basePath>/dev/logs/files/:fileName?page=1&pageSize=200`
11
+ * 倒序分页读 `<logDir>/<fileName>` 任意文件,防 path traversal,max pageSize 2000
12
+ * - `GET <basePath>/dev/logs/server-logs?limit=100&offset=0&levels=error,warn&sources=client-std`
13
+ * 合并 4 个常见日志文件(server.log / trace.log / server.std.log / client.std.log)
14
+ * 的 entries,按 timestamp desc 排序后分页 + 过滤
15
+ * - `GET <basePath>/dev/logs/server-logs/stream`(SSE)
16
+ * `LogWatcher` 增量监听 4 个文件,新行实时推送
13
17
  *
14
- * 写入文件默认 `browser.log`(浏览器运行时日志,区别于 dev.js 写的 vite 进程输出 `client.std.log`);
15
- * dev 启动即创建空文件(`'a'` 不截断),读取方无需处理“文件尚不存在”。
18
+ * jsPage 说明:endpoint 名字带 "server-" 是历史遗留(与 `client-toolkit` 写死的路径
19
+ * 兼容,见 `client-toolkit/src/server-log/poller.ts`);实际只监测一个文件
20
+ * `client.std.log`(dev.mjs 写的)。上游另外那 3 个(`server.log`、`trace.log`、
21
+ * `server.std.log`)是 fullstack 后端的产物,jsPage 不产、也没消费者,全部砍掉。
22
+ *
23
+ * 写入路径:`<logDir>/<fileName>`(默认 `./logs/client.log`,由 `LOG_DIR` 环境变量改写)。
24
+ *
25
+ * 移植自上游 `@lark-apaas/devtool-kits` 的 `dev-logs` + `collect-logs` middlewares。
26
+ * 仍然不补的 fullstack-only endpoints:
27
+ * - `/app/trace/:traceId`、`/trace/recent`、`/trace/trigger/*`、`/trace/capability/list`
28
+ * —— 全是 server-side trace.log 的索引接口
29
+ * - `/api-list` —— 从 fullstack server 抓 API route 清单
30
+ * - `/health` —— 重复(本 preset 有独立 `/dev/health`)
16
31
  */
17
32
  export interface DevLogsPluginOptions {
18
33
  /** 日志写入目录。默认 `process.env.LOG_DIR ?? './logs'`。 */
19
34
  logDir?: string;
20
- /** 日志文件名。默认 `browser.log`。 */
35
+ /** 日志文件名。默认 `client.log`。 */
21
36
  fileName?: string;
22
37
  /** Body 大小上限(bytes)。默认 20 MB。 */
23
38
  bodyLimit?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"dev-logs.d.ts","sourceRoot":"","sources":["../../src/plugins/dev-logs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwCD,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAwDxE;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"dev-logs.d.ts","sourceRoot":"","sources":["../../src/plugins/dev-logs.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0YD,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAqKxE;AAED,eAAe,aAAa,CAAC"}
@@ -34,13 +34,331 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.devLogsPlugin = devLogsPlugin;
37
+ const crypto = __importStar(require("node:crypto"));
37
38
  const fs = __importStar(require("node:fs"));
38
39
  const path = __importStar(require("node:path"));
40
+ const node_readline_1 = require("node:readline");
39
41
  const DEFAULT_BODY_LIMIT = 20 * 1024 * 1024;
40
42
  function ensureDir(dir) {
41
43
  if (!fs.existsSync(dir))
42
44
  fs.mkdirSync(dir, { recursive: true });
43
45
  }
46
+ function resolveLogFilePath(baseDir, fileName) {
47
+ const sanitized = fileName.replace(/\\/g, '/');
48
+ const segments = sanitized.split('/').filter(Boolean);
49
+ if (segments.some((seg) => seg === '..')) {
50
+ throw new Error('Invalid log file path');
51
+ }
52
+ const resolved = path.join(baseDir, segments.join('/'));
53
+ const rel = path.relative(baseDir, resolved);
54
+ if (rel.startsWith('..')) {
55
+ throw new Error('Access to the specified log file is denied');
56
+ }
57
+ return resolved;
58
+ }
59
+ function parsePositiveInt(value, fallback) {
60
+ if (!value || !value.trim())
61
+ return fallback;
62
+ const n = Number(value);
63
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
64
+ }
65
+ function parseLimit(value, def, max) {
66
+ if (!value || !value.trim())
67
+ return def;
68
+ const n = Number(value);
69
+ if (Number.isFinite(n) && n > 0)
70
+ return Math.min(Math.floor(n), max);
71
+ return def;
72
+ }
73
+ function extractLogLevel(text) {
74
+ const lower = text.toLowerCase();
75
+ if (lower.includes('fatal') || lower.includes('critical'))
76
+ return 'fatal';
77
+ if (lower.includes('error') || lower.includes('<e>') || lower.includes('✖'))
78
+ return 'error';
79
+ if (lower.includes('warn') || lower.includes('<w>') || lower.includes('⚠'))
80
+ return 'warn';
81
+ if (lower.includes('debug') || lower.includes('<d>'))
82
+ return 'debug';
83
+ if (lower.includes('verbose') || lower.includes('trace'))
84
+ return 'verbose';
85
+ return 'log';
86
+ }
87
+ /**
88
+ * std 输出日志解析(dev.mjs 的格式):
89
+ * `[2026-05-29 10:00:00] [client] message`
90
+ * 不匹配前缀时整行当 message、level 走文本启发式。
91
+ */
92
+ function parseStdLog(line, source) {
93
+ const id = crypto.randomUUID();
94
+ const m = line.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(server|client)\] (.*)$/);
95
+ if (!m) {
96
+ return {
97
+ id,
98
+ level: 'log',
99
+ timestamp: Date.now(),
100
+ message: line,
101
+ context: null,
102
+ traceId: null,
103
+ userId: null,
104
+ appId: null,
105
+ tenantId: null,
106
+ stack: null,
107
+ meta: null,
108
+ tags: [source],
109
+ };
110
+ }
111
+ const [, timeStr, , content] = m;
112
+ let timestamp = new Date(timeStr.replace(' ', 'T')).getTime();
113
+ if (Number.isNaN(timestamp))
114
+ timestamp = Date.now();
115
+ return {
116
+ id,
117
+ level: extractLogLevel(content),
118
+ timestamp,
119
+ message: content,
120
+ context: null,
121
+ traceId: null,
122
+ userId: null,
123
+ appId: null,
124
+ tenantId: null,
125
+ stack: null,
126
+ meta: null,
127
+ tags: [source],
128
+ };
129
+ }
130
+ // 监测的日志文件。jsPage 只有一个 client.std.log(dev.mjs 写的),其它 fullstack
131
+ // 后端的文件(server.log / trace.log / server.std.log)这里不监测——上游 LogWatcher
132
+ // 4 个文件的设计是 fullstack 遗留,本 preset 不携带。
133
+ const LOG_FILES = [{ fileName: 'client.std.log', source: 'client-std', parser: parseStdLog }];
134
+ async function readLogsBySource(logDir, source) {
135
+ const config = LOG_FILES.find((c) => c.source === source);
136
+ if (!config)
137
+ return [];
138
+ const filePath = path.join(logDir, config.fileName);
139
+ if (!fs.existsSync(filePath))
140
+ return [];
141
+ const out = [];
142
+ const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
143
+ const rl = (0, node_readline_1.createInterface)({ input: stream, crlfDelay: Infinity });
144
+ try {
145
+ for await (const line of rl) {
146
+ if (!line.trim())
147
+ continue;
148
+ try {
149
+ const entry = config.parser(line, source);
150
+ if (entry)
151
+ out.push(entry);
152
+ }
153
+ catch {
154
+ /* skip unparseable */
155
+ }
156
+ }
157
+ }
158
+ finally {
159
+ rl.close();
160
+ stream.close();
161
+ }
162
+ return out;
163
+ }
164
+ async function readServerLogs(logDir, opts = {}) {
165
+ const limit = opts.limit ?? 100;
166
+ const offset = opts.offset ?? 0;
167
+ const sources = opts.sources ?? LOG_FILES.map((c) => c.source);
168
+ const all = [];
169
+ for (const source of sources) {
170
+ try {
171
+ const logs = await readLogsBySource(logDir, source);
172
+ all.push(...logs);
173
+ }
174
+ catch (e) {
175
+ console.warn(`[miaoda-dev-logs] read ${source} failed: ${e instanceof Error ? e.message : String(e)}`);
176
+ }
177
+ }
178
+ if (all.length === 0)
179
+ return null;
180
+ let filtered = all;
181
+ if (opts.levels && opts.levels.length > 0) {
182
+ filtered = all.filter((l) => opts.levels.includes(l.level));
183
+ }
184
+ filtered.sort((a, b) => b.timestamp - a.timestamp);
185
+ return {
186
+ logs: filtered.slice(offset, offset + limit),
187
+ total: filtered.length,
188
+ hasMore: offset + limit < filtered.length,
189
+ };
190
+ }
191
+ class LogWatcher {
192
+ constructor() {
193
+ this.logDir = '';
194
+ this.watchers = new Map();
195
+ this.positions = new Map();
196
+ this.subscribers = new Set();
197
+ this.running = false;
198
+ }
199
+ start(logDir) {
200
+ if (this.running)
201
+ return;
202
+ this.logDir = logDir;
203
+ this.running = true;
204
+ for (const cfg of LOG_FILES)
205
+ this.watchFile(cfg);
206
+ }
207
+ stop() {
208
+ if (!this.running)
209
+ return;
210
+ this.running = false;
211
+ for (const w of this.watchers.values()) {
212
+ try {
213
+ w.close();
214
+ }
215
+ catch {
216
+ /* noop */
217
+ }
218
+ }
219
+ this.watchers.clear();
220
+ this.positions.clear();
221
+ }
222
+ onLog(cb) {
223
+ this.subscribers.add(cb);
224
+ return () => this.subscribers.delete(cb);
225
+ }
226
+ getSubscriberCount() {
227
+ return this.subscribers.size;
228
+ }
229
+ watchFile(cfg) {
230
+ const filePath = path.join(this.logDir, cfg.fileName);
231
+ if (!fs.existsSync(filePath))
232
+ return; // 文件不存在静默 skip(jsPage 常见)
233
+ try {
234
+ this.positions.set(cfg.fileName, fs.statSync(filePath).size);
235
+ }
236
+ catch {
237
+ this.positions.set(cfg.fileName, 0);
238
+ }
239
+ try {
240
+ const watcher = fs.watch(filePath, (event) => {
241
+ if (event === 'change')
242
+ this.handleChange(cfg);
243
+ });
244
+ watcher.on('error', () => this.restart(cfg));
245
+ this.watchers.set(cfg.fileName, watcher);
246
+ }
247
+ catch {
248
+ /* noop */
249
+ }
250
+ }
251
+ restart(cfg) {
252
+ const existing = this.watchers.get(cfg.fileName);
253
+ if (existing) {
254
+ try {
255
+ existing.close();
256
+ }
257
+ catch {
258
+ /* noop */
259
+ }
260
+ this.watchers.delete(cfg.fileName);
261
+ }
262
+ setTimeout(() => {
263
+ if (this.running)
264
+ this.watchFile(cfg);
265
+ }, 1000);
266
+ }
267
+ handleChange(cfg) {
268
+ const filePath = path.join(this.logDir, cfg.fileName);
269
+ const last = this.positions.get(cfg.fileName) ?? 0;
270
+ let stats;
271
+ try {
272
+ stats = fs.statSync(filePath);
273
+ }
274
+ catch {
275
+ return;
276
+ }
277
+ const cur = stats.size;
278
+ if (cur < last) {
279
+ // 文件被截断,重置 position 再走一次
280
+ this.positions.set(cfg.fileName, 0);
281
+ this.handleChange(cfg);
282
+ return;
283
+ }
284
+ if (cur === last)
285
+ return;
286
+ const buf = Buffer.alloc(cur - last);
287
+ const fd = fs.openSync(filePath, 'r');
288
+ try {
289
+ fs.readSync(fd, buf, 0, cur - last, last);
290
+ }
291
+ finally {
292
+ fs.closeSync(fd);
293
+ }
294
+ this.positions.set(cfg.fileName, cur);
295
+ for (const line of buf.toString('utf-8').split('\n')) {
296
+ if (!line.trim())
297
+ continue;
298
+ try {
299
+ const entry = cfg.parser(line, cfg.source);
300
+ if (entry)
301
+ this.notify(entry);
302
+ }
303
+ catch {
304
+ /* skip */
305
+ }
306
+ }
307
+ }
308
+ notify(entry) {
309
+ for (const sub of this.subscribers) {
310
+ try {
311
+ sub(entry);
312
+ }
313
+ catch {
314
+ /* skip subscriber errors */
315
+ }
316
+ }
317
+ }
318
+ }
319
+ function formatSSE(event, data) {
320
+ return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
321
+ }
322
+ /**
323
+ * 倒序分页读日志:page=1 返回最新 pageSize 行。
324
+ *
325
+ * 算法移植自上游 `readLogFilePage`:用环形 buffer 缓存最近 `page*pageSize` 行避免
326
+ * 把整个文件读进内存;遍历完后只输出落在第 `page` 页范围内的行。
327
+ */
328
+ async function readLogFilePage(filePath, page, pageSize) {
329
+ if (!fs.existsSync(filePath))
330
+ return null;
331
+ const capacity = page * pageSize;
332
+ const buffer = [];
333
+ let totalLines = 0;
334
+ const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
335
+ const rl = (0, node_readline_1.createInterface)({ input: stream, crlfDelay: Infinity });
336
+ try {
337
+ for await (const line of rl) {
338
+ buffer.push(line);
339
+ if (buffer.length > capacity)
340
+ buffer.shift();
341
+ totalLines += 1;
342
+ }
343
+ }
344
+ finally {
345
+ rl.close();
346
+ stream.close();
347
+ }
348
+ const totalPages = totalLines === 0 ? 0 : Math.ceil(totalLines / pageSize);
349
+ if (buffer.length === 0)
350
+ return { page, pageSize, totalLines, totalPages, lines: [] };
351
+ const startIndex = Math.max(totalLines - page * pageSize, 0);
352
+ const endIndex = Math.max(totalLines - (page - 1) * pageSize, 0);
353
+ const bufferStartIndex = totalLines - buffer.length;
354
+ const lines = [];
355
+ for (let i = buffer.length - 1; i >= 0; i -= 1) {
356
+ const lineIndex = bufferStartIndex + i;
357
+ if (lineIndex >= startIndex && lineIndex < endIndex)
358
+ lines.push(buffer[i]);
359
+ }
360
+ return { page, pageSize, totalLines, totalPages, lines: lines.reverse() };
361
+ }
44
362
  function readJsonBody(req, limit) {
45
363
  return new Promise((resolve, reject) => {
46
364
  let size = 0;
@@ -73,10 +391,18 @@ function writeJson(res, status, body) {
73
391
  res.end(JSON.stringify(body));
74
392
  }
75
393
  function devLogsPlugin(options = {}) {
76
- const { logDir = process.env.LOG_DIR || './logs', fileName = 'browser.log', bodyLimit = DEFAULT_BODY_LIMIT, basePath = '', } = options;
394
+ const { logDir = process.env.LOG_DIR || './logs', fileName = 'client.log', bodyLimit = DEFAULT_BODY_LIMIT, basePath = '', } = options;
77
395
  const absLogDir = path.isAbsolute(logDir) ? logDir : path.join(process.cwd(), logDir);
78
396
  const filePath = path.join(absLogDir, fileName);
397
+ const collectPath = `${basePath}/dev/logs/collect`;
79
398
  const collectBatchPath = `${basePath}/dev/logs/collect-batch`;
399
+ const filesPrefix = `${basePath}/dev/logs/files/`;
400
+ const serverLogsPath = `${basePath}/dev/logs/server-logs`;
401
+ const serverLogsStreamPath = `${basePath}/dev/logs/server-logs/stream`;
402
+ function appendOne(entry) {
403
+ const line = JSON.stringify({ ...entry, server_time: new Date().toISOString() }) + '\n';
404
+ return fs.promises.appendFile(filePath, line);
405
+ }
80
406
  function appendMany(entries) {
81
407
  const ts = new Date().toISOString();
82
408
  const lines = entries.map((e) => JSON.stringify({ ...e, server_time: ts }) + '\n').join('');
@@ -87,26 +413,121 @@ function devLogsPlugin(options = {}) {
87
413
  apply: 'serve',
88
414
  configureServer(server) {
89
415
  ensureDir(absLogDir);
90
- // dev 启动即创建空日志文件('a' 模式不截断已有内容),读取方无需处理“文件尚不存在”,
91
- // 行为对齐 dev.js 写的 *.std.log(startProcess 启动即 openSync 'a')。
92
- try {
93
- fs.closeSync(fs.openSync(filePath, 'a'));
94
- }
95
- catch {
96
- /* 创建失败不阻断 dev server 启动 */
97
- }
416
+ // SSE 复用一份 watcher(首个连接开 watcher、最后一个连接关)
417
+ const watcher = new LogWatcher();
418
+ const sseClients = new Set();
98
419
  server.middlewares.use(async (req, res, next) => {
99
420
  const url = req.url?.split('?')[0] ?? '';
100
- // 唯一接口:POST /dev/logs/collect-batch —— 浏览器批量上报,追加写入 browser.log
101
- if (req.method === 'POST' && url === collectBatchPath) {
421
+ // ── SSE:GET /dev/logs/server-logs/stream ───────────────────────────
422
+ // 必须放在 /server-logs 前面:/server-logs/stream 也是 /server-logs 开头
423
+ if (req.method === 'GET' && url === serverLogsStreamPath) {
424
+ res.setHeader('Content-Type', 'text/event-stream');
425
+ res.setHeader('Cache-Control', 'no-cache');
426
+ res.setHeader('Connection', 'keep-alive');
427
+ res.setHeader('X-Accel-Buffering', 'no');
428
+ // SSE 长连接:禁用 socket timeout
429
+ res.socket?.setTimeout(0);
430
+ const clientId = `sse_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
431
+ sseClients.add(res);
432
+ if (watcher.getSubscriberCount() === 0)
433
+ watcher.start(absLogDir);
434
+ const sendEvent = (event, data) => {
435
+ try {
436
+ res.write(formatSSE(event, data));
437
+ return true;
438
+ }
439
+ catch {
440
+ return false;
441
+ }
442
+ };
443
+ const unsubscribe = watcher.onLog((entry) => sendEvent('log', entry));
444
+ sendEvent('connected', { clientId, timestamp: Date.now() });
445
+ const heartbeat = setInterval(() => {
446
+ if (!sendEvent('heartbeat', { timestamp: Date.now() }))
447
+ clearInterval(heartbeat);
448
+ }, 30000);
449
+ const cleanup = () => {
450
+ clearInterval(heartbeat);
451
+ unsubscribe();
452
+ sseClients.delete(res);
453
+ if (watcher.getSubscriberCount() === 0)
454
+ watcher.stop();
455
+ };
456
+ req.on('close', cleanup);
457
+ req.on('error', cleanup);
458
+ return;
459
+ }
460
+ // ── 读取合并日志:GET /dev/logs/server-logs ─────────────────────────
461
+ if (req.method === 'GET' && url === serverLogsPath) {
462
+ const qs = new URLSearchParams(req.url?.split('?')[1] || '');
463
+ const limit = parseLimit(qs.get('limit') ?? undefined, 100, 1000);
464
+ const offset = parsePositiveInt(qs.get('offset') ?? undefined, 0);
465
+ const levels = qs.get('levels')?.split(',').map((s) => s.trim()).filter(Boolean);
466
+ const sources = qs.get('sources')?.split(',').map((s) => s.trim()).filter(Boolean);
102
467
  try {
103
- const body = (await readJsonBody(req, bodyLimit));
104
- if (!Array.isArray(body)) {
105
- writeJson(res, 400, { message: 'logContents must be an array' });
468
+ const result = await readServerLogs(absLogDir, { limit, offset, levels, sources });
469
+ if (!result) {
470
+ writeJson(res, 404, {
471
+ message: 'No log files found',
472
+ hint: `Expected files: ${LOG_FILES.map((c) => c.fileName).join(', ')}`,
473
+ });
474
+ return;
475
+ }
476
+ writeJson(res, 200, result);
477
+ }
478
+ catch (e) {
479
+ const message = e instanceof Error ? e.message : String(e);
480
+ writeJson(res, 500, { message: 'Failed to read server logs', error: { message } });
481
+ }
482
+ return;
483
+ }
484
+ // ── 读取单文件:GET /dev/logs/files/:fileName ──────────────────────
485
+ if (req.method === 'GET' && url.startsWith(filesPrefix)) {
486
+ const fileName = decodeURIComponent(url.slice(filesPrefix.length));
487
+ if (!fileName) {
488
+ writeJson(res, 400, { message: 'fileName is required' });
489
+ return;
490
+ }
491
+ // 解析 query string
492
+ const qs = new URLSearchParams(req.url?.split('?')[1] || '');
493
+ const page = parsePositiveInt(qs.get('page') ?? undefined, 1);
494
+ const pageSize = parseLimit(qs.get('pageSize') ?? undefined, 200, 2000);
495
+ try {
496
+ const filePath = resolveLogFilePath(absLogDir, fileName);
497
+ const result = await readLogFilePage(filePath, page, pageSize);
498
+ if (!result) {
499
+ writeJson(res, 404, { message: 'log file not found', file: fileName });
106
500
  return;
107
501
  }
108
- await appendMany(body);
109
- writeJson(res, 200, { success: true });
502
+ writeJson(res, 200, { file: path.relative(absLogDir, filePath), ...result });
503
+ }
504
+ catch (e) {
505
+ const message = e instanceof Error ? e.message : String(e);
506
+ writeJson(res, 500, { message: 'Failed to read log file', error: { message } });
507
+ }
508
+ return;
509
+ }
510
+ // ── 写入:POST /dev/logs/collect{,-batch} ───────────────────────────
511
+ if (req.method === 'POST' && (url === collectPath || url === collectBatchPath)) {
512
+ try {
513
+ const body = (await readJsonBody(req, bodyLimit));
514
+ if (url === collectPath) {
515
+ const entry = body;
516
+ if (!entry?.message) {
517
+ writeJson(res, 400, { message: 'message is required' });
518
+ return;
519
+ }
520
+ await appendOne(entry);
521
+ writeJson(res, 200, { success: true });
522
+ }
523
+ else {
524
+ if (!Array.isArray(body)) {
525
+ writeJson(res, 400, { message: 'logContents must be an array' });
526
+ return;
527
+ }
528
+ await appendMany(body);
529
+ writeJson(res, 200, { success: true });
530
+ }
110
531
  }
111
532
  catch (e) {
112
533
  const message = e instanceof Error ? e.message : String(e);
@@ -1 +1 @@
1
- {"version":3,"file":"dev-logs.js","sourceRoot":"","sources":["../../src/plugins/dev-logs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dev-logs.js","sourceRoot":"","sources":["../../src/plugins/dev-logs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"vite-client-patch.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-client-patch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC,wBAAgB,qBAAqB,IAAI,MAAM,CAyC9C;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"vite-client-patch.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-client-patch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AA0BnC,wBAAgB,qBAAqB,IAAI,MAAM,CA2D9C;AAED,eAAe,qBAAqB,CAAC"}
@@ -15,6 +15,12 @@ exports.viteClientPatchPlugin = viteClientPatchPlugin;
15
15
  * 仅 dev(`apply: 'serve'`)。
16
16
  */
17
17
  const RECONNECT_RELOAD_PATTERN = /(await waitForSuccessfulPing\(url\.href\);)\r?\n(\s*)location\.reload\(\);/;
18
+ /**
19
+ * 匹配 @vite/client 顶层那处悬空的 HMR 建链调用(无 .catch):
20
+ * transport.connect(createHMRHandler(handleMessage));
21
+ * 已实测 Vite 7.3.x / 8.0.x 文本一致;负向先行避免重复 patch(幂等)。
22
+ */
23
+ const CONNECT_PATTERN = /transport\.connect\(createHMRHandler\(handleMessage\)\)(?!\s*\.catch)(\s*;)?/;
18
24
  function viteClientPatchPlugin() {
19
25
  return {
20
26
  name: 'miaoda-vite-client-patch',
@@ -44,6 +50,19 @@ function viteClientPatchPlugin() {
44
50
  'sandbox_token NOT injected — Vite client.mjs may have changed.');
45
51
  }
46
52
  }
53
+ // patch 3: 给悬空的 transport.connect 补 .catch
54
+ // HMR 建链失败时(hmrPort 存在 → client.mjs 内 `throw e`),这个无 .catch 的
55
+ // 悬空 Promise reject 会变成 unhandledrejection("WebSocket closed without opened." 等),
56
+ // 冒泡到全局 / 下游 React ErrorBoundary,把 dev 建链失败升级成运行态渲染失败。
57
+ // 只截最终这一跳,不动 Vite 内部 reject / fallback / reconnect 逻辑。
58
+ if (CONNECT_PATTERN.test(patched)) {
59
+ patched = patched.replace(CONNECT_PATTERN, "transport.connect(createHMRHandler(handleMessage)).catch((e) => { " +
60
+ "console.warn('[miaoda-vite-client-patch] HMR connect failed (ignored):', e); });");
61
+ }
62
+ else {
63
+ console.warn('[miaoda-vite-client-patch] `transport.connect(createHMRHandler(handleMessage))` ' +
64
+ 'call not found in @vite/client; closed-error guard NOT applied — Vite client.mjs may have changed.');
65
+ }
47
66
  return patched === code ? undefined : { code: patched };
48
67
  },
49
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"vite-client-patch.js","sourceRoot":"","sources":["../../src/plugins/vite-client-patch.ts"],"names":[],"mappings":";;AAkBA,sDAyCC;AAzDD;;;;;;;;;;;;GAYG;AACH,MAAM,wBAAwB,GAC5B,4EAA4E,CAAC;AAE/E,SAAgB,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,OAAO;QAEd,SAAS,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;gBAAE,OAAO;YAExD,IAAI,OAAO,GAAG,IAAI,CAAC;YAEnB,wCAAwC;YACxC,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;YACjF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CACV,iFAAiF;oBAC/E,uDAAuD,CAC1D,CAAC;YACJ,CAAC;YAED,4DAA4D;YAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACpD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC1C,MAAM,OAAO,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;oBAChD,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,wBAAwB,EACxB,GAAG,EAAE,CAAC,oCAAoC,OAAO,EAAE,CACpD,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CACV,2EAA2E;wBACzE,gEAAgE,CACnE,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,kBAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"vite-client-patch.js","sourceRoot":"","sources":["../../src/plugins/vite-client-patch.ts"],"names":[],"mappings":";;AA0BA,sDA2DC;AAnFD;;;;;;;;;;;;GAYG;AACH,MAAM,wBAAwB,GAC5B,4EAA4E,CAAC;AAE/E;;;;GAIG;AACH,MAAM,eAAe,GACnB,8EAA8E,CAAC;AAEjF,SAAgB,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,OAAO;QAEd,SAAS,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;gBAAE,OAAO;YAExD,IAAI,OAAO,GAAG,IAAI,CAAC;YAEnB,wCAAwC;YACxC,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;YACjF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CACV,iFAAiF;oBAC/E,uDAAuD,CAC1D,CAAC;YACJ,CAAC;YAED,4DAA4D;YAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACpD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC1C,MAAM,OAAO,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;oBAChD,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,wBAAwB,EACxB,GAAG,EAAE,CAAC,oCAAoC,OAAO,EAAE,CACpD,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CACV,2EAA2E;wBACzE,gEAAgE,CACnE,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,2CAA2C;YAC3C,8DAA8D;YAC9D,kFAAkF;YAClF,uDAAuD;YACvD,uDAAuD;YACvD,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,eAAe,EACf,oEAAoE;oBAClE,kFAAkF,CACrF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CACV,kFAAkF;oBAChF,oGAAoG,CACvG,CAAC;YACJ,CAAC;YAED,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,kBAAe,qBAAqB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-preset-vite-react",
3
- "version": "1.0.3-alpha.8",
3
+ "version": "1.0.3",
4
4
  "description": "Vite 8 preset for miaoda-coding vite-react (jsPage) templates — pure frontend, no fullstack baggage",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -404,10 +404,22 @@ if (!window.__VITE_ERROR_OVERLAY_INITIALIZED__) {
404
404
  );
405
405
  }
406
406
 
407
+ // 检测 Vite HMR / WebSocket 建链族错误(dev-only,仅影响热更新,不应渲染错误页)
408
+ // 兜底:即便源头 client patch 失效,这些错误也不会被升级成全屏「页面出错了」
409
+ function isHmrConnectionError(error) {
410
+ const message = (error && error.message) || '';
411
+ return (
412
+ /WebSocket closed without opened/i.test(message) ||
413
+ /transport was disconnected/i.test(message) ||
414
+ /failed to connect to websocket/i.test(message) ||
415
+ /WebSocket closed/i.test(message)
416
+ );
417
+ }
418
+
407
419
  // 处理运行时错误(与 rspack 对齐)
408
420
  function handleRuntimeError(error) {
409
- // 如果是编译相关的错误,忽略它(会由 vite:error 事件处理)
410
- if (!error || isCompileError(error)) {
421
+ // 编译错误由 vite:error 处理;HMR 连接错误只影响热更新,二者都不渲染错误页
422
+ if (!error || isCompileError(error) || isHmrConnectionError(error)) {
411
423
  return;
412
424
  }
413
425