cojson 0.8.12 → 0.8.17
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/CHANGELOG.md +95 -83
- package/dist/native/PeerKnownStates.js +6 -1
- package/dist/native/PeerKnownStates.js.map +1 -1
- package/dist/native/PeerState.js +4 -3
- package/dist/native/PeerState.js.map +1 -1
- package/dist/native/PriorityBasedMessageQueue.js +1 -10
- package/dist/native/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/native/SyncStateSubscriptionManager.js +70 -0
- package/dist/native/SyncStateSubscriptionManager.js.map +1 -0
- package/dist/native/base64url.js.map +1 -1
- package/dist/native/base64url.test.js +1 -1
- package/dist/native/base64url.test.js.map +1 -1
- package/dist/native/coValue.js.map +1 -1
- package/dist/native/coValueCore.js +141 -149
- package/dist/native/coValueCore.js.map +1 -1
- package/dist/native/coValueState.js.map +1 -1
- package/dist/native/coValues/account.js +6 -6
- package/dist/native/coValues/account.js.map +1 -1
- package/dist/native/coValues/coList.js +2 -3
- package/dist/native/coValues/coList.js.map +1 -1
- package/dist/native/coValues/coMap.js +1 -1
- package/dist/native/coValues/coMap.js.map +1 -1
- package/dist/native/coValues/coStream.js +3 -5
- package/dist/native/coValues/coStream.js.map +1 -1
- package/dist/native/coValues/group.js +11 -11
- package/dist/native/coValues/group.js.map +1 -1
- package/dist/native/coreToCoValue.js +2 -2
- package/dist/native/coreToCoValue.js.map +1 -1
- package/dist/native/crypto/PureJSCrypto.js +4 -4
- package/dist/native/crypto/PureJSCrypto.js.map +1 -1
- package/dist/native/crypto/crypto.js.map +1 -1
- package/dist/native/exports.js +12 -12
- package/dist/native/exports.js.map +1 -1
- package/dist/native/ids.js.map +1 -1
- package/dist/native/jsonStringify.js.map +1 -1
- package/dist/native/localNode.js +5 -7
- package/dist/native/localNode.js.map +1 -1
- package/dist/native/permissions.js +4 -7
- package/dist/native/permissions.js.map +1 -1
- package/dist/native/priority.js.map +1 -1
- package/dist/native/storage/FileSystem.js.map +1 -1
- package/dist/native/storage/chunksAndKnownStates.js +2 -4
- package/dist/native/storage/chunksAndKnownStates.js.map +1 -1
- package/dist/native/storage/index.js +6 -15
- package/dist/native/storage/index.js.map +1 -1
- package/dist/native/streamUtils.js.map +1 -1
- package/dist/native/sync.js +57 -7
- package/dist/native/sync.js.map +1 -1
- package/dist/native/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -1
- package/dist/native/typeUtils/expectGroup.js.map +1 -1
- package/dist/native/typeUtils/isAccountID.js.map +1 -1
- package/dist/native/typeUtils/isCoValue.js +1 -1
- package/dist/native/typeUtils/isCoValue.js.map +1 -1
- package/dist/web/PeerKnownStates.js +6 -1
- package/dist/web/PeerKnownStates.js.map +1 -1
- package/dist/web/PeerState.js +4 -3
- package/dist/web/PeerState.js.map +1 -1
- package/dist/web/PriorityBasedMessageQueue.js +1 -10
- package/dist/web/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/web/SyncStateSubscriptionManager.js +70 -0
- package/dist/web/SyncStateSubscriptionManager.js.map +1 -0
- package/dist/web/base64url.js.map +1 -1
- package/dist/web/base64url.test.js +1 -1
- package/dist/web/base64url.test.js.map +1 -1
- package/dist/web/coValue.js.map +1 -1
- package/dist/web/coValueCore.js +141 -149
- package/dist/web/coValueCore.js.map +1 -1
- package/dist/web/coValueState.js.map +1 -1
- package/dist/web/coValues/account.js +6 -6
- package/dist/web/coValues/account.js.map +1 -1
- package/dist/web/coValues/coList.js +2 -3
- package/dist/web/coValues/coList.js.map +1 -1
- package/dist/web/coValues/coMap.js +1 -1
- package/dist/web/coValues/coMap.js.map +1 -1
- package/dist/web/coValues/coStream.js +3 -5
- package/dist/web/coValues/coStream.js.map +1 -1
- package/dist/web/coValues/group.js +11 -11
- package/dist/web/coValues/group.js.map +1 -1
- package/dist/web/coreToCoValue.js +2 -2
- package/dist/web/coreToCoValue.js.map +1 -1
- package/dist/web/crypto/PureJSCrypto.js +4 -4
- package/dist/web/crypto/PureJSCrypto.js.map +1 -1
- package/dist/web/crypto/WasmCrypto.js +5 -5
- package/dist/web/crypto/WasmCrypto.js.map +1 -1
- package/dist/web/crypto/crypto.js.map +1 -1
- package/dist/web/exports.js +12 -12
- package/dist/web/exports.js.map +1 -1
- package/dist/web/ids.js.map +1 -1
- package/dist/web/jsonStringify.js.map +1 -1
- package/dist/web/localNode.js +5 -7
- package/dist/web/localNode.js.map +1 -1
- package/dist/web/permissions.js +4 -7
- package/dist/web/permissions.js.map +1 -1
- package/dist/web/priority.js.map +1 -1
- package/dist/web/storage/FileSystem.js.map +1 -1
- package/dist/web/storage/chunksAndKnownStates.js +2 -4
- package/dist/web/storage/chunksAndKnownStates.js.map +1 -1
- package/dist/web/storage/index.js +6 -15
- package/dist/web/storage/index.js.map +1 -1
- package/dist/web/streamUtils.js.map +1 -1
- package/dist/web/sync.js +57 -7
- package/dist/web/sync.js.map +1 -1
- package/dist/web/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -1
- package/dist/web/typeUtils/expectGroup.js.map +1 -1
- package/dist/web/typeUtils/isAccountID.js.map +1 -1
- package/dist/web/typeUtils/isCoValue.js +1 -1
- package/dist/web/typeUtils/isCoValue.js.map +1 -1
- package/package.json +4 -14
- package/src/PeerKnownStates.ts +98 -90
- package/src/PeerState.ts +92 -73
- package/src/PriorityBasedMessageQueue.ts +42 -49
- package/src/SyncStateSubscriptionManager.ts +124 -0
- package/src/base64url.test.ts +24 -24
- package/src/base64url.ts +44 -45
- package/src/coValue.ts +45 -45
- package/src/coValueCore.ts +746 -785
- package/src/coValueState.ts +82 -72
- package/src/coValues/account.ts +143 -150
- package/src/coValues/coList.ts +520 -522
- package/src/coValues/coMap.ts +283 -285
- package/src/coValues/coStream.ts +320 -324
- package/src/coValues/group.ts +306 -305
- package/src/coreToCoValue.ts +28 -31
- package/src/crypto/PureJSCrypto.ts +188 -194
- package/src/crypto/WasmCrypto.ts +236 -254
- package/src/crypto/crypto.ts +302 -309
- package/src/exports.ts +116 -116
- package/src/ids.ts +9 -9
- package/src/jsonStringify.ts +46 -46
- package/src/jsonValue.ts +24 -10
- package/src/localNode.ts +635 -660
- package/src/media.ts +3 -3
- package/src/permissions.ts +272 -278
- package/src/priority.ts +21 -19
- package/src/storage/FileSystem.ts +91 -99
- package/src/storage/chunksAndKnownStates.ts +110 -115
- package/src/storage/index.ts +466 -497
- package/src/streamUtils.ts +60 -60
- package/src/sync.ts +656 -608
- package/src/tests/PeerKnownStates.test.ts +38 -34
- package/src/tests/PeerState.test.ts +101 -64
- package/src/tests/PriorityBasedMessageQueue.test.ts +91 -91
- package/src/tests/SyncStateSubscriptionManager.test.ts +232 -0
- package/src/tests/account.test.ts +59 -59
- package/src/tests/coList.test.ts +65 -65
- package/src/tests/coMap.test.ts +137 -137
- package/src/tests/coStream.test.ts +254 -257
- package/src/tests/coValueCore.test.ts +153 -156
- package/src/tests/crypto.test.ts +136 -144
- package/src/tests/cryptoImpl.test.ts +205 -197
- package/src/tests/group.test.ts +24 -24
- package/src/tests/permissions.test.ts +1306 -1371
- package/src/tests/priority.test.ts +65 -82
- package/src/tests/sync.test.ts +1573 -1263
- package/src/tests/testUtils.ts +85 -53
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +4 -4
- package/src/typeUtils/expectGroup.ts +9 -9
- package/src/typeUtils/isAccountID.ts +1 -1
- package/src/typeUtils/isCoValue.ts +9 -9
- package/tsconfig.json +4 -6
- package/tsconfig.native.json +9 -11
- package/tsconfig.web.json +4 -10
- package/.eslintrc.cjs +0 -25
- package/.prettierrc.js +0 -9
package/src/coValues/coList.ts
CHANGED
|
@@ -1,577 +1,575 @@
|
|
|
1
|
-
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
2
1
|
import { CoID, RawCoValue } from "../coValue.js";
|
|
3
|
-
import { isCoValue } from "../typeUtils/isCoValue.js";
|
|
4
2
|
import { CoValueCore } from "../coValueCore.js";
|
|
5
|
-
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
6
3
|
import { AgentID, SessionID, TransactionID } from "../ids.js";
|
|
4
|
+
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
5
|
+
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
6
|
+
import { isCoValue } from "../typeUtils/isCoValue.js";
|
|
7
7
|
import { RawAccountID } from "./account.js";
|
|
8
8
|
import { RawGroup } from "./group.js";
|
|
9
9
|
|
|
10
10
|
type OpID = TransactionID & { changeIdx: number };
|
|
11
11
|
|
|
12
12
|
type InsertionOpPayload<T extends JsonValue> =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
| {
|
|
14
|
+
op: "pre";
|
|
15
|
+
value: T;
|
|
16
|
+
before: OpID | "end";
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
op: "app";
|
|
20
|
+
value: T;
|
|
21
|
+
after: OpID | "start";
|
|
22
|
+
};
|
|
23
23
|
|
|
24
24
|
type DeletionOpPayload = {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
op: "del";
|
|
26
|
+
insertion: OpID;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
export type ListOpPayload<T extends JsonValue> =
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
| InsertionOpPayload<T>
|
|
31
|
+
| DeletionOpPayload;
|
|
32
32
|
|
|
33
33
|
type InsertionEntry<T extends JsonValue> = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
madeAt: number;
|
|
35
|
+
predecessors: OpID[];
|
|
36
|
+
successors: OpID[];
|
|
37
37
|
} & InsertionOpPayload<T>;
|
|
38
38
|
|
|
39
39
|
type DeletionEntry = {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
madeAt: number;
|
|
41
|
+
deletionID: OpID;
|
|
42
42
|
} & DeletionOpPayload;
|
|
43
43
|
|
|
44
44
|
export class RawCoListView<
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
Item extends JsonValue = JsonValue,
|
|
46
|
+
Meta extends JsonObject | null = null,
|
|
47
47
|
> implements RawCoValue
|
|
48
48
|
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
};
|
|
49
|
+
/** @category 6. Meta */
|
|
50
|
+
id: CoID<this>;
|
|
51
|
+
/** @category 6. Meta */
|
|
52
|
+
type = "colist" as const;
|
|
53
|
+
/** @category 6. Meta */
|
|
54
|
+
core: CoValueCore;
|
|
55
|
+
/** @internal */
|
|
56
|
+
afterStart: OpID[];
|
|
57
|
+
/** @internal */
|
|
58
|
+
beforeEnd: OpID[];
|
|
59
|
+
/** @internal */
|
|
60
|
+
insertions: {
|
|
61
|
+
[sessionID: SessionID]: {
|
|
62
|
+
[txIdx: number]: {
|
|
63
|
+
[changeIdx: number]: InsertionEntry<Item>;
|
|
64
|
+
};
|
|
66
65
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
};
|
|
67
|
+
/** @internal */
|
|
68
|
+
deletionsByInsertion: {
|
|
69
|
+
[deletedSessionID: SessionID]: {
|
|
70
|
+
[deletedTxIdx: number]: {
|
|
71
|
+
[deletedChangeIdx: number]: DeletionEntry[];
|
|
72
|
+
};
|
|
74
73
|
};
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
};
|
|
75
|
+
/** @category 6. Meta */
|
|
76
|
+
readonly _item!: Item;
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
/** @internal */
|
|
79
|
+
_cachedEntries?: {
|
|
80
|
+
value: Item;
|
|
81
|
+
madeAt: number;
|
|
82
|
+
opID: OpID;
|
|
83
|
+
}[];
|
|
84
|
+
|
|
85
|
+
/** @internal */
|
|
86
|
+
constructor(core: CoValueCore) {
|
|
87
|
+
this.id = core.id as CoID<this>;
|
|
88
|
+
this.core = core;
|
|
89
|
+
this.afterStart = [];
|
|
90
|
+
this.beforeEnd = [];
|
|
91
|
+
this.insertions = {};
|
|
92
|
+
this.deletionsByInsertion = {};
|
|
93
|
+
|
|
94
|
+
this.insertions = {};
|
|
95
|
+
this.deletionsByInsertion = {};
|
|
96
|
+
this.afterStart = [];
|
|
97
|
+
this.beforeEnd = [];
|
|
98
|
+
|
|
99
|
+
for (const {
|
|
100
|
+
txID,
|
|
101
|
+
changes,
|
|
102
|
+
madeAt,
|
|
103
|
+
} of this.core.getValidSortedTransactions()) {
|
|
104
|
+
for (const [changeIdx, changeUntyped] of changes.entries()) {
|
|
105
|
+
const change = changeUntyped as ListOpPayload<Item>;
|
|
106
|
+
|
|
107
|
+
if (change.op === "pre" || change.op === "app") {
|
|
108
|
+
let sessionEntry = this.insertions[txID.sessionID];
|
|
109
|
+
if (!sessionEntry) {
|
|
110
|
+
sessionEntry = {};
|
|
111
|
+
this.insertions[txID.sessionID] = sessionEntry;
|
|
112
|
+
}
|
|
113
|
+
let txEntry = sessionEntry[txID.txIndex];
|
|
114
|
+
if (!txEntry) {
|
|
115
|
+
txEntry = {};
|
|
116
|
+
sessionEntry[txID.txIndex] = txEntry;
|
|
117
|
+
}
|
|
118
|
+
txEntry[changeIdx] = {
|
|
102
119
|
madeAt,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
changeIdx,
|
|
152
|
-
});
|
|
153
|
-
} else {
|
|
154
|
-
const afterEntry =
|
|
155
|
-
this.insertions[change.after.sessionID]?.[
|
|
156
|
-
change.after.txIndex
|
|
157
|
-
]?.[change.after.changeIdx];
|
|
158
|
-
if (!afterEntry) {
|
|
159
|
-
// console.error(
|
|
160
|
-
// "Insertion after missing op " + change.after
|
|
161
|
-
// );
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
afterEntry.successors.push({
|
|
165
|
-
...txID,
|
|
166
|
-
changeIdx,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
} else if (change.op === "del") {
|
|
171
|
-
let sessionEntry =
|
|
172
|
-
this.deletionsByInsertion[change.insertion.sessionID];
|
|
173
|
-
if (!sessionEntry) {
|
|
174
|
-
sessionEntry = {};
|
|
175
|
-
this.deletionsByInsertion[change.insertion.sessionID] =
|
|
176
|
-
sessionEntry;
|
|
177
|
-
}
|
|
178
|
-
let txEntry = sessionEntry[change.insertion.txIndex];
|
|
179
|
-
if (!txEntry) {
|
|
180
|
-
txEntry = {};
|
|
181
|
-
sessionEntry[change.insertion.txIndex] = txEntry;
|
|
182
|
-
}
|
|
183
|
-
let changeEntry = txEntry[change.insertion.changeIdx];
|
|
184
|
-
if (!changeEntry) {
|
|
185
|
-
changeEntry = [];
|
|
186
|
-
txEntry[change.insertion.changeIdx] = changeEntry;
|
|
187
|
-
}
|
|
188
|
-
changeEntry.push({
|
|
189
|
-
madeAt,
|
|
190
|
-
deletionID: {
|
|
191
|
-
...txID,
|
|
192
|
-
changeIdx,
|
|
193
|
-
},
|
|
194
|
-
...change,
|
|
195
|
-
});
|
|
196
|
-
} else {
|
|
197
|
-
throw new Error(
|
|
198
|
-
"Unknown list operation " +
|
|
199
|
-
(change as { op: unknown }).op,
|
|
200
|
-
);
|
|
201
|
-
}
|
|
120
|
+
predecessors: [],
|
|
121
|
+
successors: [],
|
|
122
|
+
...change,
|
|
123
|
+
};
|
|
124
|
+
if (change.op === "pre") {
|
|
125
|
+
if (change.before === "end") {
|
|
126
|
+
this.beforeEnd.push({
|
|
127
|
+
...txID,
|
|
128
|
+
changeIdx,
|
|
129
|
+
});
|
|
130
|
+
} else {
|
|
131
|
+
const beforeEntry =
|
|
132
|
+
this.insertions[change.before.sessionID]?.[
|
|
133
|
+
change.before.txIndex
|
|
134
|
+
]?.[change.before.changeIdx];
|
|
135
|
+
if (!beforeEntry) {
|
|
136
|
+
// console.error(
|
|
137
|
+
// "Insertion before missing op " +
|
|
138
|
+
// change.before
|
|
139
|
+
// );
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
beforeEntry.predecessors.splice(0, 0, {
|
|
143
|
+
...txID,
|
|
144
|
+
changeIdx,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
if (change.after === "start") {
|
|
149
|
+
this.afterStart.push({
|
|
150
|
+
...txID,
|
|
151
|
+
changeIdx,
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
const afterEntry =
|
|
155
|
+
this.insertions[change.after.sessionID]?.[
|
|
156
|
+
change.after.txIndex
|
|
157
|
+
]?.[change.after.changeIdx];
|
|
158
|
+
if (!afterEntry) {
|
|
159
|
+
// console.error(
|
|
160
|
+
// "Insertion after missing op " + change.after
|
|
161
|
+
// );
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
afterEntry.successors.push({
|
|
165
|
+
...txID,
|
|
166
|
+
changeIdx,
|
|
167
|
+
});
|
|
202
168
|
}
|
|
169
|
+
}
|
|
170
|
+
} else if (change.op === "del") {
|
|
171
|
+
let sessionEntry =
|
|
172
|
+
this.deletionsByInsertion[change.insertion.sessionID];
|
|
173
|
+
if (!sessionEntry) {
|
|
174
|
+
sessionEntry = {};
|
|
175
|
+
this.deletionsByInsertion[change.insertion.sessionID] =
|
|
176
|
+
sessionEntry;
|
|
177
|
+
}
|
|
178
|
+
let txEntry = sessionEntry[change.insertion.txIndex];
|
|
179
|
+
if (!txEntry) {
|
|
180
|
+
txEntry = {};
|
|
181
|
+
sessionEntry[change.insertion.txIndex] = txEntry;
|
|
182
|
+
}
|
|
183
|
+
let changeEntry = txEntry[change.insertion.changeIdx];
|
|
184
|
+
if (!changeEntry) {
|
|
185
|
+
changeEntry = [];
|
|
186
|
+
txEntry[change.insertion.changeIdx] = changeEntry;
|
|
187
|
+
}
|
|
188
|
+
changeEntry.push({
|
|
189
|
+
madeAt,
|
|
190
|
+
deletionID: {
|
|
191
|
+
...txID,
|
|
192
|
+
changeIdx,
|
|
193
|
+
},
|
|
194
|
+
...change,
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
throw new Error(
|
|
198
|
+
"Unknown list operation " + (change as { op: unknown }).op,
|
|
199
|
+
);
|
|
203
200
|
}
|
|
201
|
+
}
|
|
204
202
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** @category 6. Meta */
|
|
206
|
+
get headerMeta(): Meta {
|
|
207
|
+
return this.core.header.meta as Meta;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** @category 6. Meta */
|
|
211
|
+
get group(): RawGroup {
|
|
212
|
+
return this.core.getGroup();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Not yet implemented
|
|
217
|
+
*
|
|
218
|
+
* @category 4. Time travel
|
|
219
|
+
*/
|
|
220
|
+
atTime(_time: number): this {
|
|
221
|
+
throw new Error("Not yet implemented");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get the item currently at `idx`.
|
|
226
|
+
*
|
|
227
|
+
* @category 1. Reading
|
|
228
|
+
*/
|
|
229
|
+
get(idx: number): Item | undefined {
|
|
230
|
+
const entry = this.entries()[idx];
|
|
231
|
+
if (!entry) {
|
|
232
|
+
return undefined;
|
|
209
233
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
234
|
+
return entry.value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Returns the current items in the CoList as an array.
|
|
239
|
+
*
|
|
240
|
+
* @category 1. Reading
|
|
241
|
+
**/
|
|
242
|
+
asArray(): Item[] {
|
|
243
|
+
return this.entries().map((entry) => entry.value);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** @internal */
|
|
247
|
+
entries(): {
|
|
248
|
+
value: Item;
|
|
249
|
+
madeAt: number;
|
|
250
|
+
opID: OpID;
|
|
251
|
+
}[] {
|
|
252
|
+
if (this._cachedEntries) {
|
|
253
|
+
return this._cachedEntries;
|
|
214
254
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
255
|
+
const arr = this.entriesUncached();
|
|
256
|
+
this._cachedEntries = arr;
|
|
257
|
+
return arr;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** @internal */
|
|
261
|
+
entriesUncached(): {
|
|
262
|
+
value: Item;
|
|
263
|
+
madeAt: number;
|
|
264
|
+
opID: OpID;
|
|
265
|
+
}[] {
|
|
266
|
+
const arr: {
|
|
267
|
+
value: Item;
|
|
268
|
+
madeAt: number;
|
|
269
|
+
opID: OpID;
|
|
270
|
+
}[] = [];
|
|
271
|
+
for (const opID of this.afterStart) {
|
|
272
|
+
this.fillArrayFromOpID(opID, arr);
|
|
223
273
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
* Get the item currently at `idx`.
|
|
227
|
-
*
|
|
228
|
-
* @category 1. Reading
|
|
229
|
-
*/
|
|
230
|
-
get(idx: number): Item | undefined {
|
|
231
|
-
const entry = this.entries()[idx];
|
|
232
|
-
if (!entry) {
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
return entry.value;
|
|
274
|
+
for (const opID of this.beforeEnd) {
|
|
275
|
+
this.fillArrayFromOpID(opID, arr);
|
|
236
276
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
277
|
+
return arr;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** @internal */
|
|
281
|
+
private fillArrayFromOpID(
|
|
282
|
+
opID: OpID,
|
|
283
|
+
arr: {
|
|
284
|
+
value: Item;
|
|
285
|
+
madeAt: number;
|
|
286
|
+
opID: OpID;
|
|
287
|
+
}[],
|
|
288
|
+
) {
|
|
289
|
+
const entry =
|
|
290
|
+
this.insertions[opID.sessionID]?.[opID.txIndex]?.[opID.changeIdx];
|
|
291
|
+
if (!entry) {
|
|
292
|
+
throw new Error("Missing op " + opID);
|
|
245
293
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
entries(): {
|
|
249
|
-
value: Item;
|
|
250
|
-
madeAt: number;
|
|
251
|
-
opID: OpID;
|
|
252
|
-
}[] {
|
|
253
|
-
if (this._cachedEntries) {
|
|
254
|
-
return this._cachedEntries;
|
|
255
|
-
}
|
|
256
|
-
const arr = this.entriesUncached();
|
|
257
|
-
this._cachedEntries = arr;
|
|
258
|
-
return arr;
|
|
294
|
+
for (const predecessor of entry.predecessors) {
|
|
295
|
+
this.fillArrayFromOpID(predecessor, arr);
|
|
259
296
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
opID: OpID;
|
|
271
|
-
}[] = [];
|
|
272
|
-
for (const opID of this.afterStart) {
|
|
273
|
-
this.fillArrayFromOpID(opID, arr);
|
|
274
|
-
}
|
|
275
|
-
for (const opID of this.beforeEnd) {
|
|
276
|
-
this.fillArrayFromOpID(opID, arr);
|
|
277
|
-
}
|
|
278
|
-
return arr;
|
|
297
|
+
const deleted =
|
|
298
|
+
(this.deletionsByInsertion[opID.sessionID]?.[opID.txIndex]?.[
|
|
299
|
+
opID.changeIdx
|
|
300
|
+
]?.length || 0) > 0;
|
|
301
|
+
if (!deleted) {
|
|
302
|
+
arr.push({
|
|
303
|
+
value: entry.value,
|
|
304
|
+
madeAt: entry.madeAt,
|
|
305
|
+
opID,
|
|
306
|
+
});
|
|
279
307
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
arr: {
|
|
285
|
-
value: Item;
|
|
286
|
-
madeAt: number;
|
|
287
|
-
opID: OpID;
|
|
288
|
-
}[],
|
|
289
|
-
) {
|
|
290
|
-
const entry =
|
|
291
|
-
this.insertions[opID.sessionID]?.[opID.txIndex]?.[opID.changeIdx];
|
|
292
|
-
if (!entry) {
|
|
293
|
-
throw new Error("Missing op " + opID);
|
|
294
|
-
}
|
|
295
|
-
for (const predecessor of entry.predecessors) {
|
|
296
|
-
this.fillArrayFromOpID(predecessor, arr);
|
|
297
|
-
}
|
|
298
|
-
const deleted =
|
|
299
|
-
(this.deletionsByInsertion[opID.sessionID]?.[opID.txIndex]?.[
|
|
300
|
-
opID.changeIdx
|
|
301
|
-
]?.length || 0) > 0;
|
|
302
|
-
if (!deleted) {
|
|
303
|
-
arr.push({
|
|
304
|
-
value: entry.value,
|
|
305
|
-
madeAt: entry.madeAt,
|
|
306
|
-
opID,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
// traverse successors in reverse for correct insertion behavior
|
|
310
|
-
for (let i = entry.successors.length - 1; i >= 0; i--) {
|
|
311
|
-
const successor = entry.successors[i]!;
|
|
312
|
-
this.fillArrayFromOpID(successor, arr);
|
|
313
|
-
}
|
|
308
|
+
// traverse successors in reverse for correct insertion behavior
|
|
309
|
+
for (let i = entry.successors.length - 1; i >= 0; i--) {
|
|
310
|
+
const successor = entry.successors[i]!;
|
|
311
|
+
this.fillArrayFromOpID(successor, arr);
|
|
314
312
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
tx: TransactionID;
|
|
330
|
-
at: Date;
|
|
331
|
-
value: Item;
|
|
332
|
-
}
|
|
333
|
-
| undefined {
|
|
334
|
-
const entry = this.entries()[idx];
|
|
335
|
-
if (!entry) {
|
|
336
|
-
return undefined;
|
|
337
|
-
}
|
|
338
|
-
const madeAt = new Date(entry.madeAt);
|
|
339
|
-
const by = accountOrAgentIDfromSessionID(entry.opID.sessionID);
|
|
340
|
-
const value = entry.value;
|
|
341
|
-
return {
|
|
342
|
-
by,
|
|
343
|
-
tx: {
|
|
344
|
-
sessionID: entry.opID.sessionID,
|
|
345
|
-
txIndex: entry.opID.txIndex,
|
|
346
|
-
},
|
|
347
|
-
at: madeAt,
|
|
348
|
-
value,
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/** @category 5. Edit history */
|
|
353
|
-
deletionEdits(): {
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Returns the current items in the CoList as an array. (alias of `asArray`)
|
|
317
|
+
*
|
|
318
|
+
* @category 1. Reading
|
|
319
|
+
*/
|
|
320
|
+
toJSON(): Item[] {
|
|
321
|
+
return this.asArray();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** @category 5. Edit history */
|
|
325
|
+
editAt(idx: number):
|
|
326
|
+
| {
|
|
354
327
|
by: RawAccountID | AgentID;
|
|
355
328
|
tx: TransactionID;
|
|
356
329
|
at: Date;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
330
|
+
value: Item;
|
|
331
|
+
}
|
|
332
|
+
| undefined {
|
|
333
|
+
const entry = this.entries()[idx];
|
|
334
|
+
if (!entry) {
|
|
335
|
+
return undefined;
|
|
336
|
+
}
|
|
337
|
+
const madeAt = new Date(entry.madeAt);
|
|
338
|
+
const by = accountOrAgentIDfromSessionID(entry.opID.sessionID);
|
|
339
|
+
const value = entry.value;
|
|
340
|
+
return {
|
|
341
|
+
by,
|
|
342
|
+
tx: {
|
|
343
|
+
sessionID: entry.opID.sessionID,
|
|
344
|
+
txIndex: entry.opID.txIndex,
|
|
345
|
+
},
|
|
346
|
+
at: madeAt,
|
|
347
|
+
value,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** @category 5. Edit history */
|
|
352
|
+
deletionEdits(): {
|
|
353
|
+
by: RawAccountID | AgentID;
|
|
354
|
+
tx: TransactionID;
|
|
355
|
+
at: Date;
|
|
356
|
+
// TODO: add indices that are now before and after the deleted item
|
|
357
|
+
}[] {
|
|
358
|
+
const edits: {
|
|
359
|
+
by: RawAccountID | AgentID;
|
|
360
|
+
tx: TransactionID;
|
|
361
|
+
at: Date;
|
|
362
|
+
}[] = [];
|
|
363
|
+
|
|
364
|
+
for (const sessionID in this.deletionsByInsertion) {
|
|
365
|
+
const sessionEntry = this.deletionsByInsertion[sessionID as SessionID];
|
|
366
|
+
for (const txIdx in sessionEntry) {
|
|
367
|
+
const txEntry = sessionEntry[Number(txIdx)];
|
|
368
|
+
for (const changeIdx in txEntry) {
|
|
369
|
+
const changeEntry = txEntry[Number(changeIdx)];
|
|
370
|
+
for (const deletion of changeEntry || []) {
|
|
371
|
+
const madeAt = new Date(deletion.madeAt);
|
|
372
|
+
const by = accountOrAgentIDfromSessionID(
|
|
373
|
+
deletion.deletionID.sessionID,
|
|
374
|
+
);
|
|
375
|
+
edits.push({
|
|
376
|
+
by,
|
|
377
|
+
tx: deletion.deletionID,
|
|
378
|
+
at: madeAt,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
385
381
|
}
|
|
386
|
-
|
|
387
|
-
return edits;
|
|
382
|
+
}
|
|
388
383
|
}
|
|
389
384
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
385
|
+
return edits;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** @category 3. Subscription */
|
|
389
|
+
subscribe(listener: (coList: this) => void): () => void {
|
|
390
|
+
return this.core.subscribe((content) => {
|
|
391
|
+
listener(content as this);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
396
394
|
}
|
|
397
395
|
|
|
398
396
|
export class RawCoList<
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
397
|
+
Item extends JsonValue = JsonValue,
|
|
398
|
+
Meta extends JsonObject | null = JsonObject | null,
|
|
399
|
+
>
|
|
400
|
+
extends RawCoListView<Item, Meta>
|
|
401
|
+
implements RawCoValue
|
|
404
402
|
{
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
this.core.makeTransaction(
|
|
439
|
-
[
|
|
440
|
-
{
|
|
441
|
-
op: "app",
|
|
442
|
-
value: isCoValue(item) ? item.id : item,
|
|
443
|
-
after: opIDBefore,
|
|
444
|
-
},
|
|
445
|
-
],
|
|
446
|
-
privacy,
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
const listAfter = new RawCoList(this.core) as this;
|
|
450
|
-
|
|
451
|
-
this.afterStart = listAfter.afterStart;
|
|
452
|
-
this.beforeEnd = listAfter.beforeEnd;
|
|
453
|
-
this.insertions = listAfter.insertions;
|
|
454
|
-
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
455
|
-
this._cachedEntries = undefined;
|
|
403
|
+
/** Appends `item` after the item currently at index `after`.
|
|
404
|
+
*
|
|
405
|
+
* 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.
|
|
406
|
+
*
|
|
407
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
408
|
+
*
|
|
409
|
+
* @category 2. Editing
|
|
410
|
+
**/
|
|
411
|
+
append(
|
|
412
|
+
item: Item,
|
|
413
|
+
after?: number,
|
|
414
|
+
privacy: "private" | "trusting" = "private",
|
|
415
|
+
) {
|
|
416
|
+
const entries = this.entries();
|
|
417
|
+
after =
|
|
418
|
+
after === undefined
|
|
419
|
+
? entries.length > 0
|
|
420
|
+
? entries.length - 1
|
|
421
|
+
: 0
|
|
422
|
+
: after;
|
|
423
|
+
let opIDBefore;
|
|
424
|
+
if (entries.length > 0) {
|
|
425
|
+
const entryBefore = entries[after];
|
|
426
|
+
if (!entryBefore) {
|
|
427
|
+
throw new Error("Invalid index " + after);
|
|
428
|
+
}
|
|
429
|
+
opIDBefore = entryBefore.opID;
|
|
430
|
+
} else {
|
|
431
|
+
if (after !== 0) {
|
|
432
|
+
throw new Error("Invalid index " + after);
|
|
433
|
+
}
|
|
434
|
+
opIDBefore = "start";
|
|
456
435
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
436
|
+
this.core.makeTransaction(
|
|
437
|
+
[
|
|
438
|
+
{
|
|
439
|
+
op: "app",
|
|
440
|
+
value: isCoValue(item) ? item.id : item,
|
|
441
|
+
after: opIDBefore,
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
privacy,
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const listAfter = new RawCoList(this.core) as this;
|
|
448
|
+
|
|
449
|
+
this.afterStart = listAfter.afterStart;
|
|
450
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
451
|
+
this.insertions = listAfter.insertions;
|
|
452
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
453
|
+
this._cachedEntries = undefined;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Prepends `item` before the item currently at index `before`.
|
|
458
|
+
*
|
|
459
|
+
* 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.
|
|
460
|
+
*
|
|
461
|
+
* If `privacy` is `"trusting"`, `item` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
462
|
+
*
|
|
463
|
+
* @category 2. Editing
|
|
464
|
+
*/
|
|
465
|
+
prepend(
|
|
466
|
+
item: Item,
|
|
467
|
+
before?: number,
|
|
468
|
+
privacy: "private" | "trusting" = "private",
|
|
469
|
+
) {
|
|
470
|
+
const entries = this.entries();
|
|
471
|
+
before = before === undefined ? 0 : before;
|
|
472
|
+
let opIDAfter;
|
|
473
|
+
if (entries.length > 0) {
|
|
474
|
+
const entryAfter = entries[before];
|
|
475
|
+
if (entryAfter) {
|
|
476
|
+
opIDAfter = entryAfter.opID;
|
|
477
|
+
} else {
|
|
478
|
+
if (before !== entries.length) {
|
|
479
|
+
throw new Error("Invalid index " + before);
|
|
490
480
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
],
|
|
499
|
-
privacy,
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
const listAfter = new RawCoList(this.core) as this;
|
|
503
|
-
|
|
504
|
-
this.afterStart = listAfter.afterStart;
|
|
505
|
-
this.beforeEnd = listAfter.beforeEnd;
|
|
506
|
-
this.insertions = listAfter.insertions;
|
|
507
|
-
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
508
|
-
this._cachedEntries = undefined;
|
|
481
|
+
opIDAfter = "end";
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
if (before !== 0) {
|
|
485
|
+
throw new Error("Invalid index " + before);
|
|
486
|
+
}
|
|
487
|
+
opIDAfter = "end";
|
|
509
488
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
489
|
+
this.core.makeTransaction(
|
|
490
|
+
[
|
|
491
|
+
{
|
|
492
|
+
op: "pre",
|
|
493
|
+
value: isCoValue(item) ? item.id : item,
|
|
494
|
+
before: opIDAfter,
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
privacy,
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
const listAfter = new RawCoList(this.core) as this;
|
|
501
|
+
|
|
502
|
+
this.afterStart = listAfter.afterStart;
|
|
503
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
504
|
+
this.insertions = listAfter.insertions;
|
|
505
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
506
|
+
this._cachedEntries = undefined;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/** Deletes the item at index `at`.
|
|
510
|
+
*
|
|
511
|
+
* 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.
|
|
512
|
+
*
|
|
513
|
+
* 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.
|
|
514
|
+
*
|
|
515
|
+
* @category 2. Editing
|
|
516
|
+
**/
|
|
517
|
+
delete(at: number, privacy: "private" | "trusting" = "private") {
|
|
518
|
+
const entries = this.entries();
|
|
519
|
+
const entry = entries[at];
|
|
520
|
+
if (!entry) {
|
|
521
|
+
throw new Error("Invalid index " + at);
|
|
542
522
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
this.afterStart = listAfter.afterStart;
|
|
572
|
-
this.beforeEnd = listAfter.beforeEnd;
|
|
573
|
-
this.insertions = listAfter.insertions;
|
|
574
|
-
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
575
|
-
this._cachedEntries = undefined;
|
|
523
|
+
this.core.makeTransaction(
|
|
524
|
+
[
|
|
525
|
+
{
|
|
526
|
+
op: "del",
|
|
527
|
+
insertion: entry.opID,
|
|
528
|
+
},
|
|
529
|
+
],
|
|
530
|
+
privacy,
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
const listAfter = new RawCoList(this.core) as this;
|
|
534
|
+
|
|
535
|
+
this.afterStart = listAfter.afterStart;
|
|
536
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
537
|
+
this.insertions = listAfter.insertions;
|
|
538
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
539
|
+
this._cachedEntries = undefined;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
replace(
|
|
543
|
+
at: number,
|
|
544
|
+
newItem: Item,
|
|
545
|
+
privacy: "private" | "trusting" = "private",
|
|
546
|
+
) {
|
|
547
|
+
const entries = this.entries();
|
|
548
|
+
const entry = entries[at];
|
|
549
|
+
if (!entry) {
|
|
550
|
+
throw new Error("Invalid index " + at);
|
|
576
551
|
}
|
|
552
|
+
|
|
553
|
+
this.core.makeTransaction(
|
|
554
|
+
[
|
|
555
|
+
{
|
|
556
|
+
op: "app",
|
|
557
|
+
value: isCoValue(newItem) ? newItem.id : newItem,
|
|
558
|
+
after: entry.opID,
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
op: "del",
|
|
562
|
+
insertion: entry.opID,
|
|
563
|
+
},
|
|
564
|
+
],
|
|
565
|
+
privacy,
|
|
566
|
+
);
|
|
567
|
+
const listAfter = new RawCoList(this.core) as this;
|
|
568
|
+
|
|
569
|
+
this.afterStart = listAfter.afterStart;
|
|
570
|
+
this.beforeEnd = listAfter.beforeEnd;
|
|
571
|
+
this.insertions = listAfter.insertions;
|
|
572
|
+
this.deletionsByInsertion = listAfter.deletionsByInsertion;
|
|
573
|
+
this._cachedEntries = undefined;
|
|
574
|
+
}
|
|
577
575
|
}
|