sliftutils 0.85.0 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +9 -1
- package/misc/types.d.ts +2 -0
- package/misc/types.ts +21 -0
- package/package.json +2 -2
- package/storage/DiskCollection.d.ts +2 -0
- package/storage/DiskCollection.ts +5 -1
- package/storage/StorageObservable.d.ts +5 -1
- package/storage/StorageObservable.ts +15 -3
- package/storage/TransactionStorage.ts +12 -18
- package/web/ExamplePage.tsx +0 -18
- package/yarn.lock +6 -6
package/index.d.ts
CHANGED
|
@@ -127,6 +127,8 @@ declare module "sliftutils/misc/random" {
|
|
|
127
127
|
|
|
128
128
|
declare module "sliftutils/misc/types" {
|
|
129
129
|
export declare function isDefined<T>(value: T | undefined | null): value is T;
|
|
130
|
+
export declare function freezeObject(value: unknown): unknown;
|
|
131
|
+
export declare function deepFreezeObject(value: unknown): void;
|
|
130
132
|
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -658,6 +660,8 @@ declare module "sliftutils/storage/DiskCollection" {
|
|
|
658
660
|
writeDelay?: number | undefined;
|
|
659
661
|
cbor?: boolean | undefined;
|
|
660
662
|
noPrompt?: boolean | undefined;
|
|
663
|
+
freeze?: "deep" | "shallow" | undefined;
|
|
664
|
+
beforeWrite?: ((newValue: T) => void) | undefined;
|
|
661
665
|
} | undefined);
|
|
662
666
|
transactionStorage: TransactionStorage | undefined;
|
|
663
667
|
initStorage(): Promise<IStorage<T>>;
|
|
@@ -969,6 +973,7 @@ declare module "sliftutils/storage/StorageObservable" {
|
|
|
969
973
|
import { IStorage, IStorageSync } from "./IStorage";
|
|
970
974
|
export declare class StorageSync<T> implements IStorageSync<T> {
|
|
971
975
|
storage: IStorage<T>;
|
|
976
|
+
private config?;
|
|
972
977
|
cached: import("mobx").ObservableMap<string, T | undefined>;
|
|
973
978
|
infoCached: import("mobx").ObservableMap<string, {
|
|
974
979
|
size: number;
|
|
@@ -978,7 +983,10 @@ declare module "sliftutils/storage/StorageObservable" {
|
|
|
978
983
|
synced: {
|
|
979
984
|
keySeqNum: number;
|
|
980
985
|
};
|
|
981
|
-
constructor(storage: IStorage<T
|
|
986
|
+
constructor(storage: IStorage<T>, config?: {
|
|
987
|
+
freeze?: "deep" | "shallow" | undefined;
|
|
988
|
+
beforeWrite?: ((newValue: T) => void) | undefined;
|
|
989
|
+
} | undefined);
|
|
982
990
|
get(key: string): T | undefined;
|
|
983
991
|
set(key: string, value: T): void;
|
|
984
992
|
remove(key: string): void;
|
package/misc/types.d.ts
CHANGED
package/misc/types.ts
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
1
|
export function isDefined<T>(value: T | undefined | null): value is T {
|
|
2
2
|
return value !== undefined && value !== null;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export function freezeObject(value: unknown) {
|
|
7
|
+
if (!value) return value;
|
|
8
|
+
Object.freeze(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function deepFreezeObject(value: unknown) {
|
|
12
|
+
if (!value) return;
|
|
13
|
+
if (typeof value !== "object") return;
|
|
14
|
+
if (Object.isFrozen(value)) return;
|
|
15
|
+
|
|
16
|
+
Object.freeze(value);
|
|
17
|
+
|
|
18
|
+
Object.getOwnPropertyNames(value).forEach(prop => {
|
|
19
|
+
const propValue = (value as any)[prop];
|
|
20
|
+
if (propValue && typeof propValue === "object") {
|
|
21
|
+
deepFreezeObject(propValue);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
3
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sliftutils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"mobx": "^6.13.3",
|
|
49
49
|
"preact-old-types": "^10.28.1",
|
|
50
50
|
"shell-quote": "^1.8.3",
|
|
51
|
-
"socket-function": "^0.
|
|
51
|
+
"socket-function": "^0.165.0",
|
|
52
52
|
"typenode": "^6.0.0",
|
|
53
53
|
"typesafecss": "*",
|
|
54
54
|
"ws": "^8.18.3",
|
|
@@ -10,6 +10,8 @@ export declare class DiskCollection<T> implements IStorageSync<T> {
|
|
|
10
10
|
writeDelay?: number | undefined;
|
|
11
11
|
cbor?: boolean | undefined;
|
|
12
12
|
noPrompt?: boolean | undefined;
|
|
13
|
+
freeze?: "deep" | "shallow" | undefined;
|
|
14
|
+
beforeWrite?: ((newValue: T) => void) | undefined;
|
|
13
15
|
} | undefined);
|
|
14
16
|
transactionStorage: TransactionStorage | undefined;
|
|
15
17
|
initStorage(): Promise<IStorage<T>>;
|
|
@@ -18,6 +18,9 @@ export class DiskCollection<T> implements IStorageSync<T> {
|
|
|
18
18
|
writeDelay?: number;
|
|
19
19
|
cbor?: boolean;
|
|
20
20
|
noPrompt?: boolean;
|
|
21
|
+
freeze?: "shallow" | "deep";
|
|
22
|
+
// May mutate newValue in order to change what will be written
|
|
23
|
+
beforeWrite?: (newValue: T) => void;
|
|
21
24
|
}
|
|
22
25
|
) {
|
|
23
26
|
}
|
|
@@ -41,7 +44,8 @@ export class DiskCollection<T> implements IStorageSync<T> {
|
|
|
41
44
|
private synced = new StorageSync(
|
|
42
45
|
new PendingStorage(`Collection (${this.collectionName})`,
|
|
43
46
|
new DelayedStorage<T>(this.baseStorage)
|
|
44
|
-
)
|
|
47
|
+
),
|
|
48
|
+
this.config
|
|
45
49
|
);
|
|
46
50
|
|
|
47
51
|
public get(key: string): T | undefined {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IStorage, IStorageSync } from "./IStorage";
|
|
2
2
|
export declare class StorageSync<T> implements IStorageSync<T> {
|
|
3
3
|
storage: IStorage<T>;
|
|
4
|
+
private config?;
|
|
4
5
|
cached: import("mobx").ObservableMap<string, T | undefined>;
|
|
5
6
|
infoCached: import("mobx").ObservableMap<string, {
|
|
6
7
|
size: number;
|
|
@@ -10,7 +11,10 @@ export declare class StorageSync<T> implements IStorageSync<T> {
|
|
|
10
11
|
synced: {
|
|
11
12
|
keySeqNum: number;
|
|
12
13
|
};
|
|
13
|
-
constructor(storage: IStorage<T
|
|
14
|
+
constructor(storage: IStorage<T>, config?: {
|
|
15
|
+
freeze?: "deep" | "shallow" | undefined;
|
|
16
|
+
beforeWrite?: ((newValue: T) => void) | undefined;
|
|
17
|
+
} | undefined);
|
|
14
18
|
get(key: string): T | undefined;
|
|
15
19
|
set(key: string, value: T): void;
|
|
16
20
|
remove(key: string): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { observable } from "mobx";
|
|
2
|
-
import { isDefined } from "../misc/types";
|
|
2
|
+
import { deepFreezeObject, freezeObject, isDefined } from "../misc/types";
|
|
3
3
|
import { IStorage, IStorageSync } from "./IStorage";
|
|
4
4
|
|
|
5
5
|
// NOTE: At around 500K values (depending on their size to some degree), this will take about 2 minutes to load. But once it does it will be fast. So... keep that in mind. I recommend not exceeding 100K
|
|
@@ -11,7 +11,11 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
11
11
|
keySeqNum: 0,
|
|
12
12
|
}, undefined, { deep: false });
|
|
13
13
|
|
|
14
|
-
constructor(public storage: IStorage<T
|
|
14
|
+
constructor(public storage: IStorage<T>, private config?: {
|
|
15
|
+
freeze?: "shallow" | "deep";
|
|
16
|
+
// May mutate newValue in order to change what will be written
|
|
17
|
+
beforeWrite?: (newValue: T) => void;
|
|
18
|
+
}) {
|
|
15
19
|
storage.watchResync?.(async () => {
|
|
16
20
|
// NOTE: If there's multiple tabs open, this'll trigger a lot, so we can't just clear all the values, as that'll cause a render where nothing's loaded.
|
|
17
21
|
this.loadedKeys = false;
|
|
@@ -33,6 +37,9 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
33
37
|
return this.cached.get(key);
|
|
34
38
|
}
|
|
35
39
|
public set(key: string, value: T): void {
|
|
40
|
+
if (this.config?.beforeWrite) {
|
|
41
|
+
this.config.beforeWrite(value);
|
|
42
|
+
}
|
|
36
43
|
if (!this.keys.has(key)) {
|
|
37
44
|
this.keys.add(key);
|
|
38
45
|
this.synced.keySeqNum++;
|
|
@@ -79,7 +86,12 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
79
86
|
let value = this.cached.get(key);
|
|
80
87
|
if (value === undefined) {
|
|
81
88
|
value = await this.storage.get(key);
|
|
82
|
-
if (this.cached.get(key) === undefined) {
|
|
89
|
+
if (value !== undefined && this.cached.get(key) === undefined) {
|
|
90
|
+
if (this.config?.freeze === "shallow") {
|
|
91
|
+
freezeObject(value);
|
|
92
|
+
} else if (this.config?.freeze === "deep") {
|
|
93
|
+
deepFreezeObject(value);
|
|
94
|
+
}
|
|
83
95
|
this.cached.set(key, value);
|
|
84
96
|
}
|
|
85
97
|
}
|
|
@@ -401,26 +401,20 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
401
401
|
this.cache.delete(entry.key);
|
|
402
402
|
} else {
|
|
403
403
|
if (!anyChanged && !initialLoad) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (!prev.value) {
|
|
409
|
-
if (entry.value) {
|
|
410
|
-
anyChanged = true;
|
|
411
|
-
}
|
|
412
|
-
} else {
|
|
413
|
-
if (!entry.value) {
|
|
414
|
-
anyChanged = true;
|
|
415
|
-
} else {
|
|
416
|
-
// Both values, so... it might not have changed
|
|
417
|
-
if (!prev.value.equals(entry.value)) {
|
|
418
|
-
anyChanged = true;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
404
|
+
const hasChanged = () => {
|
|
405
|
+
let prev = this.cache.get(entry.key);
|
|
406
|
+
if (!prev) {
|
|
407
|
+
return true;
|
|
421
408
|
}
|
|
422
|
-
|
|
409
|
+
if (!!prev.value !== !!entry.value) return true;
|
|
410
|
+
if (prev.value && entry.value && !prev.value.equals(entry.value)) {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
};
|
|
415
|
+
anyChanged = hasChanged() || anyChanged;
|
|
423
416
|
}
|
|
417
|
+
|
|
424
418
|
this.cache.set(entry.key, entry);
|
|
425
419
|
}
|
|
426
420
|
}
|
package/web/ExamplePage.tsx
CHANGED
|
@@ -13,24 +13,6 @@ export class ExamplePage extends preact.Component {
|
|
|
13
13
|
count: 0,
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
onKeyDown = (e: KeyboardEvent) => {
|
|
17
|
-
// Skip if the current target is an ipnut
|
|
18
|
-
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
let hotkeySelector = `[data-hotkey="${e.code}"]`;
|
|
22
|
-
let elements = document.querySelectorAll(hotkeySelector);
|
|
23
|
-
for (let element of elements) {
|
|
24
|
-
(element as HTMLElement).click();
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
componentDidMount(): void {
|
|
28
|
-
document.addEventListener("keydown", this.onKeyDown);
|
|
29
|
-
}
|
|
30
|
-
componentWillUnmount(): void {
|
|
31
|
-
document.removeEventListener("keydown", this.onKeyDown);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
16
|
render() {
|
|
35
17
|
return (
|
|
36
18
|
<div className={css.pad2(20)}>
|
package/yarn.lock
CHANGED
|
@@ -1349,7 +1349,7 @@ preact-old-types@^10.28.1:
|
|
|
1349
1349
|
resolved "https://registry.yarnpkg.com/preact-old-types/-/preact-old-types-10.28.1.tgz#58f9400aa1b80768809c296534ec7b49f6f09a0d"
|
|
1350
1350
|
integrity sha512-7r64HwL/PJtzE7jUMFkYVec+vSUf3z8Uozd8Bhl4HMvhcWINFzJsIEHKLAlkeCbzv+jTQl0UwVeMJQ26jK5bDg==
|
|
1351
1351
|
|
|
1352
|
-
preact@10.
|
|
1352
|
+
preact@10.24.3, "preact@npm:preact-old-types@*":
|
|
1353
1353
|
version "10.28.1"
|
|
1354
1354
|
resolved "https://registry.yarnpkg.com/preact-old-types/-/preact-old-types-10.28.1.tgz#58f9400aa1b80768809c296534ec7b49f6f09a0d"
|
|
1355
1355
|
integrity sha512-7r64HwL/PJtzE7jUMFkYVec+vSUf3z8Uozd8Bhl4HMvhcWINFzJsIEHKLAlkeCbzv+jTQl0UwVeMJQ26jK5bDg==
|
|
@@ -1494,17 +1494,17 @@ slash@^3.0.0:
|
|
|
1494
1494
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
|
1495
1495
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
|
1496
1496
|
|
|
1497
|
-
socket-function@^0.
|
|
1498
|
-
version "0.
|
|
1499
|
-
resolved "https://registry.yarnpkg.com/socket-function/-/socket-function-0.
|
|
1500
|
-
integrity sha512
|
|
1497
|
+
socket-function@^0.165.0:
|
|
1498
|
+
version "0.165.0"
|
|
1499
|
+
resolved "https://registry.yarnpkg.com/socket-function/-/socket-function-0.165.0.tgz#2c262c5cc75a79233d08538517030c504745a94c"
|
|
1500
|
+
integrity sha512-VfpljEyUEjQD4flTboGwgcerK2vuVvDM0iPNL4L4Qyo76G5DQVGcHCaYDwZuuAJ8gvTXDq9j7P7vgdjElNAhXw==
|
|
1501
1501
|
dependencies:
|
|
1502
1502
|
"@types/pako" "^2.0.3"
|
|
1503
1503
|
"@types/ws" "^8.5.3"
|
|
1504
1504
|
cbor-x "^1.6.0"
|
|
1505
1505
|
mobx "^6.6.2"
|
|
1506
1506
|
pako "^2.1.0"
|
|
1507
|
-
preact "10.
|
|
1507
|
+
preact "10.24.3"
|
|
1508
1508
|
typedev "^0.4.0"
|
|
1509
1509
|
typenode "^5.13.0"
|
|
1510
1510
|
ws "^8.17.1"
|