Skip to content

Commit 098266b

Browse files
committed
feat: cache-backed store for config data
1 parent f5d1cea commit 098266b

File tree

6 files changed

+114
-89
lines changed

6 files changed

+114
-89
lines changed

electron/main/ipc/ipc.controller.ts

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export class IpcController {
6161
}
6262

6363
private pingHandler: IpcInvokeHandler<'ping'> = async (): Promise<string> => {
64-
this.dispatch('window:pong', 'pong2');
6564
return 'pong';
6665
};
6766

electron/main/store/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './store.service';
2+
export * from './store.types';

electron/main/store/store.service.ts

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { app, safeStorage } from 'electron';
2+
import path from 'node:path';
3+
import { isNil } from 'lodash';
4+
import type { CacheService } from '../cache';
5+
import { DiskCacheServiceImpl } from '../cache';
6+
import { createLogger } from '../logger';
7+
import type { StoreService, StoreSetOptions, StoredValue } from './store.types';
8+
9+
const logger = createLogger('store');
10+
11+
/**
12+
* Simple file-backed store for storing key-value pairs.
13+
*/
14+
class StoreServiceImpl implements StoreService {
15+
private cacheService: CacheService;
16+
17+
constructor(options: { filepath: string }) {
18+
this.cacheService = new DiskCacheServiceImpl({
19+
filepath: options.filepath,
20+
});
21+
}
22+
23+
public async get<T>(key: string): Promise<T | undefined> {
24+
const storedValue = await this.cacheService.get<StoredValue<T>>(key);
25+
26+
if (storedValue?.encrypted) {
27+
const safeValueHex = storedValue.value;
28+
const safeValueBytes = Buffer.from(safeValueHex, 'hex');
29+
const safeValueJson = safeStorage.decryptString(safeValueBytes);
30+
try {
31+
return JSON.parse(safeValueJson) as T;
32+
} catch (error) {
33+
logger.error('failed to parse stored value', { key, error });
34+
return undefined;
35+
}
36+
}
37+
38+
return storedValue?.value;
39+
}
40+
41+
public async set<T>(
42+
key: string,
43+
value: T,
44+
options?: StoreSetOptions
45+
): Promise<void> {
46+
const { encrypted = false } = options ?? {};
47+
48+
if (isNil(value)) {
49+
return this.remove(key);
50+
}
51+
52+
let valueToStore: StoredValue<T>;
53+
54+
if (encrypted) {
55+
const safeValueJson = JSON.stringify(value);
56+
const safeValueBytes = safeStorage.encryptString(safeValueJson);
57+
const safeValueHex = safeValueBytes.toString('hex');
58+
valueToStore = {
59+
encrypted,
60+
value: safeValueHex,
61+
};
62+
} else {
63+
valueToStore = {
64+
encrypted,
65+
value,
66+
};
67+
}
68+
69+
await this.cacheService.set(key, valueToStore);
70+
}
71+
72+
public async remove(key: string): Promise<void> {
73+
await this.cacheService.remove(key);
74+
}
75+
}
76+
77+
// There is exactly one store instance so that it's
78+
// easy anywhere in the app to get/set config values.
79+
const store = new StoreServiceImpl({
80+
filepath: path.join(app.getPath('userData'), 'config.json'),
81+
});
82+
83+
export { store };

electron/main/store/store.types.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export type StoredValue<T> =
2+
| {
3+
encrypted: true;
4+
value: string; // hex string of encrypted json-stringified value
5+
}
6+
| {
7+
encrypted: false;
8+
value: T;
9+
};
10+
11+
export interface StoreSetOptions {
12+
/**
13+
* If `encrypted` is true then uses the operating system's
14+
* secure storage to encrypt and protect the value before storing it.
15+
*/
16+
encrypted?: boolean;
17+
}
18+
19+
export interface StoreService {
20+
get<T>(key: string): Promise<T | undefined>;
21+
set<T>(key: string, value: T, options?: StoreSetOptions): Promise<void>;
22+
remove(key: string): Promise<void>;
23+
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"electron-is-dev": "^2.0.0",
7171
"electron-log": "^5.0.0",
7272
"electron-serve": "^1.2.0",
73-
"electron-store": "^8.1.0",
73+
"fs-extra": "^11.1.1",
7474
"lodash": "^4.17.21",
7575
"react": "^18.2.0",
7676
"react-dom": "^18.2.0",

yarn.lock

+5-87
Original file line numberDiff line numberDiff line change
@@ -2698,7 +2698,7 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4, ajv@^6.12.5:
26982698
json-schema-traverse "^0.4.1"
26992699
uri-js "^4.2.2"
27002700

2701-
ajv@^8.0.0, ajv@^8.11.0, ajv@^8.6.3, ajv@^8.9.0:
2701+
ajv@^8.0.0, ajv@^8.11.0, ajv@^8.9.0:
27022702
version "8.12.0"
27032703
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
27042704
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
@@ -3013,11 +3013,6 @@ at-least-node@^1.0.0:
30133013
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
30143014
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
30153015

3016-
atomically@^1.7.0:
3017-
version "1.7.0"
3018-
resolved "https://registry.yarnpkg.com/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe"
3019-
integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==
3020-
30213016
attr-accept@^2.2.2:
30223017
version "2.2.2"
30233018
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b"
@@ -3741,22 +3736,6 @@ concurrently@^8.2.2:
37413736
tree-kill "^1.2.2"
37423737
yargs "^17.7.2"
37433738

3744-
conf@^10.2.0:
3745-
version "10.2.0"
3746-
resolved "https://registry.yarnpkg.com/conf/-/conf-10.2.0.tgz#838e757be963f1a2386dfe048a98f8f69f7b55d6"
3747-
integrity sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==
3748-
dependencies:
3749-
ajv "^8.6.3"
3750-
ajv-formats "^2.1.1"
3751-
atomically "^1.7.0"
3752-
debounce-fn "^4.0.0"
3753-
dot-prop "^6.0.1"
3754-
env-paths "^2.2.1"
3755-
json-schema-typed "^7.0.3"
3756-
onetime "^5.1.2"
3757-
pkg-up "^3.1.0"
3758-
semver "^7.3.5"
3759-
37603739
config-chain@^1.1.11:
37613740
version "1.1.13"
37623741
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
@@ -3966,13 +3945,6 @@ date-fns@^2.30.0:
39663945
dependencies:
39673946
"@babel/runtime" "^7.21.0"
39683947

3969-
debounce-fn@^4.0.0:
3970-
version "4.0.0"
3971-
resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7"
3972-
integrity sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==
3973-
dependencies:
3974-
mimic-fn "^3.0.0"
3975-
39763948
debug@4, [email protected], debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
39773949
version "4.3.4"
39783950
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@@ -4199,13 +4171,6 @@ dot-prop@^5.1.0:
41994171
dependencies:
42004172
is-obj "^2.0.0"
42014173

4202-
dot-prop@^6.0.1:
4203-
version "6.0.1"
4204-
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083"
4205-
integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==
4206-
dependencies:
4207-
is-obj "^2.0.0"
4208-
42094174
dotenv-expand@^5.1.0:
42104175
version "5.1.0"
42114176
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
@@ -4293,14 +4258,6 @@ electron-serve@^1.2.0:
42934258
resolved "https://registry.yarnpkg.com/electron-serve/-/electron-serve-1.2.0.tgz#c2aa17017d89483c935f725ed70f8a63845c0091"
42944259
integrity sha512-zJG3wisMrDn2G/gnjrhyB074COvly1FnS0U7Edm8bfXLB8MYX7UtwR9/y2LkFreYjzQHm9nEbAfgCmF+9M9LHQ==
42954260

4296-
electron-store@^8.1.0:
4297-
version "8.1.0"
4298-
resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-8.1.0.tgz#46a398f2bd9aa83c4a9daaae28380e2b3b9c7597"
4299-
integrity sha512-2clHg/juMjOH0GT9cQ6qtmIvK183B39ZXR0bUoPwKwYHJsEF3quqyDzMFUAu+0OP8ijmN2CbPRAelhNbWUbzwA==
4300-
dependencies:
4301-
conf "^10.2.0"
4302-
type-fest "^2.17.0"
4303-
43044261
electron-to-chromium@^1.4.535:
43054262
version "1.4.569"
43064263
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz#1298b67727187ffbaac005a7425490d157f3ad03"
@@ -4370,7 +4327,7 @@ env-ci@^10.0.0:
43704327
execa "^8.0.0"
43714328
java-properties "^1.0.2"
43724329

4373-
env-paths@^2.2.0, env-paths@^2.2.1:
4330+
env-paths@^2.2.0:
43744331
version "2.2.1"
43754332
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
43764333
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
@@ -4989,13 +4946,6 @@ find-up@^2.0.0:
49894946
dependencies:
49904947
locate-path "^2.0.0"
49914948

4992-
find-up@^3.0.0:
4993-
version "3.0.0"
4994-
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
4995-
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
4996-
dependencies:
4997-
locate-path "^3.0.0"
4998-
49994949
find-up@^4.0.0, find-up@^4.1.0:
50004950
version "4.1.0"
50014951
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@@ -5096,7 +5046,7 @@ fs-extra@^10.0.0, fs-extra@^10.1.0:
50965046
jsonfile "^6.0.1"
50975047
universalify "^2.0.0"
50985048

5099-
fs-extra@^11.0.0:
5049+
fs-extra@^11.0.0, fs-extra@^11.1.1:
51005050
version "11.1.1"
51015051
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
51025052
integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
@@ -6761,11 +6711,6 @@ json-schema-traverse@^1.0.0:
67616711
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
67626712
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
67636713

6764-
json-schema-typed@^7.0.3:
6765-
version "7.0.3"
6766-
resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9"
6767-
integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==
6768-
67696714
json-stable-stringify-without-jsonify@^1.0.1:
67706715
version "1.0.1"
67716716
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@@ -7093,14 +7038,6 @@ locate-path@^2.0.0:
70937038
p-locate "^2.0.0"
70947039
path-exists "^3.0.0"
70957040

7096-
locate-path@^3.0.0:
7097-
version "3.0.0"
7098-
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
7099-
integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
7100-
dependencies:
7101-
p-locate "^3.0.0"
7102-
path-exists "^3.0.0"
7103-
71047041
locate-path@^5.0.0:
71057042
version "5.0.0"
71067043
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@@ -7466,11 +7403,6 @@ mimic-fn@^2.1.0:
74667403
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
74677404
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
74687405

7469-
mimic-fn@^3.0.0:
7470-
version "3.1.0"
7471-
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74"
7472-
integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==
7473-
74747406
mimic-fn@^4.0.0:
74757407
version "4.0.0"
74767408
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
@@ -8168,7 +8100,7 @@ p-limit@^1.1.0:
81688100
dependencies:
81698101
p-try "^1.0.0"
81708102

8171-
p-limit@^2.0.0, p-limit@^2.2.0:
8103+
p-limit@^2.2.0:
81728104
version "2.3.0"
81738105
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
81748106
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
@@ -8196,13 +8128,6 @@ p-locate@^2.0.0:
81968128
dependencies:
81978129
p-limit "^1.1.0"
81988130

8199-
p-locate@^3.0.0:
8200-
version "3.0.0"
8201-
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
8202-
integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
8203-
dependencies:
8204-
p-limit "^2.0.0"
8205-
82068131
p-locate@^4.1.0:
82078132
version "4.1.0"
82088133
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
@@ -8468,13 +8393,6 @@ pkg-dir@^4.2.0:
84688393
dependencies:
84698394
find-up "^4.0.0"
84708395

8471-
pkg-up@^3.1.0:
8472-
version "3.1.0"
8473-
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
8474-
integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
8475-
dependencies:
8476-
find-up "^3.0.0"
8477-
84788396
plist@^3.0.4, plist@^3.0.5:
84798397
version "3.1.0"
84808398
resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9"
@@ -10286,7 +10204,7 @@ type-fest@^1.0.1, type-fest@^1.0.2:
1028610204
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
1028710205
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
1028810206

10289-
type-fest@^2.12.2, type-fest@^2.17.0:
10207+
type-fest@^2.12.2:
1029010208
version "2.19.0"
1029110209
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
1029210210
integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==

0 commit comments

Comments
 (0)