tool-db 2.5.3 → 2.5.5
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/README.md +82 -82
- package/bundle.js +1 -1
- package/dist/adapters-base/networkAdapter.d.ts +58 -58
- package/dist/adapters-base/networkAdapter.js +215 -215
- package/dist/adapters-base/storageAdapter.d.ts +11 -11
- package/dist/adapters-base/storageAdapter.js +35 -35
- package/dist/adapters-base/userAdapter.d.ts +15 -15
- package/dist/adapters-base/userAdapter.js +41 -41
- package/dist/crdt/baseCrdt.d.ts +9 -9
- package/dist/crdt/baseCrdt.js +26 -26
- package/dist/crdt/counterCrdt.d.ts +30 -30
- package/dist/crdt/counterCrdt.js +105 -105
- package/dist/crdt/listCrdt.d.ts +42 -42
- package/dist/crdt/listCrdt.js +158 -158
- package/dist/crdt/mapCrdt.d.ts +32 -32
- package/dist/crdt/mapCrdt.js +117 -117
- package/dist/index.d.ts +35 -34
- package/dist/index.js +84 -82
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +28 -28
- package/dist/messageHandlers/handleCrdtGet.d.ts +2 -2
- package/dist/messageHandlers/handleCrdtGet.js +49 -28
- package/dist/messageHandlers/handleCrdtGet.js.map +1 -1
- package/dist/messageHandlers/handleCrdtPut.d.ts +2 -2
- package/dist/messageHandlers/handleCrdtPut.js +102 -92
- package/dist/messageHandlers/handleCrdtPut.js.map +1 -1
- package/dist/messageHandlers/handleFunction.d.ts +2 -0
- package/dist/messageHandlers/handleFunction.js +56 -0
- package/dist/messageHandlers/handleFunction.js.map +1 -0
- package/dist/messageHandlers/handleGet.d.ts +2 -2
- package/dist/messageHandlers/handleGet.js +49 -28
- package/dist/messageHandlers/handleGet.js.map +1 -1
- package/dist/messageHandlers/handlePing.d.ts +2 -2
- package/dist/messageHandlers/handlePing.js +35 -35
- package/dist/messageHandlers/handlePing.js.map +1 -1
- package/dist/messageHandlers/handlePong.d.ts +2 -2
- package/dist/messageHandlers/handlePong.js +25 -25
- package/dist/messageHandlers/handlePut.d.ts +2 -2
- package/dist/messageHandlers/handlePut.js +77 -56
- package/dist/messageHandlers/handlePut.js.map +1 -1
- package/dist/messageHandlers/handleQuery.d.ts +2 -2
- package/dist/messageHandlers/handleQuery.js +43 -22
- package/dist/messageHandlers/handleQuery.js.map +1 -1
- package/dist/messageHandlers/handleSubscribe.d.ts +2 -2
- package/dist/messageHandlers/handleSubscribe.js +43 -43
- package/dist/server.d.ts +1 -1
- package/dist/server.js +8 -8
- package/dist/shared.d.ts +2 -2
- package/dist/shared.js +6 -6
- package/dist/toolDbAnonSignIn.d.ts +2 -2
- package/dist/toolDbAnonSignIn.js +6 -6
- package/dist/toolDbClientOnMessage.d.ts +2 -2
- package/dist/toolDbClientOnMessage.js +61 -58
- package/dist/toolDbClientOnMessage.js.map +1 -1
- package/dist/toolDbCrdtGet.d.ts +9 -9
- package/dist/toolDbCrdtGet.js +76 -76
- package/dist/toolDbCrdtGet.js.map +1 -1
- package/dist/toolDbCrdtPut.d.ts +9 -9
- package/dist/toolDbCrdtPut.js +62 -62
- package/dist/toolDbCrdtPut.js.map +1 -1
- package/dist/toolDbFunction.d.ts +9 -0
- package/dist/toolDbFunction.js +38 -0
- package/dist/toolDbFunction.js.map +1 -0
- package/dist/toolDbGet.d.ts +9 -9
- package/dist/toolDbGet.js +76 -76
- package/dist/toolDbGet.js.map +1 -1
- package/dist/toolDbKeysSignIn.d.ts +2 -2
- package/dist/toolDbKeysSignIn.js +15 -15
- package/dist/toolDbPut.d.ts +9 -9
- package/dist/toolDbPut.js +68 -68
- package/dist/toolDbPut.js.map +1 -1
- package/dist/toolDbQueryKeys.d.ts +8 -8
- package/dist/toolDbQueryKeys.js +65 -65
- package/dist/toolDbQueryKeys.js.map +1 -1
- package/dist/toolDbSignIn.d.ts +2 -2
- package/dist/toolDbSignIn.js +26 -26
- package/dist/toolDbSignIn.js.map +1 -1
- package/dist/toolDbSignUp.d.ts +2 -2
- package/dist/toolDbSignUp.js +100 -100
- package/dist/toolDbSignUp.js.map +1 -1
- package/dist/toolDbSubscribe.d.ts +9 -9
- package/dist/toolDbSubscribe.js +49 -49
- package/dist/toolDbSubscribe.js.map +1 -1
- package/dist/toolDbVerificationWrapper.d.ts +2 -2
- package/dist/toolDbVerificationWrapper.js +97 -97
- package/dist/tooldb.d.ts +123 -108
- package/dist/tooldb.js +309 -285
- package/dist/tooldb.js.map +1 -1
- package/dist/types/message.d.ts +110 -100
- package/dist/types/message.js +16 -16
- package/dist/types/message.js.map +1 -1
- package/dist/types/tooldb.d.ts +110 -84
- package/dist/types/tooldb.js +2 -2
- package/dist/utils/catchReturn.d.ts +1 -1
- package/dist/utils/catchReturn.js +7 -7
- package/dist/utils/encoding/arrayBufferToHex.d.ts +1 -1
- package/dist/utils/encoding/arrayBufferToHex.js +18 -18
- package/dist/utils/encoding/arrayBufferToString.d.ts +1 -1
- package/dist/utils/encoding/arrayBufferToString.js +11 -11
- package/dist/utils/encoding/hexToArrayBuffer.d.ts +1 -1
- package/dist/utils/encoding/hexToArrayBuffer.js +14 -14
- package/dist/utils/encoding/hexToString.d.ts +1 -1
- package/dist/utils/encoding/hexToString.js +11 -11
- package/dist/utils/encoding/hexToUint8.d.ts +1 -1
- package/dist/utils/encoding/hexToUint8.js +7 -7
- package/dist/utils/encoding/stringToArrayBuffer.d.ts +1 -1
- package/dist/utils/encoding/stringToArrayBuffer.js +11 -11
- package/dist/utils/getPeerSignature.d.ts +2 -2
- package/dist/utils/getPeerSignature.js +8 -8
- package/dist/utils/getTimestamp.d.ts +1 -1
- package/dist/utils/getTimestamp.js +6 -6
- package/dist/utils/proofOfWork.d.ts +4 -4
- package/dist/utils/proofOfWork.js +15 -15
- package/dist/utils/randomAnimal.d.ts +1 -1
- package/dist/utils/randomAnimal.js +76 -76
- package/dist/utils/sha1.d.ts +1 -1
- package/dist/utils/sha1.js +12 -12
- package/dist/utils/sha256.d.ts +3 -3
- package/dist/utils/sha256.js +12 -12
- package/dist/utils/textRandom.d.ts +1 -1
- package/dist/utils/textRandom.js +14 -14
- package/dist/utils/uniq.d.ts +1 -1
- package/dist/utils/uniq.js +6 -6
- package/dist/utils/verifyMessage.d.ts +8 -8
- package/dist/utils/verifyMessage.js +128 -128
- package/dist/utils/verifyPeer.d.ts +2 -2
- package/dist/utils/verifyPeer.js +14 -14
- package/lib/adapters-base/networkAdapter.ts +217 -217
- package/lib/adapters-base/storageAdapter.ts +35 -35
- package/lib/adapters-base/userAdapter.ts +49 -49
- package/lib/crdt/baseCrdt.ts +21 -21
- package/lib/crdt/counterCrdt.ts +111 -111
- package/lib/crdt/listCrdt.ts +190 -190
- package/lib/crdt/mapCrdt.ts +119 -119
- package/lib/index.ts +43 -42
- package/lib/logger.ts +30 -30
- package/lib/messageHandlers/handleCrdtGet.ts +34 -29
- package/lib/messageHandlers/handleCrdtPut.ts +123 -118
- package/lib/messageHandlers/handleFunction.ts +59 -0
- package/lib/messageHandlers/handleGet.ts +34 -29
- package/lib/messageHandlers/handlePing.ts +40 -40
- package/lib/messageHandlers/handlePong.ts +30 -30
- package/lib/messageHandlers/handlePut.ts +59 -54
- package/lib/messageHandlers/handleQuery.ts +30 -25
- package/lib/messageHandlers/handleSubscribe.ts +46 -46
- package/lib/server.ts +7 -7
- package/lib/shared.ts +5 -5
- package/lib/toolDbAnonSignIn.ts +5 -5
- package/lib/toolDbClientOnMessage.ts +79 -75
- package/lib/toolDbCrdtGet.ts +83 -82
- package/lib/toolDbCrdtPut.ts +78 -77
- package/lib/toolDbFunction.ts +49 -0
- package/lib/toolDbGet.ts +81 -80
- package/lib/toolDbKeysSignIn.ts +16 -16
- package/lib/toolDbPut.ts +84 -83
- package/lib/toolDbQueryKeys.ts +65 -64
- package/lib/toolDbSignIn.ts +32 -31
- package/lib/toolDbSignUp.ts +72 -71
- package/lib/toolDbSubscribe.ts +54 -53
- package/lib/toolDbVerificationWrapper.ts +55 -55
- package/lib/tooldb.ts +343 -316
- package/lib/types/message.ts +154 -133
- package/lib/types/tooldb.ts +139 -97
- package/lib/utils/catchReturn.ts +4 -4
- package/lib/utils/encoding/arrayBufferToHex.ts +18 -18
- package/lib/utils/encoding/arrayBufferToString.ts +8 -8
- package/lib/utils/encoding/hexToArrayBuffer.ts +13 -13
- package/lib/utils/encoding/hexToString.ts +8 -8
- package/lib/utils/encoding/hexToUint8.ts +5 -5
- package/lib/utils/encoding/stringToArrayBuffer.ts +8 -8
- package/lib/utils/getPeerSignature.ts +12 -12
- package/lib/utils/getTimestamp.ts +3 -3
- package/lib/utils/proofOfWork.ts +16 -16
- package/lib/utils/randomAnimal.ts +77 -77
- package/lib/utils/sha1.ts +7 -7
- package/lib/utils/sha256.ts +7 -7
- package/lib/utils/textRandom.ts +11 -11
- package/lib/utils/uniq.ts +3 -3
- package/lib/utils/verifyMessage.ts +88 -88
- package/lib/utils/verifyPeer.ts +15 -15
- package/package.json +2 -2
- package/tsconfig.json +14 -14
package/lib/crdt/baseCrdt.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export const CRDT_MAP = "MAP";
|
|
2
|
-
|
|
3
|
-
export const CRDT_LIST = "LIST";
|
|
4
|
-
|
|
5
|
-
export const CRDT_COUNTER = "COUNTER";
|
|
6
|
-
|
|
7
|
-
export class BaseCrdt<T = any, Changes = any, Value = any> {
|
|
8
|
-
public type: string = "";
|
|
9
|
-
|
|
10
|
-
public mergeChanges(changes: Changes[]) {
|
|
11
|
-
//
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public getChanges(): Changes[] {
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get value(): Value {
|
|
19
|
-
return "" as any;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
1
|
+
export const CRDT_MAP = "MAP";
|
|
2
|
+
|
|
3
|
+
export const CRDT_LIST = "LIST";
|
|
4
|
+
|
|
5
|
+
export const CRDT_COUNTER = "COUNTER";
|
|
6
|
+
|
|
7
|
+
export class BaseCrdt<T = any, Changes = any, Value = any> {
|
|
8
|
+
public type: string = "";
|
|
9
|
+
|
|
10
|
+
public mergeChanges(changes: Changes[]) {
|
|
11
|
+
//
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public getChanges(): Changes[] {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get value(): Value {
|
|
19
|
+
return "" as any;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/lib/crdt/counterCrdt.ts
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
import { BaseCrdt, CRDT_LIST } from "..";
|
|
2
|
-
|
|
3
|
-
export type CounterOperations = "ADD" | "SUB";
|
|
4
|
-
|
|
5
|
-
export interface ChangeCounterBase {
|
|
6
|
-
t: CounterOperations; // Operation type
|
|
7
|
-
v: number; // Value
|
|
8
|
-
a: string;
|
|
9
|
-
i: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface AddCounterChange extends ChangeCounterBase {
|
|
13
|
-
t: "ADD";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface SubCounterChange extends ChangeCounterBase {
|
|
17
|
-
t: "SUB";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type CounterChanges = AddCounterChange | SubCounterChange;
|
|
21
|
-
|
|
22
|
-
export class CounterCrdt<T> extends BaseCrdt<number, CounterChanges, number> {
|
|
23
|
-
public type = CRDT_LIST;
|
|
24
|
-
|
|
25
|
-
public _changes: CounterChanges[] = [];
|
|
26
|
-
|
|
27
|
-
private _author = "";
|
|
28
|
-
|
|
29
|
-
private _value: number = 0;
|
|
30
|
-
|
|
31
|
-
private _lastUpdateSize: number = 0;
|
|
32
|
-
|
|
33
|
-
constructor(author: string, changes?: CounterChanges[]) {
|
|
34
|
-
super();
|
|
35
|
-
this._author = author;
|
|
36
|
-
if (changes) {
|
|
37
|
-
this.mergeChanges(changes);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
this.calculate();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
changesSort(a: CounterChanges, b: CounterChanges) {
|
|
44
|
-
if (a.i > b.i) return 1;
|
|
45
|
-
if (a.i < b.i) return -1;
|
|
46
|
-
return 0; // Should never be equal!
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
calculate() {
|
|
50
|
-
let temp: number = 0;
|
|
51
|
-
// Only update if we have new changes
|
|
52
|
-
if (Object.values(this._changes).length !== this._lastUpdateSize) {
|
|
53
|
-
this._changes.sort(this.changesSort).forEach((change) => {
|
|
54
|
-
if (change.t === "ADD") {
|
|
55
|
-
temp += change.v;
|
|
56
|
-
} else if (change.t === "SUB") {
|
|
57
|
-
temp -= change.v;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
this._value = temp;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
get value(): number {
|
|
66
|
-
this.calculate();
|
|
67
|
-
return this._value;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public mergeChanges(newChanges: CounterChanges[]) {
|
|
71
|
-
newChanges.forEach((change) => {
|
|
72
|
-
// Filter by author and index
|
|
73
|
-
const filtered = this._changes.filter(
|
|
74
|
-
(c) => c.i === change.i && c.a === change.a && c.t === change.t
|
|
75
|
-
);
|
|
76
|
-
// Only add if there are not matches
|
|
77
|
-
if (filtered.length === 0) {
|
|
78
|
-
this._changes.push(change);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
this.calculate();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public getChanges(): CounterChanges[] {
|
|
85
|
-
return this._changes;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public ADD(value: number) {
|
|
89
|
-
const ourChanges = this._changes.filter((c) => c.a === this._author);
|
|
90
|
-
|
|
91
|
-
this._changes.push({
|
|
92
|
-
t: "ADD",
|
|
93
|
-
v: value,
|
|
94
|
-
a: this._author,
|
|
95
|
-
i: ourChanges.length,
|
|
96
|
-
});
|
|
97
|
-
this.calculate();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public SUB(value: number) {
|
|
101
|
-
const ourChanges = this._changes.filter((c) => c.a === this._author);
|
|
102
|
-
|
|
103
|
-
this._changes.push({
|
|
104
|
-
t: "SUB",
|
|
105
|
-
v: value,
|
|
106
|
-
a: this._author,
|
|
107
|
-
i: ourChanges.length,
|
|
108
|
-
});
|
|
109
|
-
this.calculate();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
1
|
+
import { BaseCrdt, CRDT_LIST } from "..";
|
|
2
|
+
|
|
3
|
+
export type CounterOperations = "ADD" | "SUB";
|
|
4
|
+
|
|
5
|
+
export interface ChangeCounterBase {
|
|
6
|
+
t: CounterOperations; // Operation type
|
|
7
|
+
v: number; // Value
|
|
8
|
+
a: string;
|
|
9
|
+
i: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AddCounterChange extends ChangeCounterBase {
|
|
13
|
+
t: "ADD";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SubCounterChange extends ChangeCounterBase {
|
|
17
|
+
t: "SUB";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type CounterChanges = AddCounterChange | SubCounterChange;
|
|
21
|
+
|
|
22
|
+
export class CounterCrdt<T> extends BaseCrdt<number, CounterChanges, number> {
|
|
23
|
+
public type = CRDT_LIST;
|
|
24
|
+
|
|
25
|
+
public _changes: CounterChanges[] = [];
|
|
26
|
+
|
|
27
|
+
private _author = "";
|
|
28
|
+
|
|
29
|
+
private _value: number = 0;
|
|
30
|
+
|
|
31
|
+
private _lastUpdateSize: number = 0;
|
|
32
|
+
|
|
33
|
+
constructor(author: string, changes?: CounterChanges[]) {
|
|
34
|
+
super();
|
|
35
|
+
this._author = author;
|
|
36
|
+
if (changes) {
|
|
37
|
+
this.mergeChanges(changes);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.calculate();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
changesSort(a: CounterChanges, b: CounterChanges) {
|
|
44
|
+
if (a.i > b.i) return 1;
|
|
45
|
+
if (a.i < b.i) return -1;
|
|
46
|
+
return 0; // Should never be equal!
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
calculate() {
|
|
50
|
+
let temp: number = 0;
|
|
51
|
+
// Only update if we have new changes
|
|
52
|
+
if (Object.values(this._changes).length !== this._lastUpdateSize) {
|
|
53
|
+
this._changes.sort(this.changesSort).forEach((change) => {
|
|
54
|
+
if (change.t === "ADD") {
|
|
55
|
+
temp += change.v;
|
|
56
|
+
} else if (change.t === "SUB") {
|
|
57
|
+
temp -= change.v;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this._value = temp;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get value(): number {
|
|
66
|
+
this.calculate();
|
|
67
|
+
return this._value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public mergeChanges(newChanges: CounterChanges[]) {
|
|
71
|
+
newChanges.forEach((change) => {
|
|
72
|
+
// Filter by author and index
|
|
73
|
+
const filtered = this._changes.filter(
|
|
74
|
+
(c) => c.i === change.i && c.a === change.a && c.t === change.t
|
|
75
|
+
);
|
|
76
|
+
// Only add if there are not matches
|
|
77
|
+
if (filtered.length === 0) {
|
|
78
|
+
this._changes.push(change);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
this.calculate();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public getChanges(): CounterChanges[] {
|
|
85
|
+
return this._changes;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public ADD(value: number) {
|
|
89
|
+
const ourChanges = this._changes.filter((c) => c.a === this._author);
|
|
90
|
+
|
|
91
|
+
this._changes.push({
|
|
92
|
+
t: "ADD",
|
|
93
|
+
v: value,
|
|
94
|
+
a: this._author,
|
|
95
|
+
i: ourChanges.length,
|
|
96
|
+
});
|
|
97
|
+
this.calculate();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public SUB(value: number) {
|
|
101
|
+
const ourChanges = this._changes.filter((c) => c.a === this._author);
|
|
102
|
+
|
|
103
|
+
this._changes.push({
|
|
104
|
+
t: "SUB",
|
|
105
|
+
v: value,
|
|
106
|
+
a: this._author,
|
|
107
|
+
i: ourChanges.length,
|
|
108
|
+
});
|
|
109
|
+
this.calculate();
|
|
110
|
+
}
|
|
111
|
+
}
|
package/lib/crdt/listCrdt.ts
CHANGED
|
@@ -1,190 +1,190 @@
|
|
|
1
|
-
import { BaseCrdt, CRDT_LIST } from "..";
|
|
2
|
-
|
|
3
|
-
export type ListOperations = "INS" | "DEL";
|
|
4
|
-
|
|
5
|
-
export interface ChangeListBase<T> {
|
|
6
|
-
t: ListOperations; // Operation type
|
|
7
|
-
i: string; // "index", author + n
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface InsListChange<T> extends ChangeListBase<T> {
|
|
11
|
-
t: "INS";
|
|
12
|
-
v: T; // Value
|
|
13
|
-
p: string | undefined; // Previous index, if any
|
|
14
|
-
n: string | undefined; // Next index, if any
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface DelListChange<T> extends ChangeListBase<T> {
|
|
18
|
-
t: "DEL";
|
|
19
|
-
v: string; // target index to tombstone
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type ListChanges<T> = InsListChange<T> | DelListChange<T>;
|
|
23
|
-
|
|
24
|
-
interface ListTempCursor<T> {
|
|
25
|
-
value: T;
|
|
26
|
-
index: string;
|
|
27
|
-
tomb: boolean;
|
|
28
|
-
prev: string | undefined;
|
|
29
|
-
next: string | undefined;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class ListCrdt<T> extends BaseCrdt<T, ListChanges<T>, T[]> {
|
|
33
|
-
public type = CRDT_LIST;
|
|
34
|
-
|
|
35
|
-
public _changes: ListChanges<T>[] = [];
|
|
36
|
-
|
|
37
|
-
private _author = "";
|
|
38
|
-
|
|
39
|
-
private _value: T[] = [];
|
|
40
|
-
|
|
41
|
-
public _tempValues: ListTempCursor<T>[] = [];
|
|
42
|
-
|
|
43
|
-
private _lastUpdateSize: number = 0;
|
|
44
|
-
|
|
45
|
-
constructor(author: string, changes?: ListChanges<T>[]) {
|
|
46
|
-
super();
|
|
47
|
-
this._author = author;
|
|
48
|
-
if (changes) {
|
|
49
|
-
this.mergeChanges(changes);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.calculate();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
changesSort(a: ListChanges<T>, b: ListChanges<T>) {
|
|
56
|
-
if (a.i > b.i) return 1;
|
|
57
|
-
if (a.i < b.i) return -1;
|
|
58
|
-
return 0; // Should never be equal!
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
calculate() {
|
|
62
|
-
const temp: ListTempCursor<T>[] = [];
|
|
63
|
-
// Only update if we have new changes
|
|
64
|
-
if (Object.values(this._changes).length !== this._lastUpdateSize) {
|
|
65
|
-
this._changes.sort(this.changesSort).forEach((change) => {
|
|
66
|
-
if (change.t === "INS") {
|
|
67
|
-
let poisitionToInsert = 0;
|
|
68
|
-
if (change.p) {
|
|
69
|
-
poisitionToInsert = temp.findIndex((v) => v.index === change.p) + 1;
|
|
70
|
-
} else if (change.n) {
|
|
71
|
-
poisitionToInsert = temp.findIndex((v) => v.index === change.n);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const cursorValue: ListTempCursor<T> = {
|
|
75
|
-
value: change.v,
|
|
76
|
-
index: change.i,
|
|
77
|
-
tomb: false,
|
|
78
|
-
prev: change.p,
|
|
79
|
-
next: change.n,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
temp.splice(poisitionToInsert, 0, cursorValue);
|
|
83
|
-
} else if (change.t === "DEL") {
|
|
84
|
-
const poisitionToInsert = temp.findIndex((v) => v.index === change.v);
|
|
85
|
-
temp[poisitionToInsert].tomb = true;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
this._lastUpdateSize = Object.values(temp).length;
|
|
89
|
-
|
|
90
|
-
this._tempValues = temp;
|
|
91
|
-
|
|
92
|
-
this._value = temp.filter((v) => !v.tomb).map((v) => v.value);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
get value(): T[] {
|
|
97
|
-
this.calculate();
|
|
98
|
-
return this._value;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public mergeChanges(newChanges: ListChanges<T>[]) {
|
|
102
|
-
newChanges.forEach((change) => {
|
|
103
|
-
// Filter by author and index
|
|
104
|
-
const filtered = this._changes.filter(
|
|
105
|
-
(c) => c.i === change.i && c.t === change.t && c.v === change.v
|
|
106
|
-
);
|
|
107
|
-
// Only add if there are not matches
|
|
108
|
-
if (filtered.length === 0) {
|
|
109
|
-
this._changes.push(change);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
this.calculate();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
public getChanges(): ListChanges<T>[] {
|
|
116
|
-
return this._changes;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
public INS(value: T, index: number) {
|
|
120
|
-
const filterTombs = this._tempValues.filter((v) => !v.tomb);
|
|
121
|
-
|
|
122
|
-
let currentPrev = undefined;
|
|
123
|
-
let currentNext = undefined;
|
|
124
|
-
|
|
125
|
-
if (filterTombs.length !== 0) {
|
|
126
|
-
const currentIndex = filterTombs[index].index;
|
|
127
|
-
const currentIndexPosition = this._tempValues.findIndex(
|
|
128
|
-
(v) => v.index === currentIndex
|
|
129
|
-
);
|
|
130
|
-
currentPrev = this._tempValues[currentIndexPosition - 1];
|
|
131
|
-
currentNext = this._tempValues[currentIndexPosition];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const ourChanges = this._changes.filter((c) =>
|
|
135
|
-
c.i.startsWith(this._author)
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
this._changes.push({
|
|
139
|
-
t: "INS",
|
|
140
|
-
p: currentPrev?.index,
|
|
141
|
-
n: currentNext?.index,
|
|
142
|
-
v: value,
|
|
143
|
-
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
144
|
-
});
|
|
145
|
-
this.calculate();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
public PUSH(value: T) {
|
|
149
|
-
const filterTombs = this._tempValues.filter((v) => !v.tomb);
|
|
150
|
-
const currentIndex = filterTombs[filterTombs.length - 1]?.index;
|
|
151
|
-
const currentIndexPosition = this._tempValues.findIndex(
|
|
152
|
-
(v) => v.index === currentIndex
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
const currentPrev = this._tempValues[currentIndexPosition];
|
|
156
|
-
|
|
157
|
-
const ourChanges = this._changes.filter((c) =>
|
|
158
|
-
c.i.startsWith(this._author)
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
this._changes.push({
|
|
162
|
-
t: "INS",
|
|
163
|
-
p: currentPrev?.index,
|
|
164
|
-
n: undefined,
|
|
165
|
-
v: value,
|
|
166
|
-
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
167
|
-
});
|
|
168
|
-
this.calculate();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
public DEL(index: number) {
|
|
172
|
-
const currentIndex = this._tempValues.filter((v) => !v.tomb)[index].index;
|
|
173
|
-
const currentIndexPosition = this._tempValues.findIndex(
|
|
174
|
-
(v) => v.index === currentIndex
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
const current = this._tempValues[currentIndexPosition];
|
|
178
|
-
|
|
179
|
-
const ourChanges = this._changes.filter((c) =>
|
|
180
|
-
c.i.startsWith(this._author)
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
this._changes.push({
|
|
184
|
-
t: "DEL",
|
|
185
|
-
v: current.index,
|
|
186
|
-
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
187
|
-
});
|
|
188
|
-
this.calculate();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
1
|
+
import { BaseCrdt, CRDT_LIST } from "..";
|
|
2
|
+
|
|
3
|
+
export type ListOperations = "INS" | "DEL";
|
|
4
|
+
|
|
5
|
+
export interface ChangeListBase<T> {
|
|
6
|
+
t: ListOperations; // Operation type
|
|
7
|
+
i: string; // "index", author + n
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface InsListChange<T> extends ChangeListBase<T> {
|
|
11
|
+
t: "INS";
|
|
12
|
+
v: T; // Value
|
|
13
|
+
p: string | undefined; // Previous index, if any
|
|
14
|
+
n: string | undefined; // Next index, if any
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DelListChange<T> extends ChangeListBase<T> {
|
|
18
|
+
t: "DEL";
|
|
19
|
+
v: string; // target index to tombstone
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ListChanges<T> = InsListChange<T> | DelListChange<T>;
|
|
23
|
+
|
|
24
|
+
interface ListTempCursor<T> {
|
|
25
|
+
value: T;
|
|
26
|
+
index: string;
|
|
27
|
+
tomb: boolean;
|
|
28
|
+
prev: string | undefined;
|
|
29
|
+
next: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ListCrdt<T> extends BaseCrdt<T, ListChanges<T>, T[]> {
|
|
33
|
+
public type = CRDT_LIST;
|
|
34
|
+
|
|
35
|
+
public _changes: ListChanges<T>[] = [];
|
|
36
|
+
|
|
37
|
+
private _author = "";
|
|
38
|
+
|
|
39
|
+
private _value: T[] = [];
|
|
40
|
+
|
|
41
|
+
public _tempValues: ListTempCursor<T>[] = [];
|
|
42
|
+
|
|
43
|
+
private _lastUpdateSize: number = 0;
|
|
44
|
+
|
|
45
|
+
constructor(author: string, changes?: ListChanges<T>[]) {
|
|
46
|
+
super();
|
|
47
|
+
this._author = author;
|
|
48
|
+
if (changes) {
|
|
49
|
+
this.mergeChanges(changes);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.calculate();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
changesSort(a: ListChanges<T>, b: ListChanges<T>) {
|
|
56
|
+
if (a.i > b.i) return 1;
|
|
57
|
+
if (a.i < b.i) return -1;
|
|
58
|
+
return 0; // Should never be equal!
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
calculate() {
|
|
62
|
+
const temp: ListTempCursor<T>[] = [];
|
|
63
|
+
// Only update if we have new changes
|
|
64
|
+
if (Object.values(this._changes).length !== this._lastUpdateSize) {
|
|
65
|
+
this._changes.sort(this.changesSort).forEach((change) => {
|
|
66
|
+
if (change.t === "INS") {
|
|
67
|
+
let poisitionToInsert = 0;
|
|
68
|
+
if (change.p) {
|
|
69
|
+
poisitionToInsert = temp.findIndex((v) => v.index === change.p) + 1;
|
|
70
|
+
} else if (change.n) {
|
|
71
|
+
poisitionToInsert = temp.findIndex((v) => v.index === change.n);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const cursorValue: ListTempCursor<T> = {
|
|
75
|
+
value: change.v,
|
|
76
|
+
index: change.i,
|
|
77
|
+
tomb: false,
|
|
78
|
+
prev: change.p,
|
|
79
|
+
next: change.n,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
temp.splice(poisitionToInsert, 0, cursorValue);
|
|
83
|
+
} else if (change.t === "DEL") {
|
|
84
|
+
const poisitionToInsert = temp.findIndex((v) => v.index === change.v);
|
|
85
|
+
temp[poisitionToInsert].tomb = true;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
this._lastUpdateSize = Object.values(temp).length;
|
|
89
|
+
|
|
90
|
+
this._tempValues = temp;
|
|
91
|
+
|
|
92
|
+
this._value = temp.filter((v) => !v.tomb).map((v) => v.value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get value(): T[] {
|
|
97
|
+
this.calculate();
|
|
98
|
+
return this._value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public mergeChanges(newChanges: ListChanges<T>[]) {
|
|
102
|
+
newChanges.forEach((change) => {
|
|
103
|
+
// Filter by author and index
|
|
104
|
+
const filtered = this._changes.filter(
|
|
105
|
+
(c) => c.i === change.i && c.t === change.t && c.v === change.v
|
|
106
|
+
);
|
|
107
|
+
// Only add if there are not matches
|
|
108
|
+
if (filtered.length === 0) {
|
|
109
|
+
this._changes.push(change);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
this.calculate();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public getChanges(): ListChanges<T>[] {
|
|
116
|
+
return this._changes;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public INS(value: T, index: number) {
|
|
120
|
+
const filterTombs = this._tempValues.filter((v) => !v.tomb);
|
|
121
|
+
|
|
122
|
+
let currentPrev = undefined;
|
|
123
|
+
let currentNext = undefined;
|
|
124
|
+
|
|
125
|
+
if (filterTombs.length !== 0) {
|
|
126
|
+
const currentIndex = filterTombs[index].index;
|
|
127
|
+
const currentIndexPosition = this._tempValues.findIndex(
|
|
128
|
+
(v) => v.index === currentIndex
|
|
129
|
+
);
|
|
130
|
+
currentPrev = this._tempValues[currentIndexPosition - 1];
|
|
131
|
+
currentNext = this._tempValues[currentIndexPosition];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const ourChanges = this._changes.filter((c) =>
|
|
135
|
+
c.i.startsWith(this._author)
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
this._changes.push({
|
|
139
|
+
t: "INS",
|
|
140
|
+
p: currentPrev?.index,
|
|
141
|
+
n: currentNext?.index,
|
|
142
|
+
v: value,
|
|
143
|
+
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
144
|
+
});
|
|
145
|
+
this.calculate();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public PUSH(value: T) {
|
|
149
|
+
const filterTombs = this._tempValues.filter((v) => !v.tomb);
|
|
150
|
+
const currentIndex = filterTombs[filterTombs.length - 1]?.index;
|
|
151
|
+
const currentIndexPosition = this._tempValues.findIndex(
|
|
152
|
+
(v) => v.index === currentIndex
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const currentPrev = this._tempValues[currentIndexPosition];
|
|
156
|
+
|
|
157
|
+
const ourChanges = this._changes.filter((c) =>
|
|
158
|
+
c.i.startsWith(this._author)
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
this._changes.push({
|
|
162
|
+
t: "INS",
|
|
163
|
+
p: currentPrev?.index,
|
|
164
|
+
n: undefined,
|
|
165
|
+
v: value,
|
|
166
|
+
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
167
|
+
});
|
|
168
|
+
this.calculate();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public DEL(index: number) {
|
|
172
|
+
const currentIndex = this._tempValues.filter((v) => !v.tomb)[index].index;
|
|
173
|
+
const currentIndexPosition = this._tempValues.findIndex(
|
|
174
|
+
(v) => v.index === currentIndex
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const current = this._tempValues[currentIndexPosition];
|
|
178
|
+
|
|
179
|
+
const ourChanges = this._changes.filter((c) =>
|
|
180
|
+
c.i.startsWith(this._author)
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
this._changes.push({
|
|
184
|
+
t: "DEL",
|
|
185
|
+
v: current.index,
|
|
186
|
+
i: this._author + "-" + `${ourChanges.length}`.padStart(8, "0"),
|
|
187
|
+
});
|
|
188
|
+
this.calculate();
|
|
189
|
+
}
|
|
190
|
+
}
|