aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/main/src')
-rw-r--r--packages/main/src/controllers/__tests__/initConfig.spec.ts20
-rw-r--r--packages/main/src/controllers/__tests__/initNativeTheme.spec.ts8
-rw-r--r--packages/main/src/controllers/initConfig.ts21
-rw-r--r--packages/main/src/devTools.ts16
-rw-r--r--packages/main/src/index.ts108
-rw-r--r--packages/main/src/init.ts9
-rw-r--r--packages/main/src/services/ConfigPersistenceService.ts4
-rw-r--r--packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts22
-rw-r--r--packages/main/src/stores/MainStore.ts46
-rw-r--r--packages/main/src/stores/SharedStore.ts5
-rw-r--r--packages/main/src/utils/log.ts7
11 files changed, 161 insertions, 105 deletions
diff --git a/packages/main/src/controllers/__tests__/initConfig.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts
index e386a07..7b6d6ab 100644
--- a/packages/main/src/controllers/__tests__/initConfig.spec.ts
+++ b/packages/main/src/controllers/__tests__/initConfig.spec.ts
@@ -60,8 +60,12 @@ describe('when initializing', () => {
60 }); 60 });
61 61
62 it('should bail if there is an an error creating the config file', async () => { 62 it('should bail if there is an an error creating the config file', async () => {
63 mocked(persistenceService.writeConfig).mockRejectedValue(new Error('boo')); 63 mocked(persistenceService.writeConfig).mockRejectedValue(
64 await expect(() => initConfig(config, persistenceService)).rejects.toBeInstanceOf(Error); 64 new Error('boo'),
65 );
66 await expect(() =>
67 initConfig(config, persistenceService),
68 ).rejects.toBeInstanceOf(Error);
65 }); 69 });
66 }); 70 });
67 71
@@ -85,7 +89,9 @@ describe('when initializing', () => {
85 mocked(persistenceService.watchConfig).mockImplementationOnce(() => { 89 mocked(persistenceService.watchConfig).mockImplementationOnce(() => {
86 throw new Error('boo'); 90 throw new Error('boo');
87 }); 91 });
88 await expect(() => initConfig(config, persistenceService)).rejects.toBeInstanceOf(Error); 92 await expect(() =>
93 initConfig(config, persistenceService),
94 ).rejects.toBeInstanceOf(Error);
89 }); 95 });
90 }); 96 });
91 97
@@ -102,7 +108,9 @@ describe('when initializing', () => {
102 108
103 it('should bail if it cannot determine whether there is a config file', async () => { 109 it('should bail if it cannot determine whether there is a config file', async () => {
104 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo')); 110 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo'));
105 await expect(() => initConfig(config, persistenceService)).rejects.toBeInstanceOf(Error); 111 await expect(() =>
112 initConfig(config, persistenceService),
113 ).rejects.toBeInstanceOf(Error);
106 }); 114 });
107}); 115});
108 116
@@ -118,7 +126,9 @@ describe('when it has loaded the config', () => {
118 }); 126 });
119 mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); 127 mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer);
120 sutDisposer = await initConfig(config, persistenceService, throttleMs); 128 sutDisposer = await initConfig(config, persistenceService, throttleMs);
121 [[configChangedCallback]] = mocked(persistenceService.watchConfig).mock.calls; 129 [[configChangedCallback]] = mocked(
130 persistenceService.watchConfig,
131 ).mock.calls;
122 jest.resetAllMocks(); 132 jest.resetAllMocks();
123 }); 133 });
124 134
diff --git a/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
index bd33f48..d4068af 100644
--- a/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
+++ b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
@@ -58,14 +58,18 @@ it('should synchronize themeSource changes to the nativeTheme', () => {
58}); 58});
59 59
60it('should synchronize shouldUseDarkColors changes to the store', () => { 60it('should synchronize shouldUseDarkColors changes to the store', () => {
61 const listener = mocked(nativeTheme.on).mock.calls.find(([event]) => event === 'updated')![1]; 61 const listener = mocked(nativeTheme.on).mock.calls.find(
62 ([event]) => event === 'updated',
63 )![1];
62 shouldUseDarkColors = true; 64 shouldUseDarkColors = true;
63 listener(); 65 listener();
64 expect(store.shared.shouldUseDarkColors).toBe(true); 66 expect(store.shared.shouldUseDarkColors).toBe(true);
65}); 67});
66 68
67it('should remove the listener on dispose', () => { 69it('should remove the listener on dispose', () => {
68 const listener = mocked(nativeTheme.on).mock.calls.find(([event]) => event === 'updated')![1]; 70 const listener = mocked(nativeTheme.on).mock.calls.find(
71 ([event]) => event === 'updated',
72 )![1];
69 disposeSut(); 73 disposeSut();
70 expect(nativeTheme.off).toBeCalledWith('updated', listener); 74 expect(nativeTheme.off).toBeCalledWith('updated', listener);
71}); 75});
diff --git a/packages/main/src/controllers/initConfig.ts b/packages/main/src/controllers/initConfig.ts
index 1d40762..e83b8da 100644
--- a/packages/main/src/controllers/initConfig.ts
+++ b/packages/main/src/controllers/initConfig.ts
@@ -59,20 +59,23 @@ export default async function initConfig(
59 lastSnapshotOnDisk = snapshot; 59 lastSnapshotOnDisk = snapshot;
60 } 60 }
61 61
62 if (!await readConfig()) { 62 if (!(await readConfig())) {
63 log.info('Config file was not found'); 63 log.info('Config file was not found');
64 await writeConfig(); 64 await writeConfig();
65 log.info('Created config file'); 65 log.info('Created config file');
66 } 66 }
67 67
68 const disposeOnSnapshot = onSnapshot(config, debounce((snapshot) => { 68 const disposeOnSnapshot = onSnapshot(
69 // We can compare snapshots by reference, since it is only recreated on store changes. 69 config,
70 if (lastSnapshotOnDisk !== snapshot) { 70 debounce((snapshot) => {
71 writeConfig().catch((err) => { 71 // We can compare snapshots by reference, since it is only recreated on store changes.
72 log.error('Failed to write config on config change', err); 72 if (lastSnapshotOnDisk !== snapshot) {
73 }); 73 writeConfig().catch((err) => {
74 } 74 log.error('Failed to write config on config change', err);
75 }, debounceTime)); 75 });
76 }
77 }, debounceTime),
78 );
76 79
77 const disposeWatcher = persistenceService.watchConfig(async () => { 80 const disposeWatcher = persistenceService.watchConfig(async () => {
78 try { 81 try {
diff --git a/packages/main/src/devTools.ts b/packages/main/src/devTools.ts
index 0486c36..69f1514 100644
--- a/packages/main/src/devTools.ts
+++ b/packages/main/src/devTools.ts
@@ -52,18 +52,12 @@ export async function installDevToolsExtensions(): Promise<void> {
52 @typescript-eslint/no-var-requires 52 @typescript-eslint/no-var-requires
53 */ 53 */
54 } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); 54 } = require('electron-devtools-installer') as typeof import('electron-devtools-installer');
55 await installExtension( 55 await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], {
56 [ 56 forceDownload: false,
57 REACT_DEVELOPER_TOOLS, 57 loadExtensionOptions: {
58 REDUX_DEVTOOLS, 58 allowFileAccess: true,
59 ],
60 {
61 forceDownload: false,
62 loadExtensionOptions: {
63 allowFileAccess: true,
64 },
65 }, 59 },
66 ); 60 });
67} 61}
68 62
69/** 63/**
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts
index bc10b4c..1f80e44 100644
--- a/packages/main/src/index.ts
+++ b/packages/main/src/index.ts
@@ -33,12 +33,7 @@ import {
33 MainToRendererIpcMessage, 33 MainToRendererIpcMessage,
34 RendererToMainIpcMessage, 34 RendererToMainIpcMessage,
35} from '@sophie/shared'; 35} from '@sophie/shared';
36import { 36import { app, BrowserView, BrowserWindow, ipcMain } from 'electron';
37 app,
38 BrowserView,
39 BrowserWindow,
40 ipcMain,
41} from 'electron';
42import { ensureDirSync, readFile, readFileSync } from 'fs-extra'; 37import { ensureDirSync, readFile, readFileSync } from 'fs-extra';
43import { autorun } from 'mobx'; 38import { autorun } from 'mobx';
44import { getSnapshot, onPatch } from 'mobx-state-tree'; 39import { getSnapshot, onPatch } from 'mobx-state-tree';
@@ -97,7 +92,9 @@ app.setAboutPanelOptions({
97 `Node.js: ${process.versions.node}`, 92 `Node.js: ${process.versions.node}`,
98 `Platform: ${osName()}`, 93 `Platform: ${osName()}`,
99 `Arch: ${arch()}`, 94 `Arch: ${arch()}`,
100 `Build date: ${new Date(Number(import.meta.env.BUILD_DATE)).toLocaleString()}`, 95 `Build date: ${new Date(
96 Number(import.meta.env.BUILD_DATE),
97 ).toLocaleString()}`,
101 `Git SHA: ${import.meta.env.GIT_SHA}`, 98 `Git SHA: ${import.meta.env.GIT_SHA}`,
102 `Git branch: ${import.meta.env.GIT_BRANCH}`, 99 `Git branch: ${import.meta.env.GIT_BRANCH}`,
103 ].join('\n'), 100 ].join('\n'),
@@ -123,11 +120,13 @@ const serviceInject: WebSource = {
123let mainWindow: BrowserWindow | null = null; 120let mainWindow: BrowserWindow | null = null;
124 121
125const store = createMainStore(); 122const store = createMainStore();
126init(store).then((disposeCompositionRoot) => { 123init(store)
127 app.on('will-quit', disposeCompositionRoot); 124 .then((disposeCompositionRoot) => {
128}).catch((err) => { 125 app.on('will-quit', disposeCompositionRoot);
129 log.log('Failed to initialize application', err); 126 })
130}); 127 .catch((err) => {
128 log.log('Failed to initialize application', err);
129 });
131 130
132const rendererBaseUrl = getResourceUrl('../renderer/'); 131const rendererBaseUrl = getResourceUrl('../renderer/');
133function shouldCancelMainWindowRequest(url: string, method: string): boolean { 132function shouldCancelMainWindowRequest(url: string, method: string): boolean {
@@ -141,12 +140,20 @@ function shouldCancelMainWindowRequest(url: string, method: string): boolean {
141 return true; 140 return true;
142 } 141 }
143 if (isDevelopment) { 142 if (isDevelopment) {
144 if (DEVMODE_ALLOWED_URL_PREFIXES.some((prefix) => normalizedUrl.startsWith(prefix))) { 143 if (
144 DEVMODE_ALLOWED_URL_PREFIXES.some((prefix) =>
145 normalizedUrl.startsWith(prefix),
146 )
147 ) {
145 return false; 148 return false;
146 } 149 }
147 if (import.meta.env.VITE_DEV_SERVER_URL !== undefined) { 150 if (import.meta.env.VITE_DEV_SERVER_URL !== undefined) {
148 const isHttp = normalizedUrl.startsWith(import.meta.env.VITE_DEV_SERVER_URL); 151 const isHttp = normalizedUrl.startsWith(
149 const isWs = normalizedUrl.startsWith(import.meta.env.VITE_DEV_SERVER_URL.replace(/^http:/, 'ws:')); 152 import.meta.env.VITE_DEV_SERVER_URL,
153 );
154 const isWs = normalizedUrl.startsWith(
155 import.meta.env.VITE_DEV_SERVER_URL.replace(/^http:/, 'ws:'),
156 );
150 return !isHttp && !isWs; 157 return !isHttp && !isWs;
151 } 158 }
152 } 159 }
@@ -168,19 +175,24 @@ async function createWindow(): Promise<unknown> {
168 175
169 webContents.userAgent = originalUserAgent; 176 webContents.userAgent = originalUserAgent;
170 177
171 webContents.session.setPermissionRequestHandler((_webContents, _permission, callback) => { 178 webContents.session.setPermissionRequestHandler(
172 callback(false); 179 (_webContents, _permission, callback) => {
173 }); 180 callback(false);
181 },
182 );
174 183
175 webContents.session.webRequest.onBeforeRequest(({ url, method }, callback) => { 184 webContents.session.webRequest.onBeforeRequest(
176 callback({ 185 ({ url, method }, callback) => {
177 cancel: shouldCancelMainWindowRequest(url, method), 186 callback({
178 }); 187 cancel: shouldCancelMainWindowRequest(url, method),
179 }); 188 });
189 },
190 );
180 191
181 const pageUrl = (isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined) 192 const pageUrl =
182 ? import.meta.env.VITE_DEV_SERVER_URL 193 isDevelopment && import.meta.env.VITE_DEV_SERVER_URL !== undefined
183 : getResourceUrl('../renderer/dist/index.html'); 194 ? import.meta.env.VITE_DEV_SERVER_URL
195 : getResourceUrl('../renderer/dist/index.html');
184 196
185 webContents.on('will-navigate', (event, url) => { 197 webContents.on('will-navigate', (event, url) => {
186 if (url !== pageUrl) { 198 if (url !== pageUrl) {
@@ -273,9 +285,8 @@ async function createWindow(): Promise<unknown> {
273 webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); 285 webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch);
274 }); 286 });
275 287
276 ipcMain.handle( 288 ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) =>
277 ServiceToMainIpcMessage.ApiExposedInMainWorld, 289 event.sender.id === browserView.webContents.id ? serviceInject : null,
278 (event) => (event.sender.id === browserView.webContents.id ? serviceInject : null),
279 ); 290 );
280 291
281 browserView.webContents.on('ipc-message', (_event, channel, ...args) => { 292 browserView.webContents.on('ipc-message', (_event, channel, ...args) => {
@@ -305,7 +316,9 @@ async function createWindow(): Promise<unknown> {
305 316
306 browserView.webContents.session.webRequest.onBeforeSendHeaders( 317 browserView.webContents.session.webRequest.onBeforeSendHeaders(
307 ({ url, requestHeaders }, callback) => { 318 ({ url, requestHeaders }, callback) => {
308 const requestUserAgent = url.match(/^[^:]+:\/\/accounts\.google\.[^./]+\//) 319 const requestUserAgent = url.match(
320 /^[^:]+:\/\/accounts\.google\.[^./]+\//,
321 )
309 ? chromelessUserAgent 322 ? chromelessUserAgent
310 : userAgent; 323 : userAgent;
311 callback({ 324 callback({
@@ -317,9 +330,11 @@ async function createWindow(): Promise<unknown> {
317 }, 330 },
318 ); 331 );
319 332
320 browserView.webContents.loadURL('https://gitlab.com/say-hi-to-sophie/sophie').catch((err) => { 333 browserView.webContents
321 log.error('Failed to load browser', err); 334 .loadURL('https://gitlab.com/say-hi-to-sophie/sophie')
322 }); 335 .catch((err) => {
336 log.error('Failed to load browser', err);
337 });
323 338
324 return mainWindow.loadURL(pageUrl); 339 return mainWindow.loadURL(pageUrl);
325} 340}
@@ -342,17 +357,20 @@ app.on('window-all-closed', () => {
342 } 357 }
343}); 358});
344 359
345app.whenReady().then(async () => { 360app
346 if (isDevelopment) { 361 .whenReady()
347 try { 362 .then(async () => {
348 await installDevToolsExtensions(); 363 if (isDevelopment) {
349 } catch (err) { 364 try {
350 log.error('Failed to install devtools extensions', err); 365 await installDevToolsExtensions();
366 } catch (err) {
367 log.error('Failed to install devtools extensions', err);
368 }
351 } 369 }
352 }
353 370
354 return createWindow(); 371 return createWindow();
355}).catch((err) => { 372 })
356 log.error('Failed to create window', err); 373 .catch((err) => {
357 process.exit(1); 374 log.error('Failed to create window', err);
358}); 375 process.exit(1);
376 });
diff --git a/packages/main/src/init.ts b/packages/main/src/init.ts
index 4487cc4..f3794bb 100644
--- a/packages/main/src/init.ts
+++ b/packages/main/src/init.ts
@@ -27,8 +27,13 @@ import { MainStore } from './stores/MainStore';
27import type Disposer from './utils/Disposer'; 27import type Disposer from './utils/Disposer';
28 28
29export default async function init(store: MainStore): Promise<Disposer> { 29export default async function init(store: MainStore): Promise<Disposer> {
30 const configPersistenceService = new ConfigPersistenceServiceImpl(app.getPath('userData')); 30 const configPersistenceService = new ConfigPersistenceServiceImpl(
31 const disposeConfigController = await initConfig(store.config, configPersistenceService); 31 app.getPath('userData'),
32 );
33 const disposeConfigController = await initConfig(
34 store.config,
35 configPersistenceService,
36 );
32 const disposeNativeThemeController = initNativeTheme(store); 37 const disposeNativeThemeController = initNativeTheme(store);
33 38
34 return () => { 39 return () => {
diff --git a/packages/main/src/services/ConfigPersistenceService.ts b/packages/main/src/services/ConfigPersistenceService.ts
index 7d508c5..ee5696d 100644
--- a/packages/main/src/services/ConfigPersistenceService.ts
+++ b/packages/main/src/services/ConfigPersistenceService.ts
@@ -21,7 +21,9 @@
21import type { ConfigSnapshotOut } from '../stores/Config'; 21import type { ConfigSnapshotOut } from '../stores/Config';
22import type Disposer from '../utils/Disposer'; 22import type Disposer from '../utils/Disposer';
23 23
24export type ReadConfigResult = { found: true; data: unknown; } | { found: false; }; 24export type ReadConfigResult =
25 | { found: true; data: unknown }
26 | { found: false };
25 27
26export default interface ConfigPersistenceService { 28export default interface ConfigPersistenceService {
27 readConfig(): Promise<ReadConfigResult>; 29 readConfig(): Promise<ReadConfigResult>;
diff --git a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts
index df8c807..e92f706 100644
--- a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts
+++ b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts
@@ -32,7 +32,9 @@ import type { ReadConfigResult } from '../ConfigPersistenceService';
32 32
33const log = getLogger('configPersistence'); 33const log = getLogger('configPersistence');
34 34
35export default class ConfigPersistenceServiceImpl implements ConfigPersistenceService { 35export default class ConfigPersistenceServiceImpl
36 implements ConfigPersistenceService
37{
36 private readonly configFilePath: string; 38 private readonly configFilePath: string;
37 39
38 private writingConfig = false; 40 private writingConfig = false;
@@ -92,13 +94,19 @@ export default class ConfigPersistenceServiceImpl implements ConfigPersistenceSe
92 log.trace('Config file last modified at', mtime); 94 log.trace('Config file last modified at', mtime);
93 } catch (err) { 95 } catch (err) {
94 if ((err as NodeJS.ErrnoException).code === 'ENOENT') { 96 if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
95 log.debug('Config file', this.configFilePath, 'was deleted after being changed'); 97 log.debug(
98 'Config file',
99 this.configFilePath,
100 'was deleted after being changed',
101 );
96 return; 102 return;
97 } 103 }
98 throw err; 104 throw err;
99 } 105 }
100 if (!this.writingConfig 106 if (
101 && (this.timeLastWritten === null || mtime > this.timeLastWritten)) { 107 !this.writingConfig &&
108 (this.timeLastWritten === null || mtime > this.timeLastWritten)
109 ) {
102 log.debug( 110 log.debug(
103 'Found a config file modified at', 111 'Found a config file modified at',
104 mtime, 112 mtime,
@@ -114,8 +122,10 @@ export default class ConfigPersistenceServiceImpl implements ConfigPersistenceSe
114 }); 122 });
115 123
116 watcher.on('change', (eventType, filename) => { 124 watcher.on('change', (eventType, filename) => {
117 if (eventType === 'change' 125 if (
118 && (filename === this.configFileName || filename === null)) { 126 eventType === 'change' &&
127 (filename === this.configFileName || filename === null)
128 ) {
119 configChanged()?.catch((err) => { 129 configChanged()?.catch((err) => {
120 log.error('Unhandled error while listening for config changes', err); 130 log.error('Unhandled error while listening for config changes', err);
121 }); 131 });
diff --git a/packages/main/src/stores/MainStore.ts b/packages/main/src/stores/MainStore.ts
index 7b26c52..eaf5b3c 100644
--- a/packages/main/src/stores/MainStore.ts
+++ b/packages/main/src/stores/MainStore.ts
@@ -24,26 +24,32 @@ import { applySnapshot, Instance, types } from 'mobx-state-tree';
24import type { Config } from './Config.js'; 24import type { Config } from './Config.js';
25import { sharedStore } from './SharedStore'; 25import { sharedStore } from './SharedStore';
26 26
27export const mainStore = types.model('MainStore', { 27export const mainStore = types
28 browserViewBounds: types.optional(types.model('BrowserViewBounds', { 28 .model('MainStore', {
29 x: 0, 29 browserViewBounds: types.optional(
30 y: 0, 30 types.model('BrowserViewBounds', {
31 width: 0, 31 x: 0,
32 height: 0, 32 y: 0,
33 }), {}), 33 width: 0,
34 shared: types.optional(sharedStore, {}), 34 height: 0,
35}).views((self) => ({ 35 }),
36 get config(): Config { 36 {},
37 return self.shared.config; 37 ),
38 }, 38 shared: types.optional(sharedStore, {}),
39})).actions((self) => ({ 39 })
40 setBrowserViewBounds(bounds: BrowserViewBounds): void { 40 .views((self) => ({
41 applySnapshot(self.browserViewBounds, bounds); 41 get config(): Config {
42 }, 42 return self.shared.config;
43 setShouldUseDarkColors(shouldUseDarkColors: boolean): void { 43 },
44 self.shared.shouldUseDarkColors = shouldUseDarkColors; 44 }))
45 }, 45 .actions((self) => ({
46})); 46 setBrowserViewBounds(bounds: BrowserViewBounds): void {
47 applySnapshot(self.browserViewBounds, bounds);
48 },
49 setShouldUseDarkColors(shouldUseDarkColors: boolean): void {
50 self.shared.shouldUseDarkColors = shouldUseDarkColors;
51 },
52 }));
47 53
48export interface MainStore extends Instance<typeof mainStore> {} 54export interface MainStore extends Instance<typeof mainStore> {}
49 55
diff --git a/packages/main/src/stores/SharedStore.ts b/packages/main/src/stores/SharedStore.ts
index c023fc7..73245cd 100644
--- a/packages/main/src/stores/SharedStore.ts
+++ b/packages/main/src/stores/SharedStore.ts
@@ -23,7 +23,10 @@ import { Instance, types } from 'mobx-state-tree';
23 23
24import { config } from './Config'; 24import { config } from './Config';
25 25
26export type { SharedStoreSnapshotIn, SharedStoreSnapshotOut } from '@sophie/shared'; 26export type {
27 SharedStoreSnapshotIn,
28 SharedStoreSnapshotOut,
29} from '@sophie/shared';
27 30
28export const sharedStore = originalSharedStore.props({ 31export const sharedStore = originalSharedStore.props({
29 config: types.optional(config, {}), 32 config: types.optional(config, {}),
diff --git a/packages/main/src/utils/log.ts b/packages/main/src/utils/log.ts
index c704797..5218721 100644
--- a/packages/main/src/utils/log.ts
+++ b/packages/main/src/utils/log.ts
@@ -46,9 +46,10 @@ prefix.apply(loglevel, {
46 format(level, name, timestamp) { 46 format(level, name, timestamp) {
47 const levelColor = getColor(level); 47 const levelColor = getColor(level);
48 const timeStr = timestamp.toString(); 48 const timeStr = timestamp.toString();
49 const nameStr = typeof name === 'undefined' 49 const nameStr =
50 ? levelColor(':') 50 typeof name === 'undefined'
51 : ` ${chalk.green(`${name}:`)}`; 51 ? levelColor(':')
52 : ` ${chalk.green(`${name}:`)}`;
52 return `${chalk.gray(`[${timeStr}]`)} ${levelColor(level)}${nameStr}`; 53 return `${chalk.gray(`[${timeStr}]`)} ${levelColor(level)}${nameStr}`;
53 }, 54 },
54}); 55});