@weaveprotocol/core 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +244 -39
- package/dist/identity/contact-key.d.ts +42 -0
- package/dist/identity/contact-key.d.ts.map +1 -0
- package/dist/identity/contact-key.js +133 -0
- package/dist/identity/contact-key.js.map +1 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/network/mesh.d.ts +6 -0
- package/dist/network/mesh.d.ts.map +1 -1
- package/dist/network/mesh.js +11 -1
- package/dist/network/mesh.js.map +1 -1
- package/dist/network/multi-signaling.d.ts +12 -2
- package/dist/network/multi-signaling.d.ts.map +1 -1
- package/dist/network/multi-signaling.js +86 -14
- package/dist/network/multi-signaling.js.map +1 -1
- package/dist/network/peer-auth.d.ts +50 -16
- package/dist/network/peer-auth.d.ts.map +1 -1
- package/dist/network/peer-auth.js +52 -15
- package/dist/network/peer-auth.js.map +1 -1
- package/dist/node/carrier.d.ts +87 -0
- package/dist/node/carrier.d.ts.map +1 -1
- package/dist/node/carrier.js +180 -59
- package/dist/node/carrier.js.map +1 -1
- package/dist/node/copy.d.ts.map +1 -1
- package/dist/node/copy.js +6 -3
- package/dist/node/copy.js.map +1 -1
- package/dist/node/host.d.ts +117 -0
- package/dist/node/host.d.ts.map +1 -0
- package/dist/node/host.js +192 -0
- package/dist/node/host.js.map +1 -0
- package/dist/node/index.d.ts +6 -2
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/node.d.ts.map +1 -1
- package/dist/node/node.js +640 -25
- package/dist/node/node.js.map +1 -1
- package/dist/node/space-runtime.d.ts +42 -25
- package/dist/node/space-runtime.d.ts.map +1 -1
- package/dist/node/space-runtime.js +734 -35
- package/dist/node/space-runtime.js.map +1 -1
- package/dist/node/types.d.ts +269 -3
- package/dist/node/types.d.ts.map +1 -1
- package/dist/privacy/space-encryption.d.ts +16 -0
- package/dist/privacy/space-encryption.d.ts.map +1 -1
- package/dist/privacy/space-encryption.js +40 -0
- package/dist/privacy/space-encryption.js.map +1 -1
- package/dist/query/engine.js +1 -1
- package/dist/query/engine.js.map +1 -1
- package/dist/query/types.d.ts +7 -0
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query/types.js.map +1 -1
- package/dist/react/use-query.d.ts +1 -1
- package/dist/react/use-query.d.ts.map +1 -1
- package/dist/records/topics.d.ts +21 -0
- package/dist/records/topics.d.ts.map +1 -0
- package/dist/records/topics.js +86 -0
- package/dist/records/topics.js.map +1 -0
- package/dist/schema/collection-def.d.ts +7 -0
- package/dist/schema/collection-def.d.ts.map +1 -1
- package/dist/schema/collection-def.js +4 -0
- package/dist/schema/collection-def.js.map +1 -1
- package/dist/schema/expression.d.ts +2 -0
- package/dist/schema/expression.d.ts.map +1 -1
- package/dist/schema/expression.js +1 -0
- package/dist/schema/expression.js.map +1 -1
- package/dist/schemas/contacts.d.ts +77 -0
- package/dist/schemas/contacts.d.ts.map +1 -0
- package/dist/schemas/contacts.js +35 -0
- package/dist/schemas/contacts.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/session/auth.d.ts.map +1 -1
- package/dist/session/auth.js +14 -3
- package/dist/session/auth.js.map +1 -1
- package/dist/session/connect.d.ts +25 -1
- package/dist/session/connect.d.ts.map +1 -1
- package/dist/session/connect.js +9 -2
- package/dist/session/connect.js.map +1 -1
- package/dist/session/hosting.d.ts +155 -0
- package/dist/session/hosting.d.ts.map +1 -0
- package/dist/session/hosting.js +160 -0
- package/dist/session/hosting.js.map +1 -0
- package/dist/space/account-registry.d.ts +6 -0
- package/dist/space/account-registry.d.ts.map +1 -1
- package/dist/space/account-registry.js +16 -4
- package/dist/space/account-registry.js.map +1 -1
- package/dist/space/notify.d.ts +88 -0
- package/dist/space/notify.d.ts.map +1 -0
- package/dist/space/notify.js +127 -0
- package/dist/space/notify.js.map +1 -0
- package/dist/space/pass.d.ts +6 -0
- package/dist/space/pass.d.ts.map +1 -1
- package/dist/space/pass.js +5 -2
- package/dist/space/pass.js.map +1 -1
- package/dist/space/roles.d.ts +71 -0
- package/dist/space/roles.d.ts.map +1 -1
- package/dist/space/roles.js +114 -0
- package/dist/space/roles.js.map +1 -1
- package/dist/space/space-access.d.ts +24 -0
- package/dist/space/space-access.d.ts.map +1 -1
- package/dist/space/space-access.js +24 -0
- package/dist/space/space-access.js.map +1 -1
- package/dist/space/space-manager.d.ts +35 -1
- package/dist/space/space-manager.d.ts.map +1 -1
- package/dist/space/space-manager.js +72 -25
- package/dist/space/space-manager.js.map +1 -1
- package/dist/storage/blob/memory.d.ts +9 -0
- package/dist/storage/blob/memory.d.ts.map +1 -0
- package/dist/storage/blob/memory.js +20 -0
- package/dist/storage/blob/memory.js.map +1 -0
- package/dist/storage/blob/s3.d.ts +16 -0
- package/dist/storage/blob/s3.d.ts.map +1 -0
- package/dist/storage/blob/s3.js +86 -0
- package/dist/storage/blob/s3.js.map +1 -0
- package/dist/storage/blob-store.d.ts +26 -0
- package/dist/storage/blob-store.d.ts.map +1 -0
- package/dist/storage/blob-store.js +2 -0
- package/dist/storage/blob-store.js.map +1 -0
- package/dist/storage/encrypted-adapter.d.ts +3 -3
- package/dist/storage/encrypted-adapter.js +3 -3
- package/dist/storage/folder-adapter.d.ts +8 -8
- package/dist/storage/folder-adapter.d.ts.map +1 -1
- package/dist/storage/folder-adapter.js +7 -7
- package/dist/storage/folder-reconcile.d.ts +12 -14
- package/dist/storage/folder-reconcile.d.ts.map +1 -1
- package/dist/storage/folder-reconcile.js +20 -14
- package/dist/storage/folder-reconcile.js.map +1 -1
- package/dist/storage/index.d.ts +0 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +0 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/indexeddb-adapter.d.ts.map +1 -1
- package/dist/storage/indexeddb-adapter.js +8 -9
- package/dist/storage/indexeddb-adapter.js.map +1 -1
- package/dist/storage/mirror.d.ts +68 -0
- package/dist/storage/mirror.d.ts.map +1 -0
- package/dist/storage/mirror.js +174 -0
- package/dist/storage/mirror.js.map +1 -0
- package/dist/storage/segment.d.ts +20 -0
- package/dist/storage/segment.d.ts.map +1 -0
- package/dist/storage/segment.js +27 -0
- package/dist/storage/segment.js.map +1 -0
- package/dist/storage/storage-provider.d.ts +36 -40
- package/dist/storage/storage-provider.d.ts.map +1 -1
- package/dist/storage/storage-provider.js +208 -117
- package/dist/storage/storage-provider.js.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/negentropy.d.ts +68 -0
- package/dist/sync/negentropy.d.ts.map +1 -0
- package/dist/sync/negentropy.js +379 -0
- package/dist/sync/negentropy.js.map +1 -0
- package/dist/sync/sync-engine.d.ts +45 -13
- package/dist/sync/sync-engine.d.ts.map +1 -1
- package/dist/sync/sync-engine.js +290 -207
- package/dist/sync/sync-engine.js.map +1 -1
- package/dist/sync/sync-messages.d.ts +42 -32
- package/dist/sync/sync-messages.d.ts.map +1 -1
- package/dist/sync/sync-messages.js +1 -1
- package/dist/sync/sync-messages.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/hash.d.ts +9 -0
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js +33 -0
- package/dist/utils/hash.js.map +1 -1
- package/package.json +3 -2
- package/dist/storage/mst.d.ts +0 -121
- package/dist/storage/mst.d.ts.map +0 -1
- package/dist/storage/mst.js +0 -402
- package/dist/storage/mst.js.map +0 -1
- package/dist/sync/anti-entropy.d.ts +0 -49
- package/dist/sync/anti-entropy.d.ts.map +0 -1
- package/dist/sync/anti-entropy.js +0 -62
- package/dist/sync/anti-entropy.js.map +0 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module negentropy
|
|
3
|
+
* Range-based set reconciliation: two peers find out which items each lacks
|
|
4
|
+
* by comparing fingerprints of ranges, never by listing everything.
|
|
5
|
+
*
|
|
6
|
+
* This is Negentropy protocol version 1 as Nostr uses it (NIP-77), ported
|
|
7
|
+
* from Doug Hoyte's reference implementation (MIT). Only the wire format is
|
|
8
|
+
* shared; the storage around it is ours.
|
|
9
|
+
*
|
|
10
|
+
* Both sides sort their items by (timestamp, id). The initiator sends
|
|
11
|
+
* fingerprints of a few ranges covering everything. For each range the other
|
|
12
|
+
* side agrees with, nothing more is said. For a range it doesn't, it splits
|
|
13
|
+
* the range into sixteen and answers with their fingerprints, or with the ids
|
|
14
|
+
* themselves once a range is small. A few rounds narrow every difference down
|
|
15
|
+
* to the ids, and the initiator ends up knowing both what it has that the
|
|
16
|
+
* other lacks and what the other has that it lacks.
|
|
17
|
+
*
|
|
18
|
+
* A fingerprint is the sum of the ids in a range, as 256-bit numbers, hashed
|
|
19
|
+
* with the count. A sum can be taken apart and put together again, which is
|
|
20
|
+
* what lets a store keep one per collection and add or subtract as versions
|
|
21
|
+
* come and go.
|
|
22
|
+
*
|
|
23
|
+
* The timestamp only orders items. It never decides which items are compared:
|
|
24
|
+
* a writer who lies about the time makes its own items slower to find, nothing
|
|
25
|
+
* else.
|
|
26
|
+
*/
|
|
27
|
+
import { sha256 } from '../utils/hash.js';
|
|
28
|
+
export const NEGENTROPY_VERSION = 0x61;
|
|
29
|
+
export const ID_SIZE = 32;
|
|
30
|
+
export const FINGERPRINT_SIZE = 16;
|
|
31
|
+
/** Ranges smaller than two buckets' worth go as their ids */
|
|
32
|
+
const BUCKETS = 16;
|
|
33
|
+
/** A timestamp past every real one: the end of the last range */
|
|
34
|
+
const INFINITY = Number.MAX_SAFE_INTEGER;
|
|
35
|
+
var Mode;
|
|
36
|
+
(function (Mode) {
|
|
37
|
+
Mode[Mode["Skip"] = 0] = "Skip";
|
|
38
|
+
Mode[Mode["Fingerprint"] = 1] = "Fingerprint";
|
|
39
|
+
Mode[Mode["IdList"] = 2] = "IdList";
|
|
40
|
+
})(Mode || (Mode = {}));
|
|
41
|
+
// ─── Bytes ─────────────────────────────────────────────────────────
|
|
42
|
+
function compareBytes(a, b) {
|
|
43
|
+
const n = Math.min(a.length, b.length);
|
|
44
|
+
for (let i = 0; i < n; i++)
|
|
45
|
+
if (a[i] !== b[i])
|
|
46
|
+
return a[i] - b[i];
|
|
47
|
+
return a.length - b.length;
|
|
48
|
+
}
|
|
49
|
+
export function compareItems(a, b) {
|
|
50
|
+
return a.timestamp === b.timestamp ? compareBytes(a.id, b.id) : a.timestamp < b.timestamp ? -1 : 1;
|
|
51
|
+
}
|
|
52
|
+
/** Negentropy's varint: seven bits a byte, most significant first. Arithmetic, so it holds past 32 bits. */
|
|
53
|
+
function encodeVarInt(n) {
|
|
54
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
55
|
+
throw new Error('varint out of range');
|
|
56
|
+
const out = [n % 128];
|
|
57
|
+
n = Math.floor(n / 128);
|
|
58
|
+
while (n > 0) {
|
|
59
|
+
out.push((n % 128) | 128);
|
|
60
|
+
n = Math.floor(n / 128);
|
|
61
|
+
}
|
|
62
|
+
return out.reverse();
|
|
63
|
+
}
|
|
64
|
+
class Writer {
|
|
65
|
+
bytes = [];
|
|
66
|
+
get length() {
|
|
67
|
+
return this.bytes.length;
|
|
68
|
+
}
|
|
69
|
+
push(...values) {
|
|
70
|
+
for (const value of values) {
|
|
71
|
+
if (typeof value === 'number')
|
|
72
|
+
this.bytes.push(value);
|
|
73
|
+
else
|
|
74
|
+
for (let i = 0; i < value.length; i++)
|
|
75
|
+
this.bytes.push(value[i]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
append(other) {
|
|
79
|
+
this.push(other.bytes);
|
|
80
|
+
}
|
|
81
|
+
done() {
|
|
82
|
+
return Uint8Array.from(this.bytes);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
class Reader {
|
|
86
|
+
bytes;
|
|
87
|
+
at = 0;
|
|
88
|
+
constructor(bytes) {
|
|
89
|
+
this.bytes = bytes;
|
|
90
|
+
}
|
|
91
|
+
get remaining() {
|
|
92
|
+
return this.bytes.length - this.at;
|
|
93
|
+
}
|
|
94
|
+
byte() {
|
|
95
|
+
if (this.at >= this.bytes.length)
|
|
96
|
+
throw new Error('Negentropy message ends too soon');
|
|
97
|
+
return this.bytes[this.at++];
|
|
98
|
+
}
|
|
99
|
+
take(n) {
|
|
100
|
+
if (this.remaining < n)
|
|
101
|
+
throw new Error('Negentropy message ends too soon');
|
|
102
|
+
const out = this.bytes.subarray(this.at, this.at + n);
|
|
103
|
+
this.at += n;
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
varint() {
|
|
107
|
+
let n = 0;
|
|
108
|
+
for (;;) {
|
|
109
|
+
const byte = this.byte();
|
|
110
|
+
n = n * 128 + (byte & 127);
|
|
111
|
+
if (!Number.isSafeInteger(n))
|
|
112
|
+
throw new Error('Negentropy varint too large');
|
|
113
|
+
if ((byte & 128) === 0)
|
|
114
|
+
return n;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// ─── Fingerprints ──────────────────────────────────────────────────
|
|
119
|
+
const MOD = 1n << 256n;
|
|
120
|
+
/** An id as the little-endian 256-bit number the sum is taken over */
|
|
121
|
+
export function idToNumber(id) {
|
|
122
|
+
const view = new DataView(id.buffer, id.byteOffset, ID_SIZE);
|
|
123
|
+
return (view.getBigUint64(0, true) |
|
|
124
|
+
(view.getBigUint64(8, true) << 64n) |
|
|
125
|
+
(view.getBigUint64(16, true) << 128n) |
|
|
126
|
+
(view.getBigUint64(24, true) << 192n));
|
|
127
|
+
}
|
|
128
|
+
export const EMPTY_SUM = { sum: 0n, count: 0 };
|
|
129
|
+
export const addToSum = (s, id) => ({ sum: (s.sum + idToNumber(id)) % MOD, count: s.count + 1 });
|
|
130
|
+
export const removeFromSum = (s, id) => ({ sum: (s.sum - idToNumber(id) + MOD) % MOD, count: s.count - 1 });
|
|
131
|
+
export const combineSums = (a, b) => ({ sum: (a.sum + b.sum) % MOD, count: a.count + b.count });
|
|
132
|
+
/** Hashes a sum the one way both sides do: 32 little-endian bytes, then the count as a varint */
|
|
133
|
+
export async function fingerprintOf(s) {
|
|
134
|
+
const input = new Uint8Array(ID_SIZE + 10);
|
|
135
|
+
let n = s.sum;
|
|
136
|
+
for (let i = 0; i < ID_SIZE; i++) {
|
|
137
|
+
input[i] = Number(n & 0xffn);
|
|
138
|
+
n >>= 8n;
|
|
139
|
+
}
|
|
140
|
+
const count = encodeVarInt(s.count);
|
|
141
|
+
input.set(count, ID_SIZE);
|
|
142
|
+
return (await sha256(input.subarray(0, ID_SIZE + count.length))).subarray(0, FINGERPRINT_SIZE);
|
|
143
|
+
}
|
|
144
|
+
// ─── A sorted set ──────────────────────────────────────────────────
|
|
145
|
+
/**
|
|
146
|
+
* Items sorted by (timestamp, id), with running sums so any range's
|
|
147
|
+
* fingerprint costs two lookups rather than a pass over it.
|
|
148
|
+
*/
|
|
149
|
+
export class ItemSet {
|
|
150
|
+
items;
|
|
151
|
+
/** prefix[i] is the sum of the first i ids */
|
|
152
|
+
prefix;
|
|
153
|
+
constructor(items) {
|
|
154
|
+
const sorted = [...items].sort(compareItems);
|
|
155
|
+
const unique = [];
|
|
156
|
+
for (const item of sorted) {
|
|
157
|
+
if (item.id.length !== ID_SIZE)
|
|
158
|
+
throw new Error('Negentropy ids are 32 bytes');
|
|
159
|
+
const last = unique[unique.length - 1];
|
|
160
|
+
if (!last || compareItems(last, item) !== 0)
|
|
161
|
+
unique.push(item);
|
|
162
|
+
}
|
|
163
|
+
this.items = unique;
|
|
164
|
+
this.prefix = [0n];
|
|
165
|
+
for (const item of unique)
|
|
166
|
+
this.prefix.push((this.prefix[this.prefix.length - 1] + idToNumber(item.id)) % MOD);
|
|
167
|
+
}
|
|
168
|
+
get size() {
|
|
169
|
+
return this.items.length;
|
|
170
|
+
}
|
|
171
|
+
sum(begin, end) {
|
|
172
|
+
return { sum: (this.prefix[end] - this.prefix[begin] + MOD) % MOD, count: end - begin };
|
|
173
|
+
}
|
|
174
|
+
fingerprint(begin, end) {
|
|
175
|
+
return fingerprintOf(this.sum(begin, end));
|
|
176
|
+
}
|
|
177
|
+
/** The first index in [begin, end) whose item is not below `bound` */
|
|
178
|
+
lowerBound(begin, end, bound) {
|
|
179
|
+
let lo = begin;
|
|
180
|
+
let hi = end;
|
|
181
|
+
while (lo < hi) {
|
|
182
|
+
const mid = (lo + hi) >>> 1;
|
|
183
|
+
if (compareItems(this.items[mid], bound) < 0)
|
|
184
|
+
lo = mid + 1;
|
|
185
|
+
else
|
|
186
|
+
hi = mid;
|
|
187
|
+
}
|
|
188
|
+
return lo;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* One side of one reconciliation.
|
|
193
|
+
*
|
|
194
|
+
* @param set This side's items
|
|
195
|
+
* @param frameSizeLimit Largest message to produce, in bytes; 0 for no limit.
|
|
196
|
+
* What doesn't fit is left for the next round.
|
|
197
|
+
*/
|
|
198
|
+
export function createReconciler(set, options) {
|
|
199
|
+
const { initiator } = options;
|
|
200
|
+
const frameSizeLimit = options.frameSizeLimit ?? 0;
|
|
201
|
+
if (frameSizeLimit !== 0 && frameSizeLimit < 4096)
|
|
202
|
+
throw new Error('frameSizeLimit too small');
|
|
203
|
+
const exceeded = (n) => frameSizeLimit !== 0 && n > frameSizeLimit - 200;
|
|
204
|
+
let lastIn = 0;
|
|
205
|
+
let lastOut = 0;
|
|
206
|
+
const encodeTimestamp = (timestamp) => {
|
|
207
|
+
if (timestamp === INFINITY) {
|
|
208
|
+
lastOut = INFINITY;
|
|
209
|
+
return encodeVarInt(0);
|
|
210
|
+
}
|
|
211
|
+
const delta = timestamp - lastOut;
|
|
212
|
+
lastOut = timestamp;
|
|
213
|
+
return encodeVarInt(delta + 1);
|
|
214
|
+
};
|
|
215
|
+
const decodeTimestamp = (reader) => {
|
|
216
|
+
const raw = reader.varint();
|
|
217
|
+
if (raw === 0 || lastIn === INFINITY) {
|
|
218
|
+
lastIn = INFINITY;
|
|
219
|
+
return INFINITY;
|
|
220
|
+
}
|
|
221
|
+
const timestamp = lastIn + raw - 1;
|
|
222
|
+
if (!Number.isSafeInteger(timestamp))
|
|
223
|
+
throw new Error('Negentropy timestamp too large');
|
|
224
|
+
lastIn = timestamp;
|
|
225
|
+
return timestamp;
|
|
226
|
+
};
|
|
227
|
+
const writeBound = (out, bound) => out.push(encodeTimestamp(bound.timestamp), encodeVarInt(bound.id.length), bound.id);
|
|
228
|
+
const readBound = (reader) => {
|
|
229
|
+
const timestamp = decodeTimestamp(reader);
|
|
230
|
+
const length = reader.varint();
|
|
231
|
+
if (length > ID_SIZE)
|
|
232
|
+
throw new Error('Negentropy bound too long');
|
|
233
|
+
return { timestamp, id: reader.take(length) };
|
|
234
|
+
};
|
|
235
|
+
/** The shortest bound that falls after `prev` and not after `curr` */
|
|
236
|
+
const minimalBound = (prev, curr) => {
|
|
237
|
+
if (curr.timestamp !== prev.timestamp)
|
|
238
|
+
return { timestamp: curr.timestamp, id: new Uint8Array(0) };
|
|
239
|
+
let shared = 0;
|
|
240
|
+
while (shared < ID_SIZE && curr.id[shared] === prev.id[shared])
|
|
241
|
+
shared++;
|
|
242
|
+
return { timestamp: curr.timestamp, id: curr.id.subarray(0, shared + 1) };
|
|
243
|
+
};
|
|
244
|
+
const splitRange = async (lower, upper, upperBound, out) => {
|
|
245
|
+
const count = upper - lower;
|
|
246
|
+
if (count < BUCKETS * 2) {
|
|
247
|
+
writeBound(out, upperBound);
|
|
248
|
+
out.push(encodeVarInt(Mode.IdList), encodeVarInt(count));
|
|
249
|
+
for (let i = lower; i < upper; i++)
|
|
250
|
+
out.push(set.items[i].id);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const per = Math.floor(count / BUCKETS);
|
|
254
|
+
const extra = count % BUCKETS;
|
|
255
|
+
let at = lower;
|
|
256
|
+
for (let i = 0; i < BUCKETS; i++) {
|
|
257
|
+
const size = per + (i < extra ? 1 : 0);
|
|
258
|
+
const fingerprint = await set.fingerprint(at, at + size);
|
|
259
|
+
at += size;
|
|
260
|
+
writeBound(out, at === upper ? upperBound : minimalBound(set.items[at - 1], set.items[at]));
|
|
261
|
+
out.push(encodeVarInt(Mode.Fingerprint), fingerprint);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
/** The first message: the whole set, split into ranges. Initiator only. */
|
|
266
|
+
async initiate() {
|
|
267
|
+
if (!initiator)
|
|
268
|
+
throw new Error('Only the initiator starts');
|
|
269
|
+
lastOut = 0;
|
|
270
|
+
const out = new Writer();
|
|
271
|
+
out.push(NEGENTROPY_VERSION);
|
|
272
|
+
await splitRange(0, set.size, { timestamp: INFINITY, id: new Uint8Array(0) }, out);
|
|
273
|
+
return out.done();
|
|
274
|
+
},
|
|
275
|
+
/** Takes the other side's message and works out the answer. */
|
|
276
|
+
async reconcile(message) {
|
|
277
|
+
const have = [];
|
|
278
|
+
const need = [];
|
|
279
|
+
const reader = new Reader(message);
|
|
280
|
+
lastIn = 0;
|
|
281
|
+
lastOut = 0;
|
|
282
|
+
const full = new Writer();
|
|
283
|
+
full.push(NEGENTROPY_VERSION);
|
|
284
|
+
const version = reader.byte();
|
|
285
|
+
if (version < 0x60 || version > 0x6f)
|
|
286
|
+
throw new Error('Not a Negentropy message');
|
|
287
|
+
if (version !== NEGENTROPY_VERSION) {
|
|
288
|
+
// A responder answers with its own version, and a newer initiator falls back to it.
|
|
289
|
+
if (initiator)
|
|
290
|
+
throw new Error(`Unsupported Negentropy version ${version - 0x60}`);
|
|
291
|
+
return { message: full.done(), have, need };
|
|
292
|
+
}
|
|
293
|
+
let prevBound = { timestamp: 0, id: new Uint8Array(0) };
|
|
294
|
+
let prevIndex = 0;
|
|
295
|
+
let skip = false;
|
|
296
|
+
while (reader.remaining > 0) {
|
|
297
|
+
let out = new Writer();
|
|
298
|
+
const flushSkip = () => {
|
|
299
|
+
if (!skip)
|
|
300
|
+
return;
|
|
301
|
+
skip = false;
|
|
302
|
+
writeBound(out, prevBound);
|
|
303
|
+
out.push(encodeVarInt(Mode.Skip));
|
|
304
|
+
};
|
|
305
|
+
const currBound = readBound(reader);
|
|
306
|
+
const mode = reader.varint();
|
|
307
|
+
const lower = prevIndex;
|
|
308
|
+
let upper = set.lowerBound(prevIndex, set.size, currBound);
|
|
309
|
+
if (mode === Mode.Skip) {
|
|
310
|
+
skip = true;
|
|
311
|
+
}
|
|
312
|
+
else if (mode === Mode.Fingerprint) {
|
|
313
|
+
const theirs = reader.take(FINGERPRINT_SIZE);
|
|
314
|
+
const ours = await set.fingerprint(lower, upper);
|
|
315
|
+
if (compareBytes(theirs, ours) !== 0) {
|
|
316
|
+
flushSkip();
|
|
317
|
+
await splitRange(lower, upper, currBound, out);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
skip = true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else if (mode === Mode.IdList) {
|
|
324
|
+
const n = reader.varint();
|
|
325
|
+
const theirs = new Map();
|
|
326
|
+
for (let i = 0; i < n; i++) {
|
|
327
|
+
const id = reader.take(ID_SIZE);
|
|
328
|
+
if (initiator)
|
|
329
|
+
theirs.set(key(id), id);
|
|
330
|
+
}
|
|
331
|
+
if (initiator) {
|
|
332
|
+
skip = true;
|
|
333
|
+
for (let i = lower; i < upper; i++) {
|
|
334
|
+
const id = set.items[i].id;
|
|
335
|
+
if (!theirs.delete(key(id)))
|
|
336
|
+
have.push(id);
|
|
337
|
+
}
|
|
338
|
+
need.push(...theirs.values());
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
flushSkip();
|
|
342
|
+
const ids = new Writer();
|
|
343
|
+
let count = 0;
|
|
344
|
+
let endBound = currBound;
|
|
345
|
+
for (let i = lower; i < upper; i++) {
|
|
346
|
+
if (exceeded(full.length + ids.length)) {
|
|
347
|
+
endBound = set.items[i];
|
|
348
|
+
upper = i; // the rest of the range gets a fingerprint below
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
ids.push(set.items[i].id);
|
|
352
|
+
count++;
|
|
353
|
+
}
|
|
354
|
+
writeBound(out, endBound);
|
|
355
|
+
out.push(encodeVarInt(Mode.IdList), encodeVarInt(count));
|
|
356
|
+
out.append(ids);
|
|
357
|
+
full.append(out);
|
|
358
|
+
out = new Writer();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
throw new Error('Unknown Negentropy mode');
|
|
363
|
+
}
|
|
364
|
+
if (exceeded(full.length + out.length)) {
|
|
365
|
+
// Out of room: one fingerprint for everything not covered yet, answered next round.
|
|
366
|
+
writeBound(full, { timestamp: INFINITY, id: new Uint8Array(0) });
|
|
367
|
+
full.push(encodeVarInt(Mode.Fingerprint), await set.fingerprint(upper, set.size));
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
full.append(out);
|
|
371
|
+
prevIndex = upper;
|
|
372
|
+
prevBound = currBound;
|
|
373
|
+
}
|
|
374
|
+
return { message: initiator && full.length === 1 ? null : full.done(), have, need };
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const key = (id) => String.fromCharCode(...id);
|
|
379
|
+
//# sourceMappingURL=negentropy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negentropy.js","sourceRoot":"","sources":["../../src/sync/negentropy.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,17 +2,29 @@
|
|
|
2
2
|
* @module sync-engine
|
|
3
3
|
* Keeps one store in step with its peers.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* 1. A peer says hello with a fingerprint of each collection it keeps. Equal
|
|
6
|
+
* fingerprints mean the same versions: nothing to do for that collection.
|
|
7
|
+
* 2. For each collection that differs, one side — the initiator — reconciles
|
|
8
|
+
* it with the other (`negentropy.ts`). A few rounds of fingerprints of
|
|
9
|
+
* ever smaller ranges end with the initiator knowing which versions each
|
|
10
|
+
* side lacks.
|
|
11
|
+
* 3. The initiator asks for what it lacks, and sends what the other lacks.
|
|
12
|
+
* Everything that arrives passes the gatekeeper before it is stored.
|
|
6
13
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* batches and skipping any subtree that is already part of its own tree.
|
|
10
|
-
* 3. The keys found in the nodes it fetched, less the records it already
|
|
11
|
-
* holds, are what it is missing. It asks for those, and every one of them
|
|
12
|
-
* passes the gatekeeper before it is stored.
|
|
14
|
+
* Cost follows the difference, not the size: two stores differing by one
|
|
15
|
+
* version exchange a few hundred bytes.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
17
|
+
* The initiator is the peer whose id sorts first, so two peers that hear each
|
|
18
|
+
* other's hello at once don't both do the work. A peer that isn't the
|
|
19
|
+
* initiator answers a hello with its own, which starts the other.
|
|
20
|
+
*
|
|
21
|
+
* **Holding part of a space.** A node may hold every collection, or only
|
|
22
|
+
* some (plus the space's own `sys.*`, which every node holds). Each hello
|
|
23
|
+
* says which. Two peers reconcile only the collections both hold, and a
|
|
24
|
+
* version for a collection this node doesn't hold is not taken in. Whatever
|
|
25
|
+
* a node does take in from a peer, it tells that peer it has (`stored`): a
|
|
26
|
+
* node holding part of a space keeps its own writes until enough keepers have
|
|
27
|
+
* said so.
|
|
16
28
|
*/
|
|
17
29
|
import type { Expression } from '../types.js';
|
|
18
30
|
import type { StorageProvider } from '../storage/storage-provider.js';
|
|
@@ -29,9 +41,19 @@ export interface IncomingValidation {
|
|
|
29
41
|
*/
|
|
30
42
|
readonly later?: boolean;
|
|
31
43
|
}
|
|
44
|
+
/** What a node holds of a space: every collection, or these (besides `sys.*`, which every node holds) */
|
|
45
|
+
export type Holds = 'all' | ReadonlySet<string>;
|
|
46
|
+
/** Whether a collection is held, given what a node holds */
|
|
47
|
+
export declare const holdsCollection: (holds: Holds, collection: string) => boolean;
|
|
32
48
|
export interface SyncEngineConfig {
|
|
33
49
|
readonly storageProvider: StorageProvider;
|
|
34
50
|
readonly sendToPeer: (peerId: string, message: SyncMessage) => void;
|
|
51
|
+
/**
|
|
52
|
+
* This node's id among its peers. The one of two peers whose id sorts first
|
|
53
|
+
* starts reconciling. Without it, this node starts whenever it hears of a
|
|
54
|
+
* difference — harmless, just sometimes twice the work.
|
|
55
|
+
*/
|
|
56
|
+
readonly self?: string;
|
|
35
57
|
readonly heartbeatInterval?: number;
|
|
36
58
|
/**
|
|
37
59
|
* Gatekeeper for expressions arriving from peers — typically a
|
|
@@ -42,14 +64,24 @@ export interface SyncEngineConfig {
|
|
|
42
64
|
* for a trusted transport or a test.
|
|
43
65
|
*/
|
|
44
66
|
readonly validate?: (expression: Expression) => Promise<IncomingValidation>;
|
|
67
|
+
/** What this node holds, asked afresh for every hello. Default: everything. */
|
|
68
|
+
readonly holds?: () => Holds;
|
|
45
69
|
}
|
|
46
|
-
|
|
70
|
+
/**
|
|
71
|
+
* - `synced` (peer, full): nothing left in flight with the peer; `full` when the peer holds every collection
|
|
72
|
+
* - `level` (peer, collection, full): this node holds what the peer holds of a
|
|
73
|
+
* collection, as far as it could take it in; `full` when the peer holds every collection
|
|
74
|
+
* - `stored` (peer, ids): the peer says it now has these versions
|
|
75
|
+
* - `expression-received` (version), `rejected` (peer, version, reason), `error` (error)
|
|
76
|
+
*/
|
|
77
|
+
export type SyncEvent = 'synced' | 'level' | 'stored' | 'expression-received' | 'rejected' | 'error';
|
|
47
78
|
type EventHandler = (...args: any[]) => void;
|
|
48
79
|
export interface SyncEngine {
|
|
49
80
|
start(): void;
|
|
50
81
|
stop(): void;
|
|
51
82
|
/** Handles whatever a peer sent; anything that is not a sync message this peer speaks is ignored. */
|
|
52
83
|
handleMessage(peerId: string, message: unknown): Promise<void>;
|
|
84
|
+
/** Says hello to these peers now, rather than at the next heartbeat. */
|
|
53
85
|
notifyPeers(peers: ReadonlyArray<string>): void;
|
|
54
86
|
onLocalChange(expression: Expression): void;
|
|
55
87
|
addPeer(peerId: string): void;
|
|
@@ -57,10 +89,10 @@ export interface SyncEngine {
|
|
|
57
89
|
on(event: SyncEvent, callback: EventHandler): void;
|
|
58
90
|
off(event: SyncEvent, callback: EventHandler): void;
|
|
59
91
|
}
|
|
60
|
-
/**
|
|
61
|
-
export declare const MAX_CIDS_PER_REQUEST = 64;
|
|
62
|
-
/** Records asked for in one message. */
|
|
92
|
+
/** Records asked for, or sent, in one message. */
|
|
63
93
|
export declare const MAX_IDS_PER_REQUEST = 200;
|
|
94
|
+
/** Largest Negentropy message, in bytes before base64. Stays well inside a data channel's limit. */
|
|
95
|
+
export declare const FRAME_SIZE_LIMIT = 32000;
|
|
64
96
|
/**
|
|
65
97
|
* Creates a sync engine orchestrator.
|
|
66
98
|
* @param config Sync engine configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../../src/sync/sync-engine.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../../src/sync/sync-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAKtE,OAAO,EAA2C,KAAK,WAAW,EAAwB,MAAM,oBAAoB,CAAC;AAErH,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAOD,yGAAyG;AACzG,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAEhD,4DAA4D;AAC5D,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,EAAE,YAAY,MAAM,KAAG,OACQ,CAAC;AAK5E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACpE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5E,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,qBAAqB,GAAG,UAAU,GAAG,OAAO,CAAC;AACrG,KAAK,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,qGAAqG;IACrG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,wEAAwE;IACxE,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAChD,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACnD,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CACrD;AAED,kDAAkD;AAClD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAiCvC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA2WrE"}
|