cojson 0.19.22 → 0.20.1
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 +66 -0
- package/dist/PeerState.d.ts +6 -1
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +18 -3
- package/dist/PeerState.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +0 -2
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +0 -8
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +4 -2
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +30 -0
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +70 -5
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +302 -31
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +6 -1
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +9 -0
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coList.d.ts +4 -2
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js +3 -0
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +3 -6
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +2 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -12
- package/dist/config.js.map +1 -1
- package/dist/crypto/NapiCrypto.d.ts +1 -2
- package/dist/crypto/NapiCrypto.d.ts.map +1 -1
- package/dist/crypto/NapiCrypto.js +19 -4
- package/dist/crypto/NapiCrypto.js.map +1 -1
- package/dist/crypto/RNCrypto.d.ts.map +1 -1
- package/dist/crypto/RNCrypto.js +19 -4
- package/dist/crypto/RNCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.d.ts +11 -4
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +52 -10
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/WasmCryptoEdge.d.ts +1 -0
- package/dist/crypto/WasmCryptoEdge.d.ts.map +1 -1
- package/dist/crypto/WasmCryptoEdge.js +4 -1
- package/dist/crypto/WasmCryptoEdge.js.map +1 -1
- package/dist/crypto/crypto.d.ts +3 -3
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/crypto/crypto.js +6 -1
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/exports.d.ts +5 -5
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +4 -3
- package/dist/exports.js.map +1 -1
- package/dist/ids.d.ts +4 -1
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +4 -0
- package/dist/ids.js.map +1 -1
- package/dist/knownState.d.ts +2 -0
- package/dist/knownState.d.ts.map +1 -1
- package/dist/localNode.d.ts +12 -0
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +14 -0
- package/dist/localNode.js.map +1 -1
- package/dist/platformUtils.d.ts +3 -0
- package/dist/platformUtils.d.ts.map +1 -0
- package/dist/platformUtils.js +24 -0
- package/dist/platformUtils.js.map +1 -0
- package/dist/queue/LinkedList.d.ts +9 -3
- package/dist/queue/LinkedList.d.ts.map +1 -1
- package/dist/queue/LinkedList.js +30 -1
- package/dist/queue/LinkedList.js.map +1 -1
- package/dist/queue/OutgoingLoadQueue.d.ts +95 -0
- package/dist/queue/OutgoingLoadQueue.d.ts.map +1 -0
- package/dist/queue/OutgoingLoadQueue.js +240 -0
- package/dist/queue/OutgoingLoadQueue.js.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts +30 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js +84 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js.map +1 -0
- package/dist/storage/sqlite/client.d.ts +3 -0
- package/dist/storage/sqlite/client.d.ts.map +1 -1
- package/dist/storage/sqlite/client.js +44 -0
- package/dist/storage/sqlite/client.js.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.js +7 -0
- package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
- package/dist/storage/sqliteAsync/client.d.ts +3 -0
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
- package/dist/storage/sqliteAsync/client.js +42 -0
- package/dist/storage/sqliteAsync/client.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +7 -0
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +48 -0
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +6 -0
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +42 -0
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +59 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +66 -43
- package/dist/sync.js.map +1 -1
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts +2 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts.map +1 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js +149 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js.map +1 -0
- package/dist/tests/GarbageCollector.test.js +5 -6
- package/dist/tests/GarbageCollector.test.js.map +1 -1
- package/dist/tests/LinkedList.test.js +90 -0
- package/dist/tests/LinkedList.test.js.map +1 -1
- package/dist/tests/OutgoingLoadQueue.test.d.ts +2 -0
- package/dist/tests/OutgoingLoadQueue.test.d.ts.map +1 -0
- package/dist/tests/OutgoingLoadQueue.test.js +814 -0
- package/dist/tests/OutgoingLoadQueue.test.js.map +1 -0
- package/dist/tests/StorageApiAsync.test.js +484 -152
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +505 -136
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/WasmCrypto.test.js +6 -3
- package/dist/tests/WasmCrypto.test.js.map +1 -1
- package/dist/tests/coValueCore.loadFromStorage.test.js +3 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +34 -13
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coreWasm.test.js +127 -4
- package/dist/tests/coreWasm.test.js.map +1 -1
- package/dist/tests/crypto.test.js +89 -93
- package/dist/tests/crypto.test.js.map +1 -1
- package/dist/tests/deleteCoValue.test.d.ts +2 -0
- package/dist/tests/deleteCoValue.test.d.ts.map +1 -0
- package/dist/tests/deleteCoValue.test.js +313 -0
- package/dist/tests/deleteCoValue.test.js.map +1 -0
- package/dist/tests/group.removeMember.test.js +18 -30
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/knownState.lazyLoading.test.js +3 -0
- package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
- package/dist/tests/sync.concurrentLoad.test.d.ts +2 -0
- package/dist/tests/sync.concurrentLoad.test.d.ts.map +1 -0
- package/dist/tests/sync.concurrentLoad.test.js +481 -0
- package/dist/tests/sync.concurrentLoad.test.js.map +1 -0
- package/dist/tests/sync.deleted.test.d.ts +2 -0
- package/dist/tests/sync.deleted.test.d.ts.map +1 -0
- package/dist/tests/sync.deleted.test.js +214 -0
- package/dist/tests/sync.deleted.test.js.map +1 -0
- package/dist/tests/sync.mesh.test.js +3 -2
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +4 -3
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.test.js +3 -2
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +3 -0
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +17 -1
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +7 -3
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +19 -4
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +6 -16
- package/src/PeerState.ts +26 -3
- package/src/coValueContentMessage.ts +0 -14
- package/src/coValueCore/SessionMap.ts +43 -1
- package/src/coValueCore/coValueCore.ts +415 -27
- package/src/coValueCore/verifiedState.ts +26 -3
- package/src/coValues/coList.ts +9 -3
- package/src/coValues/group.ts +5 -6
- package/src/config.ts +4 -13
- package/src/crypto/NapiCrypto.ts +29 -13
- package/src/crypto/RNCrypto.ts +29 -11
- package/src/crypto/WasmCrypto.ts +67 -20
- package/src/crypto/WasmCryptoEdge.ts +5 -1
- package/src/crypto/crypto.ts +16 -4
- package/src/exports.ts +4 -2
- package/src/ids.ts +11 -1
- package/src/localNode.ts +15 -0
- package/src/platformUtils.ts +26 -0
- package/src/queue/LinkedList.ts +34 -4
- package/src/queue/OutgoingLoadQueue.ts +307 -0
- package/src/storage/DeletedCoValuesEraserScheduler.ts +124 -0
- package/src/storage/sqlite/client.ts +77 -0
- package/src/storage/sqlite/sqliteMigrations.ts +7 -0
- package/src/storage/sqliteAsync/client.ts +75 -0
- package/src/storage/storageAsync.ts +62 -0
- package/src/storage/storageSync.ts +58 -0
- package/src/storage/types.ts +69 -0
- package/src/sync.ts +78 -46
- package/src/tests/DeletedCoValuesEraserScheduler.test.ts +185 -0
- package/src/tests/GarbageCollector.test.ts +6 -10
- package/src/tests/LinkedList.test.ts +111 -0
- package/src/tests/OutgoingLoadQueue.test.ts +1129 -0
- package/src/tests/StorageApiAsync.test.ts +572 -162
- package/src/tests/StorageApiSync.test.ts +580 -143
- package/src/tests/WasmCrypto.test.ts +8 -3
- package/src/tests/coValueCore.loadFromStorage.test.ts +6 -0
- package/src/tests/coValueCore.test.ts +49 -14
- package/src/tests/coreWasm.test.ts +319 -10
- package/src/tests/crypto.test.ts +141 -150
- package/src/tests/deleteCoValue.test.ts +528 -0
- package/src/tests/group.removeMember.test.ts +35 -35
- package/src/tests/knownState.lazyLoading.test.ts +6 -0
- package/src/tests/sync.concurrentLoad.test.ts +650 -0
- package/src/tests/sync.deleted.test.ts +294 -0
- package/src/tests/sync.mesh.test.ts +5 -2
- package/src/tests/sync.storage.test.ts +6 -3
- package/src/tests/sync.test.ts +5 -2
- package/src/tests/testStorage.ts +31 -2
- package/src/tests/testUtils.ts +31 -10
- package/dist/crypto/PureJSCrypto.d.ts +0 -77
- package/dist/crypto/PureJSCrypto.d.ts.map +0 -1
- package/dist/crypto/PureJSCrypto.js +0 -236
- package/dist/crypto/PureJSCrypto.js.map +0 -1
- package/dist/tests/PureJSCrypto.test.d.ts +0 -2
- package/dist/tests/PureJSCrypto.test.d.ts.map +0 -1
- package/dist/tests/PureJSCrypto.test.js +0 -145
- package/dist/tests/PureJSCrypto.test.js.map +0 -1
- package/src/crypto/PureJSCrypto.ts +0 -429
- package/src/tests/PureJSCrypto.test.ts +0 -217
|
@@ -14,12 +14,16 @@ import {
|
|
|
14
14
|
Signature,
|
|
15
15
|
SignerID,
|
|
16
16
|
} from "../crypto/crypto.js";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
isDeleteSessionID,
|
|
19
|
+
RawCoID,
|
|
20
|
+
SessionID,
|
|
21
|
+
TransactionID,
|
|
22
|
+
} from "../ids.js";
|
|
18
23
|
import { Stringified } from "../jsonStringify.js";
|
|
19
24
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
20
25
|
import { PermissionsDef as RulesetDef } from "../permissions.js";
|
|
21
26
|
import { NewContentMessage } from "../sync.js";
|
|
22
|
-
import { TryAddTransactionsError } from "./coValueCore.js";
|
|
23
27
|
import { SessionMap } from "./SessionMap.js";
|
|
24
28
|
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
25
29
|
import {
|
|
@@ -35,10 +39,19 @@ export type CoValueHeader = {
|
|
|
35
39
|
} & CoValueUniqueness;
|
|
36
40
|
|
|
37
41
|
export type CoValueUniqueness = {
|
|
38
|
-
uniqueness:
|
|
42
|
+
uniqueness: Uniqueness;
|
|
39
43
|
createdAt?: `2${string}` | null;
|
|
40
44
|
};
|
|
41
45
|
|
|
46
|
+
export type Uniqueness =
|
|
47
|
+
| string
|
|
48
|
+
| boolean
|
|
49
|
+
| null
|
|
50
|
+
| undefined
|
|
51
|
+
| {
|
|
52
|
+
[key: string]: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
42
55
|
export type PrivateTransaction = {
|
|
43
56
|
privacy: "private";
|
|
44
57
|
madeAt: number;
|
|
@@ -63,6 +76,7 @@ export class VerifiedState {
|
|
|
63
76
|
public lastAccessed: number | undefined;
|
|
64
77
|
public branchSourceId?: RawCoID;
|
|
65
78
|
public branchName?: string;
|
|
79
|
+
private isDeleted: boolean = false;
|
|
66
80
|
|
|
67
81
|
constructor(
|
|
68
82
|
id: RawCoID,
|
|
@@ -87,6 +101,11 @@ export class VerifiedState {
|
|
|
87
101
|
);
|
|
88
102
|
}
|
|
89
103
|
|
|
104
|
+
markAsDeleted() {
|
|
105
|
+
this.isDeleted = true;
|
|
106
|
+
this.sessions.markAsDeleted();
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
tryAddTransactions(
|
|
91
110
|
sessionID: SessionID,
|
|
92
111
|
signerID: SignerID | undefined,
|
|
@@ -199,6 +218,10 @@ export class VerifiedState {
|
|
|
199
218
|
const sessionSent = knownState?.sessions;
|
|
200
219
|
|
|
201
220
|
for (const [sessionID, log] of this.sessions.sessions) {
|
|
221
|
+
if (this.isDeleted && !isDeleteSessionID(sessionID)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
202
225
|
const startFrom = sessionSent?.[sessionID] ?? 0;
|
|
203
226
|
|
|
204
227
|
let currentSessionSize = 0;
|
package/src/coValues/coList.ts
CHANGED
|
@@ -59,14 +59,14 @@ export class RawCoList<
|
|
|
59
59
|
afterStart: OpID[] = [];
|
|
60
60
|
beforeEnd: OpID[] = [];
|
|
61
61
|
insertions: {
|
|
62
|
-
[sessionID:
|
|
62
|
+
[sessionID: SessionIndex]: {
|
|
63
63
|
[txIdx: number]: {
|
|
64
64
|
[changeIdx: number]: InsertionEntry<Item>;
|
|
65
65
|
};
|
|
66
66
|
};
|
|
67
67
|
} = {};
|
|
68
68
|
deletionsByInsertion: {
|
|
69
|
-
[deletedSessionID:
|
|
69
|
+
[deletedSessionID: SessionIndex]: {
|
|
70
70
|
[deletedTxIdx: number]: {
|
|
71
71
|
[deletedChangeIdx: number]: DeletionEntry[];
|
|
72
72
|
};
|
|
@@ -378,6 +378,10 @@ export class RawCoList<
|
|
|
378
378
|
return arr;
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
+
length() {
|
|
382
|
+
return this.entries().length;
|
|
383
|
+
}
|
|
384
|
+
|
|
381
385
|
/** @internal */
|
|
382
386
|
entriesUncached(): {
|
|
383
387
|
value: Item;
|
|
@@ -700,7 +704,9 @@ export class RawCoList<
|
|
|
700
704
|
}
|
|
701
705
|
}
|
|
702
706
|
|
|
703
|
-
|
|
707
|
+
type SessionIndex = SessionID | `${SessionID}_branch_${RawCoID}`;
|
|
708
|
+
|
|
709
|
+
function getSessionIndex(txID: TransactionID): SessionIndex {
|
|
704
710
|
if (txID.branch) {
|
|
705
711
|
return `${txID.sessionID}_branch_${txID.branch}`;
|
|
706
712
|
}
|
package/src/coValues/group.ts
CHANGED
|
@@ -1203,12 +1203,11 @@ export class RawGroup<
|
|
|
1203
1203
|
|
|
1204
1204
|
this.set(memberKey, "revoked", "trusting");
|
|
1205
1205
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
// }
|
|
1206
|
+
if (this.get(memberKey) !== "revoked") {
|
|
1207
|
+
throw new Error(
|
|
1208
|
+
`Failed to revoke role to ${memberKey} (role of current account is ${this.myRole()})`,
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1212
1211
|
}
|
|
1213
1212
|
|
|
1214
1213
|
/**
|
package/src/config.ts
CHANGED
|
@@ -7,25 +7,17 @@
|
|
|
7
7
|
**/
|
|
8
8
|
export const TRANSACTION_CONFIG = {
|
|
9
9
|
MAX_RECOMMENDED_TX_SIZE: 100 * 1024,
|
|
10
|
-
/**
|
|
11
|
-
* Messages larger than this will be rejected when creating a transaction.
|
|
12
|
-
* The current limit is set at 1MB because that's the limit imposed by Cloudflare to Websocket messages.
|
|
13
|
-
*/
|
|
14
|
-
MAX_TX_SIZE_BYTES: 1 * 1024 * 1024,
|
|
15
10
|
};
|
|
16
11
|
|
|
17
12
|
export function setMaxRecommendedTxSize(size: number) {
|
|
18
13
|
TRANSACTION_CONFIG.MAX_RECOMMENDED_TX_SIZE = size;
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
export function setMaxTxSizeBytes(size: number) {
|
|
22
|
-
TRANSACTION_CONFIG.MAX_TX_SIZE_BYTES = size;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
16
|
export const CO_VALUE_LOADING_CONFIG = {
|
|
26
17
|
MAX_RETRIES: 1,
|
|
27
|
-
TIMEOUT:
|
|
18
|
+
TIMEOUT: 60_000,
|
|
28
19
|
RETRY_DELAY: 3000,
|
|
20
|
+
MAX_IN_FLIGHT_LOADS_PER_PEER: 1000,
|
|
29
21
|
};
|
|
30
22
|
|
|
31
23
|
export function setCoValueLoadingMaxRetries(maxRetries: number) {
|
|
@@ -63,13 +55,12 @@ export function setGarbageCollectorInterval(interval: number) {
|
|
|
63
55
|
|
|
64
56
|
export const WEBSOCKET_CONFIG = {
|
|
65
57
|
MAX_OUTGOING_MESSAGES_CHUNK_BYTES: 25_000,
|
|
66
|
-
OUTGOING_MESSAGES_CHUNK_DELAY: 5,
|
|
67
58
|
};
|
|
68
59
|
|
|
69
60
|
export function setMaxOutgoingMessagesChunkBytes(bytes: number) {
|
|
70
61
|
WEBSOCKET_CONFIG.MAX_OUTGOING_MESSAGES_CHUNK_BYTES = bytes;
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
export function
|
|
74
|
-
|
|
64
|
+
export function setMaxInFlightLoadsPerPeer(limit: number) {
|
|
65
|
+
CO_VALUE_LOADING_CONFIG.MAX_IN_FLIGHT_LOADS_PER_PEER = limit;
|
|
75
66
|
}
|
package/src/crypto/NapiCrypto.ts
CHANGED
|
@@ -19,7 +19,6 @@ import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
|
19
19
|
import { Stringified, stableStringify } from "../jsonStringify.js";
|
|
20
20
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
21
21
|
import { logger } from "../logger.js";
|
|
22
|
-
import { PureJSCrypto } from "./PureJSCrypto.js";
|
|
23
22
|
import {
|
|
24
23
|
CryptoProvider,
|
|
25
24
|
Encrypted,
|
|
@@ -58,7 +57,7 @@ export class NapiCrypto extends CryptoProvider<Blake3State> {
|
|
|
58
57
|
super();
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
static async create(): Promise<NapiCrypto |
|
|
60
|
+
static async create(): Promise<NapiCrypto | WasmCrypto> {
|
|
62
61
|
return new NapiCrypto();
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -190,11 +189,24 @@ class SessionLogAdapter {
|
|
|
190
189
|
newSignature: Signature,
|
|
191
190
|
skipVerify: boolean,
|
|
192
191
|
): void {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
// Use direct calls instead of JSON.stringify for better performance
|
|
193
|
+
for (const tx of transactions) {
|
|
194
|
+
if (tx.privacy === "private") {
|
|
195
|
+
this.sessionLog.addExistingPrivateTransaction(
|
|
196
|
+
tx.encryptedChanges,
|
|
197
|
+
tx.keyUsed,
|
|
198
|
+
tx.madeAt,
|
|
199
|
+
tx.meta,
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
this.sessionLog.addExistingTrustingTransaction(
|
|
203
|
+
tx.changes,
|
|
204
|
+
tx.madeAt,
|
|
205
|
+
tx.meta,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.sessionLog.commitTransactions(newSignature, skipVerify);
|
|
198
210
|
}
|
|
199
211
|
|
|
200
212
|
addNewPrivateTransaction(
|
|
@@ -206,12 +218,14 @@ class SessionLogAdapter {
|
|
|
206
218
|
meta: JsonObject | undefined,
|
|
207
219
|
): { signature: Signature; transaction: PrivateTransaction } {
|
|
208
220
|
const output = this.sessionLog.addNewPrivateTransaction(
|
|
209
|
-
stableStringify
|
|
221
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
222
|
+
JSON.stringify(changes),
|
|
210
223
|
signerAgent.currentSignerSecret(),
|
|
211
224
|
keySecret,
|
|
212
225
|
keyID,
|
|
213
226
|
madeAt,
|
|
214
|
-
|
|
227
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
228
|
+
meta ? JSON.stringify(meta) : undefined,
|
|
215
229
|
);
|
|
216
230
|
const parsedOutput = JSON.parse(output);
|
|
217
231
|
const transaction: PrivateTransaction = {
|
|
@@ -230,8 +244,10 @@ class SessionLogAdapter {
|
|
|
230
244
|
madeAt: number,
|
|
231
245
|
meta: JsonObject | undefined,
|
|
232
246
|
): { signature: Signature; transaction: TrustingTransaction } {
|
|
233
|
-
|
|
234
|
-
const
|
|
247
|
+
// We can avoid stableStringify because the changes will be in a string format already.
|
|
248
|
+
const stringifiedChanges = JSON.stringify(changes);
|
|
249
|
+
// We can avoid stableStringify because the meta will be in a string format already.
|
|
250
|
+
const stringifiedMeta = meta ? JSON.stringify(meta) : undefined;
|
|
235
251
|
const output = this.sessionLog.addNewTrustingTransaction(
|
|
236
252
|
stringifiedChanges,
|
|
237
253
|
signerAgent.currentSignerSecret(),
|
|
@@ -241,8 +257,8 @@ class SessionLogAdapter {
|
|
|
241
257
|
const transaction: TrustingTransaction = {
|
|
242
258
|
privacy: "trusting",
|
|
243
259
|
madeAt,
|
|
244
|
-
changes: stringifiedChanges
|
|
245
|
-
meta: stringifiedMeta,
|
|
260
|
+
changes: stringifiedChanges as Stringified<JsonValue[]>,
|
|
261
|
+
meta: stringifiedMeta as Stringified<JsonObject> | undefined,
|
|
246
262
|
};
|
|
247
263
|
return { signature: output as Signature, transaction };
|
|
248
264
|
}
|
package/src/crypto/RNCrypto.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
Blake3Hasher,
|
|
48
48
|
SessionLog,
|
|
49
49
|
} from "cojson-core-rn";
|
|
50
|
+
import { WasmCrypto } from "./WasmCrypto.js";
|
|
50
51
|
|
|
51
52
|
type Blake3State = Blake3Hasher;
|
|
52
53
|
|
|
@@ -221,11 +222,24 @@ class SessionLogAdapter implements SessionLogImpl {
|
|
|
221
222
|
newSignature: Signature,
|
|
222
223
|
skipVerify: boolean,
|
|
223
224
|
): void {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
// Use direct calls instead of JSON.stringify for better performance
|
|
226
|
+
for (const tx of transactions) {
|
|
227
|
+
if (tx.privacy === "private") {
|
|
228
|
+
this.sessionLog.addExistingPrivateTransaction(
|
|
229
|
+
tx.encryptedChanges,
|
|
230
|
+
tx.keyUsed,
|
|
231
|
+
tx.madeAt,
|
|
232
|
+
tx.meta,
|
|
233
|
+
);
|
|
234
|
+
} else {
|
|
235
|
+
this.sessionLog.addExistingTrustingTransaction(
|
|
236
|
+
tx.changes,
|
|
237
|
+
tx.madeAt,
|
|
238
|
+
tx.meta,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
this.sessionLog.commitTransactions(newSignature, skipVerify);
|
|
229
243
|
}
|
|
230
244
|
|
|
231
245
|
addNewPrivateTransaction(
|
|
@@ -237,12 +251,14 @@ class SessionLogAdapter implements SessionLogImpl {
|
|
|
237
251
|
meta: JsonObject | undefined,
|
|
238
252
|
) {
|
|
239
253
|
const output = this.sessionLog.addNewPrivateTransaction(
|
|
240
|
-
stableStringify
|
|
254
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
255
|
+
JSON.stringify(changes),
|
|
241
256
|
signerAgent.currentSignerSecret(),
|
|
242
257
|
keySecret,
|
|
243
258
|
keyID,
|
|
244
259
|
madeAt,
|
|
245
|
-
|
|
260
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
261
|
+
meta ? JSON.stringify(meta) : undefined,
|
|
246
262
|
);
|
|
247
263
|
const parsedOutput = JSON.parse(output);
|
|
248
264
|
const transaction: PrivateTransaction = {
|
|
@@ -261,8 +277,10 @@ class SessionLogAdapter implements SessionLogImpl {
|
|
|
261
277
|
madeAt: number,
|
|
262
278
|
meta: JsonObject | undefined,
|
|
263
279
|
) {
|
|
264
|
-
|
|
265
|
-
const
|
|
280
|
+
// We can avoid stableStringify because the changes will be in a string format already.
|
|
281
|
+
const stringifiedChanges = JSON.stringify(changes);
|
|
282
|
+
// We can avoid stableStringify because the meta will be in a string format already.
|
|
283
|
+
const stringifiedMeta = meta ? JSON.stringify(meta) : undefined;
|
|
266
284
|
const output = this.sessionLog.addNewTrustingTransaction(
|
|
267
285
|
stringifiedChanges,
|
|
268
286
|
signerAgent.currentSignerSecret(),
|
|
@@ -272,8 +290,8 @@ class SessionLogAdapter implements SessionLogImpl {
|
|
|
272
290
|
const transaction: TrustingTransaction = {
|
|
273
291
|
privacy: "trusting",
|
|
274
292
|
madeAt,
|
|
275
|
-
changes: stringifiedChanges
|
|
276
|
-
meta: stringifiedMeta,
|
|
293
|
+
changes: stringifiedChanges as Stringified<JsonValue[]>,
|
|
294
|
+
meta: stringifiedMeta as Stringified<JsonObject> | undefined,
|
|
277
295
|
};
|
|
278
296
|
return { signature: output as Signature, transaction };
|
|
279
297
|
}
|
package/src/crypto/WasmCrypto.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SessionLog,
|
|
3
3
|
initialize,
|
|
4
|
+
initializeSync,
|
|
4
5
|
Blake3Hasher,
|
|
5
6
|
blake3HashOnce,
|
|
6
7
|
blake3HashOnceWithContext,
|
|
@@ -20,7 +21,6 @@ import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
|
20
21
|
import { Stringified, stableStringify } from "../jsonStringify.js";
|
|
21
22
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
22
23
|
import { logger } from "../logger.js";
|
|
23
|
-
import { PureJSCrypto } from "./PureJSCrypto.js";
|
|
24
24
|
import {
|
|
25
25
|
CryptoProvider,
|
|
26
26
|
Encrypted,
|
|
@@ -41,10 +41,34 @@ import {
|
|
|
41
41
|
Transaction,
|
|
42
42
|
TrustingTransaction,
|
|
43
43
|
} from "../coValueCore/verifiedState.js";
|
|
44
|
+
import { isCloudflare, isEvalAllowed } from "../platformUtils.js";
|
|
44
45
|
|
|
45
46
|
type Blake3State = Blake3Hasher;
|
|
46
47
|
|
|
47
48
|
let wasmInit = initialize;
|
|
49
|
+
let wasmInitSync = initializeSync;
|
|
50
|
+
|
|
51
|
+
const wasmCryptoErrorMessage = (
|
|
52
|
+
e: unknown,
|
|
53
|
+
) => `Critical Error: Failed to load WASM module
|
|
54
|
+
|
|
55
|
+
${!isEvalAllowed() ? `You need to add \`import "jazz-tools/load-edge-wasm";\` on top of your entry module to make Jazz work with ${isCloudflare() ? "Cloudflare workers" : "this runtime"}` : (e as Error).message}
|
|
56
|
+
|
|
57
|
+
A native crypto module is required for Jazz to work. See https://jazz.tools/docs/react/reference/performance#use-the-best-crypto-implementation-for-your-platform for possible alternatives.`;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Initializes the WasmCrypto module. This function can be used to initialize the WasmCrypto module in a worker or a browser.
|
|
61
|
+
* if you are using SSR and you want to initialize WASM crypto asynchronously you can use this function.
|
|
62
|
+
* @returns A promise that resolves when the WasmCrypto module is successfully initialized.
|
|
63
|
+
*/
|
|
64
|
+
export async function initWasmCrypto() {
|
|
65
|
+
try {
|
|
66
|
+
await wasmInit();
|
|
67
|
+
} catch (e) {
|
|
68
|
+
throw new Error(wasmCryptoErrorMessage(e), { cause: e });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
48
72
|
/**
|
|
49
73
|
* WebAssembly implementation of the CryptoProvider interface using cojson-core-wasm.
|
|
50
74
|
* This provides the primary implementation using WebAssembly for optimal performance, offering:
|
|
@@ -54,7 +78,7 @@ let wasmInit = initialize;
|
|
|
54
78
|
* - Hashing (BLAKE3)
|
|
55
79
|
*/
|
|
56
80
|
export class WasmCrypto extends CryptoProvider<Blake3State> {
|
|
57
|
-
|
|
81
|
+
protected constructor() {
|
|
58
82
|
super();
|
|
59
83
|
}
|
|
60
84
|
|
|
@@ -62,17 +86,23 @@ export class WasmCrypto extends CryptoProvider<Blake3State> {
|
|
|
62
86
|
wasmInit = value;
|
|
63
87
|
}
|
|
64
88
|
|
|
65
|
-
static
|
|
89
|
+
static setInitSync(value: typeof initializeSync) {
|
|
90
|
+
wasmInitSync = value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static createSync(): WasmCrypto {
|
|
66
94
|
try {
|
|
67
|
-
|
|
95
|
+
wasmInitSync();
|
|
68
96
|
} catch (e) {
|
|
69
|
-
|
|
70
|
-
"Failed to initialize WasmCrypto, falling back to PureJSCrypto",
|
|
71
|
-
{ err: e },
|
|
72
|
-
);
|
|
73
|
-
return new PureJSCrypto();
|
|
97
|
+
throw new Error(wasmCryptoErrorMessage(e), { cause: e });
|
|
74
98
|
}
|
|
99
|
+
return new WasmCrypto();
|
|
100
|
+
}
|
|
75
101
|
|
|
102
|
+
// TODO: Remove this method and use createSync instead, this is not necessary since we can use createSync in the browser and in the worker.
|
|
103
|
+
// @deprecated
|
|
104
|
+
static async create(): Promise<WasmCrypto> {
|
|
105
|
+
await initWasmCrypto();
|
|
76
106
|
return new WasmCrypto();
|
|
77
107
|
}
|
|
78
108
|
|
|
@@ -204,11 +234,24 @@ class SessionLogAdapter {
|
|
|
204
234
|
newSignature: Signature,
|
|
205
235
|
skipVerify: boolean,
|
|
206
236
|
): void {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
237
|
+
// Use direct calls instead of JSON.stringify for better performance
|
|
238
|
+
for (const tx of transactions) {
|
|
239
|
+
if (tx.privacy === "private") {
|
|
240
|
+
this.sessionLog.addExistingPrivateTransaction(
|
|
241
|
+
tx.encryptedChanges,
|
|
242
|
+
tx.keyUsed,
|
|
243
|
+
tx.madeAt,
|
|
244
|
+
tx.meta,
|
|
245
|
+
);
|
|
246
|
+
} else {
|
|
247
|
+
this.sessionLog.addExistingTrustingTransaction(
|
|
248
|
+
tx.changes,
|
|
249
|
+
tx.madeAt,
|
|
250
|
+
tx.meta,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
this.sessionLog.commitTransactions(newSignature, skipVerify);
|
|
212
255
|
}
|
|
213
256
|
|
|
214
257
|
addNewPrivateTransaction(
|
|
@@ -220,12 +263,14 @@ class SessionLogAdapter {
|
|
|
220
263
|
meta: JsonObject | undefined,
|
|
221
264
|
): { signature: Signature; transaction: PrivateTransaction } {
|
|
222
265
|
const output = this.sessionLog.addNewPrivateTransaction(
|
|
223
|
-
stableStringify
|
|
266
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
267
|
+
JSON.stringify(changes),
|
|
224
268
|
signerAgent.currentSignerSecret(),
|
|
225
269
|
keySecret,
|
|
226
270
|
keyID,
|
|
227
271
|
madeAt,
|
|
228
|
-
|
|
272
|
+
// We can avoid stableStringify because it will be encrypted.
|
|
273
|
+
meta ? JSON.stringify(meta) : undefined,
|
|
229
274
|
);
|
|
230
275
|
const parsedOutput = JSON.parse(output);
|
|
231
276
|
const transaction: PrivateTransaction = {
|
|
@@ -244,8 +289,10 @@ class SessionLogAdapter {
|
|
|
244
289
|
madeAt: number,
|
|
245
290
|
meta: JsonObject | undefined,
|
|
246
291
|
): { signature: Signature; transaction: TrustingTransaction } {
|
|
247
|
-
|
|
248
|
-
const
|
|
292
|
+
// We can avoid stableStringify because the changes will be in a string format already.
|
|
293
|
+
const stringifiedChanges = JSON.stringify(changes);
|
|
294
|
+
// We can avoid stableStringify because the meta will be in a string format already.
|
|
295
|
+
const stringifiedMeta = meta ? JSON.stringify(meta) : undefined;
|
|
249
296
|
const output = this.sessionLog.addNewTrustingTransaction(
|
|
250
297
|
stringifiedChanges,
|
|
251
298
|
signerAgent.currentSignerSecret(),
|
|
@@ -255,8 +302,8 @@ class SessionLogAdapter {
|
|
|
255
302
|
const transaction: TrustingTransaction = {
|
|
256
303
|
privacy: "trusting",
|
|
257
304
|
madeAt,
|
|
258
|
-
changes: stringifiedChanges
|
|
259
|
-
meta: stringifiedMeta,
|
|
305
|
+
changes: stringifiedChanges as Stringified<JsonValue[]>,
|
|
306
|
+
meta: stringifiedMeta as Stringified<JsonObject> | undefined,
|
|
260
307
|
};
|
|
261
308
|
return { signature: output as Signature, transaction };
|
|
262
309
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { initialize } from "cojson-core-wasm/edge-lite";
|
|
1
|
+
import { initialize, initializeSync } from "cojson-core-wasm/edge-lite";
|
|
2
2
|
import { WasmCrypto } from "./WasmCrypto.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -12,3 +12,7 @@ import { WasmCrypto } from "./WasmCrypto.js";
|
|
|
12
12
|
export const init = async () => {
|
|
13
13
|
return initialize();
|
|
14
14
|
};
|
|
15
|
+
|
|
16
|
+
export const initSync = () => {
|
|
17
|
+
return initializeSync();
|
|
18
|
+
};
|
package/src/crypto/crypto.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { base58 } from "@scure/base";
|
|
2
2
|
import { ControlledAccountOrAgent, RawAccountID } from "../coValues/account.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
AgentID,
|
|
5
|
+
RawCoID,
|
|
6
|
+
TransactionID,
|
|
7
|
+
SessionID,
|
|
8
|
+
ActiveSessionID,
|
|
9
|
+
DeleteSessionID,
|
|
10
|
+
} from "../ids.js";
|
|
5
11
|
import { Stringified, parseJSON, stableStringify } from "../jsonStringify.js";
|
|
6
12
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
7
13
|
import { logger } from "../logger.js";
|
|
@@ -246,8 +252,14 @@ export abstract class CryptoProvider<Blake3State = any> {
|
|
|
246
252
|
)}`;
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
newRandomSessionID(accountID: RawAccountID | AgentID):
|
|
250
|
-
|
|
255
|
+
newRandomSessionID(accountID: RawAccountID | AgentID): ActiveSessionID {
|
|
256
|
+
const randomPart = base58.encode(this.randomBytes(8));
|
|
257
|
+
return `${accountID}_session_z${randomPart}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
newDeleteSessionID(accountID: RawAccountID | AgentID): DeleteSessionID {
|
|
261
|
+
const randomPart = base58.encode(this.randomBytes(7));
|
|
262
|
+
return `${accountID}_session_d${randomPart}$`;
|
|
251
263
|
}
|
|
252
264
|
|
|
253
265
|
abstract createSessionLog(
|
package/src/exports.ts
CHANGED
|
@@ -77,6 +77,7 @@ import { emptyKnownState } from "./knownState.js";
|
|
|
77
77
|
import {
|
|
78
78
|
getContentMessageSize,
|
|
79
79
|
getTransactionSize,
|
|
80
|
+
knownStateFromContent,
|
|
80
81
|
} from "./coValueContentMessage.js";
|
|
81
82
|
import { getDependedOnCoValuesFromRawData } from "./coValueCore/utils.js";
|
|
82
83
|
import {
|
|
@@ -87,8 +88,8 @@ import {
|
|
|
87
88
|
setCoValueLoadingRetryDelay,
|
|
88
89
|
setCoValueLoadingTimeout,
|
|
89
90
|
setIncomingMessagesTimeBudget,
|
|
91
|
+
setMaxInFlightLoadsPerPeer,
|
|
90
92
|
setMaxOutgoingMessagesChunkBytes,
|
|
91
|
-
setOutgoingMessagesChunkDelay,
|
|
92
93
|
setMaxRecommendedTxSize,
|
|
93
94
|
} from "./config.js";
|
|
94
95
|
import { LogLevel, logger } from "./logger.js";
|
|
@@ -102,6 +103,7 @@ type Value = JsonValue | AnyRawCoValue;
|
|
|
102
103
|
export { PriorityBasedMessageQueue } from "./queue/PriorityBasedMessageQueue.js";
|
|
103
104
|
/** @hidden */
|
|
104
105
|
export const cojsonInternals = {
|
|
106
|
+
knownStateFromContent,
|
|
105
107
|
connectedPeers,
|
|
106
108
|
rawCoIDtoBytes,
|
|
107
109
|
rawCoIDfromBytes,
|
|
@@ -140,7 +142,7 @@ export const cojsonInternals = {
|
|
|
140
142
|
canBeBranched,
|
|
141
143
|
WEBSOCKET_CONFIG,
|
|
142
144
|
setMaxOutgoingMessagesChunkBytes,
|
|
143
|
-
|
|
145
|
+
setMaxInFlightLoadsPerPeer,
|
|
144
146
|
};
|
|
145
147
|
|
|
146
148
|
export {
|
package/src/ids.ts
CHANGED
|
@@ -36,7 +36,17 @@ export function isAgentID(id: unknown): id is AgentID {
|
|
|
36
36
|
);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export type
|
|
39
|
+
export type ActiveSessionID = `${RawAccountID | AgentID}_session_z${string}`;
|
|
40
|
+
export type DeleteSessionID = `${RawAccountID | AgentID}_session_d${string}$`;
|
|
41
|
+
export type SessionID = ActiveSessionID | DeleteSessionID;
|
|
42
|
+
|
|
43
|
+
const CHAR_DOLLAR = "$".charCodeAt(0);
|
|
44
|
+
|
|
45
|
+
export function isDeleteSessionID(
|
|
46
|
+
sessionID: SessionID,
|
|
47
|
+
): sessionID is DeleteSessionID {
|
|
48
|
+
return sessionID.charCodeAt(sessionID.length - 1) === CHAR_DOLLAR;
|
|
49
|
+
}
|
|
40
50
|
|
|
41
51
|
export function isParentGroupReference(
|
|
42
52
|
key: string,
|
package/src/localNode.ts
CHANGED
|
@@ -101,6 +101,21 @@ export class LocalNode {
|
|
|
101
101
|
this.syncManager.removeStorage();
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Enable background erasure of deleted coValues (space reclamation).
|
|
106
|
+
*
|
|
107
|
+
* Deleted coValues are immediately blocked from syncing via tombstones; this feature
|
|
108
|
+
* only reclaims local storage space by deleting historical content while preserving
|
|
109
|
+
* the tombstone (header + delete session).
|
|
110
|
+
*
|
|
111
|
+
* This is opt-in and affects only the currently configured storage (if any)
|
|
112
|
+
*
|
|
113
|
+
* @category 3. Low-level
|
|
114
|
+
*/
|
|
115
|
+
enableDeletedCoValuesErasure() {
|
|
116
|
+
this.storage?.enableDeletedCoValuesErasure();
|
|
117
|
+
}
|
|
118
|
+
|
|
104
119
|
hasCoValue(id: RawCoID) {
|
|
105
120
|
const coValue = this.coValues.get(id);
|
|
106
121
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function isCloudflare() {
|
|
2
|
+
if (
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
typeof navigator !== "undefined" &&
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
navigator?.userAgent?.includes("Cloudflare")
|
|
7
|
+
) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const isEvalAllowed = () => {
|
|
15
|
+
if (isCloudflare()) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const F = Function;
|
|
21
|
+
new F("");
|
|
22
|
+
return true;
|
|
23
|
+
} catch (_) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
};
|