cojson 0.16.4 → 0.16.6
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 +23 -0
- package/dist/GarbageCollector.d.ts +12 -0
- package/dist/GarbageCollector.d.ts.map +1 -0
- package/dist/GarbageCollector.js +37 -0
- package/dist/GarbageCollector.js.map +1 -0
- package/dist/coValue.d.ts +1 -1
- package/dist/coValue.d.ts.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +1 -0
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +11 -3
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +8 -11
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +30 -122
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/utils.d.ts.map +1 -1
- package/dist/coValueCore/utils.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +1 -0
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coMap.d.ts +3 -3
- package/dist/coValues/coPlainText.d.ts +1 -0
- package/dist/coValues/coPlainText.d.ts.map +1 -1
- package/dist/coValues/coPlainText.js +27 -8
- package/dist/coValues/coPlainText.js.map +1 -1
- package/dist/coValues/coStream.d.ts +2 -2
- package/dist/coValues/group.d.ts +19 -11
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +221 -59
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +10 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -1
- package/dist/config.js.map +1 -1
- package/dist/exports.d.ts +11 -4
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +8 -3
- package/dist/exports.js.map +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/localNode.d.ts +8 -5
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +11 -0
- package/dist/localNode.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.js +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
- package/dist/queue/StoreQueue.d.ts +7 -1
- package/dist/queue/StoreQueue.d.ts.map +1 -1
- package/dist/queue/StoreQueue.js +35 -13
- package/dist/queue/StoreQueue.js.map +1 -1
- package/dist/storage/sqlite/client.d.ts +4 -4
- package/dist/storage/sqlite/client.d.ts.map +1 -1
- package/dist/storage/sqlite/client.js +13 -4
- package/dist/storage/sqlite/client.js.map +1 -1
- package/dist/storage/sqliteAsync/client.d.ts +3 -3
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
- package/dist/storage/sqliteAsync/client.js +12 -3
- package/dist/storage/sqliteAsync/client.js.map +1 -1
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +2 -7
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +2 -7
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +2 -2
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +17 -3
- package/dist/sync.js.map +1 -1
- package/dist/tests/GarbageCollector.test.d.ts +2 -0
- package/dist/tests/GarbageCollector.test.d.ts.map +1 -0
- package/dist/tests/GarbageCollector.test.js +85 -0
- package/dist/tests/GarbageCollector.test.js.map +1 -0
- package/dist/tests/coPlainText.test.js +142 -4
- package/dist/tests/coPlainText.test.js.map +1 -1
- package/dist/tests/coStream.test.js +3 -3
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/group.inheritance.test.js +195 -0
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +152 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +2 -2
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/group.test.js +81 -3
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/sync.garbageCollection.test.d.ts +2 -0
- package/dist/tests/sync.garbageCollection.test.d.ts.map +1 -0
- package/dist/tests/sync.garbageCollection.test.js +133 -0
- package/dist/tests/sync.garbageCollection.test.js.map +1 -0
- package/dist/tests/sync.load.test.js +6 -3
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +48 -34
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +31 -21
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +76 -29
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +1 -0
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +1 -1
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +2 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +6 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.js +6 -5
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +1 -1
- package/src/GarbageCollector.ts +48 -0
- package/src/coValue.ts +1 -4
- package/src/coValueContentMessage.ts +16 -3
- package/src/coValueCore/coValueCore.ts +50 -198
- package/src/coValueCore/utils.ts +1 -0
- package/src/coValueCore/verifiedState.ts +1 -0
- package/src/coValues/coPlainText.ts +40 -8
- package/src/coValues/group.ts +310 -91
- package/src/config.ts +20 -1
- package/src/exports.ts +13 -5
- package/src/ids.ts +3 -3
- package/src/localNode.ts +22 -8
- package/src/queue/LocalTransactionsSyncQueue.ts +1 -1
- package/src/queue/StoreQueue.ts +45 -12
- package/src/storage/sqlite/client.ts +24 -10
- package/src/storage/sqliteAsync/client.ts +26 -5
- package/src/storage/storageAsync.ts +5 -9
- package/src/storage/storageSync.ts +2 -9
- package/src/storage/types.ts +7 -4
- package/src/sync.ts +19 -3
- package/src/tests/GarbageCollector.test.ts +127 -0
- package/src/tests/coPlainText.test.ts +176 -4
- package/src/tests/coStream.test.ts +7 -3
- package/src/tests/group.inheritance.test.ts +279 -0
- package/src/tests/group.removeMember.test.ts +244 -1
- package/src/tests/group.roleOf.test.ts +2 -2
- package/src/tests/group.test.ts +105 -5
- package/src/tests/sync.garbageCollection.test.ts +178 -0
- package/src/tests/sync.load.test.ts +6 -3
- package/src/tests/sync.mesh.test.ts +49 -34
- package/src/tests/sync.storage.test.ts +31 -21
- package/src/tests/sync.storageAsync.test.ts +81 -29
- package/src/tests/testStorage.ts +11 -3
- package/src/tests/testUtils.ts +9 -1
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
- package/src/typeUtils/expectGroup.ts +8 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { UpDownCounter, ValueType, metrics } from "@opentelemetry/api";
|
|
2
2
|
import { Result, err } from "neverthrow";
|
|
3
|
-
import { PeerState } from "../PeerState.js";
|
|
4
|
-
import { RawCoValue } from "../coValue.js";
|
|
5
|
-
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
6
|
-
import { RawGroup } from "../coValues/group.js";
|
|
3
|
+
import type { PeerState } from "../PeerState.js";
|
|
4
|
+
import type { RawCoValue } from "../coValue.js";
|
|
5
|
+
import type { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
6
|
+
import type { RawGroup } from "../coValues/group.js";
|
|
7
7
|
import { CO_VALUE_LOADING_CONFIG } from "../config.js";
|
|
8
8
|
import { coreToCoValue } from "../coreToCoValue.js";
|
|
9
9
|
import {
|
|
@@ -16,25 +16,15 @@ import {
|
|
|
16
16
|
SignerID,
|
|
17
17
|
StreamingHash,
|
|
18
18
|
} from "../crypto/crypto.js";
|
|
19
|
-
import {
|
|
20
|
-
RawCoID,
|
|
21
|
-
SessionID,
|
|
22
|
-
TransactionID,
|
|
23
|
-
getParentGroupId,
|
|
24
|
-
isParentGroupReference,
|
|
25
|
-
} from "../ids.js";
|
|
19
|
+
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
26
20
|
import { parseJSON, stableStringify } from "../jsonStringify.js";
|
|
27
21
|
import { JsonValue } from "../jsonValue.js";
|
|
28
22
|
import { LocalNode, ResolveAccountAgentError } from "../localNode.js";
|
|
29
23
|
import { logger } from "../logger.js";
|
|
30
|
-
import {
|
|
31
|
-
determineValidTransactions,
|
|
32
|
-
isKeyForKeyField,
|
|
33
|
-
} from "../permissions.js";
|
|
24
|
+
import { determineValidTransactions } from "../permissions.js";
|
|
34
25
|
import { CoValueKnownState, PeerID, emptyKnownState } from "../sync.js";
|
|
35
26
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
36
27
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
37
|
-
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
38
28
|
import { getDependedOnCoValuesFromRawData } from "./utils.js";
|
|
39
29
|
import { CoValueHeader, Transaction, VerifiedState } from "./verifiedState.js";
|
|
40
30
|
|
|
@@ -53,8 +43,6 @@ export type DecryptedTransaction = {
|
|
|
53
43
|
trusting?: boolean;
|
|
54
44
|
};
|
|
55
45
|
|
|
56
|
-
const readKeyCache = new WeakMap<CoValueCore, { [id: KeyID]: KeySecret }>();
|
|
57
|
-
|
|
58
46
|
export type AvailableCoValueCore = CoValueCore & { verified: VerifiedState };
|
|
59
47
|
|
|
60
48
|
export class CoValueCore {
|
|
@@ -81,7 +69,9 @@ export class CoValueCore {
|
|
|
81
69
|
}
|
|
82
70
|
private readonly peers = new Map<
|
|
83
71
|
PeerID,
|
|
84
|
-
| {
|
|
72
|
+
| {
|
|
73
|
+
type: "unknown" | "pending" | "available" | "unavailable";
|
|
74
|
+
}
|
|
85
75
|
| {
|
|
86
76
|
type: "errored";
|
|
87
77
|
error: TryAddTransactionsError;
|
|
@@ -90,9 +80,8 @@ export class CoValueCore {
|
|
|
90
80
|
|
|
91
81
|
// cached state and listeners
|
|
92
82
|
private _cachedContent?: RawCoValue;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
> = new Set();
|
|
83
|
+
readonly listeners: Set<(core: CoValueCore, unsub: () => void) => void> =
|
|
84
|
+
new Set();
|
|
96
85
|
private readonly _decryptionCache: {
|
|
97
86
|
[key: Encrypted<JsonValue[], JsonValue>]: JsonValue[] | undefined;
|
|
98
87
|
} = {};
|
|
@@ -213,6 +202,26 @@ export class CoValueCore {
|
|
|
213
202
|
}
|
|
214
203
|
}
|
|
215
204
|
|
|
205
|
+
unmount() {
|
|
206
|
+
// For simplicity, we don't unmount groups and accounts
|
|
207
|
+
if (this.verified?.header.ruleset.type === "group") {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (this.listeners.size > 0) {
|
|
212
|
+
return false; // The coValue is still in use
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.counter.add(-1, { state: this.loadingState });
|
|
216
|
+
|
|
217
|
+
if (this.groupInvalidationSubscription) {
|
|
218
|
+
this.groupInvalidationSubscription();
|
|
219
|
+
this.groupInvalidationSubscription = undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
|
|
216
225
|
markNotFoundInPeer(peerId: PeerID) {
|
|
217
226
|
const previousState = this.loadingState;
|
|
218
227
|
this.peers.set(peerId, { type: "unavailable" });
|
|
@@ -621,9 +630,7 @@ export class CoValueCore {
|
|
|
621
630
|
return success;
|
|
622
631
|
}
|
|
623
632
|
|
|
624
|
-
getCurrentContent(options?: {
|
|
625
|
-
ignorePrivateTransactions: true;
|
|
626
|
-
}): RawCoValue {
|
|
633
|
+
getCurrentContent(options?: { ignorePrivateTransactions: true }): RawCoValue {
|
|
627
634
|
if (!this.verified) {
|
|
628
635
|
throw new Error(
|
|
629
636
|
"CoValueCore: getCurrentContent called on coValue without verified state",
|
|
@@ -768,20 +775,7 @@ export class CoValueCore {
|
|
|
768
775
|
}
|
|
769
776
|
|
|
770
777
|
if (this.verified.header.ruleset.type === "group") {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
const currentKeyId = content.getCurrentReadKeyId();
|
|
774
|
-
|
|
775
|
-
if (!currentKeyId) {
|
|
776
|
-
throw new Error("No readKey set");
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
const secret = this.getReadKey(currentKeyId);
|
|
780
|
-
|
|
781
|
-
return {
|
|
782
|
-
secret: secret,
|
|
783
|
-
id: currentKeyId,
|
|
784
|
-
};
|
|
778
|
+
return expectGroup(this.getCurrentContent()).getCurrentReadKey();
|
|
785
779
|
} else if (this.verified.header.ruleset.type === "ownedByGroup") {
|
|
786
780
|
return this.node
|
|
787
781
|
.expectCoValueLoaded(this.verified.header.ruleset.group)
|
|
@@ -793,154 +787,36 @@ export class CoValueCore {
|
|
|
793
787
|
}
|
|
794
788
|
}
|
|
795
789
|
|
|
790
|
+
readKeyCache = new Map<KeyID, KeySecret>();
|
|
796
791
|
getReadKey(keyID: KeyID): KeySecret | undefined {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (!cache) {
|
|
803
|
-
cache = {};
|
|
804
|
-
readKeyCache.set(this, cache);
|
|
805
|
-
}
|
|
806
|
-
cache[keyID] = key;
|
|
807
|
-
}
|
|
792
|
+
// We want to check the cache here, to skip re-computing the group content
|
|
793
|
+
const cachedSecret = this.readKeyCache.get(keyID);
|
|
794
|
+
|
|
795
|
+
if (cachedSecret) {
|
|
796
|
+
return cachedSecret;
|
|
808
797
|
}
|
|
809
|
-
return key;
|
|
810
|
-
}
|
|
811
798
|
|
|
812
|
-
getUncachedReadKey(keyID: KeyID): KeySecret | undefined {
|
|
813
799
|
if (!this.verified) {
|
|
814
800
|
throw new Error(
|
|
815
801
|
"CoValueCore: getUncachedReadKey called on coValue without verified state",
|
|
816
802
|
);
|
|
817
803
|
}
|
|
818
804
|
|
|
805
|
+
// Getting the readKey from accounts
|
|
819
806
|
if (this.verified.header.ruleset.type === "group") {
|
|
820
807
|
const content = expectGroup(
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (keyForEveryone) {
|
|
825
|
-
return keyForEveryone;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// Try to find key revelation for us
|
|
829
|
-
const currentAgentOrAccountID = accountOrAgentIDfromSessionID(
|
|
830
|
-
this.node.currentSessionID,
|
|
831
|
-
);
|
|
832
|
-
|
|
833
|
-
// being careful here to avoid recursion
|
|
834
|
-
const lookupAccountOrAgentID = isAccountID(currentAgentOrAccountID)
|
|
835
|
-
? this.id === currentAgentOrAccountID
|
|
836
|
-
? this.crypto.getAgentID(this.node.agentSecret) // in accounts, the read key is revealed for the primitive agent
|
|
837
|
-
: currentAgentOrAccountID // current account ID
|
|
838
|
-
: currentAgentOrAccountID; // current agent ID
|
|
839
|
-
|
|
840
|
-
const lastReadyKeyEdit = content.lastEditAt(
|
|
841
|
-
`${keyID}_for_${lookupAccountOrAgentID}`,
|
|
808
|
+
// load the account without private transactions, because we are here
|
|
809
|
+
// to be able to decrypt those
|
|
810
|
+
this.getCurrentContent({ ignorePrivateTransactions: true }),
|
|
842
811
|
);
|
|
843
812
|
|
|
844
|
-
|
|
845
|
-
const revealer = lastReadyKeyEdit.by;
|
|
846
|
-
const revealerAgent = this.node
|
|
847
|
-
.resolveAccountAgent(revealer, "Expected to know revealer")
|
|
848
|
-
._unsafeUnwrap({ withStackTrace: true });
|
|
849
|
-
|
|
850
|
-
const secret = this.crypto.unseal(
|
|
851
|
-
lastReadyKeyEdit.value,
|
|
852
|
-
this.crypto.getAgentSealerSecret(this.node.agentSecret), // being careful here to avoid recursion
|
|
853
|
-
this.crypto.getAgentSealerID(revealerAgent),
|
|
854
|
-
{
|
|
855
|
-
in: this.id,
|
|
856
|
-
tx: lastReadyKeyEdit.tx,
|
|
857
|
-
},
|
|
858
|
-
);
|
|
859
|
-
|
|
860
|
-
if (secret) {
|
|
861
|
-
return secret as KeySecret;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// Try to find indirect revelation through previousKeys
|
|
866
|
-
|
|
867
|
-
for (const co of content.keys()) {
|
|
868
|
-
if (isKeyForKeyField(co) && co.startsWith(keyID)) {
|
|
869
|
-
const encryptingKeyID = co.split("_for_")[1] as KeyID;
|
|
870
|
-
const encryptingKeySecret = this.getReadKey(encryptingKeyID);
|
|
871
|
-
|
|
872
|
-
if (!encryptingKeySecret) {
|
|
873
|
-
continue;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const encryptedPreviousKey = content.get(co)!;
|
|
877
|
-
|
|
878
|
-
const secret = this.crypto.decryptKeySecret(
|
|
879
|
-
{
|
|
880
|
-
encryptedID: keyID,
|
|
881
|
-
encryptingID: encryptingKeyID,
|
|
882
|
-
encrypted: encryptedPreviousKey,
|
|
883
|
-
},
|
|
884
|
-
encryptingKeySecret,
|
|
885
|
-
);
|
|
886
|
-
|
|
887
|
-
if (secret) {
|
|
888
|
-
return secret as KeySecret;
|
|
889
|
-
} else {
|
|
890
|
-
logger.warn(
|
|
891
|
-
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// try to find revelation to parent group read keys
|
|
898
|
-
for (const co of content.keys()) {
|
|
899
|
-
if (isParentGroupReference(co)) {
|
|
900
|
-
const parentGroupID = getParentGroupId(co);
|
|
901
|
-
const parentGroup = this.node.expectCoValueLoaded(
|
|
902
|
-
parentGroupID,
|
|
903
|
-
"Expected parent group to be loaded",
|
|
904
|
-
);
|
|
905
|
-
|
|
906
|
-
const parentKeys = this.findValidParentKeys(
|
|
907
|
-
keyID,
|
|
908
|
-
content,
|
|
909
|
-
parentGroup,
|
|
910
|
-
);
|
|
911
|
-
|
|
912
|
-
for (const parentKey of parentKeys) {
|
|
913
|
-
const revelationForParentKey = content.get(
|
|
914
|
-
`${keyID}_for_${parentKey.id}`,
|
|
915
|
-
);
|
|
916
|
-
|
|
917
|
-
if (revelationForParentKey) {
|
|
918
|
-
const secret = parentGroup.crypto.decryptKeySecret(
|
|
919
|
-
{
|
|
920
|
-
encryptedID: keyID,
|
|
921
|
-
encryptingID: parentKey.id,
|
|
922
|
-
encrypted: revelationForParentKey,
|
|
923
|
-
},
|
|
924
|
-
parentKey.secret,
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
if (secret) {
|
|
928
|
-
return secret as KeySecret;
|
|
929
|
-
} else {
|
|
930
|
-
logger.warn(
|
|
931
|
-
`Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`,
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
return undefined;
|
|
813
|
+
return content.getReadKey(keyID);
|
|
940
814
|
} else if (this.verified.header.ruleset.type === "ownedByGroup") {
|
|
941
|
-
return
|
|
942
|
-
|
|
943
|
-
|
|
815
|
+
return expectGroup(
|
|
816
|
+
this.node
|
|
817
|
+
.expectCoValueLoaded(this.verified.header.ruleset.group)
|
|
818
|
+
.getCurrentContent(),
|
|
819
|
+
).getReadKey(keyID);
|
|
944
820
|
} else {
|
|
945
821
|
throw new Error(
|
|
946
822
|
"Only groups or values owned by groups have read secrets",
|
|
@@ -948,28 +824,6 @@ export class CoValueCore {
|
|
|
948
824
|
}
|
|
949
825
|
}
|
|
950
826
|
|
|
951
|
-
findValidParentKeys(keyID: KeyID, group: RawGroup, parentGroup: CoValueCore) {
|
|
952
|
-
const validParentKeys: { id: KeyID; secret: KeySecret }[] = [];
|
|
953
|
-
|
|
954
|
-
for (const co of group.keys()) {
|
|
955
|
-
if (isKeyForKeyField(co) && co.startsWith(keyID)) {
|
|
956
|
-
const encryptingKeyID = co.split("_for_")[1] as KeyID;
|
|
957
|
-
const encryptingKeySecret = parentGroup.getReadKey(encryptingKeyID);
|
|
958
|
-
|
|
959
|
-
if (!encryptingKeySecret) {
|
|
960
|
-
continue;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
validParentKeys.push({
|
|
964
|
-
id: encryptingKeyID,
|
|
965
|
-
secret: encryptingKeySecret,
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
return validParentKeys;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
827
|
getGroup(): RawGroup {
|
|
974
828
|
if (!this.verified) {
|
|
975
829
|
throw new Error(
|
|
@@ -1016,9 +870,7 @@ export class CoValueCore {
|
|
|
1016
870
|
}
|
|
1017
871
|
}
|
|
1018
872
|
|
|
1019
|
-
waitForSync(options?: {
|
|
1020
|
-
timeout?: number;
|
|
1021
|
-
}) {
|
|
873
|
+
waitForSync(options?: { timeout?: number }) {
|
|
1022
874
|
return this.node.syncManager.waitForSync(this.id, options?.timeout);
|
|
1023
875
|
}
|
|
1024
876
|
|
package/src/coValueCore/utils.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { getGroupDependentKey } from "../ids.js";
|
|
|
2
2
|
import { RawCoID, SessionID } from "../ids.js";
|
|
3
3
|
import { Stringified, parseJSON } from "../jsonStringify.js";
|
|
4
4
|
import { JsonValue } from "../jsonValue.js";
|
|
5
|
+
import { NewContentMessage } from "../sync.js";
|
|
5
6
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
6
7
|
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
7
8
|
import { CoValueHeader, Transaction } from "./verifiedState.js";
|
|
@@ -65,6 +65,7 @@ export class VerifiedState {
|
|
|
65
65
|
private _cachedKnownState?: CoValueKnownState;
|
|
66
66
|
private _cachedNewContentSinceEmpty: NewContentMessage[] | undefined;
|
|
67
67
|
private streamingKnownState?: CoValueKnownState["sessions"];
|
|
68
|
+
public lastAccessed: number | undefined;
|
|
68
69
|
|
|
69
70
|
constructor(
|
|
70
71
|
id: RawCoID,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { splitGraphemes } from "unicode-segmenter/grapheme";
|
|
2
2
|
import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
|
|
3
|
+
import { TRANSACTION_CONFIG } from "../config.js";
|
|
3
4
|
import { JsonObject } from "../jsonValue.js";
|
|
4
5
|
import { DeletionOpPayload, OpID, RawCoList } from "./coList.js";
|
|
5
6
|
|
|
@@ -110,16 +111,34 @@ export class RawCoPlainText<
|
|
|
110
111
|
text: string,
|
|
111
112
|
privacy: "private" | "trusting" = "private",
|
|
112
113
|
) {
|
|
113
|
-
const graphemes =
|
|
114
|
+
const graphemes = Array.from(splitGraphemes(text));
|
|
114
115
|
|
|
115
116
|
if (idx === 0) {
|
|
116
|
-
// For insertions at start, prepend
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
// For insertions at start, prepend the first char and append the rest
|
|
118
|
+
const firstChar = graphemes[0];
|
|
119
|
+
|
|
120
|
+
if (firstChar) {
|
|
121
|
+
this.prepend(firstChar, 0, privacy);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (graphemes.length > 1) {
|
|
125
|
+
this.appendChars(graphemes.slice(1), 0, privacy);
|
|
119
126
|
}
|
|
120
127
|
} else {
|
|
121
128
|
// For other insertions, append after the previous character
|
|
122
|
-
this.
|
|
129
|
+
this.appendChars(graphemes, idx - 1, privacy);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
appendChars(
|
|
134
|
+
text: string[],
|
|
135
|
+
position: number,
|
|
136
|
+
privacy: "private" | "trusting" = "private",
|
|
137
|
+
) {
|
|
138
|
+
const chunks = splitIntoChunks(text);
|
|
139
|
+
for (const chunk of chunks) {
|
|
140
|
+
this.appendItems(chunk, position, privacy);
|
|
141
|
+
position += chunk.length;
|
|
123
142
|
}
|
|
124
143
|
}
|
|
125
144
|
|
|
@@ -136,11 +155,12 @@ export class RawCoPlainText<
|
|
|
136
155
|
text: string,
|
|
137
156
|
privacy: "private" | "trusting" = "private",
|
|
138
157
|
) {
|
|
139
|
-
const graphemes =
|
|
158
|
+
const graphemes = Array.from(splitGraphemes(text));
|
|
159
|
+
|
|
140
160
|
if (idx >= this.entries().length) {
|
|
141
|
-
this.
|
|
161
|
+
this.appendChars(graphemes, idx - 1, privacy);
|
|
142
162
|
} else {
|
|
143
|
-
this.
|
|
163
|
+
this.appendChars(graphemes, idx, privacy);
|
|
144
164
|
}
|
|
145
165
|
}
|
|
146
166
|
|
|
@@ -178,3 +198,15 @@ export class RawCoPlainText<
|
|
|
178
198
|
return graphemes.join("");
|
|
179
199
|
}
|
|
180
200
|
}
|
|
201
|
+
|
|
202
|
+
function splitIntoChunks(text: string[]) {
|
|
203
|
+
const chunks: string[][] = [];
|
|
204
|
+
for (
|
|
205
|
+
let i = 0;
|
|
206
|
+
i < text.length;
|
|
207
|
+
i += TRANSACTION_CONFIG.MAX_RECOMMENDED_TX_SIZE
|
|
208
|
+
) {
|
|
209
|
+
chunks.push(text.slice(i, i + TRANSACTION_CONFIG.MAX_RECOMMENDED_TX_SIZE));
|
|
210
|
+
}
|
|
211
|
+
return chunks;
|
|
212
|
+
}
|