@lark-apaas/devtool-kits 1.2.11-alpha.1 → 1.2.11-alpha.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.
package/dist/index.js CHANGED
@@ -1465,7 +1465,7 @@ function sendSimpleRedirect(req, res) {
1465
1465
  __name(sendSimpleRedirect, "sendSimpleRedirect");
1466
1466
 
1467
1467
  // src/middlewares/index.ts
1468
- import path6 from "path";
1468
+ import path7 from "path";
1469
1469
 
1470
1470
  // src/middlewares/openapi/router.ts
1471
1471
  import express from "express";
@@ -1809,8 +1809,8 @@ function hasSpecialPatterns(pattern) {
1809
1809
  return /[{*]/.test(pattern);
1810
1810
  }
1811
1811
  __name(hasSpecialPatterns, "hasSpecialPatterns");
1812
- function normalizePathForMatching(path7) {
1813
- return path7.replace(/\/+/g, "/").replace(/\/+$/, "");
1812
+ function normalizePathForMatching(path8) {
1813
+ return path8.replace(/\/+/g, "/").replace(/\/+$/, "");
1814
1814
  }
1815
1815
  __name(normalizePathForMatching, "normalizePathForMatching");
1816
1816
 
@@ -2357,7 +2357,7 @@ __name(readLogsBySource, "readLogsBySource");
2357
2357
  // src/middlewares/dev-logs/services/trigger.service.ts
2358
2358
  import { createReadStream as createReadStream3 } from "fs";
2359
2359
  import { createInterface as createInterface3 } from "readline";
2360
- async function readTriggerList(filePath, trigger, path7, limit, triggerID) {
2360
+ async function readTriggerList(filePath, trigger, path8, limit, triggerID) {
2361
2361
  if (!await fileExists(filePath)) {
2362
2362
  return void 0;
2363
2363
  }
@@ -2383,7 +2383,7 @@ async function readTriggerList(filePath, trigger, path7, limit, triggerID) {
2383
2383
  if (alreadyAdded) {
2384
2384
  return false;
2385
2385
  }
2386
- const isAutomationTrigger = builder.path?.endsWith(path7);
2386
+ const isAutomationTrigger = builder.path?.endsWith(path8);
2387
2387
  if (!isAutomationTrigger) {
2388
2388
  return false;
2389
2389
  }
@@ -2466,7 +2466,7 @@ async function readTriggerList(filePath, trigger, path7, limit, triggerID) {
2466
2466
  };
2467
2467
  }
2468
2468
  __name(readTriggerList, "readTriggerList");
2469
- async function readTriggerDetail(filePath, path7, instanceID) {
2469
+ async function readTriggerDetail(filePath, path8, instanceID) {
2470
2470
  const exists = await fileExists(filePath);
2471
2471
  if (!exists) {
2472
2472
  return void 0;
@@ -2482,7 +2482,7 @@ async function readTriggerDetail(filePath, path7, instanceID) {
2482
2482
  for await (const line of rl) {
2483
2483
  const entry = parseLogLine2(line);
2484
2484
  if (!entry) continue;
2485
- const isAutomationTrigger = entry.path?.endsWith(path7);
2485
+ const isAutomationTrigger = entry.path?.endsWith(path8);
2486
2486
  const hasInstanceID = entry.instance_id === instanceID && entry.trigger;
2487
2487
  if (!isAutomationTrigger || !hasInstanceID) continue;
2488
2488
  matches.push(entry);
@@ -2736,16 +2736,16 @@ function createGetTriggerListHandler(logDir) {
2736
2736
  });
2737
2737
  }
2738
2738
  const triggerID = typeof req.query.triggerID === "string" ? req.query.triggerID.trim() : void 0;
2739
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2739
+ const path8 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2740
2740
  const limit = parseLimit(req.query.limit, 10, 200);
2741
2741
  try {
2742
- const result = await readTriggerList(traceLogPath, trigger, path7, limit, triggerID);
2742
+ const result = await readTriggerList(traceLogPath, trigger, path8, limit, triggerID);
2743
2743
  if (!result) {
2744
2744
  return handleNotFound(res, traceLogPath);
2745
2745
  }
2746
2746
  res.json({
2747
2747
  file: getRelativePath(traceLogPath),
2748
- path: path7,
2748
+ path: path8,
2749
2749
  ...result
2750
2750
  });
2751
2751
  } catch (error) {
@@ -2763,9 +2763,9 @@ function createGetTriggerDetailHandler(logDir) {
2763
2763
  message: "instanceID is required"
2764
2764
  });
2765
2765
  }
2766
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2766
+ const path8 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2767
2767
  try {
2768
- const result = await readTriggerDetail(traceLogPath, path7, instanceID);
2768
+ const result = await readTriggerDetail(traceLogPath, path8, instanceID);
2769
2769
  if (!result) {
2770
2770
  return handleNotFound(res, traceLogPath);
2771
2771
  }
@@ -2872,6 +2872,521 @@ function createHealthCheckHandler(options = {}) {
2872
2872
  }
2873
2873
  __name(createHealthCheckHandler, "createHealthCheckHandler");
2874
2874
 
2875
+ // src/middlewares/dev-logs/sse/log-watcher.ts
2876
+ import * as fs9 from "fs";
2877
+ import * as path6 from "path";
2878
+ function mapPinoLevelToServerLogLevel2(pinoLevel) {
2879
+ if (typeof pinoLevel === "string") {
2880
+ const lower = pinoLevel.toLowerCase();
2881
+ if (lower === "fatal") return "fatal";
2882
+ if (lower === "error") return "error";
2883
+ if (lower === "warn" || lower === "warning") return "warn";
2884
+ if (lower === "info" || lower === "log") return "log";
2885
+ if (lower === "debug") return "debug";
2886
+ if (lower === "trace" || lower === "verbose") return "verbose";
2887
+ return "log";
2888
+ }
2889
+ if (pinoLevel >= 60) return "fatal";
2890
+ if (pinoLevel >= 50) return "error";
2891
+ if (pinoLevel >= 40) return "warn";
2892
+ if (pinoLevel >= 30) return "log";
2893
+ if (pinoLevel >= 20) return "debug";
2894
+ return "verbose";
2895
+ }
2896
+ __name(mapPinoLevelToServerLogLevel2, "mapPinoLevelToServerLogLevel");
2897
+ function extractLogLevel2(text) {
2898
+ const lower = text.toLowerCase();
2899
+ if (lower.includes("fatal") || lower.includes("critical")) return "fatal";
2900
+ if (lower.includes("error") || lower.includes("<e>") || lower.includes("\u2716")) return "error";
2901
+ if (lower.includes("warn") || lower.includes("warning") || lower.includes("<w>") || lower.includes("\u26A0")) return "warn";
2902
+ if (lower.includes("debug") || lower.includes("<d>")) return "debug";
2903
+ if (lower.includes("verbose") || lower.includes("trace")) return "verbose";
2904
+ return "log";
2905
+ }
2906
+ __name(extractLogLevel2, "extractLogLevel");
2907
+ function generateUUID2() {
2908
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
2909
+ const r = Math.random() * 16 | 0;
2910
+ const v = c === "x" ? r : r & 3 | 8;
2911
+ return v.toString(16);
2912
+ });
2913
+ }
2914
+ __name(generateUUID2, "generateUUID");
2915
+ function parsePinoLog2(line, source) {
2916
+ try {
2917
+ const pinoLog = JSON.parse(line);
2918
+ const id = generateUUID2();
2919
+ return {
2920
+ id,
2921
+ level: mapPinoLevelToServerLogLevel2(pinoLog.level),
2922
+ timestamp: new Date(pinoLog.time).getTime(),
2923
+ message: pinoLog.message || pinoLog.msg || "",
2924
+ context: pinoLog.context || null,
2925
+ traceId: pinoLog.trace_id || null,
2926
+ userId: pinoLog.user_id || null,
2927
+ appId: pinoLog.app_id || null,
2928
+ tenantId: pinoLog.tenant_id || null,
2929
+ stack: pinoLog.stack || null,
2930
+ meta: {
2931
+ pid: pinoLog.pid,
2932
+ hostname: pinoLog.hostname,
2933
+ path: pinoLog.path,
2934
+ method: pinoLog.method,
2935
+ statusCode: pinoLog.status_code,
2936
+ durationMs: pinoLog.duration_ms,
2937
+ ip: pinoLog.ip,
2938
+ requestBody: pinoLog.request_body,
2939
+ responseBody: pinoLog.response_body
2940
+ },
2941
+ tags: [
2942
+ source
2943
+ ]
2944
+ };
2945
+ } catch {
2946
+ return null;
2947
+ }
2948
+ }
2949
+ __name(parsePinoLog2, "parsePinoLog");
2950
+ function parseStdLog2(line, source) {
2951
+ const id = generateUUID2();
2952
+ const match = line.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(server|client)\] (.*)$/);
2953
+ if (!match) {
2954
+ return {
2955
+ id,
2956
+ level: extractLogLevel2(line),
2957
+ timestamp: Date.now(),
2958
+ message: line,
2959
+ context: null,
2960
+ traceId: null,
2961
+ userId: null,
2962
+ appId: null,
2963
+ tenantId: null,
2964
+ stack: null,
2965
+ meta: null,
2966
+ tags: [
2967
+ source
2968
+ ]
2969
+ };
2970
+ }
2971
+ const [, timeStr, , content] = match;
2972
+ let timestamp;
2973
+ try {
2974
+ const isoStr = timeStr.replace(" ", "T");
2975
+ timestamp = new Date(isoStr).getTime();
2976
+ if (isNaN(timestamp)) {
2977
+ timestamp = Date.now();
2978
+ }
2979
+ } catch {
2980
+ timestamp = Date.now();
2981
+ }
2982
+ return {
2983
+ id,
2984
+ level: extractLogLevel2(content),
2985
+ timestamp,
2986
+ message: content,
2987
+ context: null,
2988
+ traceId: null,
2989
+ userId: null,
2990
+ appId: null,
2991
+ tenantId: null,
2992
+ stack: null,
2993
+ meta: null,
2994
+ tags: [
2995
+ source
2996
+ ]
2997
+ };
2998
+ }
2999
+ __name(parseStdLog2, "parseStdLog");
3000
+ var LogWatcher = class {
3001
+ static {
3002
+ __name(this, "LogWatcher");
3003
+ }
3004
+ logDir = "";
3005
+ watchers = /* @__PURE__ */ new Map();
3006
+ filePositions = /* @__PURE__ */ new Map();
3007
+ subscribers = /* @__PURE__ */ new Set();
3008
+ isRunning = false;
3009
+ debug = false;
3010
+ logFiles = [
3011
+ {
3012
+ fileName: "server.log",
3013
+ source: "server",
3014
+ parser: parsePinoLog2
3015
+ },
3016
+ {
3017
+ fileName: "trace.log",
3018
+ source: "trace",
3019
+ parser: parsePinoLog2
3020
+ },
3021
+ {
3022
+ fileName: "server.std.log",
3023
+ source: "server-std",
3024
+ parser: parseStdLog2
3025
+ },
3026
+ {
3027
+ fileName: "client.std.log",
3028
+ source: "client-std",
3029
+ parser: parseStdLog2
3030
+ }
3031
+ ];
3032
+ constructor(options = {}) {
3033
+ this.debug = options.debug ?? false;
3034
+ }
3035
+ log(...args) {
3036
+ if (this.debug) {
3037
+ console.log("[LogWatcher]", ...args);
3038
+ }
3039
+ }
3040
+ /**
3041
+ * Start watching log files
3042
+ */
3043
+ start(logDir) {
3044
+ if (this.isRunning) {
3045
+ this.log("Already running, ignoring start call");
3046
+ return;
3047
+ }
3048
+ this.logDir = logDir;
3049
+ this.isRunning = true;
3050
+ this.log(`Starting to watch log files in: ${logDir}`);
3051
+ for (const config of this.logFiles) {
3052
+ this.watchFile(config);
3053
+ }
3054
+ }
3055
+ /**
3056
+ * Stop watching all files
3057
+ */
3058
+ stop() {
3059
+ if (!this.isRunning) {
3060
+ return;
3061
+ }
3062
+ this.log("Stopping file watchers");
3063
+ this.isRunning = false;
3064
+ Array.from(this.watchers.entries()).forEach(([fileName, watcher]) => {
3065
+ watcher.close();
3066
+ this.log(`Closed watcher for: ${fileName}`);
3067
+ });
3068
+ this.watchers.clear();
3069
+ this.filePositions.clear();
3070
+ }
3071
+ /**
3072
+ * Subscribe to new log events
3073
+ */
3074
+ onLog(callback) {
3075
+ this.subscribers.add(callback);
3076
+ this.log(`Subscriber added, total: ${this.subscribers.size}`);
3077
+ return () => {
3078
+ this.subscribers.delete(callback);
3079
+ this.log(`Subscriber removed, total: ${this.subscribers.size}`);
3080
+ };
3081
+ }
3082
+ /**
3083
+ * Get subscriber count
3084
+ */
3085
+ getSubscriberCount() {
3086
+ return this.subscribers.size;
3087
+ }
3088
+ /**
3089
+ * Watch a single log file
3090
+ */
3091
+ watchFile(config) {
3092
+ const filePath = path6.join(this.logDir, config.fileName);
3093
+ if (!fs9.existsSync(filePath)) {
3094
+ this.log(`File not found, skipping: ${config.fileName}`);
3095
+ return;
3096
+ }
3097
+ try {
3098
+ const stats = fs9.statSync(filePath);
3099
+ this.filePositions.set(config.fileName, stats.size);
3100
+ this.log(`Initialized position for ${config.fileName}: ${stats.size} bytes`);
3101
+ } catch (error) {
3102
+ this.log(`Failed to get initial position for ${config.fileName}:`, error);
3103
+ this.filePositions.set(config.fileName, 0);
3104
+ }
3105
+ try {
3106
+ const watcher = fs9.watch(filePath, (eventType) => {
3107
+ if (eventType === "change") {
3108
+ this.handleFileChange(config);
3109
+ }
3110
+ });
3111
+ watcher.on("error", (error) => {
3112
+ this.log(`Watcher error for ${config.fileName}:`, error);
3113
+ this.restartWatcher(config);
3114
+ });
3115
+ this.watchers.set(config.fileName, watcher);
3116
+ this.log(`Started watching: ${config.fileName}`);
3117
+ } catch (error) {
3118
+ this.log(`Failed to start watcher for ${config.fileName}:`, error);
3119
+ }
3120
+ }
3121
+ /**
3122
+ * Restart a file watcher after error
3123
+ */
3124
+ restartWatcher(config) {
3125
+ const existingWatcher = this.watchers.get(config.fileName);
3126
+ if (existingWatcher) {
3127
+ existingWatcher.close();
3128
+ this.watchers.delete(config.fileName);
3129
+ }
3130
+ setTimeout(() => {
3131
+ if (this.isRunning) {
3132
+ this.log(`Restarting watcher for: ${config.fileName}`);
3133
+ this.watchFile(config);
3134
+ }
3135
+ }, 1e3);
3136
+ }
3137
+ /**
3138
+ * Handle file change event - read new content
3139
+ */
3140
+ handleFileChange(config) {
3141
+ const filePath = path6.join(this.logDir, config.fileName);
3142
+ const lastPosition = this.filePositions.get(config.fileName) || 0;
3143
+ try {
3144
+ const stats = fs9.statSync(filePath);
3145
+ const currentSize = stats.size;
3146
+ if (currentSize < lastPosition) {
3147
+ this.log(`File ${config.fileName} was truncated, resetting position`);
3148
+ this.filePositions.set(config.fileName, 0);
3149
+ this.handleFileChange(config);
3150
+ return;
3151
+ }
3152
+ if (currentSize === lastPosition) {
3153
+ return;
3154
+ }
3155
+ const readSize = currentSize - lastPosition;
3156
+ const buffer = Buffer.alloc(readSize);
3157
+ const fd = fs9.openSync(filePath, "r");
3158
+ try {
3159
+ fs9.readSync(fd, buffer, 0, readSize, lastPosition);
3160
+ } finally {
3161
+ fs9.closeSync(fd);
3162
+ }
3163
+ this.filePositions.set(config.fileName, currentSize);
3164
+ const content = buffer.toString("utf8");
3165
+ const lines = content.split("\n");
3166
+ for (const line of lines) {
3167
+ if (!line.trim()) continue;
3168
+ try {
3169
+ const log = config.parser(line, config.source);
3170
+ if (log) {
3171
+ this.notifySubscribers(log);
3172
+ }
3173
+ } catch {
3174
+ }
3175
+ }
3176
+ } catch (error) {
3177
+ this.log(`Error reading file ${config.fileName}:`, error);
3178
+ }
3179
+ }
3180
+ /**
3181
+ * Notify all subscribers of new log
3182
+ */
3183
+ notifySubscribers(log) {
3184
+ Array.from(this.subscribers).forEach((subscriber) => {
3185
+ try {
3186
+ subscriber(log);
3187
+ } catch (error) {
3188
+ this.log("Subscriber error:", error);
3189
+ }
3190
+ });
3191
+ }
3192
+ };
3193
+
3194
+ // src/middlewares/dev-logs/sse/client-manager.ts
3195
+ var ClientManager = class {
3196
+ static {
3197
+ __name(this, "ClientManager");
3198
+ }
3199
+ clients = /* @__PURE__ */ new Map();
3200
+ debug = false;
3201
+ constructor(options = {}) {
3202
+ this.debug = options.debug ?? false;
3203
+ }
3204
+ log(...args) {
3205
+ if (this.debug) {
3206
+ console.log("[ClientManager]", ...args);
3207
+ }
3208
+ }
3209
+ /**
3210
+ * Generate a unique client ID
3211
+ */
3212
+ generateClientId() {
3213
+ return `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
3214
+ }
3215
+ /**
3216
+ * Add a new client connection
3217
+ */
3218
+ addClient(id, res) {
3219
+ this.clients.set(id, {
3220
+ id,
3221
+ res,
3222
+ connectedAt: Date.now()
3223
+ });
3224
+ this.log(`Client connected: ${id}, total clients: ${this.clients.size}`);
3225
+ }
3226
+ /**
3227
+ * Remove a client connection
3228
+ */
3229
+ removeClient(id) {
3230
+ if (this.clients.has(id)) {
3231
+ this.clients.delete(id);
3232
+ this.log(`Client disconnected: ${id}, total clients: ${this.clients.size}`);
3233
+ }
3234
+ }
3235
+ /**
3236
+ * Get current client count
3237
+ */
3238
+ getClientCount() {
3239
+ return this.clients.size;
3240
+ }
3241
+ /**
3242
+ * Check if a client exists
3243
+ */
3244
+ hasClient(id) {
3245
+ return this.clients.has(id);
3246
+ }
3247
+ /**
3248
+ * Send SSE event to a specific client
3249
+ */
3250
+ sendToClient(clientId, event, data) {
3251
+ const client = this.clients.get(clientId);
3252
+ if (!client) {
3253
+ return false;
3254
+ }
3255
+ try {
3256
+ const message = this.formatSSEMessage(event, data);
3257
+ client.res.write(message);
3258
+ return true;
3259
+ } catch (error) {
3260
+ this.log(`Failed to send to client ${clientId}:`, error);
3261
+ this.removeClient(clientId);
3262
+ return false;
3263
+ }
3264
+ }
3265
+ /**
3266
+ * Broadcast SSE event to all clients
3267
+ */
3268
+ broadcast(event, data) {
3269
+ const message = this.formatSSEMessage(event, data);
3270
+ const failedClients = [];
3271
+ Array.from(this.clients.entries()).forEach(([id, client]) => {
3272
+ try {
3273
+ client.res.write(message);
3274
+ } catch (error) {
3275
+ this.log(`Broadcast failed for client ${id}:`, error);
3276
+ failedClients.push(id);
3277
+ }
3278
+ });
3279
+ failedClients.forEach((id) => {
3280
+ this.removeClient(id);
3281
+ });
3282
+ }
3283
+ /**
3284
+ * Format SSE message
3285
+ * SSE format: event: <event>\ndata: <json>\n\n
3286
+ */
3287
+ formatSSEMessage(event, data) {
3288
+ const jsonData = JSON.stringify(data);
3289
+ return `event: ${event}
3290
+ data: ${jsonData}
3291
+
3292
+ `;
3293
+ }
3294
+ /**
3295
+ * Get all client IDs
3296
+ */
3297
+ getClientIds() {
3298
+ return Array.from(this.clients.keys());
3299
+ }
3300
+ /**
3301
+ * Get client info
3302
+ */
3303
+ getClientInfo(id) {
3304
+ const client = this.clients.get(id);
3305
+ if (!client) {
3306
+ return null;
3307
+ }
3308
+ return {
3309
+ id: client.id,
3310
+ connectedAt: client.connectedAt
3311
+ };
3312
+ }
3313
+ /**
3314
+ * Close all client connections
3315
+ */
3316
+ closeAll() {
3317
+ this.log(`Closing all ${this.clients.size} clients`);
3318
+ Array.from(this.clients.entries()).forEach(([id, client]) => {
3319
+ try {
3320
+ client.res.end();
3321
+ } catch (error) {
3322
+ this.log(`Error closing client ${id}:`, error);
3323
+ }
3324
+ });
3325
+ this.clients.clear();
3326
+ }
3327
+ };
3328
+
3329
+ // src/middlewares/dev-logs/sse/sse.controller.ts
3330
+ function createSSEHandler(logDir, options = {}) {
3331
+ const { debug = false, heartbeatInterval = 3e4 } = options;
3332
+ const logWatcher = new LogWatcher({
3333
+ debug
3334
+ });
3335
+ const clientManager = new ClientManager({
3336
+ debug
3337
+ });
3338
+ const log = /* @__PURE__ */ __name((...args) => {
3339
+ if (debug) {
3340
+ console.log("[SSEHandler]", ...args);
3341
+ }
3342
+ }, "log");
3343
+ return (req, res) => {
3344
+ res.setHeader("Content-Type", "text/event-stream");
3345
+ res.setHeader("Cache-Control", "no-cache");
3346
+ res.setHeader("Connection", "keep-alive");
3347
+ res.setHeader("X-Accel-Buffering", "no");
3348
+ res.setTimeout(0);
3349
+ const clientId = clientManager.generateClientId();
3350
+ clientManager.addClient(clientId, res);
3351
+ log(`New SSE connection: ${clientId}`);
3352
+ if (clientManager.getClientCount() === 1) {
3353
+ log("First client connected, starting log watcher");
3354
+ logWatcher.start(logDir);
3355
+ }
3356
+ const unsubscribe = logWatcher.onLog((logEntry) => {
3357
+ clientManager.sendToClient(clientId, "log", logEntry);
3358
+ });
3359
+ clientManager.sendToClient(clientId, "connected", {
3360
+ clientId,
3361
+ timestamp: Date.now()
3362
+ });
3363
+ const heartbeat = setInterval(() => {
3364
+ const success = clientManager.sendToClient(clientId, "heartbeat", {
3365
+ timestamp: Date.now()
3366
+ });
3367
+ if (!success) {
3368
+ clearInterval(heartbeat);
3369
+ }
3370
+ }, heartbeatInterval);
3371
+ const cleanup = /* @__PURE__ */ __name(() => {
3372
+ log(`Client disconnected: ${clientId}`);
3373
+ clearInterval(heartbeat);
3374
+ unsubscribe();
3375
+ clientManager.removeClient(clientId);
3376
+ if (clientManager.getClientCount() === 0) {
3377
+ log("No more clients, stopping log watcher");
3378
+ logWatcher.stop();
3379
+ }
3380
+ }, "cleanup");
3381
+ req.on("close", cleanup);
3382
+ req.on("error", (error) => {
3383
+ log(`Client error ${clientId}:`, error);
3384
+ cleanup();
3385
+ });
3386
+ };
3387
+ }
3388
+ __name(createSSEHandler, "createSSEHandler");
3389
+
2875
3390
  // src/middlewares/dev-logs/router.ts
2876
3391
  function createDevLogRouter(options = {}) {
2877
3392
  const logDir = resolveLogDir(options.logDir);
@@ -2880,6 +3395,7 @@ function createDevLogRouter(options = {}) {
2880
3395
  router.get("/trace/recent", createGetRecentTracesHandler(logDir));
2881
3396
  router.get("/files/:fileName", createGetLogFileHandler(logDir));
2882
3397
  router.get("/server-logs", createGetServerLogsHandler(logDir));
3398
+ router.get("/server-logs/stream", createSSEHandler(logDir));
2883
3399
  router.get("/trace/trigger/list", createGetTriggerListHandler(logDir));
2884
3400
  router.get("/trace/trigger/:instanceID", createGetTriggerDetailHandler(logDir));
2885
3401
  router.get("/trace/capability/list", createGetCapabilityTraceListHandler(logDir));
@@ -2941,22 +3457,22 @@ __name(createDevLogsMiddleware, "createDevLogsMiddleware");
2941
3457
  import express3 from "express";
2942
3458
 
2943
3459
  // src/middlewares/collect-logs/controller.ts
2944
- import { join as join6 } from "path";
2945
- import fs10 from "fs";
3460
+ import { join as join7 } from "path";
3461
+ import fs11 from "fs";
2946
3462
 
2947
3463
  // src/middlewares/collect-logs/utils.ts
2948
- import { isAbsolute as isAbsolute2, join as join5 } from "path";
2949
- import fs9 from "fs";
3464
+ import { isAbsolute as isAbsolute2, join as join6 } from "path";
3465
+ import fs10 from "fs";
2950
3466
  function resolveLogDir2(provided) {
2951
3467
  if (!provided) {
2952
- return join5(process.cwd(), "logs");
3468
+ return join6(process.cwd(), "logs");
2953
3469
  }
2954
- return isAbsolute2(provided) ? provided : join5(process.cwd(), provided);
3470
+ return isAbsolute2(provided) ? provided : join6(process.cwd(), provided);
2955
3471
  }
2956
3472
  __name(resolveLogDir2, "resolveLogDir");
2957
3473
  function ensureDir(dir) {
2958
- if (!fs9.existsSync(dir)) {
2959
- fs9.mkdirSync(dir, {
3474
+ if (!fs10.existsSync(dir)) {
3475
+ fs10.mkdirSync(dir, {
2960
3476
  recursive: true
2961
3477
  });
2962
3478
  }
@@ -2974,7 +3490,7 @@ __name(serializeError2, "serializeError");
2974
3490
 
2975
3491
  // src/middlewares/collect-logs/controller.ts
2976
3492
  function collectLogsHandler(logDir, fileName) {
2977
- const filePath = join6(logDir, fileName);
3493
+ const filePath = join7(logDir, fileName);
2978
3494
  ensureDir(logDir);
2979
3495
  return async (req, res) => {
2980
3496
  try {
@@ -2988,7 +3504,7 @@ function collectLogsHandler(logDir, fileName) {
2988
3504
  ...logContent,
2989
3505
  server_time: (/* @__PURE__ */ new Date()).toISOString()
2990
3506
  }) + "\n";
2991
- await fs10.promises.appendFile(filePath, logLine);
3507
+ await fs11.promises.appendFile(filePath, logLine);
2992
3508
  res.json({
2993
3509
  success: true
2994
3510
  });
@@ -2999,7 +3515,7 @@ function collectLogsHandler(logDir, fileName) {
2999
3515
  }
3000
3516
  __name(collectLogsHandler, "collectLogsHandler");
3001
3517
  function collectLogsBatchHandler(logDir, fileName) {
3002
- const filePath = join6(logDir, fileName);
3518
+ const filePath = join7(logDir, fileName);
3003
3519
  ensureDir(logDir);
3004
3520
  return async (req, res) => {
3005
3521
  try {
@@ -3016,7 +3532,7 @@ function collectLogsBatchHandler(logDir, fileName) {
3016
3532
  server_time: (/* @__PURE__ */ new Date()).toISOString()
3017
3533
  }) + "\n");
3018
3534
  }
3019
- await fs10.promises.appendFile(filePath, logLines.join(""));
3535
+ await fs11.promises.appendFile(filePath, logLines.join(""));
3020
3536
  res.json({
3021
3537
  success: true
3022
3538
  });
@@ -3079,7 +3595,7 @@ function isGlobalMiddleware(middleware) {
3079
3595
  }
3080
3596
  __name(isGlobalMiddleware, "isGlobalMiddleware");
3081
3597
  function computeMountPath(basePath, mountPath) {
3082
- const routePath = path6.posix.join(basePath, mountPath);
3598
+ const routePath = path7.posix.join(basePath, mountPath);
3083
3599
  return routePath.startsWith("/") ? routePath : `/${routePath}`;
3084
3600
  }
3085
3601
  __name(computeMountPath, "computeMountPath");
@@ -3087,7 +3603,7 @@ function logMiddlewareRegistration(middleware, fullMountPath) {
3087
3603
  if (middleware.routes && middleware.routes.length > 0) {
3088
3604
  console.log(`[Middleware] Registered: ${middleware.name} at ${fullMountPath}`);
3089
3605
  middleware.routes.forEach((route) => {
3090
- const routePath = route.path === "/" ? fullMountPath : path6.posix.join(fullMountPath, route.path);
3606
+ const routePath = route.path === "/" ? fullMountPath : path7.posix.join(fullMountPath, route.path);
3091
3607
  console.log(` ${route.method} ${routePath} - ${route.description}`);
3092
3608
  });
3093
3609
  } else {