cojson 0.18.36 → 0.18.38
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/coValueCore/SessionMap.d.ts +5 -3
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +19 -9
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +5 -2
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +24 -4
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +1 -3
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +10 -14
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/group.d.ts +2 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +21 -18
- package/dist/coValues/group.js.map +1 -1
- package/dist/exports.d.ts +5 -4
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +3 -3
- package/dist/exports.js.map +1 -1
- package/dist/permissions.d.ts +0 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +83 -89
- package/dist/permissions.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.js +1 -18
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +8 -0
- package/dist/sync.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +8 -8
- package/dist/tests/coValueCore.isStreaming.test.js +30 -40
- package/dist/tests/coValueCore.isStreaming.test.js.map +1 -1
- package/dist/tests/coValueCore.newContentSince.test.js +242 -132
- package/dist/tests/coValueCore.newContentSince.test.js.map +1 -1
- package/dist/tests/group.inheritance.test.js +47 -1
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.invite.test.js +4 -9
- package/dist/tests/group.invite.test.js.map +1 -1
- package/dist/tests/sync.auth.test.js +6 -6
- package/dist/tests/sync.load.test.js +11 -75
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +2 -2
- package/dist/tests/sync.storage.test.js +22 -48
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +121 -71
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +11 -75
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +4 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +11 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/coValueCore/SessionMap.ts +25 -15
- package/src/coValueCore/coValueCore.ts +32 -2
- package/src/coValueCore/verifiedState.ts +11 -20
- package/src/coValues/group.ts +28 -24
- package/src/exports.ts +5 -2
- package/src/permissions.ts +98 -119
- package/src/queue/LocalTransactionsSyncQueue.ts +1 -20
- package/src/sync.ts +9 -0
- package/src/tests/StorageApiAsync.test.ts +8 -8
- package/src/tests/coValueCore.isStreaming.test.ts +84 -91
- package/src/tests/coValueCore.newContentSince.test.ts +246 -141
- package/src/tests/group.inheritance.test.ts +61 -0
- package/src/tests/group.invite.test.ts +4 -21
- package/src/tests/sync.auth.test.ts +6 -6
- package/src/tests/sync.load.test.ts +11 -79
- package/src/tests/sync.mesh.test.ts +2 -2
- package/src/tests/sync.storage.test.ts +22 -51
- package/src/tests/sync.storageAsync.test.ts +159 -76
- package/src/tests/sync.upload.test.ts +11 -78
- package/src/tests/testUtils.ts +16 -0
package/src/permissions.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ParentGroupReferenceRole,
|
|
9
9
|
RawGroup,
|
|
10
10
|
isInheritableRole,
|
|
11
|
+
isSelfExtension,
|
|
11
12
|
} from "./coValues/group.js";
|
|
12
13
|
import { KeyID } from "./crypto/crypto.js";
|
|
13
14
|
import {
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
getParentGroupId,
|
|
18
19
|
} from "./ids.js";
|
|
19
20
|
import { JsonValue } from "./jsonValue.js";
|
|
20
|
-
import { logger } from "./logger.js";
|
|
21
21
|
import { expectGroup } from "./typeUtils/expectGroup.js";
|
|
22
22
|
|
|
23
23
|
export type PermissionsDef =
|
|
@@ -70,25 +70,6 @@ function canAdmin(role: Role | undefined): boolean {
|
|
|
70
70
|
return role === "admin" || role === "manager";
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
type MemberState = { [agent: RawAccountID | AgentID]: Role; [EVERYONE]?: Role };
|
|
74
|
-
|
|
75
|
-
let logPermissionErrors = true;
|
|
76
|
-
|
|
77
|
-
export function disablePermissionErrors() {
|
|
78
|
-
logPermissionErrors = false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function logPermissionError(
|
|
82
|
-
message: string,
|
|
83
|
-
attributes?: Record<string, JsonValue>,
|
|
84
|
-
) {
|
|
85
|
-
if (logPermissionErrors === false) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
logger.debug("Permission error: " + message, attributes);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
73
|
export function determineValidTransactions(coValue: CoValueCore): void {
|
|
93
74
|
if (!coValue.isAvailable()) {
|
|
94
75
|
throw new Error("determineValidTransactions CoValue is not available");
|
|
@@ -130,7 +111,10 @@ export function determineValidTransactions(coValue: CoValueCore): void {
|
|
|
130
111
|
);
|
|
131
112
|
|
|
132
113
|
if (!effectiveTransactor) {
|
|
133
|
-
tx.markInvalid(
|
|
114
|
+
tx.markInvalid("Transactor not found in group", {
|
|
115
|
+
transactor: tx.author,
|
|
116
|
+
group: groupAtTime.toJSON(),
|
|
117
|
+
});
|
|
134
118
|
continue;
|
|
135
119
|
}
|
|
136
120
|
|
|
@@ -158,7 +142,10 @@ export function determineValidTransactions(coValue: CoValueCore): void {
|
|
|
158
142
|
transactorRoleAtTxTime !== "writer" &&
|
|
159
143
|
transactorRoleAtTxTime !== "writeOnly"
|
|
160
144
|
) {
|
|
161
|
-
tx.markInvalid(
|
|
145
|
+
tx.markInvalid("Transactor has no write permissions", {
|
|
146
|
+
transactor: tx.author,
|
|
147
|
+
transactorRole: transactorRoleAtTxTime ?? "undefined",
|
|
148
|
+
});
|
|
162
149
|
continue;
|
|
163
150
|
}
|
|
164
151
|
|
|
@@ -193,77 +180,78 @@ function isHigherRole(a: Role, b: Role | undefined) {
|
|
|
193
180
|
return a === "writer" && b === "reader";
|
|
194
181
|
}
|
|
195
182
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
parentReference: ParentGroupReference,
|
|
200
|
-
roleMapping: ParentGroupReferenceRole,
|
|
201
|
-
extendChain: Set<CoValueCore["id"]>,
|
|
202
|
-
) {
|
|
203
|
-
const parentGroup = coValue.node.expectCoValueLoaded(
|
|
204
|
-
getParentGroupId(parentReference),
|
|
205
|
-
"Expected parent group to be loaded",
|
|
206
|
-
);
|
|
183
|
+
class MemberRoleResolver {
|
|
184
|
+
private parentGroups = new Map<RawGroup, ParentGroupReferenceRole>();
|
|
185
|
+
private memberRoles = new Map<RawAccountID | AgentID | Everyone, Role>();
|
|
207
186
|
|
|
208
|
-
|
|
209
|
-
|
|
187
|
+
setDirectRole(member: RawAccountID | AgentID | Everyone, role: Role) {
|
|
188
|
+
this.memberRoles.set(member, role);
|
|
210
189
|
}
|
|
211
190
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return;
|
|
191
|
+
removeMember(member: RawAccountID | AgentID | Everyone) {
|
|
192
|
+
this.memberRoles.delete(member);
|
|
215
193
|
}
|
|
216
194
|
|
|
217
|
-
|
|
195
|
+
addParentGroup(parentGroup: RawGroup, roleMapping: ParentGroupReferenceRole) {
|
|
196
|
+
this.parentGroups.set(parentGroup, roleMapping);
|
|
197
|
+
}
|
|
218
198
|
|
|
219
|
-
|
|
220
|
-
|
|
199
|
+
removeParentGroup(parentGroup: RawGroup) {
|
|
200
|
+
this.parentGroups.delete(parentGroup);
|
|
221
201
|
}
|
|
222
202
|
|
|
223
|
-
|
|
203
|
+
getDirectRole(member: RawAccountID | AgentID | Everyone) {
|
|
204
|
+
return this.memberRoles.get(member);
|
|
205
|
+
}
|
|
224
206
|
|
|
225
|
-
|
|
226
|
-
|
|
207
|
+
getRoleAtTime(member: RawAccountID | AgentID | Everyone, time: number) {
|
|
208
|
+
let role = this.memberRoles.get(member);
|
|
227
209
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
>) {
|
|
231
|
-
const parentRole = parentGroupMemberState[agent];
|
|
232
|
-
const currentRole = memberState[agent];
|
|
210
|
+
for (const [parentGroup, roleMapping] of this.parentGroups.entries()) {
|
|
211
|
+
const parentRole = parentGroup.atTime(time).roleOfInternal(member);
|
|
233
212
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
213
|
+
if (!parentRole || !isInheritableRole(parentRole)) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const resolvedParentRole =
|
|
218
|
+
roleMapping === "extend" ? parentRole : roleMapping;
|
|
219
|
+
|
|
220
|
+
if (isHigherRole(resolvedParentRole, role)) {
|
|
221
|
+
role = resolvedParentRole;
|
|
239
222
|
}
|
|
240
223
|
}
|
|
224
|
+
|
|
225
|
+
return role;
|
|
241
226
|
}
|
|
242
227
|
}
|
|
243
228
|
|
|
244
229
|
function determineValidTransactionsForGroup(
|
|
245
230
|
coValue: CoValueCore,
|
|
246
231
|
initialAdmin: RawAccountID | AgentID,
|
|
247
|
-
|
|
248
|
-
): { memberState: MemberState } {
|
|
232
|
+
): void {
|
|
249
233
|
coValue.verifiedTransactions.sort(coValue.compareTransactions);
|
|
250
234
|
|
|
251
|
-
const memberState: MemberState = {};
|
|
252
235
|
const writeOnlyKeys: Record<RawAccountID | AgentID, KeyID> = {};
|
|
253
236
|
const writeKeys = new Set<string>();
|
|
237
|
+
const memberRoleResolver = new MemberRoleResolver();
|
|
254
238
|
|
|
255
239
|
for (const transaction of coValue.verifiedTransactions) {
|
|
256
240
|
const transactor = transaction.author;
|
|
257
|
-
|
|
241
|
+
|
|
242
|
+
const transactorRole = memberRoleResolver.getRoleAtTime(
|
|
243
|
+
transactor,
|
|
244
|
+
transaction.currentMadeAt,
|
|
245
|
+
);
|
|
258
246
|
|
|
259
247
|
const tx = transaction.tx;
|
|
260
248
|
|
|
261
249
|
if (tx.privacy === "private") {
|
|
262
|
-
if (
|
|
250
|
+
if (transactorRole === "admin") {
|
|
263
251
|
transaction.markValid();
|
|
264
252
|
continue;
|
|
265
253
|
} else {
|
|
266
|
-
|
|
254
|
+
transaction.markInvalid(
|
|
267
255
|
"Only admins can make private transactions in groups",
|
|
268
256
|
);
|
|
269
257
|
continue;
|
|
@@ -285,21 +273,18 @@ function determineValidTransactionsForGroup(
|
|
|
285
273
|
| MapOpPayload<`child_${CoID<RawGroup>}`, CoID<RawGroup>>;
|
|
286
274
|
|
|
287
275
|
if (changes.length !== 1) {
|
|
288
|
-
|
|
289
|
-
transaction.markInvalid();
|
|
276
|
+
transaction.markInvalid("Group transaction must have exactly one change");
|
|
290
277
|
continue;
|
|
291
278
|
}
|
|
292
279
|
|
|
293
280
|
if (change.op !== "set") {
|
|
294
|
-
|
|
295
|
-
transaction.markInvalid();
|
|
281
|
+
transaction.markInvalid("Group transaction must set a role or readKey");
|
|
296
282
|
continue;
|
|
297
283
|
}
|
|
298
284
|
|
|
299
285
|
if (change.key === "readKey") {
|
|
300
286
|
if (!canAdmin(transactorRole)) {
|
|
301
|
-
|
|
302
|
-
transaction.markInvalid();
|
|
287
|
+
transaction.markInvalid("Only admins can set readKeys");
|
|
303
288
|
continue;
|
|
304
289
|
}
|
|
305
290
|
|
|
@@ -307,8 +292,7 @@ function determineValidTransactionsForGroup(
|
|
|
307
292
|
continue;
|
|
308
293
|
} else if (change.key === "profile") {
|
|
309
294
|
if (!canAdmin(transactorRole)) {
|
|
310
|
-
|
|
311
|
-
transaction.markInvalid();
|
|
295
|
+
transaction.markInvalid("Only admins can set profile");
|
|
312
296
|
continue;
|
|
313
297
|
}
|
|
314
298
|
|
|
@@ -316,7 +300,7 @@ function determineValidTransactionsForGroup(
|
|
|
316
300
|
continue;
|
|
317
301
|
} else if (change.key === "root") {
|
|
318
302
|
if (!canAdmin(transactorRole)) {
|
|
319
|
-
|
|
303
|
+
transaction.markInvalid("Only admins can set root");
|
|
320
304
|
continue;
|
|
321
305
|
}
|
|
322
306
|
|
|
@@ -336,47 +320,51 @@ function determineValidTransactionsForGroup(
|
|
|
336
320
|
transactorRole !== "writeOnlyInvite" &&
|
|
337
321
|
!isOwnWriteKeyRevelation(change.key, transactor, writeOnlyKeys)
|
|
338
322
|
) {
|
|
339
|
-
|
|
340
|
-
transaction.markInvalid();
|
|
323
|
+
transaction.markInvalid("Only admins and managers can reveal keys");
|
|
341
324
|
continue;
|
|
342
325
|
}
|
|
343
326
|
|
|
344
|
-
// TODO: check validity of agents who the key is revealed to?
|
|
345
327
|
transaction.markValid();
|
|
346
328
|
continue;
|
|
347
329
|
} else if (isParentExtension(change.key)) {
|
|
348
330
|
if (!canAdmin(transactorRole)) {
|
|
349
|
-
|
|
331
|
+
transaction.markInvalid(
|
|
350
332
|
"Only admins and managers can set parent extensions",
|
|
351
333
|
);
|
|
352
|
-
transaction.markInvalid();
|
|
353
334
|
continue;
|
|
354
335
|
}
|
|
355
336
|
|
|
356
|
-
|
|
337
|
+
const parentGroupId = getParentGroupId(change.key);
|
|
357
338
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
change.key,
|
|
362
|
-
change.value as ParentGroupReferenceRole,
|
|
363
|
-
extendChain,
|
|
339
|
+
const parentGroupCore = coValue.node.expectCoValueLoaded(
|
|
340
|
+
parentGroupId,
|
|
341
|
+
"Expected parent group to be loaded",
|
|
364
342
|
);
|
|
365
343
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
344
|
+
if (!parentGroupCore.isGroup()) {
|
|
345
|
+
transaction.markInvalid("Parent group is not a group");
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const parentGroup = expectGroup(parentGroupCore.getCurrentContent());
|
|
350
|
+
|
|
351
|
+
if (isSelfExtension(coValue, parentGroup)) {
|
|
352
|
+
transaction.markInvalid("Parent group is a circular dependency");
|
|
372
353
|
continue;
|
|
373
354
|
}
|
|
374
355
|
|
|
356
|
+
const value = change.value as ParentGroupReferenceRole;
|
|
357
|
+
|
|
358
|
+
if (value === "revoked") {
|
|
359
|
+
memberRoleResolver.removeParentGroup(parentGroup);
|
|
360
|
+
} else {
|
|
361
|
+
memberRoleResolver.addParentGroup(parentGroup, value);
|
|
362
|
+
}
|
|
363
|
+
|
|
375
364
|
transaction.markValid();
|
|
376
365
|
continue;
|
|
377
366
|
} else if (isChildExtension(change.key)) {
|
|
378
|
-
|
|
379
|
-
transaction.markInvalid();
|
|
367
|
+
transaction.markInvalid("Child extensions are not allowed anymore");
|
|
380
368
|
continue;
|
|
381
369
|
} else if (isWriteKeyForMember(change.key)) {
|
|
382
370
|
const memberKey = getAccountOrAgentFromWriteKeyForMember(change.key);
|
|
@@ -387,8 +375,7 @@ function determineValidTransactionsForGroup(
|
|
|
387
375
|
transactorRole !== "writeOnlyInvite" &&
|
|
388
376
|
memberKey !== transactor
|
|
389
377
|
) {
|
|
390
|
-
|
|
391
|
-
transaction.markInvalid();
|
|
378
|
+
transaction.markInvalid("Only admins and managers can set writeKeys");
|
|
392
379
|
continue;
|
|
393
380
|
}
|
|
394
381
|
|
|
@@ -403,10 +390,9 @@ function determineValidTransactionsForGroup(
|
|
|
403
390
|
* blocking them from accessing the group.ß
|
|
404
391
|
*/
|
|
405
392
|
if (writeKeys.has(change.key) && !canAdmin(transactorRole)) {
|
|
406
|
-
|
|
393
|
+
transaction.markInvalid(
|
|
407
394
|
"Write key already exists and can't be overridden by invite",
|
|
408
395
|
);
|
|
409
|
-
transaction.markInvalid();
|
|
410
396
|
continue;
|
|
411
397
|
}
|
|
412
398
|
|
|
@@ -432,8 +418,7 @@ function determineValidTransactionsForGroup(
|
|
|
432
418
|
assignedRole !== "readerInvite" &&
|
|
433
419
|
assignedRole !== "writeOnlyInvite"
|
|
434
420
|
) {
|
|
435
|
-
|
|
436
|
-
transaction.markInvalid();
|
|
421
|
+
transaction.markInvalid("Group transaction must set a valid role");
|
|
437
422
|
continue;
|
|
438
423
|
}
|
|
439
424
|
|
|
@@ -446,10 +431,9 @@ function determineValidTransactionsForGroup(
|
|
|
446
431
|
assignedRole === "revoked"
|
|
447
432
|
)
|
|
448
433
|
) {
|
|
449
|
-
|
|
434
|
+
transaction.markInvalid(
|
|
450
435
|
"Everyone can only be set to reader, writer, writeOnly or revoked",
|
|
451
436
|
);
|
|
452
|
-
transaction.markInvalid();
|
|
453
437
|
continue;
|
|
454
438
|
}
|
|
455
439
|
|
|
@@ -460,15 +444,10 @@ function determineValidTransactionsForGroup(
|
|
|
460
444
|
throw new Error("Expected set operation");
|
|
461
445
|
}
|
|
462
446
|
|
|
463
|
-
|
|
447
|
+
memberRoleResolver.setDirectRole(change.key, change.value);
|
|
464
448
|
transaction.markValid();
|
|
465
449
|
}
|
|
466
450
|
|
|
467
|
-
function markTransactionAsInvalid(message: string) {
|
|
468
|
-
logPermissionError(message);
|
|
469
|
-
transaction.markInvalid();
|
|
470
|
-
}
|
|
471
|
-
|
|
472
451
|
// is first self promotion to admin
|
|
473
452
|
if (
|
|
474
453
|
transactorRole === undefined &&
|
|
@@ -486,7 +465,10 @@ function determineValidTransactionsForGroup(
|
|
|
486
465
|
continue;
|
|
487
466
|
}
|
|
488
467
|
|
|
489
|
-
const affectedMemberRole =
|
|
468
|
+
const affectedMemberRole = memberRoleResolver.getRoleAtTime(
|
|
469
|
+
affectedMember,
|
|
470
|
+
transaction.currentMadeAt,
|
|
471
|
+
);
|
|
490
472
|
|
|
491
473
|
/**
|
|
492
474
|
* Admins can't:
|
|
@@ -498,7 +480,7 @@ function determineValidTransactionsForGroup(
|
|
|
498
480
|
assignedRole !== "admin" &&
|
|
499
481
|
affectedMember !== transactor
|
|
500
482
|
) {
|
|
501
|
-
|
|
483
|
+
transaction.markInvalid("Admins can't demote admins.");
|
|
502
484
|
continue;
|
|
503
485
|
}
|
|
504
486
|
|
|
@@ -514,20 +496,20 @@ function determineValidTransactionsForGroup(
|
|
|
514
496
|
*/
|
|
515
497
|
if (transactorRole === "manager") {
|
|
516
498
|
if (affectedMemberRole === "admin") {
|
|
517
|
-
|
|
499
|
+
transaction.markInvalid("Managers can't demote admins.");
|
|
518
500
|
continue;
|
|
519
501
|
}
|
|
520
502
|
if (change.value === "admin") {
|
|
521
|
-
|
|
503
|
+
transaction.markInvalid("Managers can't promote to admin.");
|
|
522
504
|
continue;
|
|
523
505
|
}
|
|
524
506
|
|
|
525
507
|
if (change.value === "adminInvite") {
|
|
526
|
-
|
|
508
|
+
transaction.markInvalid("Managers can't invite admins.");
|
|
527
509
|
continue;
|
|
528
510
|
}
|
|
529
511
|
if (change.value === "managerInvite") {
|
|
530
|
-
|
|
512
|
+
transaction.markInvalid("Managers can't invite managers.");
|
|
531
513
|
continue;
|
|
532
514
|
}
|
|
533
515
|
|
|
@@ -537,42 +519,39 @@ function determineValidTransactionsForGroup(
|
|
|
537
519
|
|
|
538
520
|
if (transactorRole === "adminInvite") {
|
|
539
521
|
if (change.value !== "admin") {
|
|
540
|
-
|
|
541
|
-
transaction.markInvalid();
|
|
522
|
+
transaction.markInvalid("AdminInvites can only create admins.");
|
|
542
523
|
continue;
|
|
543
524
|
}
|
|
544
525
|
} else if (transactorRole === "managerInvite") {
|
|
545
526
|
if (change.value !== "manager") {
|
|
546
|
-
|
|
527
|
+
transaction.markInvalid("managerInvite can only create managers.");
|
|
547
528
|
continue;
|
|
548
529
|
}
|
|
549
530
|
} else if (transactorRole === "writerInvite") {
|
|
550
531
|
if (change.value !== "writer") {
|
|
551
|
-
|
|
532
|
+
transaction.markInvalid("WriterInvites can only create writers.");
|
|
552
533
|
continue;
|
|
553
534
|
}
|
|
554
535
|
} else if (transactorRole === "readerInvite") {
|
|
555
536
|
if (change.value !== "reader") {
|
|
556
|
-
|
|
537
|
+
transaction.markInvalid("ReaderInvites can only create reader.");
|
|
557
538
|
continue;
|
|
558
539
|
}
|
|
559
540
|
} else if (transactorRole === "writeOnlyInvite") {
|
|
560
541
|
if (change.value !== "writeOnly") {
|
|
561
|
-
|
|
542
|
+
transaction.markInvalid("WriteOnlyInvites can only create writeOnly.");
|
|
562
543
|
continue;
|
|
563
544
|
}
|
|
564
545
|
} else {
|
|
565
|
-
|
|
546
|
+
transaction.markInvalid(
|
|
566
547
|
"Group transaction must be made by current admin, manager, or invite",
|
|
567
548
|
);
|
|
568
549
|
continue;
|
|
569
550
|
}
|
|
570
551
|
|
|
571
|
-
|
|
552
|
+
memberRoleResolver.setDirectRole(affectedMember, change.value);
|
|
572
553
|
transaction.markValid();
|
|
573
554
|
}
|
|
574
|
-
|
|
575
|
-
return { memberState };
|
|
576
555
|
}
|
|
577
556
|
|
|
578
557
|
function agentInAccountOrMemberInGroup(
|
|
@@ -50,33 +50,14 @@ export class LocalTransactionsSyncQueue {
|
|
|
50
50
|
coValue: VerifiedState,
|
|
51
51
|
knownStateBefore: CoValueKnownState,
|
|
52
52
|
) {
|
|
53
|
-
const content = coValue.newContentSince(knownStateBefore
|
|
54
|
-
skipExpectContentUntil: true, // we need to calculate the streaming header considering the current batch
|
|
55
|
-
});
|
|
53
|
+
const content = coValue.newContentSince(knownStateBefore);
|
|
56
54
|
|
|
57
55
|
if (!content) {
|
|
58
56
|
return;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
let firstChunk = this.firstChunks.get(coValue.id);
|
|
62
|
-
|
|
63
59
|
for (const piece of content) {
|
|
64
60
|
this.batch.push(piece);
|
|
65
|
-
|
|
66
|
-
// Check if the local content updates are in streaming, if so we need to add the info to the first chunk
|
|
67
|
-
if (firstChunk) {
|
|
68
|
-
if (!firstChunk.expectContentUntil) {
|
|
69
|
-
firstChunk.expectContentUntil =
|
|
70
|
-
knownStateFromContent(firstChunk).sessions;
|
|
71
|
-
}
|
|
72
|
-
combineKnownStateSessions(
|
|
73
|
-
firstChunk.expectContentUntil,
|
|
74
|
-
knownStateFromContent(piece).sessions,
|
|
75
|
-
);
|
|
76
|
-
} else {
|
|
77
|
-
firstChunk = piece;
|
|
78
|
-
this.firstChunks.set(coValue.id, firstChunk);
|
|
79
|
-
}
|
|
80
61
|
}
|
|
81
62
|
}
|
|
82
63
|
|
package/src/sync.ts
CHANGED
|
@@ -484,6 +484,15 @@ export class SyncManager {
|
|
|
484
484
|
? "import"
|
|
485
485
|
: peer?.role;
|
|
486
486
|
|
|
487
|
+
// TODO: We can't handle client-to-client streaming until we
|
|
488
|
+
// handle the streaming state reset on disconnection
|
|
489
|
+
if (peer?.role === "client" && msg.expectContentUntil) {
|
|
490
|
+
msg = {
|
|
491
|
+
...msg,
|
|
492
|
+
expectContentUntil: undefined,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
487
496
|
coValue.addDependenciesFromContentMessage(msg);
|
|
488
497
|
|
|
489
498
|
// If some of the dependencies are missing, we wait for them to be available
|
|
@@ -539,16 +539,16 @@ describe("StorageApiAsync", () => {
|
|
|
539
539
|
}),
|
|
540
540
|
).toMatchInlineSnapshot(`
|
|
541
541
|
[
|
|
542
|
-
"test -> test-storage | CONTENT Core header: false new: After: 1 New: 1
|
|
543
|
-
"test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1
|
|
542
|
+
"test -> test-storage | CONTENT Core header: false new: After: 1 New: 1",
|
|
543
|
+
"test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1",
|
|
544
544
|
"test -> test-storage | CONTENT Core header: false new: After: 2 New: 1",
|
|
545
545
|
"test -> test-storage | CONTENT Core2 header: false new: After: 2 New: 1",
|
|
546
546
|
"test-storage -> test | KNOWN CORRECTION Core sessions: empty",
|
|
547
547
|
"test -> test-storage | CONTENT Core header: true new: After: 0 New: 3",
|
|
548
548
|
"test-storage -> test | KNOWN CORRECTION Core2 sessions: empty",
|
|
549
549
|
"test -> test-storage | CONTENT Core2 header: true new: After: 0 New: 3",
|
|
550
|
-
"test -> test-storage | CONTENT Core header: false new: After: 3 New: 1
|
|
551
|
-
"test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1
|
|
550
|
+
"test -> test-storage | CONTENT Core header: false new: After: 3 New: 1",
|
|
551
|
+
"test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1",
|
|
552
552
|
"test -> test-storage | CONTENT Core header: false new: After: 4 New: 1",
|
|
553
553
|
"test -> test-storage | CONTENT Core2 header: false new: After: 4 New: 1",
|
|
554
554
|
]
|
|
@@ -606,14 +606,14 @@ describe("StorageApiAsync", () => {
|
|
|
606
606
|
}),
|
|
607
607
|
).toMatchInlineSnapshot(`
|
|
608
608
|
[
|
|
609
|
-
"test -> test-storage | CONTENT Core header: false new: After: 1 New: 1
|
|
610
|
-
"test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1
|
|
609
|
+
"test -> test-storage | CONTENT Core header: false new: After: 1 New: 1",
|
|
610
|
+
"test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1",
|
|
611
611
|
"test -> test-storage | CONTENT Core header: false new: After: 2 New: 1",
|
|
612
612
|
"test -> test-storage | CONTENT Core2 header: false new: After: 2 New: 1",
|
|
613
613
|
"test-storage -> test | KNOWN CORRECTION Core sessions: empty",
|
|
614
614
|
"test -> test-storage | CONTENT Core header: true new: After: 0 New: 3",
|
|
615
|
-
"test -> test-storage | CONTENT Core header: false new: After: 3 New: 1
|
|
616
|
-
"test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1
|
|
615
|
+
"test -> test-storage | CONTENT Core header: false new: After: 3 New: 1",
|
|
616
|
+
"test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1",
|
|
617
617
|
"test -> test-storage | CONTENT Core header: false new: After: 4 New: 1",
|
|
618
618
|
"test -> test-storage | CONTENT Core2 header: false new: After: 4 New: 1",
|
|
619
619
|
]
|