@fluidframework/map 2.0.0-rc.1.0.6 → 2.0.0-rc.2.0.1

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.
Files changed (132) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +10 -1
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +11 -0
  4. package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
  5. package/api-extractor-lint.json +1 -1
  6. package/api-extractor.json +1 -1
  7. package/api-report/map.api.md +14 -57
  8. package/dist/directory.d.ts +10 -50
  9. package/dist/directory.d.ts.map +1 -1
  10. package/dist/directory.js +76 -164
  11. package/dist/directory.js.map +1 -1
  12. package/dist/index.d.ts +45 -4
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +43 -8
  15. package/dist/index.js.map +1 -1
  16. package/dist/interfaces.d.ts.map +1 -1
  17. package/dist/interfaces.js.map +1 -1
  18. package/dist/internalInterfaces.d.ts +2 -2
  19. package/dist/internalInterfaces.d.ts.map +1 -1
  20. package/dist/internalInterfaces.js.map +1 -1
  21. package/dist/localValues.d.ts +3 -5
  22. package/dist/localValues.d.ts.map +1 -1
  23. package/dist/localValues.js +9 -8
  24. package/dist/localValues.js.map +1 -1
  25. package/dist/map-alpha.d.ts +31 -116
  26. package/dist/map-beta.d.ts +24 -105
  27. package/dist/map-public.d.ts +24 -105
  28. package/dist/map-untrimmed.d.ts +31 -116
  29. package/dist/map.d.ts +4 -23
  30. package/dist/map.d.ts.map +1 -1
  31. package/dist/map.js +6 -29
  32. package/dist/map.js.map +1 -1
  33. package/dist/mapKernel.d.ts +3 -4
  34. package/dist/mapKernel.d.ts.map +1 -1
  35. package/dist/mapKernel.js +30 -35
  36. package/dist/mapKernel.js.map +1 -1
  37. package/dist/package.json +3 -0
  38. package/dist/packageVersion.d.ts +1 -1
  39. package/dist/packageVersion.js +1 -1
  40. package/dist/packageVersion.js.map +1 -1
  41. package/dist/tsdoc-metadata.json +1 -1
  42. package/lib/{directory.d.mts → directory.d.ts} +11 -51
  43. package/lib/directory.d.ts.map +1 -0
  44. package/lib/{directory.mjs → directory.js} +77 -165
  45. package/lib/directory.js.map +1 -0
  46. package/lib/index.d.ts +61 -0
  47. package/lib/index.d.ts.map +1 -0
  48. package/lib/index.js +55 -0
  49. package/lib/index.js.map +1 -0
  50. package/lib/{interfaces.d.mts → interfaces.d.ts} +1 -1
  51. package/lib/interfaces.d.ts.map +1 -0
  52. package/lib/{interfaces.mjs → interfaces.js} +1 -1
  53. package/lib/interfaces.js.map +1 -0
  54. package/lib/{internalInterfaces.d.mts → internalInterfaces.d.ts} +3 -3
  55. package/lib/internalInterfaces.d.ts.map +1 -0
  56. package/lib/{internalInterfaces.mjs → internalInterfaces.js} +1 -1
  57. package/lib/internalInterfaces.js.map +1 -0
  58. package/lib/{localValues.d.mts → localValues.d.ts} +4 -6
  59. package/lib/localValues.d.ts.map +1 -0
  60. package/lib/{localValues.mjs → localValues.js} +10 -9
  61. package/lib/localValues.js.map +1 -0
  62. package/lib/{map-alpha.d.mts → map-alpha.d.ts} +43 -116
  63. package/lib/{map-beta.d.mts → map-beta.d.ts} +36 -105
  64. package/lib/{map-public.d.mts → map-public.d.ts} +36 -105
  65. package/lib/{map-untrimmed.d.mts → map-untrimmed.d.ts} +43 -116
  66. package/lib/{map.d.mts → map.d.ts} +5 -24
  67. package/lib/map.d.ts.map +1 -0
  68. package/lib/{map.mjs → map.js} +5 -28
  69. package/lib/map.js.map +1 -0
  70. package/lib/{mapKernel.d.mts → mapKernel.d.ts} +4 -5
  71. package/lib/mapKernel.d.ts.map +1 -0
  72. package/lib/{mapKernel.mjs → mapKernel.js} +32 -37
  73. package/lib/mapKernel.js.map +1 -0
  74. package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
  75. package/lib/packageVersion.d.ts.map +1 -0
  76. package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
  77. package/lib/packageVersion.js.map +1 -0
  78. package/lib/test/memory/directory.spec.js +71 -0
  79. package/lib/test/memory/directory.spec.js.map +1 -0
  80. package/lib/test/memory/map.spec.js +71 -0
  81. package/lib/test/memory/map.spec.js.map +1 -0
  82. package/lib/test/mocha/directory.order.spec.js +422 -0
  83. package/lib/test/mocha/directory.order.spec.js.map +1 -0
  84. package/lib/test/mocha/directory.snapshot.spec.js +111 -0
  85. package/lib/test/mocha/directory.snapshot.spec.js.map +1 -0
  86. package/lib/test/mocha/directory.spec.js +1406 -0
  87. package/lib/test/mocha/directory.spec.js.map +1 -0
  88. package/lib/test/mocha/directoryEquivalenceUtils.js +36 -0
  89. package/lib/test/mocha/directoryEquivalenceUtils.js.map +1 -0
  90. package/lib/test/mocha/directoryFuzzTests.spec.js +337 -0
  91. package/lib/test/mocha/directoryFuzzTests.spec.js.map +1 -0
  92. package/lib/test/mocha/dirname.cjs +16 -0
  93. package/lib/test/mocha/dirname.cjs.map +1 -0
  94. package/lib/test/mocha/map.fuzz.spec.js +114 -0
  95. package/lib/test/mocha/map.fuzz.spec.js.map +1 -0
  96. package/lib/test/mocha/map.spec.js +685 -0
  97. package/lib/test/mocha/map.spec.js.map +1 -0
  98. package/lib/test/mocha/rebasing.spec.js +158 -0
  99. package/lib/test/mocha/rebasing.spec.js.map +1 -0
  100. package/lib/test/mocha/reconnection.spec.js +327 -0
  101. package/lib/test/mocha/reconnection.spec.js.map +1 -0
  102. package/lib/test/types/validateMapPrevious.generated.js +66 -0
  103. package/lib/test/types/validateMapPrevious.generated.js.map +1 -0
  104. package/package.json +55 -52
  105. package/src/directory.ts +122 -217
  106. package/src/index.ts +57 -4
  107. package/src/interfaces.ts +2 -2
  108. package/src/internalInterfaces.ts +2 -2
  109. package/src/localValues.ts +14 -9
  110. package/src/map.ts +7 -32
  111. package/src/mapKernel.ts +40 -42
  112. package/src/packageVersion.ts +1 -1
  113. package/tsconfig.cjs.json +7 -0
  114. package/tsconfig.json +2 -5
  115. package/lib/directory.d.mts.map +0 -1
  116. package/lib/directory.mjs.map +0 -1
  117. package/lib/index.d.mts +0 -9
  118. package/lib/index.d.mts.map +0 -1
  119. package/lib/index.mjs +0 -8
  120. package/lib/index.mjs.map +0 -1
  121. package/lib/interfaces.d.mts.map +0 -1
  122. package/lib/interfaces.mjs.map +0 -1
  123. package/lib/internalInterfaces.d.mts.map +0 -1
  124. package/lib/internalInterfaces.mjs.map +0 -1
  125. package/lib/localValues.d.mts.map +0 -1
  126. package/lib/localValues.mjs.map +0 -1
  127. package/lib/map.d.mts.map +0 -1
  128. package/lib/map.mjs.map +0 -1
  129. package/lib/mapKernel.d.mts.map +0 -1
  130. package/lib/mapKernel.mjs.map +0 -1
  131. package/lib/packageVersion.d.mts.map +0 -1
  132. package/lib/packageVersion.mjs.map +0 -1
package/src/directory.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert } from "@fluidframework/core-utils";
6
+ import { assert, unreachableCase } from "@fluidframework/core-utils";
7
7
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
8
8
  import { ITelemetryLoggerExt, UsageError } from "@fluidframework/telemetry-utils";
9
9
  import { readAndParse } from "@fluidframework/driver-utils";
@@ -16,7 +16,12 @@ import {
16
16
  IChannelFactory,
17
17
  } from "@fluidframework/datastore-definitions";
18
18
  import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
19
- import { IFluidSerializer, SharedObject, ValueType } from "@fluidframework/shared-object-base";
19
+ import {
20
+ IFluidSerializer,
21
+ SharedObject,
22
+ ValueType,
23
+ parseHandles,
24
+ } from "@fluidframework/shared-object-base";
20
25
  import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
21
26
  import path from "path-browserify";
22
27
  import { RedBlackTree } from "@fluidframework/merge-tree";
@@ -30,9 +35,9 @@ import {
30
35
  ISharedDirectory,
31
36
  ISharedDirectoryEvents,
32
37
  IValueChanged,
33
- } from "./interfaces";
34
- import { ILocalValue, LocalValueMaker, makeSerializable } from "./localValues";
35
- import { pkgVersion } from "./packageVersion";
38
+ } from "./interfaces.js";
39
+ import { ILocalValue, LocalValueMaker, makeSerializable } from "./localValues.js";
40
+ import { pkgVersion } from "./packageVersion.js";
36
41
 
37
42
  // We use path-browserify since this code can run safely on the server or the browser.
38
43
  // We standardize on using posix slashes everywhere.
@@ -65,8 +70,6 @@ interface IDirectoryMessageHandler {
65
70
  * @param localOpMetadata - The metadata to be submitted with the message.
66
71
  */
67
72
  submit(op: IDirectoryOperation, localOpMetadata: unknown): void;
68
-
69
- applyStashedOp(op: IDirectoryOperation): unknown;
70
73
  }
71
74
 
72
75
  /**
@@ -271,7 +274,7 @@ export interface IDirectoryNewStorageFormat {
271
274
  * @sealed
272
275
  * @alpha
273
276
  */
274
- export class DirectoryFactory implements IChannelFactory {
277
+ export class DirectoryFactory implements IChannelFactory<ISharedDirectory> {
275
278
  /**
276
279
  * {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory."type"}
277
280
  */
@@ -346,25 +349,25 @@ export class DirectoryFactory implements IChannelFactory {
346
349
  * 4. A 'seq' value of zero indicates that the subdirectory was created in detached state, and it is considered acknowledged for the
347
350
  * purpose of ordering.
348
351
  */
349
- const seqDataComparator = (a: SequenceData, b: SequenceData) => {
352
+ const seqDataComparator = (a: SequenceData, b: SequenceData): number => {
350
353
  if (isAcknowledgedOrDetached(a)) {
351
354
  if (isAcknowledgedOrDetached(b)) {
352
355
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
353
- return a.seq !== b.seq ? a.seq - b.seq : a.clientSeq! - b.clientSeq!;
356
+ return a.seq === b.seq ? a.clientSeq! - b.clientSeq! : a.seq - b.seq;
354
357
  } else {
355
358
  return -1;
356
359
  }
357
360
  } else {
358
- if (!isAcknowledgedOrDetached(b)) {
359
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
360
- return a.seq !== b.seq ? a.seq - b.seq : a.clientSeq! - b.clientSeq!;
361
- } else {
361
+ if (isAcknowledgedOrDetached(b)) {
362
362
  return 1;
363
+ } else {
364
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
365
+ return a.seq === b.seq ? a.clientSeq! - b.clientSeq! : a.seq - b.seq;
363
366
  }
364
367
  }
365
368
  };
366
369
 
367
- function isAcknowledgedOrDetached(seqData: SequenceData) {
370
+ function isAcknowledgedOrDetached(seqData: SequenceData): boolean {
368
371
  return seqData.seq >= 0;
369
372
  }
370
373
 
@@ -464,8 +467,8 @@ export class SharedDirectory
464
467
  * @param id - Optional name of the shared directory
465
468
  * @returns Newly create shared directory (but not attached yet)
466
469
  */
467
- public static create(runtime: IFluidDataStoreRuntime, id?: string): SharedDirectory {
468
- return runtime.createChannel(id, DirectoryFactory.Type) as SharedDirectory;
470
+ public static create(runtime: IFluidDataStoreRuntime, id?: string): ISharedDirectory {
471
+ return runtime.createChannel(id, DirectoryFactory.Type) as ISharedDirectory;
469
472
  }
470
473
 
471
474
  /**
@@ -473,7 +476,7 @@ export class SharedDirectory
473
476
  *
474
477
  * @returns A factory that creates and load SharedDirectory
475
478
  */
476
- public static getFactory(): IChannelFactory {
479
+ public static getFactory(): IChannelFactory<ISharedDirectory> {
477
480
  return new DirectoryFactory();
478
481
  }
479
482
 
@@ -523,7 +526,7 @@ export class SharedDirectory
523
526
  attributes: IChannelAttributes,
524
527
  ) {
525
528
  super(id, runtime, attributes, "fluid_directory_");
526
- this.localValueMaker = new LocalValueMaker(this.serializer);
529
+ this.localValueMaker = new LocalValueMaker();
527
530
  this.setMessageHandlers();
528
531
  // Mirror the containedValueChanged op on the SharedDirectory
529
532
  this.root.on("containedValueChanged", (changed: IValueChanged, local: boolean) => {
@@ -808,9 +811,9 @@ export class SharedDirectory
808
811
  }
809
812
  newSubDir = new SubDirectory(
810
813
  seqData,
811
- createInfo !== undefined
812
- ? new Set<string>(createInfo.ccIds)
813
- : new Set(),
814
+ createInfo === undefined
815
+ ? new Set()
816
+ : new Set<string>(createInfo.ccIds),
814
817
  this,
815
818
  this.runtime,
816
819
  this.serializer,
@@ -832,7 +835,8 @@ export class SharedDirectory
832
835
  const localValue = this.makeLocal(
833
836
  key,
834
837
  currentSubDir.absolutePath,
835
- serializable,
838
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
839
+ parseHandles(serializable, this.serializer),
836
840
  );
837
841
  currentSubDir.populateStorage(key, localValue);
838
842
  }
@@ -896,7 +900,7 @@ export class SharedDirectory
896
900
  serializable.type === ValueType[ValueType.Shared],
897
901
  0x1e4 /* "Unexpected serializable type" */,
898
902
  );
899
- return this.localValueMaker.fromSerializable(serializable);
903
+ return this.localValueMaker.fromSerializable(serializable, this.serializer, this.handle);
900
904
  }
901
905
 
902
906
  /**
@@ -950,12 +954,6 @@ export class SharedDirectory
950
954
  subdir.resubmitClearMessage(op, localOpMetadata);
951
955
  }
952
956
  },
953
- applyStashedOp: (op: IDirectoryClearOperation): IClearLocalOpMetadata | undefined => {
954
- const subdir = this.getWorkingDirectory(op.path) as SubDirectory | undefined;
955
- if (subdir) {
956
- return subdir.applyStashedClearMessage(op);
957
- }
958
- },
959
957
  });
960
958
  this.messageHandlers.set("delete", {
961
959
  process: (
@@ -977,14 +975,6 @@ export class SharedDirectory
977
975
  subdir.resubmitKeyMessage(op, localOpMetadata);
978
976
  }
979
977
  },
980
- applyStashedOp: (
981
- op: IDirectoryDeleteOperation,
982
- ): IKeyEditLocalOpMetadata | undefined => {
983
- const subdir = this.getWorkingDirectory(op.path) as SubDirectory | undefined;
984
- if (subdir) {
985
- return subdir.applyStashedDeleteMessage(op);
986
- }
987
- },
988
978
  });
989
979
  this.messageHandlers.set("set", {
990
980
  process: (
@@ -1007,13 +997,6 @@ export class SharedDirectory
1007
997
  subdir.resubmitKeyMessage(op, localOpMetadata);
1008
998
  }
1009
999
  },
1010
- applyStashedOp: (op: IDirectorySetOperation): IKeyEditLocalOpMetadata | undefined => {
1011
- const subdir = this.getWorkingDirectory(op.path) as SubDirectory | undefined;
1012
- if (subdir) {
1013
- const context = this.makeLocal(op.key, op.path, op.value);
1014
- return subdir.applyStashedSetMessage(op, context);
1015
- }
1016
- },
1017
1000
  });
1018
1001
 
1019
1002
  this.messageHandlers.set("createSubDirectory", {
@@ -1037,14 +1020,6 @@ export class SharedDirectory
1037
1020
  parentSubdir.resubmitSubDirectoryMessage(op, localOpMetadata);
1038
1021
  }
1039
1022
  },
1040
- applyStashedOp: (
1041
- op: IDirectoryCreateSubDirectoryOperation,
1042
- ): ICreateSubDirLocalOpMetadata | undefined => {
1043
- const parentSubdir = this.getWorkingDirectory(op.path) as SubDirectory | undefined;
1044
- if (parentSubdir) {
1045
- return parentSubdir.applyStashedCreateSubDirMessage(op);
1046
- }
1047
- },
1048
1023
  });
1049
1024
 
1050
1025
  this.messageHandlers.set("deleteSubDirectory", {
@@ -1068,26 +1043,47 @@ export class SharedDirectory
1068
1043
  parentSubdir.resubmitSubDirectoryMessage(op, localOpMetadata);
1069
1044
  }
1070
1045
  },
1071
- applyStashedOp: (
1072
- op: IDirectoryDeleteSubDirectoryOperation,
1073
- ): IDeleteSubDirLocalOpMetadata | undefined => {
1074
- const parentSubdir = this.getWorkingDirectory(op.path) as SubDirectory | undefined;
1075
- if (parentSubdir) {
1076
- return parentSubdir.applyStashedDeleteSubDirMessage(op);
1077
- }
1078
- },
1079
1046
  });
1080
1047
  }
1081
1048
 
1082
1049
  /**
1083
1050
  * {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
1084
1051
  */
1085
- protected applyStashedOp(op: unknown): unknown {
1086
- const handler = this.messageHandlers.get((op as IDirectoryOperation).type);
1087
- if (handler === undefined) {
1088
- throw new Error("no apply stashed op handler");
1052
+ protected applyStashedOp(op: unknown): void {
1053
+ const directoryOp = op as IDirectoryOperation;
1054
+ const dir = this.getWorkingDirectory(directoryOp.path);
1055
+ switch (directoryOp.type) {
1056
+ case "clear": {
1057
+ dir?.clear();
1058
+ break;
1059
+ }
1060
+ case "createSubDirectory": {
1061
+ dir?.createSubDirectory(directoryOp.subdirName);
1062
+ break;
1063
+ }
1064
+ case "delete": {
1065
+ dir?.delete(directoryOp.key);
1066
+ break;
1067
+ }
1068
+ case "deleteSubDirectory": {
1069
+ dir?.deleteSubDirectory(directoryOp.subdirName);
1070
+ break;
1071
+ }
1072
+ case "set": {
1073
+ dir?.set(
1074
+ directoryOp.key,
1075
+ this.localValueMaker.fromSerializable(
1076
+ directoryOp.value,
1077
+ this.serializer,
1078
+ this.handle,
1079
+ ).value,
1080
+ );
1081
+ break;
1082
+ }
1083
+ default: {
1084
+ unreachableCase(directoryOp);
1085
+ }
1089
1086
  }
1090
- return handler.applyStashedOp(op as IDirectoryOperation);
1091
1087
  }
1092
1088
 
1093
1089
  private serializeDirectory(
@@ -1221,6 +1217,7 @@ function isDirectoryLocalOpMetadata(metadata: any): metadata is DirectoryLocalOp
1221
1217
 
1222
1218
  /* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */
1223
1219
 
1220
+ // eslint-disable-next-line @rushstack/no-new-null
1224
1221
  function assertNonNullClientId(clientId: string | null): asserts clientId is string {
1225
1222
  assert(clientId !== null, 0x6af /* client id should never be null */);
1226
1223
  }
@@ -1451,13 +1448,15 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1451
1448
  }
1452
1449
 
1453
1450
  /**
1454
- * @returns The Sequence Data which should be used for local changes.
1451
+ * Gets the Sequence Data which should be used for local changes.
1452
+ *
1455
1453
  * @remarks While detached, 0 is used rather than -1 to represent a change which should be universally known (as opposed to known
1456
1454
  * only by the local client). This ensures that if the directory is later attached, none of its data needs to be updated (the values
1457
1455
  * last set while detached will now be known to any new client, until they are changed).
1458
1456
  *
1459
1457
  * The client sequence number is incremented by 1 for maintaining the internal order of locally created subdirectories
1460
- * TODO: Convert these conventions to named constants. The semantics used here match those for merge-tree.
1458
+ *
1459
+ * @privateRemarks TODO: Convert these conventions to named constants. The semantics used here match those for merge-tree.
1461
1460
  */
1462
1461
  private getLocalSeq(): SequenceData {
1463
1462
  return this.directory.isAttached()
@@ -1541,15 +1540,19 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1541
1540
  const entriesIterator = {
1542
1541
  index: 0,
1543
1542
  dirs: this._subdirectories,
1544
- next(): IteratorResult<[string, any]> {
1543
+ next(): IteratorResult<[string, IDirectory]> {
1545
1544
  if (this.index < subdirNames.length) {
1546
1545
  const subdirName = subdirNames[this.index++];
1547
1546
  const subdir = this.dirs.get(subdirName);
1547
+ assert(
1548
+ subdir !== undefined,
1549
+ 0x8ac /* Could not find expected sub-directory. */,
1550
+ );
1548
1551
  return { value: [subdirName, subdir], done: false };
1549
1552
  }
1550
1553
  return { value: undefined, done: true };
1551
1554
  },
1552
- [Symbol.iterator](): IterableIterator<[string, any]> {
1555
+ [Symbol.iterator](): IterableIterator<[string, IDirectory]> {
1553
1556
  return this;
1554
1557
  },
1555
1558
  };
@@ -1712,7 +1715,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1712
1715
  * @param local - Whether the message originated from the local client
1713
1716
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
1714
1717
  * For messages from a remote client, this will be undefined.
1715
- * @internal
1716
1718
  */
1717
1719
  public processClearMessage(
1718
1720
  msg: ISequencedDocumentMessage,
@@ -1739,25 +1741,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1739
1741
  this.clearExceptPendingKeys(false);
1740
1742
  }
1741
1743
 
1742
- /**
1743
- * Apply clear operation locally and generate metadata
1744
- * @param op - Op to apply
1745
- * @returns metadata generated for stahed op
1746
- */
1747
- public applyStashedClearMessage(op: IDirectoryClearOperation): IClearLocalOpMetadata {
1748
- this.throwIfDisposed();
1749
- const previousValue = new Map<string, ILocalValue>(this._storage);
1750
- this.clearExceptPendingKeys(true);
1751
- const pendingMsgId = ++this.pendingMessageId;
1752
- this.pendingClearMessageIds.push(pendingMsgId);
1753
- const metadata: IClearLocalOpMetadata = {
1754
- type: "clear",
1755
- pendingMessageId: pendingMsgId,
1756
- previousStorage: previousValue,
1757
- };
1758
- return metadata;
1759
- }
1760
-
1761
1744
  /**
1762
1745
  * Process a delete operation.
1763
1746
  * @param msg - The message from the server to apply.
@@ -1765,7 +1748,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1765
1748
  * @param local - Whether the message originated from the local client
1766
1749
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
1767
1750
  * For messages from a remote client, this will be undefined.
1768
- * @internal
1769
1751
  */
1770
1752
  public processDeleteMessage(
1771
1753
  msg: ISequencedDocumentMessage,
@@ -1785,23 +1767,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1785
1767
  this.deleteCore(op.key, local);
1786
1768
  }
1787
1769
 
1788
- /**
1789
- * Apply delete operation locally and generate metadata
1790
- * @param op - Op to apply
1791
- * @returns metadata generated for stahed op
1792
- */
1793
- public applyStashedDeleteMessage(op: IDirectoryDeleteOperation): IKeyEditLocalOpMetadata {
1794
- this.throwIfDisposed();
1795
- const previousValue = this.deleteCore(op.key, true);
1796
- const pendingMessageId = this.getKeyMessageId(op);
1797
- const localMetadata: IKeyEditLocalOpMetadata = {
1798
- type: "edit",
1799
- pendingMessageId,
1800
- previousValue,
1801
- };
1802
- return localMetadata;
1803
- }
1804
-
1805
1770
  /**
1806
1771
  * Process a set operation.
1807
1772
  * @param msg - The message from the server to apply.
@@ -1809,7 +1774,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1809
1774
  * @param local - Whether the message originated from the local client
1810
1775
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
1811
1776
  * For messages from a remote client, this will be undefined.
1812
- * @internal
1813
1777
  */
1814
1778
  public processSetMessage(
1815
1779
  msg: ISequencedDocumentMessage,
@@ -1834,28 +1798,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1834
1798
  this.setCore(op.key, context!, local);
1835
1799
  }
1836
1800
 
1837
- /**
1838
- * Apply set operation locally and generate metadata
1839
- * @param op - Op to apply
1840
- * @returns metadata generated for stahed op
1841
- */
1842
- public applyStashedSetMessage(
1843
- op: IDirectorySetOperation,
1844
- context: ILocalValue,
1845
- ): IKeyEditLocalOpMetadata {
1846
- this.throwIfDisposed();
1847
- // Set the value locally.
1848
- const previousValue = this.setCore(op.key, context, true);
1849
-
1850
- // Create metadata
1851
- const pendingMessageId = this.getKeyMessageId(op);
1852
- const localMetadata: IKeyEditLocalOpMetadata = {
1853
- type: "edit",
1854
- pendingMessageId,
1855
- previousValue,
1856
- };
1857
- return localMetadata;
1858
- }
1859
1801
  /**
1860
1802
  * Process a create subdirectory operation.
1861
1803
  * @param msg - The message from the server to apply.
@@ -1863,7 +1805,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1863
1805
  * @param local - Whether the message originated from the local client
1864
1806
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
1865
1807
  * For messages from a remote client, this will be undefined.
1866
- * @internal
1867
1808
  */
1868
1809
  public processCreateSubDirectoryMessage(
1869
1810
  msg: ISequencedDocumentMessage,
@@ -1889,30 +1830,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1889
1830
  );
1890
1831
  }
1891
1832
 
1892
- /**
1893
- * Apply createSubDirectory operation locally and generate metadata
1894
- * @param op - Op to apply
1895
- * @returns metadata generated for stahed op
1896
- */
1897
- public applyStashedCreateSubDirMessage(
1898
- op: IDirectoryCreateSubDirectoryOperation,
1899
- ): ICreateSubDirLocalOpMetadata {
1900
- this.throwIfDisposed();
1901
- // Create the sub directory locally first.
1902
- this.createSubDirectoryCore(
1903
- op.subdirName,
1904
- true,
1905
- this.getLocalSeq(),
1906
- this.runtime.clientId ?? "detached",
1907
- );
1908
- this.updatePendingSubDirMessageCount(op);
1909
-
1910
- const localOpMetadata: ICreateSubDirLocalOpMetadata = {
1911
- type: "createSubDir",
1912
- };
1913
- return localOpMetadata;
1914
- }
1915
-
1916
1833
  /**
1917
1834
  * Process a delete subdirectory operation.
1918
1835
  * @param msg - The message from the server to apply.
@@ -1920,7 +1837,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1920
1837
  * @param local - Whether the message originated from the local client
1921
1838
  * @param localOpMetadata - For local client messages, this is the metadata that was submitted with the message.
1922
1839
  * For messages from a remote client, this will be undefined.
1923
- * @internal
1924
1840
  */
1925
1841
  public processDeleteSubDirectoryMessage(
1926
1842
  msg: ISequencedDocumentMessage,
@@ -1940,24 +1856,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1940
1856
  this.deleteSubDirectoryCore(op.subdirName, local);
1941
1857
  }
1942
1858
 
1943
- /**
1944
- * Apply deleteSubDirectory operation locally and generate metadata
1945
- * @param op - Op to apply
1946
- * @returns metadata generated for stahed op
1947
- */
1948
- public applyStashedDeleteSubDirMessage(
1949
- op: IDirectoryDeleteSubDirectoryOperation,
1950
- ): IDeleteSubDirLocalOpMetadata {
1951
- this.throwIfDisposed();
1952
- const subDir = this.deleteSubDirectoryCore(op.subdirName, true);
1953
- this.updatePendingSubDirMessageCount(op);
1954
- const metadata: IDeleteSubDirLocalOpMetadata = {
1955
- type: "deleteSubDir",
1956
- subDirectory: subDir,
1957
- };
1958
- return metadata;
1959
- }
1960
-
1961
1859
  /**
1962
1860
  * Submit a clear operation.
1963
1861
  * @param op - The operation
@@ -1980,7 +1878,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
1980
1878
  /**
1981
1879
  * Resubmit a clear operation.
1982
1880
  * @param op - The operation
1983
- * @internal
1984
1881
  */
1985
1882
  public resubmitClearMessage(op: IDirectoryClearOperation, localOpMetadata: unknown): void {
1986
1883
  assert(
@@ -2003,10 +1900,10 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2003
1900
  // We don't reuse the metadata pendingMessageId but send a new one on each submit.
2004
1901
  const pendingMessageId = ++this.pendingMessageId;
2005
1902
  const pendingMessageIds = this.pendingKeys.get(op.key);
2006
- if (pendingMessageIds !== undefined) {
2007
- pendingMessageIds.push(pendingMessageId);
2008
- } else {
1903
+ if (pendingMessageIds === undefined) {
2009
1904
  this.pendingKeys.set(op.key, [pendingMessageId]);
1905
+ } else {
1906
+ pendingMessageIds.push(pendingMessageId);
2010
1907
  }
2011
1908
  return pendingMessageId;
2012
1909
  }
@@ -2027,7 +1924,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2027
1924
  * Submit a key message to remote clients based on a previous submit.
2028
1925
  * @param op - The map key message
2029
1926
  * @param localOpMetadata - Metadata from the previous submit
2030
- * @internal
2031
1927
  */
2032
1928
  public resubmitKeyMessage(op: IDirectoryKeyOperation, localOpMetadata: unknown): void {
2033
1929
  assert(
@@ -2040,9 +1936,7 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2040
1936
  // Only submit the op, if we have record for it, otherwise it is possible that the older instance
2041
1937
  // is already deleted, in which case we don't need to submit the op.
2042
1938
  if (pendingMessageIds !== undefined) {
2043
- const index = pendingMessageIds.findIndex(
2044
- (id) => id === localOpMetadata.pendingMessageId,
2045
- );
1939
+ const index = pendingMessageIds.indexOf(localOpMetadata.pendingMessageId);
2046
1940
  if (index === -1) {
2047
1941
  return;
2048
1942
  }
@@ -2054,12 +1948,12 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2054
1948
  }
2055
1949
  }
2056
1950
 
2057
- private incrementPendingSubDirCount(map: Map<string, number>, subDirName: string) {
1951
+ private incrementPendingSubDirCount(map: Map<string, number>, subDirName: string): void {
2058
1952
  const count = map.get(subDirName) ?? 0;
2059
1953
  map.set(subDirName, count + 1);
2060
1954
  }
2061
1955
 
2062
- private decrementPendingSubDirCount(map: Map<string, number>, subDirName: string) {
1956
+ private decrementPendingSubDirCount(map: Map<string, number>, subDirName: string): void {
2063
1957
  const count = map.get(subDirName) ?? 0;
2064
1958
  map.set(subDirName, count - 1);
2065
1959
  if (count <= 1) {
@@ -2071,7 +1965,7 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2071
1965
  * Update the count for pending create/delete of the sub directory so that it can be validated on receiving op
2072
1966
  * or while resubmitting the op.
2073
1967
  */
2074
- private updatePendingSubDirMessageCount(op: IDirectorySubDirectoryOperation) {
1968
+ private updatePendingSubDirMessageCount(op: IDirectorySubDirectoryOperation): void {
2075
1969
  if (op.type === "deleteSubDirectory") {
2076
1970
  this.incrementPendingSubDirCount(
2077
1971
  this.pendingDeleteSubDirectoriesTracker,
@@ -2122,7 +2016,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2122
2016
  * Submit a subdirectory operation again
2123
2017
  * @param op - The operation
2124
2018
  * @param localOpMetadata - metadata submitted with the op originally
2125
- * @internal
2126
2019
  */
2127
2020
  public resubmitSubDirectoryMessage(
2128
2021
  op: IDirectorySubDirectoryOperation,
@@ -2166,7 +2059,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2166
2059
  * Get the storage of this subdirectory in a serializable format, to be used in snapshotting.
2167
2060
  * @param serializer - The serializer to use to serialize handles in its values.
2168
2061
  * @returns The JSONable string representing the storage of this subdirectory
2169
- * @internal
2170
2062
  */
2171
2063
  public *getSerializedStorage(
2172
2064
  serializer: IFluidSerializer,
@@ -2179,11 +2071,11 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2179
2071
  }
2180
2072
  }
2181
2073
 
2182
- public getSerializableCreateInfo() {
2074
+ public getSerializableCreateInfo(): ICreateInfo {
2183
2075
  this.throwIfDisposed();
2184
2076
  const createInfo: ICreateInfo = {
2185
2077
  csn: this.seqData.seq,
2186
- ccIds: Array.from(this.clientIds),
2078
+ ccIds: [...this.clientIds],
2187
2079
  };
2188
2080
  return createInfo;
2189
2081
  }
@@ -2192,7 +2084,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2192
2084
  * Populate a key value in this subdirectory's storage, to be used when loading from snapshot.
2193
2085
  * @param key - The key to populate
2194
2086
  * @param localValue - The local value to populate into it
2195
- * @internal
2196
2087
  */
2197
2088
  public populateStorage(key: string, localValue: ILocalValue): void {
2198
2089
  this.throwIfDisposed();
@@ -2203,7 +2094,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2203
2094
  * Populate a subdirectory into this subdirectory, to be used when loading from snapshot.
2204
2095
  * @param subdirName - The name of the subdirectory to add
2205
2096
  * @param newSubDir - The new subdirectory to add
2206
- * @internal
2207
2097
  */
2208
2098
  public populateSubDirectory(subdirName: string, newSubDir: SubDirectory): void {
2209
2099
  this.throwIfDisposed();
@@ -2215,7 +2105,6 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2215
2105
  * value so op handlers can be retrieved
2216
2106
  * @param key - The key to retrieve from
2217
2107
  * @returns The local value
2218
- * @internal
2219
2108
  */
2220
2109
  public getLocalValue<T extends ILocalValue = ILocalValue>(key: string): T {
2221
2110
  this.throwIfDisposed();
@@ -2268,46 +2157,62 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2268
2157
  throw new Error("Rollback op does match last clear");
2269
2158
  }
2270
2159
  } else if ((op.type === "delete" || op.type === "set") && localOpMetadata.type === "edit") {
2160
+ const key: unknown = op.key;
2161
+ assert(key !== undefined, 0x8ad /* "key" property is missing from edit operation. */);
2162
+ assert(
2163
+ typeof key === "string",
2164
+ 0x8ae /* "key" property in edit operation is misconfigured. Expected a string. */,
2165
+ );
2166
+
2271
2167
  if (localOpMetadata.previousValue === undefined) {
2272
- this.deleteCore(op.key as string, true);
2168
+ this.deleteCore(key, true);
2273
2169
  } else {
2274
- this.setCore(op.key as string, localOpMetadata.previousValue, true);
2170
+ this.setCore(key, localOpMetadata.previousValue, true);
2275
2171
  }
2276
2172
 
2277
- this.rollbackPendingMessageId(
2278
- this.pendingKeys,
2279
- op.key as string,
2280
- localOpMetadata.pendingMessageId,
2281
- );
2173
+ this.rollbackPendingMessageId(this.pendingKeys, key, localOpMetadata.pendingMessageId);
2282
2174
  } else if (op.type === "createSubDirectory" && localOpMetadata.type === "createSubDir") {
2283
- this.deleteSubDirectoryCore(op.subdirName as string, true);
2284
-
2285
- this.decrementPendingSubDirCount(
2286
- this.pendingCreateSubDirectoriesTracker,
2287
- op.subdirName as string,
2175
+ const subdirName: unknown = op.subdirName;
2176
+ assert(
2177
+ subdirName !== undefined,
2178
+ 0x8af /* "subdirName" property is missing from "createSubDirectory" operation. */,
2288
2179
  );
2180
+ assert(
2181
+ typeof subdirName === "string",
2182
+ 0x8b0 /* "subdirName" property in "createSubDirectory" operation is misconfigured. Expected a string. */,
2183
+ );
2184
+
2185
+ this.deleteSubDirectoryCore(subdirName, true);
2186
+ this.decrementPendingSubDirCount(this.pendingCreateSubDirectoriesTracker, subdirName);
2289
2187
  } else if (op.type === "deleteSubDirectory" && localOpMetadata.type === "deleteSubDir") {
2188
+ const subdirName: unknown = op.subdirName;
2189
+ assert(
2190
+ subdirName !== undefined,
2191
+ 0x8b1 /* "subdirName" property is missing from "deleteSubDirectory" operation. */,
2192
+ );
2193
+ assert(
2194
+ typeof subdirName === "string",
2195
+ 0x8b2 /* "subdirName" property in "deleteSubDirectory" operation is misconfigured. Expected a string. */,
2196
+ );
2197
+
2290
2198
  if (localOpMetadata.subDirectory !== undefined) {
2291
2199
  this.undeleteSubDirectoryTree(localOpMetadata.subDirectory);
2292
2200
  // don't need to register events because deleting never unregistered
2293
- this._subdirectories.set(op.subdirName as string, localOpMetadata.subDirectory);
2201
+ this._subdirectories.set(subdirName, localOpMetadata.subDirectory);
2294
2202
  // Restore the record in creation tracker
2295
2203
  if (isAcknowledgedOrDetached(localOpMetadata.subDirectory.seqData)) {
2296
- this.ackedCreationSeqTracker.set(op.subdirName, {
2204
+ this.ackedCreationSeqTracker.set(subdirName, {
2297
2205
  ...localOpMetadata.subDirectory.seqData,
2298
2206
  });
2299
2207
  } else {
2300
- this.localCreationSeqTracker.set(op.subdirName, {
2208
+ this.localCreationSeqTracker.set(subdirName, {
2301
2209
  ...localOpMetadata.subDirectory.seqData,
2302
2210
  });
2303
2211
  }
2304
- this.emit("subDirectoryCreated", op.subdirName, true, this);
2212
+ this.emit("subDirectoryCreated", subdirName, true, this);
2305
2213
  }
2306
2214
 
2307
- this.decrementPendingSubDirCount(
2308
- this.pendingDeleteSubDirectoriesTracker,
2309
- op.subDirName as string,
2310
- );
2215
+ this.decrementPendingSubDirCount(this.pendingDeleteSubDirectoriesTracker, subdirName);
2311
2216
  } else {
2312
2217
  throw new Error("Unsupported op for rollback");
2313
2218
  }
@@ -2397,7 +2302,7 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2397
2302
  * can be deleted and created again, then this finds if the message is for current instance of directory or not.
2398
2303
  * @param msg - message for the directory
2399
2304
  */
2400
- private isMessageForCurrentInstanceOfSubDirectory(msg: ISequencedDocumentMessage) {
2305
+ private isMessageForCurrentInstanceOfSubDirectory(msg: ISequencedDocumentMessage): boolean {
2401
2306
  // If the message is either from the creator of directory or this directory was created when
2402
2307
  // container was detached or in case this directory is already live(known to other clients)
2403
2308
  // and the op was created after the directory was created then apply this op.
@@ -2625,10 +2530,10 @@ class SubDirectory extends TypedEventEmitter<IDirectoryEvents> implements IDirec
2625
2530
  * Store the sequnce numbers of newly created subdirectory to the proper creation tracker, based
2626
2531
  * on whether the creation behavior has been ack'd or not
2627
2532
  */
2628
- if (!isAcknowledgedOrDetached(seqData)) {
2629
- this.localCreationSeqTracker.set(subdirName, { ...seqData });
2630
- } else {
2533
+ if (isAcknowledgedOrDetached(seqData)) {
2631
2534
  this.ackedCreationSeqTracker.set(subdirName, { ...seqData });
2535
+ } else {
2536
+ this.localCreationSeqTracker.set(subdirName, { ...seqData });
2632
2537
  }
2633
2538
 
2634
2539
  this.registerEventsOnSubDirectory(subDir, subdirName);