cojson 0.9.9 → 0.9.11
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 +3 -3
- package/CHANGELOG.md +13 -0
- package/dist/native/PeerState.js +2 -1
- package/dist/native/PeerState.js.map +1 -1
- package/dist/native/PriorityBasedMessageQueue.js +54 -7
- package/dist/native/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/native/base64url.js +0 -6
- package/dist/native/base64url.js.map +1 -1
- package/dist/native/coValue.js +27 -0
- package/dist/native/coValue.js.map +1 -1
- package/dist/native/coValueCore.js +30 -177
- package/dist/native/coValueCore.js.map +1 -1
- package/dist/native/coValueState.js +5 -4
- package/dist/native/coValueState.js.map +1 -1
- package/dist/native/coValues/account.js +2 -1
- package/dist/native/coValues/account.js.map +1 -1
- package/dist/native/coValues/coList.js +0 -7
- package/dist/native/coValues/coList.js.map +1 -1
- package/dist/native/coValues/coStream.js +3 -8
- package/dist/native/coValues/coStream.js.map +1 -1
- package/dist/native/coValues/group.js +3 -2
- package/dist/native/coValues/group.js.map +1 -1
- package/dist/native/coreToCoValue.js +2 -1
- package/dist/native/coreToCoValue.js.map +1 -1
- package/dist/native/crypto/PureJSCrypto.js +2 -1
- package/dist/native/crypto/PureJSCrypto.js.map +1 -1
- package/dist/native/crypto/WasmCrypto.js +2 -1
- package/dist/native/crypto/WasmCrypto.js.map +1 -1
- package/dist/native/crypto/crypto.js +2 -4
- package/dist/native/crypto/crypto.js.map +1 -1
- package/dist/native/exports.js +2 -1
- package/dist/native/exports.js.map +1 -1
- package/dist/native/localNode.js +5 -6
- package/dist/native/localNode.js.map +1 -1
- package/dist/native/logger.js +58 -0
- package/dist/native/logger.js.map +1 -0
- package/dist/native/permissions.js +3 -4
- package/dist/native/permissions.js.map +1 -1
- package/dist/native/storage/FileSystem.js +0 -10
- package/dist/native/storage/FileSystem.js.map +1 -1
- package/dist/native/storage/index.js +14 -23
- package/dist/native/storage/index.js.map +1 -1
- package/dist/native/sync.js +20 -28
- package/dist/native/sync.js.map +1 -1
- package/dist/web/PeerState.js +2 -1
- package/dist/web/PeerState.js.map +1 -1
- package/dist/web/PriorityBasedMessageQueue.js +54 -7
- package/dist/web/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/web/base64url.js +0 -6
- package/dist/web/base64url.js.map +1 -1
- package/dist/web/coValue.js +27 -0
- package/dist/web/coValue.js.map +1 -1
- package/dist/web/coValueCore.js +30 -177
- package/dist/web/coValueCore.js.map +1 -1
- package/dist/web/coValueState.js +5 -4
- package/dist/web/coValueState.js.map +1 -1
- package/dist/web/coValues/account.js +2 -1
- package/dist/web/coValues/account.js.map +1 -1
- package/dist/web/coValues/coList.js +0 -7
- package/dist/web/coValues/coList.js.map +1 -1
- package/dist/web/coValues/coStream.js +3 -8
- package/dist/web/coValues/coStream.js.map +1 -1
- package/dist/web/coValues/group.js +3 -2
- package/dist/web/coValues/group.js.map +1 -1
- package/dist/web/coreToCoValue.js +2 -1
- package/dist/web/coreToCoValue.js.map +1 -1
- package/dist/web/crypto/PureJSCrypto.js +2 -1
- package/dist/web/crypto/PureJSCrypto.js.map +1 -1
- package/dist/web/crypto/WasmCrypto.js +2 -1
- package/dist/web/crypto/WasmCrypto.js.map +1 -1
- package/dist/web/crypto/crypto.js +2 -4
- package/dist/web/crypto/crypto.js.map +1 -1
- package/dist/web/exports.js +2 -1
- package/dist/web/exports.js.map +1 -1
- package/dist/web/localNode.js +5 -6
- package/dist/web/localNode.js.map +1 -1
- package/dist/web/logger.js +58 -0
- package/dist/web/logger.js.map +1 -0
- package/dist/web/permissions.js +3 -4
- package/dist/web/permissions.js.map +1 -1
- package/dist/web/storage/FileSystem.js +0 -10
- package/dist/web/storage/FileSystem.js.map +1 -1
- package/dist/web/storage/index.js +14 -23
- package/dist/web/storage/index.js.map +1 -1
- package/dist/web/sync.js +20 -28
- package/dist/web/sync.js.map +1 -1
- package/package.json +1 -1
- package/src/PeerState.ts +4 -3
- package/src/PriorityBasedMessageQueue.ts +67 -11
- package/src/base64url.ts +1 -6
- package/src/coValue.ts +37 -0
- package/src/coValueCore.ts +34 -180
- package/src/coValueState.ts +5 -4
- package/src/coValues/account.ts +2 -1
- package/src/coValues/coList.ts +0 -7
- package/src/coValues/coStream.ts +3 -8
- package/src/coValues/group.ts +3 -2
- package/src/coreToCoValue.ts +2 -1
- package/src/crypto/PureJSCrypto.ts +2 -1
- package/src/crypto/WasmCrypto.ts +2 -1
- package/src/crypto/crypto.ts +2 -4
- package/src/exports.ts +2 -0
- package/src/localNode.ts +5 -9
- package/src/logger.ts +78 -0
- package/src/permissions.ts +3 -5
- package/src/storage/FileSystem.ts +0 -12
- package/src/storage/index.ts +21 -37
- package/src/sync.ts +20 -29
- package/src/tests/PeerState.test.ts +0 -3
- package/src/tests/PriorityBasedMessageQueue.test.ts +1 -1
- package/src/tests/coValueCore.test.ts +32 -2
- package/src/tests/logger.test.ts +145 -0
- package/src/tests/sync.test.ts +43 -0
- package/src/tests/testUtils.ts +19 -0
package/src/PeerState.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "./PriorityBasedMessageQueue.js";
|
|
6
6
|
import { TryAddTransactionsError } from "./coValueCore.js";
|
|
7
7
|
import { RawCoID } from "./ids.js";
|
|
8
|
+
import { logger } from "./logger.js";
|
|
8
9
|
import { CO_VALUE_PRIORITY } from "./priority.js";
|
|
9
10
|
import { Peer, SyncMessage } from "./sync.js";
|
|
10
11
|
|
|
@@ -92,7 +93,7 @@ export class PeerState {
|
|
|
92
93
|
|
|
93
94
|
this.processing = true;
|
|
94
95
|
|
|
95
|
-
let entry: QueueEntry | undefined;
|
|
96
|
+
let entry: QueueEntry<SyncMessage> | undefined;
|
|
96
97
|
while ((entry = this.queue.pull())) {
|
|
97
98
|
// Awaiting the push to send one message at a time
|
|
98
99
|
// This way when the peer is "under pressure" we can enqueue all
|
|
@@ -129,7 +130,7 @@ export class PeerState {
|
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
private closeQueue() {
|
|
132
|
-
let entry: QueueEntry | undefined;
|
|
133
|
+
let entry: QueueEntry<SyncMessage> | undefined;
|
|
133
134
|
while ((entry = this.queue.pull())) {
|
|
134
135
|
// Using resolve here to avoid unnecessary noise in the logs
|
|
135
136
|
entry.resolve();
|
|
@@ -137,7 +138,7 @@ export class PeerState {
|
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
gracefulShutdown() {
|
|
140
|
-
|
|
141
|
+
logger.debug("Gracefully closing", this.id);
|
|
141
142
|
this.closeQueue();
|
|
142
143
|
this.peer.outgoing.close();
|
|
143
144
|
this.closed = true;
|
|
@@ -18,11 +18,12 @@ function promiseWithResolvers<R>() {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export type QueueEntry = {
|
|
22
|
-
msg:
|
|
21
|
+
export type QueueEntry<V> = {
|
|
22
|
+
msg: V;
|
|
23
23
|
promise: Promise<void>;
|
|
24
24
|
resolve: () => void;
|
|
25
25
|
reject: (_: unknown) => void;
|
|
26
|
+
next: QueueEntry<V> | undefined;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -33,10 +34,68 @@ type Tuple<T, N extends number, A extends unknown[] = []> = A extends {
|
|
|
33
34
|
}
|
|
34
35
|
? A
|
|
35
36
|
: Tuple<T, N, [...A, T]>;
|
|
36
|
-
type QueueTuple = Tuple<
|
|
37
|
+
type QueueTuple = Tuple<Queue<SyncMessage>, 8>;
|
|
38
|
+
|
|
39
|
+
class Queue<V> {
|
|
40
|
+
head: QueueEntry<V> | undefined = undefined;
|
|
41
|
+
tail: QueueEntry<V> | undefined = undefined;
|
|
42
|
+
|
|
43
|
+
push(msg: V) {
|
|
44
|
+
const { promise, resolve, reject } = promiseWithResolvers<void>();
|
|
45
|
+
const entry: QueueEntry<V> = {
|
|
46
|
+
msg,
|
|
47
|
+
promise,
|
|
48
|
+
resolve,
|
|
49
|
+
reject,
|
|
50
|
+
next: undefined,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (this.head === undefined) {
|
|
54
|
+
this.head = entry;
|
|
55
|
+
} else {
|
|
56
|
+
if (this.tail === undefined) {
|
|
57
|
+
throw new Error("Tail is null but head is not");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.tail.next = entry;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.tail = entry;
|
|
64
|
+
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
pull() {
|
|
69
|
+
const entry = this.head;
|
|
70
|
+
|
|
71
|
+
if (entry) {
|
|
72
|
+
this.head = entry.next;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.head === undefined) {
|
|
76
|
+
this.tail = undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return entry;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
isNonEmpty() {
|
|
83
|
+
return this.head !== undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
37
86
|
|
|
38
87
|
export class PriorityBasedMessageQueue {
|
|
39
|
-
private queues: QueueTuple = [
|
|
88
|
+
private queues: QueueTuple = [
|
|
89
|
+
new Queue(),
|
|
90
|
+
new Queue(),
|
|
91
|
+
new Queue(),
|
|
92
|
+
new Queue(),
|
|
93
|
+
new Queue(),
|
|
94
|
+
new Queue(),
|
|
95
|
+
new Queue(),
|
|
96
|
+
new Queue(),
|
|
97
|
+
];
|
|
98
|
+
|
|
40
99
|
queueSizeCounter = metrics
|
|
41
100
|
.getMeter("cojson")
|
|
42
101
|
.createUpDownCounter("jazz.messagequeue.size", {
|
|
@@ -52,22 +111,19 @@ export class PriorityBasedMessageQueue {
|
|
|
52
111
|
constructor(private defaultPriority: CoValuePriority) {}
|
|
53
112
|
|
|
54
113
|
public push(msg: SyncMessage) {
|
|
55
|
-
const { promise, resolve, reject } = promiseWithResolvers<void>();
|
|
56
|
-
const entry: QueueEntry = { msg, promise, resolve, reject };
|
|
57
|
-
|
|
58
114
|
const priority = "priority" in msg ? msg.priority : this.defaultPriority;
|
|
59
115
|
|
|
60
|
-
this.getQueue(priority).push(
|
|
116
|
+
const entry = this.getQueue(priority).push(msg);
|
|
61
117
|
|
|
62
118
|
this.queueSizeCounter.add(1, {
|
|
63
119
|
priority,
|
|
64
120
|
});
|
|
65
121
|
|
|
66
|
-
return promise;
|
|
122
|
+
return entry.promise;
|
|
67
123
|
}
|
|
68
124
|
|
|
69
125
|
public pull() {
|
|
70
|
-
const priority = this.queues.findIndex((queue) => queue.
|
|
126
|
+
const priority = this.queues.findIndex((queue) => queue.isNonEmpty());
|
|
71
127
|
|
|
72
128
|
if (priority === -1) {
|
|
73
129
|
return;
|
|
@@ -77,6 +133,6 @@ export class PriorityBasedMessageQueue {
|
|
|
77
133
|
priority,
|
|
78
134
|
});
|
|
79
135
|
|
|
80
|
-
return this.queues[priority]?.
|
|
136
|
+
return this.queues[priority]?.pull();
|
|
81
137
|
}
|
|
82
138
|
}
|
package/src/base64url.ts
CHANGED
|
@@ -43,12 +43,7 @@ export function bytesToBase64url(bytes: Uint8Array) {
|
|
|
43
43
|
let base64 = decoder.decode(new Uint8Array(encoded.buffer, 0, n));
|
|
44
44
|
if (k === 1) base64 += "==";
|
|
45
45
|
if (k === 2) base64 += "=";
|
|
46
|
-
|
|
47
|
-
// console.log(
|
|
48
|
-
// "bytesToBase64url bandwidth in MB/s for length",
|
|
49
|
-
// (1000 * bytes.length / (after - before)) / (1024 * 1024),
|
|
50
|
-
// bytes.length
|
|
51
|
-
// );
|
|
46
|
+
|
|
52
47
|
return base64;
|
|
53
48
|
}
|
|
54
49
|
|
package/src/coValue.ts
CHANGED
|
@@ -35,6 +35,43 @@ export interface RawCoValue {
|
|
|
35
35
|
subscribe(listener: (coValue: this) => void): () => void;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export class RawUnknownCoValue implements RawCoValue {
|
|
39
|
+
id: CoID<this>;
|
|
40
|
+
core: CoValueCore;
|
|
41
|
+
|
|
42
|
+
constructor(core: CoValueCore) {
|
|
43
|
+
this.id = core.id as CoID<this>;
|
|
44
|
+
this.core = core;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get type() {
|
|
48
|
+
return this.core.header.type;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get headerMeta() {
|
|
52
|
+
return this.core.header.meta as JsonObject;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @category 6. Meta */
|
|
56
|
+
get group(): RawGroup {
|
|
57
|
+
return this.core.getGroup();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toJSON() {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
atTime() {
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
subscribe(listener: (value: this) => void): () => void {
|
|
69
|
+
return this.core.subscribe((content) => {
|
|
70
|
+
listener(content as this);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
38
75
|
export type AnyRawCoValue =
|
|
39
76
|
| RawCoMap
|
|
40
77
|
| RawGroup
|
package/src/coValueCore.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { Stringified, parseJSON, stableStringify } from "./jsonStringify.js";
|
|
25
25
|
import { JsonObject, JsonValue } from "./jsonValue.js";
|
|
26
26
|
import { LocalNode, ResolveAccountAgentError } from "./localNode.js";
|
|
27
|
+
import { logger } from "./logger.js";
|
|
27
28
|
import {
|
|
28
29
|
PermissionsDef as RulesetDef,
|
|
29
30
|
determineValidTransactions,
|
|
@@ -126,10 +127,7 @@ export class CoValueCore {
|
|
|
126
127
|
.expectCoValueLoaded(header.ruleset.group)
|
|
127
128
|
.subscribe((_groupUpdate) => {
|
|
128
129
|
this._cachedContent = undefined;
|
|
129
|
-
|
|
130
|
-
for (const listener of this.listeners) {
|
|
131
|
-
listener(newContent);
|
|
132
|
-
}
|
|
130
|
+
this.notifyUpdate("immediate");
|
|
133
131
|
});
|
|
134
132
|
}
|
|
135
133
|
}
|
|
@@ -212,16 +210,10 @@ export class CoValueCore {
|
|
|
212
210
|
.andThen((agent) => {
|
|
213
211
|
const signerID = this.crypto.getAgentSignerID(agent);
|
|
214
212
|
|
|
215
|
-
// const beforeHash = performance.now();
|
|
216
213
|
const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(
|
|
217
214
|
sessionID,
|
|
218
215
|
newTransactions,
|
|
219
216
|
);
|
|
220
|
-
// const afterHash = performance.now();
|
|
221
|
-
// console.log(
|
|
222
|
-
// "Hashing took",
|
|
223
|
-
// afterHash - beforeHash
|
|
224
|
-
// );
|
|
225
217
|
|
|
226
218
|
if (givenExpectedNewHash && givenExpectedNewHash !== expectedNewHash) {
|
|
227
219
|
return err({
|
|
@@ -244,11 +236,6 @@ export class CoValueCore {
|
|
|
244
236
|
signerID,
|
|
245
237
|
} satisfies InvalidSignatureError);
|
|
246
238
|
}
|
|
247
|
-
// const afterVerify = performance.now();
|
|
248
|
-
// console.log(
|
|
249
|
-
// "Verify took",
|
|
250
|
-
// afterVerify - beforeVerify
|
|
251
|
-
// );
|
|
252
239
|
|
|
253
240
|
this.doAddTransactions(
|
|
254
241
|
sessionID,
|
|
@@ -263,138 +250,6 @@ export class CoValueCore {
|
|
|
263
250
|
});
|
|
264
251
|
}
|
|
265
252
|
|
|
266
|
-
/*tryAddTransactionsAsync(
|
|
267
|
-
sessionID: SessionID,
|
|
268
|
-
newTransactions: Transaction[],
|
|
269
|
-
givenExpectedNewHash: Hash | undefined,
|
|
270
|
-
newSignature: Signature,
|
|
271
|
-
): ResultAsync<true, TryAddTransactionsError> {
|
|
272
|
-
const currentAsyncAddTransaction = this._currentAsyncAddTransaction;
|
|
273
|
-
let maybeAwaitPrevious:
|
|
274
|
-
| ResultAsync<void, TryAddTransactionsError>
|
|
275
|
-
| undefined;
|
|
276
|
-
let thisDone = () => {};
|
|
277
|
-
|
|
278
|
-
if (currentAsyncAddTransaction) {
|
|
279
|
-
// eslint-disable-next-line neverthrow/must-use-result
|
|
280
|
-
maybeAwaitPrevious = ResultAsync.fromSafePromise(
|
|
281
|
-
currentAsyncAddTransaction,
|
|
282
|
-
);
|
|
283
|
-
} else {
|
|
284
|
-
// eslint-disable-next-line neverthrow/must-use-result
|
|
285
|
-
maybeAwaitPrevious = ResultAsync.fromSafePromise(Promise.resolve());
|
|
286
|
-
this._currentAsyncAddTransaction = new Promise((resolve) => {
|
|
287
|
-
thisDone = resolve;
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return maybeAwaitPrevious
|
|
292
|
-
.andThen((_previousDone) =>
|
|
293
|
-
this.node
|
|
294
|
-
.resolveAccountAgentAsync(
|
|
295
|
-
accountOrAgentIDfromSessionID(sessionID),
|
|
296
|
-
"Expected to know signer of transaction",
|
|
297
|
-
)
|
|
298
|
-
.andThen((agent) => {
|
|
299
|
-
const signerID = this.crypto.getAgentSignerID(agent);
|
|
300
|
-
|
|
301
|
-
const nTxBefore =
|
|
302
|
-
this.sessionLogs.get(sessionID)?.transactions
|
|
303
|
-
.length ?? 0;
|
|
304
|
-
|
|
305
|
-
// const beforeHash = performance.now();
|
|
306
|
-
return ResultAsync.fromSafePromise(
|
|
307
|
-
this.expectedNewHashAfterAsync(
|
|
308
|
-
sessionID,
|
|
309
|
-
newTransactions,
|
|
310
|
-
),
|
|
311
|
-
).andThen(({ expectedNewHash, newStreamingHash }) => {
|
|
312
|
-
// const afterHash = performance.now();
|
|
313
|
-
// console.log(
|
|
314
|
-
// "Hashing took",
|
|
315
|
-
// afterHash - beforeHash
|
|
316
|
-
// );
|
|
317
|
-
|
|
318
|
-
const nTxAfter =
|
|
319
|
-
this.sessionLogs.get(sessionID)?.transactions
|
|
320
|
-
.length ?? 0;
|
|
321
|
-
|
|
322
|
-
if (nTxAfter !== nTxBefore) {
|
|
323
|
-
const newTransactionLengthBefore =
|
|
324
|
-
newTransactions.length;
|
|
325
|
-
newTransactions = newTransactions.slice(
|
|
326
|
-
nTxAfter - nTxBefore,
|
|
327
|
-
);
|
|
328
|
-
console.warn(
|
|
329
|
-
"Transactions changed while async hashing",
|
|
330
|
-
{
|
|
331
|
-
nTxBefore,
|
|
332
|
-
nTxAfter,
|
|
333
|
-
newTransactionLengthBefore,
|
|
334
|
-
remainingNewTransactions:
|
|
335
|
-
newTransactions.length,
|
|
336
|
-
},
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (
|
|
341
|
-
givenExpectedNewHash &&
|
|
342
|
-
givenExpectedNewHash !== expectedNewHash
|
|
343
|
-
) {
|
|
344
|
-
return err({
|
|
345
|
-
type: "InvalidHash",
|
|
346
|
-
id: this.id,
|
|
347
|
-
expectedNewHash,
|
|
348
|
-
givenExpectedNewHash,
|
|
349
|
-
} satisfies InvalidHashError);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
performance.mark("verifyStart" + this.id);
|
|
353
|
-
if (
|
|
354
|
-
!this.crypto.verify(
|
|
355
|
-
newSignature,
|
|
356
|
-
expectedNewHash,
|
|
357
|
-
signerID,
|
|
358
|
-
)
|
|
359
|
-
) {
|
|
360
|
-
return err({
|
|
361
|
-
type: "InvalidSignature",
|
|
362
|
-
id: this.id,
|
|
363
|
-
newSignature,
|
|
364
|
-
sessionID,
|
|
365
|
-
signerID,
|
|
366
|
-
} satisfies InvalidSignatureError);
|
|
367
|
-
}
|
|
368
|
-
performance.mark("verifyEnd" + this.id);
|
|
369
|
-
performance.measure(
|
|
370
|
-
"verify" + this.id,
|
|
371
|
-
"verifyStart" + this.id,
|
|
372
|
-
"verifyEnd" + this.id,
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
this.doAddTransactions(
|
|
376
|
-
sessionID,
|
|
377
|
-
newTransactions,
|
|
378
|
-
newSignature,
|
|
379
|
-
expectedNewHash,
|
|
380
|
-
newStreamingHash,
|
|
381
|
-
"deferred",
|
|
382
|
-
);
|
|
383
|
-
|
|
384
|
-
return ok(true as const);
|
|
385
|
-
});
|
|
386
|
-
}),
|
|
387
|
-
)
|
|
388
|
-
.map((trueResult) => {
|
|
389
|
-
thisDone();
|
|
390
|
-
return trueResult;
|
|
391
|
-
})
|
|
392
|
-
.mapErr((err) => {
|
|
393
|
-
thisDone();
|
|
394
|
-
return err;
|
|
395
|
-
});
|
|
396
|
-
}*/
|
|
397
|
-
|
|
398
253
|
private doAddTransactions(
|
|
399
254
|
sessionID: SessionID,
|
|
400
255
|
newTransactions: Transaction[],
|
|
@@ -432,12 +287,6 @@ export class CoValueCore {
|
|
|
432
287
|
);
|
|
433
288
|
|
|
434
289
|
if (sizeOfTxsSinceLastInbetweenSignature > MAX_RECOMMENDED_TX_SIZE) {
|
|
435
|
-
// console.log(
|
|
436
|
-
// "Saving inbetween signature for tx ",
|
|
437
|
-
// sessionID,
|
|
438
|
-
// transactions.length - 1,
|
|
439
|
-
// sizeOfTxsSinceLastInbetweenSignature
|
|
440
|
-
// );
|
|
441
290
|
signatureAfter[transactions.length - 1] = newSignature;
|
|
442
291
|
}
|
|
443
292
|
|
|
@@ -463,34 +312,40 @@ export class CoValueCore {
|
|
|
463
312
|
this._cachedDependentOn = undefined;
|
|
464
313
|
this._cachedNewContentSinceEmpty = undefined;
|
|
465
314
|
|
|
466
|
-
|
|
467
|
-
if (notifyMode === "immediate") {
|
|
468
|
-
const content = this.getCurrentContent();
|
|
469
|
-
for (const listener of this.listeners) {
|
|
470
|
-
listener(content);
|
|
471
|
-
}
|
|
472
|
-
} else {
|
|
473
|
-
if (!this.nextDeferredNotify) {
|
|
474
|
-
this.nextDeferredNotify = new Promise((resolve) => {
|
|
475
|
-
setTimeout(() => {
|
|
476
|
-
this.nextDeferredNotify = undefined;
|
|
477
|
-
this.deferredUpdates = 0;
|
|
478
|
-
const content = this.getCurrentContent();
|
|
479
|
-
for (const listener of this.listeners) {
|
|
480
|
-
listener(content);
|
|
481
|
-
}
|
|
482
|
-
resolve();
|
|
483
|
-
}, 0);
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
this.deferredUpdates++;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
315
|
+
this.notifyUpdate(notifyMode);
|
|
489
316
|
}
|
|
490
317
|
|
|
491
318
|
deferredUpdates = 0;
|
|
492
319
|
nextDeferredNotify: Promise<void> | undefined;
|
|
493
320
|
|
|
321
|
+
notifyUpdate(notifyMode: "immediate" | "deferred") {
|
|
322
|
+
if (this.listeners.size === 0) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (notifyMode === "immediate") {
|
|
327
|
+
const content = this.getCurrentContent();
|
|
328
|
+
for (const listener of this.listeners) {
|
|
329
|
+
listener(content);
|
|
330
|
+
}
|
|
331
|
+
} else {
|
|
332
|
+
if (!this.nextDeferredNotify) {
|
|
333
|
+
this.nextDeferredNotify = new Promise((resolve) => {
|
|
334
|
+
setTimeout(() => {
|
|
335
|
+
this.nextDeferredNotify = undefined;
|
|
336
|
+
this.deferredUpdates = 0;
|
|
337
|
+
const content = this.getCurrentContent();
|
|
338
|
+
for (const listener of this.listeners) {
|
|
339
|
+
listener(content);
|
|
340
|
+
}
|
|
341
|
+
resolve();
|
|
342
|
+
}, 0);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
this.deferredUpdates++;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
494
349
|
subscribe(listener: (content?: RawCoValue) => void): () => void {
|
|
495
350
|
this.listeners.add(listener);
|
|
496
351
|
listener(this.getCurrentContent());
|
|
@@ -531,7 +386,6 @@ export class CoValueCore {
|
|
|
531
386
|
streamingHash.update(transaction);
|
|
532
387
|
const after = performance.now();
|
|
533
388
|
if (after - before > 1) {
|
|
534
|
-
// console.log("Hashing blocked for", after - before);
|
|
535
389
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
536
390
|
before = performance.now();
|
|
537
391
|
}
|
|
@@ -680,7 +534,7 @@ export class CoValueCore {
|
|
|
680
534
|
}
|
|
681
535
|
|
|
682
536
|
if (!decryptedChanges) {
|
|
683
|
-
|
|
537
|
+
logger.error("Failed to decrypt transaction despite having key");
|
|
684
538
|
continue;
|
|
685
539
|
}
|
|
686
540
|
|
|
@@ -825,7 +679,7 @@ export class CoValueCore {
|
|
|
825
679
|
if (secret) {
|
|
826
680
|
return secret as KeySecret;
|
|
827
681
|
} else {
|
|
828
|
-
|
|
682
|
+
logger.warn(
|
|
829
683
|
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
|
|
830
684
|
);
|
|
831
685
|
}
|
|
@@ -865,7 +719,7 @@ export class CoValueCore {
|
|
|
865
719
|
if (secret) {
|
|
866
720
|
return secret as KeySecret;
|
|
867
721
|
} else {
|
|
868
|
-
|
|
722
|
+
logger.warn(
|
|
869
723
|
`Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`,
|
|
870
724
|
);
|
|
871
725
|
}
|
package/src/coValueState.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PeerState } from "./PeerState.js";
|
|
2
2
|
import { CoValueCore } from "./coValueCore.js";
|
|
3
3
|
import { RawCoID } from "./ids.js";
|
|
4
|
+
import { logger } from "./logger.js";
|
|
4
5
|
import { PeerID } from "./sync.js";
|
|
5
6
|
|
|
6
7
|
export const CO_VALUE_LOADING_MAX_RETRIES = 5;
|
|
@@ -282,7 +283,7 @@ async function loadCoValueFromPeers(
|
|
|
282
283
|
...coValueEntry.state.coValue.knownState(),
|
|
283
284
|
})
|
|
284
285
|
.catch((err) => {
|
|
285
|
-
|
|
286
|
+
logger.warn(`Failed to push load message to peer ${peer.id}`, err);
|
|
286
287
|
});
|
|
287
288
|
} else {
|
|
288
289
|
/**
|
|
@@ -296,14 +297,14 @@ async function loadCoValueFromPeers(
|
|
|
296
297
|
sessions: {},
|
|
297
298
|
})
|
|
298
299
|
.catch((err) => {
|
|
299
|
-
|
|
300
|
+
logger.warn(`Failed to push load message to peer ${peer.id}`, err);
|
|
300
301
|
});
|
|
301
302
|
}
|
|
302
303
|
|
|
303
304
|
if (coValueEntry.state.type === "loading") {
|
|
304
305
|
const timeout = setTimeout(() => {
|
|
305
306
|
if (coValueEntry.state.type === "loading") {
|
|
306
|
-
|
|
307
|
+
logger.warn("Failed to load coValue from peer", peer.id);
|
|
307
308
|
coValueEntry.dispatch({
|
|
308
309
|
type: "not-found-in-peer",
|
|
309
310
|
peerId: peer.id,
|
|
@@ -356,7 +357,7 @@ function sleep(ms: number) {
|
|
|
356
357
|
function getPeersWithoutErrors(peers: PeerState[], coValueId: RawCoID) {
|
|
357
358
|
return peers.filter((p) => {
|
|
358
359
|
if (p.erroredCoValues.has(coValueId)) {
|
|
359
|
-
|
|
360
|
+
logger.warn(
|
|
360
361
|
`Skipping load on errored coValue ${coValueId} from peer ${p.id}`,
|
|
361
362
|
);
|
|
362
363
|
return false;
|
package/src/coValues/account.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { AgentID } from "../ids.js";
|
|
17
17
|
import { JsonObject } from "../jsonValue.js";
|
|
18
18
|
import { LocalNode } from "../localNode.js";
|
|
19
|
+
import { logger } from "../logger.js";
|
|
19
20
|
import type { AccountRole } from "../permissions.js";
|
|
20
21
|
import { RawCoMap } from "./coMap.js";
|
|
21
22
|
import { InviteSecret, RawGroup } from "./group.js";
|
|
@@ -59,7 +60,7 @@ export class RawAccount<
|
|
|
59
60
|
);
|
|
60
61
|
|
|
61
62
|
if (agents.length !== 1) {
|
|
62
|
-
|
|
63
|
+
logger.warn("Account has " + agents.length + " agents", this.id);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
this._cachedCurrentAgentID = agents[0];
|
package/src/coValues/coList.ts
CHANGED
|
@@ -133,10 +133,6 @@ export class RawCoListView<
|
|
|
133
133
|
change.before.txIndex
|
|
134
134
|
]?.[change.before.changeIdx];
|
|
135
135
|
if (!beforeEntry) {
|
|
136
|
-
// console.error(
|
|
137
|
-
// "Insertion before missing op " +
|
|
138
|
-
// change.before
|
|
139
|
-
// );
|
|
140
136
|
continue;
|
|
141
137
|
}
|
|
142
138
|
beforeEntry.predecessors.splice(0, 0, {
|
|
@@ -156,9 +152,6 @@ export class RawCoListView<
|
|
|
156
152
|
change.after.txIndex
|
|
157
153
|
]?.[change.after.changeIdx];
|
|
158
154
|
if (!afterEntry) {
|
|
159
|
-
// console.error(
|
|
160
|
-
// "Insertion after missing op " + change.after
|
|
161
|
-
// );
|
|
162
155
|
continue;
|
|
163
156
|
}
|
|
164
157
|
afterEntry.successors.push({
|
package/src/coValues/coStream.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { CoID, RawCoValue } from "../coValue.js";
|
|
|
3
3
|
import { CoValueCore } from "../coValueCore.js";
|
|
4
4
|
import { AgentID, SessionID, TransactionID } from "../ids.js";
|
|
5
5
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
6
7
|
import { CoValueKnownState } from "../sync.js";
|
|
7
8
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
8
9
|
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
@@ -309,7 +310,7 @@ export class RawBinaryCoStreamView<
|
|
|
309
310
|
const start = items[0];
|
|
310
311
|
|
|
311
312
|
if (start?.type !== "start") {
|
|
312
|
-
|
|
313
|
+
logger.error("Invalid binary stream start", start);
|
|
313
314
|
return;
|
|
314
315
|
}
|
|
315
316
|
|
|
@@ -328,7 +329,7 @@ export class RawBinaryCoStreamView<
|
|
|
328
329
|
}
|
|
329
330
|
|
|
330
331
|
if (item.type !== "chunk") {
|
|
331
|
-
|
|
332
|
+
logger.error("Invalid binary stream chunk", item);
|
|
332
333
|
return undefined;
|
|
333
334
|
}
|
|
334
335
|
|
|
@@ -382,7 +383,6 @@ export class RawBinaryCoStream<
|
|
|
382
383
|
chunk: Uint8Array,
|
|
383
384
|
privacy: "private" | "trusting" = "private",
|
|
384
385
|
): void {
|
|
385
|
-
// const before = performance.now();
|
|
386
386
|
this.push(
|
|
387
387
|
{
|
|
388
388
|
type: "chunk",
|
|
@@ -391,11 +391,6 @@ export class RawBinaryCoStream<
|
|
|
391
391
|
privacy,
|
|
392
392
|
false,
|
|
393
393
|
);
|
|
394
|
-
// const after = performance.now();
|
|
395
|
-
// console.log(
|
|
396
|
-
// "pushBinaryStreamChunk bandwidth in MB/s",
|
|
397
|
-
// (1000 * chunk.length) / (after - before) / (1024 * 1024)
|
|
398
|
-
// );
|
|
399
394
|
}
|
|
400
395
|
|
|
401
396
|
endBinaryStream(privacy: "private" | "trusting" = "private") {
|
package/src/coValues/group.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isParentGroupReference,
|
|
14
14
|
} from "../ids.js";
|
|
15
15
|
import { JsonObject } from "../jsonValue.js";
|
|
16
|
+
import { logger } from "../logger.js";
|
|
16
17
|
import { AccountRole, Role } from "../permissions.js";
|
|
17
18
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
18
19
|
import {
|
|
@@ -153,7 +154,7 @@ export class RawGroup<
|
|
|
153
154
|
child.state.type === "unavailable"
|
|
154
155
|
) {
|
|
155
156
|
child.loadFromPeers(peers).catch(() => {
|
|
156
|
-
|
|
157
|
+
logger.error(`Failed to load child group ${id}`);
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
160
|
|
|
@@ -321,7 +322,7 @@ export class RawGroup<
|
|
|
321
322
|
const secret = this.core.getReadKey(keyID);
|
|
322
323
|
|
|
323
324
|
if (!secret) {
|
|
324
|
-
|
|
325
|
+
logger.error("Can't find key", keyID);
|
|
325
326
|
continue;
|
|
326
327
|
}
|
|
327
328
|
|
package/src/coreToCoValue.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RawUnknownCoValue } from "./coValue.js";
|
|
1
2
|
import type { CoValueCore } from "./coValueCore.js";
|
|
2
3
|
import { RawAccount, RawControlledAccount } from "./coValues/account.js";
|
|
3
4
|
import { RawCoList } from "./coValues/coList.js";
|
|
@@ -38,6 +39,6 @@ export function coreToCoValue(
|
|
|
38
39
|
return new RawCoStream(core);
|
|
39
40
|
}
|
|
40
41
|
} else {
|
|
41
|
-
|
|
42
|
+
return new RawUnknownCoValue(core);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -7,6 +7,7 @@ import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
|
|
|
7
7
|
import { RawCoID, TransactionID } from "../ids.js";
|
|
8
8
|
import { Stringified, stableStringify } from "../jsonStringify.js";
|
|
9
9
|
import { JsonValue } from "../jsonValue.js";
|
|
10
|
+
import { logger } from "../logger.js";
|
|
10
11
|
import {
|
|
11
12
|
CryptoProvider,
|
|
12
13
|
Encrypted,
|
|
@@ -192,7 +193,7 @@ export class PureJSCrypto extends CryptoProvider<Blake3State> {
|
|
|
192
193
|
try {
|
|
193
194
|
return JSON.parse(textDecoder.decode(plaintext));
|
|
194
195
|
} catch (e) {
|
|
195
|
-
|
|
196
|
+
logger.error("Failed to decrypt/parse sealed message", e);
|
|
196
197
|
return undefined;
|
|
197
198
|
}
|
|
198
199
|
}
|