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
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
newRandomKeySecret,
|
|
10
10
|
seal,
|
|
11
11
|
} from "./crypto.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
CoValueCore,
|
|
14
|
+
CoValueHeader,
|
|
15
|
+
newRandomSessionID,
|
|
16
|
+
} from "./coValueCore.js";
|
|
13
17
|
import {
|
|
14
18
|
InviteSecret,
|
|
15
19
|
Group,
|
|
@@ -19,9 +23,10 @@ import {
|
|
|
19
23
|
} from "./group.js";
|
|
20
24
|
import { Peer, SyncManager } from "./sync.js";
|
|
21
25
|
import { AgentID, RawCoID, SessionID, isAgentID } from "./ids.js";
|
|
22
|
-
import { CoID
|
|
26
|
+
import { CoID } from "./coValue.js";
|
|
27
|
+
import { Queried, query } from "./queries.js";
|
|
23
28
|
import {
|
|
24
|
-
|
|
29
|
+
AccountGroup,
|
|
25
30
|
AccountMeta,
|
|
26
31
|
accountHeaderForInitialAgentSecret,
|
|
27
32
|
GeneralizedControlledAccount,
|
|
@@ -30,9 +35,9 @@ import {
|
|
|
30
35
|
AccountID,
|
|
31
36
|
Profile,
|
|
32
37
|
AccountContent,
|
|
33
|
-
AccountMap,
|
|
34
38
|
} from "./account.js";
|
|
35
39
|
import { CoMap } from "./coValues/coMap.js";
|
|
40
|
+
import { CoValue } from "./index.js";
|
|
36
41
|
|
|
37
42
|
/** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
|
|
38
43
|
|
|
@@ -48,11 +53,14 @@ const { localNode } = useJazz();
|
|
|
48
53
|
export class LocalNode {
|
|
49
54
|
/** @internal */
|
|
50
55
|
coValues: { [key: RawCoID]: CoValueState } = {};
|
|
51
|
-
/** @
|
|
56
|
+
/** @category 3. Low-level */
|
|
52
57
|
account: GeneralizedControlledAccount;
|
|
58
|
+
/** @category 3. Low-level */
|
|
53
59
|
currentSessionID: SessionID;
|
|
54
|
-
|
|
60
|
+
/** @category 3. Low-level */
|
|
61
|
+
syncManager = new SyncManager(this);
|
|
55
62
|
|
|
63
|
+
/** @category 3. Low-level */
|
|
56
64
|
constructor(
|
|
57
65
|
account: GeneralizedControlledAccount,
|
|
58
66
|
currentSessionID: SessionID
|
|
@@ -61,6 +69,7 @@ export class LocalNode {
|
|
|
61
69
|
this.currentSessionID = currentSessionID;
|
|
62
70
|
}
|
|
63
71
|
|
|
72
|
+
/** @category 2. Node Creation */
|
|
64
73
|
static withNewlyCreatedAccount(
|
|
65
74
|
name: string,
|
|
66
75
|
initialAgentSecret = newRandomAgentSecret()
|
|
@@ -91,6 +100,7 @@ export class LocalNode {
|
|
|
91
100
|
};
|
|
92
101
|
}
|
|
93
102
|
|
|
103
|
+
/** @category 2. Node Creation */
|
|
94
104
|
static async withLoadedAccount(
|
|
95
105
|
accountID: AccountID,
|
|
96
106
|
accountSecret: AgentSecret,
|
|
@@ -105,7 +115,7 @@ export class LocalNode {
|
|
|
105
115
|
const accountPromise = loadingNode.load(accountID);
|
|
106
116
|
|
|
107
117
|
for (const peer of peersToLoadFrom) {
|
|
108
|
-
loadingNode.
|
|
118
|
+
loadingNode.syncManager.addPeer(peer);
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
const account = await accountPromise;
|
|
@@ -115,8 +125,8 @@ export class LocalNode {
|
|
|
115
125
|
new ControlledAccount(accountSecret, account, loadingNode),
|
|
116
126
|
sessionID
|
|
117
127
|
);
|
|
118
|
-
node.
|
|
119
|
-
node.
|
|
128
|
+
node.syncManager = loadingNode.syncManager;
|
|
129
|
+
node.syncManager.local = node;
|
|
120
130
|
|
|
121
131
|
return node;
|
|
122
132
|
}
|
|
@@ -126,7 +136,7 @@ export class LocalNode {
|
|
|
126
136
|
const coValue = new CoValueCore(header, this);
|
|
127
137
|
this.coValues[coValue.id] = { state: "loaded", coValue: coValue };
|
|
128
138
|
|
|
129
|
-
void this.
|
|
139
|
+
void this.syncManager.syncCoValue(coValue);
|
|
130
140
|
|
|
131
141
|
return coValue;
|
|
132
142
|
}
|
|
@@ -139,7 +149,7 @@ export class LocalNode {
|
|
|
139
149
|
|
|
140
150
|
this.coValues[id] = entry;
|
|
141
151
|
|
|
142
|
-
this.
|
|
152
|
+
this.syncManager.loadFromPeers(id);
|
|
143
153
|
}
|
|
144
154
|
if (entry.state === "loaded") {
|
|
145
155
|
return Promise.resolve(entry.coValue);
|
|
@@ -151,28 +161,51 @@ export class LocalNode {
|
|
|
151
161
|
* Loads a CoValue's content, syncing from peers as necessary and resolving the returned
|
|
152
162
|
* promise once a first version has been loaded. See `coValue.subscribe()` and `node.useTelepathicData()`
|
|
153
163
|
* for listening to subsequent updates to the CoValue.
|
|
164
|
+
*
|
|
165
|
+
* @category 3. Low-level
|
|
154
166
|
*/
|
|
155
|
-
async load<T extends
|
|
167
|
+
async load<T extends CoValue>(id: CoID<T>): Promise<T> {
|
|
156
168
|
return (await this.loadCoValue(id)).getCurrentContent() as T;
|
|
157
169
|
}
|
|
158
170
|
|
|
159
|
-
/**
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
171
|
+
/** @category 3. Low-level */
|
|
172
|
+
subscribe<T extends CoValue>(
|
|
173
|
+
id: CoID<T>,
|
|
174
|
+
callback: (update: T) => void
|
|
175
|
+
): () => void {
|
|
176
|
+
let stopped = false;
|
|
177
|
+
let unsubscribe!: () => void;
|
|
166
178
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
console.log("Subscribing to " + id);
|
|
180
|
+
|
|
181
|
+
this.load(id)
|
|
182
|
+
.then((coValue) => {
|
|
183
|
+
if (stopped) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
unsubscribe = coValue.subscribe(callback);
|
|
187
|
+
})
|
|
188
|
+
.catch((e) => {
|
|
189
|
+
console.error("Error subscribing to ", id, e);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return () => {
|
|
193
|
+
console.log("Unsubscribing from " + id);
|
|
194
|
+
stopped = true;
|
|
195
|
+
unsubscribe?.();
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** @category 1. High-level */
|
|
200
|
+
query<T extends CoValue>(
|
|
201
|
+
id: CoID<T>,
|
|
202
|
+
callback: (update: Queried<T> | undefined) => void
|
|
203
|
+
): () => void {
|
|
204
|
+
return query(id, this, callback);
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
|
|
207
|
+
/** @category 1. High-level */
|
|
208
|
+
async acceptInvite<T extends CoValue>(
|
|
176
209
|
groupOrOwnedValueID: CoID<T>,
|
|
177
210
|
inviteSecret: InviteSecret
|
|
178
211
|
): Promise<void> {
|
|
@@ -204,10 +237,7 @@ export class LocalNode {
|
|
|
204
237
|
}
|
|
205
238
|
});
|
|
206
239
|
setTimeout(
|
|
207
|
-
() =>
|
|
208
|
-
reject(
|
|
209
|
-
new Error("Couldn't find invite before timeout")
|
|
210
|
-
),
|
|
240
|
+
() => reject(new Error("Couldn't find invite before timeout")),
|
|
211
241
|
2000
|
|
212
242
|
);
|
|
213
243
|
});
|
|
@@ -224,7 +254,9 @@ export class LocalNode {
|
|
|
224
254
|
(existingRole === "writer" && inviteRole === "reader") ||
|
|
225
255
|
(existingRole === "reader" && inviteRole === "readerInvite")
|
|
226
256
|
) {
|
|
227
|
-
console.debug(
|
|
257
|
+
console.debug(
|
|
258
|
+
"Not accepting invite that would replace or downgrade role"
|
|
259
|
+
);
|
|
228
260
|
return;
|
|
229
261
|
}
|
|
230
262
|
|
|
@@ -242,7 +274,8 @@ export class LocalNode {
|
|
|
242
274
|
: "reader"
|
|
243
275
|
);
|
|
244
276
|
|
|
245
|
-
group.underlyingMap.core._sessions =
|
|
277
|
+
group.underlyingMap.core._sessions =
|
|
278
|
+
groupAsInvite.underlyingMap.core.sessions;
|
|
246
279
|
group.underlyingMap.core._cachedContent = undefined;
|
|
247
280
|
|
|
248
281
|
for (const groupListener of group.underlyingMap.core.listeners) {
|
|
@@ -292,11 +325,12 @@ export class LocalNode {
|
|
|
292
325
|
name: string,
|
|
293
326
|
agentSecret = newRandomAgentSecret()
|
|
294
327
|
): ControlledAccount {
|
|
328
|
+
const accountAgentID = getAgentID(agentSecret);
|
|
295
329
|
const account = this.createCoValue(
|
|
296
330
|
accountHeaderForInitialAgentSecret(agentSecret)
|
|
297
331
|
).testWithDifferentAccount(
|
|
298
332
|
new AnonymousControlledAccount(agentSecret),
|
|
299
|
-
newRandomSessionID(
|
|
333
|
+
newRandomSessionID(accountAgentID)
|
|
300
334
|
);
|
|
301
335
|
|
|
302
336
|
const accountAsGroup = new Group(
|
|
@@ -304,22 +338,22 @@ export class LocalNode {
|
|
|
304
338
|
account.node
|
|
305
339
|
);
|
|
306
340
|
|
|
307
|
-
accountAsGroup.underlyingMap.
|
|
308
|
-
editable.set(
|
|
341
|
+
accountAsGroup.underlyingMap.mutate((editable) => {
|
|
342
|
+
editable.set(accountAgentID, "admin", "trusting");
|
|
309
343
|
|
|
310
344
|
const readKey = newRandomKeySecret();
|
|
311
345
|
|
|
312
346
|
editable.set(
|
|
313
|
-
`${readKey.id}_for_${
|
|
314
|
-
seal(
|
|
315
|
-
readKey.secret,
|
|
316
|
-
getAgentSealerSecret(agentSecret),
|
|
317
|
-
getAgentSealerID(
|
|
318
|
-
{
|
|
347
|
+
`${readKey.id}_for_${accountAgentID}`,
|
|
348
|
+
seal({
|
|
349
|
+
message: readKey.secret,
|
|
350
|
+
from: getAgentSealerSecret(agentSecret),
|
|
351
|
+
to: getAgentSealerID(accountAgentID),
|
|
352
|
+
nOnceMaterial: {
|
|
319
353
|
in: account.id,
|
|
320
354
|
tx: account.nextTransactionID(),
|
|
321
|
-
}
|
|
322
|
-
),
|
|
355
|
+
},
|
|
356
|
+
}),
|
|
323
357
|
"trusting"
|
|
324
358
|
);
|
|
325
359
|
|
|
@@ -332,28 +366,38 @@ export class LocalNode {
|
|
|
332
366
|
account.node
|
|
333
367
|
);
|
|
334
368
|
|
|
335
|
-
const profile = accountAsGroup.createMap<Profile>(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
369
|
+
const profile = accountAsGroup.createMap<Profile>(
|
|
370
|
+
{ name },
|
|
371
|
+
{
|
|
372
|
+
type: "profile",
|
|
373
|
+
},
|
|
374
|
+
"trusting"
|
|
375
|
+
);
|
|
342
376
|
|
|
343
|
-
accountAsGroup.underlyingMap.
|
|
344
|
-
editable.set("profile", profile.id, "trusting");
|
|
345
|
-
});
|
|
377
|
+
accountAsGroup.underlyingMap.set("profile", profile.id, "trusting");
|
|
346
378
|
|
|
347
379
|
const accountOnThisNode = this.expectCoValueLoaded(account.id);
|
|
348
380
|
|
|
349
|
-
accountOnThisNode._sessions = {
|
|
381
|
+
accountOnThisNode._sessions = {
|
|
382
|
+
...accountAsGroup.underlyingMap.core.sessions,
|
|
383
|
+
};
|
|
350
384
|
accountOnThisNode._cachedContent = undefined;
|
|
351
385
|
|
|
386
|
+
const profileOnThisNode = this.createCoValue(profile.core.header);
|
|
387
|
+
|
|
388
|
+
profileOnThisNode._sessions = {
|
|
389
|
+
...profile.core.sessions,
|
|
390
|
+
};
|
|
391
|
+
profileOnThisNode._cachedContent = undefined;
|
|
392
|
+
|
|
352
393
|
return controlledAccount;
|
|
353
394
|
}
|
|
354
395
|
|
|
355
396
|
/** @internal */
|
|
356
|
-
resolveAccountAgent(
|
|
397
|
+
resolveAccountAgent(
|
|
398
|
+
id: AccountID | AgentID,
|
|
399
|
+
expectation?: string
|
|
400
|
+
): AgentID {
|
|
357
401
|
if (isAgentID(id)) {
|
|
358
402
|
return id;
|
|
359
403
|
}
|
|
@@ -374,13 +418,16 @@ export class LocalNode {
|
|
|
374
418
|
);
|
|
375
419
|
}
|
|
376
420
|
|
|
377
|
-
return new
|
|
421
|
+
return new AccountGroup(
|
|
378
422
|
coValue.getCurrentContent() as CoMap<GroupContent, AccountMeta>,
|
|
379
423
|
this
|
|
380
424
|
).getCurrentAgentID();
|
|
381
425
|
}
|
|
382
426
|
|
|
383
|
-
/**
|
|
427
|
+
/**
|
|
428
|
+
* Creates a new group (with the current account as the group's first admin).
|
|
429
|
+
* @category 1. High-level
|
|
430
|
+
*/
|
|
384
431
|
createGroup(): Group {
|
|
385
432
|
const groupCoValue = this.createCoValue({
|
|
386
433
|
type: "comap",
|
|
@@ -391,22 +438,22 @@ export class LocalNode {
|
|
|
391
438
|
|
|
392
439
|
let groupContent = expectGroupContent(groupCoValue.getCurrentContent());
|
|
393
440
|
|
|
394
|
-
groupContent = groupContent.
|
|
441
|
+
groupContent = groupContent.mutate((editable) => {
|
|
395
442
|
editable.set(this.account.id, "admin", "trusting");
|
|
396
443
|
|
|
397
444
|
const readKey = newRandomKeySecret();
|
|
398
445
|
|
|
399
446
|
editable.set(
|
|
400
447
|
`${readKey.id}_for_${this.account.id}`,
|
|
401
|
-
seal(
|
|
402
|
-
readKey.secret,
|
|
403
|
-
this.account.currentSealerSecret(),
|
|
404
|
-
this.account.currentSealerID(),
|
|
405
|
-
{
|
|
448
|
+
seal({
|
|
449
|
+
message: readKey.secret,
|
|
450
|
+
from: this.account.currentSealerSecret(),
|
|
451
|
+
to: this.account.currentSealerID(),
|
|
452
|
+
nOnceMaterial: {
|
|
406
453
|
in: groupCoValue.id,
|
|
407
454
|
tx: groupCoValue.nextTransactionID(),
|
|
408
|
-
}
|
|
409
|
-
),
|
|
455
|
+
},
|
|
456
|
+
}),
|
|
410
457
|
"trusting"
|
|
411
458
|
);
|
|
412
459
|
|
|
@@ -443,7 +490,11 @@ export class LocalNode {
|
|
|
443
490
|
continue;
|
|
444
491
|
}
|
|
445
492
|
|
|
446
|
-
const newCoValue = new CoValueCore(
|
|
493
|
+
const newCoValue = new CoValueCore(
|
|
494
|
+
entry.coValue.header,
|
|
495
|
+
newNode,
|
|
496
|
+
{ ...entry.coValue.sessions }
|
|
497
|
+
);
|
|
447
498
|
|
|
448
499
|
newNode.coValues[coValueID as RawCoID] = {
|
|
449
500
|
state: "loaded",
|
package/src/media.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { CoMap } from './coValues/coMap.js'
|
|
2
|
-
import { CoID } from './coValue.js'
|
|
3
2
|
import { BinaryCoStream } from './coValues/coStream.js'
|
|
4
3
|
|
|
5
4
|
export type ImageDefinition = CoMap<{
|
|
6
5
|
originalSize: [number, number];
|
|
7
6
|
placeholderDataURL?: string;
|
|
8
|
-
[res: `${number}x${number}`]:
|
|
7
|
+
[res: `${number}x${number}`]: BinaryCoStream;
|
|
9
8
|
}>;
|
package/src/permissions.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { CoID } from "./coValue.js";
|
|
2
2
|
import { MapOpPayload } from "./coValues/coMap.js";
|
|
3
3
|
import { JsonValue } from "./jsonValue.js";
|
|
4
|
-
import {
|
|
5
|
-
KeyID,
|
|
6
|
-
} from "./crypto.js";
|
|
4
|
+
import { KeyID } from "./crypto.js";
|
|
7
5
|
import {
|
|
8
6
|
CoValueCore,
|
|
9
7
|
Transaction,
|
|
@@ -11,11 +9,9 @@ import {
|
|
|
11
9
|
accountOrAgentIDfromSessionID,
|
|
12
10
|
} from "./coValueCore.js";
|
|
13
11
|
import { AgentID, RawCoID, SessionID, TransactionID } from "./ids.js";
|
|
14
|
-
import {
|
|
15
|
-
AccountID,
|
|
16
|
-
Profile,
|
|
17
|
-
} from "./account.js";
|
|
12
|
+
import { AccountID, Profile } from "./account.js";
|
|
18
13
|
import { parseJSON } from "./jsonStringify.js";
|
|
14
|
+
import { expectGroupContent } from "./group.js";
|
|
19
15
|
|
|
20
16
|
export type PermissionsDef =
|
|
21
17
|
| { type: "group"; initialAdmin: AccountID | AgentID }
|
|
@@ -77,7 +73,7 @@ export function determineValidTransactions(
|
|
|
77
73
|
// console.log("before", { memberState, validTransactions });
|
|
78
74
|
const transactor = accountOrAgentIDfromSessionID(sessionID);
|
|
79
75
|
|
|
80
|
-
const changes = parseJSON(tx.changes)
|
|
76
|
+
const changes = parseJSON(tx.changes);
|
|
81
77
|
|
|
82
78
|
const change = changes[0] as
|
|
83
79
|
| MapOpPayload<AccountID | AgentID, Role>
|
|
@@ -193,12 +189,14 @@ export function determineValidTransactions(
|
|
|
193
189
|
|
|
194
190
|
return validTransactions;
|
|
195
191
|
} else if (coValue.header.ruleset.type === "ownedByGroup") {
|
|
196
|
-
const groupContent =
|
|
197
|
-
.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
192
|
+
const groupContent = expectGroupContent(
|
|
193
|
+
coValue.node
|
|
194
|
+
.expectCoValueLoaded(
|
|
195
|
+
coValue.header.ruleset.group,
|
|
196
|
+
"Determining valid transaction in owned object but its group wasn't loaded"
|
|
197
|
+
)
|
|
198
|
+
.getCurrentContent()
|
|
199
|
+
);
|
|
202
200
|
|
|
203
201
|
if (groupContent.type !== "comap") {
|
|
204
202
|
throw new Error("Group must be a map");
|
|
@@ -211,10 +209,9 @@ export function determineValidTransactions(
|
|
|
211
209
|
);
|
|
212
210
|
return sessionLog.transactions
|
|
213
211
|
.filter((tx) => {
|
|
214
|
-
const transactorRoleAtTxTime = groupContent
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
);
|
|
212
|
+
const transactorRoleAtTxTime = groupContent
|
|
213
|
+
.atTime(tx.madeAt)
|
|
214
|
+
.get(transactor);
|
|
218
215
|
|
|
219
216
|
return (
|
|
220
217
|
transactorRoleAtTxTime === "admin" ||
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { CoList, MutableCoList } from "../coValues/coList.js";
|
|
2
|
+
import { CoValueCore } from "../coValueCore.js";
|
|
3
|
+
import { Group } from "../group.js";
|
|
4
|
+
import { isAccountID } from "../account.js";
|
|
5
|
+
import { AnyCoList, CoID, CoValue } from "../coValue.js";
|
|
6
|
+
import { TransactionID } from "../ids.js";
|
|
7
|
+
import { QueriedAccountAndProfile } from "./queriedCoMap.js";
|
|
8
|
+
import { ValueOrSubQueried, QueryContext } from "../queries.js";
|
|
9
|
+
|
|
10
|
+
export class QueriedCoList<L extends AnyCoList> extends Array<
|
|
11
|
+
ValueOrSubQueried<L["_item"]>
|
|
12
|
+
> {
|
|
13
|
+
coList!: L;
|
|
14
|
+
id!: CoID<L>;
|
|
15
|
+
type!: "colist";
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
constructor(coList: L, queryContext: QueryContext) {
|
|
19
|
+
if (!(coList instanceof CoList)) {
|
|
20
|
+
// this might be called from an intrinsic, like map, trying to create an empty array
|
|
21
|
+
// passing `0` as the only parameter
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
return new Array(coList) as any;
|
|
24
|
+
}
|
|
25
|
+
super(
|
|
26
|
+
...coList
|
|
27
|
+
.asArray()
|
|
28
|
+
.map(
|
|
29
|
+
(item) =>
|
|
30
|
+
queryContext.resolveValue(item) as ValueOrSubQueried<
|
|
31
|
+
L["_item"]
|
|
32
|
+
>
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
Object.defineProperties(this, {
|
|
37
|
+
coList: { value: coList },
|
|
38
|
+
id: { value: coList.id },
|
|
39
|
+
type: { value: "colist" },
|
|
40
|
+
edits: {
|
|
41
|
+
value: [...this.keys()].map((i) => {
|
|
42
|
+
const edit = coList.editAt(i)!;
|
|
43
|
+
return {
|
|
44
|
+
by:
|
|
45
|
+
edit.by && isAccountID(edit.by)
|
|
46
|
+
? queryContext.resolveAccount(edit.by)
|
|
47
|
+
: undefined,
|
|
48
|
+
tx: edit.tx,
|
|
49
|
+
at: new Date(edit.at),
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
value: queryContext.resolveValue(edit.value) as any,
|
|
52
|
+
};
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
deletions: {
|
|
56
|
+
value: coList.deletionEdits().map((deletion) => ({
|
|
57
|
+
by:
|
|
58
|
+
deletion.by && isAccountID(deletion.by)
|
|
59
|
+
? queryContext.resolveAccount(deletion.by)
|
|
60
|
+
: undefined,
|
|
61
|
+
tx: deletion.tx,
|
|
62
|
+
at: new Date(deletion.at),
|
|
63
|
+
})),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get meta(): L["meta"] {
|
|
69
|
+
return this.coList.meta;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get group(): Group {
|
|
73
|
+
return this.coList.group;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get core(): CoValueCore {
|
|
77
|
+
return this.coList.core;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
append(
|
|
81
|
+
item: L["_item"] extends CoValue
|
|
82
|
+
? L["_item"] | CoID<L["_item"]>
|
|
83
|
+
: L["_item"],
|
|
84
|
+
after?: number,
|
|
85
|
+
privacy?: "private" | "trusting"
|
|
86
|
+
): L {
|
|
87
|
+
return this.coList.append(item, after, privacy);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
prepend(
|
|
91
|
+
item: L["_item"] extends CoValue
|
|
92
|
+
? L["_item"] | CoID<L["_item"]>
|
|
93
|
+
: L["_item"],
|
|
94
|
+
before?: number,
|
|
95
|
+
privacy?: "private" | "trusting"
|
|
96
|
+
): L {
|
|
97
|
+
return this.coList.prepend(item, before, privacy);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
delete(at: number, privacy: "private" | "trusting"): L {
|
|
101
|
+
return this.coList.delete(at, privacy);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
mutate(
|
|
105
|
+
mutator: (mutable: MutableCoList<L["_item"], L["meta"]>) => void
|
|
106
|
+
): L {
|
|
107
|
+
return this.coList.mutate(mutator);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
edits!: {
|
|
111
|
+
by?: QueriedAccountAndProfile;
|
|
112
|
+
tx: TransactionID;
|
|
113
|
+
at: Date;
|
|
114
|
+
value: L["_item"] extends CoValue
|
|
115
|
+
? CoID<L["_item"]>
|
|
116
|
+
: Exclude<L["_item"], CoValue>;
|
|
117
|
+
}[];
|
|
118
|
+
|
|
119
|
+
deletions!: {
|
|
120
|
+
by?: QueriedAccountAndProfile;
|
|
121
|
+
tx: TransactionID;
|
|
122
|
+
at: Date;
|
|
123
|
+
}[];
|
|
124
|
+
|
|
125
|
+
/** @internal */
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
|
+
static isArray(arg: any): arg is any[] {
|
|
128
|
+
return Array.isArray(arg);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @internal */
|
|
132
|
+
static from<T>(arrayLike: ArrayLike<T>): T[];
|
|
133
|
+
/** @internal */
|
|
134
|
+
static from<T, U>(
|
|
135
|
+
arrayLike: ArrayLike<T>,
|
|
136
|
+
mapfn: (v: T, k: number) => U,
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
138
|
+
thisArg?: any
|
|
139
|
+
): U[];
|
|
140
|
+
/** @internal */
|
|
141
|
+
static from<T>(iterable: Iterable<T> | ArrayLike<T>): T[];
|
|
142
|
+
/** @internal */
|
|
143
|
+
static from<T, U>(
|
|
144
|
+
iterable: Iterable<T> | ArrayLike<T>,
|
|
145
|
+
mapfn: (v: T, k: number) => U,
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
|
+
thisArg?: any
|
|
148
|
+
): U[];
|
|
149
|
+
/** @internal */
|
|
150
|
+
static from<T, U>(
|
|
151
|
+
_iterable: unknown,
|
|
152
|
+
_mapfn?: unknown,
|
|
153
|
+
_thisArg?: unknown
|
|
154
|
+
): T[] | U[] | T[] | U[] {
|
|
155
|
+
throw new Error("Array method 'from' not supported on QueriedCoList");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** @internal */
|
|
159
|
+
static of<T>(..._items: T[]): T[] {
|
|
160
|
+
throw new Error("Array method 'of' not supported on QueriedCoList");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** @internal */
|
|
164
|
+
pop(): ValueOrSubQueried<L["_item"]> | undefined {
|
|
165
|
+
throw new Error("Array method 'pop' not supported on QueriedCoList");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** @internal */
|
|
169
|
+
push(..._items: ValueOrSubQueried<L["_item"]>[]): number {
|
|
170
|
+
throw new Error("Array method 'push' not supported on QueriedCoList");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** @internal */
|
|
174
|
+
concat(
|
|
175
|
+
..._items: ConcatArray<ValueOrSubQueried<L["_item"]>>[]
|
|
176
|
+
): ValueOrSubQueried<L["_item"]>[];
|
|
177
|
+
/** @internal */
|
|
178
|
+
concat(
|
|
179
|
+
..._items: (
|
|
180
|
+
| ValueOrSubQueried<L["_item"]>
|
|
181
|
+
| ConcatArray<ValueOrSubQueried<L["_item"]>>
|
|
182
|
+
)[]
|
|
183
|
+
): ValueOrSubQueried<L["_item"]>[];
|
|
184
|
+
/** @internal */
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
concat(..._items: any[]): ValueOrSubQueried<L["_item"]>[] {
|
|
187
|
+
throw new Error("Array method 'concat' not supported on QueriedCoList");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** @internal */
|
|
191
|
+
reverse(): ValueOrSubQueried<L["_item"]>[] {
|
|
192
|
+
throw new Error(
|
|
193
|
+
"Array method 'reverse' not supported on QueriedCoList"
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** @internal */
|
|
198
|
+
shift(): ValueOrSubQueried<L["_item"]> | undefined {
|
|
199
|
+
throw new Error("Array method 'shift' not supported on QueriedCoList");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** @internal */
|
|
203
|
+
sort(
|
|
204
|
+
_compareFn?:
|
|
205
|
+
| ((
|
|
206
|
+
a: ValueOrSubQueried<L["_item"]>,
|
|
207
|
+
b: ValueOrSubQueried<L["_item"]>
|
|
208
|
+
) => number)
|
|
209
|
+
| undefined
|
|
210
|
+
): this {
|
|
211
|
+
throw new Error("Array method 'sort' not supported on QueriedCoList");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** @internal */
|
|
215
|
+
splice(
|
|
216
|
+
_start: number,
|
|
217
|
+
_deleteCount?: number | undefined
|
|
218
|
+
): ValueOrSubQueried<L["_item"]>[] {
|
|
219
|
+
throw new Error("Array method 'splice' not supported on QueriedCoList");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** @internal */
|
|
223
|
+
unshift(..._items: ValueOrSubQueried<L["_item"]>[]): number {
|
|
224
|
+
throw new Error(
|
|
225
|
+
"Array method 'unshift' not supported on QueriedCoList"
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** @internal */
|
|
230
|
+
fill(
|
|
231
|
+
_value: ValueOrSubQueried<L["_item"]>,
|
|
232
|
+
_start?: number | undefined,
|
|
233
|
+
_end?: number | undefined
|
|
234
|
+
): this {
|
|
235
|
+
throw new Error("Array method 'fill' not supported on QueriedCoList");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** @internal */
|
|
239
|
+
copyWithin(
|
|
240
|
+
_target: number,
|
|
241
|
+
_start: number,
|
|
242
|
+
_end?: number | undefined
|
|
243
|
+
): this {
|
|
244
|
+
throw new Error(
|
|
245
|
+
"Array method 'copyWithin' not supported on QueriedCoList"
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|