@fluidframework/container-runtime 2.43.0-343119 → 2.50.0-345060

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 (94) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/container-runtime.test-files.tar +0 -0
  3. package/dist/channelCollection.d.ts +1 -1
  4. package/dist/channelCollection.d.ts.map +1 -1
  5. package/dist/channelCollection.js +3 -1
  6. package/dist/channelCollection.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +1 -1
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +18 -17
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +0 -2
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js.map +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +7 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/opLifecycle/batchManager.d.ts +1 -0
  19. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  20. package/dist/opLifecycle/batchManager.js +3 -2
  21. package/dist/opLifecycle/batchManager.js.map +1 -1
  22. package/dist/opLifecycle/index.d.ts +1 -1
  23. package/dist/opLifecycle/index.d.ts.map +1 -1
  24. package/dist/opLifecycle/index.js +2 -1
  25. package/dist/opLifecycle/index.js.map +1 -1
  26. package/dist/opLifecycle/opGroupingManager.d.ts +1 -1
  27. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  28. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  29. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  30. package/dist/opLifecycle/outbox.js +2 -5
  31. package/dist/opLifecycle/outbox.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.js +1 -1
  34. package/dist/packageVersion.js.map +1 -1
  35. package/dist/pendingStateManager.d.ts +7 -6
  36. package/dist/pendingStateManager.d.ts.map +1 -1
  37. package/dist/pendingStateManager.js +20 -15
  38. package/dist/pendingStateManager.js.map +1 -1
  39. package/dist/runtimeLayerCompatState.d.ts +3 -3
  40. package/dist/runtimeLayerCompatState.d.ts.map +1 -1
  41. package/dist/runtimeLayerCompatState.js +10 -10
  42. package/dist/runtimeLayerCompatState.js.map +1 -1
  43. package/lib/channelCollection.d.ts +1 -1
  44. package/lib/channelCollection.d.ts.map +1 -1
  45. package/lib/channelCollection.js +3 -1
  46. package/lib/channelCollection.js.map +1 -1
  47. package/lib/containerRuntime.d.ts +1 -1
  48. package/lib/containerRuntime.d.ts.map +1 -1
  49. package/lib/containerRuntime.js +18 -17
  50. package/lib/containerRuntime.js.map +1 -1
  51. package/lib/dataStoreContext.d.ts +0 -2
  52. package/lib/dataStoreContext.d.ts.map +1 -1
  53. package/lib/dataStoreContext.js.map +1 -1
  54. package/lib/index.d.ts +1 -0
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.js +1 -0
  57. package/lib/index.js.map +1 -1
  58. package/lib/opLifecycle/batchManager.d.ts +1 -0
  59. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  60. package/lib/opLifecycle/batchManager.js +1 -1
  61. package/lib/opLifecycle/batchManager.js.map +1 -1
  62. package/lib/opLifecycle/index.d.ts +1 -1
  63. package/lib/opLifecycle/index.d.ts.map +1 -1
  64. package/lib/opLifecycle/index.js +1 -1
  65. package/lib/opLifecycle/index.js.map +1 -1
  66. package/lib/opLifecycle/opGroupingManager.d.ts +1 -1
  67. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  68. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  69. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  70. package/lib/opLifecycle/outbox.js +2 -5
  71. package/lib/opLifecycle/outbox.js.map +1 -1
  72. package/lib/packageVersion.d.ts +1 -1
  73. package/lib/packageVersion.js +1 -1
  74. package/lib/packageVersion.js.map +1 -1
  75. package/lib/pendingStateManager.d.ts +7 -6
  76. package/lib/pendingStateManager.d.ts.map +1 -1
  77. package/lib/pendingStateManager.js +20 -15
  78. package/lib/pendingStateManager.js.map +1 -1
  79. package/lib/runtimeLayerCompatState.d.ts +3 -3
  80. package/lib/runtimeLayerCompatState.d.ts.map +1 -1
  81. package/lib/runtimeLayerCompatState.js +9 -9
  82. package/lib/runtimeLayerCompatState.js.map +1 -1
  83. package/package.json +20 -20
  84. package/src/channelCollection.ts +3 -1
  85. package/src/containerRuntime.ts +24 -28
  86. package/src/dataStoreContext.ts +0 -2
  87. package/src/index.ts +7 -0
  88. package/src/opLifecycle/batchManager.ts +1 -1
  89. package/src/opLifecycle/index.ts +1 -0
  90. package/src/opLifecycle/opGroupingManager.ts +1 -1
  91. package/src/opLifecycle/outbox.ts +2 -5
  92. package/src/packageVersion.ts +1 -1
  93. package/src/pendingStateManager.ts +30 -22
  94. package/src/runtimeLayerCompatState.ts +10 -10
package/src/index.ts CHANGED
@@ -112,3 +112,10 @@ export {
112
112
  DefaultSummaryConfiguration,
113
113
  } from "./summary/index.js";
114
114
  export { IChunkedOp, unpackRuntimeMessage } from "./opLifecycle/index.js";
115
+ export {
116
+ runtimeCoreCompatDetails,
117
+ runtimeCompatDetailsForLoader,
118
+ runtimeCompatDetailsForDataStore,
119
+ loaderSupportRequirementsForRuntime,
120
+ dataStoreSupportRequirementsForRuntime,
121
+ } from "./runtimeLayerCompatState.js";
@@ -178,7 +178,7 @@ export class BatchManager {
178
178
  }
179
179
  }
180
180
 
181
- const addBatchMetadata = (batch: LocalBatch, batchId?: BatchId): LocalBatch => {
181
+ export const addBatchMetadata = (batch: LocalBatch, batchId?: BatchId): LocalBatch => {
182
182
  const batchEnd = batch.messages.length - 1;
183
183
 
184
184
  const firstMsg = batch.messages[0];
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  export {
7
+ addBatchMetadata,
7
8
  BatchId,
8
9
  BatchManager,
9
10
  BatchSequenceNumbers,
@@ -53,7 +53,7 @@ export interface OpGroupingManagerConfig {
53
53
  */
54
54
  export interface EmptyGroupedBatch {
55
55
  type: typeof OpGroupingManager.groupedBatchOp;
56
- contents: readonly unknown[];
56
+ contents: readonly [];
57
57
  }
58
58
 
59
59
  export class OpGroupingManager {
@@ -455,10 +455,7 @@ export class Outbox {
455
455
  if (
456
456
  batchManager.options.canRebase &&
457
457
  rawBatch.hasReentrantOps === true &&
458
- // NOTE: This is too restrictive. We should rebase for any reentrant op, not just if it's going to be a grouped batch
459
- // However there is some test that is depending on this behavior so we haven't removed these conditions yet. See AB#33427
460
- groupingEnabled &&
461
- rawBatch.messages.length > 1
458
+ groupingEnabled
462
459
  ) {
463
460
  assert(!this.rebasing, 0x6fa /* A rebased batch should never have reentrant ops */);
464
461
  // If a batch contains reentrant ops (ops created as a result from processing another op)
@@ -466,7 +463,7 @@ export class Outbox {
466
463
  // and eventual consistency at the DDS level.
467
464
  // Note: Since this is happening in the same turn the ops were originally created with,
468
465
  // and they haven't gone to PendingStateManager yet, we can just let them respect
469
- // ContainerRuntime.inStagingMode
466
+ // ContainerRuntime.inStagingMode. So we do not plumb local 'staged' variable through here.
470
467
  this.rebase(rawBatch, batchManager);
471
468
  return;
472
469
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.43.0-343119";
9
+ export const pkgVersion = "2.50.0-345060";
@@ -48,9 +48,9 @@ export interface IPendingMessage {
48
48
  content: string;
49
49
  /**
50
50
  * The original runtime op that was submitted to the ContainerRuntime
51
- * Unless this pending message came from stashed content, in which case this was roundtripped through string
51
+ * Unless this pending message came from stashed content, in which case this is undefined at first and then deserialized from the contents string
52
52
  */
53
- runtimeOp?: LocalContainerRuntimeMessage | EmptyGroupedBatch | undefined; // Undefined for initial messages before parsing
53
+ runtimeOp: LocalContainerRuntimeMessage | EmptyGroupedBatch | undefined; // Undefined for initial messages before parsing
54
54
  /**
55
55
  * Local Op Metadata that was passed to the ContainerRuntime when the op was submitted.
56
56
  * This contains state needed when processing the ack, or to resubmit or rollback the op.
@@ -234,10 +234,11 @@ function toSerializableForm(
234
234
 
235
235
  interface ReplayPendingStateOptions {
236
236
  /**
237
- * If true, only replay staged batches. This is used when we are exiting staging mode and want to rebase and submit the staged batches.
237
+ * If true, only replay staged batches, clearing the "staged" flag.
238
+ * This is used when we are exiting staging mode and want to rebase and submit the staged batches without resubmitting pre-staged messages.
238
239
  * Default: false
239
240
  */
240
- onlyStagedBatches: boolean;
241
+ committingStagedBatches: boolean;
241
242
  /**
242
243
  * @param squash - If true, edits should be squashed when resubmitting.
243
244
  * Default: false
@@ -246,7 +247,7 @@ interface ReplayPendingStateOptions {
246
247
  }
247
248
 
248
249
  const defaultReplayPendingStatesOptions: ReplayPendingStateOptions = {
249
- onlyStagedBatches: false,
250
+ committingStagedBatches: false,
250
251
  squash: false,
251
252
  };
252
253
 
@@ -300,8 +301,8 @@ export class PendingStateManager implements IDisposable {
300
301
  for (let i = 0; i < this.pendingMessages.length; i++) {
301
302
  const element = this.pendingMessages.get(i);
302
303
  if (
303
- element?.runtimeOp !== undefined &&
304
- isNotEmptyGroupedBatch(element) &&
304
+ element !== undefined &&
305
+ hasTypicalRuntimeOp(element) && // Empty batches don't count towards user changes
305
306
  isContainerMessageDirtyable(element.runtimeOp)
306
307
  ) {
307
308
  return true;
@@ -742,16 +743,18 @@ export class PendingStateManager implements IDisposable {
742
743
  * states in its queue. This includes triggering resubmission of unacked ops.
743
744
  * ! Note: successfully resubmitting an op that has been successfully sequenced is not possible due to checks in the ConnectionStateHandler (Loader layer)
744
745
  */
745
- public replayPendingStates(optionsParam?: ReplayPendingStateOptions): void {
746
- const options = { ...defaultReplayPendingStatesOptions, ...optionsParam };
747
- const { onlyStagedBatches, squash } = options;
746
+ public replayPendingStates(options?: ReplayPendingStateOptions): void {
747
+ const { committingStagedBatches, squash } = {
748
+ ...defaultReplayPendingStatesOptions,
749
+ ...options,
750
+ };
748
751
  assert(
749
- this.stateHandler.connected() || onlyStagedBatches === true,
752
+ this.stateHandler.connected() || committingStagedBatches === true,
750
753
  0x172 /* "The connection state is not consistent with the runtime" */,
751
754
  );
752
755
 
753
756
  // Staged batches have not yet been submitted so check doesn't apply
754
- if (!onlyStagedBatches) {
757
+ if (!committingStagedBatches) {
755
758
  // This assert suggests we are about to send same ops twice, which will result in data loss.
756
759
  assert(
757
760
  this.clientIdFromLastReplay !== this.stateHandler.clientId(),
@@ -778,8 +781,8 @@ export class PendingStateManager implements IDisposable {
778
781
  let pendingMessage = this.pendingMessages.shift()!;
779
782
  remainingPendingMessagesCount--;
780
783
 
781
- // Re-queue pre-staging messages if we are only processing staged batches
782
- if (onlyStagedBatches) {
784
+ // Re-queue pre-staging messages - we are only to replay staged batches
785
+ if (committingStagedBatches) {
783
786
  if (!pendingMessage.batchInfo.staged) {
784
787
  assert(!seenStagedBatch, 0xb86 /* Staged batch was followed by non-staged batch */);
785
788
  this.pendingMessages.push(pendingMessage);
@@ -807,8 +810,8 @@ export class PendingStateManager implements IDisposable {
807
810
  }
808
811
 
809
812
  assert(
810
- pendingMessage.runtimeOp !== undefined && isNotEmptyGroupedBatch(pendingMessage),
811
- 0xb87 /* viableOp is only undefined for empty batches */,
813
+ hasTypicalRuntimeOp(pendingMessage),
814
+ 0xb87 /* runtimeOp is only undefined for empty batches */,
812
815
  );
813
816
 
814
817
  /**
@@ -843,8 +846,8 @@ export class PendingStateManager implements IDisposable {
843
846
  // check is >= because batch end may be last pending message
844
847
  while (remainingPendingMessagesCount >= 0) {
845
848
  assert(
846
- pendingMessage.runtimeOp !== undefined && isNotEmptyGroupedBatch(pendingMessage),
847
- 0xb88 /* viableOp is only undefined for empty batches */,
849
+ hasTypicalRuntimeOp(pendingMessage),
850
+ 0xb88 /* runtimeOp is only undefined for empty batches */,
848
851
  );
849
852
  batch.push({
850
853
  runtimeOp: pendingMessage.runtimeOp,
@@ -890,15 +893,17 @@ export class PendingStateManager implements IDisposable {
890
893
  */
891
894
  public popStagedBatches(
892
895
  callback: (
893
- stagedMessage: IPendingMessage & { runtimeOp?: LocalContainerRuntimeMessage }, // exclude empty grouped batches
896
+ // callback will only be given staged messages with a valid runtime op (i.e. not empty batch and not an initial message with only serialized content)
897
+ stagedMessage: IPendingMessage & { runtimeOp: LocalContainerRuntimeMessage },
894
898
  ) => void,
895
899
  ): void {
896
900
  while (!this.pendingMessages.isEmpty()) {
897
901
  const stagedMessage = this.pendingMessages.peekBack();
898
902
  if (stagedMessage?.batchInfo.staged === true) {
899
- if (isNotEmptyGroupedBatch(stagedMessage)) {
903
+ this.pendingMessages.pop();
904
+
905
+ if (hasTypicalRuntimeOp(stagedMessage)) {
900
906
  callback(stagedMessage);
901
- this.pendingMessages.pop();
902
907
  }
903
908
  } else {
904
909
  break; // no more staged messages
@@ -924,7 +929,10 @@ function patchbatchInfo(
924
929
  }
925
930
  }
926
931
 
927
- function isNotEmptyGroupedBatch(
932
+ /**
933
+ * This filters out messages that are not "typical" runtime ops, i.e. empty batches or initial messages (which only have serialized content).
934
+ */
935
+ function hasTypicalRuntimeOp(
928
936
  message: IPendingMessage,
929
937
  ): message is IPendingMessage & { runtimeOp: LocalContainerRuntimeMessage } {
930
938
  return message.runtimeOp !== undefined && message.runtimeOp.type !== "groupedBatch";
@@ -48,7 +48,7 @@ export const runtimeCompatDetailsForLoader: ILayerCompatDetails = {
48
48
  * The requirements that the Loader layer must meet to be compatible with this Runtime.
49
49
  * @internal
50
50
  */
51
- export const loaderSupportRequirements: ILayerCompatSupportRequirements = {
51
+ export const loaderSupportRequirementsForRuntime: ILayerCompatSupportRequirements = {
52
52
  /**
53
53
  * Minimum generation that Loader must be at to be compatible with Runtime. Note that 0 is used here so
54
54
  * that Loader layers before the introduction of the layer compatibility enforcement are compatible.
@@ -76,7 +76,7 @@ export const runtimeCompatDetailsForDataStore: ILayerCompatDetails = {
76
76
  * The requirements that the DataStore layer must meet to be compatible with this Runtime.
77
77
  * @internal
78
78
  */
79
- export const dataStoreSupportRequirements: ILayerCompatSupportRequirements = {
79
+ export const dataStoreSupportRequirementsForRuntime: ILayerCompatSupportRequirements = {
80
80
  /**
81
81
  * Minimum generation that DataStore must be at to be compatible with Runtime. Note that 0 is used here so
82
82
  * that DataStore layers before the introduction of the layer compatibility enforcement are compatible.
@@ -93,21 +93,21 @@ export const dataStoreSupportRequirements: ILayerCompatSupportRequirements = {
93
93
  * @internal
94
94
  */
95
95
  export function validateLoaderCompatibility(
96
- maybeloaderCompatDetailsForRuntime: ILayerCompatDetails | undefined,
96
+ maybeLoaderCompatDetailsForRuntime: ILayerCompatDetails | undefined,
97
97
  disposeFn: (error?: ICriticalContainerError) => void,
98
98
  ): void {
99
99
  const layerCheckResult = checkLayerCompatibility(
100
- loaderSupportRequirements,
101
- maybeloaderCompatDetailsForRuntime,
100
+ loaderSupportRequirementsForRuntime,
101
+ maybeLoaderCompatDetailsForRuntime,
102
102
  );
103
103
  if (!layerCheckResult.isCompatible) {
104
104
  const error = new UsageError("Runtime is not compatible with Loader", {
105
105
  errorDetails: JSON.stringify({
106
106
  runtimeVersion: runtimeCoreCompatDetails.pkgVersion,
107
- loaderVersion: maybeloaderCompatDetailsForRuntime?.pkgVersion,
107
+ loaderVersion: maybeLoaderCompatDetailsForRuntime?.pkgVersion,
108
108
  runtimeGeneration: runtimeCoreCompatDetails.generation,
109
- loaderGeneration: maybeloaderCompatDetailsForRuntime?.generation,
110
- minSupportedGeneration: loaderSupportRequirements.minSupportedGeneration,
109
+ loaderGeneration: maybeLoaderCompatDetailsForRuntime?.generation,
110
+ minSupportedGeneration: loaderSupportRequirementsForRuntime.minSupportedGeneration,
111
111
  isGenerationCompatible: layerCheckResult.isGenerationCompatible,
112
112
  unsupportedFeatures: layerCheckResult.unsupportedFeatures,
113
113
  }),
@@ -126,7 +126,7 @@ export function validateDatastoreCompatibility(
126
126
  disposeFn: () => void,
127
127
  ): void {
128
128
  const layerCheckResult = checkLayerCompatibility(
129
- dataStoreSupportRequirements,
129
+ dataStoreSupportRequirementsForRuntime,
130
130
  maybeDataStoreCompatDetails,
131
131
  );
132
132
  if (!layerCheckResult.isCompatible) {
@@ -136,7 +136,7 @@ export function validateDatastoreCompatibility(
136
136
  dataStoreVersion: maybeDataStoreCompatDetails?.pkgVersion,
137
137
  runtimeGeneration: runtimeCoreCompatDetails.generation,
138
138
  dataStoreGeneration: maybeDataStoreCompatDetails?.generation,
139
- minSupportedGeneration: dataStoreSupportRequirements.minSupportedGeneration,
139
+ minSupportedGeneration: dataStoreSupportRequirementsForRuntime.minSupportedGeneration,
140
140
  isGenerationCompatible: layerCheckResult.isGenerationCompatible,
141
141
  unsupportedFeatures: layerCheckResult.unsupportedFeatures,
142
142
  }),