@electron-memory/monitor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +105 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +84 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -481,6 +481,12 @@ declare class ElectronMemoryMonitor extends EventEmitter {
|
|
|
481
481
|
private mergeConfig;
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
/**
|
|
485
|
+
* 必须在 app.on('ready') 之前调用(与 new ElectronMemoryMonitor 同文件顶部或更早)。
|
|
486
|
+
* 由 ElectronMemoryMonitor 在启用时于构造函数内调用。
|
|
487
|
+
*/
|
|
488
|
+
declare function registerDashboardSchemePrivileged(): void;
|
|
489
|
+
|
|
484
490
|
/**
|
|
485
491
|
* IPC 通道常量定义
|
|
486
492
|
* 所有通道以 'emm:' 为前缀,避免与业务 IPC 冲突
|
|
@@ -507,4 +513,4 @@ declare const IPC_CHANNELS: {
|
|
|
507
513
|
readonly RENDERER_REQUEST: "emm:renderer:request";
|
|
508
514
|
};
|
|
509
515
|
|
|
510
|
-
export { type AnomalyCategory, type AnomalyEvent, type AnomalyRule, type AnomalySeverity, type CompareReport, ElectronMemoryMonitor, type EventMark, type GCResult, IPC_CHANNELS, type Improvement, type MemorySnapshot, type MetricDiff, type MetricSummary, type MonitorConfig, type ProcessMemoryInfo, type Regression, type RendererV8Detail, type SessionIndex, type SessionReport, type Suggestion, type SystemMemoryInfo, type TestSession, type TrendInfo, type V8HeapDetailStats, type V8HeapSpaceInfo, type V8HeapStats };
|
|
516
|
+
export { type AnomalyCategory, type AnomalyEvent, type AnomalyRule, type AnomalySeverity, type CompareReport, ElectronMemoryMonitor, type EventMark, type GCResult, IPC_CHANNELS, type Improvement, type MemorySnapshot, type MetricDiff, type MetricSummary, type MonitorConfig, type ProcessMemoryInfo, type Regression, type RendererV8Detail, type SessionIndex, type SessionReport, type Suggestion, type SystemMemoryInfo, type TestSession, type TrendInfo, type V8HeapDetailStats, type V8HeapSpaceInfo, type V8HeapStats, registerDashboardSchemePrivileged };
|
package/dist/index.d.ts
CHANGED
|
@@ -481,6 +481,12 @@ declare class ElectronMemoryMonitor extends EventEmitter {
|
|
|
481
481
|
private mergeConfig;
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
/**
|
|
485
|
+
* 必须在 app.on('ready') 之前调用(与 new ElectronMemoryMonitor 同文件顶部或更早)。
|
|
486
|
+
* 由 ElectronMemoryMonitor 在启用时于构造函数内调用。
|
|
487
|
+
*/
|
|
488
|
+
declare function registerDashboardSchemePrivileged(): void;
|
|
489
|
+
|
|
484
490
|
/**
|
|
485
491
|
* IPC 通道常量定义
|
|
486
492
|
* 所有通道以 'emm:' 为前缀,避免与业务 IPC 冲突
|
|
@@ -507,4 +513,4 @@ declare const IPC_CHANNELS: {
|
|
|
507
513
|
readonly RENDERER_REQUEST: "emm:renderer:request";
|
|
508
514
|
};
|
|
509
515
|
|
|
510
|
-
export { type AnomalyCategory, type AnomalyEvent, type AnomalyRule, type AnomalySeverity, type CompareReport, ElectronMemoryMonitor, type EventMark, type GCResult, IPC_CHANNELS, type Improvement, type MemorySnapshot, type MetricDiff, type MetricSummary, type MonitorConfig, type ProcessMemoryInfo, type Regression, type RendererV8Detail, type SessionIndex, type SessionReport, type Suggestion, type SystemMemoryInfo, type TestSession, type TrendInfo, type V8HeapDetailStats, type V8HeapSpaceInfo, type V8HeapStats };
|
|
516
|
+
export { type AnomalyCategory, type AnomalyEvent, type AnomalyRule, type AnomalySeverity, type CompareReport, ElectronMemoryMonitor, type EventMark, type GCResult, IPC_CHANNELS, type Improvement, type MemorySnapshot, type MetricDiff, type MetricSummary, type MonitorConfig, type ProcessMemoryInfo, type Regression, type RendererV8Detail, type SessionIndex, type SessionReport, type Suggestion, type SystemMemoryInfo, type TestSession, type TrendInfo, type V8HeapDetailStats, type V8HeapSpaceInfo, type V8HeapStats, registerDashboardSchemePrivileged };
|
package/dist/index.js
CHANGED
|
@@ -31,13 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
ElectronMemoryMonitor: () => ElectronMemoryMonitor,
|
|
34
|
-
IPC_CHANNELS: () => IPC_CHANNELS
|
|
34
|
+
IPC_CHANNELS: () => IPC_CHANNELS,
|
|
35
|
+
registerDashboardSchemePrivileged: () => registerDashboardSchemePrivileged
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(src_exports);
|
|
37
38
|
|
|
38
39
|
// src/core/monitor.ts
|
|
39
|
-
var
|
|
40
|
-
var
|
|
40
|
+
var import_electron5 = require("electron");
|
|
41
|
+
var path4 = __toESM(require("path"));
|
|
41
42
|
var v82 = __toESM(require("v8"));
|
|
42
43
|
var import_events3 = require("events");
|
|
43
44
|
|
|
@@ -1106,8 +1107,76 @@ var Analyzer = class {
|
|
|
1106
1107
|
};
|
|
1107
1108
|
|
|
1108
1109
|
// src/core/dashboard.ts
|
|
1110
|
+
var import_electron3 = require("electron");
|
|
1111
|
+
var path3 = __toESM(require("path"));
|
|
1112
|
+
|
|
1113
|
+
// src/core/dashboard-protocol.ts
|
|
1109
1114
|
var import_electron2 = require("electron");
|
|
1110
1115
|
var path2 = __toESM(require("path"));
|
|
1116
|
+
var import_node_url = require("url");
|
|
1117
|
+
var SCHEME = "emm-dashboard";
|
|
1118
|
+
var privilegedRegistered = false;
|
|
1119
|
+
var handlerRegistered = false;
|
|
1120
|
+
function isPathInsideRoot(filePath, root) {
|
|
1121
|
+
const f = path2.resolve(filePath);
|
|
1122
|
+
const r = path2.resolve(root);
|
|
1123
|
+
if (f === r) {
|
|
1124
|
+
return true;
|
|
1125
|
+
}
|
|
1126
|
+
const sep2 = r.endsWith(path2.sep) ? r : `${r}${path2.sep}`;
|
|
1127
|
+
return f.startsWith(sep2);
|
|
1128
|
+
}
|
|
1129
|
+
function registerDashboardSchemePrivileged() {
|
|
1130
|
+
if (privilegedRegistered) {
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
privilegedRegistered = true;
|
|
1134
|
+
import_electron2.protocol.registerSchemesAsPrivileged([
|
|
1135
|
+
{
|
|
1136
|
+
scheme: SCHEME,
|
|
1137
|
+
privileges: {
|
|
1138
|
+
standard: true,
|
|
1139
|
+
secure: true,
|
|
1140
|
+
supportFetchAPI: true,
|
|
1141
|
+
corsEnabled: true,
|
|
1142
|
+
stream: true
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
]);
|
|
1146
|
+
}
|
|
1147
|
+
function ensureDashboardProtocolHandler(uiRoot) {
|
|
1148
|
+
if (handlerRegistered) {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
if (!import_electron2.app.isReady()) {
|
|
1152
|
+
throw new Error(
|
|
1153
|
+
"[@electron-memory/monitor] ensureDashboardProtocolHandler: app must be ready before opening dashboard"
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
handlerRegistered = true;
|
|
1157
|
+
const base = path2.resolve(uiRoot);
|
|
1158
|
+
import_electron2.protocol.handle(SCHEME, (request) => {
|
|
1159
|
+
try {
|
|
1160
|
+
const { pathname } = new URL(request.url);
|
|
1161
|
+
let rel = pathname.startsWith("/") ? pathname.slice(1) : pathname;
|
|
1162
|
+
if (!rel) {
|
|
1163
|
+
rel = "index.html";
|
|
1164
|
+
}
|
|
1165
|
+
const filePath = path2.resolve(path2.join(base, rel));
|
|
1166
|
+
if (!isPathInsideRoot(filePath, base)) {
|
|
1167
|
+
return new Response("Forbidden", { status: 403 });
|
|
1168
|
+
}
|
|
1169
|
+
return import_electron2.net.fetch((0, import_node_url.pathToFileURL)(filePath).href);
|
|
1170
|
+
} catch {
|
|
1171
|
+
return new Response("Bad Request", { status: 400 });
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
function getDashboardPageURL() {
|
|
1176
|
+
return `${SCHEME}://electron/index.html`;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// src/core/dashboard.ts
|
|
1111
1180
|
var DashboardManager = class {
|
|
1112
1181
|
constructor(config) {
|
|
1113
1182
|
this.window = null;
|
|
@@ -1130,8 +1199,8 @@ var DashboardManager = class {
|
|
|
1130
1199
|
this.window.focus();
|
|
1131
1200
|
return;
|
|
1132
1201
|
}
|
|
1133
|
-
const preloadPath =
|
|
1134
|
-
this.window = new
|
|
1202
|
+
const preloadPath = path3.join(__dirname, "dashboard-preload.js");
|
|
1203
|
+
this.window = new import_electron3.BrowserWindow({
|
|
1135
1204
|
width: this.config.dashboard.width,
|
|
1136
1205
|
height: this.config.dashboard.height,
|
|
1137
1206
|
title: "Electron Memory Monitor",
|
|
@@ -1142,8 +1211,9 @@ var DashboardManager = class {
|
|
|
1142
1211
|
nodeIntegration: false
|
|
1143
1212
|
}
|
|
1144
1213
|
});
|
|
1145
|
-
const
|
|
1146
|
-
|
|
1214
|
+
const uiRoot = path3.join(__dirname, "ui");
|
|
1215
|
+
ensureDashboardProtocolHandler(uiRoot);
|
|
1216
|
+
this.window.loadURL(getDashboardPageURL());
|
|
1147
1217
|
this.window.on("closed", () => {
|
|
1148
1218
|
this.window = null;
|
|
1149
1219
|
});
|
|
@@ -1165,7 +1235,7 @@ var DashboardManager = class {
|
|
|
1165
1235
|
};
|
|
1166
1236
|
|
|
1167
1237
|
// src/ipc/main-handler.ts
|
|
1168
|
-
var
|
|
1238
|
+
var import_electron4 = require("electron");
|
|
1169
1239
|
|
|
1170
1240
|
// src/ipc/channels.ts
|
|
1171
1241
|
var IPC_CHANNELS = {
|
|
@@ -1203,49 +1273,49 @@ var IPCMainHandler = class {
|
|
|
1203
1273
|
}
|
|
1204
1274
|
/** 注册所有 IPC handlers */
|
|
1205
1275
|
register() {
|
|
1206
|
-
|
|
1276
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_START, (_event, args) => {
|
|
1207
1277
|
return this.monitor.startSession(args.label, args.description);
|
|
1208
1278
|
});
|
|
1209
|
-
|
|
1279
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_STOP, async () => {
|
|
1210
1280
|
return this.monitor.stopSession();
|
|
1211
1281
|
});
|
|
1212
|
-
|
|
1282
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_LIST, async () => {
|
|
1213
1283
|
return this.monitor.getSessions();
|
|
1214
1284
|
});
|
|
1215
|
-
|
|
1285
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_REPORT, async (_event, sessionId) => {
|
|
1216
1286
|
return this.monitor.getSessionReport(sessionId);
|
|
1217
1287
|
});
|
|
1218
|
-
|
|
1288
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_COMPARE, async (_event, args) => {
|
|
1219
1289
|
return this.monitor.compareSessions(args.baseId, args.targetId);
|
|
1220
1290
|
});
|
|
1221
|
-
|
|
1291
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_SNAPSHOTS, async (_event, args) => {
|
|
1222
1292
|
return this.monitor.getSessionSnapshots(args.sessionId, args.startTime, args.endTime, args.maxPoints);
|
|
1223
1293
|
});
|
|
1224
|
-
|
|
1294
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.TRIGGER_GC, async () => {
|
|
1225
1295
|
return this.monitor.triggerGC();
|
|
1226
1296
|
});
|
|
1227
|
-
|
|
1297
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.HEAP_SNAPSHOT, async (_event, filePath) => {
|
|
1228
1298
|
return this.monitor.takeHeapSnapshot(filePath);
|
|
1229
1299
|
});
|
|
1230
|
-
|
|
1300
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.MARK, (_event, args) => {
|
|
1231
1301
|
this.monitor.mark(args.label, args.metadata);
|
|
1232
1302
|
});
|
|
1233
|
-
|
|
1303
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.GET_CONFIG, () => {
|
|
1234
1304
|
return this.monitor.getConfig();
|
|
1235
1305
|
});
|
|
1236
|
-
|
|
1306
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.GET_SESSIONS, async () => {
|
|
1237
1307
|
return this.monitor.getSessions();
|
|
1238
1308
|
});
|
|
1239
|
-
|
|
1309
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_EXPORT, async (_event, sessionId) => {
|
|
1240
1310
|
return this.monitor.exportSession(sessionId);
|
|
1241
1311
|
});
|
|
1242
|
-
|
|
1312
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_IMPORT, async () => {
|
|
1243
1313
|
return this.monitor.importSession();
|
|
1244
1314
|
});
|
|
1245
|
-
|
|
1315
|
+
import_electron4.ipcMain.handle(IPC_CHANNELS.SESSION_DELETE, async (_event, sessionId) => {
|
|
1246
1316
|
return this.monitor.deleteSession(sessionId);
|
|
1247
1317
|
});
|
|
1248
|
-
|
|
1318
|
+
import_electron4.ipcMain.on(IPC_CHANNELS.RENDERER_REPORT, (_event, detail) => {
|
|
1249
1319
|
this.monitor.updateRendererDetail(detail);
|
|
1250
1320
|
});
|
|
1251
1321
|
}
|
|
@@ -1265,8 +1335,8 @@ var IPCMainHandler = class {
|
|
|
1265
1335
|
unregister() {
|
|
1266
1336
|
const channels = Object.values(IPC_CHANNELS);
|
|
1267
1337
|
for (const channel of channels) {
|
|
1268
|
-
|
|
1269
|
-
|
|
1338
|
+
import_electron4.ipcMain.removeHandler(channel);
|
|
1339
|
+
import_electron4.ipcMain.removeAllListeners(channel);
|
|
1270
1340
|
}
|
|
1271
1341
|
}
|
|
1272
1342
|
};
|
|
@@ -1313,6 +1383,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1313
1383
|
this.dashboard = null;
|
|
1314
1384
|
return;
|
|
1315
1385
|
}
|
|
1386
|
+
registerDashboardSchemePrivileged();
|
|
1316
1387
|
this.collector = new MemoryCollector(this.config);
|
|
1317
1388
|
this.anomalyDetector = new AnomalyDetector(this.config);
|
|
1318
1389
|
this.analyzer = new Analyzer();
|
|
@@ -1325,10 +1396,10 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1325
1396
|
/** 启动监控 */
|
|
1326
1397
|
async start() {
|
|
1327
1398
|
if (!this.config.enabled || this.started) return;
|
|
1328
|
-
if (!
|
|
1329
|
-
await
|
|
1399
|
+
if (!import_electron5.app.isReady()) {
|
|
1400
|
+
await import_electron5.app.whenReady();
|
|
1330
1401
|
}
|
|
1331
|
-
const storageDir = this.config.storage.directory ||
|
|
1402
|
+
const storageDir = this.config.storage.directory || path4.join(import_electron5.app.getPath("userData"), "memory-monitor");
|
|
1332
1403
|
this.persister = new DataPersister(this.config, storageDir);
|
|
1333
1404
|
this.sessionManager = new SessionManager(this.persister);
|
|
1334
1405
|
this.ipcHandler = new IPCMainHandler(this);
|
|
@@ -1400,7 +1471,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1400
1471
|
anomalies,
|
|
1401
1472
|
completedSession.dataFile
|
|
1402
1473
|
);
|
|
1403
|
-
const reportPath =
|
|
1474
|
+
const reportPath = path4.join(this.persister.getStorageDir(), completedSession.id, "report.json");
|
|
1404
1475
|
const fs2 = await import("fs");
|
|
1405
1476
|
fs2.writeFileSync(reportPath, JSON.stringify(report, null, 2), "utf-8");
|
|
1406
1477
|
this.emit("session-end", report);
|
|
@@ -1430,7 +1501,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1430
1501
|
/** 获取指定会话报告 */
|
|
1431
1502
|
async getSessionReport(sessionId) {
|
|
1432
1503
|
const fs2 = await import("fs");
|
|
1433
|
-
const reportPath =
|
|
1504
|
+
const reportPath = path4.join(this.persister.getStorageDir(), sessionId, "report.json");
|
|
1434
1505
|
try {
|
|
1435
1506
|
const content = fs2.readFileSync(reportPath, "utf-8");
|
|
1436
1507
|
return JSON.parse(content);
|
|
@@ -1561,7 +1632,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1561
1632
|
} catch {
|
|
1562
1633
|
}
|
|
1563
1634
|
}
|
|
1564
|
-
await new Promise((
|
|
1635
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
1565
1636
|
const afterMem = process.memoryUsage();
|
|
1566
1637
|
const freed = beforeMem.heapUsed - afterMem.heapUsed;
|
|
1567
1638
|
return {
|
|
@@ -1574,7 +1645,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1574
1645
|
}
|
|
1575
1646
|
/** 导出堆快照 */
|
|
1576
1647
|
async takeHeapSnapshot(filePath) {
|
|
1577
|
-
const snapshotPath = filePath ||
|
|
1648
|
+
const snapshotPath = filePath || path4.join(
|
|
1578
1649
|
this.persister.getStorageDir(),
|
|
1579
1650
|
`heap-${Date.now()}.heapsnapshot`
|
|
1580
1651
|
);
|
|
@@ -1635,6 +1706,7 @@ var ElectronMemoryMonitor = class extends import_events3.EventEmitter {
|
|
|
1635
1706
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1636
1707
|
0 && (module.exports = {
|
|
1637
1708
|
ElectronMemoryMonitor,
|
|
1638
|
-
IPC_CHANNELS
|
|
1709
|
+
IPC_CHANNELS,
|
|
1710
|
+
registerDashboardSchemePrivileged
|
|
1639
1711
|
});
|
|
1640
1712
|
//# sourceMappingURL=index.js.map
|