@fluidframework/map 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.3.2.178189
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 +20 -0
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +120 -97
- package/dist/directory.js.map +1 -1
- package/dist/interfaces.d.ts +2 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/mapKernel.d.ts.map +1 -1
- package/dist/mapKernel.js +13 -5
- package/dist/mapKernel.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/lib/directory.d.ts.map +1 -1
- package/lib/directory.js +120 -97
- package/lib/directory.js.map +1 -1
- package/lib/interfaces.d.ts +2 -1
- package/lib/interfaces.d.ts.map +1 -1
- package/lib/interfaces.js.map +1 -1
- package/lib/mapKernel.d.ts.map +1 -1
- package/lib/mapKernel.js +13 -5
- package/lib/mapKernel.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +21 -23
- package/src/directory.ts +155 -117
- package/src/interfaces.ts +2 -6
- package/src/mapKernel.ts +17 -8
- package/src/packageVersion.ts +1 -1
package/lib/directory.js
CHANGED
|
@@ -349,7 +349,11 @@ export class SharedDirectory extends SharedObject {
|
|
|
349
349
|
let newSubDir = currentSubDir.getSubDirectory(subdirName);
|
|
350
350
|
if (!newSubDir) {
|
|
351
351
|
const createInfo = subdirObject.ci;
|
|
352
|
-
newSubDir = new SubDirectory(
|
|
352
|
+
newSubDir = new SubDirectory(
|
|
353
|
+
// If csn is -1, then initialize it with 0, otherwise we will never process ops for this
|
|
354
|
+
// sub directory. This could be done at serialization time too, but we need to maintain
|
|
355
|
+
// back compat too and also we will actually know the state when it was serialized.
|
|
356
|
+
createInfo !== undefined && createInfo.csn > -1 ? createInfo.csn : 0, createInfo !== undefined
|
|
353
357
|
? new Set(createInfo.ccIds)
|
|
354
358
|
: new Set(), this, this.runtime, this.serializer, posix.join(currentSubDir.absolutePath, subdirName));
|
|
355
359
|
currentSubDir.populateSubDirectory(subdirName, newSubDir);
|
|
@@ -637,16 +641,12 @@ function isClearLocalOpMetadata(metadata) {
|
|
|
637
641
|
}
|
|
638
642
|
function isSubDirLocalOpMetadata(metadata) {
|
|
639
643
|
return (metadata !== undefined &&
|
|
640
|
-
typeof metadata.pendingMessageId === "number" &&
|
|
641
644
|
(metadata.type === "createSubDir" || metadata.type === "deleteSubDir"));
|
|
642
645
|
}
|
|
643
646
|
function isDirectoryLocalOpMetadata(metadata) {
|
|
644
|
-
return (metadata
|
|
645
|
-
|
|
646
|
-
(metadata
|
|
647
|
-
metadata.type === "deleteSubDir" ||
|
|
648
|
-
(metadata.type === "clear" && typeof metadata.previousStorage === "object") ||
|
|
649
|
-
metadata.type === "createSubDir"));
|
|
647
|
+
return (isKeyEditLocalOpMetadata(metadata) ||
|
|
648
|
+
isClearLocalOpMetadata(metadata) ||
|
|
649
|
+
isSubDirLocalOpMetadata(metadata));
|
|
650
650
|
}
|
|
651
651
|
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */
|
|
652
652
|
function assertNonNullClientId(clientId) {
|
|
@@ -691,18 +691,24 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
691
691
|
*/
|
|
692
692
|
this._subdirectories = new Map();
|
|
693
693
|
/**
|
|
694
|
-
* Keys that have been modified locally but not yet ack'd from the server.
|
|
694
|
+
* Keys that have been modified locally but not yet ack'd from the server. This is for operations on keys like
|
|
695
|
+
* set/delete operations on keys. The value of this map is list of pendingMessageIds at which that key
|
|
696
|
+
* was modified. We don't store the type of ops, and behaviour of key ops are different from behaviour of sub
|
|
697
|
+
* directory ops, so we have separate map from subDirectories tracker.
|
|
695
698
|
*/
|
|
696
699
|
this.pendingKeys = new Map();
|
|
697
700
|
/**
|
|
698
|
-
* Subdirectories that have been
|
|
701
|
+
* Subdirectories that have been deleted locally but not yet ack'd from the server. This maintains the record
|
|
702
|
+
* of delete op that are pending or yet to be acked from server. This is maintained just to track the locally
|
|
703
|
+
* deleted sub directory.
|
|
699
704
|
*/
|
|
700
|
-
this.
|
|
705
|
+
this.pendingDeleteSubDirectoriesTracker = new Map();
|
|
701
706
|
/**
|
|
702
|
-
* Subdirectories that have been
|
|
703
|
-
* of
|
|
707
|
+
* Subdirectories that have been created locally but not yet ack'd from the server. This maintains the record
|
|
708
|
+
* of create op that are pending or yet to be acked from server. This is maintained just to track the locally
|
|
709
|
+
* created sub directory.
|
|
704
710
|
*/
|
|
705
|
-
this.
|
|
711
|
+
this.pendingCreateSubDirectoriesTracker = new Map();
|
|
706
712
|
/**
|
|
707
713
|
* This is used to assign a unique id to every outgoing operation and helps in tracking unack'd ops.
|
|
708
714
|
*/
|
|
@@ -869,8 +875,7 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
869
875
|
* @returns - true if there is pending delete.
|
|
870
876
|
*/
|
|
871
877
|
isSubDirectoryDeletePending(subDirName) {
|
|
872
|
-
|
|
873
|
-
if (pendingDeleteSubDirectory !== undefined && pendingDeleteSubDirectory > 0) {
|
|
878
|
+
if (this.pendingDeleteSubDirectoriesTracker.has(subDirName)) {
|
|
874
879
|
return true;
|
|
875
880
|
}
|
|
876
881
|
return false;
|
|
@@ -1110,7 +1115,8 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1110
1115
|
*/
|
|
1111
1116
|
processCreateSubDirectoryMessage(msg, op, local, localOpMetadata) {
|
|
1112
1117
|
this.throwIfDisposed();
|
|
1113
|
-
if (!this.
|
|
1118
|
+
if (!(this.isMessageForCurrentInstanceOfSubDirectory(msg) &&
|
|
1119
|
+
this.needProcessSubDirectoryOperation(msg, op, local, localOpMetadata))) {
|
|
1114
1120
|
return;
|
|
1115
1121
|
}
|
|
1116
1122
|
assertNonNullClientId(msg.clientId);
|
|
@@ -1126,10 +1132,9 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1126
1132
|
this.throwIfDisposed();
|
|
1127
1133
|
// Create the sub directory locally first.
|
|
1128
1134
|
this.createSubDirectoryCore(op.subdirName, true, -1, (_c = this.runtime.clientId) !== null && _c !== void 0 ? _c : "detached");
|
|
1129
|
-
|
|
1135
|
+
this.updatePendingSubDirMessageCount(op);
|
|
1130
1136
|
const localOpMetadata = {
|
|
1131
1137
|
type: "createSubDir",
|
|
1132
|
-
pendingMessageId: newMessageId,
|
|
1133
1138
|
};
|
|
1134
1139
|
return localOpMetadata;
|
|
1135
1140
|
}
|
|
@@ -1158,10 +1163,9 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1158
1163
|
applyStashedDeleteSubDirMessage(op) {
|
|
1159
1164
|
this.throwIfDisposed();
|
|
1160
1165
|
const subDir = this.deleteSubDirectoryCore(op.subdirName, true);
|
|
1161
|
-
|
|
1166
|
+
this.updatePendingSubDirMessageCount(op);
|
|
1162
1167
|
const metadata = {
|
|
1163
1168
|
type: "deleteSubDir",
|
|
1164
|
-
pendingMessageId: newMessageId,
|
|
1165
1169
|
subDirectory: subDir,
|
|
1166
1170
|
};
|
|
1167
1171
|
return metadata;
|
|
@@ -1190,8 +1194,11 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1190
1194
|
assert(isClearLocalOpMetadata(localOpMetadata), 0x32b /* Invalid localOpMetadata for clear */);
|
|
1191
1195
|
// We don't reuse the metadata pendingMessageId but send a new one on each submit.
|
|
1192
1196
|
const pendingClearMessageId = this.pendingClearMessageIds.shift();
|
|
1193
|
-
|
|
1194
|
-
|
|
1197
|
+
// Only submit the op, if we have record for it, otherwise it is possible that the older instance
|
|
1198
|
+
// is already deleted, in which case we don't need to submit the op.
|
|
1199
|
+
if (pendingClearMessageId === localOpMetadata.pendingMessageId) {
|
|
1200
|
+
this.submitClearMessage(op, localOpMetadata.previousStorage);
|
|
1201
|
+
}
|
|
1195
1202
|
}
|
|
1196
1203
|
/**
|
|
1197
1204
|
* Get a new pending message id for the op and cache it to track the pending op
|
|
@@ -1229,33 +1236,41 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1229
1236
|
assert(isKeyEditLocalOpMetadata(localOpMetadata), 0x32d /* Invalid localOpMetadata in submit */);
|
|
1230
1237
|
// clear the old pending message id
|
|
1231
1238
|
const pendingMessageIds = this.pendingKeys.get(op.key);
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
pendingMessageIds
|
|
1235
|
-
|
|
1236
|
-
|
|
1239
|
+
// Only submit the op, if we have record for it, otherwise it is possible that the older instance
|
|
1240
|
+
// is already deleted, in which case we don't need to submit the op.
|
|
1241
|
+
if (pendingMessageIds !== undefined &&
|
|
1242
|
+
pendingMessageIds[0] === localOpMetadata.pendingMessageId) {
|
|
1243
|
+
pendingMessageIds.shift();
|
|
1244
|
+
if (pendingMessageIds.length === 0) {
|
|
1245
|
+
this.pendingKeys.delete(op.key);
|
|
1246
|
+
}
|
|
1247
|
+
this.submitKeyMessage(op, localOpMetadata.previousValue);
|
|
1237
1248
|
}
|
|
1238
|
-
this.submitKeyMessage(op, localOpMetadata.previousValue);
|
|
1239
1249
|
}
|
|
1240
|
-
|
|
1241
|
-
* Get a new pending message id for the op and cache it to track the pending op
|
|
1242
|
-
*/
|
|
1243
|
-
getSubDirMessageId(op) {
|
|
1250
|
+
incrementPendingSubDirCount(map, subDirName) {
|
|
1244
1251
|
var _c;
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1252
|
+
const count = (_c = map.get(subDirName)) !== null && _c !== void 0 ? _c : 0;
|
|
1253
|
+
map.set(subDirName, count + 1);
|
|
1254
|
+
}
|
|
1255
|
+
decrementPendingSubDirCount(map, subDirName) {
|
|
1256
|
+
var _c;
|
|
1257
|
+
const count = (_c = map.get(subDirName)) !== null && _c !== void 0 ? _c : 0;
|
|
1258
|
+
map.set(subDirName, count - 1);
|
|
1259
|
+
if (count <= 1) {
|
|
1260
|
+
map.delete(subDirName);
|
|
1253
1261
|
}
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Update the count for pending create/delete of the sub directory so that it can be validated on receiving op
|
|
1265
|
+
* or while resubmitting the op.
|
|
1266
|
+
*/
|
|
1267
|
+
updatePendingSubDirMessageCount(op) {
|
|
1254
1268
|
if (op.type === "deleteSubDirectory") {
|
|
1255
|
-
|
|
1256
|
-
|
|
1269
|
+
this.incrementPendingSubDirCount(this.pendingDeleteSubDirectoriesTracker, op.subdirName);
|
|
1270
|
+
}
|
|
1271
|
+
else if (op.type === "createSubDirectory") {
|
|
1272
|
+
this.incrementPendingSubDirCount(this.pendingCreateSubDirectoriesTracker, op.subdirName);
|
|
1257
1273
|
}
|
|
1258
|
-
return newMessageId;
|
|
1259
1274
|
}
|
|
1260
1275
|
/**
|
|
1261
1276
|
* Submit a create subdirectory operation.
|
|
@@ -1263,10 +1278,9 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1263
1278
|
*/
|
|
1264
1279
|
submitCreateSubDirectoryMessage(op) {
|
|
1265
1280
|
this.throwIfDisposed();
|
|
1266
|
-
|
|
1281
|
+
this.updatePendingSubDirMessageCount(op);
|
|
1267
1282
|
const localOpMetadata = {
|
|
1268
1283
|
type: "createSubDir",
|
|
1269
|
-
pendingMessageId: newMessageId,
|
|
1270
1284
|
};
|
|
1271
1285
|
this.directory.submitDirectoryMessage(op, localOpMetadata);
|
|
1272
1286
|
}
|
|
@@ -1277,10 +1291,9 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1277
1291
|
*/
|
|
1278
1292
|
submitDeleteSubDirectoryMessage(op, subDir) {
|
|
1279
1293
|
this.throwIfDisposed();
|
|
1280
|
-
|
|
1294
|
+
this.updatePendingSubDirMessageCount(op);
|
|
1281
1295
|
const localOpMetadata = {
|
|
1282
1296
|
type: "deleteSubDir",
|
|
1283
|
-
pendingMessageId: newMessageId,
|
|
1284
1297
|
subDirectory: subDir,
|
|
1285
1298
|
};
|
|
1286
1299
|
this.directory.submitDirectoryMessage(op, localOpMetadata);
|
|
@@ -1293,18 +1306,22 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1293
1306
|
*/
|
|
1294
1307
|
resubmitSubDirectoryMessage(op, localOpMetadata) {
|
|
1295
1308
|
assert(isSubDirLocalOpMetadata(localOpMetadata), 0x32f /* Invalid localOpMetadata for sub directory op */);
|
|
1296
|
-
//
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1309
|
+
// Only submit the op, if we have record for it, otherwise it is possible that the older instance
|
|
1310
|
+
// is already deleted, in which case we don't need to submit the op.
|
|
1311
|
+
if (localOpMetadata.type === "createSubDir" &&
|
|
1312
|
+
!this.pendingCreateSubDirectoriesTracker.has(op.subdirName)) {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
else if (localOpMetadata.type === "deleteSubDir" &&
|
|
1316
|
+
!this.pendingDeleteSubDirectoriesTracker.has(op.subdirName)) {
|
|
1317
|
+
return;
|
|
1303
1318
|
}
|
|
1304
1319
|
if (localOpMetadata.type === "createSubDir") {
|
|
1320
|
+
this.decrementPendingSubDirCount(this.pendingCreateSubDirectoriesTracker, op.subdirName);
|
|
1305
1321
|
this.submitCreateSubDirectoryMessage(op);
|
|
1306
1322
|
}
|
|
1307
1323
|
else {
|
|
1324
|
+
this.decrementPendingSubDirCount(this.pendingDeleteSubDirectoriesTracker, op.subdirName);
|
|
1308
1325
|
this.submitDeleteSubDirectoryMessage(op, localOpMetadata.subDirectory);
|
|
1309
1326
|
}
|
|
1310
1327
|
}
|
|
@@ -1408,7 +1425,7 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1408
1425
|
}
|
|
1409
1426
|
else if (op.type === "createSubDirectory" && localOpMetadata.type === "createSubDir") {
|
|
1410
1427
|
this.deleteSubDirectoryCore(op.subdirName, true);
|
|
1411
|
-
this.
|
|
1428
|
+
this.decrementPendingSubDirCount(this.pendingCreateSubDirectoriesTracker, op.subdirName);
|
|
1412
1429
|
}
|
|
1413
1430
|
else if (op.type === "deleteSubDirectory" && localOpMetadata.type === "deleteSubDir") {
|
|
1414
1431
|
if (localOpMetadata.subDirectory !== undefined) {
|
|
@@ -1417,13 +1434,7 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1417
1434
|
this._subdirectories.set(op.subdirName, localOpMetadata.subDirectory);
|
|
1418
1435
|
this.emit("subDirectoryCreated", op.subdirName, true, this);
|
|
1419
1436
|
}
|
|
1420
|
-
this.
|
|
1421
|
-
const count = this.pendingDeleteSubDirectoriesCount.get(op.subdirName);
|
|
1422
|
-
assert(count !== undefined && count > 0, 0x5ab /* should have record for delete op */);
|
|
1423
|
-
this.pendingDeleteSubDirectoriesCount.set(op.subdirName, count - 1);
|
|
1424
|
-
if (count === 1) {
|
|
1425
|
-
this.pendingDeleteSubDirectoriesCount.delete(op.subdirName);
|
|
1426
|
-
}
|
|
1437
|
+
this.decrementPendingSubDirCount(this.pendingDeleteSubDirectoriesTracker, op.subDirName);
|
|
1427
1438
|
}
|
|
1428
1439
|
else {
|
|
1429
1440
|
throw new Error("Unsupported op for rollback");
|
|
@@ -1516,51 +1527,63 @@ class SubDirectory extends TypedEventEmitter {
|
|
|
1516
1527
|
* @returns True if the operation should be processed, false otherwise
|
|
1517
1528
|
*/
|
|
1518
1529
|
needProcessSubDirectoryOperation(msg, op, local, localOpMetadata) {
|
|
1519
|
-
const pendingSubDirectoryMessageId = this.pendingSubDirectories.get(op.subdirName);
|
|
1520
1530
|
assertNonNullClientId(msg.clientId);
|
|
1521
|
-
|
|
1531
|
+
const pendingDeleteCount = this.pendingDeleteSubDirectoriesTracker.get(op.subdirName);
|
|
1532
|
+
const pendingCreateCount = this.pendingCreateSubDirectoriesTracker.get(op.subdirName);
|
|
1533
|
+
if ((pendingDeleteCount !== undefined && pendingDeleteCount > 0) ||
|
|
1534
|
+
(pendingCreateCount !== undefined && pendingCreateCount > 0)) {
|
|
1522
1535
|
if (local) {
|
|
1523
1536
|
assert(isSubDirLocalOpMetadata(localOpMetadata), 0x012 /* pendingMessageId is missing from the local client's operation */);
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
pendingMessageIds.shift();
|
|
1528
|
-
if (pendingMessageIds.length === 0) {
|
|
1529
|
-
this.pendingSubDirectories.delete(op.subdirName);
|
|
1537
|
+
if (localOpMetadata.type === "deleteSubDir") {
|
|
1538
|
+
assert(pendingDeleteCount !== undefined && pendingDeleteCount > 0, 0x6c2 /* pendingDeleteCount should exist */);
|
|
1539
|
+
this.decrementPendingSubDirCount(this.pendingDeleteSubDirectoriesTracker, op.subdirName);
|
|
1530
1540
|
}
|
|
1531
|
-
if (
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
this.pendingDeleteSubDirectoriesCount.set(op.subdirName, count - 1);
|
|
1535
|
-
if (count === 1) {
|
|
1536
|
-
this.pendingDeleteSubDirectoriesCount.delete(op.subdirName);
|
|
1537
|
-
}
|
|
1541
|
+
else if (localOpMetadata.type === "createSubDir") {
|
|
1542
|
+
assert(pendingCreateCount !== undefined && pendingCreateCount > 0, 0x6c3 /* pendingCreateCount should exist */);
|
|
1543
|
+
this.decrementPendingSubDirCount(this.pendingCreateSubDirectoriesTracker, op.subdirName);
|
|
1538
1544
|
}
|
|
1539
1545
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
subDirectory
|
|
1546
|
-
//
|
|
1546
|
+
if (op.type === "deleteSubDirectory") {
|
|
1547
|
+
const resetSubDirectoryTree = (directory) => {
|
|
1548
|
+
if (!directory) {
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
// If this is delete op and we have keys in this subDirectory, then we need to delete these
|
|
1552
|
+
// keys except the pending ones as they will be sequenced after this delete.
|
|
1553
|
+
directory.clearExceptPendingKeys(local);
|
|
1554
|
+
// In case of delete op, we need to reset the creation seq number and client ids of
|
|
1547
1555
|
// creators as the previous directory is getting deleted and we will initialize again when
|
|
1548
1556
|
// we will receive op for the create again.
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1557
|
+
directory.sequenceNumber = -1;
|
|
1558
|
+
directory.clientIds.clear();
|
|
1559
|
+
// Do the same thing for the subtree of the directory. If create is not pending for a child, then just
|
|
1560
|
+
// delete it.
|
|
1561
|
+
const subDirectories = directory.subdirectories();
|
|
1562
|
+
for (const [subDirName, subDir] of subDirectories) {
|
|
1563
|
+
if (directory.pendingCreateSubDirectoriesTracker.has(subDirName)) {
|
|
1564
|
+
resetSubDirectoryTree(subDir);
|
|
1565
|
+
continue;
|
|
1566
|
+
}
|
|
1567
|
+
directory.deleteSubDirectoryCore(subDirName, false);
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
const subDirectory = this._subdirectories.get(op.subdirName);
|
|
1571
|
+
resetSubDirectoryTree(subDirectory);
|
|
1552
1572
|
}
|
|
1553
1573
|
if (op.type === "createSubDirectory") {
|
|
1554
1574
|
const dir = this._subdirectories.get(op.subdirName);
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
dir.sequenceNumber
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
dir
|
|
1563
|
-
|
|
1575
|
+
// Child sub directory create seq number can't be lower than the parent subdirectory.
|
|
1576
|
+
if (this.sequenceNumber !== -1 && this.sequenceNumber < msg.sequenceNumber) {
|
|
1577
|
+
if ((dir === null || dir === void 0 ? void 0 : dir.sequenceNumber) === -1) {
|
|
1578
|
+
// Only set the seq on the first message, could be more
|
|
1579
|
+
dir.sequenceNumber = msg.sequenceNumber;
|
|
1580
|
+
}
|
|
1581
|
+
// The client created the dir at or after the dirs seq, so list its client id as a creator.
|
|
1582
|
+
if (dir !== undefined &&
|
|
1583
|
+
!dir.clientIds.has(msg.clientId) &&
|
|
1584
|
+
dir.sequenceNumber <= msg.sequenceNumber) {
|
|
1585
|
+
dir.clientIds.add(msg.clientId);
|
|
1586
|
+
}
|
|
1564
1587
|
}
|
|
1565
1588
|
}
|
|
1566
1589
|
return false;
|