@fluidframework/container-runtime 2.92.0 → 2.100.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 (62) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/container-runtime.test-files.tar +0 -0
  4. package/dist/containerRuntime.d.ts +16 -4
  5. package/dist/containerRuntime.d.ts.map +1 -1
  6. package/dist/containerRuntime.js +80 -60
  7. package/dist/containerRuntime.js.map +1 -1
  8. package/dist/dataStore.d.ts +1 -1
  9. package/dist/dataStore.d.ts.map +1 -1
  10. package/dist/dataStore.js +6 -7
  11. package/dist/dataStore.js.map +1 -1
  12. package/dist/opLifecycle/batchManager.d.ts +3 -9
  13. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  14. package/dist/opLifecycle/batchManager.js +3 -2
  15. package/dist/opLifecycle/batchManager.js.map +1 -1
  16. package/dist/opLifecycle/outbox.d.ts +8 -5
  17. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  18. package/dist/opLifecycle/outbox.js +40 -57
  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/pendingStateManager.d.ts +1 -6
  25. package/dist/pendingStateManager.d.ts.map +1 -1
  26. package/dist/pendingStateManager.js +6 -16
  27. package/dist/pendingStateManager.js.map +1 -1
  28. package/dist/runtimeLayerCompatState.d.ts +2 -2
  29. package/eslint.config.mts +1 -1
  30. package/lib/containerRuntime.d.ts +16 -4
  31. package/lib/containerRuntime.d.ts.map +1 -1
  32. package/lib/containerRuntime.js +82 -62
  33. package/lib/containerRuntime.js.map +1 -1
  34. package/lib/dataStore.d.ts +1 -1
  35. package/lib/dataStore.d.ts.map +1 -1
  36. package/lib/dataStore.js +1 -2
  37. package/lib/dataStore.js.map +1 -1
  38. package/lib/opLifecycle/batchManager.d.ts +3 -9
  39. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  40. package/lib/opLifecycle/batchManager.js +3 -2
  41. package/lib/opLifecycle/batchManager.js.map +1 -1
  42. package/lib/opLifecycle/outbox.d.ts +8 -5
  43. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  44. package/lib/opLifecycle/outbox.js +41 -58
  45. package/lib/opLifecycle/outbox.js.map +1 -1
  46. package/lib/packageVersion.d.ts +1 -1
  47. package/lib/packageVersion.d.ts.map +1 -1
  48. package/lib/packageVersion.js +1 -1
  49. package/lib/packageVersion.js.map +1 -1
  50. package/lib/pendingStateManager.d.ts +1 -6
  51. package/lib/pendingStateManager.d.ts.map +1 -1
  52. package/lib/pendingStateManager.js +6 -16
  53. package/lib/pendingStateManager.js.map +1 -1
  54. package/lib/runtimeLayerCompatState.d.ts +2 -2
  55. package/lib/tsdoc-metadata.json +1 -1
  56. package/package.json +26 -31
  57. package/src/containerRuntime.ts +91 -76
  58. package/src/dataStore.ts +5 -6
  59. package/src/opLifecycle/batchManager.ts +4 -12
  60. package/src/opLifecycle/outbox.ts +51 -69
  61. package/src/packageVersion.ts +1 -1
  62. package/src/pendingStateManager.ts +5 -23
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.52.11"
8
+ "packageVersion": "7.58.1"
9
9
  }
10
10
  ]
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.92.0",
3
+ "version": "2.100.0",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -119,18 +119,18 @@
119
119
  "temp-directory": "nyc/.nyc_output"
120
120
  },
121
121
  "dependencies": {
122
- "@fluid-internal/client-utils": "~2.92.0",
123
- "@fluidframework/container-definitions": "~2.92.0",
124
- "@fluidframework/container-runtime-definitions": "~2.92.0",
125
- "@fluidframework/core-interfaces": "~2.92.0",
126
- "@fluidframework/core-utils": "~2.92.0",
127
- "@fluidframework/datastore": "~2.92.0",
128
- "@fluidframework/driver-definitions": "~2.92.0",
129
- "@fluidframework/driver-utils": "~2.92.0",
130
- "@fluidframework/id-compressor": "~2.92.0",
131
- "@fluidframework/runtime-definitions": "~2.92.0",
132
- "@fluidframework/runtime-utils": "~2.92.0",
133
- "@fluidframework/telemetry-utils": "~2.92.0",
122
+ "@fluid-internal/client-utils": "~2.100.0",
123
+ "@fluidframework/container-definitions": "~2.100.0",
124
+ "@fluidframework/container-runtime-definitions": "~2.100.0",
125
+ "@fluidframework/core-interfaces": "~2.100.0",
126
+ "@fluidframework/core-utils": "~2.100.0",
127
+ "@fluidframework/datastore": "~2.100.0",
128
+ "@fluidframework/driver-definitions": "~2.100.0",
129
+ "@fluidframework/driver-utils": "~2.100.0",
130
+ "@fluidframework/id-compressor": "~2.100.0",
131
+ "@fluidframework/runtime-definitions": "~2.100.0",
132
+ "@fluidframework/runtime-utils": "~2.100.0",
133
+ "@fluidframework/telemetry-utils": "~2.100.0",
134
134
  "@tylerbu/sorted-btree-es6": "^2.1.1",
135
135
  "double-ended-queue": "^2.1.0-0",
136
136
  "lz4js": "^0.2.0",
@@ -140,21 +140,21 @@
140
140
  "devDependencies": {
141
141
  "@arethetypeswrong/cli": "^0.18.2",
142
142
  "@biomejs/biome": "~2.4.5",
143
- "@fluid-internal/mocha-test-setup": "~2.92.0",
144
- "@fluid-private/stochastic-test-utils": "~2.92.0",
145
- "@fluid-private/test-pairwise-generator": "~2.92.0",
146
- "@fluid-tools/benchmark": "^0.52.0",
147
- "@fluid-tools/build-cli": "^0.64.0",
143
+ "@fluid-internal/mocha-test-setup": "~2.100.0",
144
+ "@fluid-private/stochastic-test-utils": "~2.100.0",
145
+ "@fluid-private/test-pairwise-generator": "~2.100.0",
146
+ "@fluid-tools/benchmark": "^0.58.0",
147
+ "@fluid-tools/build-cli": "^0.65.0",
148
148
  "@fluidframework/build-common": "^2.0.3",
149
- "@fluidframework/build-tools": "^0.64.0",
150
- "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.91.0",
149
+ "@fluidframework/build-tools": "^0.65.0",
150
+ "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.92.0",
151
151
  "@fluidframework/eslint-config-fluid": "^9.0.0",
152
- "@fluidframework/test-runtime-utils": "~2.92.0",
153
- "@microsoft/api-extractor": "7.52.11",
152
+ "@fluidframework/test-runtime-utils": "~2.100.0",
153
+ "@microsoft/api-extractor": "7.58.1",
154
154
  "@types/double-ended-queue": "^2.1.0",
155
155
  "@types/lz4js": "^0.2.0",
156
156
  "@types/mocha": "^10.0.10",
157
- "@types/node": "~20.19.30",
157
+ "@types/node": "~22.19.17",
158
158
  "@types/sinon": "^17.0.3",
159
159
  "c8": "^10.1.3",
160
160
  "concurrently": "^9.2.1",
@@ -169,17 +169,14 @@
169
169
  "typescript": "~5.4.5"
170
170
  },
171
171
  "typeValidation": {
172
- "broken": {
173
- "Interface_ContainerRuntimeOptions": {
174
- "forwardCompat": false
175
- }
176
- },
172
+ "broken": {},
177
173
  "entrypoint": "legacy"
178
174
  },
179
175
  "scripts": {
180
176
  "api": "fluid-build . --task api",
181
177
  "api-extractor:commonjs": "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist",
182
178
  "api-extractor:esnext": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat",
179
+ "bench": "cross-env FLUID_TEST_PERF_MODE=1 mocha --parentProcess",
183
180
  "build": "fluid-build . --task build",
184
181
  "build:api-reports": "concurrently \"npm:build:api-reports:*\"",
185
182
  "build:api-reports:current": "api-extractor run --local --config api-extractor/api-extractor.current.json",
@@ -215,7 +212,6 @@
215
212
  "pack:tests": "tar -cf ./container-runtime.test-files.tar ./src/test ./dist/test ./lib/test",
216
213
  "place:cjs:package-stub": "copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
217
214
  "test": "npm run test:mocha",
218
- "test:benchmark:report": "cross-env \"MOCHA_SPEC=dist/**/*.perf.spec.*js\" mocha --timeout 10s --perfMode --parentProcess --fgrep @Benchmark --fgrep @ExecutionTime --reporter @fluid-tools/benchmark/dist/MochaReporter.js",
219
215
  "test:coverage": "c8 npm test",
220
216
  "test:mocha": "npm run test:mocha:esm && echo skipping cjs to avoid overhead - npm run test:mocha:cjs",
221
217
  "test:mocha:cjs": "cross-env FLUID_TEST_MODULE_SYSTEM=CJS mocha",
@@ -223,7 +219,6 @@
223
219
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
224
220
  "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
225
221
  "tsc:watch": "npm run place:cjs:package-stub && fluid-tsc commonjs --project ./tsconfig.cjs.json --watch",
226
- "typetests:gen": "flub generate typetests --dir . -v",
227
- "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
222
+ "typetests:gen": "flub generate typetests --dir . -v"
228
223
  }
229
224
  }
@@ -95,7 +95,6 @@ import { FetchSource, MessageType } from "@fluidframework/driver-definitions/int
95
95
  import { readAndParse } from "@fluidframework/driver-utils/internal";
96
96
  import type { IIdCompressor } from "@fluidframework/id-compressor";
97
97
  import type {
98
- // eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
99
98
  IIdCompressorCore,
100
99
  IdCreationRange,
101
100
  SerializedIdCompressorWithNoSession,
@@ -105,6 +104,7 @@ import {
105
104
  createIdCompressor,
106
105
  createSessionId,
107
106
  deserializeIdCompressor,
107
+ toIdCompressorWithCore,
108
108
  } from "@fluidframework/id-compressor/internal";
109
109
  import {
110
110
  FlushMode,
@@ -131,7 +131,6 @@ import type {
131
131
  IContainerRuntimeBaseInternal,
132
132
  MinimumVersionForCollab,
133
133
  ContainerExtensionExpectations,
134
- ContainerRuntimeBaseAlpha,
135
134
  } from "@fluidframework/runtime-definitions/internal";
136
135
  import {
137
136
  addBlobToSummary,
@@ -173,6 +172,7 @@ import {
173
172
  wrapError,
174
173
  tagCodeArtifacts,
175
174
  normalizeError,
175
+ toITelemetryLoggerExt,
176
176
  } from "@fluidframework/telemetry-utils/internal";
177
177
  import { gt } from "semver-ts";
178
178
  import { v4 as uuid } from "uuid";
@@ -675,18 +675,11 @@ export function getDeviceSpec(): {
675
675
  deviceMemory?: number | undefined;
676
676
  hardwareConcurrency?: number | undefined;
677
677
  } {
678
- try {
679
- if (typeof navigator === "object" && navigator !== null) {
680
- return {
681
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
682
- deviceMemory: (navigator as any).deviceMemory,
683
- hardwareConcurrency: navigator.hardwareConcurrency,
684
- };
685
- }
686
- } catch {
687
- // Eat the error
688
- }
689
- return {};
678
+ return {
679
+ // deviceMemory is only available in browsers and is not part of the Navigator type definition. In Node 22 it is undefined.
680
+ deviceMemory: (navigator as Navigator & { deviceMemory?: number }).deviceMemory,
681
+ hardwareConcurrency: navigator.hardwareConcurrency,
682
+ };
690
683
  }
691
684
 
692
685
  /**
@@ -846,7 +839,7 @@ export async function loadContainerRuntime(
846
839
  * @legacy @alpha
847
840
  */
848
841
  export async function loadContainerRuntimeAlpha(params: LoadContainerRuntimeParams): Promise<{
849
- runtime: IContainerRuntime & ContainerRuntimeBaseAlpha & IRuntime;
842
+ runtime: IContainerRuntime & IRuntime;
850
843
  }> {
851
844
  return ContainerRuntime.loadRuntime2({
852
845
  ...params,
@@ -1185,7 +1178,6 @@ export class ContainerRuntime
1185
1178
  idCompressorMode = desiredIdCompressorMode;
1186
1179
  }
1187
1180
 
1188
- // eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
1189
1181
  const createIdCompressorFn = (): IIdCompressor & IIdCompressorCore => {
1190
1182
  /**
1191
1183
  * Because the IdCompressor emits so much telemetry, this function is used to sample
@@ -1204,17 +1196,21 @@ export class ContainerRuntime
1204
1196
  const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
1205
1197
 
1206
1198
  if (pendingLocalState?.pendingIdCompressorState !== undefined) {
1207
- return deserializeIdCompressor(
1208
- pendingLocalState.pendingIdCompressorState,
1209
- compressorLogger,
1199
+ return toIdCompressorWithCore(
1200
+ deserializeIdCompressor(
1201
+ pendingLocalState.pendingIdCompressorState,
1202
+ toITelemetryLoggerExt(compressorLogger),
1203
+ ),
1210
1204
  );
1211
1205
  } else if (serializedIdCompressor === undefined) {
1212
- return createIdCompressor(compressorLogger);
1206
+ return toIdCompressorWithCore(createIdCompressor(compressorLogger));
1213
1207
  } else {
1214
- return deserializeIdCompressor(
1215
- serializedIdCompressor,
1216
- createSessionId(),
1217
- compressorLogger,
1208
+ return toIdCompressorWithCore(
1209
+ deserializeIdCompressor(
1210
+ serializedIdCompressor,
1211
+ createSessionId(),
1212
+ toITelemetryLoggerExt(compressorLogger),
1213
+ ),
1218
1214
  );
1219
1215
  }
1220
1216
  };
@@ -1378,7 +1374,6 @@ export class ContainerRuntime
1378
1374
  return this.documentsSchemaController.sessionSchema.runtime;
1379
1375
  }
1380
1376
 
1381
- // eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
1382
1377
  private _idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
1383
1378
 
1384
1379
  // We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
@@ -1394,7 +1389,6 @@ export class ContainerRuntime
1394
1389
  /**
1395
1390
  * {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor}
1396
1391
  */
1397
- // eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
1398
1392
  public get idCompressor(): (IIdCompressor & IIdCompressorCore) | undefined {
1399
1393
  // Expose ID Compressor only if it's On from the start.
1400
1394
  // If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
@@ -1615,7 +1609,6 @@ export class ContainerRuntime
1615
1609
 
1616
1610
  blobManagerLoadInfo: IBlobManagerLoadInfo,
1617
1611
  private readonly _storage: IContainerStorageService,
1618
- // eslint-disable-next-line import-x/no-deprecated -- Will be undeprecated in 2.100.0 when it becomes an internal API
1619
1612
  private readonly createIdCompressorFn: () => IIdCompressor & IIdCompressorCore,
1620
1613
 
1621
1614
  private readonly documentsSchemaController: DocumentsSchemaController,
@@ -2069,6 +2062,24 @@ export class ContainerRuntime
2069
2062
  }),
2070
2063
  reSubmit: this.reSubmit.bind(this),
2071
2064
  opReentrancy: () => this.dataModelChangeRunner.running,
2065
+ generateIdAllocationOp: (): LocalBatchMessage | undefined => {
2066
+ if (this._idCompressor === undefined) {
2067
+ return undefined;
2068
+ }
2069
+ const idRange = this._idCompressor.takeNextCreationRange();
2070
+ if (idRange.ids === undefined) {
2071
+ return undefined;
2072
+ }
2073
+ const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
2074
+ type: ContainerMessageType.IdAllocation,
2075
+ contents: idRange,
2076
+ };
2077
+ return {
2078
+ runtimeOp: idAllocationMessage,
2079
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2080
+ staged: false,
2081
+ };
2082
+ },
2072
2083
  });
2073
2084
 
2074
2085
  this._quorum = quorum;
@@ -3580,7 +3591,18 @@ export class ContainerRuntime
3580
3591
  let stageControls: StageControlsInternal | undefined;
3581
3592
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback") === true) {
3582
3593
  if (!this.batchRunner.running && !this.inStagingMode) {
3583
- stageControls = this.enterStagingMode();
3594
+ // Use silent=true to suppress stagingModeChanged events for orderSequentially.
3595
+ // orderSequentially uses staging mode as a rollback mechanism.
3596
+ // Emitting stagingModeChanged here would:
3597
+ // - Cause UI flicker — consumers rendering staging mode event would see
3598
+ // unexpected enter/exit flashes on every orderSequentially call.
3599
+ // - consumers cannot distinguish this internal usage
3600
+ // from a user explicitly entering staging mode, as there is no source field
3601
+ // on the event to filter by.
3602
+ // - if orderSequentially is
3603
+ // later reimplemented without staging mode, consumers calibrated
3604
+ // to these events would break silently.
3605
+ stageControls = this.enterStagingModeCore(true);
3584
3606
  }
3585
3607
  // Note: we are not touching any batches other than mainBatch here, for two reasons:
3586
3608
  // 1. It would not help, as other batches are flushed independently from main batch.
@@ -3656,9 +3678,22 @@ export class ContainerRuntime
3656
3678
  * Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service.
3657
3679
  * To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method.
3658
3680
  *
3681
+ * @remarks
3682
+ * The `stagingModeChanged` event is emitted when staging mode is entered or exited via this method.
3683
+ * It is NOT emitted when staging mode is used internally (e.g. by `orderSequentially` for rollback support).
3684
+ *
3659
3685
  * @returns Controls for exiting Staging Mode.
3660
3686
  */
3661
- public enterStagingMode = (): StageControlsInternal => {
3687
+ public enterStagingMode = (): StageControlsInternal => this.enterStagingModeCore(false);
3688
+
3689
+ /**
3690
+ * Internal implementation of enterStagingMode.
3691
+ * @param silent - When true, suppresses `stagingModeChanged` event emission.
3692
+ * Pass `true` when staging mode is used as an internal implementation detail (e.g. by
3693
+ * `orderSequentially` for rollback support) so that external listeners only observe
3694
+ * user-initiated staging mode transitions. Pass `false` for all public entry points.
3695
+ */
3696
+ private readonly enterStagingModeCore = (silent: boolean): StageControlsInternal => {
3662
3697
  if (this.stageControls !== undefined) {
3663
3698
  throw new UsageError("Already in staging mode");
3664
3699
  }
@@ -3670,10 +3705,15 @@ export class ContainerRuntime
3670
3705
  // since we mark whole batches as "staged" or not to indicate whether to submit them.
3671
3706
  this.flush();
3672
3707
 
3708
+ // Note: `silent` is captured from the enclosing `enterStagingModeCore` call.
3709
+ // When `true`, both enter and exit events are suppressed (see orderSequentially).
3673
3710
  const exitStagingMode = (
3674
3711
  discardOrCommit: () => IPendingMessage["batchInfo"][],
3675
3712
  exitMethod: "commit" | "discard",
3676
3713
  ): void => {
3714
+ if (this.stageControls !== stageControls) {
3715
+ throw new UsageError("Not in staging mode");
3716
+ }
3677
3717
  try {
3678
3718
  PerformanceEvent.timedExec(
3679
3719
  this.mc.logger,
@@ -3687,9 +3727,6 @@ export class ContainerRuntime
3687
3727
 
3688
3728
  this.stageControls = undefined;
3689
3729
 
3690
- // During Staging Mode, we avoid submitting any ID Allocation ops (apart from resubmitting pre-staging ops).
3691
- // Now that we've exited, we need to submit an ID Allocation op for any IDs that were generated while in Staging Mode.
3692
- this.submitIdAllocationOpIfNeeded({ staged: false });
3693
3730
  const batchInfos = discardOrCommit();
3694
3731
  event.reportProgress({
3695
3732
  details: {
@@ -3708,6 +3745,12 @@ export class ContainerRuntime
3708
3745
  this.closeFn(normalizedError);
3709
3746
  throw normalizedError;
3710
3747
  }
3748
+ if (!silent) {
3749
+ this.emit("stagingModeChanged", {
3750
+ inStagingMode: false,
3751
+ commit: exitMethod === "commit",
3752
+ });
3753
+ }
3711
3754
  };
3712
3755
 
3713
3756
  const stageControls: StageControlsInternal = {
@@ -3737,8 +3780,16 @@ export class ContainerRuntime
3737
3780
 
3738
3781
  this.stageControls = stageControls;
3739
3782
  this.channelCollection.notifyStagingMode(true);
3783
+ if (!silent) {
3784
+ try {
3785
+ this.emit("stagingModeChanged", { inStagingMode: true });
3786
+ } catch (error) {
3787
+ // Don't let a listener error prevent the caller from receiving stage controls.
3788
+ this.mc.logger.sendErrorEvent({ eventName: "StagingModeChangedError" }, error);
3789
+ }
3790
+ }
3740
3791
 
3741
- return this.stageControls;
3792
+ return stageControls;
3742
3793
  };
3743
3794
 
3744
3795
  /**
@@ -4272,7 +4323,6 @@ export class ContainerRuntime
4272
4323
  outboxLength: this.outbox.messageCount,
4273
4324
  mainBatchLength: this.outbox.mainBatchMessageCount,
4274
4325
  blobAttachBatchLength: this.outbox.blobAttachBatchMessageCount,
4275
- idAllocationBatchLength: this.outbox.idAllocationBatchMessageCount,
4276
4326
  },
4277
4327
  );
4278
4328
  }
@@ -4605,7 +4655,8 @@ export class ContainerRuntime
4605
4655
 
4606
4656
  /**
4607
4657
  * This helper is called during summarization. If the container is dirty, it will return a failed summarize result
4608
- * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
4658
+ * (IBaseSummarizeResult) unless this is the final summarize attempt, in which case the summary is allowed to
4659
+ * proceed to make progress in documents where there are consistently pending ops in the summarizer.
4609
4660
  * @param logger - The logger to be used for sending telemetry.
4610
4661
  * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
4611
4662
  * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
@@ -4624,13 +4675,9 @@ export class ContainerRuntime
4624
4675
  return;
4625
4676
  }
4626
4677
 
4627
- // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
4628
- // This is a fallback to make progress in documents where there are consistently pending ops in
4629
- // the summarizer.
4630
- if (
4631
- finalAttempt &&
4632
- this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary") === true
4633
- ) {
4678
+ // Don't fail the summary in the last attempt. This is a fallback to make progress in
4679
+ // documents where there are consistently pending ops in the summarizer.
4680
+ if (finalAttempt) {
4634
4681
  const error = DataProcessingError.create(
4635
4682
  "Pending ops during summarization",
4636
4683
  "submitSummary",
@@ -4639,7 +4686,7 @@ export class ContainerRuntime
4639
4686
  );
4640
4687
  logger.sendErrorEvent(
4641
4688
  {
4642
- eventName: "SkipFailingIncorrectSummary",
4689
+ eventName: "PendingOpsDuringSummaryFinalAttempt",
4643
4690
  referenceSequenceNumber,
4644
4691
  minimumSequenceNumber,
4645
4692
  beforeGenerate: beforeSummaryGeneration,
@@ -4733,33 +4780,6 @@ export class ContainerRuntime
4733
4780
  return this.blobManager.lookupTemporaryBlobStorageId(localId);
4734
4781
  }
4735
4782
 
4736
- private submitIdAllocationOpIfNeeded({
4737
- resubmitOutstandingRanges = false,
4738
- staged,
4739
- }: {
4740
- resubmitOutstandingRanges?: boolean;
4741
- staged: boolean;
4742
- }): void {
4743
- if (this._idCompressor) {
4744
- const idRange = resubmitOutstandingRanges
4745
- ? this._idCompressor.takeUnfinalizedCreationRange()
4746
- : this._idCompressor.takeNextCreationRange();
4747
- // Don't include the idRange if there weren't any Ids allocated
4748
- if (idRange.ids !== undefined) {
4749
- const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
4750
- type: ContainerMessageType.IdAllocation,
4751
- contents: idRange,
4752
- };
4753
- const idAllocationBatchMessage: LocalBatchMessage = {
4754
- runtimeOp: idAllocationMessage,
4755
- referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
4756
- staged,
4757
- };
4758
- this.outbox.submitIdAllocation(idAllocationBatchMessage);
4759
- }
4760
- }
4761
- }
4762
-
4763
4783
  private submit(
4764
4784
  containerRuntimeMessage: LocalContainerRuntimeMessage,
4765
4785
  localOpMetadata: unknown = undefined,
@@ -4803,11 +4823,6 @@ export class ContainerRuntime
4803
4823
  0xbba /* Unexpected message type submitted in Staging Mode */,
4804
4824
  );
4805
4825
 
4806
- // Before submitting any non-staged change, submit the ID Allocation op to cover any compressed IDs included in the op.
4807
- if (!staged) {
4808
- this.submitIdAllocationOpIfNeeded({ staged: false });
4809
- }
4810
-
4811
4826
  // Allow document schema controller to send a message if it needs to propose change in document schema.
4812
4827
  // If it needs to send a message, it will call provided callback with payload of such message and rely
4813
4828
  // on this callback to do actual sending.
@@ -4867,7 +4882,7 @@ export class ContainerRuntime
4867
4882
  // Incoming ops still break the batch via direct this.flush() calls elsewhere
4868
4883
  // (deltaManager "op" handler, process(), connection changes, getPendingLocalState,
4869
4884
  // exitStagingMode). Those all bypass scheduleFlush(), so they're unaffected by this check.
4870
- // Additionally, outbox.maybeFlushPartialBatch() (called on every submit) detects
4885
+ // Additionally, outbox.outboxSequenceNumberCoherencyCheck() (called on every submit) detects
4871
4886
  // sequence number changes and throws if unexpected changes are detected.
4872
4887
  if (
4873
4888
  this.inStagingMode &&
package/src/dataStore.ts CHANGED
@@ -7,11 +7,10 @@ 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 {
11
- type AliasResult,
12
- type IDataStore,
13
- type IFluidDataStoreChannel,
14
- asLegacyAlpha,
10
+ import type {
11
+ AliasResult,
12
+ IDataStore,
13
+ IFluidDataStoreChannel,
15
14
  } from "@fluidframework/runtime-definitions/internal";
16
15
  import {
17
16
  type ITelemetryLoggerExt,
@@ -81,7 +80,7 @@ class DataStore implements IDataStore {
81
80
  if (alias.includes("/")) {
82
81
  throw new UsageError(`The alias cannot contain slashes: '${alias}'`);
83
82
  }
84
- if (asLegacyAlpha(this.parentContext.containerRuntime).inStagingMode === true) {
83
+ if (this.parentContext.containerRuntime.inStagingMode === true) {
85
84
  throw new UsageError("Cannot set aliases while in staging mode");
86
85
  }
87
86
 
@@ -20,17 +20,8 @@ import { serializeOp } from "./opSerialization.js";
20
20
  import type { BatchStartInfo } from "./remoteMessageProcessor.js";
21
21
 
22
22
  export interface IBatchManagerOptions {
23
+ readonly disableGroupedBatching: boolean;
23
24
  readonly compressionOptions?: ICompressionRuntimeOptions;
24
-
25
- /**
26
- * If true, the outbox is allowed to rebase the batch during flushing.
27
- */
28
- readonly canRebase: boolean;
29
-
30
- /**
31
- * If true, don't compare batchID of incoming batches to this. e.g. ID Allocation Batch IDs should be ignored
32
- */
33
- readonly ignoreBatchId?: boolean;
34
25
  }
35
26
 
36
27
  export interface BatchSequenceNumbers {
@@ -127,8 +118,9 @@ export class BatchManager {
127
118
 
128
119
  /**
129
120
  * Gets the pending batch and clears state for the next batch.
121
+ * The caller is responsible for calling {@link addBatchMetadata} after any modifications (e.g. prepending messages).
130
122
  */
131
- public popBatch(batchId?: BatchId): LocalBatch {
123
+ public popBatch(): LocalBatch {
132
124
  assert(this.pendingBatch[0] !== undefined, 0xb8a /* expected non-empty batch */);
133
125
  const batch: LocalBatch = {
134
126
  messages: this.pendingBatch,
@@ -141,7 +133,7 @@ export class BatchManager {
141
133
  this.clientSequenceNumber = undefined;
142
134
  this.hasReentrantOps = false;
143
135
 
144
- return addBatchMetadata(batch, batchId);
136
+ return batch;
145
137
  }
146
138
 
147
139
  /**