cojson 0.18.26 → 0.18.27
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +7 -0
- package/dist/PeerKnownStates.d.ts +4 -3
- package/dist/PeerKnownStates.d.ts.map +1 -1
- package/dist/PeerKnownStates.js +27 -18
- package/dist/PeerKnownStates.js.map +1 -1
- package/dist/PeerState.d.ts +3 -2
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js.map +1 -1
- package/dist/SyncStateManager.d.ts +2 -2
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +2 -10
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +1 -1
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +1 -1
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +6 -3
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +41 -8
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/branching.d.ts +3 -3
- package/dist/coValueCore/branching.d.ts.map +1 -1
- package/dist/coValueCore/branching.js +2 -2
- package/dist/coValueCore/branching.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +3 -2
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +2 -3
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +12 -6
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +28 -56
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coMap.d.ts.map +1 -1
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts.map +1 -1
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/exports.d.ts +3 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +2 -1
- package/dist/exports.js.map +1 -1
- package/dist/knownState.d.ts +58 -2
- package/dist/knownState.d.ts.map +1 -1
- package/dist/knownState.js +79 -5
- package/dist/knownState.js.map +1 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js.map +1 -1
- package/dist/storage/knownState.d.ts +1 -1
- package/dist/storage/knownState.d.ts.map +1 -1
- package/dist/storage/knownState.js +2 -3
- package/dist/storage/knownState.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +2 -1
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +5 -6
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +2 -1
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +5 -5
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +2 -1
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts +2 -12
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +7 -36
- package/dist/sync.js.map +1 -1
- package/dist/tests/PeerKnownStates.test.js +1 -1
- package/dist/tests/PeerKnownStates.test.js.map +1 -1
- package/dist/tests/PeerState.test.js +19 -0
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/PureJSCrypto.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +1 -1
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +1 -2
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/StoreQueue.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +1 -1
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coValueContentMessage.test.js +1 -1
- package/dist/tests/coValueContentMessage.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +28 -0
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/knownState.test.d.ts +2 -0
- package/dist/tests/knownState.test.d.ts.map +1 -0
- package/dist/tests/knownState.test.js +510 -0
- package/dist/tests/knownState.test.js.map +1 -0
- package/dist/tests/messagesTestUtils.d.ts.map +1 -1
- package/dist/tests/messagesTestUtils.js.map +1 -1
- package/dist/tests/priority.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/PeerKnownStates.ts +36 -22
- package/src/PeerState.ts +2 -1
- package/src/SyncStateManager.ts +4 -17
- package/src/coValueContentMessage.ts +2 -1
- package/src/coValueCore/SessionMap.ts +66 -11
- package/src/coValueCore/branching.ts +9 -10
- package/src/coValueCore/coValueCore.ts +9 -10
- package/src/coValueCore/verifiedState.ts +32 -64
- package/src/coValues/coMap.ts +1 -5
- package/src/coValues/coStream.ts +1 -5
- package/src/exports.ts +2 -2
- package/src/knownState.ts +118 -12
- package/src/permissions.ts +0 -3
- package/src/storage/knownState.ts +9 -3
- package/src/storage/storageAsync.ts +15 -7
- package/src/storage/storageSync.ts +16 -8
- package/src/storage/types.ts +2 -1
- package/src/sync.ts +12 -58
- package/src/tests/PeerKnownStates.test.ts +1 -1
- package/src/tests/PeerState.test.ts +29 -3
- package/src/tests/PureJSCrypto.test.ts +0 -1
- package/src/tests/StorageApiAsync.test.ts +3 -6
- package/src/tests/StorageApiSync.test.ts +2 -6
- package/src/tests/StoreQueue.test.ts +3 -2
- package/src/tests/SyncStateManager.test.ts +1 -1
- package/src/tests/coValueContentMessage.test.ts +2 -2
- package/src/tests/coValueCore.test.ts +38 -0
- package/src/tests/knownState.test.ts +665 -0
- package/src/tests/messagesTestUtils.ts +2 -1
- package/src/tests/priority.test.ts +0 -2
- package/src/tests/sync.storage.test.ts +0 -1
- package/src/tests/sync.upload.test.ts +0 -1
- package/src/tests/testUtils.ts +1 -2
|
@@ -17,11 +17,11 @@ import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
|
17
17
|
import { Stringified } from "../jsonStringify.js";
|
|
18
18
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
19
19
|
import { PermissionsDef as RulesetDef } from "../permissions.js";
|
|
20
|
-
import {
|
|
20
|
+
import { NewContentMessage } from "../sync.js";
|
|
21
21
|
import { TryAddTransactionsError } from "./coValueCore.js";
|
|
22
22
|
import { SessionLog, SessionMap } from "./SessionMap.js";
|
|
23
23
|
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
24
|
-
import {
|
|
24
|
+
import { cloneKnownState, CoValueKnownState } from "../knownState.js";
|
|
25
25
|
|
|
26
26
|
export type CoValueHeader = {
|
|
27
27
|
type: AnyRawCoValue["type"];
|
|
@@ -56,8 +56,8 @@ export class VerifiedState {
|
|
|
56
56
|
readonly header: CoValueHeader;
|
|
57
57
|
readonly sessions: SessionMap;
|
|
58
58
|
private _cachedKnownState?: CoValueKnownState;
|
|
59
|
+
private _cachedKnownStateWithStreaming?: CoValueKnownState;
|
|
59
60
|
private _cachedNewContentSinceEmpty: NewContentMessage[] | undefined;
|
|
60
|
-
private streamingKnownState?: CoValueKnownState["sessions"];
|
|
61
61
|
public lastAccessed: number | undefined;
|
|
62
62
|
public branchSourceId?: RawCoID;
|
|
63
63
|
public branchName?: string;
|
|
@@ -67,15 +67,11 @@ export class VerifiedState {
|
|
|
67
67
|
crypto: CryptoProvider,
|
|
68
68
|
header: CoValueHeader,
|
|
69
69
|
sessions?: SessionMap,
|
|
70
|
-
streamingKnownState?: CoValueKnownState["sessions"],
|
|
71
70
|
) {
|
|
72
71
|
this.id = id;
|
|
73
72
|
this.crypto = crypto;
|
|
74
73
|
this.header = header;
|
|
75
74
|
this.sessions = sessions ?? new SessionMap(id, crypto);
|
|
76
|
-
this.streamingKnownState = streamingKnownState
|
|
77
|
-
? { ...streamingKnownState }
|
|
78
|
-
: undefined;
|
|
79
75
|
this.branchSourceId = header.meta?.source as RawCoID | undefined;
|
|
80
76
|
this.branchName = header.meta?.branch as string | undefined;
|
|
81
77
|
}
|
|
@@ -86,7 +82,6 @@ export class VerifiedState {
|
|
|
86
82
|
this.crypto,
|
|
87
83
|
this.header,
|
|
88
84
|
this.sessions.clone(),
|
|
89
|
-
this.streamingKnownState ? { ...this.streamingKnownState } : undefined,
|
|
90
85
|
);
|
|
91
86
|
}
|
|
92
87
|
|
|
@@ -108,6 +103,7 @@ export class VerifiedState {
|
|
|
108
103
|
if (result.isOk()) {
|
|
109
104
|
this._cachedNewContentSinceEmpty = undefined;
|
|
110
105
|
this._cachedKnownState = undefined;
|
|
106
|
+
this._cachedKnownStateWithStreaming = undefined;
|
|
111
107
|
}
|
|
112
108
|
|
|
113
109
|
return result;
|
|
@@ -130,6 +126,7 @@ export class VerifiedState {
|
|
|
130
126
|
|
|
131
127
|
this._cachedNewContentSinceEmpty = undefined;
|
|
132
128
|
this._cachedKnownState = undefined;
|
|
129
|
+
this._cachedKnownStateWithStreaming = undefined;
|
|
133
130
|
|
|
134
131
|
return result;
|
|
135
132
|
}
|
|
@@ -155,6 +152,7 @@ export class VerifiedState {
|
|
|
155
152
|
|
|
156
153
|
this._cachedNewContentSinceEmpty = undefined;
|
|
157
154
|
this._cachedKnownState = undefined;
|
|
155
|
+
this._cachedKnownStateWithStreaming = undefined;
|
|
158
156
|
|
|
159
157
|
return result;
|
|
160
158
|
}
|
|
@@ -289,72 +287,42 @@ export class VerifiedState {
|
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
/**
|
|
292
|
-
* Returns the known state
|
|
290
|
+
* Returns the known state of the CoValue
|
|
293
291
|
*
|
|
294
|
-
*
|
|
292
|
+
* The return value identity is going to be stable as long as the CoValue is not modified.
|
|
293
|
+
*
|
|
294
|
+
* On change the knownState is invalidated and a new object is returned.
|
|
295
295
|
*/
|
|
296
|
-
|
|
297
|
-
const knownState = this.knownState();
|
|
298
|
-
|
|
299
|
-
if (this.streamingKnownState) {
|
|
300
|
-
const newSessions: CoValueKnownState["sessions"] = {};
|
|
301
|
-
const entries = Object.entries(this.streamingKnownState);
|
|
302
|
-
|
|
303
|
-
for (const [sessionID, txs] of entries) {
|
|
304
|
-
newSessions[sessionID as SessionID] = txs;
|
|
305
|
-
if ((knownState.sessions[sessionID as SessionID] ?? 0) < txs) {
|
|
306
|
-
newSessions[sessionID as SessionID] = txs;
|
|
307
|
-
} else {
|
|
308
|
-
newSessions[sessionID as SessionID] = txs;
|
|
309
|
-
delete this.streamingKnownState[sessionID as SessionID];
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (Object.keys(this.streamingKnownState).length === 0) {
|
|
314
|
-
this.streamingKnownState = undefined;
|
|
315
|
-
return knownState;
|
|
316
|
-
} else {
|
|
317
|
-
return {
|
|
318
|
-
id: knownState.id,
|
|
319
|
-
header: knownState.header,
|
|
320
|
-
sessions: newSessions,
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return knownState;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
isStreaming(): boolean {
|
|
329
|
-
// Call knownStateWithStreaming to delete the streamingKnownState when it matches the current knownState
|
|
330
|
-
this.knownStateWithStreaming();
|
|
331
|
-
|
|
332
|
-
return this.streamingKnownState !== undefined;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
knownState(): CoValueKnownState {
|
|
296
|
+
knownState() {
|
|
336
297
|
if (this._cachedKnownState) {
|
|
337
298
|
return this._cachedKnownState;
|
|
338
|
-
} else {
|
|
339
|
-
const knownState = this.knownStateUncached();
|
|
340
|
-
this._cachedKnownState = knownState;
|
|
341
|
-
return knownState;
|
|
342
299
|
}
|
|
300
|
+
this._cachedKnownState = cloneKnownState(this.sessions.knownState);
|
|
301
|
+
return this._cachedKnownState;
|
|
343
302
|
}
|
|
344
303
|
|
|
345
|
-
/**
|
|
346
|
-
|
|
347
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Returns the known state considering the known state of the streaming source
|
|
306
|
+
*
|
|
307
|
+
* Used to correctly manage the content & subscriptions during the content streaming process
|
|
308
|
+
*/
|
|
309
|
+
knownStateWithStreaming() {
|
|
310
|
+
if (!this.sessions.knownStateWithStreaming) {
|
|
311
|
+
return this.knownState();
|
|
312
|
+
}
|
|
348
313
|
|
|
349
|
-
|
|
350
|
-
|
|
314
|
+
if (this._cachedKnownStateWithStreaming) {
|
|
315
|
+
return this._cachedKnownStateWithStreaming;
|
|
351
316
|
}
|
|
317
|
+
this._cachedKnownStateWithStreaming = cloneKnownState(
|
|
318
|
+
this.sessions.knownStateWithStreaming,
|
|
319
|
+
);
|
|
352
320
|
|
|
353
|
-
return
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
321
|
+
return this._cachedKnownStateWithStreaming;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
isStreaming(): boolean {
|
|
325
|
+
return Boolean(this.sessions.knownStateWithStreaming);
|
|
358
326
|
}
|
|
359
327
|
|
|
360
328
|
decryptTransaction(
|
package/src/coValues/coMap.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { CoID, RawCoValue } from "../coValue.js";
|
|
2
|
-
import {
|
|
3
|
-
AvailableCoValueCore,
|
|
4
|
-
CoValueCore,
|
|
5
|
-
} from "../coValueCore/coValueCore.js";
|
|
2
|
+
import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
|
|
6
3
|
import { AgentID, TransactionID } from "../ids.js";
|
|
7
4
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
8
|
-
import { CoValueKnownState } from "../sync.js";
|
|
9
5
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
10
6
|
import { isCoValue } from "../typeUtils/isCoValue.js";
|
|
11
7
|
import { RawAccountID } from "./account.js";
|
package/src/coValues/coStream.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
|
|
2
2
|
import { CoID, RawCoValue } from "../coValue.js";
|
|
3
|
-
import {
|
|
4
|
-
AvailableCoValueCore,
|
|
5
|
-
CoValueCore,
|
|
6
|
-
} from "../coValueCore/coValueCore.js";
|
|
3
|
+
import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
|
|
7
4
|
import { AgentID, SessionID, TransactionID } from "../ids.js";
|
|
8
5
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
9
6
|
import { logger } from "../logger.js";
|
|
10
|
-
import { CoValueKnownState } from "../sync.js";
|
|
11
7
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
12
8
|
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
13
9
|
import { isCoValue } from "../typeUtils/isCoValue.js";
|
package/src/exports.ts
CHANGED
|
@@ -65,9 +65,9 @@ import type { Peer, SyncMessage } from "./sync.js";
|
|
|
65
65
|
import {
|
|
66
66
|
DisconnectedError,
|
|
67
67
|
SyncManager,
|
|
68
|
-
emptyKnownState,
|
|
69
68
|
hwrServerPeerSelector,
|
|
70
69
|
} from "./sync.js";
|
|
70
|
+
import { emptyKnownState } from "./knownState.js";
|
|
71
71
|
|
|
72
72
|
import {
|
|
73
73
|
getContentMessageSize,
|
|
@@ -189,7 +189,7 @@ export * from "./storage/index.js";
|
|
|
189
189
|
// biome-ignore format: off
|
|
190
190
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
191
191
|
export namespace CojsonInternalTypes {
|
|
192
|
-
export type CoValueKnownState = import("./
|
|
192
|
+
export type CoValueKnownState = import("./knownState.js").CoValueKnownState;
|
|
193
193
|
export type CoJsonValue<T> = import("./jsonValue.js").CoJsonValue<T>;
|
|
194
194
|
export type DoneMessage = import("./sync.js").DoneMessage;
|
|
195
195
|
export type Encrypted<T extends JsonValue, N extends JsonValue> = import("./crypto/crypto.js").Encrypted<T, N>;
|
package/src/knownState.ts
CHANGED
|
@@ -1,17 +1,123 @@
|
|
|
1
|
-
import type { SessionID } from "./exports.js";
|
|
2
|
-
import type { CoValueKnownState } from "./sync.js";
|
|
1
|
+
import type { RawCoID, SessionID } from "./exports.js";
|
|
3
2
|
|
|
3
|
+
export type KnownStateSessions = { [sessionID: SessionID]: number };
|
|
4
|
+
|
|
5
|
+
export type CoValueKnownState = {
|
|
6
|
+
id: RawCoID;
|
|
7
|
+
header: boolean;
|
|
8
|
+
sessions: KnownStateSessions;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns an empty known state for a CoValue, with no header and empty sessions.
|
|
13
|
+
*/
|
|
14
|
+
export function emptyKnownState(id: RawCoID): CoValueKnownState {
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
header: false,
|
|
18
|
+
sessions: {},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Picks the knownState properties from the input object
|
|
24
|
+
*/
|
|
25
|
+
export function knownStateFrom(input: CoValueKnownState) {
|
|
26
|
+
return {
|
|
27
|
+
id: input.id,
|
|
28
|
+
header: input.header,
|
|
29
|
+
sessions: input.sessions,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mutate the target known state by combining the sessions from the source.
|
|
35
|
+
*
|
|
36
|
+
* The function assigns the sessions to the target only when the value in the source is greater.
|
|
37
|
+
*/
|
|
38
|
+
export function combineKnownStates(
|
|
39
|
+
target: CoValueKnownState,
|
|
40
|
+
source: CoValueKnownState,
|
|
41
|
+
): CoValueKnownState {
|
|
42
|
+
combineKnownStateSessions(target.sessions, source.sessions);
|
|
43
|
+
|
|
44
|
+
if (source.header && !target.header) {
|
|
45
|
+
target.header = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return target;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Mutate the target sessions counter by combining the entries from the source.
|
|
53
|
+
*
|
|
54
|
+
* The function assigns the sessions to the target only when the value in the source is greater.
|
|
55
|
+
*/
|
|
4
56
|
export function combineKnownStateSessions(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
)
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
57
|
+
target: KnownStateSessions,
|
|
58
|
+
source: KnownStateSessions,
|
|
59
|
+
) {
|
|
60
|
+
for (const [sessionID, count] of Object.entries(source) as [
|
|
61
|
+
SessionID,
|
|
62
|
+
number,
|
|
63
|
+
][]) {
|
|
64
|
+
const currentCount = target[sessionID] || 0;
|
|
65
|
+
|
|
66
|
+
if (count > currentCount) {
|
|
67
|
+
target[sessionID] = count;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return target;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Set the session counter for a sessionId in the known state.
|
|
76
|
+
*/
|
|
77
|
+
export function setSessionCounter(
|
|
78
|
+
knownState: KnownStateSessions,
|
|
79
|
+
sessionId: SessionID,
|
|
80
|
+
value: number,
|
|
81
|
+
) {
|
|
82
|
+
knownState[sessionId] = value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Update the session counter for a sessionId in the known state.
|
|
87
|
+
*
|
|
88
|
+
* The function assigns the value to the target only when the value in the knownState is less than the provided value.
|
|
89
|
+
*/
|
|
90
|
+
export function updateSessionCounter(
|
|
91
|
+
knownState: KnownStateSessions,
|
|
92
|
+
sessionId: SessionID,
|
|
93
|
+
value: number,
|
|
94
|
+
) {
|
|
95
|
+
knownState[sessionId] = Math.max(knownState[sessionId] || 0, value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Efficient cloning of a known state.
|
|
100
|
+
*/
|
|
101
|
+
export function cloneKnownState(knownState: CoValueKnownState) {
|
|
102
|
+
return {
|
|
103
|
+
id: knownState.id,
|
|
104
|
+
header: knownState.header,
|
|
105
|
+
sessions: { ...knownState.sessions },
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Checks if all the local sessions have the same counters as in remote.
|
|
111
|
+
*/
|
|
112
|
+
export function areLocalSessionsUploaded(
|
|
113
|
+
local: Record<string, number>,
|
|
114
|
+
remote: Record<string, number>,
|
|
115
|
+
) {
|
|
116
|
+
for (const sessionId of Object.keys(local)) {
|
|
117
|
+
if (local[sessionId] !== remote[sessionId]) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
14
120
|
}
|
|
15
121
|
|
|
16
|
-
return
|
|
122
|
+
return true;
|
|
17
123
|
}
|
package/src/permissions.ts
CHANGED
|
@@ -15,15 +15,12 @@ import {
|
|
|
15
15
|
AgentID,
|
|
16
16
|
ParentGroupReference,
|
|
17
17
|
RawCoID,
|
|
18
|
-
SessionID,
|
|
19
18
|
TransactionID,
|
|
20
19
|
getParentGroupId,
|
|
21
20
|
} from "./ids.js";
|
|
22
21
|
import { parseJSON } from "./jsonStringify.js";
|
|
23
22
|
import { JsonValue } from "./jsonValue.js";
|
|
24
23
|
import { logger } from "./logger.js";
|
|
25
|
-
import { CoValueKnownState } from "./sync.js";
|
|
26
|
-
import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
|
|
27
24
|
import { expectGroup } from "./typeUtils/expectGroup.js";
|
|
28
25
|
|
|
29
26
|
export type PermissionsDef =
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { getIsUploaded } from "../SyncStateManager.js";
|
|
2
1
|
import { type CoValueCore } from "../exports.js";
|
|
3
2
|
import { RawCoID } from "../ids.js";
|
|
4
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CoValueKnownState,
|
|
5
|
+
emptyKnownState,
|
|
6
|
+
areLocalSessionsUploaded,
|
|
7
|
+
} from "../knownState.js";
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Track how much data we have stored inside our storage
|
|
@@ -84,5 +87,8 @@ function isInSync(
|
|
|
84
87
|
return false;
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
return
|
|
90
|
+
return areLocalSessionsUploaded(
|
|
91
|
+
knownState.sessions,
|
|
92
|
+
knownStateFromStorage.sessions,
|
|
93
|
+
);
|
|
88
94
|
}
|
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
logger,
|
|
11
11
|
} from "../exports.js";
|
|
12
12
|
import { StoreQueue } from "../queue/StoreQueue.js";
|
|
13
|
+
import { NewContentMessage } from "../sync.js";
|
|
13
14
|
import {
|
|
14
15
|
CoValueKnownState,
|
|
15
|
-
NewContentMessage,
|
|
16
16
|
emptyKnownState,
|
|
17
|
-
|
|
17
|
+
setSessionCounter,
|
|
18
|
+
} from "../knownState.js";
|
|
18
19
|
import { StorageKnownState } from "./knownState.js";
|
|
19
20
|
import {
|
|
20
21
|
collectNewTxs,
|
|
@@ -93,7 +94,11 @@ export class StorageApiAsync implements StorageAPI {
|
|
|
93
94
|
knownState.header = true;
|
|
94
95
|
|
|
95
96
|
for (const sessionRow of allCoValueSessions) {
|
|
96
|
-
|
|
97
|
+
setSessionCounter(
|
|
98
|
+
knownState.sessions,
|
|
99
|
+
sessionRow.sessionID,
|
|
100
|
+
sessionRow.lastIdx,
|
|
101
|
+
);
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
this.loadedCoValues.add(coValueRow.id);
|
|
@@ -101,7 +106,7 @@ export class StorageApiAsync implements StorageAPI {
|
|
|
101
106
|
let contentMessage = createContentMessage(coValueRow.id, coValueRow.header);
|
|
102
107
|
|
|
103
108
|
if (contentStreaming) {
|
|
104
|
-
contentMessage.expectContentUntil = knownState
|
|
109
|
+
contentMessage.expectContentUntil = knownState.sessions;
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
for (const sessionRow of allCoValueSessions) {
|
|
@@ -282,14 +287,17 @@ export class StorageApiAsync implements StorageAPI {
|
|
|
282
287
|
);
|
|
283
288
|
|
|
284
289
|
if (sessionRow) {
|
|
285
|
-
|
|
290
|
+
setSessionCounter(
|
|
291
|
+
knownState.sessions,
|
|
292
|
+
sessionRow.sessionID,
|
|
293
|
+
sessionRow.lastIdx,
|
|
294
|
+
);
|
|
286
295
|
}
|
|
287
296
|
|
|
288
297
|
const lastIdx = sessionRow?.lastIdx || 0;
|
|
289
298
|
const after = msg.new[sessionID]?.after || 0;
|
|
290
299
|
|
|
291
300
|
if (lastIdx < after) {
|
|
292
|
-
knownState.sessions[sessionID] = lastIdx;
|
|
293
301
|
invalidAssumptions = true;
|
|
294
302
|
} else {
|
|
295
303
|
const newLastIdx = await this.putNewTxs(
|
|
@@ -298,7 +306,7 @@ export class StorageApiAsync implements StorageAPI {
|
|
|
298
306
|
sessionRow,
|
|
299
307
|
storedCoValueRowID,
|
|
300
308
|
);
|
|
301
|
-
knownState.sessions
|
|
309
|
+
setSessionCounter(knownState.sessions, sessionID, newLastIdx);
|
|
302
310
|
}
|
|
303
311
|
});
|
|
304
312
|
}
|
|
@@ -2,7 +2,6 @@ import { UpDownCounter, metrics } from "@opentelemetry/api";
|
|
|
2
2
|
import {
|
|
3
3
|
createContentMessage,
|
|
4
4
|
exceedsRecommendedSize,
|
|
5
|
-
getTransactionSize,
|
|
6
5
|
} from "../coValueContentMessage.js";
|
|
7
6
|
import {
|
|
8
7
|
CoValueCore,
|
|
@@ -11,12 +10,13 @@ import {
|
|
|
11
10
|
type StorageAPI,
|
|
12
11
|
logger,
|
|
13
12
|
} from "../exports.js";
|
|
13
|
+
import { NewContentMessage } from "../sync.js";
|
|
14
|
+
import { StorageKnownState } from "./knownState.js";
|
|
14
15
|
import {
|
|
15
16
|
CoValueKnownState,
|
|
16
|
-
NewContentMessage,
|
|
17
17
|
emptyKnownState,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
setSessionCounter,
|
|
19
|
+
} from "../knownState.js";
|
|
20
20
|
import {
|
|
21
21
|
collectNewTxs,
|
|
22
22
|
getDependedOnCoValues,
|
|
@@ -96,7 +96,11 @@ export class StorageApiSync implements StorageAPI {
|
|
|
96
96
|
knownState.header = true;
|
|
97
97
|
|
|
98
98
|
for (const sessionRow of allCoValueSessions) {
|
|
99
|
-
|
|
99
|
+
setSessionCounter(
|
|
100
|
+
knownState.sessions,
|
|
101
|
+
sessionRow.sessionID,
|
|
102
|
+
sessionRow.lastIdx,
|
|
103
|
+
);
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
this.loadedCoValues.add(coValueRow.id);
|
|
@@ -105,7 +109,7 @@ export class StorageApiSync implements StorageAPI {
|
|
|
105
109
|
|
|
106
110
|
if (contentStreaming) {
|
|
107
111
|
this.streamingCounter.add(1);
|
|
108
|
-
contentMessage.expectContentUntil = knownState
|
|
112
|
+
contentMessage.expectContentUntil = knownState.sessions;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
for (const sessionRow of allCoValueSessions) {
|
|
@@ -260,7 +264,11 @@ export class StorageApiSync implements StorageAPI {
|
|
|
260
264
|
);
|
|
261
265
|
|
|
262
266
|
if (sessionRow) {
|
|
263
|
-
|
|
267
|
+
setSessionCounter(
|
|
268
|
+
knownState.sessions,
|
|
269
|
+
sessionRow.sessionID,
|
|
270
|
+
sessionRow.lastIdx,
|
|
271
|
+
);
|
|
264
272
|
}
|
|
265
273
|
|
|
266
274
|
if ((sessionRow?.lastIdx || 0) < (msg.new[sessionID]?.after || 0)) {
|
|
@@ -272,7 +280,7 @@ export class StorageApiSync implements StorageAPI {
|
|
|
272
280
|
sessionRow,
|
|
273
281
|
storedCoValueRowID,
|
|
274
282
|
);
|
|
275
|
-
knownState.sessions
|
|
283
|
+
setSessionCounter(knownState.sessions, sessionID, newLastIdx);
|
|
276
284
|
}
|
|
277
285
|
});
|
|
278
286
|
}
|
package/src/storage/types.ts
CHANGED
|
@@ -4,7 +4,8 @@ import type {
|
|
|
4
4
|
} from "../coValueCore/verifiedState.js";
|
|
5
5
|
import { Signature } from "../crypto/crypto.js";
|
|
6
6
|
import type { CoValueCore, RawCoID, SessionID } from "../exports.js";
|
|
7
|
-
import {
|
|
7
|
+
import { NewContentMessage } from "../sync.js";
|
|
8
|
+
import { CoValueKnownState } from "../knownState.js";
|
|
8
9
|
|
|
9
10
|
export type CorrectionCallback = (
|
|
10
11
|
correction: CoValueKnownState,
|
package/src/sync.ts
CHANGED
|
@@ -16,20 +16,11 @@ import { logger } from "./logger.js";
|
|
|
16
16
|
import { CoValuePriority } from "./priority.js";
|
|
17
17
|
import { IncomingMessagesQueue } from "./queue/IncomingMessagesQueue.js";
|
|
18
18
|
import { LocalTransactionsSyncQueue } from "./queue/LocalTransactionsSyncQueue.js";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export function emptyKnownState(id: RawCoID): CoValueKnownState {
|
|
27
|
-
return {
|
|
28
|
-
id,
|
|
29
|
-
header: false,
|
|
30
|
-
sessions: {},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
19
|
+
import {
|
|
20
|
+
CoValueKnownState,
|
|
21
|
+
knownStateFrom,
|
|
22
|
+
KnownStateSessions,
|
|
23
|
+
} from "./knownState.js";
|
|
33
24
|
|
|
34
25
|
export type SyncMessage =
|
|
35
26
|
| LoadMessage
|
|
@@ -55,9 +46,7 @@ export type NewContentMessage = {
|
|
|
55
46
|
new: {
|
|
56
47
|
[sessionID: SessionID]: SessionNewContent;
|
|
57
48
|
};
|
|
58
|
-
expectContentUntil?:
|
|
59
|
-
[sessionID: SessionID]: number;
|
|
60
|
-
};
|
|
49
|
+
expectContentUntil?: KnownStateSessions;
|
|
61
50
|
};
|
|
62
51
|
|
|
63
52
|
export type SessionNewContent = {
|
|
@@ -97,31 +86,6 @@ export interface Peer {
|
|
|
97
86
|
persistent?: boolean;
|
|
98
87
|
}
|
|
99
88
|
|
|
100
|
-
export function combinedKnownStates(
|
|
101
|
-
stateA: CoValueKnownState,
|
|
102
|
-
stateB: CoValueKnownState,
|
|
103
|
-
): CoValueKnownState {
|
|
104
|
-
const sessionStates: CoValueKnownState["sessions"] = {};
|
|
105
|
-
|
|
106
|
-
const allSessions = new Set([
|
|
107
|
-
...Object.keys(stateA.sessions),
|
|
108
|
-
...Object.keys(stateB.sessions),
|
|
109
|
-
] as SessionID[]);
|
|
110
|
-
|
|
111
|
-
for (const sessionID of allSessions) {
|
|
112
|
-
const stateAValue = stateA.sessions[sessionID];
|
|
113
|
-
const stateBValue = stateB.sessions[sessionID];
|
|
114
|
-
|
|
115
|
-
sessionStates[sessionID] = Math.max(stateAValue || 0, stateBValue || 0);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
id: stateA.id,
|
|
120
|
-
header: stateA.header || stateB.header,
|
|
121
|
-
sessions: sessionStates,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
89
|
export type ServerPeerSelector = (
|
|
126
90
|
id: RawCoID,
|
|
127
91
|
serverPeers: PeerState[],
|
|
@@ -446,7 +410,7 @@ export class SyncManager {
|
|
|
446
410
|
* This way we can track part of the data loss that may occur when the other peer is restarted
|
|
447
411
|
*
|
|
448
412
|
*/
|
|
449
|
-
peer.setKnownState(msg.id,
|
|
413
|
+
peer.setKnownState(msg.id, knownStateFrom(msg));
|
|
450
414
|
const coValue = this.local.getCoValue(msg.id);
|
|
451
415
|
|
|
452
416
|
if (coValue.isAvailable()) {
|
|
@@ -482,7 +446,7 @@ export class SyncManager {
|
|
|
482
446
|
handleKnownState(msg: KnownStateMessage, peer: PeerState) {
|
|
483
447
|
const coValue = this.local.getCoValue(msg.id);
|
|
484
448
|
|
|
485
|
-
peer.combineWith(msg.id,
|
|
449
|
+
peer.combineWith(msg.id, knownStateFrom(msg));
|
|
486
450
|
|
|
487
451
|
// The header is a boolean value that tells us if the other peer do have information about the header.
|
|
488
452
|
// If it's false in this point it means that the coValue is unavailable on the other peer.
|
|
@@ -706,12 +670,10 @@ export class SyncManager {
|
|
|
706
670
|
contentToStore.new[sessionID] = newContentForSession;
|
|
707
671
|
}
|
|
708
672
|
|
|
709
|
-
|
|
710
|
-
msg.id,
|
|
711
|
-
sessionID,
|
|
673
|
+
const transactionsCount =
|
|
712
674
|
newContentForSession.after +
|
|
713
|
-
|
|
714
|
-
);
|
|
675
|
+
newContentForSession.newTransactions.length;
|
|
676
|
+
peer?.updateSessionCounter(msg.id, sessionID, transactionsCount);
|
|
715
677
|
}
|
|
716
678
|
|
|
717
679
|
/**
|
|
@@ -804,7 +766,7 @@ export class SyncManager {
|
|
|
804
766
|
}
|
|
805
767
|
|
|
806
768
|
handleCorrection(msg: KnownStateMessage, peer: PeerState) {
|
|
807
|
-
peer.setKnownState(msg.id,
|
|
769
|
+
peer.setKnownState(msg.id, knownStateFrom(msg));
|
|
808
770
|
|
|
809
771
|
return this.sendNewContent(msg.id, peer);
|
|
810
772
|
}
|
|
@@ -952,14 +914,6 @@ export class SyncManager {
|
|
|
952
914
|
}
|
|
953
915
|
}
|
|
954
916
|
|
|
955
|
-
function knownStateIn(msg: LoadMessage | KnownStateMessage) {
|
|
956
|
-
return {
|
|
957
|
-
id: msg.id,
|
|
958
|
-
header: msg.header,
|
|
959
|
-
sessions: msg.sessions,
|
|
960
|
-
};
|
|
961
|
-
}
|
|
962
|
-
|
|
963
917
|
/**
|
|
964
918
|
* Returns a ServerPeerSelector that implements the Highest Weighted Random (HWR) algorithm.
|
|
965
919
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test, vi } from "vitest";
|
|
2
2
|
import { PeerKnownStates } from "../PeerKnownStates.js";
|
|
3
3
|
import { RawCoID, SessionID } from "../ids.js";
|
|
4
|
-
import { CoValueKnownState, emptyKnownState } from "../
|
|
4
|
+
import { CoValueKnownState, emptyKnownState } from "../knownState.js";
|
|
5
5
|
|
|
6
6
|
describe("PeerKnownStates", () => {
|
|
7
7
|
test("should set and get a known state", () => {
|