@fluidframework/container-runtime 2.70.0-361248 → 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/container-runtime.test-files.tar +0 -0
  3. package/dist/blobManager/blobManager.d.ts.map +1 -1
  4. package/dist/blobManager/blobManager.js +0 -1
  5. package/dist/blobManager/blobManager.js.map +1 -1
  6. package/dist/containerRuntime.d.ts +25 -6
  7. package/dist/containerRuntime.d.ts.map +1 -1
  8. package/dist/containerRuntime.js +92 -22
  9. package/dist/containerRuntime.js.map +1 -1
  10. package/dist/dataStore.d.ts +1 -1
  11. package/dist/dataStore.d.ts.map +1 -1
  12. package/dist/dataStore.js +7 -8
  13. package/dist/dataStore.js.map +1 -1
  14. package/dist/dataStoreContext.d.ts.map +1 -1
  15. package/dist/dataStoreContext.js +1 -1
  16. package/dist/dataStoreContext.js.map +1 -1
  17. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  18. package/dist/opLifecycle/outbox.js +7 -0
  19. package/dist/opLifecycle/outbox.js.map +1 -1
  20. package/dist/packageVersion.d.ts +1 -1
  21. package/dist/packageVersion.d.ts.map +1 -1
  22. package/dist/packageVersion.js +1 -1
  23. package/dist/packageVersion.js.map +1 -1
  24. package/dist/runtimeLayerCompatState.d.ts +4 -3
  25. package/dist/runtimeLayerCompatState.d.ts.map +1 -1
  26. package/dist/runtimeLayerCompatState.js +4 -35
  27. package/dist/runtimeLayerCompatState.js.map +1 -1
  28. package/dist/storageServiceWithAttachBlobs.d.ts +0 -36
  29. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -1
  30. package/dist/storageServiceWithAttachBlobs.js +0 -55
  31. package/dist/storageServiceWithAttachBlobs.js.map +1 -1
  32. package/lib/blobManager/blobManager.d.ts.map +1 -1
  33. package/lib/blobManager/blobManager.js +0 -1
  34. package/lib/blobManager/blobManager.js.map +1 -1
  35. package/lib/containerRuntime.d.ts +25 -6
  36. package/lib/containerRuntime.d.ts.map +1 -1
  37. package/lib/containerRuntime.js +92 -22
  38. package/lib/containerRuntime.js.map +1 -1
  39. package/lib/dataStore.d.ts +1 -1
  40. package/lib/dataStore.d.ts.map +1 -1
  41. package/lib/dataStore.js +2 -3
  42. package/lib/dataStore.js.map +1 -1
  43. package/lib/dataStoreContext.d.ts.map +1 -1
  44. package/lib/dataStoreContext.js +1 -1
  45. package/lib/dataStoreContext.js.map +1 -1
  46. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  47. package/lib/opLifecycle/outbox.js +7 -0
  48. package/lib/opLifecycle/outbox.js.map +1 -1
  49. package/lib/packageVersion.d.ts +1 -1
  50. package/lib/packageVersion.d.ts.map +1 -1
  51. package/lib/packageVersion.js +1 -1
  52. package/lib/packageVersion.js.map +1 -1
  53. package/lib/runtimeLayerCompatState.d.ts +4 -3
  54. package/lib/runtimeLayerCompatState.d.ts.map +1 -1
  55. package/lib/runtimeLayerCompatState.js +5 -36
  56. package/lib/runtimeLayerCompatState.js.map +1 -1
  57. package/lib/storageServiceWithAttachBlobs.d.ts +0 -36
  58. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -1
  59. package/lib/storageServiceWithAttachBlobs.js +0 -55
  60. package/lib/storageServiceWithAttachBlobs.js.map +1 -1
  61. package/package.json +20 -17
  62. package/src/blobManager/blobManager.ts +0 -1
  63. package/src/containerRuntime.ts +144 -37
  64. package/src/dataStore.ts +6 -9
  65. package/src/dataStoreContext.ts +1 -0
  66. package/src/opLifecycle/outbox.ts +10 -0
  67. package/src/packageVersion.ts +1 -1
  68. package/src/runtimeLayerCompatState.ts +23 -39
  69. package/src/storageServiceWithAttachBlobs.ts +0 -92
@@ -23,6 +23,7 @@ import type {
23
23
  IDeltaManagerFull,
24
24
  ILoader,
25
25
  IContainerStorageService,
26
+ ConnectionStatus,
26
27
  } from "@fluidframework/container-definitions/internal";
27
28
  import {
28
29
  ConnectionState,
@@ -120,10 +121,8 @@ import type {
120
121
  IInboundSignalMessage,
121
122
  IRuntimeMessagesContent,
122
123
  ISummarizerNodeWithGC,
123
- // eslint-disable-next-line import/no-deprecated
124
- StageControlsExperimental,
125
- // eslint-disable-next-line import/no-deprecated
126
- IContainerRuntimeBaseExperimental,
124
+ StageControlsInternal,
125
+ IContainerRuntimeBaseInternal,
127
126
  IFluidParentContext,
128
127
  MinimumVersionForCollab,
129
128
  } from "@fluidframework/runtime-definitions/internal";
@@ -817,8 +816,7 @@ export class ContainerRuntime
817
816
  extends TypedEventEmitter<IContainerRuntimeEvents>
818
817
  implements
819
818
  IContainerRuntimeInternal,
820
- // eslint-disable-next-line import/no-deprecated
821
- IContainerRuntimeBaseExperimental,
819
+ IContainerRuntimeBaseInternal,
822
820
  // eslint-disable-next-line import/no-deprecated
823
821
  IContainerRuntimeWithResolveHandle_Deprecated,
824
822
  IRuntime,
@@ -1215,6 +1213,8 @@ export class ContainerRuntime
1215
1213
  recentBatchInfo,
1216
1214
  );
1217
1215
 
1216
+ runtime.sharePendingBlobs();
1217
+
1218
1218
  // Initialize the base state of the runtime before it's returned.
1219
1219
  await runtime.initializeBaseState(context.loader);
1220
1220
 
@@ -1568,6 +1568,7 @@ export class ContainerRuntime
1568
1568
  deltaManager,
1569
1569
  quorum,
1570
1570
  audience,
1571
+ signalAudience,
1571
1572
  pendingLocalState,
1572
1573
  supportedFeatures,
1573
1574
  snapshotWithContents,
@@ -1581,13 +1582,6 @@ export class ContainerRuntime
1581
1582
 
1582
1583
  this.isSnapshotInstanceOfISnapshot = snapshotWithContents !== undefined;
1583
1584
 
1584
- // Validate that the Loader is compatible with this Runtime.
1585
- const maybeLoaderCompatDetailsForRuntime = context as FluidObject<ILayerCompatDetails>;
1586
- validateLoaderCompatibility(
1587
- maybeLoaderCompatDetailsForRuntime.ILayerCompatDetails,
1588
- this.disposeFn,
1589
- );
1590
-
1591
1585
  this.mc = createChildMonitoringContext({
1592
1586
  logger: this.baseLogger,
1593
1587
  namespace: "ContainerRuntime",
@@ -1598,6 +1592,14 @@ export class ContainerRuntime
1598
1592
  },
1599
1593
  });
1600
1594
 
1595
+ // Validate that the Loader is compatible with this Runtime.
1596
+ const maybeLoaderCompatDetailsForRuntime = context as FluidObject<ILayerCompatDetails>;
1597
+ validateLoaderCompatibility(
1598
+ maybeLoaderCompatDetailsForRuntime.ILayerCompatDetails,
1599
+ this.disposeFn,
1600
+ this.mc.logger,
1601
+ );
1602
+
1601
1603
  // If we support multiple algorithms in the future, then we would need to manage it here carefully.
1602
1604
  // We can use runtimeOptions.compressionOptions.compressionAlgorithm, but only if it's in the schema list!
1603
1605
  // If it's not in the list, then we will need to either use no compression, or fallback to some other (supported by format)
@@ -1718,10 +1720,11 @@ export class ContainerRuntime
1718
1720
  this.messageAtLastSummary = lastMessageFromMetadata(metadata);
1719
1721
 
1720
1722
  // Note that we only need to pull the *initial* connected state from the context.
1721
- // Later updates come through calls to setConnectionState.
1723
+ // Later updates come through calls to setConnectionState/Status.
1722
1724
  this.canSendOps = connected;
1723
1725
  this.canSendSignals = this.getConnectionState
1724
- ? this.getConnectionState() === ConnectionState.Connected
1726
+ ? this.getConnectionState() === ConnectionState.Connected ||
1727
+ this.getConnectionState() === ConnectionState.CatchingUp
1725
1728
  : undefined;
1726
1729
 
1727
1730
  this.mc.logger.sendTelemetryEvent({
@@ -2037,6 +2040,8 @@ export class ContainerRuntime
2037
2040
  });
2038
2041
  }
2039
2042
 
2043
+ this.signalAudience = signalAudience;
2044
+
2040
2045
  const closeSummarizerDelayOverride = this.mc.config.getNumber(
2041
2046
  "Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
2042
2047
  );
@@ -2809,6 +2814,59 @@ export class ContainerRuntime
2809
2814
  this.channelCollection.notifyReadOnlyState(readonly);
2810
2815
 
2811
2816
  public setConnectionState(canSendOps: boolean, clientId?: string): void {
2817
+ this.setConnectionStateToConnectedOrDisconnected(canSendOps, clientId);
2818
+ }
2819
+
2820
+ public setConnectionStatus(status: ConnectionStatus): void {
2821
+ switch (status.connectionState) {
2822
+ case ConnectionState.Connected: {
2823
+ this.setConnectionStateToConnectedOrDisconnected(
2824
+ status.canSendOps,
2825
+ status.clientConnectionId,
2826
+ );
2827
+
2828
+ break;
2829
+ }
2830
+ case ConnectionState.Disconnected: {
2831
+ this.setConnectionStateToConnectedOrDisconnected(
2832
+ status.canSendOps,
2833
+ status.priorConnectedClientConnectionId,
2834
+ );
2835
+
2836
+ break;
2837
+ }
2838
+ case ConnectionState.CatchingUp: {
2839
+ assert(
2840
+ this.getConnectionState !== undefined &&
2841
+ this.getConnectionState() === ConnectionState.CatchingUp,
2842
+ 0xc8d /* connection state mismatch between getConnectionState and setConnectionStatus notification */,
2843
+ );
2844
+
2845
+ // Note: Historically when only `setConnectionState` of `IRuntime`
2846
+ // was supported, it was possible to be in `CatchingUp` state and
2847
+ // call through to `setConnectionStateCore` when there is a readonly
2848
+ // change - see `Container`'s `"deltaManager.on("readonly"`. There
2849
+ // would not be a transition of `canSendOps` in that case, but
2850
+ // `channelCollection` and `garbageCollector` would receive early
2851
+ // `setConnectionState` call AND `this` would `emit` "disconnected"
2852
+ // event.
2853
+
2854
+ this.emitServiceConnectionEvents(
2855
+ /* canSendOpsChanged */ this.canSendOps,
2856
+ /* canSendOps */ false,
2857
+ status.pendingClientConnectionId,
2858
+ );
2859
+
2860
+ break;
2861
+ }
2862
+ // No default
2863
+ }
2864
+ }
2865
+
2866
+ private setConnectionStateToConnectedOrDisconnected(
2867
+ canSendOps: boolean,
2868
+ clientId: string | undefined,
2869
+ ): void {
2812
2870
  // Validate we have consistent state
2813
2871
  const currentClientId = this._audience.getSelf()?.clientId;
2814
2872
  assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
@@ -2893,7 +2951,7 @@ export class ContainerRuntime
2893
2951
  * Emits service connection events based on connection state changes.
2894
2952
  *
2895
2953
  * @remarks
2896
- * "connectedToService" is emitted when container connection state transitions to 'Connected' regardless of connection mode.
2954
+ * "connectedToService" is emitted when container connection state transitions to 'CatchingUp' or 'Connected' regardless of connection mode.
2897
2955
  * "disconnectedFromService" excludes false "disconnected" events that happen when readonly client transitions to 'Connected'.
2898
2956
  */
2899
2957
  private emitServiceConnectionEvents(
@@ -2905,21 +2963,25 @@ export class ContainerRuntime
2905
2963
  return;
2906
2964
  }
2907
2965
 
2908
- const canSendSignals = this.getConnectionState() === ConnectionState.Connected;
2966
+ const connectionState = this.getConnectionState();
2967
+ const canSendSignals =
2968
+ connectionState === ConnectionState.Connected ||
2969
+ connectionState === ConnectionState.CatchingUp;
2909
2970
  const canSendSignalsChanged = this.canSendSignals !== canSendSignals;
2910
2971
  this.canSendSignals = canSendSignals;
2911
2972
  if (canSendSignalsChanged) {
2912
- // If canSendSignals changed, we either transitioned from Connected to Disconnected or CatchingUp to Connected
2973
+ // If canSendSignals changed, we either transitioned from CatchingUp or
2974
+ // Connected to Disconnected or EstablishingConnection to CatchingUp.
2913
2975
  if (canSendSignals) {
2914
- // Emit for CatchingUp to Connected transition
2976
+ // Emit for EstablishingConnection to CatchingUp or Connected transition
2915
2977
  this.emit("connectedToService", clientId, canSendOps);
2916
2978
  } else {
2917
- // Emit for Connected to Disconnected transition
2979
+ // Emit for CatchingUp or Connected to Disconnected transition
2918
2980
  this.emit("disconnectedFromService");
2919
2981
  }
2920
2982
  } else if (canSendOpsChanged) {
2921
- // If canSendSignals did not change but canSendOps did, then connection type has changed.
2922
- this.emit("connectionTypeChanged", canSendOps);
2983
+ // If canSendSignals did not change but canSendOps did, then operations possible has changed.
2984
+ this.emit("operabilityChanged", canSendOps);
2923
2985
  }
2924
2986
  }
2925
2987
 
@@ -3452,8 +3514,7 @@ export class ContainerRuntime
3452
3514
  */
3453
3515
  public orderSequentially<T>(callback: () => T): T {
3454
3516
  let checkpoint: IBatchCheckpoint | undefined;
3455
- // eslint-disable-next-line import/no-deprecated
3456
- let stageControls: StageControlsExperimental | undefined;
3517
+ let stageControls: StageControlsInternal | undefined;
3457
3518
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback") === true) {
3458
3519
  if (!this.batchRunner.running && !this.inStagingMode) {
3459
3520
  stageControls = this.enterStagingMode();
@@ -3517,8 +3578,7 @@ export class ContainerRuntime
3517
3578
  return result;
3518
3579
  }
3519
3580
 
3520
- // eslint-disable-next-line import/no-deprecated
3521
- private stageControls: StageControlsExperimental | undefined;
3581
+ private stageControls: StageControlsInternal | undefined;
3522
3582
 
3523
3583
  /**
3524
3584
  * If true, the ContainerRuntime is not submitting any new ops to the ordering service.
@@ -3533,10 +3593,9 @@ export class ContainerRuntime
3533
3593
  * Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service.
3534
3594
  * To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method.
3535
3595
  *
3536
- * @returns StageControlsExperimental - Controls for exiting Staging Mode.
3596
+ * @returns Controls for exiting Staging Mode.
3537
3597
  */
3538
- // eslint-disable-next-line import/no-deprecated
3539
- public enterStagingMode = (): StageControlsExperimental => {
3598
+ public enterStagingMode = (): StageControlsInternal => {
3540
3599
  if (this.stageControls !== undefined) {
3541
3600
  throw new UsageError("Already in staging mode");
3542
3601
  }
@@ -3569,8 +3628,7 @@ export class ContainerRuntime
3569
3628
  }
3570
3629
  };
3571
3630
 
3572
- // eslint-disable-next-line import/no-deprecated
3573
- const stageControls: StageControlsExperimental = {
3631
+ const stageControls: StageControlsInternal = {
3574
3632
  discardChanges: () =>
3575
3633
  exitStagingMode(() => {
3576
3634
  // Pop all staged batches from the PSM and roll them back in LIFO order
@@ -3677,6 +3735,14 @@ export class ContainerRuntime
3677
3735
  return this._audience;
3678
3736
  }
3679
3737
 
3738
+ /**
3739
+ * When defined, this {@link @fluidframework/container-definitions#IAudience}
3740
+ * maintains member list using signals only.
3741
+ * Thus "write" members may be known earlier than quorum and avoid noise from
3742
+ * un-summarized quorum history.
3743
+ */
3744
+ private readonly signalAudience?: IAudience;
3745
+
3680
3746
  /**
3681
3747
  * Returns true of container is dirty, i.e. there are some pending local changes that
3682
3748
  * either were not sent out to delta stream or were not yet acknowledged.
@@ -4548,7 +4614,6 @@ export class ContainerRuntime
4548
4614
  contents: any,
4549
4615
  localOpMetadata: unknown = undefined,
4550
4616
  ): void {
4551
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
4552
4617
  this.submit({ type, contents }, localOpMetadata);
4553
4618
  }
4554
4619
 
@@ -5133,6 +5198,43 @@ export class ContainerRuntime
5133
5198
  );
5134
5199
  }
5135
5200
 
5201
+ /**
5202
+ * ContainerRuntime knows about additional restrictions on when blob sharing can be resumed as compared
5203
+ * to BlobManager. In particular, it wants to avoid sharing blobs while in readonly state, and it also
5204
+ * wants to avoid sharing blobs before connection completes (otherwise it may cause the sharing to happen
5205
+ * before processing shared ops).
5206
+ *
5207
+ * This method can be called safely before those conditions are met. In the background, it will wait until
5208
+ * it is safe before initiating sharing. It will close the container on any error.
5209
+ */
5210
+ public sharePendingBlobs = (): void => {
5211
+ new Promise<void>((resolve) => {
5212
+ // eslint-disable-next-line unicorn/consistent-function-scoping
5213
+ const canStartSharing = (): boolean =>
5214
+ this.connected && this.deltaManager.readOnlyInfo.readonly !== true;
5215
+
5216
+ if (canStartSharing()) {
5217
+ resolve();
5218
+ return;
5219
+ }
5220
+
5221
+ const checkCanShare = (readonly: boolean): void => {
5222
+ if (canStartSharing()) {
5223
+ this.deltaManager.off("readonly", checkCanShare);
5224
+ this.off("connected", checkCanShare);
5225
+ resolve();
5226
+ }
5227
+ };
5228
+ this.deltaManager.on("readonly", checkCanShare);
5229
+ this.on("connected", checkCanShare);
5230
+ })
5231
+ .then(this.blobManager.sharePendingBlobs)
5232
+ // It may not be necessary to close the container on failures - this should just mean there's
5233
+ // a handle in the container that is stuck pending, which is a scenario that customers need to
5234
+ // handle anyway. Starting with this more aggressive/restrictive behavior to be cautious.
5235
+ .catch(this.closeFn);
5236
+ };
5237
+
5136
5238
  public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
5137
5239
  if (this._summarizer !== undefined) {
5138
5240
  return this._summarizer.summarizeOnDemand(options);
@@ -5169,8 +5271,8 @@ export class ContainerRuntime
5169
5271
  eventEmitter.emit("joined", { clientId, canWrite });
5170
5272
  });
5171
5273
  this.on("disconnectedFromService", () => eventEmitter.emit("disconnected"));
5172
- this.on("connectionTypeChanged", (canWrite: boolean) =>
5173
- eventEmitter.emit("connectionTypeChanged", canWrite),
5274
+ this.on("operabilityChanged", (canWrite: boolean) =>
5275
+ eventEmitter.emit("operabilityChanged", canWrite),
5174
5276
  );
5175
5277
  } else {
5176
5278
  this.on("connected", (clientId: string) => {
@@ -5185,7 +5287,11 @@ export class ContainerRuntime
5185
5287
  const getConnectionState = this.getConnectionState;
5186
5288
  if (getConnectionState) {
5187
5289
  const connectionState = getConnectionState();
5188
- if (connectionState === ConnectionState.Connected) {
5290
+ if (
5291
+ connectionState === ConnectionState.Connected ||
5292
+ connectionState === ConnectionState.CatchingUp
5293
+ ) {
5294
+ // Note: when CatchingUp, canSendOps will always be false.
5189
5295
  return this.canSendOps ? "joinedForWriting" : "joinedForReading";
5190
5296
  }
5191
5297
  } else if (this.canSendOps) {
@@ -5211,9 +5317,10 @@ export class ContainerRuntime
5211
5317
  ): T {
5212
5318
  let entry = this.extensions.get(id);
5213
5319
  if (entry === undefined) {
5320
+ const audience = this.signalAudience;
5214
5321
  const runtime = {
5215
5322
  getJoinedStatus: this.getJoinedStatus.bind(this),
5216
- getClientId: () => this.clientId,
5323
+ getClientId: audience ? () => audience.getSelf()?.clientId : () => this.clientId,
5217
5324
  events: this.lazyEventsForExtensions.value,
5218
5325
  logger: this.baseLogger,
5219
5326
  submitAddressedSignal: (
@@ -5223,7 +5330,7 @@ export class ContainerRuntime
5223
5330
  this.submitExtensionSignal(id, addressChain, message);
5224
5331
  },
5225
5332
  getQuorum: this.getQuorum.bind(this),
5226
- getAudience: this.getAudience.bind(this),
5333
+ getAudience: audience ? () => audience : this.getAudience.bind(this),
5227
5334
  supportedFeatures: this.ILayerCompatDetails.supportedFeatures,
5228
5335
  } satisfies ExtensionHost<TRuntimeProperties>;
5229
5336
  entry = new factory(runtime, ...useContext);
package/src/dataStore.ts CHANGED
@@ -7,12 +7,11 @@ import { AttachState } from "@fluidframework/container-definitions";
7
7
  import type { FluidObject } from "@fluidframework/core-interfaces";
8
8
  import type { IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
9
9
  import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
10
- import type {
11
- AliasResult,
12
- IDataStore,
13
- IFluidDataStoreChannel,
14
- // eslint-disable-next-line import/no-deprecated
15
- IContainerRuntimeBaseExperimental,
10
+ import {
11
+ type AliasResult,
12
+ type IDataStore,
13
+ type IFluidDataStoreChannel,
14
+ asLegacyAlpha,
16
15
  } from "@fluidframework/runtime-definitions/internal";
17
16
  import {
18
17
  type ITelemetryLoggerExt,
@@ -80,9 +79,7 @@ class DataStore implements IDataStore {
80
79
  if (alias.includes("/")) {
81
80
  throw new UsageError(`The alias cannot contain slashes: '${alias}'`);
82
81
  }
83
- // eslint-disable-next-line import/no-deprecated
84
- const runtime = this.parentContext.containerRuntime as IContainerRuntimeBaseExperimental;
85
- if (runtime.inStagingMode === true) {
82
+ if (asLegacyAlpha(this.parentContext.containerRuntime).inStagingMode === true) {
86
83
  throw new UsageError("Cannot set aliases while in staging mode");
87
84
  }
88
85
 
@@ -1004,6 +1004,7 @@ export abstract class FluidDataStoreContext
1004
1004
  validateDatastoreCompatibility(
1005
1005
  maybeDataStoreCompatDetails.ILayerCompatDetails,
1006
1006
  this.dispose.bind(this),
1007
+ this.mc.logger,
1007
1008
  );
1008
1009
 
1009
1010
  // And now mark the runtime active
@@ -365,6 +365,16 @@ export class Outbox {
365
365
  * @param resubmitInfo - Key information when flushing a resubmitted batch. Undefined means this is not resubmit.
366
366
  */
367
367
  public flush(resubmitInfo?: BatchResubmitInfo): void {
368
+ // We have nothing to flush if all batchManagers are empty, and we we're not needing to resubmit an empty batch placeholder
369
+ if (
370
+ this.idAllocationBatch.empty &&
371
+ this.blobAttachBatch.empty &&
372
+ this.mainBatch.empty &&
373
+ resubmitInfo?.batchId === undefined
374
+ ) {
375
+ return;
376
+ }
377
+
368
378
  assert(
369
379
  !this.isContextReentrant(),
370
380
  0xb7b /* Flushing must not happen while incoming changes are being processed */,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.70.0-361248";
9
+ export const pkgVersion = "2.70.0";
@@ -3,17 +3,19 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import {
7
- checkLayerCompatibility,
8
- type ILayerCompatDetails,
9
- type ILayerCompatSupportRequirements,
6
+ import type {
7
+ ILayerCompatDetails,
8
+ ILayerCompatSupportRequirements,
10
9
  } from "@fluid-internal/client-utils";
11
10
  import type { ICriticalContainerError } from "@fluidframework/container-definitions";
12
11
  import {
13
12
  encodeHandlesInContainerRuntime,
14
13
  notifiesReadOnlyState,
15
14
  } from "@fluidframework/runtime-definitions/internal";
16
- import { UsageError } from "@fluidframework/telemetry-utils/internal";
15
+ import {
16
+ validateLayerCompatibility,
17
+ type ITelemetryLoggerExt,
18
+ } from "@fluidframework/telemetry-utils/internal";
17
19
 
18
20
  import { pkgVersion } from "./packageVersion.js";
19
21
 
@@ -95,26 +97,17 @@ export const dataStoreSupportRequirementsForRuntime: ILayerCompatSupportRequirem
95
97
  export function validateLoaderCompatibility(
96
98
  maybeLoaderCompatDetailsForRuntime: ILayerCompatDetails | undefined,
97
99
  disposeFn: (error?: ICriticalContainerError) => void,
100
+ logger: ITelemetryLoggerExt,
98
101
  ): void {
99
- const layerCheckResult = checkLayerCompatibility(
102
+ validateLayerCompatibility(
103
+ "runtime",
104
+ "loader",
105
+ runtimeCompatDetailsForLoader,
100
106
  loaderSupportRequirementsForRuntime,
101
107
  maybeLoaderCompatDetailsForRuntime,
108
+ disposeFn,
109
+ logger,
102
110
  );
103
- if (!layerCheckResult.isCompatible) {
104
- const error = new UsageError("Runtime is not compatible with Loader", {
105
- errorDetails: JSON.stringify({
106
- runtimeVersion: runtimeCoreCompatDetails.pkgVersion,
107
- loaderVersion: maybeLoaderCompatDetailsForRuntime?.pkgVersion,
108
- runtimeGeneration: runtimeCoreCompatDetails.generation,
109
- loaderGeneration: maybeLoaderCompatDetailsForRuntime?.generation,
110
- minSupportedGeneration: loaderSupportRequirementsForRuntime.minSupportedGeneration,
111
- isGenerationCompatible: layerCheckResult.isGenerationCompatible,
112
- unsupportedFeatures: layerCheckResult.unsupportedFeatures,
113
- }),
114
- });
115
- disposeFn(error);
116
- throw error;
117
- }
118
111
  }
119
112
 
120
113
  /**
@@ -122,26 +115,17 @@ export function validateLoaderCompatibility(
122
115
  * @internal
123
116
  */
124
117
  export function validateDatastoreCompatibility(
125
- maybeDataStoreCompatDetails: ILayerCompatDetails | undefined,
118
+ maybeDataStoreCompatDetailsForRuntime: ILayerCompatDetails | undefined,
126
119
  disposeFn: () => void,
120
+ logger: ITelemetryLoggerExt,
127
121
  ): void {
128
- const layerCheckResult = checkLayerCompatibility(
122
+ validateLayerCompatibility(
123
+ "runtime",
124
+ "dataStore",
125
+ runtimeCompatDetailsForDataStore,
129
126
  dataStoreSupportRequirementsForRuntime,
130
- maybeDataStoreCompatDetails,
127
+ maybeDataStoreCompatDetailsForRuntime,
128
+ disposeFn,
129
+ logger,
131
130
  );
132
- if (!layerCheckResult.isCompatible) {
133
- const error = new UsageError("Runtime is not compatible with DataStore", {
134
- errorDetails: JSON.stringify({
135
- runtimeVersion: runtimeCoreCompatDetails.pkgVersion,
136
- dataStoreVersion: maybeDataStoreCompatDetails?.pkgVersion,
137
- runtimeGeneration: runtimeCoreCompatDetails.generation,
138
- dataStoreGeneration: maybeDataStoreCompatDetails?.generation,
139
- minSupportedGeneration: dataStoreSupportRequirementsForRuntime.minSupportedGeneration,
140
- isGenerationCompatible: layerCheckResult.isGenerationCompatible,
141
- unsupportedFeatures: layerCheckResult.unsupportedFeatures,
142
- }),
143
- });
144
- disposeFn();
145
- throw error;
146
- }
147
131
  }
@@ -3,20 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import type {
7
- FetchSource,
8
- ICreateBlobResponse,
9
- IDocumentStorageServicePolicies,
10
- ISnapshot,
11
- ISnapshotFetchOptions,
12
- ISnapshotTree,
13
- ISummaryContext,
14
- ISummaryHandle,
15
- ISummaryTree,
16
- IVersion,
17
- } from "@fluidframework/driver-definitions/internal";
18
6
  import type { IRuntimeStorageService } from "@fluidframework/runtime-definitions/internal";
19
- import { UsageError } from "@fluidframework/telemetry-utils/internal";
20
7
 
21
8
  /**
22
9
  * IRuntimeStorageService proxy which intercepts requests if they can be satisfied by the blobs received in the
@@ -28,14 +15,6 @@ export class StorageServiceWithAttachBlobs implements IRuntimeStorageService {
28
15
  private readonly attachBlobs: Map<string, ArrayBufferLike>,
29
16
  ) {}
30
17
 
31
- /**
32
- * {@link IRuntimeStorageService.policies}.
33
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
34
- */
35
- public get policies(): IDocumentStorageServicePolicies | undefined {
36
- return this.internalStorageService.policies;
37
- }
38
-
39
18
  public async readBlob(id: string): Promise<ArrayBufferLike> {
40
19
  const blob = this.attachBlobs.get(id);
41
20
  if (blob !== undefined) {
@@ -46,75 +25,4 @@ export class StorageServiceWithAttachBlobs implements IRuntimeStorageService {
46
25
  // IRuntimeStorageService to cache appropriately, no need to double-cache.
47
26
  return this.internalStorageService.readBlob(id);
48
27
  }
49
-
50
- /**
51
- * {@link IRuntimeStorageService.getSnapshotTree}.
52
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
53
- */
54
- public async getSnapshotTree(
55
- version?: IVersion,
56
- scenarioName?: string,
57
- // eslint-disable-next-line @rushstack/no-new-null
58
- ): Promise<ISnapshotTree | null> {
59
- return this.internalStorageService.getSnapshotTree(version, scenarioName);
60
- }
61
-
62
- /**
63
- * {@link IRuntimeStorageService.getSnapshot}.
64
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
65
- */
66
- public async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {
67
- if (this.internalStorageService.getSnapshot !== undefined) {
68
- return this.internalStorageService.getSnapshot(snapshotFetchOptions);
69
- }
70
- throw new UsageError(
71
- "getSnapshot api should exist on internal storage in documentStorageServiceProxy class",
72
- );
73
- }
74
-
75
- /**
76
- * {@link IRuntimeStorageService.getVersions}.
77
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
78
- */
79
- public async getVersions(
80
- // eslint-disable-next-line @rushstack/no-new-null
81
- versionId: string | null,
82
- count: number,
83
- scenarioName?: string,
84
- fetchSource?: FetchSource,
85
- ): Promise<IVersion[]> {
86
- return this.internalStorageService.getVersions(
87
- versionId,
88
- count,
89
- scenarioName,
90
- fetchSource,
91
- );
92
- }
93
-
94
- /**
95
- * {@link IRuntimeStorageService.uploadSummaryWithContext}.
96
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
97
- */
98
- public async uploadSummaryWithContext(
99
- summary: ISummaryTree,
100
- context: ISummaryContext,
101
- ): Promise<string> {
102
- return this.internalStorageService.uploadSummaryWithContext(summary, context);
103
- }
104
-
105
- /**
106
- * {@link IRuntimeStorageService.createBlob}.
107
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
108
- */
109
- public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
110
- return this.internalStorageService.createBlob(file);
111
- }
112
-
113
- /**
114
- * {@link IRuntimeStorageService.downloadSummary}.
115
- * @deprecated This will be removed in a future release. The DataStore layer does not need this.
116
- */
117
- public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
118
- return this.internalStorageService.downloadSummary(handle);
119
- }
120
28
  }