aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/main/esbuild.config.js33
-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
-rw-r--r--packages/main/tsconfig.json5
-rw-r--r--packages/main/types/importMeta.d.ts2
-rw-r--r--packages/preload/esbuild.config.js8
-rw-r--r--packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts56
-rw-r--r--packages/preload/src/contextBridge/createSophieRenderer.ts29
-rw-r--r--packages/preload/tsconfig.json10
-rw-r--r--packages/preload/types/importMeta.d.ts2
-rw-r--r--packages/renderer/.eslinrc.cjs5
-rw-r--r--packages/renderer/index.html9
-rw-r--r--packages/renderer/src/components/BrowserViewPlaceholder.tsx55
-rw-r--r--packages/renderer/src/components/StoreProvider.tsx13
-rw-r--r--packages/renderer/src/components/ThemeProvider.tsx28
-rw-r--r--packages/renderer/src/components/ToggleDarkModeButton.tsx4
-rw-r--r--packages/renderer/src/devTools.ts4
-rw-r--r--packages/renderer/src/stores/RendererStore.ts81
-rw-r--r--packages/renderer/tsconfig.json10
-rw-r--r--packages/renderer/vite.config.js10
-rw-r--r--packages/service-inject/.eslintrc.cjs5
-rw-r--r--packages/service-inject/esbuild.config.js4
-rw-r--r--packages/service-inject/tsconfig.json12
-rw-r--r--packages/service-preload/esbuild.config.js8
-rw-r--r--packages/service-preload/tsconfig.json6
-rw-r--r--packages/service-preload/types/importMeta.d.ts2
-rw-r--r--packages/service-shared/.eslintrc.cjs5
-rw-r--r--packages/service-shared/esbuild.config.js8
-rw-r--r--packages/service-shared/src/index.ts10
-rw-r--r--packages/service-shared/src/ipc.ts3
-rw-r--r--packages/service-shared/tsconfig.build.json4
-rw-r--r--packages/service-shared/tsconfig.json6
-rw-r--r--packages/shared/.eslintrc.cjs5
-rw-r--r--packages/shared/esbuild.config.js10
-rw-r--r--packages/shared/src/index.ts18
-rw-r--r--packages/shared/src/stores/Config.ts7
-rw-r--r--packages/shared/src/stores/SharedStore.ts3
-rw-r--r--packages/shared/tsconfig.build.json4
-rw-r--r--packages/shared/tsconfig.json6
48 files changed, 379 insertions, 377 deletions
diff --git a/packages/main/esbuild.config.js b/packages/main/esbuild.config.js
index 49fba6b..d5f6f1e 100644
--- a/packages/main/esbuild.config.js
+++ b/packages/main/esbuild.config.js
@@ -12,19 +12,20 @@ if (process.env.MODE !== 'development') {
12 12
13const gitInfo = getRepoInfo(); 13const gitInfo = getRepoInfo();
14 14
15export default getEsbuildConfig({ 15export default getEsbuildConfig(
16 absWorkingDir: fileURLToDirname(import.meta.url), 16 {
17 entryPoints: [ 17 absWorkingDir: fileURLToDirname(import.meta.url),
18 'src/index.ts', 18 entryPoints: ['src/index.ts'],
19 ], 19 outfile: 'dist/index.cjs',
20 outfile: 'dist/index.cjs', 20 format: 'cjs',
21 format: 'cjs', 21 platform: 'node',
22 platform: 'node', 22 target: node,
23 target: node, 23 external: externalPackages,
24 external: externalPackages, 24 },
25}, { 25 {
26 VITE_DEV_SERVER_URL: process.env.VITE_DEV_SERVER_URL || null, 26 VITE_DEV_SERVER_URL: process.env.VITE_DEV_SERVER_URL || null,
27 GIT_SHA: gitInfo.abbreviatedSha, 27 GIT_SHA: gitInfo.abbreviatedSha,
28 GIT_BRANCH: gitInfo.branch, 28 GIT_BRANCH: gitInfo.branch,
29 BUILD_DATE: new Date().getTime(), 29 BUILD_DATE: new Date().getTime(),
30}); 30 },
31);
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});
diff --git a/packages/main/tsconfig.json b/packages/main/tsconfig.json
index bdf68f4..dad597d 100644
--- a/packages/main/tsconfig.json
+++ b/packages/main/tsconfig.json
@@ -2,10 +2,7 @@
2 "extends": "../../config/tsconfig.base.json", 2 "extends": "../../config/tsconfig.base.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "noEmit": true, 4 "noEmit": true,
5 "types": [ 5 "types": ["@types/jest", "node"]
6 "@types/jest",
7 "node"
8 ]
9 }, 6 },
10 "references": [ 7 "references": [
11 { 8 {
diff --git a/packages/main/types/importMeta.d.ts b/packages/main/types/importMeta.d.ts
index e422c30..efcf48a 100644
--- a/packages/main/types/importMeta.d.ts
+++ b/packages/main/types/importMeta.d.ts
@@ -7,5 +7,5 @@ interface ImportMeta {
7 GIT_SHA: string; 7 GIT_SHA: string;
8 GIT_BRANCH: string; 8 GIT_BRANCH: string;
9 BUILD_DATE: number; 9 BUILD_DATE: number;
10 } 10 };
11} 11}
diff --git a/packages/preload/esbuild.config.js b/packages/preload/esbuild.config.js
index 66f5e84..d888987 100644
--- a/packages/preload/esbuild.config.js
+++ b/packages/preload/esbuild.config.js
@@ -4,15 +4,11 @@ import getEsbuildConfig from '../../config/getEsbuildConfig.js';
4 4
5export default getEsbuildConfig({ 5export default getEsbuildConfig({
6 absWorkingDir: fileURLToDirname(import.meta.url), 6 absWorkingDir: fileURLToDirname(import.meta.url),
7 entryPoints: [ 7 entryPoints: ['src/index.ts'],
8 'src/index.ts',
9 ],
10 outfile: 'dist/index.cjs', 8 outfile: 'dist/index.cjs',
11 format: 'cjs', 9 format: 'cjs',
12 platform: 'node', 10 platform: 'node',
13 target: chrome, 11 target: chrome,
14 sourcemap: 'inline', 12 sourcemap: 'inline',
15 external: [ 13 external: ['electron'],
16 'electron',
17 ],
18}); 14});
diff --git a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
index a38dbac..f63c3f6 100644
--- a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
+++ b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
@@ -40,9 +40,12 @@ jest.unstable_mockModule('electron', () => ({
40 40
41const { ipcRenderer } = await import('electron'); 41const { ipcRenderer } = await import('electron');
42 42
43const { default: createSophieRenderer } = await import('../createSophieRenderer'); 43const { default: createSophieRenderer } = await import(
44 '../createSophieRenderer'
45);
44 46
45const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; 47const event: Electron.IpcRendererEvent =
48 null as unknown as Electron.IpcRendererEvent;
46 49
47const snapshot: SharedStoreSnapshotIn = { 50const snapshot: SharedStoreSnapshotIn = {
48 shouldUseDarkColors: true, 51 shouldUseDarkColors: true,
@@ -83,7 +86,10 @@ describe('createSophieRenderer', () => {
83 86
84describe('SharedStoreConnector', () => { 87describe('SharedStoreConnector', () => {
85 let sut: SophieRenderer; 88 let sut: SophieRenderer;
86 let onSharedStorePatch: (eventArg: Electron.IpcRendererEvent, patchArg: unknown) => void; 89 let onSharedStorePatch: (
90 eventArg: Electron.IpcRendererEvent,
91 patchArg: unknown,
92 ) => void;
87 const listener = { 93 const listener = {
88 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars 94 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
89 onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => {}), 95 onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => {}),
@@ -102,22 +108,25 @@ describe('SharedStoreConnector', () => {
102 it('should request a snapshot from the main process', async () => { 108 it('should request a snapshot from the main process', async () => {
103 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot); 109 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot);
104 await sut.onSharedStoreChange(listener); 110 await sut.onSharedStoreChange(listener);
105 expect(ipcRenderer.invoke).toBeCalledWith(RendererToMainIpcMessage.GetSharedStoreSnapshot); 111 expect(ipcRenderer.invoke).toBeCalledWith(
112 RendererToMainIpcMessage.GetSharedStoreSnapshot,
113 );
106 expect(listener.onSnapshot).toBeCalledWith(snapshot); 114 expect(listener.onSnapshot).toBeCalledWith(snapshot);
107 }); 115 });
108 116
109 it('should catch IPC errors without exposing them', async () => { 117 it('should catch IPC errors without exposing them', async () => {
110 mocked(ipcRenderer.invoke).mockRejectedValue(new Error('s3cr3t')); 118 mocked(ipcRenderer.invoke).mockRejectedValue(new Error('s3cr3t'));
111 await expect(sut.onSharedStoreChange(listener)).rejects.not.toHaveProperty( 119 await expect(
112 'message', 120 sut.onSharedStoreChange(listener),
113 expect.stringMatching(/s3cr3t/), 121 ).rejects.not.toHaveProperty('message', expect.stringMatching(/s3cr3t/));
114 );
115 expect(listener.onSnapshot).not.toBeCalled(); 122 expect(listener.onSnapshot).not.toBeCalled();
116 }); 123 });
117 124
118 it('should not pass on invalid snapshots', async () => { 125 it('should not pass on invalid snapshots', async () => {
119 mocked(ipcRenderer.invoke).mockResolvedValueOnce(invalidSnapshot); 126 mocked(ipcRenderer.invoke).mockResolvedValueOnce(invalidSnapshot);
120 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(Error); 127 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(
128 Error,
129 );
121 expect(listener.onSnapshot).not.toBeCalled(); 130 expect(listener.onSnapshot).not.toBeCalled();
122 }); 131 });
123 }); 132 });
@@ -125,7 +134,10 @@ describe('SharedStoreConnector', () => {
125 describe('dispatchAction', () => { 134 describe('dispatchAction', () => {
126 it('should dispatch valid actions', () => { 135 it('should dispatch valid actions', () => {
127 sut.dispatchAction(action); 136 sut.dispatchAction(action);
128 expect(ipcRenderer.send).toBeCalledWith(RendererToMainIpcMessage.DispatchAction, action); 137 expect(ipcRenderer.send).toBeCalledWith(
138 RendererToMainIpcMessage.DispatchAction,
139 action,
140 );
129 }); 141 });
130 142
131 it('should not dispatch invalid actions', () => { 143 it('should not dispatch invalid actions', () => {
@@ -142,7 +154,9 @@ describe('SharedStoreConnector', () => {
142 154
143 function itRefusesToRegisterAnotherListener(): void { 155 function itRefusesToRegisterAnotherListener(): void {
144 it('should refuse to register another listener', async () => { 156 it('should refuse to register another listener', async () => {
145 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(Error); 157 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(
158 Error,
159 );
146 }); 160 });
147 } 161 }
148 162
@@ -167,7 +181,9 @@ describe('SharedStoreConnector', () => {
167 }); 181 });
168 182
169 it('should catch listener errors', () => { 183 it('should catch listener errors', () => {
170 mocked(listener.onPatch).mockImplementation(() => { throw new Error(); }); 184 mocked(listener.onPatch).mockImplementation(() => {
185 throw new Error();
186 });
171 onSharedStorePatch(event, patch); 187 onSharedStorePatch(event, patch);
172 }); 188 });
173 189
@@ -175,7 +191,9 @@ describe('SharedStoreConnector', () => {
175 191
176 describe('after the listener threw in onPatch', () => { 192 describe('after the listener threw in onPatch', () => {
177 beforeEach(() => { 193 beforeEach(() => {
178 mocked(listener.onPatch).mockImplementation(() => { throw new Error(); }); 194 mocked(listener.onPatch).mockImplementation(() => {
195 throw new Error();
196 });
179 onSharedStorePatch(event, patch); 197 onSharedStorePatch(event, patch);
180 listener.onPatch.mockRestore(); 198 listener.onPatch.mockRestore();
181 }); 199 });
@@ -217,7 +235,9 @@ describe('SharedStoreConnector', () => {
217 describe('when a listener failed to register due to listener error', () => { 235 describe('when a listener failed to register due to listener error', () => {
218 beforeEach(async () => { 236 beforeEach(async () => {
219 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot); 237 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot);
220 mocked(listener.onSnapshot).mockImplementation(() => { throw new Error(); }); 238 mocked(listener.onSnapshot).mockImplementation(() => {
239 throw new Error();
240 });
221 try { 241 try {
222 await sut.onSharedStoreChange(listener); 242 await sut.onSharedStoreChange(listener);
223 } catch { 243 } catch {
@@ -236,15 +256,17 @@ describe('SharedStoreConnector', () => {
236 }; 256 };
237 const listener2 = { 257 const listener2 = {
238 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars 258 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
239 onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => { }), 259 onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => {}),
240 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars 260 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
241 onPatch: jest.fn((_patch: IJsonPatch) => { }), 261 onPatch: jest.fn((_patch: IJsonPatch) => {}),
242 }; 262 };
243 263
244 it('should fetch a second snapshot', async () => { 264 it('should fetch a second snapshot', async () => {
245 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2); 265 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2);
246 await sut.onSharedStoreChange(listener2); 266 await sut.onSharedStoreChange(listener2);
247 expect(ipcRenderer.invoke).toBeCalledWith(RendererToMainIpcMessage.GetSharedStoreSnapshot); 267 expect(ipcRenderer.invoke).toBeCalledWith(
268 RendererToMainIpcMessage.GetSharedStoreSnapshot,
269 );
248 expect(listener2.onSnapshot).toBeCalledWith(snapshot2); 270 expect(listener2.onSnapshot).toBeCalledWith(snapshot2);
249 }); 271 });
250 272
diff --git a/packages/preload/src/contextBridge/createSophieRenderer.ts b/packages/preload/src/contextBridge/createSophieRenderer.ts
index 2055080..b97503d 100644
--- a/packages/preload/src/contextBridge/createSophieRenderer.ts
+++ b/packages/preload/src/contextBridge/createSophieRenderer.ts
@@ -37,15 +37,18 @@ class SharedStoreConnector {
37 private listener: SharedStoreListener | null = null; 37 private listener: SharedStoreListener | null = null;
38 38
39 constructor(private readonly allowReplaceListener: boolean) { 39 constructor(private readonly allowReplaceListener: boolean) {
40 ipcRenderer.on(MainToRendererIpcMessage.SharedStorePatch, (_event, patch) => { 40 ipcRenderer.on(
41 try { 41 MainToRendererIpcMessage.SharedStorePatch,
42 // `mobx-state-tree` will validate the patch, so we can safely cast here. 42 (_event, patch) => {
43 this.listener?.onPatch(patch as IJsonPatch); 43 try {
44 } catch (err) { 44 // `mobx-state-tree` will validate the patch, so we can safely cast here.
45 log.error('Shared store listener onPatch failed', err); 45 this.listener?.onPatch(patch as IJsonPatch);
46 this.listener = null; 46 } catch (err) {
47 } 47 log.error('Shared store listener onPatch failed', err);
48 }); 48 this.listener = null;
49 }
50 },
51 );
49 } 52 }
50 53
51 async onSharedStoreChange(listener: SharedStoreListener): Promise<void> { 54 async onSharedStoreChange(listener: SharedStoreListener): Promise<void> {
@@ -56,7 +59,9 @@ class SharedStoreConnector {
56 let success = false; 59 let success = false;
57 let snapshot: unknown | null = null; 60 let snapshot: unknown | null = null;
58 try { 61 try {
59 snapshot = await ipcRenderer.invoke(RendererToMainIpcMessage.GetSharedStoreSnapshot); 62 snapshot = await ipcRenderer.invoke(
63 RendererToMainIpcMessage.GetSharedStoreSnapshot,
64 );
60 success = true; 65 success = true;
61 } catch (err) { 66 } catch (err) {
62 log.error('Failed to get initial shared store snapshot', err); 67 log.error('Failed to get initial shared store snapshot', err);
@@ -87,7 +92,9 @@ function dispatchAction(actionToDispatch: Action): void {
87 } 92 }
88} 93}
89 94
90export default function createSophieRenderer(allowReplaceListener: boolean): SophieRenderer { 95export default function createSophieRenderer(
96 allowReplaceListener: boolean,
97): SophieRenderer {
91 const connector = new SharedStoreConnector(allowReplaceListener); 98 const connector = new SharedStoreConnector(allowReplaceListener);
92 return { 99 return {
93 onSharedStoreChange: connector.onSharedStoreChange.bind(connector), 100 onSharedStoreChange: connector.onSharedStoreChange.bind(connector),
diff --git a/packages/preload/tsconfig.json b/packages/preload/tsconfig.json
index 0cb1390..18c72b4 100644
--- a/packages/preload/tsconfig.json
+++ b/packages/preload/tsconfig.json
@@ -2,14 +2,8 @@
2 "extends": "../../config/tsconfig.base.json", 2 "extends": "../../config/tsconfig.base.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "noEmit": true, 4 "noEmit": true,
5 "lib": [ 5 "lib": ["dom", "dom.iterable", "esnext"],
6 "dom", 6 "types": ["@types/jest"]
7 "dom.iterable",
8 "esnext"
9 ],
10 "types": [
11 "@types/jest"
12 ]
13 }, 7 },
14 "references": [ 8 "references": [
15 { 9 {
diff --git a/packages/preload/types/importMeta.d.ts b/packages/preload/types/importMeta.d.ts
index 9b73170..ff3b17c 100644
--- a/packages/preload/types/importMeta.d.ts
+++ b/packages/preload/types/importMeta.d.ts
@@ -3,5 +3,5 @@ interface ImportMeta {
3 DEV: boolean; 3 DEV: boolean;
4 MODE: string; 4 MODE: string;
5 PROD: boolean; 5 PROD: boolean;
6 } 6 };
7} 7}
diff --git a/packages/renderer/.eslinrc.cjs b/packages/renderer/.eslinrc.cjs
index 37d27ad..ee3cca6 100644
--- a/packages/renderer/.eslinrc.cjs
+++ b/packages/renderer/.eslinrc.cjs
@@ -5,10 +5,7 @@ module.exports = {
5 }, 5 },
6 overrides: [ 6 overrides: [
7 { 7 {
8 files: [ 8 files: ['.eslintrc.cjs', 'vite.config.js'],
9 '.eslintrc.cjs',
10 'vite.config.js',
11 ],
12 env: { 9 env: {
13 browser: false, 10 browser: false,
14 node: true, 11 node: true,
diff --git a/packages/renderer/index.html b/packages/renderer/index.html
index 08469c7..039ce61 100644
--- a/packages/renderer/index.html
+++ b/packages/renderer/index.html
@@ -1,9 +1,12 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html lang="en"> 2<html lang="en">
3 <head> 3 <head>
4 <meta charset="UTF-8"> 4 <meta charset="UTF-8" />
5 <meta http-equiv="Content-Security-Policy" content="script-src 'self' blob:"> 5 <meta
6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 http-equiv="Content-Security-Policy"
7 content="script-src 'self' blob:"
8 />
9 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7 <title>Sophie</title> 10 <title>Sophie</title>
8 </head> 11 </head>
9 <body> 12 <body>
diff --git a/packages/renderer/src/components/BrowserViewPlaceholder.tsx b/packages/renderer/src/components/BrowserViewPlaceholder.tsx
index 11c09d6..8f055e7 100644
--- a/packages/renderer/src/components/BrowserViewPlaceholder.tsx
+++ b/packages/renderer/src/components/BrowserViewPlaceholder.tsx
@@ -29,36 +29,37 @@ export default observer(() => {
29 const store = useStore(); 29 const store = useStore();
30 30
31 // eslint-disable-next-line react-hooks/exhaustive-deps -- react-hooks doesn't support `throttle`. 31 // eslint-disable-next-line react-hooks/exhaustive-deps -- react-hooks doesn't support `throttle`.
32 const onResize = useCallback(throttle(([entry]: ResizeObserverEntry[]) => { 32 const onResize = useCallback(
33 if (entry) { 33 throttle(([entry]: ResizeObserverEntry[]) => {
34 const { 34 if (entry) {
35 x, 35 const { x, y, width, height } = entry.target.getBoundingClientRect();
36 y, 36 store.setBrowserViewBounds({
37 width, 37 x,
38 height, 38 y,
39 } = entry.target.getBoundingClientRect(); 39 width,
40 store.setBrowserViewBounds({ 40 height,
41 x, 41 });
42 y, 42 }
43 width, 43 }, 100),
44 height, 44 [store],
45 }); 45 );
46 }
47 }, 100), [store]);
48 46
49 const resizeObserverRef = useRef<ResizeObserver | null>(null); 47 const resizeObserverRef = useRef<ResizeObserver | null>(null);
50 48
51 const ref = useCallback((element: HTMLElement | null) => { 49 const ref = useCallback(
52 if (resizeObserverRef.current !== null) { 50 (element: HTMLElement | null) => {
53 resizeObserverRef.current.disconnect(); 51 if (resizeObserverRef.current !== null) {
54 } 52 resizeObserverRef.current.disconnect();
55 if (element === null) { 53 }
56 resizeObserverRef.current = null; 54 if (element === null) {
57 return; 55 resizeObserverRef.current = null;
58 } 56 return;
59 resizeObserverRef.current = new ResizeObserver(onResize); 57 }
60 resizeObserverRef.current.observe(element); 58 resizeObserverRef.current = new ResizeObserver(onResize);
61 }, [onResize, resizeObserverRef]); 59 resizeObserverRef.current.observe(element);
60 },
61 [onResize, resizeObserverRef],
62 );
62 63
63 return ( 64 return (
64 <Box 65 <Box
diff --git a/packages/renderer/src/components/StoreProvider.tsx b/packages/renderer/src/components/StoreProvider.tsx
index cde6a31..bb8495c 100644
--- a/packages/renderer/src/components/StoreProvider.tsx
+++ b/packages/renderer/src/components/StoreProvider.tsx
@@ -32,13 +32,14 @@ export function useStore(): RendererStore {
32 return store; 32 return store;
33} 33}
34 34
35export default function StoreProvider({ children, store }: { 35export default function StoreProvider({
36 children: JSX.Element | JSX.Element[], 36 children,
37 store: RendererStore, 37 store,
38}: {
39 children: JSX.Element | JSX.Element[];
40 store: RendererStore;
38}): JSX.Element { 41}): JSX.Element {
39 return ( 42 return (
40 <StoreContext.Provider value={store}> 43 <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
41 {children}
42 </StoreContext.Provider>
43 ); 44 );
44} 45}
diff --git a/packages/renderer/src/components/ThemeProvider.tsx b/packages/renderer/src/components/ThemeProvider.tsx
index eacaa52..3943371 100644
--- a/packages/renderer/src/components/ThemeProvider.tsx
+++ b/packages/renderer/src/components/ThemeProvider.tsx
@@ -27,20 +27,18 @@ import React from 'react';
27 27
28import { useStore } from './StoreProvider'; 28import { useStore } from './StoreProvider';
29 29
30export default observer(({ children }: { 30export default observer(
31 children: JSX.Element | JSX.Element[]; 31 ({ children }: { children: JSX.Element | JSX.Element[] }) => {
32}) => { 32 const {
33 const { shared: { shouldUseDarkColors } } = useStore(); 33 shared: { shouldUseDarkColors },
34 } = useStore();
34 35
35 const theme = createTheme({ 36 const theme = createTheme({
36 palette: { 37 palette: {
37 mode: shouldUseDarkColors ? 'dark' : 'light', 38 mode: shouldUseDarkColors ? 'dark' : 'light',
38 }, 39 },
39 }); 40 });
40 41
41 return ( 42 return <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>;
42 <MuiThemeProvider theme={theme}> 43 },
43 {children} 44);
44 </MuiThemeProvider>
45 );
46});
diff --git a/packages/renderer/src/components/ToggleDarkModeButton.tsx b/packages/renderer/src/components/ToggleDarkModeButton.tsx
index c8ffdf0..695756a 100644
--- a/packages/renderer/src/components/ToggleDarkModeButton.tsx
+++ b/packages/renderer/src/components/ToggleDarkModeButton.tsx
@@ -28,7 +28,9 @@ import { useStore } from './StoreProvider';
28 28
29export default observer(() => { 29export default observer(() => {
30 const store = useStore(); 30 const store = useStore();
31 const { shared: { shouldUseDarkColors } } = store; 31 const {
32 shared: { shouldUseDarkColors },
33 } = store;
32 34
33 return ( 35 return (
34 <IconButton 36 <IconButton
diff --git a/packages/renderer/src/devTools.ts b/packages/renderer/src/devTools.ts
index 3d3ba99..cb695c3 100644
--- a/packages/renderer/src/devTools.ts
+++ b/packages/renderer/src/devTools.ts
@@ -35,7 +35,9 @@ import type { IAnyStateTreeNode } from 'mobx-state-tree';
35 * @return A promise that resolves when the store was exposed to the devtools. 35 * @return A promise that resolves when the store was exposed to the devtools.
36 * @see https://github.com/SocketCluster/socketcluster-client/issues/118#issuecomment-469064682 36 * @see https://github.com/SocketCluster/socketcluster-client/issues/118#issuecomment-469064682
37 */ 37 */
38export async function exposeToReduxDevtools(model: IAnyStateTreeNode): Promise<void> { 38export async function exposeToReduxDevtools(
39 model: IAnyStateTreeNode,
40): Promise<void> {
39 (window as { global?: unknown }).global = window; 41 (window as { global?: unknown }).global = window;
40 42
41 // Hack to load dev dependencies on demand. 43 // Hack to load dev dependencies on demand.
diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts
index e684759..0b78ce1 100644
--- a/packages/renderer/src/stores/RendererStore.ts
+++ b/packages/renderer/src/stores/RendererStore.ts
@@ -24,12 +24,7 @@ import {
24 SophieRenderer, 24 SophieRenderer,
25 ThemeSource, 25 ThemeSource,
26} from '@sophie/shared'; 26} from '@sophie/shared';
27import { 27import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree';
28 applySnapshot,
29 applyPatch,
30 Instance,
31 types,
32} from 'mobx-state-tree';
33 28
34import { getLogger } from '../utils/log'; 29import { getLogger } from '../utils/log';
35 30
@@ -38,29 +33,31 @@ import { getEnv } from './RendererEnv';
38 33
39const log = getLogger('RendererStore'); 34const log = getLogger('RendererStore');
40 35
41export const rendererStore = types.model('RendererStore', { 36export const rendererStore = types
42 shared: types.optional(sharedStore, {}), 37 .model('RendererStore', {
43}).actions((self) => ({ 38 shared: types.optional(sharedStore, {}),
44 setBrowserViewBounds(browserViewBounds: BrowserViewBounds): void { 39 })
45 getEnv(self).dispatchMainAction({ 40 .actions((self) => ({
46 action: 'set-browser-view-bounds', 41 setBrowserViewBounds(browserViewBounds: BrowserViewBounds): void {
47 browserViewBounds, 42 getEnv(self).dispatchMainAction({
48 }); 43 action: 'set-browser-view-bounds',
49 }, 44 browserViewBounds,
50 setThemeSource(themeSource: ThemeSource): void { 45 });
51 getEnv(self).dispatchMainAction({ 46 },
52 action: 'set-theme-source', 47 setThemeSource(themeSource: ThemeSource): void {
53 themeSource, 48 getEnv(self).dispatchMainAction({
54 }); 49 action: 'set-theme-source',
55 }, 50 themeSource,
56 toggleDarkMode(): void { 51 });
57 if (self.shared.shouldUseDarkColors) { 52 },
58 this.setThemeSource('light'); 53 toggleDarkMode(): void {
59 } else { 54 if (self.shared.shouldUseDarkColors) {
60 this.setThemeSource('dark'); 55 this.setThemeSource('light');
61 } 56 } else {
62 }, 57 this.setThemeSource('dark');
63})); 58 }
59 },
60 }));
64 61
65export interface RendererStore extends Instance<typeof rendererStore> {} 62export interface RendererStore extends Instance<typeof rendererStore> {}
66 63
@@ -72,22 +69,26 @@ export interface RendererStore extends Instance<typeof rendererStore> {}
72 * 69 *
73 * @param ipc The `sophieRenderer` context bridge. 70 * @param ipc The `sophieRenderer` context bridge.
74 */ 71 */
75export function createAndConnectRendererStore(ipc: SophieRenderer): RendererStore { 72export function createAndConnectRendererStore(
73 ipc: SophieRenderer,
74): RendererStore {
76 const env: RendererEnv = { 75 const env: RendererEnv = {
77 dispatchMainAction: ipc.dispatchAction, 76 dispatchMainAction: ipc.dispatchAction,
78 }; 77 };
79 const store = rendererStore.create({}, env); 78 const store = rendererStore.create({}, env);
80 79
81 ipc.onSharedStoreChange({ 80 ipc
82 onSnapshot(snapshot) { 81 .onSharedStoreChange({
83 applySnapshot(store.shared, snapshot); 82 onSnapshot(snapshot) {
84 }, 83 applySnapshot(store.shared, snapshot);
85 onPatch(patch) { 84 },
86 applyPatch(store.shared, patch); 85 onPatch(patch) {
87 }, 86 applyPatch(store.shared, patch);
88 }).catch((err) => { 87 },
89 log.error('Failed to connect to shared store', err); 88 })
90 }); 89 .catch((err) => {
90 log.error('Failed to connect to shared store', err);
91 });
91 92
92 return store; 93 return store;
93} 94}
diff --git a/packages/renderer/tsconfig.json b/packages/renderer/tsconfig.json
index 14c3e0c..5453330 100644
--- a/packages/renderer/tsconfig.json
+++ b/packages/renderer/tsconfig.json
@@ -3,14 +3,8 @@
3 "compilerOptions": { 3 "compilerOptions": {
4 "noEmit": true, 4 "noEmit": true,
5 "jsx": "react", 5 "jsx": "react",
6 "lib": [ 6 "lib": ["dom", "dom.iterable", "esnext"],
7 "dom", 7 "types": ["vite/client"]
8 "dom.iterable",
9 "esnext"
10 ],
11 "types": [
12 "vite/client"
13 ]
14 }, 8 },
15 "references": [ 9 "references": [
16 { 10 {
diff --git a/packages/renderer/vite.config.js b/packages/renderer/vite.config.js
index 6440ead..e20e0f1 100644
--- a/packages/renderer/vite.config.js
+++ b/packages/renderer/vite.config.js
@@ -46,9 +46,7 @@ export default {
46 preserveSymlinks: true, 46 preserveSymlinks: true,
47 }, 47 },
48 optimizeDeps: { 48 optimizeDeps: {
49 exclude: [ 49 exclude: ['@sophie/shared'],
50 '@sophie/shared',
51 ],
52 }, 50 },
53 build: { 51 build: {
54 target: chrome, 52 target: chrome,
@@ -59,11 +57,7 @@ export default {
59 minify: !isDevelopment, 57 minify: !isDevelopment,
60 brotliSize: false, 58 brotliSize: false,
61 rollupOptions: { 59 rollupOptions: {
62 external: [ 60 external: ['mst-middlewares', 'remotedev', ...builtinModules],
63 'mst-middlewares',
64 'remotedev',
65 ...builtinModules,
66 ],
67 output: { 61 output: {
68 banner, 62 banner,
69 }, 63 },
diff --git a/packages/service-inject/.eslintrc.cjs b/packages/service-inject/.eslintrc.cjs
index 5555f5b..3131abd 100644
--- a/packages/service-inject/.eslintrc.cjs
+++ b/packages/service-inject/.eslintrc.cjs
@@ -5,10 +5,7 @@ module.exports = {
5 }, 5 },
6 overrides: [ 6 overrides: [
7 { 7 {
8 files: [ 8 files: ['.eslintrc.cjs', 'esbuild.config.js'],
9 '.eslintrc.cjs',
10 'esbuild.config.js',
11 ],
12 env: { 9 env: {
13 browser: false, 10 browser: false,
14 node: true, 11 node: true,
diff --git a/packages/service-inject/esbuild.config.js b/packages/service-inject/esbuild.config.js
index d0b04bb..795b0f6 100644
--- a/packages/service-inject/esbuild.config.js
+++ b/packages/service-inject/esbuild.config.js
@@ -4,9 +4,7 @@ import getEsbuildConfig from '../../config/getEsbuildConfig.js';
4 4
5export default getEsbuildConfig({ 5export default getEsbuildConfig({
6 absWorkingDir: fileURLToDirname(import.meta.url), 6 absWorkingDir: fileURLToDirname(import.meta.url),
7 entryPoints: [ 7 entryPoints: ['src/index.ts'],
8 'src/index.ts',
9 ],
10 outfile: 'dist/index.js', 8 outfile: 'dist/index.js',
11 format: 'iife', 9 format: 'iife',
12 platform: 'browser', 10 platform: 'browser',
diff --git a/packages/service-inject/tsconfig.json b/packages/service-inject/tsconfig.json
index 8f84d98..33ce1de 100644
--- a/packages/service-inject/tsconfig.json
+++ b/packages/service-inject/tsconfig.json
@@ -2,20 +2,12 @@
2 "extends": "../../config/tsconfig.base.json", 2 "extends": "../../config/tsconfig.base.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "noEmit": true, 4 "noEmit": true,
5 "lib": [ 5 "lib": ["dom", "dom.iterable", "esnext"]
6 "dom",
7 "dom.iterable",
8 "esnext"
9 ]
10 }, 6 },
11 "references": [ 7 "references": [
12 { 8 {
13 "path": "../service-shared/tsconfig.build.json" 9 "path": "../service-shared/tsconfig.build.json"
14 } 10 }
15 ], 11 ],
16 "include": [ 12 "include": ["src/**/*.ts", ".eslintrc.cjs", "esbuild.config.js"]
17 "src/**/*.ts",
18 ".eslintrc.cjs",
19 "esbuild.config.js"
20 ]
21} 13}
diff --git a/packages/service-preload/esbuild.config.js b/packages/service-preload/esbuild.config.js
index 66f5e84..d888987 100644
--- a/packages/service-preload/esbuild.config.js
+++ b/packages/service-preload/esbuild.config.js
@@ -4,15 +4,11 @@ import getEsbuildConfig from '../../config/getEsbuildConfig.js';
4 4
5export default getEsbuildConfig({ 5export default getEsbuildConfig({
6 absWorkingDir: fileURLToDirname(import.meta.url), 6 absWorkingDir: fileURLToDirname(import.meta.url),
7 entryPoints: [ 7 entryPoints: ['src/index.ts'],
8 'src/index.ts',
9 ],
10 outfile: 'dist/index.cjs', 8 outfile: 'dist/index.cjs',
11 format: 'cjs', 9 format: 'cjs',
12 platform: 'node', 10 platform: 'node',
13 target: chrome, 11 target: chrome,
14 sourcemap: 'inline', 12 sourcemap: 'inline',
15 external: [ 13 external: ['electron'],
16 'electron',
17 ],
18}); 14});
diff --git a/packages/service-preload/tsconfig.json b/packages/service-preload/tsconfig.json
index 768c464..189859e 100644
--- a/packages/service-preload/tsconfig.json
+++ b/packages/service-preload/tsconfig.json
@@ -2,11 +2,7 @@
2 "extends": "../../config/tsconfig.base.json", 2 "extends": "../../config/tsconfig.base.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "noEmit": true, 4 "noEmit": true,
5 "lib": [ 5 "lib": ["dom", "dom.iterable", "esnext"]
6 "dom",
7 "dom.iterable",
8 "esnext"
9 ]
10 }, 6 },
11 "references": [ 7 "references": [
12 { 8 {
diff --git a/packages/service-preload/types/importMeta.d.ts b/packages/service-preload/types/importMeta.d.ts
index 9b73170..ff3b17c 100644
--- a/packages/service-preload/types/importMeta.d.ts
+++ b/packages/service-preload/types/importMeta.d.ts
@@ -3,5 +3,5 @@ interface ImportMeta {
3 DEV: boolean; 3 DEV: boolean;
4 MODE: string; 4 MODE: string;
5 PROD: boolean; 5 PROD: boolean;
6 } 6 };
7} 7}
diff --git a/packages/service-shared/.eslintrc.cjs b/packages/service-shared/.eslintrc.cjs
index c19829d..25fd252 100644
--- a/packages/service-shared/.eslintrc.cjs
+++ b/packages/service-shared/.eslintrc.cjs
@@ -6,10 +6,7 @@ module.exports = {
6 }, 6 },
7 overrides: [ 7 overrides: [
8 { 8 {
9 files: [ 9 files: ['.eslintrc.cjs', 'esbuild.config.js'],
10 '.eslintrc.cjs',
11 'esbuild.config.js',
12 ],
13 env: { 10 env: {
14 node: true, 11 node: true,
15 }, 12 },
diff --git a/packages/service-shared/esbuild.config.js b/packages/service-shared/esbuild.config.js
index ccee72c..2b0dec8 100644
--- a/packages/service-shared/esbuild.config.js
+++ b/packages/service-shared/esbuild.config.js
@@ -4,9 +4,7 @@ import getEsbuildConfig from '../../config/getEsbuildConfig.js';
4 4
5export default getEsbuildConfig({ 5export default getEsbuildConfig({
6 absWorkingDir: fileURLToDirname(import.meta.url), 6 absWorkingDir: fileURLToDirname(import.meta.url),
7 entryPoints: [ 7 entryPoints: ['src/index.ts'],
8 'src/index.ts',
9 ],
10 outfile: 'dist/index.mjs', 8 outfile: 'dist/index.mjs',
11 format: 'esm', 9 format: 'esm',
12 // The package that includes this one will have a header comment, 10 // The package that includes this one will have a header comment,
@@ -14,7 +12,5 @@ export default getEsbuildConfig({
14 banner: {}, 12 banner: {},
15 platform: 'node', 13 platform: 'node',
16 target: [chrome, node], 14 target: [chrome, node],
17 external: [ 15 external: ['zod'],
18 'zod',
19 ],
20}); 16});
diff --git a/packages/service-shared/src/index.ts b/packages/service-shared/src/index.ts
index e111347..94be734 100644
--- a/packages/service-shared/src/index.ts
+++ b/packages/service-shared/src/index.ts
@@ -20,11 +20,5 @@
20 20
21export { MainToServiceIpcMessage, ServiceToMainIpcMessage } from './ipc'; 21export { MainToServiceIpcMessage, ServiceToMainIpcMessage } from './ipc';
22 22
23export type { 23export type { UnreadCount, WebSource } from './schemas';
24 UnreadCount, 24export { unreadCount, webSource } from './schemas';
25 WebSource,
26} from './schemas';
27export {
28 unreadCount,
29 webSource,
30} from './schemas';
diff --git a/packages/service-shared/src/ipc.ts b/packages/service-shared/src/ipc.ts
index c0dab11..e0a8755 100644
--- a/packages/service-shared/src/ipc.ts
+++ b/packages/service-shared/src/ipc.ts
@@ -18,8 +18,7 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21export enum MainToServiceIpcMessage { 21export enum MainToServiceIpcMessage {}
22}
23 22
24export enum ServiceToMainIpcMessage { 23export enum ServiceToMainIpcMessage {
25 ApiExposedInMainWorld = 'sophie-service-to-main:api-exposed-in-main-world', 24 ApiExposedInMainWorld = 'sophie-service-to-main:api-exposed-in-main-world',
diff --git a/packages/service-shared/tsconfig.build.json b/packages/service-shared/tsconfig.build.json
index 9a0c835..d300514 100644
--- a/packages/service-shared/tsconfig.build.json
+++ b/packages/service-shared/tsconfig.build.json
@@ -6,7 +6,5 @@
6 "emitDeclarationOnly": true, 6 "emitDeclarationOnly": true,
7 "rootDir": "src" 7 "rootDir": "src"
8 }, 8 },
9 "include": [ 9 "include": ["src/**/*.ts"]
10 "src/**/*.ts"
11 ]
12} 10}
diff --git a/packages/service-shared/tsconfig.json b/packages/service-shared/tsconfig.json
index 3e6c6ff..daad7c4 100644
--- a/packages/service-shared/tsconfig.json
+++ b/packages/service-shared/tsconfig.json
@@ -7,9 +7,5 @@
7 "noEmit": true, 7 "noEmit": true,
8 "rootDir": null 8 "rootDir": null
9 }, 9 },
10 "include": [ 10 "include": ["src/**/*.ts", ".eslintrc.cjs", "esbuild.config.js"]
11 "src/**/*.ts",
12 ".eslintrc.cjs",
13 "esbuild.config.js"
14 ]
15} 11}
diff --git a/packages/shared/.eslintrc.cjs b/packages/shared/.eslintrc.cjs
index c19829d..25fd252 100644
--- a/packages/shared/.eslintrc.cjs
+++ b/packages/shared/.eslintrc.cjs
@@ -6,10 +6,7 @@ module.exports = {
6 }, 6 },
7 overrides: [ 7 overrides: [
8 { 8 {
9 files: [ 9 files: ['.eslintrc.cjs', 'esbuild.config.js'],
10 '.eslintrc.cjs',
11 'esbuild.config.js',
12 ],
13 env: { 10 env: {
14 node: true, 11 node: true,
15 }, 12 },
diff --git a/packages/shared/esbuild.config.js b/packages/shared/esbuild.config.js
index 78249ab..44501bd 100644
--- a/packages/shared/esbuild.config.js
+++ b/packages/shared/esbuild.config.js
@@ -4,9 +4,7 @@ import getEsbuildConfig from '../../config/getEsbuildConfig.js';
4 4
5export default getEsbuildConfig({ 5export default getEsbuildConfig({
6 absWorkingDir: fileURLToDirname(import.meta.url), 6 absWorkingDir: fileURLToDirname(import.meta.url),
7 entryPoints: [ 7 entryPoints: ['src/index.ts'],
8 'src/index.ts',
9 ],
10 outfile: 'dist/index.mjs', 8 outfile: 'dist/index.mjs',
11 format: 'esm', 9 format: 'esm',
12 // The package that includes this one will have a header comment, 10 // The package that includes this one will have a header comment,
@@ -14,9 +12,5 @@ export default getEsbuildConfig({
14 banner: {}, 12 banner: {},
15 platform: 'node', 13 platform: 'node',
16 target: [chrome, node], 14 target: [chrome, node],
17 external: [ 15 external: ['mobx', 'mobx-state-tree', 'zod'],
18 'mobx',
19 'mobx-state-tree',
20 'zod',
21 ],
22}); 16});
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index 9828ec4..6383f63 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -22,18 +22,14 @@ export type { SophieRenderer } from './contextBridge/SophieRenderer';
22 22
23export { MainToRendererIpcMessage, RendererToMainIpcMessage } from './ipc'; 23export { MainToRendererIpcMessage, RendererToMainIpcMessage } from './ipc';
24 24
25export type { 25export type { Action, BrowserViewBounds, ThemeSource } from './schemas';
26 Action, 26export { action, browserViewBounds, themeSource } from './schemas';
27 BrowserViewBounds,
28 ThemeSource,
29} from './schemas';
30export {
31 action,
32 browserViewBounds,
33 themeSource,
34} from './schemas';
35 27
36export type { Config, ConfigSnapshotIn, ConfigSnapshotOut } from './stores/Config'; 28export type {
29 Config,
30 ConfigSnapshotIn,
31 ConfigSnapshotOut,
32} from './stores/Config';
37export { config } from './stores/Config'; 33export { config } from './stores/Config';
38 34
39export type { 35export type {
diff --git a/packages/shared/src/stores/Config.ts b/packages/shared/src/stores/Config.ts
index 432945c..1d98a33 100644
--- a/packages/shared/src/stores/Config.ts
+++ b/packages/shared/src/stores/Config.ts
@@ -18,12 +18,7 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { 21import { Instance, types, SnapshotIn, SnapshotOut } from 'mobx-state-tree';
22 Instance,
23 types,
24 SnapshotIn,
25 SnapshotOut,
26} from 'mobx-state-tree';
27 22
28import { themeSource } from '../schemas'; 23import { themeSource } from '../schemas';
29 24
diff --git a/packages/shared/src/stores/SharedStore.ts b/packages/shared/src/stores/SharedStore.ts
index c6c3ddc..cb14394 100644
--- a/packages/shared/src/stores/SharedStore.ts
+++ b/packages/shared/src/stores/SharedStore.ts
@@ -37,7 +37,8 @@ export interface SharedStore extends Instance<typeof sharedStore> {}
37 37
38export interface SharedStoreSnapshotIn extends SnapshotIn<typeof sharedStore> {} 38export interface SharedStoreSnapshotIn extends SnapshotIn<typeof sharedStore> {}
39 39
40export interface SharedStoreSnapshotOut extends SnapshotOut<typeof sharedStore> {} 40export interface SharedStoreSnapshotOut
41 extends SnapshotOut<typeof sharedStore> {}
41 42
42export interface SharedStoreListener { 43export interface SharedStoreListener {
43 onSnapshot(snapshot: SharedStoreSnapshotIn): void; 44 onSnapshot(snapshot: SharedStoreSnapshotIn): void;
diff --git a/packages/shared/tsconfig.build.json b/packages/shared/tsconfig.build.json
index 9a0c835..d300514 100644
--- a/packages/shared/tsconfig.build.json
+++ b/packages/shared/tsconfig.build.json
@@ -6,7 +6,5 @@
6 "emitDeclarationOnly": true, 6 "emitDeclarationOnly": true,
7 "rootDir": "src" 7 "rootDir": "src"
8 }, 8 },
9 "include": [ 9 "include": ["src/**/*.ts"]
10 "src/**/*.ts"
11 ]
12} 10}
diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json
index 3e6c6ff..daad7c4 100644
--- a/packages/shared/tsconfig.json
+++ b/packages/shared/tsconfig.json
@@ -7,9 +7,5 @@
7 "noEmit": true, 7 "noEmit": true,
8 "rootDir": null 8 "rootDir": null
9 }, 9 },
10 "include": [ 10 "include": ["src/**/*.ts", ".eslintrc.cjs", "esbuild.config.js"]
11 "src/**/*.ts",
12 ".eslintrc.cjs",
13 "esbuild.config.js"
14 ]
15} 11}