cojson 0.1.8 → 0.1.9
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/dist/account.d.ts +4 -2
- package/dist/account.js +4 -2
- package/dist/account.js.map +1 -1
- package/dist/coValue.d.ts +44 -81
- package/dist/coValue.js +4 -348
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.d.ts +84 -0
- package/dist/coValueCore.js +351 -0
- package/dist/coValueCore.js.map +1 -0
- package/dist/coValues/coList.d.ts +113 -0
- package/dist/{contentTypes → coValues}/coList.js +59 -19
- package/dist/coValues/coList.js.map +1 -0
- package/dist/{contentTypes → coValues}/coMap.d.ts +25 -7
- package/dist/{contentTypes → coValues}/coMap.js +34 -15
- package/dist/coValues/coMap.js.map +1 -0
- package/dist/coValues/coStream.d.ts +14 -0
- package/dist/coValues/coStream.js +22 -0
- package/dist/coValues/coStream.js.map +1 -0
- package/dist/coValues/static.d.ts +14 -0
- package/dist/coValues/static.js +20 -0
- package/dist/coValues/static.js.map +1 -0
- package/dist/group.d.ts +54 -9
- package/dist/group.js +68 -28
- package/dist/group.js.map +1 -1
- package/dist/index.d.ts +17 -10
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +59 -5
- package/dist/node.js +36 -15
- package/dist/node.js.map +1 -1
- package/dist/permissions.d.ts +2 -2
- package/dist/permissions.js +1 -1
- package/dist/permissions.js.map +1 -1
- package/dist/sync.d.ts +3 -3
- package/dist/sync.js +2 -2
- package/dist/sync.js.map +1 -1
- package/dist/testUtils.d.ts +2 -2
- package/dist/testUtils.js +1 -1
- package/dist/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/account.test.ts +1 -1
- package/src/account.ts +6 -4
- package/src/coValue.test.ts +233 -130
- package/src/coValue.ts +50 -576
- package/src/coValueCore.test.ts +181 -0
- package/src/coValueCore.ts +588 -0
- package/src/{contentTypes → coValues}/coList.ts +89 -40
- package/src/{contentTypes → coValues}/coMap.ts +40 -20
- package/src/coValues/coStream.ts +33 -0
- package/src/coValues/static.ts +31 -0
- package/src/group.ts +87 -50
- package/src/index.ts +30 -28
- package/src/node.ts +47 -26
- package/src/permissions.test.ts +32 -32
- package/src/permissions.ts +5 -5
- package/src/sync.test.ts +77 -77
- package/src/sync.ts +5 -5
- package/src/testUtils.ts +1 -1
- package/tsconfig.json +1 -2
- package/dist/contentType.d.ts +0 -15
- package/dist/contentType.js +0 -7
- package/dist/contentType.js.map +0 -1
- package/dist/contentTypes/coList.d.ts +0 -77
- package/dist/contentTypes/coList.js.map +0 -1
- package/dist/contentTypes/coMap.js.map +0 -1
- package/dist/contentTypes/coStream.d.ts +0 -11
- package/dist/contentTypes/coStream.js +0 -16
- package/dist/contentTypes/coStream.js.map +0 -1
- package/dist/contentTypes/static.d.ts +0 -11
- package/dist/contentTypes/static.js +0 -14
- package/dist/contentTypes/static.js.map +0 -1
- package/src/contentType.test.ts +0 -284
- package/src/contentType.ts +0 -26
- package/src/contentTypes/coStream.ts +0 -24
- package/src/contentTypes/static.ts +0 -22
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { randomBytes } from "@noble/hashes/utils";
|
|
2
|
+
import { Static } from "./coValues/static.js";
|
|
3
|
+
import { CoStream } from "./coValues/coStream.js";
|
|
4
|
+
import { CoMap } from "./coValues/coMap.js";
|
|
5
|
+
import { StreamingHash, unseal, shortHash, sign, verify, encryptForTransaction, decryptForTransaction, decryptKeySecret, getAgentSignerID, getAgentSealerID, } from "./crypto.js";
|
|
6
|
+
import { base58 } from "@scure/base";
|
|
7
|
+
import { determineValidTransactions, isKeyForKeyField, } from "./permissions.js";
|
|
8
|
+
import { Group, expectGroupContent } from "./group.js";
|
|
9
|
+
import { CoList } from "./coValues/coList.js";
|
|
10
|
+
export function idforHeader(header) {
|
|
11
|
+
const hash = shortHash(header);
|
|
12
|
+
return `co_z${hash.slice("shortHash_z".length)}`;
|
|
13
|
+
}
|
|
14
|
+
export function accountOrAgentIDfromSessionID(sessionID) {
|
|
15
|
+
return sessionID.split("_session")[0];
|
|
16
|
+
}
|
|
17
|
+
export function newRandomSessionID(accountID) {
|
|
18
|
+
return `${accountID}_session_z${base58.encode(randomBytes(8))}`;
|
|
19
|
+
}
|
|
20
|
+
const readKeyCache = new WeakMap();
|
|
21
|
+
export class CoValueCore {
|
|
22
|
+
constructor(header, node, internalInitSessions = {}) {
|
|
23
|
+
this.listeners = new Set();
|
|
24
|
+
this.id = idforHeader(header);
|
|
25
|
+
this.header = header;
|
|
26
|
+
this._sessions = internalInitSessions;
|
|
27
|
+
this.node = node;
|
|
28
|
+
if (header.ruleset.type == "ownedByGroup") {
|
|
29
|
+
this.node
|
|
30
|
+
.expectCoValueLoaded(header.ruleset.group)
|
|
31
|
+
.subscribe((_groupUpdate) => {
|
|
32
|
+
this._cachedContent = undefined;
|
|
33
|
+
const newContent = this.getCurrentContent();
|
|
34
|
+
for (const listener of this.listeners) {
|
|
35
|
+
listener(newContent);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
get sessions() {
|
|
41
|
+
return this._sessions;
|
|
42
|
+
}
|
|
43
|
+
testWithDifferentAccount(account, currentSessionID) {
|
|
44
|
+
const newNode = this.node.testWithDifferentAccount(account, currentSessionID);
|
|
45
|
+
return newNode.expectCoValueLoaded(this.id);
|
|
46
|
+
}
|
|
47
|
+
knownState() {
|
|
48
|
+
return {
|
|
49
|
+
id: this.id,
|
|
50
|
+
header: true,
|
|
51
|
+
sessions: Object.fromEntries(Object.entries(this.sessions).map(([k, v]) => [
|
|
52
|
+
k,
|
|
53
|
+
v.transactions.length,
|
|
54
|
+
])),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
get meta() {
|
|
58
|
+
return this.header?.meta ?? null;
|
|
59
|
+
}
|
|
60
|
+
nextTransactionID() {
|
|
61
|
+
const sessionID = this.node.currentSessionID;
|
|
62
|
+
return {
|
|
63
|
+
sessionID,
|
|
64
|
+
txIndex: this.sessions[sessionID]?.transactions.length || 0,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
tryAddTransactions(sessionID, newTransactions, givenExpectedNewHash, newSignature) {
|
|
68
|
+
const signerID = getAgentSignerID(this.node.resolveAccountAgent(accountOrAgentIDfromSessionID(sessionID), "Expected to know signer of transaction"));
|
|
69
|
+
if (!signerID) {
|
|
70
|
+
console.warn("Unknown agent", accountOrAgentIDfromSessionID(sessionID));
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const { expectedNewHash, newStreamingHash } = this.expectedNewHashAfter(sessionID, newTransactions);
|
|
74
|
+
if (givenExpectedNewHash && givenExpectedNewHash !== expectedNewHash) {
|
|
75
|
+
console.warn("Invalid hash", {
|
|
76
|
+
expectedNewHash,
|
|
77
|
+
givenExpectedNewHash,
|
|
78
|
+
});
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (!verify(newSignature, expectedNewHash, signerID)) {
|
|
82
|
+
console.warn("Invalid signature", newSignature, expectedNewHash, signerID);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const transactions = this.sessions[sessionID]?.transactions ?? [];
|
|
86
|
+
transactions.push(...newTransactions);
|
|
87
|
+
this._sessions[sessionID] = {
|
|
88
|
+
transactions,
|
|
89
|
+
lastHash: expectedNewHash,
|
|
90
|
+
streamingHash: newStreamingHash,
|
|
91
|
+
lastSignature: newSignature,
|
|
92
|
+
};
|
|
93
|
+
this._cachedContent = undefined;
|
|
94
|
+
const content = this.getCurrentContent();
|
|
95
|
+
for (const listener of this.listeners) {
|
|
96
|
+
listener(content);
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
subscribe(listener) {
|
|
101
|
+
this.listeners.add(listener);
|
|
102
|
+
listener(this.getCurrentContent());
|
|
103
|
+
return () => {
|
|
104
|
+
this.listeners.delete(listener);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
expectedNewHashAfter(sessionID, newTransactions) {
|
|
108
|
+
const streamingHash = this.sessions[sessionID]?.streamingHash.clone() ??
|
|
109
|
+
new StreamingHash();
|
|
110
|
+
for (const transaction of newTransactions) {
|
|
111
|
+
streamingHash.update(transaction);
|
|
112
|
+
}
|
|
113
|
+
const newStreamingHash = streamingHash.clone();
|
|
114
|
+
return {
|
|
115
|
+
expectedNewHash: streamingHash.digest(),
|
|
116
|
+
newStreamingHash,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
makeTransaction(changes, privacy) {
|
|
120
|
+
const madeAt = Date.now();
|
|
121
|
+
let transaction;
|
|
122
|
+
if (privacy === "private") {
|
|
123
|
+
const { secret: keySecret, id: keyID } = this.getCurrentReadKey();
|
|
124
|
+
if (!keySecret) {
|
|
125
|
+
throw new Error("Can't make transaction without read key secret");
|
|
126
|
+
}
|
|
127
|
+
transaction = {
|
|
128
|
+
privacy: "private",
|
|
129
|
+
madeAt,
|
|
130
|
+
keyUsed: keyID,
|
|
131
|
+
encryptedChanges: encryptForTransaction(changes, keySecret, {
|
|
132
|
+
in: this.id,
|
|
133
|
+
tx: this.nextTransactionID(),
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
transaction = {
|
|
139
|
+
privacy: "trusting",
|
|
140
|
+
madeAt,
|
|
141
|
+
changes,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const sessionID = this.node.currentSessionID;
|
|
145
|
+
const { expectedNewHash } = this.expectedNewHashAfter(sessionID, [
|
|
146
|
+
transaction,
|
|
147
|
+
]);
|
|
148
|
+
const signature = sign(this.node.account.currentSignerSecret(), expectedNewHash);
|
|
149
|
+
const success = this.tryAddTransactions(sessionID, [transaction], expectedNewHash, signature);
|
|
150
|
+
if (success) {
|
|
151
|
+
void this.node.sync.syncCoValue(this);
|
|
152
|
+
}
|
|
153
|
+
return success;
|
|
154
|
+
}
|
|
155
|
+
getCurrentContent() {
|
|
156
|
+
if (this._cachedContent) {
|
|
157
|
+
return this._cachedContent;
|
|
158
|
+
}
|
|
159
|
+
if (this.header.type === "comap") {
|
|
160
|
+
this._cachedContent = new CoMap(this);
|
|
161
|
+
}
|
|
162
|
+
else if (this.header.type === "colist") {
|
|
163
|
+
this._cachedContent = new CoList(this);
|
|
164
|
+
}
|
|
165
|
+
else if (this.header.type === "costream") {
|
|
166
|
+
this._cachedContent = new CoStream(this);
|
|
167
|
+
}
|
|
168
|
+
else if (this.header.type === "static") {
|
|
169
|
+
this._cachedContent = new Static(this);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
throw new Error(`Unknown coValue type ${this.header.type}`);
|
|
173
|
+
}
|
|
174
|
+
return this._cachedContent;
|
|
175
|
+
}
|
|
176
|
+
getValidSortedTransactions() {
|
|
177
|
+
const validTransactions = determineValidTransactions(this);
|
|
178
|
+
const allTransactions = validTransactions
|
|
179
|
+
.map(({ txID, tx }) => {
|
|
180
|
+
if (tx.privacy === "trusting") {
|
|
181
|
+
return {
|
|
182
|
+
txID,
|
|
183
|
+
madeAt: tx.madeAt,
|
|
184
|
+
changes: tx.changes,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const readKey = this.getReadKey(tx.keyUsed);
|
|
189
|
+
if (!readKey) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const decrytedChanges = decryptForTransaction(tx.encryptedChanges, readKey, {
|
|
194
|
+
in: this.id,
|
|
195
|
+
tx: txID,
|
|
196
|
+
});
|
|
197
|
+
if (!decrytedChanges) {
|
|
198
|
+
console.error("Failed to decrypt transaction despite having key");
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
txID,
|
|
203
|
+
madeAt: tx.madeAt,
|
|
204
|
+
changes: decrytedChanges,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
.filter((x) => !!x);
|
|
210
|
+
allTransactions.sort((a, b) => a.madeAt - b.madeAt ||
|
|
211
|
+
(a.txID.sessionID < b.txID.sessionID ? -1 : 1) ||
|
|
212
|
+
a.txID.txIndex - b.txID.txIndex);
|
|
213
|
+
return allTransactions;
|
|
214
|
+
}
|
|
215
|
+
getCurrentReadKey() {
|
|
216
|
+
if (this.header.ruleset.type === "group") {
|
|
217
|
+
const content = expectGroupContent(this.getCurrentContent());
|
|
218
|
+
const currentKeyId = content.get("readKey");
|
|
219
|
+
if (!currentKeyId) {
|
|
220
|
+
throw new Error("No readKey set");
|
|
221
|
+
}
|
|
222
|
+
const secret = this.getReadKey(currentKeyId);
|
|
223
|
+
return {
|
|
224
|
+
secret: secret,
|
|
225
|
+
id: currentKeyId,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
else if (this.header.ruleset.type === "ownedByGroup") {
|
|
229
|
+
return this.node
|
|
230
|
+
.expectCoValueLoaded(this.header.ruleset.group)
|
|
231
|
+
.getCurrentReadKey();
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
throw new Error("Only groups or values owned by groups have read secrets");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
getReadKey(keyID) {
|
|
238
|
+
if (readKeyCache.get(this)?.[keyID]) {
|
|
239
|
+
return readKeyCache.get(this)?.[keyID];
|
|
240
|
+
}
|
|
241
|
+
if (this.header.ruleset.type === "group") {
|
|
242
|
+
const content = expectGroupContent(this.getCurrentContent());
|
|
243
|
+
// Try to find key revelation for us
|
|
244
|
+
const readKeyEntry = content.getLastEntry(`${keyID}_for_${this.node.account.id}`);
|
|
245
|
+
if (readKeyEntry) {
|
|
246
|
+
const revealer = accountOrAgentIDfromSessionID(readKeyEntry.txID.sessionID);
|
|
247
|
+
const revealerAgent = this.node.resolveAccountAgent(revealer, "Expected to know revealer");
|
|
248
|
+
const secret = unseal(readKeyEntry.value, this.node.account.currentSealerSecret(), getAgentSealerID(revealerAgent), {
|
|
249
|
+
in: this.id,
|
|
250
|
+
tx: readKeyEntry.txID,
|
|
251
|
+
});
|
|
252
|
+
if (secret) {
|
|
253
|
+
let cache = readKeyCache.get(this);
|
|
254
|
+
if (!cache) {
|
|
255
|
+
cache = {};
|
|
256
|
+
readKeyCache.set(this, cache);
|
|
257
|
+
}
|
|
258
|
+
cache[keyID] = secret;
|
|
259
|
+
return secret;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Try to find indirect revelation through previousKeys
|
|
263
|
+
for (const field of content.keys()) {
|
|
264
|
+
if (isKeyForKeyField(field) && field.startsWith(keyID)) {
|
|
265
|
+
const encryptingKeyID = field.split("_for_")[1];
|
|
266
|
+
const encryptingKeySecret = this.getReadKey(encryptingKeyID);
|
|
267
|
+
if (!encryptingKeySecret) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const encryptedPreviousKey = content.get(field);
|
|
271
|
+
const secret = decryptKeySecret({
|
|
272
|
+
encryptedID: keyID,
|
|
273
|
+
encryptingID: encryptingKeyID,
|
|
274
|
+
encrypted: encryptedPreviousKey,
|
|
275
|
+
}, encryptingKeySecret);
|
|
276
|
+
if (secret) {
|
|
277
|
+
let cache = readKeyCache.get(this);
|
|
278
|
+
if (!cache) {
|
|
279
|
+
cache = {};
|
|
280
|
+
readKeyCache.set(this, cache);
|
|
281
|
+
}
|
|
282
|
+
cache[keyID] = secret;
|
|
283
|
+
return secret;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
console.error(`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
else if (this.header.ruleset.type === "ownedByGroup") {
|
|
293
|
+
return this.node
|
|
294
|
+
.expectCoValueLoaded(this.header.ruleset.group)
|
|
295
|
+
.getReadKey(keyID);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
throw new Error("Only groups or values owned by groups have read secrets");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
getGroup() {
|
|
302
|
+
if (this.header.ruleset.type !== "ownedByGroup") {
|
|
303
|
+
throw new Error("Only values owned by groups have groups");
|
|
304
|
+
}
|
|
305
|
+
return new Group(expectGroupContent(this.node
|
|
306
|
+
.expectCoValueLoaded(this.header.ruleset.group)
|
|
307
|
+
.getCurrentContent()), this.node);
|
|
308
|
+
}
|
|
309
|
+
getTx(txID) {
|
|
310
|
+
return this.sessions[txID.sessionID]?.transactions[txID.txIndex];
|
|
311
|
+
}
|
|
312
|
+
newContentSince(knownState) {
|
|
313
|
+
const newContent = {
|
|
314
|
+
action: "content",
|
|
315
|
+
id: this.id,
|
|
316
|
+
header: knownState?.header ? undefined : this.header,
|
|
317
|
+
new: Object.fromEntries(Object.entries(this.sessions)
|
|
318
|
+
.map(([sessionID, log]) => {
|
|
319
|
+
const newTransactions = log.transactions.slice(knownState?.sessions[sessionID] || 0);
|
|
320
|
+
if (newTransactions.length === 0 ||
|
|
321
|
+
!log.lastHash ||
|
|
322
|
+
!log.lastSignature) {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
return [
|
|
326
|
+
sessionID,
|
|
327
|
+
{
|
|
328
|
+
after: knownState?.sessions[sessionID] || 0,
|
|
329
|
+
newTransactions,
|
|
330
|
+
lastSignature: log.lastSignature,
|
|
331
|
+
},
|
|
332
|
+
];
|
|
333
|
+
})
|
|
334
|
+
.filter((x) => !!x)),
|
|
335
|
+
};
|
|
336
|
+
if (!newContent.header && Object.keys(newContent.new).length === 0) {
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
return newContent;
|
|
340
|
+
}
|
|
341
|
+
getDependedOnCoValues() {
|
|
342
|
+
return this.header.ruleset.type === "group"
|
|
343
|
+
? expectGroupContent(this.getCurrentContent())
|
|
344
|
+
.keys()
|
|
345
|
+
.filter((k) => k.startsWith("co_"))
|
|
346
|
+
: this.header.ruleset.type === "ownedByGroup"
|
|
347
|
+
? [this.header.ruleset.group]
|
|
348
|
+
: [];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=coValueCore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coValueCore.js","sourceRoot":"","sources":["../src/coValueCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
2
|
+
import { CoID, ReadableCoValue, WriteableCoValue } from "../coValue.js";
|
|
3
|
+
import { CoValueCore } from "../coValueCore.js";
|
|
4
|
+
import { SessionID, TransactionID } from "../ids.js";
|
|
5
|
+
import { AccountID, Group } from "../index.js";
|
|
6
|
+
type OpID = TransactionID & {
|
|
7
|
+
changeIdx: number;
|
|
8
|
+
};
|
|
9
|
+
type InsertionOpPayload<T extends JsonValue> = {
|
|
10
|
+
op: "pre";
|
|
11
|
+
value: T;
|
|
12
|
+
before: OpID | "end";
|
|
13
|
+
} | {
|
|
14
|
+
op: "app";
|
|
15
|
+
value: T;
|
|
16
|
+
after: OpID | "start";
|
|
17
|
+
};
|
|
18
|
+
type DeletionOpPayload = {
|
|
19
|
+
op: "del";
|
|
20
|
+
insertion: OpID;
|
|
21
|
+
};
|
|
22
|
+
export type ListOpPayload<T extends JsonValue> = InsertionOpPayload<T> | DeletionOpPayload;
|
|
23
|
+
type InsertionEntry<T extends JsonValue> = {
|
|
24
|
+
madeAt: number;
|
|
25
|
+
predecessors: OpID[];
|
|
26
|
+
successors: OpID[];
|
|
27
|
+
} & InsertionOpPayload<T>;
|
|
28
|
+
type DeletionEntry = {
|
|
29
|
+
madeAt: number;
|
|
30
|
+
deletionID: OpID;
|
|
31
|
+
} & DeletionOpPayload;
|
|
32
|
+
export declare class CoList<T extends JsonValue, Meta extends JsonObject | null = null> implements ReadableCoValue {
|
|
33
|
+
id: CoID<CoList<T, Meta>>;
|
|
34
|
+
type: "colist";
|
|
35
|
+
core: CoValueCore;
|
|
36
|
+
/** @internal */
|
|
37
|
+
afterStart: OpID[];
|
|
38
|
+
/** @internal */
|
|
39
|
+
beforeEnd: OpID[];
|
|
40
|
+
/** @internal */
|
|
41
|
+
insertions: {
|
|
42
|
+
[sessionID: SessionID]: {
|
|
43
|
+
[txIdx: number]: {
|
|
44
|
+
[changeIdx: number]: InsertionEntry<T>;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
/** @internal */
|
|
49
|
+
deletionsByInsertion: {
|
|
50
|
+
[deletedSessionID: SessionID]: {
|
|
51
|
+
[deletedTxIdx: number]: {
|
|
52
|
+
[deletedChangeIdx: number]: DeletionEntry[];
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/** @internal */
|
|
57
|
+
constructor(core: CoValueCore);
|
|
58
|
+
get meta(): Meta;
|
|
59
|
+
get group(): Group;
|
|
60
|
+
/** @internal */
|
|
61
|
+
protected fillOpsFromCoValue(): void;
|
|
62
|
+
/** Get the item currently at `idx`. */
|
|
63
|
+
get(idx: number): T | undefined;
|
|
64
|
+
/** Returns the current items in the CoList as an array. */
|
|
65
|
+
asArray(): T[];
|
|
66
|
+
entries(): {
|
|
67
|
+
value: T;
|
|
68
|
+
madeAt: number;
|
|
69
|
+
opID: OpID;
|
|
70
|
+
}[];
|
|
71
|
+
/** @internal */
|
|
72
|
+
private fillArrayFromOpID;
|
|
73
|
+
/** Returns the accountID of the account that inserted value at the given index. */
|
|
74
|
+
whoInserted(idx: number): AccountID | undefined;
|
|
75
|
+
/** Returns the current items in the CoList as an array. (alias of `asArray`) */
|
|
76
|
+
toJSON(): T[];
|
|
77
|
+
map<U>(mapper: (value: T, idx: number) => U): U[];
|
|
78
|
+
filter<U extends T>(predicate: (value: T, idx: number) => value is U): U[];
|
|
79
|
+
reduce<U>(reducer: (accumulator: U, value: T, idx: number) => U, initialValue: U): U;
|
|
80
|
+
subscribe(listener: (coMap: CoList<T, Meta>) => void): () => void;
|
|
81
|
+
edit(changer: (editable: WriteableCoList<T, Meta>) => void): CoList<T, Meta>;
|
|
82
|
+
}
|
|
83
|
+
export declare class WriteableCoList<T extends JsonValue, Meta extends JsonObject | null = null> extends CoList<T, Meta> implements WriteableCoValue {
|
|
84
|
+
/** @internal */
|
|
85
|
+
edit(_changer: (editable: WriteableCoList<T, Meta>) => void): CoList<T, Meta>;
|
|
86
|
+
/** Appends a new item after index `after`.
|
|
87
|
+
*
|
|
88
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
89
|
+
*
|
|
90
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
91
|
+
append(after: number, value: T, privacy?: "private" | "trusting"): void;
|
|
92
|
+
/** Pushes a new item to the end of the list.
|
|
93
|
+
*
|
|
94
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
95
|
+
*
|
|
96
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
97
|
+
push(value: T, privacy?: "private" | "trusting"): void;
|
|
98
|
+
/**
|
|
99
|
+
* Prepends a new item before index `before`.
|
|
100
|
+
*
|
|
101
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
102
|
+
*
|
|
103
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
104
|
+
*/
|
|
105
|
+
prepend(before: number, value: T, privacy?: "private" | "trusting"): void;
|
|
106
|
+
/** Deletes the item at index `at` from the list.
|
|
107
|
+
*
|
|
108
|
+
* If `privacy` is `"private"` **(default)**, the fact of this deletion is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
109
|
+
*
|
|
110
|
+
* If `privacy` is `"trusting"`, the fact of this deletion is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
111
|
+
delete(at: number, privacy?: "private" | "trusting"): void;
|
|
112
|
+
}
|
|
113
|
+
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { accountOrAgentIDfromSessionID } from "../
|
|
1
|
+
import { accountOrAgentIDfromSessionID } from "../coValueCore.js";
|
|
2
2
|
import { isAccountID } from "../account.js";
|
|
3
3
|
export class CoList {
|
|
4
|
-
|
|
4
|
+
/** @internal */
|
|
5
|
+
constructor(core) {
|
|
5
6
|
this.type = "colist";
|
|
6
|
-
this.id =
|
|
7
|
-
this.
|
|
7
|
+
this.id = core.id;
|
|
8
|
+
this.core = core;
|
|
8
9
|
this.afterStart = [];
|
|
9
10
|
this.beforeEnd = [];
|
|
10
11
|
this.insertions = {};
|
|
@@ -12,17 +13,18 @@ export class CoList {
|
|
|
12
13
|
this.fillOpsFromCoValue();
|
|
13
14
|
}
|
|
14
15
|
get meta() {
|
|
15
|
-
return this.
|
|
16
|
+
return this.core.header.meta;
|
|
16
17
|
}
|
|
17
18
|
get group() {
|
|
18
|
-
return this.
|
|
19
|
+
return this.core.getGroup();
|
|
19
20
|
}
|
|
21
|
+
/** @internal */
|
|
20
22
|
fillOpsFromCoValue() {
|
|
21
23
|
this.insertions = {};
|
|
22
24
|
this.deletionsByInsertion = {};
|
|
23
25
|
this.afterStart = [];
|
|
24
26
|
this.beforeEnd = [];
|
|
25
|
-
for (const { txID, changes, madeAt, } of this.
|
|
27
|
+
for (const { txID, changes, madeAt, } of this.core.getValidSortedTransactions()) {
|
|
26
28
|
for (const [changeIdx, changeUntyped] of changes.entries()) {
|
|
27
29
|
const change = changeUntyped;
|
|
28
30
|
if (change.op === "pre" || change.op === "app") {
|
|
@@ -114,6 +116,18 @@ export class CoList {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
}
|
|
119
|
+
/** Get the item currently at `idx`. */
|
|
120
|
+
get(idx) {
|
|
121
|
+
const entry = this.entries()[idx];
|
|
122
|
+
if (!entry) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return entry.value;
|
|
126
|
+
}
|
|
127
|
+
/** Returns the current items in the CoList as an array. */
|
|
128
|
+
asArray() {
|
|
129
|
+
return this.entries().map((entry) => entry.value);
|
|
130
|
+
}
|
|
117
131
|
entries() {
|
|
118
132
|
const arr = [];
|
|
119
133
|
for (const opID of this.afterStart) {
|
|
@@ -124,6 +138,7 @@ export class CoList {
|
|
|
124
138
|
}
|
|
125
139
|
return arr;
|
|
126
140
|
}
|
|
141
|
+
/** @internal */
|
|
127
142
|
fillArrayFromOpID(opID, arr) {
|
|
128
143
|
const entry = this.insertions[opID.sessionID]?.[opID.txIndex]?.[opID.changeIdx];
|
|
129
144
|
if (!entry) {
|
|
@@ -144,6 +159,7 @@ export class CoList {
|
|
|
144
159
|
this.fillArrayFromOpID(successor, arr);
|
|
145
160
|
}
|
|
146
161
|
}
|
|
162
|
+
/** Returns the accountID of the account that inserted value at the given index. */
|
|
147
163
|
whoInserted(idx) {
|
|
148
164
|
const entry = this.entries()[idx];
|
|
149
165
|
if (!entry) {
|
|
@@ -157,12 +173,10 @@ export class CoList {
|
|
|
157
173
|
return undefined;
|
|
158
174
|
}
|
|
159
175
|
}
|
|
176
|
+
/** Returns the current items in the CoList as an array. (alias of `asArray`) */
|
|
160
177
|
toJSON() {
|
|
161
178
|
return this.asArray();
|
|
162
179
|
}
|
|
163
|
-
asArray() {
|
|
164
|
-
return this.entries().map((entry) => entry.value);
|
|
165
|
-
}
|
|
166
180
|
map(mapper) {
|
|
167
181
|
return this.entries().map((entry, idx) => mapper(entry.value, idx));
|
|
168
182
|
}
|
|
@@ -174,18 +188,27 @@ export class CoList {
|
|
|
174
188
|
reduce(reducer, initialValue) {
|
|
175
189
|
return this.entries().reduce((accumulator, entry, idx) => reducer(accumulator, entry.value, idx), initialValue);
|
|
176
190
|
}
|
|
177
|
-
edit(changer) {
|
|
178
|
-
const editable = new WriteableCoList(this.coValue);
|
|
179
|
-
changer(editable);
|
|
180
|
-
return new CoList(this.coValue);
|
|
181
|
-
}
|
|
182
191
|
subscribe(listener) {
|
|
183
|
-
return this.
|
|
192
|
+
return this.core.subscribe((content) => {
|
|
184
193
|
listener(content);
|
|
185
194
|
});
|
|
186
195
|
}
|
|
196
|
+
edit(changer) {
|
|
197
|
+
const editable = new WriteableCoList(this.core);
|
|
198
|
+
changer(editable);
|
|
199
|
+
return new CoList(this.core);
|
|
200
|
+
}
|
|
187
201
|
}
|
|
188
202
|
export class WriteableCoList extends CoList {
|
|
203
|
+
/** @internal */
|
|
204
|
+
edit(_changer) {
|
|
205
|
+
throw new Error("Already editing.");
|
|
206
|
+
}
|
|
207
|
+
/** Appends a new item after index `after`.
|
|
208
|
+
*
|
|
209
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
210
|
+
*
|
|
211
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
189
212
|
append(after, value, privacy = "private") {
|
|
190
213
|
const entries = this.entries();
|
|
191
214
|
let opIDBefore;
|
|
@@ -202,7 +225,7 @@ export class WriteableCoList extends CoList {
|
|
|
202
225
|
}
|
|
203
226
|
opIDBefore = "start";
|
|
204
227
|
}
|
|
205
|
-
this.
|
|
228
|
+
this.core.makeTransaction([
|
|
206
229
|
{
|
|
207
230
|
op: "app",
|
|
208
231
|
value,
|
|
@@ -211,11 +234,23 @@ export class WriteableCoList extends CoList {
|
|
|
211
234
|
], privacy);
|
|
212
235
|
this.fillOpsFromCoValue();
|
|
213
236
|
}
|
|
237
|
+
/** Pushes a new item to the end of the list.
|
|
238
|
+
*
|
|
239
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
240
|
+
*
|
|
241
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
214
242
|
push(value, privacy = "private") {
|
|
215
243
|
// TODO: optimize
|
|
216
244
|
const entries = this.entries();
|
|
217
245
|
this.append(entries.length > 0 ? entries.length - 1 : 0, value, privacy);
|
|
218
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Prepends a new item before index `before`.
|
|
249
|
+
*
|
|
250
|
+
* If `privacy` is `"private"` **(default)**, both `value` is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
251
|
+
*
|
|
252
|
+
* If `privacy` is `"trusting"`, both `value` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
253
|
+
*/
|
|
219
254
|
prepend(before, value, privacy = "private") {
|
|
220
255
|
const entries = this.entries();
|
|
221
256
|
let opIDAfter;
|
|
@@ -237,7 +272,7 @@ export class WriteableCoList extends CoList {
|
|
|
237
272
|
}
|
|
238
273
|
opIDAfter = "end";
|
|
239
274
|
}
|
|
240
|
-
this.
|
|
275
|
+
this.core.makeTransaction([
|
|
241
276
|
{
|
|
242
277
|
op: "pre",
|
|
243
278
|
value,
|
|
@@ -246,13 +281,18 @@ export class WriteableCoList extends CoList {
|
|
|
246
281
|
], privacy);
|
|
247
282
|
this.fillOpsFromCoValue();
|
|
248
283
|
}
|
|
284
|
+
/** Deletes the item at index `at` from the list.
|
|
285
|
+
*
|
|
286
|
+
* If `privacy` is `"private"` **(default)**, the fact of this deletion is encrypted in the transaction, only readable by other members of the group this `CoList` belongs to. Not even sync servers can see the content in plaintext.
|
|
287
|
+
*
|
|
288
|
+
* If `privacy` is `"trusting"`, the fact of this deletion is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers. */
|
|
249
289
|
delete(at, privacy = "private") {
|
|
250
290
|
const entries = this.entries();
|
|
251
291
|
const entry = entries[at];
|
|
252
292
|
if (!entry) {
|
|
253
293
|
throw new Error("Invalid index " + at);
|
|
254
294
|
}
|
|
255
|
-
this.
|
|
295
|
+
this.core.makeTransaction([
|
|
256
296
|
{
|
|
257
297
|
op: "del",
|
|
258
298
|
insertion: entry.opID,
|