@lvce-editor/main-process 6.12.0 → 6.14.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.
@@ -5,10 +5,10 @@ import { fileURLToPath } from 'node:url';
5
5
  import { inspect } from 'node:util';
6
6
  import { spawn } from 'node:child_process';
7
7
  import { Console } from 'node:console';
8
- import { createWriteStream, readFileSync, openAsBlob, existsSync, mkdirSync, openSync, writeSync, closeSync, rmSync } from 'node:fs';
9
- import { tmpdir, homedir } from 'node:os';
8
+ import { mkdirSync, createWriteStream, readFileSync, openAsBlob, existsSync, writeFileSync, rmSync, openSync, writeSync, closeSync } from 'node:fs';
10
9
  import * as NodePath from 'node:path';
11
10
  import { dirname, join as join$1 } from 'node:path';
11
+ import { homedir, tmpdir } from 'node:os';
12
12
  import { MessageChannel } from 'node:worker_threads';
13
13
 
14
14
  const scheme = 'lvce-oss';
@@ -778,53 +778,92 @@ const getNewLineIndex$2 = (string, startIndex = undefined) => {
778
778
  return string.indexOf('\n', startIndex);
779
779
  };
780
780
 
781
+ const join = (...paths) => {
782
+ return NodePath.join(...paths);
783
+ };
784
+
785
+ const __dirname$1 = dirname(fileURLToPath(import.meta.url));
786
+ const root = process.env.LVCE_ROOT || join(__dirname$1, '../../../../..');
787
+
788
+ const {
789
+ env,
790
+ platform
791
+ } = process;
792
+ const isLinux = platform === 'linux';
793
+ const isProduction = false;
794
+ const homeDirectory = homedir();
795
+
796
+ const xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? join(homeDirectory, '.cache') : undefined);
797
+ const xdgData = env.XDG_DATA_HOME || (homeDirectory ? join(homeDirectory, '.local', 'share') : undefined);
798
+ join(xdgData || tmpdir(), applicationName);
799
+ const xdgState = env.XDG_STATE_HOME || (homeDirectory ? join(homeDirectory, '.local', 'state') : undefined);
800
+ const logsDir = join(xdgState || tmpdir(), applicationName, 'logs');
801
+ const chromeUserDataPath = xdgCache ? join(xdgCache, applicationName, 'userdata') : '';
802
+
803
+ const useIpcForResponse = true;
804
+ const getSessionId = () => {
805
+ return process.env.SESSION_ID || `persist:${scheme}`;
806
+ };
807
+ const getSharedProcessPath = () => {
808
+ if (process.env.LVCE_SHARED_PROCESS_PATH) {
809
+ return process.env.LVCE_SHARED_PROCESS_PATH;
810
+ }
811
+ return join(root, 'packages', 'shared-process', 'src', 'sharedProcessMain.ts');
812
+ };
813
+
814
+ const createFileLogger = fileName => {
815
+ mkdirSync(logsDir, {
816
+ recursive: true
817
+ });
818
+ const logFile = join(logsDir, fileName);
819
+ const writeStream = createWriteStream(logFile);
820
+ return new Console(writeStream);
821
+ };
822
+
781
823
  // TODO disable logging via environment variable, don't enable logging during tests
782
824
 
783
- const state$6 = {
825
+ const state$7 = {
784
826
  console: undefined
785
827
  };
786
828
  const createConsole = () => {
787
- const logFile = `${tmpdir()}/log-main-process.txt`;
788
- const writeStream = createWriteStream(logFile);
789
- const logger = new Console(writeStream);
790
- return logger;
829
+ return createFileLogger('log-main-process.txt');
791
830
  };
792
- const getOrCreateLogger = () => {
793
- state$6.console ||= createConsole();
794
- return state$6.console;
831
+ const getOrCreateLogger$1 = () => {
832
+ state$7.console ||= createConsole();
833
+ return state$7.console;
795
834
  };
796
835
  const info = (...args) => {
797
- const logger = getOrCreateLogger();
836
+ const logger = getOrCreateLogger$1();
798
837
  logger.info(...args);
799
838
  console.info(...args);
800
839
  };
801
840
  const error = (...args) => {
802
- const logger = getOrCreateLogger();
841
+ const logger = getOrCreateLogger$1();
803
842
  logger.error(...args);
804
843
  console.error(...args);
805
844
  };
806
845
  process.stdout.on('close', () => {
807
- const logger = getOrCreateLogger();
846
+ const logger = getOrCreateLogger$1();
808
847
  logger.info('stdout closed');
809
848
  });
810
849
  process.stdout.on('exit', () => {
811
- const logger = getOrCreateLogger();
850
+ const logger = getOrCreateLogger$1();
812
851
  logger.info('stdout exited');
813
852
  });
814
853
  process.stderr.on('close', () => {
815
- const logger = getOrCreateLogger();
854
+ const logger = getOrCreateLogger$1();
816
855
  logger.info('stderr closed');
817
856
  });
818
857
  process.stderr.on('exit', () => {
819
- const logger = getOrCreateLogger();
858
+ const logger = getOrCreateLogger$1();
820
859
  logger.info('stderr exited');
821
860
  });
822
861
  process.stdout.on('error', error => {
823
- const logger = getOrCreateLogger();
862
+ const logger = getOrCreateLogger$1();
824
863
  logger.error(`[main-process] stdout error: ${error.stack}`);
825
864
  });
826
865
  process.stderr.on('error', error => {
827
- const logger = getOrCreateLogger();
866
+ const logger = getOrCreateLogger$1();
828
867
  logger.error(`[main-process] stderr error: ${error.stack}`);
829
868
  });
830
869
 
@@ -2271,7 +2310,7 @@ const IpcChildWithRendererProcess2$1 = {
2271
2310
  listen: listen$2,
2272
2311
  wrap: wrap$a
2273
2312
  };
2274
- const addListener = (emitter, type, callback) => {
2313
+ const addListener$1 = (emitter, type, callback) => {
2275
2314
  if ('addEventListener' in emitter) {
2276
2315
  emitter.addEventListener(type, callback);
2277
2316
  } else {
@@ -2304,7 +2343,7 @@ const getFirstEvent = (eventEmitter, eventMap) => {
2304
2343
  type
2305
2344
  });
2306
2345
  };
2307
- addListener(eventEmitter, event, listener);
2346
+ addListener$1(eventEmitter, event, listener);
2308
2347
  listenerMap[event] = listener;
2309
2348
  }
2310
2349
  return promise;
@@ -3382,27 +3421,27 @@ const formatUtilityProcessName = name => {
3382
3421
  return camelCase(name);
3383
3422
  };
3384
3423
 
3385
- const state$5 = {
3424
+ const state$6 = {
3386
3425
  all: Object.create(null)
3387
3426
  };
3388
3427
  const add$1 = (pid, process, name) => {
3389
3428
  number(pid);
3390
3429
  object(process);
3391
3430
  string(name);
3392
- state$5.all[pid] = {
3431
+ state$6.all[pid] = {
3393
3432
  name,
3394
3433
  process
3395
3434
  };
3396
3435
  };
3397
3436
  const remove$1 = pid => {
3398
3437
  number(pid);
3399
- delete state$5.all[pid];
3438
+ delete state$6.all[pid];
3400
3439
  };
3401
3440
  const getAll = () => {
3402
- return Object.entries(state$5.all);
3441
+ return Object.entries(state$6.all);
3403
3442
  };
3404
3443
  const getByName = name => {
3405
- for (const value of Object.values(state$5.all)) {
3444
+ for (const value of Object.values(state$6.all)) {
3406
3445
  // @ts-ignore
3407
3446
  if (value.name === name) {
3408
3447
  // @ts-ignore
@@ -3492,37 +3531,6 @@ const DidStartSharedProcess = 'code/didStartSharedProcess';
3492
3531
  const WillCreateCodeWindow = 'code/willCreateCodeWindow';
3493
3532
  const DidCreateCodeWindow = 'code/didCreateCodeWindow';
3494
3533
 
3495
- const join = (...paths) => {
3496
- return NodePath.join(...paths);
3497
- };
3498
-
3499
- const __dirname$1 = dirname(fileURLToPath(import.meta.url));
3500
- const root = process.env.LVCE_ROOT || join(__dirname$1, '../../../../..');
3501
-
3502
- const {
3503
- env,
3504
- platform
3505
- } = process;
3506
- const isLinux = platform === 'linux';
3507
- const isProduction = false;
3508
- const homeDirectory = homedir();
3509
-
3510
- const xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? join(homeDirectory, '.cache') : undefined);
3511
- const xdgData = env.XDG_DATA_HOME || (homeDirectory ? join(homeDirectory, '.local', 'share') : undefined);
3512
- join(xdgData || tmpdir(), applicationName);
3513
- const chromeUserDataPath = xdgCache ? join(xdgCache, applicationName, 'userdata') : '';
3514
-
3515
- const useIpcForResponse = true;
3516
- const getSessionId = () => {
3517
- return process.env.SESSION_ID || `persist:${scheme}`;
3518
- };
3519
- const getSharedProcessPath = () => {
3520
- if (process.env.LVCE_SHARED_PROCESS_PATH) {
3521
- return process.env.LVCE_SHARED_PROCESS_PATH;
3522
- }
3523
- return join(root, 'packages', 'shared-process', 'src', 'sharedProcessMain.ts');
3524
- };
3525
-
3526
3534
  const requiresSocket = () => {
3527
3535
  return false;
3528
3536
  };
@@ -3586,7 +3594,7 @@ const launchSharedProcess = async ({
3586
3594
  return sharedProcessRpc;
3587
3595
  };
3588
3596
 
3589
- const state$4 = {
3597
+ const state$5 = {
3590
3598
  /**
3591
3599
  * @type {any}
3592
3600
  */
@@ -3597,14 +3605,14 @@ const getOrCreate = async ({
3597
3605
  env = {},
3598
3606
  method
3599
3607
  }) => {
3600
- if (!state$4.promise) {
3608
+ if (!state$5.promise) {
3601
3609
  // @ts-ignore
3602
- state$4.promise = launchSharedProcess({
3610
+ state$5.promise = launchSharedProcess({
3603
3611
  env,
3604
3612
  method
3605
3613
  });
3606
3614
  }
3607
- return state$4.promise;
3615
+ return state$5.promise;
3608
3616
  };
3609
3617
  const send$1 = async (method, ...params) => {
3610
3618
  const rpc = await getOrCreate({
@@ -3768,14 +3776,14 @@ const createTitleBar = items => {
3768
3776
 
3769
3777
  const PHASE_DEFAULT = 0;
3770
3778
  const PHASE_SHUTDOWN = -1;
3771
- const state$3 = {
3779
+ const state$4 = {
3772
3780
  phase: PHASE_DEFAULT
3773
3781
  };
3774
3782
  const isShutDown = () => {
3775
- return state$3.phase === PHASE_SHUTDOWN;
3783
+ return state$4.phase === PHASE_SHUTDOWN;
3776
3784
  };
3777
3785
  const setShutDown = () => {
3778
- state$3.phase = PHASE_SHUTDOWN;
3786
+ state$4.phase = PHASE_SHUTDOWN;
3779
3787
  };
3780
3788
 
3781
3789
  // TODO move this function to shared process
@@ -4073,21 +4081,21 @@ const openExternal = async url => {
4073
4081
  await shell.openExternal(url);
4074
4082
  };
4075
4083
 
4076
- const state$2 = {
4084
+ const state$3 = {
4077
4085
  canceled: Object.create(null),
4078
4086
  fallThroughKeyBindings: [],
4079
4087
  views: Object.create(null)
4080
4088
  };
4081
4089
  const add = (id, browserWindow, view) => {
4082
4090
  // state
4083
- state$2.views[id] = {
4091
+ state$3.views[id] = {
4084
4092
  browserWindow,
4085
4093
  view
4086
4094
  };
4087
4095
  };
4088
4096
  const hasWebContents = id => {
4089
4097
  number(id);
4090
- return id in state$2.views;
4098
+ return id in state$3.views;
4091
4099
  };
4092
4100
  /**
4093
4101
  *
@@ -4095,19 +4103,19 @@ const hasWebContents = id => {
4095
4103
  * @returns {{browserWindow: Electron.BrowserWindow, view: Electron.WebContentsView}}
4096
4104
  */
4097
4105
  const get$3 = id => {
4098
- return state$2.views[id];
4106
+ return state$3.views[id];
4099
4107
  };
4100
4108
  const remove = id => {
4101
- delete state$2.views[id];
4109
+ delete state$3.views[id];
4102
4110
  };
4103
4111
  const setFallthroughKeyBindings = fallthroughKeyBindings => {
4104
- state$2.fallThroughKeyBindings = fallthroughKeyBindings;
4112
+ state$3.fallThroughKeyBindings = fallthroughKeyBindings;
4105
4113
  };
4106
4114
  const getFallthroughKeyBindings = () => {
4107
- return state$2.fallThroughKeyBindings;
4115
+ return state$3.fallThroughKeyBindings;
4108
4116
  };
4109
4117
  const setCanceled = id => {
4110
- state$2.canceled[id] = true;
4118
+ state$3.canceled[id] = true;
4111
4119
  };
4112
4120
 
4113
4121
  const shouldAllowNavigation = webContentsId => {
@@ -4437,20 +4445,20 @@ const createElectronSession = () => {
4437
4445
  return session;
4438
4446
  };
4439
4447
 
4440
- const state$1 = {
4448
+ const state$2 = {
4441
4449
  session: undefined
4442
4450
  };
4443
4451
  const has = () => {
4444
- return Boolean(state$1.session);
4452
+ return Boolean(state$2.session);
4445
4453
  };
4446
4454
  const get$2 = () => {
4447
- if (!state$1.session) {
4455
+ if (!state$2.session) {
4448
4456
  throw new Error('session is not defined');
4449
4457
  }
4450
- return state$1.session;
4458
+ return state$2.session;
4451
4459
  };
4452
4460
  const set$1 = value => {
4453
- state$1.session = value;
4461
+ state$2.session = value;
4454
4462
  };
4455
4463
 
4456
4464
  const create$2 = rpc => {
@@ -4493,6 +4501,28 @@ class WindowLoadError extends VError {
4493
4501
  }
4494
4502
  }
4495
4503
 
4504
+ const state$1 = {
4505
+ console: undefined
4506
+ };
4507
+ const getOrCreateLogger = () => {
4508
+ state$1.console ||= createFileLogger('log-window.txt');
4509
+ return state$1.console;
4510
+ };
4511
+ const formatMessage = ({
4512
+ level,
4513
+ lineNumber,
4514
+ message,
4515
+ sourceId
4516
+ }) => {
4517
+ const source = sourceId ? ` (${sourceId}:${lineNumber})` : '';
4518
+ return `${new Date().toISOString()} [${level}] [Window] ${message}${source}`;
4519
+ };
4520
+ const addListener = (webContents, logger = getOrCreateLogger()) => {
4521
+ webContents.on('console-message', event => {
4522
+ logger.log(formatMessage(event));
4523
+ });
4524
+ };
4525
+
4496
4526
  // TODO impossible to test these methods
4497
4527
  // and ensure that there is no memory leak
4498
4528
 
@@ -4513,9 +4543,6 @@ const addDevDiagnostics = window => {
4513
4543
  if (!process.env.DEV) {
4514
4544
  return;
4515
4545
  }
4516
- window.webContents.on('console-message', (_event, level, message, line, sourceId) => {
4517
- info(`[app window console] level=${level} source=${sourceId}:${line} message=${message}`);
4518
- });
4519
4546
  window.webContents.on('did-fail-load', (_event, errorCode, errorDescription, validatedUrl, isMainFrame) => {
4520
4547
  error(`[app window did-fail-load] code=${errorCode} mainFrame=${isMainFrame} url=${validatedUrl} error=${errorDescription}`);
4521
4548
  });
@@ -4539,6 +4566,7 @@ const createAppWindow = async (windowOptions, parsedArgs, workingDirectory, titl
4539
4566
  }
4540
4567
  });
4541
4568
  mark(DidCreateCodeWindow);
4569
+ addListener(window.webContents);
4542
4570
  addDevDiagnostics(window);
4543
4571
  const handleReadyToShow = () => {
4544
4572
  // due to electron bug, zoom level needs to be set here,
@@ -4860,6 +4888,106 @@ const openContextMenu = async (menuItems, x, y) => {
4860
4888
  }
4861
4889
  };
4862
4890
 
4891
+ const profileDuration = 10_000;
4892
+ const getFileName$1 = targetName => {
4893
+ const safeTargetName = targetName.replaceAll(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-/, '').replace(/-$/, '') || 'extension-host';
4894
+ return `${safeTargetName}-${Date.now()}.cpuprofile`;
4895
+ };
4896
+ const wait = async () => {
4897
+ await new Promise(resolve => {
4898
+ setTimeout(resolve, profileDuration);
4899
+ });
4900
+ };
4901
+ const takeCpuProfile = async (windowId, workerName) => {
4902
+ const browserWindow = Electron.BrowserWindow.fromId(windowId);
4903
+ if (!browserWindow) {
4904
+ throw new Error(`Browser window not found: ${windowId}`);
4905
+ }
4906
+ const electronDebugger = browserWindow.webContents.debugger;
4907
+ const wasAttached = electronDebugger.isAttached();
4908
+ let filePath = '';
4909
+ let profileStarted = false;
4910
+ let profileStopped = false;
4911
+ let sessionId;
4912
+ let success = false;
4913
+ if (!wasAttached) {
4914
+ electronDebugger.attach();
4915
+ }
4916
+ try {
4917
+ if (workerName) {
4918
+ const {
4919
+ frameTree
4920
+ } = await electronDebugger.sendCommand('Page.getFrameTree');
4921
+ const {
4922
+ targetInfos
4923
+ } = await electronDebugger.sendCommand('Target.getTargets');
4924
+ const target = targetInfos.find(targetInfo => targetInfo.type === 'worker' && targetInfo.title === workerName && targetInfo.parentFrameId === frameTree.frame.id);
4925
+ if (!target) {
4926
+ throw new Error(`Worker not found: ${workerName}`);
4927
+ }
4928
+ const attachResult = await electronDebugger.sendCommand('Target.attachToTarget', {
4929
+ flatten: true,
4930
+ targetId: target.targetId
4931
+ });
4932
+ sessionId = attachResult.sessionId;
4933
+ }
4934
+ await electronDebugger.sendCommand('Profiler.enable', undefined, sessionId);
4935
+ await electronDebugger.sendCommand('Profiler.start', undefined, sessionId);
4936
+ profileStarted = true;
4937
+ await wait();
4938
+ const {
4939
+ profile
4940
+ } = await electronDebugger.sendCommand('Profiler.stop', undefined, sessionId);
4941
+ profileStopped = true;
4942
+ const downloadsPath = Electron.app.getPath('downloads');
4943
+ mkdirSync(downloadsPath, {
4944
+ recursive: true
4945
+ });
4946
+ const targetName = workerName || `Extension Host Window ${windowId}`;
4947
+ filePath = join$1(downloadsPath, getFileName$1(targetName));
4948
+ writeFileSync(filePath, JSON.stringify(profile), {
4949
+ flag: 'wx'
4950
+ });
4951
+ success = true;
4952
+ return filePath;
4953
+ } finally {
4954
+ try {
4955
+ if (profileStarted && !profileStopped && electronDebugger.isAttached()) {
4956
+ await electronDebugger.sendCommand('Profiler.stop', undefined, sessionId);
4957
+ }
4958
+ if (electronDebugger.isAttached()) {
4959
+ await electronDebugger.sendCommand('Profiler.disable', undefined, sessionId);
4960
+ }
4961
+ } finally {
4962
+ try {
4963
+ if (!success && filePath) {
4964
+ rmSync(filePath, {
4965
+ force: true
4966
+ });
4967
+ }
4968
+ if (sessionId && electronDebugger.isAttached()) {
4969
+ await electronDebugger.sendCommand('Target.detachFromTarget', {
4970
+ sessionId
4971
+ });
4972
+ }
4973
+ } finally {
4974
+ if (!wasAttached && electronDebugger.isAttached()) {
4975
+ electronDebugger.detach();
4976
+ }
4977
+ }
4978
+ }
4979
+ }
4980
+ };
4981
+ const takeWindowCpuProfile = async windowId => {
4982
+ number(windowId);
4983
+ return takeCpuProfile(windowId, '');
4984
+ };
4985
+ const takeWorkerCpuProfile = async (windowId, workerName) => {
4986
+ number(windowId);
4987
+ string(workerName);
4988
+ return takeCpuProfile(windowId, workerName);
4989
+ };
4990
+
4863
4991
  const getFileName = workerName => {
4864
4992
  const safeWorkerName = workerName.replaceAll(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-/, '').replace(/-$/, '') || 'worker';
4865
4993
  return `${safeWorkerName}-${Date.now()}.heapsnapshot`;
@@ -6573,6 +6701,8 @@ const commandMap = {
6573
6701
  'ElectronContextMenu.openContextMenu': openContextMenu,
6574
6702
  'ElectronDeveloper.crashMainProcess': crashMainProcess,
6575
6703
  'ElectronDeveloper.getPerformanceEntries': getPerformanceEntries,
6704
+ 'ElectronDeveloper.takeWindowCpuProfile': takeWindowCpuProfile,
6705
+ 'ElectronDeveloper.takeWorkerCpuProfile': takeWorkerCpuProfile,
6576
6706
  'ElectronDeveloper.takeWorkerHeapSnapshot': takeWorkerHeapSnapshot,
6577
6707
  'ElectronDialog.showMessageBox': showMessageBox,
6578
6708
  'ElectronDialog.showOpenDialog': showOpenDialog,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-process",
3
- "version": "6.12.0",
3
+ "version": "6.14.0",
4
4
  "keywords": [
5
5
  "lvce-editor",
6
6
  "electron"