cojson 0.2.2 → 0.3.0-alpha.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/.eslintrc.cjs +1 -0
- package/dist/account.d.ts +8 -8
- package/dist/account.js +2 -2
- package/dist/account.js.map +1 -1
- package/dist/coValue.d.ts +22 -27
- package/dist/coValue.js +21 -0
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.d.ts +7 -7
- package/dist/coValueCore.js +11 -14
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/coList.d.ts +107 -42
- package/dist/coValues/coList.js +163 -72
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.d.ts +109 -50
- package/dist/coValues/coMap.js +161 -109
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts +78 -33
- package/dist/coValues/coStream.js +134 -53
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/crypto.d.ts +8 -3
- package/dist/crypto.js +6 -6
- package/dist/crypto.js.map +1 -1
- package/dist/group.d.ts +59 -23
- package/dist/group.js +83 -25
- package/dist/group.js.map +1 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/{node.d.ts → localNode.d.ts} +23 -11
- package/dist/{node.js → localNode.js} +80 -42
- package/dist/localNode.js.map +1 -0
- package/dist/media.d.ts +1 -2
- package/dist/permissions.js +6 -3
- package/dist/permissions.js.map +1 -1
- package/dist/queriedCoValues/queriedCoList.d.ts +66 -0
- package/dist/queriedCoValues/queriedCoList.js +120 -0
- package/dist/queriedCoValues/queriedCoList.js.map +1 -0
- package/dist/queriedCoValues/queriedCoMap.d.ts +47 -0
- package/dist/queriedCoValues/queriedCoMap.js +83 -0
- package/dist/queriedCoValues/queriedCoMap.js.map +1 -0
- package/dist/queriedCoValues/queriedCoStream.d.ts +40 -0
- package/dist/queriedCoValues/queriedCoStream.js +72 -0
- package/dist/queriedCoValues/queriedCoStream.js.map +1 -0
- package/dist/queries.d.ts +31 -0
- package/dist/queries.js +77 -0
- package/dist/queries.js.map +1 -0
- package/dist/sync.d.ts +1 -1
- package/dist/sync.js +1 -1
- package/dist/sync.js.map +1 -1
- package/dist/{testUtils.d.ts → tests/testUtils.d.ts} +9 -9
- package/dist/{testUtils.js → tests/testUtils.js} +9 -7
- package/dist/tests/testUtils.js.map +1 -0
- package/package.json +2 -2
- package/src/account.ts +6 -6
- package/src/coValue.ts +65 -34
- package/src/coValueCore.ts +18 -22
- package/src/coValues/coList.ts +272 -122
- package/src/coValues/coMap.ts +349 -152
- package/src/coValues/coStream.ts +258 -94
- package/src/crypto.ts +37 -24
- package/src/group.ts +112 -46
- package/src/index.ts +42 -30
- package/src/{node.ts → localNode.ts} +117 -66
- package/src/media.ts +1 -2
- package/src/permissions.ts +15 -18
- package/src/queriedCoValues/queriedCoList.ts +248 -0
- package/src/queriedCoValues/queriedCoMap.ts +180 -0
- package/src/queriedCoValues/queriedCoStream.ts +125 -0
- package/src/queries.ts +142 -0
- package/src/sync.ts +2 -2
- package/src/{account.test.ts → tests/account.test.ts} +6 -9
- package/src/{coValue.test.ts → tests/coValue.test.ts} +120 -114
- package/src/{coValueCore.test.ts → tests/coValueCore.test.ts} +7 -7
- package/src/{crypto.test.ts → tests/crypto.test.ts} +19 -21
- package/src/{group.test.ts → tests/group.test.ts} +2 -2
- package/src/{permissions.test.ts → tests/permissions.test.ts} +260 -247
- package/src/tests/queries.test.ts +318 -0
- package/src/{sync.test.ts → tests/sync.test.ts} +39 -39
- package/src/{testUtils.ts → tests/testUtils.ts} +10 -8
- package/dist/coValues/static.d.ts +0 -14
- package/dist/coValues/static.js +0 -20
- package/dist/coValues/static.js.map +0 -1
- package/dist/node.js.map +0 -1
- package/dist/testUtils.js.map +0 -1
- package/src/coValues/static.ts +0 -31
package/src/coValues/coList.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
2
|
-
import { CoID,
|
|
2
|
+
import { CoID, CoValue, isCoValue } from "../coValue.js";
|
|
3
3
|
import { CoValueCore, accountOrAgentIDfromSessionID } from "../coValueCore.js";
|
|
4
|
-
import { SessionID, TransactionID } from "../ids.js";
|
|
4
|
+
import { AgentID, SessionID, TransactionID } from "../ids.js";
|
|
5
5
|
import { Group } from "../group.js";
|
|
6
|
-
import { AccountID
|
|
6
|
+
import { AccountID } from "../account.js";
|
|
7
7
|
import { parseJSON } from "../jsonStringify.js";
|
|
8
8
|
|
|
9
9
|
type OpID = TransactionID & { changeIdx: number };
|
|
10
10
|
|
|
11
|
-
type InsertionOpPayload<T extends JsonValue> =
|
|
11
|
+
type InsertionOpPayload<T extends JsonValue | CoValue> =
|
|
12
12
|
| {
|
|
13
13
|
op: "pre";
|
|
14
|
-
value: T
|
|
14
|
+
value: T extends CoValue ? CoID<T> : Exclude<T, CoValue>;
|
|
15
15
|
before: OpID | "end";
|
|
16
16
|
}
|
|
17
17
|
| {
|
|
18
18
|
op: "app";
|
|
19
|
-
value: T
|
|
19
|
+
value: T extends CoValue ? CoID<T> : Exclude<T, CoValue>;
|
|
20
20
|
after: OpID | "start";
|
|
21
21
|
};
|
|
22
22
|
|
|
@@ -25,11 +25,11 @@ type DeletionOpPayload = {
|
|
|
25
25
|
insertion: OpID;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export type ListOpPayload<T extends JsonValue> =
|
|
28
|
+
export type ListOpPayload<T extends JsonValue | CoValue> =
|
|
29
29
|
| InsertionOpPayload<T>
|
|
30
30
|
| DeletionOpPayload;
|
|
31
31
|
|
|
32
|
-
type InsertionEntry<T extends JsonValue> = {
|
|
32
|
+
type InsertionEntry<T extends JsonValue | CoValue> = {
|
|
33
33
|
madeAt: number;
|
|
34
34
|
predecessors: OpID[];
|
|
35
35
|
successors: OpID[];
|
|
@@ -40,11 +40,16 @@ type DeletionEntry = {
|
|
|
40
40
|
deletionID: OpID;
|
|
41
41
|
} & DeletionOpPayload;
|
|
42
42
|
|
|
43
|
-
export class
|
|
44
|
-
|
|
43
|
+
export class CoListView<
|
|
44
|
+
Item extends JsonValue | CoValue,
|
|
45
|
+
Meta extends JsonObject | null = null
|
|
46
|
+
> implements CoValue
|
|
45
47
|
{
|
|
46
|
-
|
|
48
|
+
/** @category 6. Meta */
|
|
49
|
+
id: CoID<this>;
|
|
50
|
+
/** @category 6. Meta */
|
|
47
51
|
type = "colist" as const;
|
|
52
|
+
/** @category 6. Meta */
|
|
48
53
|
core: CoValueCore;
|
|
49
54
|
/** @internal */
|
|
50
55
|
afterStart: OpID[];
|
|
@@ -54,7 +59,7 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
54
59
|
insertions: {
|
|
55
60
|
[sessionID: SessionID]: {
|
|
56
61
|
[txIdx: number]: {
|
|
57
|
-
[changeIdx: number]: InsertionEntry<
|
|
62
|
+
[changeIdx: number]: InsertionEntry<Item>;
|
|
58
63
|
};
|
|
59
64
|
};
|
|
60
65
|
};
|
|
@@ -66,29 +71,18 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
66
71
|
};
|
|
67
72
|
};
|
|
68
73
|
};
|
|
74
|
+
/** @category 6. Meta */
|
|
75
|
+
readonly _item!: Item;
|
|
69
76
|
|
|
70
77
|
/** @internal */
|
|
71
78
|
constructor(core: CoValueCore) {
|
|
72
|
-
this.id = core.id as CoID<
|
|
79
|
+
this.id = core.id as CoID<this>;
|
|
73
80
|
this.core = core;
|
|
74
81
|
this.afterStart = [];
|
|
75
82
|
this.beforeEnd = [];
|
|
76
83
|
this.insertions = {};
|
|
77
84
|
this.deletionsByInsertion = {};
|
|
78
85
|
|
|
79
|
-
this.fillOpsFromCoValue();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
get meta(): Meta {
|
|
83
|
-
return this.core.header.meta as Meta;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
get group(): Group {
|
|
87
|
-
return this.core.getGroup();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** @internal */
|
|
91
|
-
protected fillOpsFromCoValue() {
|
|
92
86
|
this.insertions = {};
|
|
93
87
|
this.deletionsByInsertion = {};
|
|
94
88
|
this.afterStart = [];
|
|
@@ -99,8 +93,10 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
99
93
|
changes,
|
|
100
94
|
madeAt,
|
|
101
95
|
} of this.core.getValidSortedTransactions()) {
|
|
102
|
-
for (const [changeIdx, changeUntyped] of parseJSON(
|
|
103
|
-
|
|
96
|
+
for (const [changeIdx, changeUntyped] of parseJSON(
|
|
97
|
+
changes
|
|
98
|
+
).entries()) {
|
|
99
|
+
const change = changeUntyped as ListOpPayload<Item>;
|
|
104
100
|
|
|
105
101
|
if (change.op === "pre" || change.op === "app") {
|
|
106
102
|
let sessionEntry = this.insertions[txID.sessionID];
|
|
@@ -200,8 +196,35 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
200
196
|
}
|
|
201
197
|
}
|
|
202
198
|
|
|
203
|
-
/**
|
|
204
|
-
get(
|
|
199
|
+
/** @category 6. Meta */
|
|
200
|
+
get meta(): Meta {
|
|
201
|
+
return this.core.header.meta as Meta;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @category 6. Meta */
|
|
205
|
+
get group(): Group {
|
|
206
|
+
return this.core.getGroup();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Not yet implemented
|
|
211
|
+
*
|
|
212
|
+
* @category 4. Time travel
|
|
213
|
+
*/
|
|
214
|
+
atTime(_time: number): this {
|
|
215
|
+
throw new Error("Not yet implemented");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get the item currently at `idx`.
|
|
220
|
+
*
|
|
221
|
+
* @category 1. Reading
|
|
222
|
+
*/
|
|
223
|
+
get(
|
|
224
|
+
idx: number
|
|
225
|
+
):
|
|
226
|
+
| (Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>)
|
|
227
|
+
| undefined {
|
|
205
228
|
const entry = this.entries()[idx];
|
|
206
229
|
if (!entry) {
|
|
207
230
|
return undefined;
|
|
@@ -209,13 +232,26 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
209
232
|
return entry.value;
|
|
210
233
|
}
|
|
211
234
|
|
|
212
|
-
/**
|
|
213
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Returns the current items in the CoList as an array.
|
|
237
|
+
*
|
|
238
|
+
* @category 1. Reading
|
|
239
|
+
**/
|
|
240
|
+
asArray(): (Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>)[] {
|
|
214
241
|
return this.entries().map((entry) => entry.value);
|
|
215
242
|
}
|
|
216
243
|
|
|
217
|
-
|
|
218
|
-
|
|
244
|
+
/** @internal */
|
|
245
|
+
entries(): {
|
|
246
|
+
value: Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>;
|
|
247
|
+
madeAt: number;
|
|
248
|
+
opID: OpID;
|
|
249
|
+
}[] {
|
|
250
|
+
const arr: {
|
|
251
|
+
value: Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>;
|
|
252
|
+
madeAt: number;
|
|
253
|
+
opID: OpID;
|
|
254
|
+
}[] = [];
|
|
219
255
|
for (const opID of this.afterStart) {
|
|
220
256
|
this.fillArrayFromOpID(opID, arr);
|
|
221
257
|
}
|
|
@@ -228,7 +264,11 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
228
264
|
/** @internal */
|
|
229
265
|
private fillArrayFromOpID(
|
|
230
266
|
opID: OpID,
|
|
231
|
-
arr: {
|
|
267
|
+
arr: {
|
|
268
|
+
value: Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>;
|
|
269
|
+
madeAt: number;
|
|
270
|
+
opID: OpID;
|
|
271
|
+
}[]
|
|
232
272
|
) {
|
|
233
273
|
const entry =
|
|
234
274
|
this.insertions[opID.sessionID]?.[opID.txIndex]?.[opID.changeIdx];
|
|
@@ -254,86 +294,115 @@ export class CoList<T extends JsonValue, Meta extends JsonObject | null = null>
|
|
|
254
294
|
}
|
|
255
295
|
}
|
|
256
296
|
|
|
257
|
-
/**
|
|
258
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Returns the current items in the CoList as an array. (alias of `asArray`)
|
|
299
|
+
*
|
|
300
|
+
* @category 1. Reading
|
|
301
|
+
*/
|
|
302
|
+
toJSON(): (Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>)[] {
|
|
303
|
+
return this.asArray();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** @category 5. Edit history */
|
|
307
|
+
editAt(idx: number):
|
|
308
|
+
| {
|
|
309
|
+
by: AccountID | AgentID;
|
|
310
|
+
tx: TransactionID;
|
|
311
|
+
at: Date;
|
|
312
|
+
value: Item extends CoValue ? CoID<Item> : Exclude<Item, CoValue>;
|
|
313
|
+
}
|
|
314
|
+
| undefined {
|
|
259
315
|
const entry = this.entries()[idx];
|
|
260
316
|
if (!entry) {
|
|
261
317
|
return undefined;
|
|
262
318
|
}
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
map<U>(mapper: (value: T, idx: number) => U): U[] {
|
|
277
|
-
return this.entries().map((entry, idx) => mapper(entry.value, idx));
|
|
319
|
+
const madeAt = new Date(entry.madeAt);
|
|
320
|
+
const by = accountOrAgentIDfromSessionID(entry.opID.sessionID);
|
|
321
|
+
const value = entry.value;
|
|
322
|
+
return {
|
|
323
|
+
by,
|
|
324
|
+
tx: {
|
|
325
|
+
sessionID: entry.opID.sessionID,
|
|
326
|
+
txIndex: entry.opID.txIndex,
|
|
327
|
+
},
|
|
328
|
+
at: madeAt,
|
|
329
|
+
value,
|
|
330
|
+
};
|
|
278
331
|
}
|
|
279
332
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
333
|
+
/** @category 5. Edit history */
|
|
334
|
+
deletionEdits(): {
|
|
335
|
+
by: AccountID | AgentID;
|
|
336
|
+
tx: TransactionID;
|
|
337
|
+
at: Date;
|
|
338
|
+
// TODO: add indices that are now before and after the deleted item
|
|
339
|
+
}[] {
|
|
340
|
+
const edits: {
|
|
341
|
+
by: AccountID | AgentID;
|
|
342
|
+
tx: TransactionID;
|
|
343
|
+
at: Date;
|
|
344
|
+
}[] = [];
|
|
345
|
+
|
|
346
|
+
for (const sessionID in this.deletionsByInsertion) {
|
|
347
|
+
const sessionEntry =
|
|
348
|
+
this.deletionsByInsertion[sessionID as SessionID];
|
|
349
|
+
for (const txIdx in sessionEntry) {
|
|
350
|
+
const txEntry = sessionEntry[Number(txIdx)];
|
|
351
|
+
for (const changeIdx in txEntry) {
|
|
352
|
+
const changeEntry = txEntry[Number(changeIdx)];
|
|
353
|
+
for (const deletion of changeEntry || []) {
|
|
354
|
+
const madeAt = new Date(deletion.madeAt);
|
|
355
|
+
const by = accountOrAgentIDfromSessionID(
|
|
356
|
+
deletion.deletionID.sessionID
|
|
357
|
+
);
|
|
358
|
+
edits.push({
|
|
359
|
+
by,
|
|
360
|
+
tx: deletion.deletionID,
|
|
361
|
+
at: madeAt,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
286
367
|
|
|
287
|
-
|
|
288
|
-
reducer: (accumulator: U, value: T, idx: number) => U,
|
|
289
|
-
initialValue: U
|
|
290
|
-
): U {
|
|
291
|
-
return this.entries().reduce(
|
|
292
|
-
(accumulator, entry, idx) => reducer(accumulator, entry.value, idx),
|
|
293
|
-
initialValue
|
|
294
|
-
);
|
|
368
|
+
return edits;
|
|
295
369
|
}
|
|
296
370
|
|
|
297
|
-
|
|
371
|
+
/** @category 3. Subscription */
|
|
372
|
+
subscribe(listener: (coList: this) => void): () => void {
|
|
298
373
|
return this.core.subscribe((content) => {
|
|
299
|
-
listener(content as
|
|
374
|
+
listener(content as this);
|
|
300
375
|
});
|
|
301
376
|
}
|
|
302
|
-
|
|
303
|
-
edit(
|
|
304
|
-
changer: (editable: WriteableCoList<T, Meta>) => void
|
|
305
|
-
): CoList<T, Meta> {
|
|
306
|
-
const editable = new WriteableCoList<T, Meta>(this.core);
|
|
307
|
-
changer(editable);
|
|
308
|
-
return new CoList(this.core);
|
|
309
|
-
}
|
|
310
377
|
}
|
|
311
378
|
|
|
312
|
-
export class
|
|
313
|
-
|
|
379
|
+
export class CoList<
|
|
380
|
+
Item extends JsonValue | CoValue,
|
|
314
381
|
Meta extends JsonObject | null = null
|
|
315
382
|
>
|
|
316
|
-
extends
|
|
317
|
-
implements
|
|
383
|
+
extends CoListView<Item, Meta>
|
|
384
|
+
implements CoValue
|
|
318
385
|
{
|
|
319
|
-
/**
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
): CoList<T, Meta> {
|
|
323
|
-
throw new Error("Already editing.");
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/** Appends a new item after index `after`.
|
|
386
|
+
/** Returns a new version of this CoList with `item` appended after the item currently at index `after`.
|
|
387
|
+
*
|
|
388
|
+
* If `privacy` is `"private"` **(default)**, `item` 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.
|
|
327
389
|
*
|
|
328
|
-
* If `privacy` is `"
|
|
390
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
329
391
|
*
|
|
330
|
-
*
|
|
392
|
+
* @category 2. Editing
|
|
393
|
+
**/
|
|
331
394
|
append(
|
|
332
|
-
|
|
333
|
-
|
|
395
|
+
item: Item extends CoValue ? Item | CoID<Item> : Item,
|
|
396
|
+
after?: number,
|
|
334
397
|
privacy: "private" | "trusting" = "private"
|
|
335
|
-
):
|
|
398
|
+
): this {
|
|
336
399
|
const entries = this.entries();
|
|
400
|
+
after =
|
|
401
|
+
after === undefined
|
|
402
|
+
? entries.length > 0
|
|
403
|
+
? entries.length - 1
|
|
404
|
+
: 0
|
|
405
|
+
: 0;
|
|
337
406
|
let opIDBefore;
|
|
338
407
|
if (entries.length > 0) {
|
|
339
408
|
const entryBefore = entries[after];
|
|
@@ -351,44 +420,32 @@ export class WriteableCoList<
|
|
|
351
420
|
[
|
|
352
421
|
{
|
|
353
422
|
op: "app",
|
|
354
|
-
value,
|
|
423
|
+
value: isCoValue(item) ? item.id : item,
|
|
355
424
|
after: opIDBefore,
|
|
356
425
|
},
|
|
357
426
|
],
|
|
358
427
|
privacy
|
|
359
428
|
);
|
|
360
429
|
|
|
361
|
-
this.
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/** Pushes a new item to the end of the list.
|
|
365
|
-
*
|
|
366
|
-
* 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.
|
|
367
|
-
*
|
|
368
|
-
* 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. */
|
|
369
|
-
push(value: T, privacy: "private" | "trusting" = "private"): void {
|
|
370
|
-
// TODO: optimize
|
|
371
|
-
const entries = this.entries();
|
|
372
|
-
this.append(
|
|
373
|
-
entries.length > 0 ? entries.length - 1 : 0,
|
|
374
|
-
value,
|
|
375
|
-
privacy
|
|
376
|
-
);
|
|
430
|
+
return new CoList(this.core) as this;
|
|
377
431
|
}
|
|
378
432
|
|
|
379
433
|
/**
|
|
380
|
-
*
|
|
434
|
+
* Returns a new version of this CoList with `item` prepended before the item currently at index `before`.
|
|
435
|
+
*
|
|
436
|
+
* If `privacy` is `"private"` **(default)**, `item` 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.
|
|
381
437
|
*
|
|
382
|
-
* If `privacy` is `"
|
|
438
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
383
439
|
*
|
|
384
|
-
*
|
|
440
|
+
* @category 2. Editing
|
|
385
441
|
*/
|
|
386
442
|
prepend(
|
|
387
|
-
|
|
388
|
-
|
|
443
|
+
item: Item extends CoValue ? Item | CoID<Item> : Item,
|
|
444
|
+
before?: number,
|
|
389
445
|
privacy: "private" | "trusting" = "private"
|
|
390
|
-
):
|
|
446
|
+
): this {
|
|
391
447
|
const entries = this.entries();
|
|
448
|
+
before = before === undefined ? 0 : before;
|
|
392
449
|
let opIDAfter;
|
|
393
450
|
if (entries.length > 0) {
|
|
394
451
|
const entryAfter = entries[before];
|
|
@@ -410,22 +467,25 @@ export class WriteableCoList<
|
|
|
410
467
|
[
|
|
411
468
|
{
|
|
412
469
|
op: "pre",
|
|
413
|
-
value,
|
|
470
|
+
value: isCoValue(item) ? item.id : item,
|
|
414
471
|
before: opIDAfter,
|
|
415
472
|
},
|
|
416
473
|
],
|
|
417
474
|
privacy
|
|
418
475
|
);
|
|
419
476
|
|
|
420
|
-
this.
|
|
477
|
+
return new CoList(this.core) as this;
|
|
421
478
|
}
|
|
422
479
|
|
|
423
|
-
/**
|
|
480
|
+
/** Returns a new version of this CoList with the item at index `at` deleted from the list.
|
|
424
481
|
*
|
|
425
482
|
* 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.
|
|
426
483
|
*
|
|
427
|
-
* 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.
|
|
428
|
-
|
|
484
|
+
* 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.
|
|
485
|
+
*
|
|
486
|
+
* @category 2. Editing
|
|
487
|
+
**/
|
|
488
|
+
delete(at: number, privacy: "private" | "trusting" = "private"): this {
|
|
429
489
|
const entries = this.entries();
|
|
430
490
|
const entry = entries[at];
|
|
431
491
|
if (!entry) {
|
|
@@ -441,6 +501,96 @@ export class WriteableCoList<
|
|
|
441
501
|
privacy
|
|
442
502
|
);
|
|
443
503
|
|
|
444
|
-
this.
|
|
504
|
+
return new CoList(this.core) as this;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/** @category 2. Editing */
|
|
508
|
+
mutate(mutator: (mutable: MutableCoList<Item, Meta>) => void): this {
|
|
509
|
+
const mutable = new MutableCoList<Item, Meta>(this.core);
|
|
510
|
+
mutator(mutable);
|
|
511
|
+
return new CoList(this.core) as this;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/** @deprecated Use `mutate` instead. */
|
|
515
|
+
edit(mutator: (mutable: MutableCoList<Item, Meta>) => void): this {
|
|
516
|
+
return this.mutate(mutator);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export class MutableCoList<
|
|
521
|
+
Item extends JsonValue | CoValue,
|
|
522
|
+
Meta extends JsonObject | null = null
|
|
523
|
+
>
|
|
524
|
+
extends CoListView<Item, Meta>
|
|
525
|
+
implements CoValue
|
|
526
|
+
{
|
|
527
|
+
/** Appends `item` after the item currently at index `after`.
|
|
528
|
+
*
|
|
529
|
+
* If `privacy` is `"private"` **(default)**, `item` 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.
|
|
530
|
+
*
|
|
531
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
532
|
+
*
|
|
533
|
+
* @category 2. Mutating
|
|
534
|
+
**/
|
|
535
|
+
append(
|
|
536
|
+
item: Item extends CoValue ? Item | CoID<Item> : Item,
|
|
537
|
+
after?: number,
|
|
538
|
+
privacy: "private" | "trusting" = "private"
|
|
539
|
+
): void {
|
|
540
|
+
const listAfter = CoList.prototype.append.call(
|
|
541
|
+
this,
|
|
542
|
+
item,
|
|
543
|
+
after,
|
|
544
|
+
privacy
|
|
545
|
+
) as CoList<Item, Meta>;
|
|
546
|
+
this.afterStart = listAfter.afterStart;
|
|
547
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
548
|
+
this.insertions = listAfter.insertions;
|
|
549
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Prepends `item` before the item currently at index `before`.
|
|
553
|
+
*
|
|
554
|
+
* If `privacy` is `"private"` **(default)**, `item` 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.
|
|
555
|
+
*
|
|
556
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
557
|
+
*
|
|
558
|
+
* * @category 2. Mutating
|
|
559
|
+
**/
|
|
560
|
+
prepend(
|
|
561
|
+
item: Item extends CoValue ? Item | CoID<Item> : Item,
|
|
562
|
+
before?: number,
|
|
563
|
+
privacy: "private" | "trusting" = "private"
|
|
564
|
+
): void {
|
|
565
|
+
const listAfter = CoList.prototype.prepend.call(
|
|
566
|
+
this,
|
|
567
|
+
item,
|
|
568
|
+
before,
|
|
569
|
+
privacy
|
|
570
|
+
) as CoList<Item, Meta>;
|
|
571
|
+
this.afterStart = listAfter.afterStart;
|
|
572
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
573
|
+
this.insertions = listAfter.insertions;
|
|
574
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/** Deletes the item at index `at` from the list.
|
|
578
|
+
*
|
|
579
|
+
* 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.
|
|
580
|
+
*
|
|
581
|
+
* 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.
|
|
582
|
+
*
|
|
583
|
+
* * @category 2. Mutating
|
|
584
|
+
**/
|
|
585
|
+
delete(at: number, privacy: "private" | "trusting" = "private"): void {
|
|
586
|
+
const listAfter = CoList.prototype.delete.call(
|
|
587
|
+
this,
|
|
588
|
+
at,
|
|
589
|
+
privacy
|
|
590
|
+
) as CoList<Item, Meta>;
|
|
591
|
+
this.afterStart = listAfter.afterStart;
|
|
592
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
593
|
+
this.insertions = listAfter.insertions;
|
|
594
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
445
595
|
}
|
|
446
596
|
}
|