cojson 0.2.3 → 0.3.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/dist/account.d.ts +1 -1
- package/dist/coValue.d.ts +5 -13
- package/dist/coValue.js +14 -7
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.d.ts +6 -6
- package/dist/coValueCore.js +11 -14
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/coList.d.ts +99 -34
- package/dist/coValues/coList.js +162 -72
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.d.ts +96 -31
- package/dist/coValues/coMap.js +157 -114
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts +67 -23
- package/dist/coValues/coStream.js +131 -59
- 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 +57 -23
- package/dist/group.js +75 -33
- package/dist/group.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/{node.d.ts → localNode.d.ts} +16 -8
- package/dist/{node.js → localNode.js} +48 -40
- package/dist/localNode.js.map +1 -0
- 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 +29 -112
- package/dist/queries.js +44 -227
- package/dist/queries.js.map +1 -1
- package/dist/sync.d.ts +1 -1
- package/dist/sync.js +1 -1
- package/dist/sync.js.map +1 -1
- package/dist/tests/testUtils.d.ts +1 -1
- package/dist/tests/testUtils.js +3 -3
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/account.ts +1 -1
- package/src/coValue.ts +25 -20
- package/src/coValueCore.ts +17 -21
- package/src/coValues/coList.ts +242 -128
- package/src/coValues/coMap.ts +293 -162
- package/src/coValues/coStream.ts +227 -94
- package/src/crypto.ts +37 -24
- package/src/group.ts +90 -63
- package/src/index.ts +35 -25
- package/src/{node.ts → localNode.ts} +64 -64
- 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 +83 -460
- package/src/sync.ts +2 -2
- package/src/tests/account.test.ts +3 -6
- package/src/tests/coValue.test.ts +116 -110
- package/src/tests/coValueCore.test.ts +1 -1
- package/src/tests/crypto.test.ts +19 -21
- package/src/tests/permissions.test.ts +255 -242
- package/src/tests/queries.test.ts +57 -40
- package/src/tests/sync.test.ts +30 -30
- package/src/tests/testUtils.ts +3 -3
- 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/src/coValues/static.ts +0 -31
package/src/coValues/coMap.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
2
|
-
import { TransactionID } from "../ids.js";
|
|
2
|
+
import { AgentID, TransactionID } from "../ids.js";
|
|
3
3
|
import { CoID, CoValue, isCoValue } from "../coValue.js";
|
|
4
4
|
import { CoValueCore, accountOrAgentIDfromSessionID } from "../coValueCore.js";
|
|
5
|
-
import { AccountID
|
|
5
|
+
import { AccountID } from "../account.js";
|
|
6
6
|
import { Group } from "../group.js";
|
|
7
7
|
import { parseJSON } from "../jsonStringify.js";
|
|
8
8
|
|
|
@@ -27,19 +27,25 @@ export type MapOpPayload<
|
|
|
27
27
|
key: K;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
M extends { [key: string]: JsonValue | CoValue | undefined },
|
|
30
|
+
export class CoMapView<
|
|
31
|
+
Shape extends { [key: string]: JsonValue | CoValue | undefined },
|
|
33
32
|
Meta extends JsonObject | null = null
|
|
34
33
|
> implements CoValue
|
|
35
34
|
{
|
|
35
|
+
/** @category 6. Meta */
|
|
36
36
|
id: CoID<this>;
|
|
37
|
+
/** @category 6. Meta */
|
|
37
38
|
type = "comap" as const;
|
|
39
|
+
/** @category 6. Meta */
|
|
38
40
|
core: CoValueCore;
|
|
39
41
|
/** @internal */
|
|
40
42
|
ops: {
|
|
41
|
-
[Key in keyof
|
|
43
|
+
[Key in keyof Shape & string]?: MapOp<Key, Shape[Key]>[];
|
|
42
44
|
};
|
|
45
|
+
/** @internal */
|
|
46
|
+
atTimeFilter?: number = undefined;
|
|
47
|
+
/** @category 6. Meta */
|
|
48
|
+
readonly _shape!: Shape;
|
|
43
49
|
|
|
44
50
|
/** @internal */
|
|
45
51
|
constructor(core: CoValueCore) {
|
|
@@ -47,32 +53,17 @@ export class CoMap<
|
|
|
47
53
|
this.core = core;
|
|
48
54
|
this.ops = {};
|
|
49
55
|
|
|
50
|
-
this.fillOpsFromCoValue();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get meta(): Meta {
|
|
54
|
-
return this.core.header.meta as Meta;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get group(): Group {
|
|
58
|
-
return this.core.getGroup();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** @internal */
|
|
62
|
-
protected fillOpsFromCoValue() {
|
|
63
|
-
this.ops = {};
|
|
64
|
-
|
|
65
56
|
for (const {
|
|
66
57
|
txID,
|
|
67
58
|
changes,
|
|
68
59
|
madeAt,
|
|
69
|
-
} of
|
|
60
|
+
} of core.getValidSortedTransactions()) {
|
|
70
61
|
for (const [changeIdx, changeUntyped] of parseJSON(
|
|
71
62
|
changes
|
|
72
63
|
).entries()) {
|
|
73
64
|
const change = changeUntyped as MapOpPayload<
|
|
74
|
-
keyof
|
|
75
|
-
|
|
65
|
+
keyof Shape & string,
|
|
66
|
+
Shape[keyof Shape & string]
|
|
76
67
|
>;
|
|
77
68
|
let entries = this.ops[change.key];
|
|
78
69
|
if (!entries) {
|
|
@@ -84,222 +75,301 @@ export class CoMap<
|
|
|
84
75
|
madeAt,
|
|
85
76
|
changeIdx,
|
|
86
77
|
...(change as MapOpPayload<
|
|
87
|
-
keyof
|
|
88
|
-
|
|
78
|
+
keyof Shape & string,
|
|
79
|
+
Shape[keyof Shape & string]
|
|
89
80
|
>),
|
|
90
81
|
});
|
|
91
82
|
}
|
|
92
83
|
}
|
|
93
84
|
}
|
|
94
85
|
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
/** @category 6. Meta */
|
|
87
|
+
get meta(): Meta {
|
|
88
|
+
return this.core.header.meta as Meta;
|
|
97
89
|
}
|
|
98
90
|
|
|
99
|
-
/**
|
|
100
|
-
get
|
|
91
|
+
/** @category 6. Meta */
|
|
92
|
+
get group(): Group {
|
|
93
|
+
return this.core.getGroup();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** @category 4. Time travel */
|
|
97
|
+
atTime(time: number): this {
|
|
98
|
+
const clone = Object.create(this) as this;
|
|
99
|
+
clone.id = this.id;
|
|
100
|
+
clone.type = this.type;
|
|
101
|
+
clone.core = this.core;
|
|
102
|
+
clone.ops = this.ops;
|
|
103
|
+
clone.atTimeFilter = time;
|
|
104
|
+
return clone;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @internal */
|
|
108
|
+
timeFilteredOps<K extends keyof Shape & string>(
|
|
101
109
|
key: K
|
|
102
|
-
):
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
): MapOp<K, Shape[K]>[] | undefined {
|
|
111
|
+
if (this.atTimeFilter) {
|
|
112
|
+
return this.ops[key]?.filter(
|
|
113
|
+
(op) => op.madeAt <= this.atTimeFilter!
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
return this.ops[key];
|
|
108
117
|
}
|
|
118
|
+
}
|
|
109
119
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Get all keys currently in the map.
|
|
122
|
+
*
|
|
123
|
+
* @category 1. Reading */
|
|
124
|
+
keys(): (keyof Shape & string)[] {
|
|
125
|
+
const keys = Object.keys(this.ops) as (keyof Shape & string)[];
|
|
126
|
+
|
|
127
|
+
if (this.atTimeFilter) {
|
|
128
|
+
return keys.filter((key) => {
|
|
129
|
+
this.timeFilteredOps(key)?.length;
|
|
130
|
+
});
|
|
114
131
|
} else {
|
|
115
|
-
return
|
|
132
|
+
return keys;
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
135
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Returns the current value for the given key.
|
|
138
|
+
*
|
|
139
|
+
* @category 1. Reading
|
|
140
|
+
**/
|
|
141
|
+
get<K extends keyof Shape & string>(
|
|
142
|
+
key: K
|
|
122
143
|
):
|
|
123
|
-
| (
|
|
144
|
+
| (Shape[K] extends CoValue
|
|
145
|
+
? CoID<Shape[K]>
|
|
146
|
+
: Exclude<Shape[K], CoValue>)
|
|
124
147
|
| undefined {
|
|
125
|
-
const ops = this.
|
|
148
|
+
const ops = this.timeFilteredOps(key);
|
|
126
149
|
if (!ops) {
|
|
127
150
|
return undefined;
|
|
128
151
|
}
|
|
129
152
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
153
|
+
const includeUntil = this.atTimeFilter;
|
|
154
|
+
const lastEntry = includeUntil
|
|
155
|
+
? ops.findLast((entry) => entry.madeAt <= includeUntil)
|
|
156
|
+
: ops[ops.length - 1]!;
|
|
135
157
|
|
|
136
|
-
if (
|
|
158
|
+
if (lastEntry?.op === "del") {
|
|
137
159
|
return undefined;
|
|
138
160
|
} else {
|
|
139
|
-
return
|
|
161
|
+
return lastEntry?.value;
|
|
140
162
|
}
|
|
141
163
|
}
|
|
142
164
|
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
}
|
|
165
|
+
/** @category 1. Reading */
|
|
166
|
+
asObject(): {
|
|
167
|
+
[K in keyof Shape & string]: Shape[K] extends CoValue
|
|
168
|
+
? CoID<Shape[K]>
|
|
169
|
+
: Exclude<Shape[K], CoValue>;
|
|
170
|
+
} {
|
|
171
|
+
const object: Partial<{
|
|
172
|
+
[K in keyof Shape & string]: Shape[K] extends CoValue
|
|
173
|
+
? CoID<Shape[K]>
|
|
174
|
+
: Exclude<Shape[K], CoValue>;
|
|
175
|
+
}> = {};
|
|
156
176
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
177
|
+
for (const key of this.keys()) {
|
|
178
|
+
const value = this.get(key);
|
|
179
|
+
if (value !== undefined) {
|
|
180
|
+
object[key] = value;
|
|
181
|
+
}
|
|
161
182
|
}
|
|
162
183
|
|
|
163
|
-
|
|
184
|
+
return object as {
|
|
185
|
+
[K in keyof Shape & string]: Shape[K] extends CoValue
|
|
186
|
+
? CoID<Shape[K]>
|
|
187
|
+
: Exclude<Shape[K], CoValue>;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
164
190
|
|
|
165
|
-
|
|
191
|
+
/** @category 1. Reading */
|
|
192
|
+
toJSON(): {
|
|
193
|
+
[K in keyof Shape & string]: Shape[K] extends CoValue
|
|
194
|
+
? CoID<Shape[K]>
|
|
195
|
+
: Exclude<Shape[K], CoValue>;
|
|
196
|
+
} {
|
|
197
|
+
return this.asObject();
|
|
166
198
|
}
|
|
167
199
|
|
|
168
|
-
|
|
169
|
-
|
|
200
|
+
/** @category 5. Edit history */
|
|
201
|
+
nthEditAt<K extends keyof Shape & string>(
|
|
202
|
+
key: K,
|
|
203
|
+
n: number
|
|
170
204
|
):
|
|
171
205
|
| {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
206
|
+
by: AccountID | AgentID;
|
|
207
|
+
tx: TransactionID;
|
|
208
|
+
at: Date;
|
|
209
|
+
value?: Shape[K] extends CoValue
|
|
210
|
+
? CoID<Shape[K]>
|
|
211
|
+
: Exclude<Shape[K], CoValue>;
|
|
175
212
|
}
|
|
176
213
|
| undefined {
|
|
177
|
-
const ops = this.
|
|
178
|
-
if (!ops) {
|
|
214
|
+
const ops = this.timeFilteredOps(key);
|
|
215
|
+
if (!ops || ops.length <= n) {
|
|
179
216
|
return undefined;
|
|
180
217
|
}
|
|
181
218
|
|
|
182
|
-
const
|
|
219
|
+
const entry = ops[n]!;
|
|
183
220
|
|
|
184
|
-
if (
|
|
221
|
+
if (this.atTimeFilter && entry.madeAt > this.atTimeFilter) {
|
|
185
222
|
return undefined;
|
|
186
|
-
} else {
|
|
187
|
-
return {
|
|
188
|
-
at: lastEntry.madeAt,
|
|
189
|
-
txID: lastEntry.txID,
|
|
190
|
-
value: lastEntry.value,
|
|
191
|
-
};
|
|
192
223
|
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
by: accountOrAgentIDfromSessionID(entry.txID.sessionID),
|
|
227
|
+
tx: entry.txID,
|
|
228
|
+
at: new Date(entry.madeAt),
|
|
229
|
+
value: entry.op === "del" ? undefined : entry.value,
|
|
230
|
+
};
|
|
193
231
|
}
|
|
194
232
|
|
|
195
|
-
|
|
233
|
+
/** @category 5. Edit history */
|
|
234
|
+
lastEditAt<K extends keyof Shape & string>(
|
|
196
235
|
key: K
|
|
197
|
-
):
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
at: number;
|
|
211
|
-
txID: TransactionID;
|
|
212
|
-
value:
|
|
213
|
-
| (M[K] extends CoValue ? CoID<M[K]> : Exclude<M[K], CoValue>)
|
|
214
|
-
| undefined;
|
|
215
|
-
}[] = [];
|
|
216
|
-
|
|
217
|
-
for (const op of ops) {
|
|
218
|
-
if (op.op === "del") {
|
|
219
|
-
history.push({
|
|
220
|
-
at: op.madeAt,
|
|
221
|
-
txID: op.txID,
|
|
222
|
-
value: undefined,
|
|
223
|
-
});
|
|
224
|
-
} else {
|
|
225
|
-
history.push({ at: op.madeAt, txID: op.txID, value: op.value });
|
|
226
|
-
}
|
|
236
|
+
):
|
|
237
|
+
| {
|
|
238
|
+
by: AccountID | AgentID;
|
|
239
|
+
tx: TransactionID;
|
|
240
|
+
at: Date;
|
|
241
|
+
value?: Shape[K] extends CoValue
|
|
242
|
+
? CoID<Shape[K]>
|
|
243
|
+
: Exclude<Shape[K], CoValue>;
|
|
244
|
+
}
|
|
245
|
+
| undefined {
|
|
246
|
+
const ops = this.timeFilteredOps(key);
|
|
247
|
+
if (!ops || ops.length === 0) {
|
|
248
|
+
return undefined;
|
|
227
249
|
}
|
|
228
|
-
|
|
229
|
-
return history;
|
|
250
|
+
return this.nthEditAt(key, ops.length - 1);
|
|
230
251
|
}
|
|
231
252
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (value !== undefined) {
|
|
238
|
-
json[key] = value;
|
|
239
|
-
}
|
|
253
|
+
/** @category 5. Edit history */
|
|
254
|
+
*editsAt<K extends keyof Shape & string>(key: K) {
|
|
255
|
+
const ops = this.timeFilteredOps(key);
|
|
256
|
+
if (!ops) {
|
|
257
|
+
return;
|
|
240
258
|
}
|
|
241
259
|
|
|
242
|
-
|
|
260
|
+
for (let i = 0; i < ops.length; i++) {
|
|
261
|
+
yield this.nthEditAt(key, i)!;
|
|
262
|
+
}
|
|
243
263
|
}
|
|
244
264
|
|
|
265
|
+
/** @category 3. Subscription */
|
|
245
266
|
subscribe(listener: (coMap: this) => void): () => void {
|
|
246
267
|
return this.core.subscribe((content) => {
|
|
247
268
|
listener(content as this);
|
|
248
269
|
});
|
|
249
270
|
}
|
|
250
|
-
|
|
251
|
-
edit(changer: (editable: WriteableCoMap<M, Meta>) => void): this {
|
|
252
|
-
const editable = new WriteableCoMap<M, Meta>(this.core);
|
|
253
|
-
changer(editable);
|
|
254
|
-
return new CoMap(this.core) as this;
|
|
255
|
-
}
|
|
256
271
|
}
|
|
257
272
|
|
|
258
|
-
|
|
259
|
-
|
|
273
|
+
/** A collaborative map with precise shape `Shape` and optional static metadata `Meta` */
|
|
274
|
+
export class CoMap<
|
|
275
|
+
Shape extends { [key: string]: JsonValue | CoValue | undefined },
|
|
260
276
|
Meta extends JsonObject | null = null
|
|
261
277
|
>
|
|
262
|
-
extends
|
|
278
|
+
extends CoMapView<Shape, Meta>
|
|
263
279
|
implements CoValue
|
|
264
280
|
{
|
|
265
|
-
/** @internal */
|
|
266
|
-
edit(_changer: (editable: WriteableCoMap<M, Meta>) => void): this {
|
|
267
|
-
throw new Error("Already editing.");
|
|
268
|
-
}
|
|
269
281
|
|
|
270
|
-
|
|
282
|
+
|
|
283
|
+
/** Returns a new version of this CoMap with a new value for the given key.
|
|
271
284
|
*
|
|
272
285
|
* If `privacy` is `"private"` **(default)**, both `key` and `value` are encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
|
|
273
286
|
*
|
|
274
|
-
* If `privacy` is `"trusting"`, both `key` and `value` are stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
275
|
-
|
|
287
|
+
* If `privacy` is `"trusting"`, both `key` and `value` are stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
288
|
+
*
|
|
289
|
+
* @category 2. Editing
|
|
290
|
+
**/
|
|
291
|
+
set<K extends keyof Shape & string>(
|
|
276
292
|
key: K,
|
|
277
|
-
value:
|
|
278
|
-
privacy
|
|
279
|
-
):
|
|
280
|
-
|
|
281
|
-
|
|
293
|
+
value: Shape[K] extends CoValue ? Shape[K] | CoID<Shape[K]> : Shape[K],
|
|
294
|
+
privacy?: "private" | "trusting"
|
|
295
|
+
): this;
|
|
296
|
+
set(
|
|
297
|
+
kv: {
|
|
298
|
+
[K in keyof Shape & string]?: Shape[K] extends CoValue
|
|
299
|
+
? Shape[K] | CoID<Shape[K]>
|
|
300
|
+
: Shape[K];
|
|
301
|
+
},
|
|
302
|
+
privacy?: "private" | "trusting"
|
|
303
|
+
): this;
|
|
304
|
+
set<K extends keyof Shape & string>(
|
|
305
|
+
...args:
|
|
306
|
+
| [
|
|
307
|
+
{
|
|
308
|
+
[K in keyof Shape & string]?: Shape[K] extends CoValue
|
|
309
|
+
? Shape[K] | CoID<Shape[K]>
|
|
310
|
+
: Shape[K];
|
|
311
|
+
},
|
|
312
|
+
("private" | "trusting")?
|
|
313
|
+
]
|
|
314
|
+
| [
|
|
315
|
+
K,
|
|
316
|
+
Shape[K] extends CoValue
|
|
317
|
+
? Shape[K] | CoID<Shape[K]>
|
|
318
|
+
: Shape[K],
|
|
319
|
+
("private" | "trusting")?
|
|
320
|
+
]
|
|
321
|
+
): this {
|
|
322
|
+
if (typeof args[0] === "string") {
|
|
323
|
+
const [key, value, privacy = "private"] = args;
|
|
324
|
+
this.core.makeTransaction(
|
|
325
|
+
[
|
|
326
|
+
{
|
|
327
|
+
op: "set",
|
|
328
|
+
key,
|
|
329
|
+
value: isCoValue(value) ? value.id : value,
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
privacy
|
|
333
|
+
);
|
|
334
|
+
} else {
|
|
335
|
+
const [kv, privacy = "private"] = args as [
|
|
282
336
|
{
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
337
|
+
[K in keyof Shape & string]: Shape[K] extends CoValue
|
|
338
|
+
? Shape[K] | CoID<Shape[K]>
|
|
339
|
+
: Shape[K];
|
|
286
340
|
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
341
|
+
"private" | "trusting" | undefined
|
|
342
|
+
];
|
|
343
|
+
|
|
344
|
+
for (const [key, value] of Object.entries(kv)) {
|
|
345
|
+
this.core.makeTransaction(
|
|
346
|
+
[
|
|
347
|
+
{
|
|
348
|
+
op: "set",
|
|
349
|
+
key,
|
|
350
|
+
value: isCoValue(value) ? value.id : value,
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
privacy
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
290
357
|
|
|
291
|
-
this.
|
|
358
|
+
return new CoMap(this.core) as this;
|
|
292
359
|
}
|
|
293
360
|
|
|
294
|
-
/**
|
|
361
|
+
/** Returns a new version of this CoMap with the given key deleted (setting it to undefined).
|
|
295
362
|
*
|
|
296
363
|
* If `privacy` is `"private"` **(default)**, `key` is encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
|
|
297
364
|
*
|
|
298
|
-
* If `privacy` is `"trusting"`, `key` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
365
|
+
* If `privacy` is `"trusting"`, `key` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
366
|
+
*
|
|
367
|
+
* @category 2. Editing
|
|
368
|
+
**/
|
|
299
369
|
delete(
|
|
300
|
-
key: keyof
|
|
370
|
+
key: keyof Shape & string,
|
|
301
371
|
privacy: "private" | "trusting" = "private"
|
|
302
|
-
):
|
|
372
|
+
): this {
|
|
303
373
|
this.core.makeTransaction(
|
|
304
374
|
[
|
|
305
375
|
{
|
|
@@ -310,6 +380,67 @@ export class WriteableCoMap<
|
|
|
310
380
|
privacy
|
|
311
381
|
);
|
|
312
382
|
|
|
313
|
-
this.
|
|
383
|
+
return new CoMap(this.core) as this;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** @category 2. Editing */
|
|
387
|
+
mutate(mutator: (mutable: MutableCoMap<Shape, Meta>) => void): this {
|
|
388
|
+
const mutable = new MutableCoMap<Shape, Meta>(this.core);
|
|
389
|
+
mutator(mutable);
|
|
390
|
+
return new CoMap(this.core) as this;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** @deprecated Use `mutate` instead. */
|
|
394
|
+
edit(mutator: (mutable: MutableCoMap<Shape, Meta>) => void): this {
|
|
395
|
+
return this.mutate(mutator);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export class MutableCoMap<
|
|
400
|
+
Shape extends { [key: string]: JsonValue | CoValue | undefined },
|
|
401
|
+
Meta extends JsonObject | null = null
|
|
402
|
+
>
|
|
403
|
+
extends CoMapView<Shape, Meta>
|
|
404
|
+
implements CoValue
|
|
405
|
+
{
|
|
406
|
+
/** Sets a new value for the given key.
|
|
407
|
+
*
|
|
408
|
+
* If `privacy` is `"private"` **(default)**, both `key` and `value` are encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
|
|
409
|
+
*
|
|
410
|
+
* If `privacy` is `"trusting"`, both `key` and `value` are stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
411
|
+
*
|
|
412
|
+
* @category 2. Mutation
|
|
413
|
+
*/
|
|
414
|
+
set<K extends keyof Shape & string>(
|
|
415
|
+
key: K,
|
|
416
|
+
value: Shape[K] extends CoValue ? Shape[K] | CoID<Shape[K]> : Shape[K],
|
|
417
|
+
privacy: "private" | "trusting" = "private"
|
|
418
|
+
): void {
|
|
419
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
420
|
+
const after = (CoMap.prototype.set as Function).call(
|
|
421
|
+
this,
|
|
422
|
+
key,
|
|
423
|
+
value,
|
|
424
|
+
privacy
|
|
425
|
+
) as CoMap<Shape, Meta>;
|
|
426
|
+
this.ops = after.ops;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Deletes the value for the given key (setting it to undefined).
|
|
430
|
+
*
|
|
431
|
+
* If `privacy` is `"private"` **(default)**, `key` is encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
|
|
432
|
+
*
|
|
433
|
+
* If `privacy` is `"trusting"`, `key` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
|
|
434
|
+
* @category 2. Mutation
|
|
435
|
+
*/
|
|
436
|
+
delete(
|
|
437
|
+
key: keyof Shape & string,
|
|
438
|
+
privacy: "private" | "trusting" = "private"
|
|
439
|
+
): void {
|
|
440
|
+
const after = CoMap.prototype.delete.call(this, key, privacy) as CoMap<
|
|
441
|
+
Shape,
|
|
442
|
+
Meta
|
|
443
|
+
>;
|
|
444
|
+
this.ops = after.ops;
|
|
314
445
|
}
|
|
315
446
|
}
|