diff options
-rw-r--r-- | packages/main/esbuild.config.js | 6 | ||||
-rw-r--r-- | packages/main/package.json | 6 | ||||
-rw-r--r-- | packages/main/src/index.ts | 15 | ||||
-rw-r--r-- | packages/main/src/infrastructure/config/ConfigRepository.ts | 5 | ||||
-rw-r--r-- | packages/main/src/infrastructure/config/impl/ConfigFile.ts | 12 | ||||
-rw-r--r-- | packages/main/src/infrastructure/electron/impl/devTools.ts | 43 | ||||
-rw-r--r-- | packages/main/src/infrastructure/electron/impl/hardenSession.ts | 14 | ||||
-rw-r--r-- | packages/main/src/reactions/__tests__/synchronizeConfig.spec.ts | 56 | ||||
-rw-r--r-- | packages/main/src/reactions/synchronizeConfig.ts | 40 | ||||
-rw-r--r-- | yarn.lock | 216 |
10 files changed, 123 insertions, 290 deletions
diff --git a/packages/main/esbuild.config.js b/packages/main/esbuild.config.js index ae8565d..dddda75 100644 --- a/packages/main/esbuild.config.js +++ b/packages/main/esbuild.config.js | |||
@@ -13,7 +13,11 @@ const thisDir = fileUrlToDirname(import.meta.url); | |||
13 | const externalPackages = ['electron']; | 13 | const externalPackages = ['electron']; |
14 | 14 | ||
15 | if (process.env.MODE !== 'development') { | 15 | if (process.env.MODE !== 'development') { |
16 | externalPackages.push('electron-devtools-installer', 'source-map-support'); | 16 | externalPackages.push( |
17 | 'electron-devtools-installer', | ||
18 | 'mkdirp', | ||
19 | 'source-map-support', | ||
20 | ); | ||
17 | } | 21 | } |
18 | 22 | ||
19 | const gitInfo = getRepoInfo(); | 23 | const gitInfo = getRepoInfo(); |
diff --git a/packages/main/package.json b/packages/main/package.json index fceb392..fc972ba 100644 --- a/packages/main/package.json +++ b/packages/main/package.json | |||
@@ -11,9 +11,7 @@ | |||
11 | "@sophie/service-shared": "workspace:*", | 11 | "@sophie/service-shared": "workspace:*", |
12 | "@sophie/shared": "workspace:*", | 12 | "@sophie/shared": "workspace:*", |
13 | "chalk": "^5.0.1", | 13 | "chalk": "^5.0.1", |
14 | "deep-equal": "^2.0.5", | ||
15 | "electron": "^19.0.0-alpha.1", | 14 | "electron": "^19.0.0-alpha.1", |
16 | "fs-extra": "^10.1.0", | ||
17 | "i18next": "^21.6.16", | 15 | "i18next": "^21.6.16", |
18 | "lodash-es": "^4.17.21", | 16 | "lodash-es": "^4.17.21", |
19 | "loglevel": "^1.8.0", | 17 | "loglevel": "^1.8.0", |
@@ -21,15 +19,14 @@ | |||
21 | "mobx": "^6.5.0", | 19 | "mobx": "^6.5.0", |
22 | "mobx-state-tree": "^5.1.3", | 20 | "mobx-state-tree": "^5.1.3", |
23 | "nanoid": "^3.3.3", | 21 | "nanoid": "^3.3.3", |
24 | "os-name": "^5.0.1", | ||
25 | "slug": "^5.3.0" | 22 | "slug": "^5.3.0" |
26 | }, | 23 | }, |
27 | "devDependencies": { | 24 | "devDependencies": { |
28 | "@jest/globals": "^27.5.1", | 25 | "@jest/globals": "^27.5.1", |
29 | "@sophie/test-utils": "workspace:*", | 26 | "@sophie/test-utils": "workspace:*", |
30 | "@types/deep-equal": "^1.0.1", | ||
31 | "@types/electron-devtools-installer": "^2.2.2", | 27 | "@types/electron-devtools-installer": "^2.2.2", |
32 | "@types/lodash-es": "^4.17.6", | 28 | "@types/lodash-es": "^4.17.6", |
29 | "@types/mkdirp": "^1", | ||
33 | "@types/node": "^17.0.25", | 30 | "@types/node": "^17.0.25", |
34 | "@types/slug": "^5.0.3", | 31 | "@types/slug": "^5.0.3", |
35 | "@types/source-map-support": "^0.5.4", | 32 | "@types/source-map-support": "^0.5.4", |
@@ -38,6 +35,7 @@ | |||
38 | "git-repo-info": "^2.1.1", | 35 | "git-repo-info": "^2.1.1", |
39 | "jest": "^27.5.1", | 36 | "jest": "^27.5.1", |
40 | "jest-mock": "^27.5.1", | 37 | "jest-mock": "^27.5.1", |
38 | "mkdirp": "^1.0.4", | ||
41 | "source-map-support": "^0.5.21" | 39 | "source-map-support": "^0.5.21" |
42 | } | 40 | } |
43 | } | 41 | } |
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 29a8cca..78861c2 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -22,10 +22,11 @@ | |||
22 | import os from 'node:os'; | 22 | import os from 'node:os'; |
23 | 23 | ||
24 | import { app } from 'electron'; | 24 | import { app } from 'electron'; |
25 | import { ensureDirSync } from 'fs-extra'; | ||
26 | import osName from 'os-name'; | ||
27 | 25 | ||
28 | import { enableStacktraceSourceMaps } from './infrastructure/electron/impl/devTools'; | 26 | import { |
27 | enableStacktraceSourceMaps, | ||
28 | ensureDevDataDir, | ||
29 | } from './infrastructure/electron/impl/devTools'; | ||
29 | import electronShell from './infrastructure/electron/impl/electronShell'; | 30 | import electronShell from './infrastructure/electron/impl/electronShell'; |
30 | import initReactions from './initReactions'; | 31 | import initReactions from './initReactions'; |
31 | import MainStore from './stores/MainStore'; | 32 | import MainStore from './stores/MainStore'; |
@@ -39,11 +40,7 @@ const log = getLogger('index'); | |||
39 | app.enableSandbox(); | 40 | app.enableSandbox(); |
40 | 41 | ||
41 | if (isDevelopment) { | 42 | if (isDevelopment) { |
42 | // Use alternative directory when debugging to avoid clobbering the main installation. | 43 | ensureDevDataDir(); |
43 | app.setPath('userData', `${app.getPath('userData')}-dev`); | ||
44 | ensureDirSync(app.getPath('userData')); | ||
45 | |||
46 | // Use source maps in stack traces. | ||
47 | enableStacktraceSourceMaps(); | 44 | enableStacktraceSourceMaps(); |
48 | } | 45 | } |
49 | 46 | ||
@@ -67,7 +64,7 @@ app.setAboutPanelOptions({ | |||
67 | `Electron: ${process.versions.electron}`, | 64 | `Electron: ${process.versions.electron}`, |
68 | `Chrome: ${process.versions.chrome}`, | 65 | `Chrome: ${process.versions.chrome}`, |
69 | `Node.js: ${process.versions.node}`, | 66 | `Node.js: ${process.versions.node}`, |
70 | `Platform: ${osName()}`, | 67 | `Platform: ${os.platform()} ${os.release()}`, |
71 | `Arch: ${os.arch()}`, | 68 | `Arch: ${os.arch()}`, |
72 | `Build date: ${new Date( | 69 | `Build date: ${new Date( |
73 | Number(import.meta.env.BUILD_DATE), | 70 | Number(import.meta.env.BUILD_DATE), |
diff --git a/packages/main/src/infrastructure/config/ConfigRepository.ts b/packages/main/src/infrastructure/config/ConfigRepository.ts index e00f5a0..67bffb0 100644 --- a/packages/main/src/infrastructure/config/ConfigRepository.ts +++ b/packages/main/src/infrastructure/config/ConfigRepository.ts | |||
@@ -18,17 +18,16 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import type Config from '../../stores/config/Config'; | ||
22 | import type Disposer from '../../utils/Disposer'; | 21 | import type Disposer from '../../utils/Disposer'; |
23 | 22 | ||
24 | export type ReadConfigResult = | 23 | export type ReadConfigResult = |
25 | | { found: true; data: unknown } | 24 | | { found: true; contents: string } |
26 | | { found: false }; | 25 | | { found: false }; |
27 | 26 | ||
28 | export default interface ConfigPersistence { | 27 | export default interface ConfigPersistence { |
29 | readConfig(): Promise<ReadConfigResult>; | 28 | readConfig(): Promise<ReadConfigResult>; |
30 | 29 | ||
31 | writeConfig(config: Config): Promise<void>; | 30 | writeConfig(contents: string): Promise<void>; |
32 | 31 | ||
33 | watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer; | 32 | watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer; |
34 | } | 33 | } |
diff --git a/packages/main/src/infrastructure/config/impl/ConfigFile.ts b/packages/main/src/infrastructure/config/impl/ConfigFile.ts index c4e6d22..8b110a2 100644 --- a/packages/main/src/infrastructure/config/impl/ConfigFile.ts +++ b/packages/main/src/infrastructure/config/impl/ConfigFile.ts | |||
@@ -24,7 +24,6 @@ import path from 'node:path'; | |||
24 | 24 | ||
25 | import { throttle } from 'lodash-es'; | 25 | import { throttle } from 'lodash-es'; |
26 | 26 | ||
27 | import type Config from '../../../stores/config/Config'; | ||
28 | import type Disposer from '../../../utils/Disposer'; | 27 | import type Disposer from '../../../utils/Disposer'; |
29 | import isErrno from '../../../utils/isErrno'; | 28 | import isErrno from '../../../utils/isErrno'; |
30 | import { getLogger } from '../../../utils/log'; | 29 | import { getLogger } from '../../../utils/log'; |
@@ -48,9 +47,9 @@ export default class ConfigFile implements ConfigRepository { | |||
48 | } | 47 | } |
49 | 48 | ||
50 | async readConfig(): Promise<ReadConfigResult> { | 49 | async readConfig(): Promise<ReadConfigResult> { |
51 | let configStr: string; | 50 | let contents: string; |
52 | try { | 51 | try { |
53 | configStr = await readFile(this.configFilePath, 'utf8'); | 52 | contents = await readFile(this.configFilePath, 'utf8'); |
54 | } catch (error) { | 53 | } catch (error) { |
55 | if (isErrno(error, 'ENOENT')) { | 54 | if (isErrno(error, 'ENOENT')) { |
56 | log.debug('Config file', this.configFilePath, 'was not found'); | 55 | log.debug('Config file', this.configFilePath, 'was not found'); |
@@ -61,15 +60,14 @@ export default class ConfigFile implements ConfigRepository { | |||
61 | log.info('Read config file', this.configFilePath); | 60 | log.info('Read config file', this.configFilePath); |
62 | return { | 61 | return { |
63 | found: true, | 62 | found: true, |
64 | data: JSON.parse(configStr), | 63 | contents, |
65 | }; | 64 | }; |
66 | } | 65 | } |
67 | 66 | ||
68 | async writeConfig(configSnapshot: Config): Promise<void> { | 67 | async writeConfig(contents: string): Promise<void> { |
69 | const configJson = JSON.stringify(configSnapshot, undefined, 2); | ||
70 | this.writingConfig = true; | 68 | this.writingConfig = true; |
71 | try { | 69 | try { |
72 | await writeFile(this.configFilePath, configJson, 'utf8'); | 70 | await writeFile(this.configFilePath, contents, 'utf8'); |
73 | const { mtime } = await stat(this.configFilePath); | 71 | const { mtime } = await stat(this.configFilePath); |
74 | log.trace('Config file', this.configFilePath, 'last written at', mtime); | 72 | log.trace('Config file', this.configFilePath, 'last written at', mtime); |
75 | this.timeLastWritten = mtime; | 73 | this.timeLastWritten = mtime; |
diff --git a/packages/main/src/infrastructure/electron/impl/devTools.ts b/packages/main/src/infrastructure/electron/impl/devTools.ts index 10f4545..6db88d1 100644 --- a/packages/main/src/infrastructure/electron/impl/devTools.ts +++ b/packages/main/src/infrastructure/electron/impl/devTools.ts | |||
@@ -18,34 +18,32 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import type { BrowserWindow } from 'electron'; | 21 | import { app, type BrowserWindow } from 'electron'; |
22 | |||
23 | /* eslint-disable | ||
24 | import/no-extraneous-dependencies, | ||
25 | global-require, | ||
26 | @typescript-eslint/no-var-requires, | ||
27 | unicorn/prefer-module -- | ||
28 | Hack to lazily require a CJS module from an ES module transpiled into a CJS module. | ||
29 | */ | ||
22 | 30 | ||
23 | /** | 31 | /** |
24 | * URL prefixes Sophie is allowed load in dev mode. | 32 | * Makes sure we use a separate data dir for development. |
25 | * | ||
26 | * In dev mode, in addition to the application itself, | ||
27 | * Sophie must be able do download and load the devtools and related extensions, | ||
28 | * so we have to make exceptions in the UI process request filter. | ||
29 | */ | 33 | */ |
30 | export const DEVMODE_ALLOWED_URL_PREFIXES = [ | 34 | export function ensureDevDataDir(): void { |
31 | 'chrome-extension:', | 35 | // Use alternative directory when debugging to avoid clobbering the main installation. |
32 | 'devtools:', | 36 | app.setPath('userData', `${app.getPath('userData')}-dev`); |
33 | 'https://clients2.google.com/service/update2/crx', | 37 | const userData = app.getPath('userData'); |
34 | 'https://clients2.googleusercontent.com/crx', | 38 | const mkdirp = require('mkdirp') as typeof import('mkdirp'); |
35 | ]; | 39 | mkdirp.sync(userData); |
40 | } | ||
36 | 41 | ||
37 | /** | 42 | /** |
38 | * Enables using source maps for node stack traces. | 43 | * Enables using source maps for node stack traces. |
39 | */ | 44 | */ |
40 | export function enableStacktraceSourceMaps(): void { | 45 | export function enableStacktraceSourceMaps(): void { |
41 | const sourceMapSupport = | 46 | const sourceMapSupport = |
42 | /* eslint-disable-next-line | ||
43 | import/no-extraneous-dependencies, | ||
44 | global-require, | ||
45 | @typescript-eslint/no-var-requires, | ||
46 | unicorn/prefer-module -- | ||
47 | Hack to lazily require a CJS module from an ES module transpiled into a CJS module. | ||
48 | */ | ||
49 | require('source-map-support') as typeof import('source-map-support'); | 47 | require('source-map-support') as typeof import('source-map-support'); |
50 | sourceMapSupport.install(); | 48 | sourceMapSupport.install(); |
51 | } | 49 | } |
@@ -61,13 +59,6 @@ export async function installDevToolsExtensions(): Promise<void> { | |||
61 | default: installExtension, | 59 | default: installExtension, |
62 | REACT_DEVELOPER_TOOLS, | 60 | REACT_DEVELOPER_TOOLS, |
63 | REDUX_DEVTOOLS, | 61 | REDUX_DEVTOOLS, |
64 | /* eslint-disable-next-line | ||
65 | import/no-extraneous-dependencies, | ||
66 | global-require, | ||
67 | @typescript-eslint/no-var-requires, | ||
68 | unicorn/prefer-module -- | ||
69 | Hack to lazily require a CJS module from an ES module transpiled into a CJS module. | ||
70 | */ | ||
71 | } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); | 62 | } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); |
72 | await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], { | 63 | await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], { |
73 | forceDownload: false, | 64 | forceDownload: false, |
diff --git a/packages/main/src/infrastructure/electron/impl/hardenSession.ts b/packages/main/src/infrastructure/electron/impl/hardenSession.ts index 10b694a..53675a7 100644 --- a/packages/main/src/infrastructure/electron/impl/hardenSession.ts +++ b/packages/main/src/infrastructure/electron/impl/hardenSession.ts | |||
@@ -25,7 +25,19 @@ import type { Session } from 'electron'; | |||
25 | import { getLogger } from '../../../utils/log'; | 25 | import { getLogger } from '../../../utils/log'; |
26 | import type Resources from '../../resources/Resources'; | 26 | import type Resources from '../../resources/Resources'; |
27 | 27 | ||
28 | import { DEVMODE_ALLOWED_URL_PREFIXES } from './devTools'; | 28 | /** |
29 | * URL prefixes Sophie is allowed load in dev mode. | ||
30 | * | ||
31 | * In dev mode, in addition to the application itself, | ||
32 | * Sophie must be able do download and load the devtools and related extensions, | ||
33 | * so we have to make exceptions in the UI process request filter. | ||
34 | */ | ||
35 | export const DEVMODE_ALLOWED_URL_PREFIXES = [ | ||
36 | 'chrome-extension:', | ||
37 | 'devtools:', | ||
38 | 'https://clients2.google.com/service/update2/crx', | ||
39 | 'https://clients2.googleusercontent.com/crx', | ||
40 | ]; | ||
29 | 41 | ||
30 | const log = getLogger('hardenSession'); | 42 | const log = getLogger('hardenSession'); |
31 | 43 | ||
diff --git a/packages/main/src/reactions/__tests__/synchronizeConfig.spec.ts b/packages/main/src/reactions/__tests__/synchronizeConfig.spec.ts index b5013ea..d3338d0 100644 --- a/packages/main/src/reactions/__tests__/synchronizeConfig.spec.ts +++ b/packages/main/src/reactions/__tests__/synchronizeConfig.spec.ts | |||
@@ -25,7 +25,7 @@ import type ConfigRepository from '../../infrastructure/config/ConfigRepository' | |||
25 | import SharedStore from '../../stores/SharedStore'; | 25 | import SharedStore from '../../stores/SharedStore'; |
26 | import type Disposer from '../../utils/Disposer'; | 26 | import type Disposer from '../../utils/Disposer'; |
27 | import { silenceLogger } from '../../utils/log'; | 27 | import { silenceLogger } from '../../utils/log'; |
28 | import synchronizeConfig from '../synchronizeConfig'; | 28 | import synchronizeConfig, { serializeConfig } from '../synchronizeConfig'; |
29 | 29 | ||
30 | let store: SharedStore; | 30 | let store: SharedStore; |
31 | const repository: ConfigRepository = { | 31 | const repository: ConfigRepository = { |
@@ -70,11 +70,11 @@ describe('when synchronizeializing', () => { | |||
70 | beforeEach(() => { | 70 | beforeEach(() => { |
71 | mocked(repository.readConfig).mockResolvedValueOnce({ | 71 | mocked(repository.readConfig).mockResolvedValueOnce({ |
72 | found: true, | 72 | found: true, |
73 | data: { | 73 | contents: serializeConfig({ |
74 | // Use a default empty config file to not trigger config rewrite. | 74 | // Use a default empty config file to not trigger config rewrite. |
75 | ...store.config, | 75 | ...store.config, |
76 | themeSource: 'dark', | 76 | themeSource: 'dark', |
77 | }, | 77 | }), |
78 | }); | 78 | }); |
79 | }); | 79 | }); |
80 | 80 | ||
@@ -97,12 +97,15 @@ describe('when synchronizeializing', () => { | |||
97 | it('should update the config file if new details are added during read', async () => { | 97 | it('should update the config file if new details are added during read', async () => { |
98 | mocked(repository.readConfig).mockResolvedValueOnce({ | 98 | mocked(repository.readConfig).mockResolvedValueOnce({ |
99 | found: true, | 99 | found: true, |
100 | data: { | 100 | contents: `{ |
101 | themeSource: 'light', | 101 | "themeSource": "light", |
102 | profile: { | 102 | "profiles": [ |
103 | name: 'Test profile', | 103 | { |
104 | }, | 104 | "name": "Test profile" |
105 | }, | 105 | } |
106 | ] | ||
107 | } | ||
108 | `, | ||
106 | }); | 109 | }); |
107 | await synchronizeConfig(store, repository); | 110 | await synchronizeConfig(store, repository); |
108 | expect(repository.writeConfig).toHaveBeenCalledTimes(1); | 111 | expect(repository.writeConfig).toHaveBeenCalledTimes(1); |
@@ -111,9 +114,10 @@ describe('when synchronizeializing', () => { | |||
111 | it('should not apply an invalid config file but should not overwrite it', async () => { | 114 | it('should not apply an invalid config file but should not overwrite it', async () => { |
112 | mocked(repository.readConfig).mockResolvedValueOnce({ | 115 | mocked(repository.readConfig).mockResolvedValueOnce({ |
113 | found: true, | 116 | found: true, |
114 | data: { | 117 | contents: `{ |
115 | themeSource: -1, | 118 | "themeSource": -1 |
116 | }, | 119 | } |
120 | `, | ||
117 | }); | 121 | }); |
118 | await synchronizeConfig(store, repository); | 122 | await synchronizeConfig(store, repository); |
119 | expect(store.settings.themeSource).not.toBe(-1); | 123 | expect(store.settings.themeSource).not.toBe(-1); |
@@ -136,7 +140,7 @@ describe('when it has loaded the config', () => { | |||
136 | beforeEach(async () => { | 140 | beforeEach(async () => { |
137 | mocked(repository.readConfig).mockResolvedValueOnce({ | 141 | mocked(repository.readConfig).mockResolvedValueOnce({ |
138 | found: true, | 142 | found: true, |
139 | data: store.config, | 143 | contents: serializeConfig(store.config), |
140 | }); | 144 | }); |
141 | mocked(repository.watchConfig).mockReturnValueOnce(watcherDisposer); | 145 | mocked(repository.watchConfig).mockReturnValueOnce(watcherDisposer); |
142 | sutDisposer = await synchronizeConfig(store, repository, throttleMs); | 146 | sutDisposer = await synchronizeConfig(store, repository, throttleMs); |
@@ -163,11 +167,11 @@ describe('when it has loaded the config', () => { | |||
163 | it('should read the config file when it has changed', async () => { | 167 | it('should read the config file when it has changed', async () => { |
164 | mocked(repository.readConfig).mockResolvedValueOnce({ | 168 | mocked(repository.readConfig).mockResolvedValueOnce({ |
165 | found: true, | 169 | found: true, |
166 | data: { | 170 | contents: serializeConfig({ |
167 | // Use a default empty config file to not trigger config rewrite. | 171 | // Use a default empty config file to not trigger config rewrite. |
168 | ...store.config, | 172 | ...store.config, |
169 | themeSource: 'dark', | 173 | themeSource: 'dark', |
170 | }, | 174 | }), |
171 | }); | 175 | }); |
172 | await configChangedCallback(); | 176 | await configChangedCallback(); |
173 | // Do not write back the changes we have just read. | 177 | // Do not write back the changes we have just read. |
@@ -178,12 +182,15 @@ describe('when it has loaded the config', () => { | |||
178 | it('should update the config file if new details are added', async () => { | 182 | it('should update the config file if new details are added', async () => { |
179 | mocked(repository.readConfig).mockResolvedValueOnce({ | 183 | mocked(repository.readConfig).mockResolvedValueOnce({ |
180 | found: true, | 184 | found: true, |
181 | data: { | 185 | contents: `{ |
182 | themeSource: 'light', | 186 | "themeSource": "light", |
183 | profile: { | 187 | "profiles": [ |
184 | name: 'Test profile', | 188 | { |
185 | }, | 189 | "name": "Test profile" |
186 | }, | 190 | } |
191 | ] | ||
192 | } | ||
193 | `, | ||
187 | }); | 194 | }); |
188 | await configChangedCallback(); | 195 | await configChangedCallback(); |
189 | expect(repository.writeConfig).toHaveBeenCalledTimes(1); | 196 | expect(repository.writeConfig).toHaveBeenCalledTimes(1); |
@@ -192,9 +199,10 @@ describe('when it has loaded the config', () => { | |||
192 | it('should not apply an invalid config file when it has changed but should not overwrite it', async () => { | 199 | it('should not apply an invalid config file when it has changed but should not overwrite it', async () => { |
193 | mocked(repository.readConfig).mockResolvedValueOnce({ | 200 | mocked(repository.readConfig).mockResolvedValueOnce({ |
194 | found: true, | 201 | found: true, |
195 | data: { | 202 | contents: `{ |
196 | themeSource: -1, | 203 | "themeSource": -1 |
197 | }, | 204 | } |
205 | `, | ||
198 | }); | 206 | }); |
199 | await configChangedCallback(); | 207 | await configChangedCallback(); |
200 | expect(store.settings.themeSource).not.toBe(-1); | 208 | expect(store.settings.themeSource).not.toBe(-1); |
diff --git a/packages/main/src/reactions/synchronizeConfig.ts b/packages/main/src/reactions/synchronizeConfig.ts index 7e366e2..247c2e2 100644 --- a/packages/main/src/reactions/synchronizeConfig.ts +++ b/packages/main/src/reactions/synchronizeConfig.ts | |||
@@ -18,7 +18,6 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import deepEqual from 'deep-equal'; | ||
22 | import { debounce } from 'lodash-es'; | 21 | import { debounce } from 'lodash-es'; |
23 | import { reaction } from 'mobx'; | 22 | import { reaction } from 'mobx'; |
24 | 23 | ||
@@ -32,36 +31,38 @@ const DEFAULT_CONFIG_DEBOUNCE_TIME_MS = 1000; | |||
32 | 31 | ||
33 | const log = getLogger('synchronizeConfig'); | 32 | const log = getLogger('synchronizeConfig'); |
34 | 33 | ||
34 | export function serializeConfig(config: Config): string { | ||
35 | return `${JSON.stringify(config, undefined, 2)}\n`; | ||
36 | } | ||
37 | |||
35 | export default async function synchronizeConfig( | 38 | export default async function synchronizeConfig( |
36 | sharedStore: SharedStore, | 39 | sharedStore: SharedStore, |
37 | repository: ConfigRepository, | 40 | repository: ConfigRepository, |
38 | debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME_MS, | 41 | debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME_MS, |
39 | ): Promise<Disposer> { | 42 | ): Promise<Disposer> { |
40 | let lastConfigOnDisk: Config | undefined; | 43 | let lastConfigOnDisk: string | undefined; |
41 | 44 | ||
42 | async function writeConfig(): Promise<void> { | 45 | async function writeConfig(serializedConfig: string): Promise<void> { |
43 | const { config } = sharedStore; | 46 | await repository.writeConfig(serializedConfig); |
44 | await repository.writeConfig(config); | 47 | lastConfigOnDisk = serializedConfig; |
45 | lastConfigOnDisk = config; | ||
46 | } | 48 | } |
47 | 49 | ||
48 | async function readConfig(): Promise<boolean> { | 50 | async function readConfig(): Promise<boolean> { |
49 | const result = await repository.readConfig(); | 51 | const result = await repository.readConfig(); |
50 | if (result.found) { | 52 | if (result.found) { |
53 | const { contents } = result; | ||
51 | try { | 54 | try { |
52 | // This cast is unsound if the config file is invalid, | 55 | // This cast is unsound if the config file is invalid, |
53 | // but we'll throw an error in the end anyways. | 56 | // but we'll throw an error in the end anyways. |
54 | sharedStore.loadConfig(result.data as Config); | 57 | const data = JSON.parse(contents) as Config; |
58 | sharedStore.loadConfig(data); | ||
55 | } catch (error) { | 59 | } catch (error) { |
56 | log.error('Failed to apply config snapshot', result.data, error); | 60 | log.error('Failed to apply config snapshot', contents, error); |
57 | return true; | 61 | return true; |
58 | } | 62 | } |
59 | lastConfigOnDisk = sharedStore.config; | 63 | lastConfigOnDisk = serializeConfig(sharedStore.config); |
60 | // We can't use `comparer.structural` from `mobx`, because | 64 | if (contents !== lastConfigOnDisk) { |
61 | // it handles missing values and `undefined` values differently, | 65 | await writeConfig(lastConfigOnDisk); |
62 | // but JSON is unable to distinguish them. | ||
63 | if (!deepEqual(result.data, lastConfigOnDisk, { strict: true })) { | ||
64 | await writeConfig(); | ||
65 | } | 66 | } |
66 | } | 67 | } |
67 | return result.found; | 68 | return result.found; |
@@ -69,16 +70,17 @@ export default async function synchronizeConfig( | |||
69 | 70 | ||
70 | if (!(await readConfig())) { | 71 | if (!(await readConfig())) { |
71 | log.info('Config file was not found'); | 72 | log.info('Config file was not found'); |
72 | await writeConfig(); | 73 | const serializedConfig = serializeConfig(sharedStore.config); |
74 | await writeConfig(serializedConfig); | ||
73 | log.info('Created config file'); | 75 | log.info('Created config file'); |
74 | } | 76 | } |
75 | 77 | ||
76 | const disposeReaction = reaction( | 78 | const disposeReaction = reaction( |
77 | () => sharedStore.config, | 79 | () => sharedStore.config, |
78 | debounce((config) => { | 80 | debounce(() => { |
79 | // We can compare snapshots by reference, since it is only recreated on store changes. | 81 | const serializedConfig = serializeConfig(sharedStore.config); |
80 | if (!deepEqual(config, lastConfigOnDisk, { strict: true })) { | 82 | if (serializedConfig !== lastConfigOnDisk) { |
81 | writeConfig().catch((error) => { | 83 | writeConfig(serializedConfig).catch((error) => { |
82 | log.error('Failed to write config on config change', error); | 84 | log.error('Failed to write config on config change', error); |
83 | }); | 85 | }); |
84 | } | 86 | } |
@@ -1264,18 +1264,16 @@ __metadata: | |||
1264 | "@sophie/service-shared": "workspace:*" | 1264 | "@sophie/service-shared": "workspace:*" |
1265 | "@sophie/shared": "workspace:*" | 1265 | "@sophie/shared": "workspace:*" |
1266 | "@sophie/test-utils": "workspace:*" | 1266 | "@sophie/test-utils": "workspace:*" |
1267 | "@types/deep-equal": ^1.0.1 | ||
1268 | "@types/electron-devtools-installer": ^2.2.2 | 1267 | "@types/electron-devtools-installer": ^2.2.2 |
1269 | "@types/lodash-es": ^4.17.6 | 1268 | "@types/lodash-es": ^4.17.6 |
1269 | "@types/mkdirp": ^1 | ||
1270 | "@types/node": ^17.0.25 | 1270 | "@types/node": ^17.0.25 |
1271 | "@types/slug": ^5.0.3 | 1271 | "@types/slug": ^5.0.3 |
1272 | "@types/source-map-support": ^0.5.4 | 1272 | "@types/source-map-support": ^0.5.4 |
1273 | chalk: ^5.0.1 | 1273 | chalk: ^5.0.1 |
1274 | deep-equal: ^2.0.5 | ||
1275 | electron: ^19.0.0-alpha.1 | 1274 | electron: ^19.0.0-alpha.1 |
1276 | electron-devtools-installer: ^3.2.0 | 1275 | electron-devtools-installer: ^3.2.0 |
1277 | esbuild: ^0.14.38 | 1276 | esbuild: ^0.14.38 |
1278 | fs-extra: ^10.1.0 | ||
1279 | git-repo-info: ^2.1.1 | 1277 | git-repo-info: ^2.1.1 |
1280 | i18next: ^21.6.16 | 1278 | i18next: ^21.6.16 |
1281 | jest: ^27.5.1 | 1279 | jest: ^27.5.1 |
@@ -1283,10 +1281,10 @@ __metadata: | |||
1283 | lodash-es: ^4.17.21 | 1281 | lodash-es: ^4.17.21 |
1284 | loglevel: ^1.8.0 | 1282 | loglevel: ^1.8.0 |
1285 | loglevel-plugin-prefix: ^0.8.4 | 1283 | loglevel-plugin-prefix: ^0.8.4 |
1284 | mkdirp: ^1.0.4 | ||
1286 | mobx: ^6.5.0 | 1285 | mobx: ^6.5.0 |
1287 | mobx-state-tree: ^5.1.3 | 1286 | mobx-state-tree: ^5.1.3 |
1288 | nanoid: ^3.3.3 | 1287 | nanoid: ^3.3.3 |
1289 | os-name: ^5.0.1 | ||
1290 | slug: ^5.3.0 | 1288 | slug: ^5.3.0 |
1291 | source-map-support: ^0.5.21 | 1289 | source-map-support: ^0.5.21 |
1292 | languageName: unknown | 1290 | languageName: unknown |
@@ -1478,13 +1476,6 @@ __metadata: | |||
1478 | languageName: node | 1476 | languageName: node |
1479 | linkType: hard | 1477 | linkType: hard |
1480 | 1478 | ||
1481 | "@types/deep-equal@npm:^1.0.1": | ||
1482 | version: 1.0.1 | ||
1483 | resolution: "@types/deep-equal@npm:1.0.1" | ||
1484 | checksum: 689b5737dd0a37d173d9e1231c07f70a1a9a989087b757422e1d167ec3640fd7eb8a538bd6008b3df400c4c11ed07a6c2a92d9aafc1f98ffaa04731a9442c781 | ||
1485 | languageName: node | ||
1486 | linkType: hard | ||
1487 | |||
1488 | "@types/electron-devtools-installer@npm:^2.2.2": | 1479 | "@types/electron-devtools-installer@npm:^2.2.2": |
1489 | version: 2.2.2 | 1480 | version: 2.2.2 |
1490 | resolution: "@types/electron-devtools-installer@npm:2.2.2" | 1481 | resolution: "@types/electron-devtools-installer@npm:2.2.2" |
@@ -1610,6 +1601,15 @@ __metadata: | |||
1610 | languageName: node | 1601 | languageName: node |
1611 | linkType: hard | 1602 | linkType: hard |
1612 | 1603 | ||
1604 | "@types/mkdirp@npm:^1": | ||
1605 | version: 1.0.2 | ||
1606 | resolution: "@types/mkdirp@npm:1.0.2" | ||
1607 | dependencies: | ||
1608 | "@types/node": "*" | ||
1609 | checksum: 72dedfb2d250f0e44ec964ac68ff6a4a03d7d9d6e83ae1d5ba6d212791af69cf051a5fac59846826242d099de56a18c8e0581861792fae8b845b3c9ad67ecdeb | ||
1610 | languageName: node | ||
1611 | linkType: hard | ||
1612 | |||
1613 | "@types/ms@npm:*": | 1613 | "@types/ms@npm:*": |
1614 | version: 0.7.31 | 1614 | version: 0.7.31 |
1615 | resolution: "@types/ms@npm:0.7.31" | 1615 | resolution: "@types/ms@npm:0.7.31" |
@@ -2287,13 +2287,6 @@ __metadata: | |||
2287 | languageName: node | 2287 | languageName: node |
2288 | linkType: hard | 2288 | linkType: hard |
2289 | 2289 | ||
2290 | "available-typed-arrays@npm:^1.0.5": | ||
2291 | version: 1.0.5 | ||
2292 | resolution: "available-typed-arrays@npm:1.0.5" | ||
2293 | checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a | ||
2294 | languageName: node | ||
2295 | linkType: hard | ||
2296 | |||
2297 | "axe-core@npm:^4.3.5": | 2290 | "axe-core@npm:^4.3.5": |
2298 | version: 4.3.5 | 2291 | version: 4.3.5 |
2299 | resolution: "axe-core@npm:4.3.5" | 2292 | resolution: "axe-core@npm:4.3.5" |
@@ -3211,29 +3204,6 @@ __metadata: | |||
3211 | languageName: node | 3204 | languageName: node |
3212 | linkType: hard | 3205 | linkType: hard |
3213 | 3206 | ||
3214 | "deep-equal@npm:^2.0.5": | ||
3215 | version: 2.0.5 | ||
3216 | resolution: "deep-equal@npm:2.0.5" | ||
3217 | dependencies: | ||
3218 | call-bind: ^1.0.0 | ||
3219 | es-get-iterator: ^1.1.1 | ||
3220 | get-intrinsic: ^1.0.1 | ||
3221 | is-arguments: ^1.0.4 | ||
3222 | is-date-object: ^1.0.2 | ||
3223 | is-regex: ^1.1.1 | ||
3224 | isarray: ^2.0.5 | ||
3225 | object-is: ^1.1.4 | ||
3226 | object-keys: ^1.1.1 | ||
3227 | object.assign: ^4.1.2 | ||
3228 | regexp.prototype.flags: ^1.3.0 | ||
3229 | side-channel: ^1.0.3 | ||
3230 | which-boxed-primitive: ^1.0.1 | ||
3231 | which-collection: ^1.0.1 | ||
3232 | which-typed-array: ^1.1.2 | ||
3233 | checksum: 2bb7332badf589b540184d25098acac750e30fe11c8dce4523d03fc5db15f46881a0105e6bf0b64bb0c57213a95ed964029ff0259026ad6f7f9e0019f8200de5 | ||
3234 | languageName: node | ||
3235 | linkType: hard | ||
3236 | |||
3237 | "deep-extend@npm:^0.6.0": | 3207 | "deep-extend@npm:^0.6.0": |
3238 | version: 0.6.0 | 3208 | version: 0.6.0 |
3239 | resolution: "deep-extend@npm:0.6.0" | 3209 | resolution: "deep-extend@npm:0.6.0" |
@@ -3615,7 +3585,7 @@ __metadata: | |||
3615 | languageName: node | 3585 | languageName: node |
3616 | linkType: hard | 3586 | linkType: hard |
3617 | 3587 | ||
3618 | "es-abstract@npm:^1.18.5, es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1": | 3588 | "es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1": |
3619 | version: 1.19.1 | 3589 | version: 1.19.1 |
3620 | resolution: "es-abstract@npm:1.19.1" | 3590 | resolution: "es-abstract@npm:1.19.1" |
3621 | dependencies: | 3591 | dependencies: |
@@ -3643,22 +3613,6 @@ __metadata: | |||
3643 | languageName: node | 3613 | languageName: node |
3644 | linkType: hard | 3614 | linkType: hard |
3645 | 3615 | ||
3646 | "es-get-iterator@npm:^1.1.1": | ||
3647 | version: 1.1.2 | ||
3648 | resolution: "es-get-iterator@npm:1.1.2" | ||
3649 | dependencies: | ||
3650 | call-bind: ^1.0.2 | ||
3651 | get-intrinsic: ^1.1.0 | ||
3652 | has-symbols: ^1.0.1 | ||
3653 | is-arguments: ^1.1.0 | ||
3654 | is-map: ^2.0.2 | ||
3655 | is-set: ^2.0.2 | ||
3656 | is-string: ^1.0.5 | ||
3657 | isarray: ^2.0.5 | ||
3658 | checksum: f75e66acb6a45686fa08b3ade9c9421a70d36a0c43ed4363e67f4d7aab2226cb73dd977cb48abbaf75721b946d3cd810682fcf310c7ad0867802fbf929b17dcf | ||
3659 | languageName: node | ||
3660 | linkType: hard | ||
3661 | |||
3662 | "es-to-primitive@npm:^1.2.1": | 3616 | "es-to-primitive@npm:^1.2.1": |
3663 | version: 1.2.1 | 3617 | version: 1.2.1 |
3664 | resolution: "es-to-primitive@npm:1.2.1" | 3618 | resolution: "es-to-primitive@npm:1.2.1" |
@@ -4356,7 +4310,7 @@ __metadata: | |||
4356 | languageName: node | 4310 | languageName: node |
4357 | linkType: hard | 4311 | linkType: hard |
4358 | 4312 | ||
4359 | "execa@npm:^5.0.0, execa@npm:^5.1.1": | 4313 | "execa@npm:^5.0.0": |
4360 | version: 5.1.1 | 4314 | version: 5.1.1 |
4361 | resolution: "execa@npm:5.1.1" | 4315 | resolution: "execa@npm:5.1.1" |
4362 | dependencies: | 4316 | dependencies: |
@@ -4551,13 +4505,6 @@ __metadata: | |||
4551 | languageName: node | 4505 | languageName: node |
4552 | linkType: hard | 4506 | linkType: hard |
4553 | 4507 | ||
4554 | "foreach@npm:^2.0.5": | ||
4555 | version: 2.0.5 | ||
4556 | resolution: "foreach@npm:2.0.5" | ||
4557 | checksum: dab4fbfef0b40b69ee5eab81bcb9626b8fa8b3469c8cfa26480f3e5e1ee08c40eae07048c9a967c65aeda26e774511ccc70b3f10a604c01753c6ef24361f0fc8 | ||
4558 | languageName: node | ||
4559 | linkType: hard | ||
4560 | |||
4561 | "form-data@npm:^3.0.0": | 4508 | "form-data@npm:^3.0.0": |
4562 | version: 3.0.1 | 4509 | version: 3.0.1 |
4563 | resolution: "form-data@npm:3.0.1" | 4510 | resolution: "form-data@npm:3.0.1" |
@@ -4580,7 +4527,7 @@ __metadata: | |||
4580 | languageName: node | 4527 | languageName: node |
4581 | linkType: hard | 4528 | linkType: hard |
4582 | 4529 | ||
4583 | "fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": | 4530 | "fs-extra@npm:^10.0.0": |
4584 | version: 10.1.0 | 4531 | version: 10.1.0 |
4585 | resolution: "fs-extra@npm:10.1.0" | 4532 | resolution: "fs-extra@npm:10.1.0" |
4586 | dependencies: | 4533 | dependencies: |
@@ -4694,7 +4641,7 @@ __metadata: | |||
4694 | languageName: node | 4641 | languageName: node |
4695 | linkType: hard | 4642 | linkType: hard |
4696 | 4643 | ||
4697 | "get-intrinsic@npm:^1.0.1, get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": | 4644 | "get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": |
4698 | version: 1.1.1 | 4645 | version: 1.1.1 |
4699 | resolution: "get-intrinsic@npm:1.1.1" | 4646 | resolution: "get-intrinsic@npm:1.1.1" |
4700 | dependencies: | 4647 | dependencies: |
@@ -5224,16 +5171,6 @@ __metadata: | |||
5224 | languageName: node | 5171 | languageName: node |
5225 | linkType: hard | 5172 | linkType: hard |
5226 | 5173 | ||
5227 | "is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.0": | ||
5228 | version: 1.1.1 | ||
5229 | resolution: "is-arguments@npm:1.1.1" | ||
5230 | dependencies: | ||
5231 | call-bind: ^1.0.2 | ||
5232 | has-tostringtag: ^1.0.0 | ||
5233 | checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 | ||
5234 | languageName: node | ||
5235 | linkType: hard | ||
5236 | |||
5237 | "is-arrayish@npm:^0.2.1": | 5174 | "is-arrayish@npm:^0.2.1": |
5238 | version: 0.2.1 | 5175 | version: 0.2.1 |
5239 | resolution: "is-arrayish@npm:0.2.1" | 5176 | resolution: "is-arrayish@npm:0.2.1" |
@@ -5316,7 +5253,7 @@ __metadata: | |||
5316 | languageName: node | 5253 | languageName: node |
5317 | linkType: hard | 5254 | linkType: hard |
5318 | 5255 | ||
5319 | "is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.2": | 5256 | "is-date-object@npm:^1.0.1": |
5320 | version: 1.0.5 | 5257 | version: 1.0.5 |
5321 | resolution: "is-date-object@npm:1.0.5" | 5258 | resolution: "is-date-object@npm:1.0.5" |
5322 | dependencies: | 5259 | dependencies: |
@@ -5372,13 +5309,6 @@ __metadata: | |||
5372 | languageName: node | 5309 | languageName: node |
5373 | linkType: hard | 5310 | linkType: hard |
5374 | 5311 | ||
5375 | "is-map@npm:^2.0.1, is-map@npm:^2.0.2": | ||
5376 | version: 2.0.2 | ||
5377 | resolution: "is-map@npm:2.0.2" | ||
5378 | checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728 | ||
5379 | languageName: node | ||
5380 | linkType: hard | ||
5381 | |||
5382 | "is-negative-zero@npm:^2.0.1": | 5312 | "is-negative-zero@npm:^2.0.1": |
5383 | version: 2.0.2 | 5313 | version: 2.0.2 |
5384 | resolution: "is-negative-zero@npm:2.0.2" | 5314 | resolution: "is-negative-zero@npm:2.0.2" |
@@ -5430,7 +5360,7 @@ __metadata: | |||
5430 | languageName: node | 5360 | languageName: node |
5431 | linkType: hard | 5361 | linkType: hard |
5432 | 5362 | ||
5433 | "is-regex@npm:^1.1.1, is-regex@npm:^1.1.4": | 5363 | "is-regex@npm:^1.1.4": |
5434 | version: 1.1.4 | 5364 | version: 1.1.4 |
5435 | resolution: "is-regex@npm:1.1.4" | 5365 | resolution: "is-regex@npm:1.1.4" |
5436 | dependencies: | 5366 | dependencies: |
@@ -5440,13 +5370,6 @@ __metadata: | |||
5440 | languageName: node | 5370 | languageName: node |
5441 | linkType: hard | 5371 | linkType: hard |
5442 | 5372 | ||
5443 | "is-set@npm:^2.0.1, is-set@npm:^2.0.2": | ||
5444 | version: 2.0.2 | ||
5445 | resolution: "is-set@npm:2.0.2" | ||
5446 | checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57 | ||
5447 | languageName: node | ||
5448 | linkType: hard | ||
5449 | |||
5450 | "is-shared-array-buffer@npm:^1.0.1": | 5373 | "is-shared-array-buffer@npm:^1.0.1": |
5451 | version: 1.0.1 | 5374 | version: 1.0.1 |
5452 | resolution: "is-shared-array-buffer@npm:1.0.1" | 5375 | resolution: "is-shared-array-buffer@npm:1.0.1" |
@@ -5479,19 +5402,6 @@ __metadata: | |||
5479 | languageName: node | 5402 | languageName: node |
5480 | linkType: hard | 5403 | linkType: hard |
5481 | 5404 | ||
5482 | "is-typed-array@npm:^1.1.7": | ||
5483 | version: 1.1.8 | ||
5484 | resolution: "is-typed-array@npm:1.1.8" | ||
5485 | dependencies: | ||
5486 | available-typed-arrays: ^1.0.5 | ||
5487 | call-bind: ^1.0.2 | ||
5488 | es-abstract: ^1.18.5 | ||
5489 | foreach: ^2.0.5 | ||
5490 | has-tostringtag: ^1.0.0 | ||
5491 | checksum: aa0f9f0716e19e2fb8aef69e69e4205479d25ace778e2339fc910948115cde4b0d9aff9d5d1e8b80f09a5664998278e05e54ad3dc9cb12cefcf86db71084ed00 | ||
5492 | languageName: node | ||
5493 | linkType: hard | ||
5494 | |||
5495 | "is-typedarray@npm:^1.0.0": | 5405 | "is-typedarray@npm:^1.0.0": |
5496 | version: 1.0.0 | 5406 | version: 1.0.0 |
5497 | resolution: "is-typedarray@npm:1.0.0" | 5407 | resolution: "is-typedarray@npm:1.0.0" |
@@ -5499,13 +5409,6 @@ __metadata: | |||
5499 | languageName: node | 5409 | languageName: node |
5500 | linkType: hard | 5410 | linkType: hard |
5501 | 5411 | ||
5502 | "is-weakmap@npm:^2.0.1": | ||
5503 | version: 2.0.1 | ||
5504 | resolution: "is-weakmap@npm:2.0.1" | ||
5505 | checksum: 1222bb7e90c32bdb949226e66d26cb7bce12e1e28e3e1b40bfa6b390ba3e08192a8664a703dff2a00a84825f4e022f9cd58c4599ff9981ab72b1d69479f4f7f6 | ||
5506 | languageName: node | ||
5507 | linkType: hard | ||
5508 | |||
5509 | "is-weakref@npm:^1.0.1": | 5412 | "is-weakref@npm:^1.0.1": |
5510 | version: 1.0.2 | 5413 | version: 1.0.2 |
5511 | resolution: "is-weakref@npm:1.0.2" | 5414 | resolution: "is-weakref@npm:1.0.2" |
@@ -5515,16 +5418,6 @@ __metadata: | |||
5515 | languageName: node | 5418 | languageName: node |
5516 | linkType: hard | 5419 | linkType: hard |
5517 | 5420 | ||
5518 | "is-weakset@npm:^2.0.1": | ||
5519 | version: 2.0.2 | ||
5520 | resolution: "is-weakset@npm:2.0.2" | ||
5521 | dependencies: | ||
5522 | call-bind: ^1.0.2 | ||
5523 | get-intrinsic: ^1.1.1 | ||
5524 | checksum: 5d8698d1fa599a0635d7ca85be9c26d547b317ed8fd83fc75f03efbe75d50001b5eececb1e9971de85fcde84f69ae6f8346bc92d20d55d46201d328e4c74a367 | ||
5525 | languageName: node | ||
5526 | linkType: hard | ||
5527 | |||
5528 | "is-yarn-global@npm:^0.3.0": | 5421 | "is-yarn-global@npm:^0.3.0": |
5529 | version: 0.3.0 | 5422 | version: 0.3.0 |
5530 | resolution: "is-yarn-global@npm:0.3.0" | 5423 | resolution: "is-yarn-global@npm:0.3.0" |
@@ -5532,13 +5425,6 @@ __metadata: | |||
5532 | languageName: node | 5425 | languageName: node |
5533 | linkType: hard | 5426 | linkType: hard |
5534 | 5427 | ||
5535 | "isarray@npm:^2.0.5": | ||
5536 | version: 2.0.5 | ||
5537 | resolution: "isarray@npm:2.0.5" | ||
5538 | checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a | ||
5539 | languageName: node | ||
5540 | linkType: hard | ||
5541 | |||
5542 | "isarray@npm:~1.0.0": | 5428 | "isarray@npm:~1.0.0": |
5543 | version: 1.0.0 | 5429 | version: 1.0.0 |
5544 | resolution: "isarray@npm:1.0.0" | 5430 | resolution: "isarray@npm:1.0.0" |
@@ -6550,13 +6436,6 @@ __metadata: | |||
6550 | languageName: node | 6436 | languageName: node |
6551 | linkType: hard | 6437 | linkType: hard |
6552 | 6438 | ||
6553 | "macos-release@npm:^3.0.1": | ||
6554 | version: 3.0.1 | ||
6555 | resolution: "macos-release@npm:3.0.1" | ||
6556 | checksum: 117c78e92b995bcd391cd7a35cbae122aae491ec6ef726257c7d58ab06087506b9c09d2c89c1dc11cf8fca5ade7dbfb18f8bed01702f5faf7ea5371e07405074 | ||
6557 | languageName: node | ||
6558 | linkType: hard | ||
6559 | |||
6560 | "make-dir@npm:^3.0.0": | 6439 | "make-dir@npm:^3.0.0": |
6561 | version: 3.1.0 | 6440 | version: 3.1.0 |
6562 | resolution: "make-dir@npm:3.1.0" | 6441 | resolution: "make-dir@npm:3.1.0" |
@@ -7020,16 +6899,6 @@ __metadata: | |||
7020 | languageName: node | 6899 | languageName: node |
7021 | linkType: hard | 6900 | linkType: hard |
7022 | 6901 | ||
7023 | "object-is@npm:^1.1.4": | ||
7024 | version: 1.1.5 | ||
7025 | resolution: "object-is@npm:1.1.5" | ||
7026 | dependencies: | ||
7027 | call-bind: ^1.0.2 | ||
7028 | define-properties: ^1.1.3 | ||
7029 | checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe | ||
7030 | languageName: node | ||
7031 | linkType: hard | ||
7032 | |||
7033 | "object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": | 6902 | "object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": |
7034 | version: 1.1.1 | 6903 | version: 1.1.1 |
7035 | resolution: "object-keys@npm:1.1.1" | 6904 | resolution: "object-keys@npm:1.1.1" |
@@ -7138,16 +7007,6 @@ __metadata: | |||
7138 | languageName: node | 7007 | languageName: node |
7139 | linkType: hard | 7008 | linkType: hard |
7140 | 7009 | ||
7141 | "os-name@npm:^5.0.1": | ||
7142 | version: 5.0.1 | ||
7143 | resolution: "os-name@npm:5.0.1" | ||
7144 | dependencies: | ||
7145 | macos-release: ^3.0.1 | ||
7146 | windows-release: ^5.0.1 | ||
7147 | checksum: 7fe0db633aae8a030d0897655deede763a5b76a2b7b156e3f956e28b1c2ba9bb43565ce6b82cb4cf1c196673a80ca68b420d33450e29dd82911f3b37fc168142 | ||
7148 | languageName: node | ||
7149 | linkType: hard | ||
7150 | |||
7151 | "p-cancelable@npm:^1.0.0": | 7010 | "p-cancelable@npm:^1.0.0": |
7152 | version: 1.1.0 | 7011 | version: 1.1.0 |
7153 | resolution: "p-cancelable@npm:1.1.0" | 7012 | resolution: "p-cancelable@npm:1.1.0" |
@@ -7717,7 +7576,7 @@ __metadata: | |||
7717 | languageName: node | 7576 | languageName: node |
7718 | linkType: hard | 7577 | linkType: hard |
7719 | 7578 | ||
7720 | "regexp.prototype.flags@npm:^1.3.0, regexp.prototype.flags@npm:^1.3.1": | 7579 | "regexp.prototype.flags@npm:^1.3.1": |
7721 | version: 1.3.1 | 7580 | version: 1.3.1 |
7722 | resolution: "regexp.prototype.flags@npm:1.3.1" | 7581 | resolution: "regexp.prototype.flags@npm:1.3.1" |
7723 | dependencies: | 7582 | dependencies: |
@@ -8097,7 +7956,7 @@ __metadata: | |||
8097 | languageName: node | 7956 | languageName: node |
8098 | linkType: hard | 7957 | linkType: hard |
8099 | 7958 | ||
8100 | "side-channel@npm:^1.0.3, side-channel@npm:^1.0.4": | 7959 | "side-channel@npm:^1.0.4": |
8101 | version: 1.0.4 | 7960 | version: 1.0.4 |
8102 | resolution: "side-channel@npm:1.0.4" | 7961 | resolution: "side-channel@npm:1.0.4" |
8103 | dependencies: | 7962 | dependencies: |
@@ -9184,7 +9043,7 @@ __metadata: | |||
9184 | languageName: node | 9043 | languageName: node |
9185 | linkType: hard | 9044 | linkType: hard |
9186 | 9045 | ||
9187 | "which-boxed-primitive@npm:^1.0.1, which-boxed-primitive@npm:^1.0.2": | 9046 | "which-boxed-primitive@npm:^1.0.2": |
9188 | version: 1.0.2 | 9047 | version: 1.0.2 |
9189 | resolution: "which-boxed-primitive@npm:1.0.2" | 9048 | resolution: "which-boxed-primitive@npm:1.0.2" |
9190 | dependencies: | 9049 | dependencies: |
@@ -9197,32 +9056,6 @@ __metadata: | |||
9197 | languageName: node | 9056 | languageName: node |
9198 | linkType: hard | 9057 | linkType: hard |
9199 | 9058 | ||
9200 | "which-collection@npm:^1.0.1": | ||
9201 | version: 1.0.1 | ||
9202 | resolution: "which-collection@npm:1.0.1" | ||
9203 | dependencies: | ||
9204 | is-map: ^2.0.1 | ||
9205 | is-set: ^2.0.1 | ||
9206 | is-weakmap: ^2.0.1 | ||
9207 | is-weakset: ^2.0.1 | ||
9208 | checksum: c815bbd163107ef9cb84f135e6f34453eaf4cca994e7ba85ddb0d27cea724c623fae2a473ceccfd5549c53cc65a5d82692de418166df3f858e1e5dc60818581c | ||
9209 | languageName: node | ||
9210 | linkType: hard | ||
9211 | |||
9212 | "which-typed-array@npm:^1.1.2": | ||
9213 | version: 1.1.7 | ||
9214 | resolution: "which-typed-array@npm:1.1.7" | ||
9215 | dependencies: | ||
9216 | available-typed-arrays: ^1.0.5 | ||
9217 | call-bind: ^1.0.2 | ||
9218 | es-abstract: ^1.18.5 | ||
9219 | foreach: ^2.0.5 | ||
9220 | has-tostringtag: ^1.0.0 | ||
9221 | is-typed-array: ^1.1.7 | ||
9222 | checksum: 147837cf5866e36b6b2e427731709e02f79f1578477cbde68ed773a5307520a6cb6836c73c79c30690a473266ee59010b83b6d9b25d8d677a40ff77fb37a8a84 | ||
9223 | languageName: node | ||
9224 | linkType: hard | ||
9225 | |||
9226 | "which@npm:^2.0.1, which@npm:^2.0.2": | 9059 | "which@npm:^2.0.1, which@npm:^2.0.2": |
9227 | version: 2.0.2 | 9060 | version: 2.0.2 |
9228 | resolution: "which@npm:2.0.2" | 9061 | resolution: "which@npm:2.0.2" |
@@ -9252,15 +9085,6 @@ __metadata: | |||
9252 | languageName: node | 9085 | languageName: node |
9253 | linkType: hard | 9086 | linkType: hard |
9254 | 9087 | ||
9255 | "windows-release@npm:^5.0.1": | ||
9256 | version: 5.0.1 | ||
9257 | resolution: "windows-release@npm:5.0.1" | ||
9258 | dependencies: | ||
9259 | execa: ^5.1.1 | ||
9260 | checksum: b6b403333b7b3ea31a805c287f210962d8f3191865d81d2fd3955e603ab4d6893abc746d87b7da5b2a7a044b7b18df97c948e7d5392baed1d2bc5687fbf7431d | ||
9261 | languageName: node | ||
9262 | linkType: hard | ||
9263 | |||
9264 | "word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": | 9088 | "word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": |
9265 | version: 1.2.3 | 9089 | version: 1.2.3 |
9266 | resolution: "word-wrap@npm:1.2.3" | 9090 | resolution: "word-wrap@npm:1.2.3" |