@lvce-editor/process-explorer 3.22.0 → 3.23.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.
Files changed (2) hide show
  1. package/dist/index.js +357 -95
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  import { spawn, execFile as execFile$2 } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
+ import { createWriteStream, readFileSync } from 'node:fs';
4
+ import { readdir, readlink, readFile, rm } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
3
7
  import require$$0$3 from 'events';
4
8
  import require$$1$1 from 'https';
5
9
  import require$$2$1 from 'http';
@@ -11,10 +15,8 @@ import require$$7 from 'url';
11
15
  import require$$0 from 'zlib';
12
16
  import require$$0$1 from 'buffer';
13
17
  import require$$2 from 'util';
18
+ import { setTimeout as setTimeout$1 } from 'node:timers/promises';
14
19
  import { Buffer as Buffer$1 } from 'node:buffer';
15
- import { readFile } from 'node:fs/promises';
16
- import { join } from 'node:path';
17
- import { readFileSync } from 'node:fs';
18
20
 
19
21
  const normalizeLine = line => {
20
22
  if (line.startsWith('Error: ')) {
@@ -82,7 +84,7 @@ const Object$1 = 1;
82
84
  const Number$1 = 2;
83
85
  const Array$1 = 3;
84
86
  const String$1 = 4;
85
- const Boolean = 5;
87
+ const Boolean$1 = 5;
86
88
  const Function = 6;
87
89
  const Null = 7;
88
90
  const Unknown = 8;
@@ -103,7 +105,7 @@ const getType = value => {
103
105
  }
104
106
  return Object$1;
105
107
  case 'boolean':
106
- return Boolean;
108
+ return Boolean$1;
107
109
  default:
108
110
  return Unknown;
109
111
  }
@@ -1497,11 +1499,12 @@ const kill = (pid, signal) => {
1497
1499
 
1498
1500
  const SIGINT = 'SIGINT';
1499
1501
  const SIGTERM = 'SIGTERM';
1502
+ const SIGUSR1 = 'SIGUSR1';
1500
1503
 
1501
1504
  const fixtureScript = 'setTimeout(() => process.exit(0), 120_000); setInterval(() => {}, 1000)';
1502
1505
  const fixtureProcesses = new Map();
1503
1506
  const createE2eFixtureProcess = marker => {
1504
- const childProcess = spawn(process.execPath, ['-e', fixtureScript, marker], {
1507
+ const childProcess = spawn(process.execPath, ['--inspect=9000', '-e', fixtureScript, marker], {
1505
1508
  env: {
1506
1509
  ...process.env,
1507
1510
  ELECTRON_RUN_AS_NODE: '1'
@@ -1725,91 +1728,6 @@ const getMainProcessId = ({
1725
1728
  return getRemoteRootProcessId(childProcessId);
1726
1729
  };
1727
1730
 
1728
- const commandMap = {
1729
- 'HandleElectronMessagePort.handleElectronMessagePort': handleElectronMessagePort,
1730
- 'HandleMessagePort.handleMessagePort': handleMessagePort,
1731
- 'HandleSocket.handleSocket': handleSocket,
1732
- 'HandleWebSocket.handleWebSocket': handleWebSocket,
1733
- 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage': listProcessesWithMemoryUsage$2,
1734
- 'Process.createE2eFixtureProcess': createE2eFixtureProcess,
1735
- 'Process.disposeE2eFixtureProcess': disposeE2eFixtureProcess,
1736
- 'Process.kill': killProcess,
1737
- 'ProcessId.getMainProcessId': getMainProcessId
1738
- };
1739
-
1740
- const set$1 = commandMap => {
1741
- state.commandMap = commandMap;
1742
- };
1743
-
1744
- const set = commandMap => {
1745
- set$1(commandMap);
1746
- };
1747
-
1748
- const NodeWorker = 1;
1749
- const NodeForkedProcess = 2;
1750
- const ElectronUtilityProcess = 3;
1751
- const ElectronMessagePort = 4;
1752
- const WebSocket$1 = 6;
1753
- const Auto = () => {
1754
- const {
1755
- argv
1756
- } = process;
1757
- if (argv.includes('--ipc-type=node-worker')) {
1758
- return NodeWorker;
1759
- }
1760
- if (argv.includes('--ipc-type=node-forked-process')) {
1761
- return NodeForkedProcess;
1762
- }
1763
- if (argv.includes('--ipc-type=electron-utility-process')) {
1764
- return ElectronUtilityProcess;
1765
- }
1766
- throw new Error(`[shared-process] unknown ipc type`);
1767
- };
1768
-
1769
- const getModule = method => {
1770
- switch (method) {
1771
- case ElectronMessagePort:
1772
- return create$6;
1773
- case ElectronUtilityProcess:
1774
- return create$5;
1775
- case NodeForkedProcess:
1776
- return create$3;
1777
- case NodeWorker:
1778
- return create$1;
1779
- case WebSocket$1:
1780
- return create$2;
1781
- default:
1782
- throw new Error('unexpected ipc type');
1783
- }
1784
- };
1785
-
1786
- const listen$1 = async ({
1787
- method,
1788
- ...params
1789
- }) => {
1790
- const create = getModule(method);
1791
- const rpc = await create(params);
1792
- return rpc;
1793
- };
1794
-
1795
- const registerLaunchParentRpc = rpc => {
1796
- setRpc(rpc, SharedProcess);
1797
- };
1798
- const listen = async () => {
1799
- set(commandMap);
1800
- const rpc = await listen$1({
1801
- commandMap: commandMap,
1802
- method: Auto()
1803
- });
1804
- registerLaunchParentRpc(rpc);
1805
- };
1806
-
1807
- const main = async () => {
1808
- await listen();
1809
- };
1810
-
1811
- main();
1812
-
1813
1731
  function getDefaultExportFromCjs (x) {
1814
1732
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1815
1733
  }
@@ -2165,7 +2083,7 @@ function requirePermessageDeflate() {
2165
2083
  acceptAsServer(offers) {
2166
2084
  const opts = this._options;
2167
2085
  const accepted = offers.find(params => {
2168
- if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === 'number' && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === 'number' && !params.client_max_window_bits) {
2086
+ if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === 'number' && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === 'number' && (typeof params.client_max_window_bits === 'number' ? opts.clientMaxWindowBits > params.client_max_window_bits : !params.client_max_window_bits)) {
2169
2087
  return false;
2170
2088
  }
2171
2089
  return true;
@@ -5589,7 +5507,7 @@ function requireSubprotocol() {
5589
5507
  requireSubprotocol();
5590
5508
 
5591
5509
  var websocketExports = requireWebsocket();
5592
- const WebSocket = /*@__PURE__*/getDefaultExportFromCjs(websocketExports);
5510
+ const WebSocket$1 = /*@__PURE__*/getDefaultExportFromCjs(websocketExports);
5593
5511
 
5594
5512
  /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
5595
5513
  var websocketServer$1;
@@ -6064,10 +5982,354 @@ const websocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExpo
6064
5982
 
6065
5983
  const wrapper = {
6066
5984
  __proto__: null,
6067
- WebSocket,
5985
+ WebSocket: WebSocket$1,
6068
5986
  WebSocketServer: websocketServer,
6069
- default: WebSocket
5987
+ default: WebSocket$1
5988
+ };
5989
+
5990
+ const defaultInspectorPorts = [9000, 9229];
5991
+ const inspectOptionRegex = /--inspect(?:-brk|-wait|-port)?(?:=|\s+)([^\s"']+)/g;
5992
+ const digitsRegex = /^\d+$/;
5993
+ const getInspectorPortsFromCommand = command => {
5994
+ const ports = new Set(defaultInspectorPorts);
5995
+ for (const match of command.matchAll(inspectOptionRegex)) {
5996
+ const portText = match[1].split(':').at(-1) || '';
5997
+ const port = digitsRegex.test(portText) ? Number(portText) : 0;
5998
+ if (port > 0 && port <= 65_535) {
5999
+ ports.add(port);
6000
+ }
6001
+ }
6002
+ return [...ports];
6003
+ };
6004
+
6005
+ const commandId$1 = 1;
6006
+ const timeoutMs$1 = 2000;
6007
+ const getInspectorProcessId = url => {
6008
+ return new Promise(resolve => {
6009
+ const webSocket = new WebSocket$1(url);
6010
+ let settled = false;
6011
+ const finish = pid => {
6012
+ if (settled) {
6013
+ return;
6014
+ }
6015
+ settled = true;
6016
+ clearTimeout(timeout);
6017
+ webSocket.close();
6018
+ resolve(pid);
6019
+ };
6020
+ const timeout = setTimeout(finish, timeoutMs$1, 0);
6021
+ webSocket.on('error', () => finish(0));
6022
+ webSocket.on('close', () => finish(0));
6023
+ webSocket.on('message', data => {
6024
+ try {
6025
+ const message = JSON.parse(data.toString());
6026
+ if (message.id !== commandId$1) {
6027
+ return;
6028
+ }
6029
+ const value = message.result?.result?.value;
6030
+ finish(typeof value === 'number' ? value : 0);
6031
+ } catch {
6032
+ finish(0);
6033
+ }
6034
+ });
6035
+ webSocket.on('open', () => {
6036
+ webSocket.send(JSON.stringify({
6037
+ id: commandId$1,
6038
+ method: 'Runtime.evaluate',
6039
+ params: {
6040
+ expression: 'process.pid',
6041
+ returnByValue: true
6042
+ }
6043
+ }));
6044
+ });
6045
+ });
6046
+ };
6047
+
6048
+ const socketRegex = /^socket:\[(\d+)\]$/;
6049
+ const whitespaceRegex = /\s+/;
6050
+ const parseProcNetTcp = (content, socketInodes) => {
6051
+ const ports = [];
6052
+ const lines = content.split('\n').slice(1);
6053
+ for (const line of lines) {
6054
+ const fields = line.trim().split(whitespaceRegex);
6055
+ if (fields.length < 10 || fields[3] !== '0A') {
6056
+ continue;
6057
+ }
6058
+ const inode = fields[9];
6059
+ if (!socketInodes.has(inode)) {
6060
+ continue;
6061
+ }
6062
+ const separatorIndex = fields[1].lastIndexOf(':');
6063
+ const port = Number.parseInt(fields[1].slice(separatorIndex + 1), 16);
6064
+ if (port > 0) {
6065
+ ports.push(port);
6066
+ }
6067
+ }
6068
+ return ports;
6069
+ };
6070
+ const getSocketInodes = async pid => {
6071
+ const directory = `/proc/${pid}/fd`;
6072
+ const entries = await readdir(directory);
6073
+ const links = await Promise.allSettled(entries.map(entry => readlink(`${directory}/${entry}`)));
6074
+ const inodes = new Set();
6075
+ for (const link of links) {
6076
+ if (link.status !== 'fulfilled') {
6077
+ continue;
6078
+ }
6079
+ const match = link.value.match(socketRegex);
6080
+ if (match) {
6081
+ inodes.add(match[1]);
6082
+ }
6083
+ }
6084
+ return inodes;
6085
+ };
6086
+ const readNetworkTable = async path => {
6087
+ try {
6088
+ return await readFile(path, 'utf8');
6089
+ } catch {
6090
+ return '';
6091
+ }
6070
6092
  };
6093
+ const getLinuxProcessListeningPorts = async pid => {
6094
+ try {
6095
+ const socketInodes = await getSocketInodes(pid);
6096
+ const [tcp, tcp6] = await Promise.all([readNetworkTable(`/proc/${pid}/net/tcp`), readNetworkTable(`/proc/${pid}/net/tcp6`)]);
6097
+ return [...parseProcNetTcp(tcp, socketInodes), ...parseProcNetTcp(tcp6, socketInodes)];
6098
+ } catch {
6099
+ return [];
6100
+ }
6101
+ };
6102
+
6103
+ const getProcessListeningPorts = async pid => {
6104
+ if (process.platform !== 'linux') {
6105
+ return [];
6106
+ }
6107
+ return getLinuxProcessListeningPorts(pid);
6108
+ };
6109
+
6110
+ const maxAttempts = 50;
6111
+ const retryDelay = 100;
6112
+ const getInspectorWebSocketUrlAtPort = async (pid, port) => {
6113
+ try {
6114
+ const response = await fetch(`http://127.0.0.1:${port}/json/list`, {
6115
+ signal: AbortSignal.timeout(500)
6116
+ });
6117
+ if (!response.ok) {
6118
+ return '';
6119
+ }
6120
+ const targets = await response.json();
6121
+ if (!Array.isArray(targets)) {
6122
+ return '';
6123
+ }
6124
+ const pidSuffix = `[${pid}]`;
6125
+ for (const target of targets) {
6126
+ const {
6127
+ title = '',
6128
+ webSocketDebuggerUrl = ''
6129
+ } = target;
6130
+ if (!webSocketDebuggerUrl) {
6131
+ continue;
6132
+ }
6133
+ if (title.endsWith(pidSuffix)) {
6134
+ return webSocketDebuggerUrl;
6135
+ }
6136
+ const inspectorPid = await getInspectorProcessId(webSocketDebuggerUrl);
6137
+ if (inspectorPid === pid) {
6138
+ return webSocketDebuggerUrl;
6139
+ }
6140
+ }
6141
+ return '';
6142
+ } catch {
6143
+ return '';
6144
+ }
6145
+ };
6146
+ const getInspectorWebSocketUrl = async (pid, command) => {
6147
+ const commandPorts = getInspectorPortsFromCommand(command);
6148
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
6149
+ const listeningPorts = await getProcessListeningPorts(pid);
6150
+ const ports = new Set([...commandPorts, ...listeningPorts]);
6151
+ const urls = await Promise.all(Array.from(ports, port => getInspectorWebSocketUrlAtPort(pid, port)));
6152
+ const url = urls.find(Boolean);
6153
+ if (url) {
6154
+ return url;
6155
+ }
6156
+ await setTimeout$1(retryDelay);
6157
+ }
6158
+ throw new Error(`Could not find the inspector for process ${pid}`);
6159
+ };
6160
+
6161
+ const commandId = 1;
6162
+ const timeoutMs = 5 * 60 * 1000;
6163
+ const takeHeapSnapshotWithCdp = (webSocket, output) => {
6164
+ return new Promise((resolve, reject) => {
6165
+ let settled = false;
6166
+ const timeout = setTimeout(() => {
6167
+ fail(new Error('Timed out while taking the heap snapshot'));
6168
+ }, timeoutMs);
6169
+ const dispose = () => {
6170
+ clearTimeout(timeout);
6171
+ webSocket.close();
6172
+ };
6173
+ const fail = error => {
6174
+ if (settled) {
6175
+ return;
6176
+ }
6177
+ settled = true;
6178
+ output.destroy();
6179
+ dispose();
6180
+ reject(error);
6181
+ };
6182
+ output.on('error', fail);
6183
+ webSocket.on('error', fail);
6184
+ webSocket.on('close', () => {
6185
+ fail(new Error('Inspector connection closed while taking heap snapshot'));
6186
+ });
6187
+ webSocket.on('message', data => {
6188
+ try {
6189
+ const message = JSON.parse(data.toString());
6190
+ if (message.method === 'HeapProfiler.addHeapSnapshotChunk') {
6191
+ const chunk = message.params?.chunk;
6192
+ if (!output.write(chunk)) {
6193
+ webSocket.pause();
6194
+ output.once('drain', () => webSocket.resume());
6195
+ }
6196
+ return;
6197
+ }
6198
+ if (message.id !== commandId) {
6199
+ return;
6200
+ }
6201
+ if (message.error) {
6202
+ fail(new Error(message.error.message));
6203
+ return;
6204
+ }
6205
+ output.end(() => {
6206
+ if (settled) {
6207
+ return;
6208
+ }
6209
+ settled = true;
6210
+ dispose();
6211
+ resolve();
6212
+ });
6213
+ } catch (error) {
6214
+ fail(new Error('Failed to handle inspector message', {
6215
+ cause: error
6216
+ }));
6217
+ }
6218
+ });
6219
+ webSocket.on('open', () => {
6220
+ webSocket.send(JSON.stringify({
6221
+ id: commandId,
6222
+ method: 'HeapProfiler.takeHeapSnapshot',
6223
+ params: {
6224
+ reportProgress: false
6225
+ }
6226
+ }));
6227
+ });
6228
+ });
6229
+ };
6230
+
6231
+ const takeHeapSnapshot = async (pid, command) => {
6232
+ kill(pid, SIGUSR1);
6233
+ const inspectorUrl = await getInspectorWebSocketUrl(pid, command);
6234
+ const path = join(tmpdir(), `lvce-process-${pid}-${Date.now()}.heapsnapshot`);
6235
+ const webSocket = new WebSocket$1(inspectorUrl);
6236
+ const output = createWriteStream(path);
6237
+ try {
6238
+ await takeHeapSnapshotWithCdp(webSocket, output);
6239
+ return path;
6240
+ } catch (error) {
6241
+ await rm(path, {
6242
+ force: true
6243
+ });
6244
+ throw error;
6245
+ }
6246
+ };
6247
+
6248
+ const commandMap = {
6249
+ 'HandleElectronMessagePort.handleElectronMessagePort': handleElectronMessagePort,
6250
+ 'HandleMessagePort.handleMessagePort': handleMessagePort,
6251
+ 'HandleSocket.handleSocket': handleSocket,
6252
+ 'HandleWebSocket.handleWebSocket': handleWebSocket,
6253
+ 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage': listProcessesWithMemoryUsage$2,
6254
+ 'Process.createE2eFixtureProcess': createE2eFixtureProcess,
6255
+ 'Process.disposeE2eFixtureProcess': disposeE2eFixtureProcess,
6256
+ 'Process.kill': killProcess,
6257
+ 'Process.takeHeapSnapshot': takeHeapSnapshot,
6258
+ 'ProcessId.getMainProcessId': getMainProcessId
6259
+ };
6260
+
6261
+ const set$1 = commandMap => {
6262
+ state.commandMap = commandMap;
6263
+ };
6264
+
6265
+ const set = commandMap => {
6266
+ set$1(commandMap);
6267
+ };
6268
+
6269
+ const NodeWorker = 1;
6270
+ const NodeForkedProcess = 2;
6271
+ const ElectronUtilityProcess = 3;
6272
+ const ElectronMessagePort = 4;
6273
+ const WebSocket = 6;
6274
+ const Auto = () => {
6275
+ const {
6276
+ argv
6277
+ } = process;
6278
+ if (argv.includes('--ipc-type=node-worker')) {
6279
+ return NodeWorker;
6280
+ }
6281
+ if (argv.includes('--ipc-type=node-forked-process')) {
6282
+ return NodeForkedProcess;
6283
+ }
6284
+ if (argv.includes('--ipc-type=electron-utility-process')) {
6285
+ return ElectronUtilityProcess;
6286
+ }
6287
+ throw new Error(`[shared-process] unknown ipc type`);
6288
+ };
6289
+
6290
+ const getModule = method => {
6291
+ switch (method) {
6292
+ case ElectronMessagePort:
6293
+ return create$6;
6294
+ case ElectronUtilityProcess:
6295
+ return create$5;
6296
+ case NodeForkedProcess:
6297
+ return create$3;
6298
+ case NodeWorker:
6299
+ return create$1;
6300
+ case WebSocket:
6301
+ return create$2;
6302
+ default:
6303
+ throw new Error('unexpected ipc type');
6304
+ }
6305
+ };
6306
+
6307
+ const listen$1 = async ({
6308
+ method,
6309
+ ...params
6310
+ }) => {
6311
+ const create = getModule(method);
6312
+ const rpc = await create(params);
6313
+ return rpc;
6314
+ };
6315
+
6316
+ const registerLaunchParentRpc = rpc => {
6317
+ setRpc(rpc, SharedProcess);
6318
+ };
6319
+ const listen = async () => {
6320
+ set(commandMap);
6321
+ const rpc = await listen$1({
6322
+ commandMap: commandMap,
6323
+ method: Auto()
6324
+ });
6325
+ registerLaunchParentRpc(rpc);
6326
+ };
6327
+
6328
+ const main = async () => {
6329
+ await listen();
6330
+ };
6331
+
6332
+ main();
6071
6333
 
6072
6334
  const createWebSocketServer = async () => {
6073
6335
  const _ws = await Promise.resolve().then(function () { return wrapper; });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/process-explorer",
3
- "version": "3.22.0",
3
+ "version": "3.23.0",
4
4
  "description": "Process Explorer",
5
5
  "main": "dist/index.js",
6
6
  "bin": "bin/processExplorer.js",