@fluidframework/container-runtime 2.0.0-dev-rc.4.0.0.261659 → 2.0.0-dev-rc.5.0.0.263932

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 (178) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/api-report/container-runtime.api.md +62 -22
  3. package/dist/blobManager.d.ts +7 -7
  4. package/dist/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager.js +2 -4
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/channelCollection.d.ts +6 -4
  8. package/dist/channelCollection.d.ts.map +1 -1
  9. package/dist/channelCollection.js +19 -8
  10. package/dist/channelCollection.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts +1 -1
  12. package/dist/connectionTelemetry.d.ts.map +1 -1
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +5 -8
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +65 -38
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.js.map +1 -1
  19. package/dist/dataStoreContext.d.ts +9 -6
  20. package/dist/dataStoreContext.d.ts.map +1 -1
  21. package/dist/dataStoreContext.js +18 -5
  22. package/dist/dataStoreContext.js.map +1 -1
  23. package/dist/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
  24. package/dist/deltaManagerProxies.d.ts.map +1 -0
  25. package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +38 -2
  26. package/dist/deltaManagerProxies.js.map +1 -0
  27. package/dist/deltaScheduler.d.ts +1 -1
  28. package/dist/deltaScheduler.d.ts.map +1 -1
  29. package/dist/deltaScheduler.js.map +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/legacy.d.ts +5 -0
  34. package/dist/messageTypes.d.ts +5 -2
  35. package/dist/messageTypes.d.ts.map +1 -1
  36. package/dist/messageTypes.js.map +1 -1
  37. package/dist/opLifecycle/batchManager.d.ts +4 -0
  38. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  39. package/dist/opLifecycle/batchManager.js.map +1 -1
  40. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  41. package/dist/opLifecycle/outbox.js +5 -4
  42. package/dist/opLifecycle/outbox.js.map +1 -1
  43. package/dist/packageVersion.d.ts +1 -1
  44. package/dist/packageVersion.js +1 -1
  45. package/dist/packageVersion.js.map +1 -1
  46. package/dist/pendingStateManager.d.ts +6 -0
  47. package/dist/pendingStateManager.d.ts.map +1 -1
  48. package/dist/pendingStateManager.js +10 -1
  49. package/dist/pendingStateManager.js.map +1 -1
  50. package/dist/scheduleManager.d.ts +1 -1
  51. package/dist/scheduleManager.d.ts.map +1 -1
  52. package/dist/scheduleManager.js.map +1 -1
  53. package/dist/summary/documentSchema.js +1 -1
  54. package/dist/summary/documentSchema.js.map +1 -1
  55. package/dist/summary/index.d.ts +1 -1
  56. package/dist/summary/index.d.ts.map +1 -1
  57. package/dist/summary/index.js.map +1 -1
  58. package/dist/summary/orderedClientElection.d.ts +1 -1
  59. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  60. package/dist/summary/orderedClientElection.js.map +1 -1
  61. package/dist/summary/runningSummarizer.js +10 -10
  62. package/dist/summary/runningSummarizer.js.map +1 -1
  63. package/dist/summary/summarizerTypes.d.ts +1 -2
  64. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  65. package/dist/summary/summarizerTypes.js.map +1 -1
  66. package/dist/summary/summaryCollection.d.ts +1 -1
  67. package/dist/summary/summaryCollection.d.ts.map +1 -1
  68. package/dist/summary/summaryCollection.js.map +1 -1
  69. package/dist/summary/summaryFormat.d.ts +25 -5
  70. package/dist/summary/summaryFormat.d.ts.map +1 -1
  71. package/dist/summary/summaryFormat.js.map +1 -1
  72. package/dist/summary/summaryGenerator.js +11 -11
  73. package/dist/summary/summaryGenerator.js.map +1 -1
  74. package/dist/summary/summaryManager.js +5 -5
  75. package/dist/summary/summaryManager.js.map +1 -1
  76. package/lib/blobManager.d.ts +7 -7
  77. package/lib/blobManager.d.ts.map +1 -1
  78. package/lib/blobManager.js +3 -5
  79. package/lib/blobManager.js.map +1 -1
  80. package/lib/channelCollection.d.ts +6 -4
  81. package/lib/channelCollection.d.ts.map +1 -1
  82. package/lib/channelCollection.js +20 -9
  83. package/lib/channelCollection.js.map +1 -1
  84. package/lib/connectionTelemetry.d.ts +1 -1
  85. package/lib/connectionTelemetry.d.ts.map +1 -1
  86. package/lib/connectionTelemetry.js.map +1 -1
  87. package/lib/containerRuntime.d.ts +5 -8
  88. package/lib/containerRuntime.d.ts.map +1 -1
  89. package/lib/containerRuntime.js +65 -38
  90. package/lib/containerRuntime.js.map +1 -1
  91. package/lib/dataStore.js.map +1 -1
  92. package/lib/dataStoreContext.d.ts +9 -6
  93. package/lib/dataStoreContext.d.ts.map +1 -1
  94. package/lib/dataStoreContext.js +20 -7
  95. package/lib/dataStoreContext.js.map +1 -1
  96. package/lib/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
  97. package/lib/deltaManagerProxies.d.ts.map +1 -0
  98. package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +36 -1
  99. package/lib/deltaManagerProxies.js.map +1 -0
  100. package/lib/deltaScheduler.d.ts +1 -1
  101. package/lib/deltaScheduler.d.ts.map +1 -1
  102. package/lib/deltaScheduler.js.map +1 -1
  103. package/lib/index.d.ts +1 -1
  104. package/lib/index.d.ts.map +1 -1
  105. package/lib/index.js.map +1 -1
  106. package/lib/legacy.d.ts +5 -0
  107. package/lib/messageTypes.d.ts +5 -2
  108. package/lib/messageTypes.d.ts.map +1 -1
  109. package/lib/messageTypes.js.map +1 -1
  110. package/lib/opLifecycle/batchManager.d.ts +4 -0
  111. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  112. package/lib/opLifecycle/batchManager.js.map +1 -1
  113. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  114. package/lib/opLifecycle/outbox.js +5 -4
  115. package/lib/opLifecycle/outbox.js.map +1 -1
  116. package/lib/packageVersion.d.ts +1 -1
  117. package/lib/packageVersion.js +1 -1
  118. package/lib/packageVersion.js.map +1 -1
  119. package/lib/pendingStateManager.d.ts +6 -0
  120. package/lib/pendingStateManager.d.ts.map +1 -1
  121. package/lib/pendingStateManager.js +10 -1
  122. package/lib/pendingStateManager.js.map +1 -1
  123. package/lib/scheduleManager.d.ts +1 -1
  124. package/lib/scheduleManager.d.ts.map +1 -1
  125. package/lib/scheduleManager.js.map +1 -1
  126. package/lib/summary/documentSchema.js +1 -1
  127. package/lib/summary/documentSchema.js.map +1 -1
  128. package/lib/summary/index.d.ts +1 -1
  129. package/lib/summary/index.d.ts.map +1 -1
  130. package/lib/summary/index.js.map +1 -1
  131. package/lib/summary/orderedClientElection.d.ts +1 -1
  132. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  133. package/lib/summary/orderedClientElection.js.map +1 -1
  134. package/lib/summary/runningSummarizer.js +1 -1
  135. package/lib/summary/runningSummarizer.js.map +1 -1
  136. package/lib/summary/summarizerTypes.d.ts +1 -2
  137. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  138. package/lib/summary/summarizerTypes.js.map +1 -1
  139. package/lib/summary/summaryCollection.d.ts +1 -1
  140. package/lib/summary/summaryCollection.d.ts.map +1 -1
  141. package/lib/summary/summaryCollection.js.map +1 -1
  142. package/lib/summary/summaryFormat.d.ts +25 -5
  143. package/lib/summary/summaryFormat.d.ts.map +1 -1
  144. package/lib/summary/summaryFormat.js.map +1 -1
  145. package/lib/summary/summaryGenerator.js +1 -1
  146. package/lib/summary/summaryGenerator.js.map +1 -1
  147. package/lib/summary/summaryManager.js +1 -1
  148. package/lib/summary/summaryManager.js.map +1 -1
  149. package/lib/tsdoc-metadata.json +1 -1
  150. package/package.json +25 -23
  151. package/src/blobManager.ts +11 -10
  152. package/src/channelCollection.ts +29 -13
  153. package/src/connectionTelemetry.ts +1 -1
  154. package/src/containerRuntime.ts +93 -53
  155. package/src/dataStore.ts +2 -2
  156. package/src/dataStoreContext.ts +56 -16
  157. package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +55 -3
  158. package/src/deltaScheduler.ts +1 -1
  159. package/src/index.ts +5 -0
  160. package/src/messageTypes.ts +4 -2
  161. package/src/opLifecycle/batchManager.ts +5 -0
  162. package/src/opLifecycle/outbox.ts +5 -4
  163. package/src/packageVersion.ts +1 -1
  164. package/src/pendingStateManager.ts +11 -1
  165. package/src/scheduleManager.ts +1 -1
  166. package/src/summary/documentSchema.ts +1 -1
  167. package/src/summary/index.ts +4 -0
  168. package/src/summary/orderedClientElection.ts +1 -1
  169. package/src/summary/runningSummarizer.ts +1 -1
  170. package/src/summary/summarizerTypes.ts +1 -2
  171. package/src/summary/summaryCollection.ts +1 -1
  172. package/src/summary/summaryFormat.ts +30 -4
  173. package/src/summary/summaryGenerator.ts +1 -1
  174. package/src/summary/summaryManager.ts +1 -1
  175. package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
  176. package/dist/deltaManagerSummarizerProxy.js.map +0 -1
  177. package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
  178. package/lib/deltaManagerSummarizerProxy.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "2.0.0-dev-rc.4.0.0.261659",
3
+ "version": "2.0.0-dev-rc.5.0.0.263932",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -127,19 +127,19 @@
127
127
  "temp-directory": "nyc/.nyc_output"
128
128
  },
129
129
  "dependencies": {
130
- "@fluid-internal/client-utils": "2.0.0-dev-rc.4.0.0.261659",
131
- "@fluidframework/container-definitions": "2.0.0-dev-rc.4.0.0.261659",
132
- "@fluidframework/container-runtime-definitions": "2.0.0-dev-rc.4.0.0.261659",
133
- "@fluidframework/core-interfaces": "2.0.0-dev-rc.4.0.0.261659",
134
- "@fluidframework/core-utils": "2.0.0-dev-rc.4.0.0.261659",
135
- "@fluidframework/datastore": "2.0.0-dev-rc.4.0.0.261659",
136
- "@fluidframework/driver-definitions": "2.0.0-dev-rc.4.0.0.261659",
137
- "@fluidframework/driver-utils": "2.0.0-dev-rc.4.0.0.261659",
138
- "@fluidframework/id-compressor": "2.0.0-dev-rc.4.0.0.261659",
130
+ "@fluid-internal/client-utils": "2.0.0-dev-rc.5.0.0.263932",
131
+ "@fluidframework/container-definitions": "2.0.0-dev-rc.5.0.0.263932",
132
+ "@fluidframework/container-runtime-definitions": "2.0.0-dev-rc.5.0.0.263932",
133
+ "@fluidframework/core-interfaces": "2.0.0-dev-rc.5.0.0.263932",
134
+ "@fluidframework/core-utils": "2.0.0-dev-rc.5.0.0.263932",
135
+ "@fluidframework/datastore": "2.0.0-dev-rc.5.0.0.263932",
136
+ "@fluidframework/driver-definitions": "2.0.0-dev-rc.5.0.0.263932",
137
+ "@fluidframework/driver-utils": "2.0.0-dev-rc.5.0.0.263932",
138
+ "@fluidframework/id-compressor": "2.0.0-dev-rc.5.0.0.263932",
139
139
  "@fluidframework/protocol-definitions": "^3.2.0",
140
- "@fluidframework/runtime-definitions": "2.0.0-dev-rc.4.0.0.261659",
141
- "@fluidframework/runtime-utils": "2.0.0-dev-rc.4.0.0.261659",
142
- "@fluidframework/telemetry-utils": "2.0.0-dev-rc.4.0.0.261659",
140
+ "@fluidframework/runtime-definitions": "2.0.0-dev-rc.5.0.0.263932",
141
+ "@fluidframework/runtime-utils": "2.0.0-dev-rc.5.0.0.263932",
142
+ "@fluidframework/telemetry-utils": "2.0.0-dev-rc.5.0.0.263932",
143
143
  "@tylerbu/sorted-btree-es6": "^1.8.0",
144
144
  "double-ended-queue": "^2.1.0-0",
145
145
  "lz4js": "^0.2.0",
@@ -148,17 +148,17 @@
148
148
  "devDependencies": {
149
149
  "@arethetypeswrong/cli": "^0.15.2",
150
150
  "@biomejs/biome": "^1.6.2",
151
- "@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.4.0.0.261659",
152
- "@fluid-private/stochastic-test-utils": "2.0.0-dev-rc.4.0.0.261659",
153
- "@fluid-private/test-pairwise-generator": "2.0.0-dev-rc.4.0.0.261659",
151
+ "@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.5.0.0.263932",
152
+ "@fluid-private/stochastic-test-utils": "2.0.0-dev-rc.5.0.0.263932",
153
+ "@fluid-private/test-pairwise-generator": "2.0.0-dev-rc.5.0.0.263932",
154
154
  "@fluid-tools/benchmark": "^0.48.0",
155
- "@fluid-tools/build-cli": "0.38.0-259537",
155
+ "@fluid-tools/build-cli": "^0.38.0",
156
156
  "@fluidframework/build-common": "^2.0.3",
157
- "@fluidframework/build-tools": "0.38.0-259537",
157
+ "@fluidframework/build-tools": "^0.38.0",
158
158
  "@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-rc.3.0.0",
159
159
  "@fluidframework/eslint-config-fluid": "^5.1.0",
160
- "@fluidframework/test-runtime-utils": "2.0.0-dev-rc.4.0.0.261659",
161
- "@microsoft/api-extractor": "^7.42.3",
160
+ "@fluidframework/test-runtime-utils": "2.0.0-dev-rc.5.0.0.263932",
161
+ "@microsoft/api-extractor": "^7.43.1",
162
162
  "@types/double-ended-queue": "^2.1.0",
163
163
  "@types/mocha": "^9.1.1",
164
164
  "@types/node": "^18.19.0",
@@ -180,7 +180,8 @@
180
180
  "typeValidation": {
181
181
  "broken": {
182
182
  "ClassDeclaration_ChannelCollection": {
183
- "backCompat": false
183
+ "backCompat": false,
184
+ "forwardCompat": false
184
185
  },
185
186
  "ClassDeclaration_ContainerRuntime": {
186
187
  "backCompat": false,
@@ -215,6 +216,7 @@
215
216
  "format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore",
216
217
  "lint": "fluid-build . --task lint",
217
218
  "lint:fix": "fluid-build . --task eslint:fix --task format",
219
+ "place:cjs:package-stub": "copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
218
220
  "test": "npm run test:mocha",
219
221
  "test:benchmark:report": "mocha --timeout 999999 --perfMode --parentProcess --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js \"./dist/**/*.perf.spec.*js\"",
220
222
  "test:coverage": "c8 npm test",
@@ -222,8 +224,8 @@
222
224
  "test:mocha:cjs": "mocha --recursive \"dist/test/**/*.spec.*js\" --exit",
223
225
  "test:mocha:esm": "mocha --recursive \"lib/test/**/*.spec.*js\" --exit",
224
226
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
225
- "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
226
- "tsc:watch": "tsc --watch",
227
+ "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
228
+ "tsc:watch": "npm run place:cjs:package-stub && fluid-tsc commonjs --project ./tsconfig.cjs.json --watch",
227
229
  "typetests:gen": "flub generate typetests --dir . -v --publicFallback",
228
230
  "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
229
231
  }
@@ -9,7 +9,10 @@ import {
9
9
  IContainerRuntime,
10
10
  IContainerRuntimeEvents,
11
11
  } from "@fluidframework/container-runtime-definitions/internal";
12
- import { IFluidHandle, IFluidHandleContext } from "@fluidframework/core-interfaces";
12
+ import {
13
+ IFluidHandleContext,
14
+ type IFluidHandleInternal,
15
+ } from "@fluidframework/core-interfaces/internal";
13
16
  import { assert, Deferred } from "@fluidframework/core-utils/internal";
14
17
  import { IDocumentStorageService } from "@fluidframework/driver-definitions/internal";
15
18
  import { canRetryOnError, runWithRetry } from "@fluidframework/driver-utils/internal";
@@ -24,6 +27,7 @@ import {
24
27
  ITelemetryContext,
25
28
  } from "@fluidframework/runtime-definitions";
26
29
  import {
30
+ FluidHandleBase,
27
31
  SummaryTreeBuilder,
28
32
  createResponseError,
29
33
  generateHandleContextPath,
@@ -48,13 +52,9 @@ import { IBlobMetadata } from "./metadata.js";
48
52
  * DataObject.request() recognizes requests in the form of `/blobs/<id>`
49
53
  * and loads blob.
50
54
  */
51
- export class BlobHandle implements IFluidHandle<ArrayBufferLike> {
55
+ export class BlobHandle extends FluidHandleBase<ArrayBufferLike> {
52
56
  private attached: boolean = false;
53
57
 
54
- public get IFluidHandle(): IFluidHandle {
55
- return this;
56
- }
57
-
58
58
  public get isAttached(): boolean {
59
59
  return this.routeContext.isAttached && this.attached;
60
60
  }
@@ -64,9 +64,10 @@ export class BlobHandle implements IFluidHandle<ArrayBufferLike> {
64
64
  constructor(
65
65
  public readonly path: string,
66
66
  public readonly routeContext: IFluidHandleContext,
67
- public get: () => Promise<any>,
67
+ public get: () => Promise<ArrayBufferLike>,
68
68
  private readonly onAttachGraph?: () => void,
69
69
  ) {
70
+ super();
70
71
  this.absolutePath = generateHandleContextPath(path, this.routeContext);
71
72
  }
72
73
 
@@ -77,7 +78,7 @@ export class BlobHandle implements IFluidHandle<ArrayBufferLike> {
77
78
  }
78
79
  }
79
80
 
80
- public bind(handle: IFluidHandle) {
81
+ public bind(handle: IFluidHandleInternal) {
81
82
  throw new Error("Cannot bind to blob handle");
82
83
  }
83
84
  }
@@ -433,7 +434,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
433
434
 
434
435
  private async createBlobDetached(
435
436
  blob: ArrayBufferLike,
436
- ): Promise<IFluidHandle<ArrayBufferLike>> {
437
+ ): Promise<IFluidHandleInternal<ArrayBufferLike>> {
437
438
  // Blobs created while the container is detached are stored in IDetachedBlobStorage.
438
439
  // The 'IDocumentStorageService.createBlob()' call below will respond with a localId.
439
440
  const response = await this.getStorage().createBlob(blob);
@@ -444,7 +445,7 @@ export class BlobManager extends TypedEventEmitter<IBlobManagerEvents> {
444
445
  public async createBlob(
445
446
  blob: ArrayBufferLike,
446
447
  signal?: AbortSignal,
447
- ): Promise<IFluidHandle<ArrayBufferLike>> {
448
+ ): Promise<IFluidHandleInternal<ArrayBufferLike>> {
448
449
  if (this.runtime.attachState === AttachState.Detached) {
449
450
  return this.createBlobDetached(blob);
450
451
  }
@@ -7,14 +7,19 @@ import { AttachState } from "@fluidframework/container-definitions";
7
7
  import {
8
8
  FluidObject,
9
9
  IDisposable,
10
- IFluidHandle,
11
10
  IRequest,
12
11
  IResponse,
13
12
  ITelemetryBaseLogger,
14
13
  } from "@fluidframework/core-interfaces";
14
+ import type { IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
15
15
  import { assert, Lazy, LazyPromise } from "@fluidframework/core-utils/internal";
16
16
  import { FluidObjectHandle } from "@fluidframework/datastore/internal";
17
- import { buildSnapshotTree } from "@fluidframework/driver-utils/internal";
17
+ import {
18
+ buildSnapshotTree,
19
+ getSnapshotTree,
20
+ isInstanceOfISnapshot,
21
+ } from "@fluidframework/driver-utils/internal";
22
+ import type { ISnapshot } from "@fluidframework/driver-definitions/internal";
18
23
  import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
19
24
  import {
20
25
  IGarbageCollectionData,
@@ -255,7 +260,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
255
260
 
256
261
  private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());
257
262
 
258
- public readonly entryPoint: IFluidHandle<FluidObject>;
263
+ public readonly entryPoint: IFluidHandleInternal<FluidObject>;
259
264
 
260
265
  public readonly containerLoadStats: {
261
266
  // number of dataStores during loadContainer
@@ -269,7 +274,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
269
274
  private dataStoresSinceLastGC: string[] = [];
270
275
  // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
271
276
  // the container runtime to other nodes.
272
- private readonly containerRuntimeHandle: IFluidHandle;
277
+ private readonly containerRuntimeHandle: IFluidHandleInternal;
273
278
  private readonly pendingAliasMap: Map<string, Promise<AliasResult>> = new Map<
274
279
  string,
275
280
  Promise<AliasResult>
@@ -279,7 +284,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
279
284
  private readonly aliasedDataStores: Set<string>;
280
285
 
281
286
  constructor(
282
- protected readonly baseSnapshot: ISnapshotTree | undefined,
287
+ protected readonly baseSnapshot: ISnapshotTree | ISnapshot | undefined,
283
288
  public readonly parentContext: IFluidParentContext,
284
289
  baseLogger: ITelemetryBaseLogger,
285
290
  private readonly gcNodeUpdated: (props: IGCNodeUpdatedProps) => void,
@@ -304,7 +309,8 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
304
309
  // Extract stores stored inside the snapshot
305
310
  const fluidDataStores = new Map<string, ISnapshotTree>();
306
311
  if (baseSnapshot) {
307
- for (const [key, value] of Object.entries(baseSnapshot.trees)) {
312
+ const baseSnapshotTree = getSnapshotTree(baseSnapshot);
313
+ for (const [key, value] of Object.entries(baseSnapshotTree.trees)) {
308
314
  fluidDataStores.set(key, value);
309
315
  }
310
316
  }
@@ -320,9 +326,16 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
320
326
  }
321
327
  // If we have a detached container, then create local data store contexts.
322
328
  if (this.parentContext.attachState !== AttachState.Detached) {
329
+ let snapshotForRemoteFluidDatastoreContext: ISnapshot | ISnapshotTree = value;
330
+ if (isInstanceOfISnapshot(baseSnapshot)) {
331
+ snapshotForRemoteFluidDatastoreContext = {
332
+ ...baseSnapshot,
333
+ snapshotTree: value,
334
+ };
335
+ }
323
336
  dataStoreContext = new RemoteFluidDataStoreContext({
324
337
  id: key,
325
- snapshotTree: value,
338
+ snapshot: snapshotForRemoteFluidDatastoreContext,
326
339
  parentContext: this.wrapContextForInnerChannel(key),
327
340
  storage: this.parentContext.storage,
328
341
  scope: this.parentContext.scope,
@@ -443,9 +456,12 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
443
456
  }
444
457
 
445
458
  const flatAttachBlobs = new Map<string, ArrayBufferLike>();
446
- let snapshotTree: ISnapshotTree | undefined;
459
+ let snapshot: ISnapshotTree | ISnapshot | undefined;
447
460
  if (attachMessage.snapshot) {
448
- snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatAttachBlobs);
461
+ snapshot = buildSnapshotTree(attachMessage.snapshot.entries, flatAttachBlobs);
462
+ if (isInstanceOfISnapshot(this.baseSnapshot)) {
463
+ snapshot = { ...this.baseSnapshot, snapshotTree: snapshot };
464
+ }
449
465
  }
450
466
 
451
467
  // Include the type of attach message which is the pkg of the store to be
@@ -453,7 +469,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
453
469
  const pkg = [attachMessage.type];
454
470
  const remoteFluidDataStoreContext = new RemoteFluidDataStoreContext({
455
471
  id: attachMessage.id,
456
- snapshotTree,
472
+ snapshot,
457
473
  parentContext: this.wrapContextForInnerChannel(attachMessage.id),
458
474
  storage: new StorageServiceWithAttachBlobs(this.parentContext.storage, flatAttachBlobs),
459
475
  scope: this.parentContext.scope,
@@ -563,8 +579,8 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
563
579
  * If the container is detached, this data store will be part of the summary that makes the container attached.
564
580
  */
565
581
  if (this.parentContext.attachState !== AttachState.Detached) {
566
- localContext.setAttachState(AttachState.Attaching);
567
582
  this.submitAttachChannelOp(localContext);
583
+ localContext.setAttachState(AttachState.Attaching);
568
584
  }
569
585
 
570
586
  this.contexts.bind(id);
@@ -644,7 +660,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
644
660
  createProps?: any,
645
661
  loadingGroupId?: string,
646
662
  ) {
647
- assert(loadingGroupId !== "", "loadingGroupId should not be the empty string");
663
+ assert(loadingGroupId !== "", 0x974 /* loadingGroupId should not be the empty string */);
648
664
  const context = new contextCtor({
649
665
  id,
650
666
  pkg,
@@ -1154,7 +1170,7 @@ export class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
1154
1170
  0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
1155
1171
  );
1156
1172
  dataStoreSummary = convertSnapshotTreeToSummaryTree(
1157
- this.baseSnapshot.trees[key],
1173
+ getSnapshotTree(this.baseSnapshot).trees[key],
1158
1174
  );
1159
1175
  }
1160
1176
  builder.addWithStats(key, dataStoreSummary);
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { performance } from "@fluid-internal/client-utils";
7
- import { IDeltaManager } from "@fluidframework/container-definitions";
7
+ import { IDeltaManager } from "@fluidframework/container-definitions/internal";
8
8
  import { IContainerRuntimeEvents } from "@fluidframework/container-runtime-definitions/internal";
9
9
  import { IEventProvider } from "@fluidframework/core-interfaces";
10
10
  import { assert } from "@fluidframework/core-utils/internal";
@@ -9,7 +9,6 @@ import {
9
9
  IAudience,
10
10
  ISelf,
11
11
  ICriticalContainerError,
12
- IDeltaManager,
13
12
  } from "@fluidframework/container-definitions";
14
13
  import {
15
14
  IBatchMessage,
@@ -19,6 +18,7 @@ import {
19
18
  IRuntime,
20
19
  LoaderHeader,
21
20
  type IAudienceEvents,
21
+ IDeltaManager,
22
22
  } from "@fluidframework/container-definitions/internal";
23
23
  import {
24
24
  IContainerRuntime,
@@ -28,11 +28,12 @@ import {
28
28
  FluidObject,
29
29
  IFluidHandle,
30
30
  IFluidHandleContext,
31
+ type IFluidHandleInternal,
31
32
  IProvideFluidHandleContext,
32
33
  IRequest,
33
34
  IResponse,
34
35
  ITelemetryBaseLogger,
35
- } from "@fluidframework/core-interfaces";
36
+ } from "@fluidframework/core-interfaces/internal";
36
37
  import { ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
37
38
  import {
38
39
  assert,
@@ -130,7 +131,7 @@ import { IPerfSignalReport, ReportOpPerfTelemetry } from "./connectionTelemetry.
130
131
  import { ContainerFluidHandleContext } from "./containerHandleContext.js";
131
132
  import { channelToDataStore } from "./dataStore.js";
132
133
  import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
133
- import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
134
+ import { DeltaManagerPendingOpsProxy, DeltaManagerSummarizerProxy } from "./deltaManagerProxies.js";
134
135
  import {
135
136
  GCNodeType,
136
137
  GarbageCollector,
@@ -465,10 +466,7 @@ export interface IContainerRuntimeOptions {
465
466
  * message to be sent to the service.
466
467
  * The grouping an ungrouping of such messages is handled by the "OpGroupingManager".
467
468
  *
468
- * By default, the feature is disabled. If enabled from options, the `Fluid.ContainerRuntime.DisableGroupedBatching`
469
- * flag can be used to disable it at runtime.
470
- *
471
- * @experimental Not ready for use.
469
+ * By default, the feature is enabled.
472
470
  */
473
471
  readonly enableGroupedBatching?: boolean;
474
472
 
@@ -801,7 +799,7 @@ export class ContainerRuntime
801
799
  maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
802
800
  enableRuntimeIdCompressor,
803
801
  chunkSizeInBytes = defaultChunkSizeInBytes,
804
- enableGroupedBatching = false,
802
+ enableGroupedBatching = true,
805
803
  explicitSchemaControl = false,
806
804
  } = runtimeOptions;
807
805
 
@@ -962,9 +960,6 @@ export class ContainerRuntime
962
960
  }
963
961
  };
964
962
 
965
- const disableGroupedBatching = mc.config.getBoolean(
966
- "Fluid.ContainerRuntime.DisableGroupedBatching",
967
- );
968
963
  const disableCompression = mc.config.getBoolean(
969
964
  "Fluid.ContainerRuntime.CompressionDisabled",
970
965
  );
@@ -973,8 +968,6 @@ export class ContainerRuntime
973
968
  compressionOptions.minimumBatchSizeInBytes !== Infinity &&
974
969
  compressionOptions.compressionAlgorithm === "lz4";
975
970
 
976
- const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
977
-
978
971
  const documentSchemaController = new DocumentsSchemaController(
979
972
  existing,
980
973
  protocolSequenceNumber,
@@ -983,7 +976,7 @@ export class ContainerRuntime
983
976
  explicitSchemaControl,
984
977
  compressionLz4,
985
978
  idCompressorMode,
986
- opGroupingEnabled,
979
+ opGroupingEnabled: enableGroupedBatching,
987
980
  disallowedVersions: [],
988
981
  },
989
982
  (schema) => {
@@ -992,7 +985,6 @@ export class ContainerRuntime
992
985
  );
993
986
 
994
987
  const featureGatesForTelemetry: Record<string, boolean | number | undefined> = {
995
- disableGroupedBatching,
996
988
  disableCompression,
997
989
  };
998
990
 
@@ -1394,6 +1386,7 @@ export class ContainerRuntime
1394
1386
  loader,
1395
1387
  pendingLocalState,
1396
1388
  supportedFeatures,
1389
+ snapshotWithContents,
1397
1390
  } = context;
1398
1391
 
1399
1392
  this.mc = createChildMonitoringContext({
@@ -1413,7 +1406,6 @@ export class ContainerRuntime
1413
1406
  };
1414
1407
 
1415
1408
  this.innerDeltaManager = deltaManager;
1416
- this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
1417
1409
 
1418
1410
  // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
1419
1411
  // This makes ContainerRuntime the final gatekeeper for outgoing messages.
@@ -1518,6 +1510,44 @@ export class ContainerRuntime
1518
1510
  opGroupingManager,
1519
1511
  );
1520
1512
 
1513
+ const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
1514
+ this.pendingStateManager = new PendingStateManager(
1515
+ {
1516
+ applyStashedOp: this.applyStashedOp.bind(this),
1517
+ clientId: () => this.clientId,
1518
+ close: this.closeFn,
1519
+ connected: () => this.connected,
1520
+ reSubmit: (message: IPendingBatchMessage) => {
1521
+ this.reSubmit(message);
1522
+ this.flush();
1523
+ },
1524
+ reSubmitBatch: this.reSubmitBatch.bind(this),
1525
+ isActiveConnection: () => this.innerDeltaManager.active,
1526
+ isAttached: () => this.attachState !== AttachState.Detached,
1527
+ },
1528
+ pendingRuntimeState?.pending,
1529
+ this.logger,
1530
+ );
1531
+
1532
+ let outerDeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
1533
+ const useDeltaManagerOpsProxy =
1534
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
1535
+ // The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
1536
+ const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
1537
+ outerDeltaManager = summarizerDeltaManagerProxy;
1538
+
1539
+ // The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
1540
+ // It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
1541
+ if (useDeltaManagerOpsProxy) {
1542
+ const pendingOpsDeltaManagerProxy = new DeltaManagerPendingOpsProxy(
1543
+ summarizerDeltaManagerProxy,
1544
+ this.pendingStateManager,
1545
+ );
1546
+ outerDeltaManager = pendingOpsDeltaManagerProxy;
1547
+ }
1548
+
1549
+ this.deltaManager = outerDeltaManager;
1550
+
1521
1551
  this.handleContext = new ContainerFluidHandleContext("", this);
1522
1552
 
1523
1553
  if (this.summaryConfiguration.state === "enabled") {
@@ -1543,8 +1573,6 @@ export class ContainerRuntime
1543
1573
  this._flushMode = runtimeOptions.flushMode;
1544
1574
  }
1545
1575
 
1546
- const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
1547
-
1548
1576
  if (context.attachState === AttachState.Attached) {
1549
1577
  const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
1550
1578
  if (
@@ -1616,8 +1644,19 @@ export class ContainerRuntime
1616
1644
  return this.submitSignalFn(envelope2, targetClientId);
1617
1645
  };
1618
1646
 
1647
+ let snapshot: ISnapshot | ISnapshotTree | undefined = getSummaryForDatastores(
1648
+ baseSnapshot,
1649
+ metadata,
1650
+ );
1651
+ if (snapshot !== undefined && snapshotWithContents !== undefined) {
1652
+ snapshot = {
1653
+ ...snapshotWithContents,
1654
+ snapshotTree: snapshot,
1655
+ };
1656
+ }
1657
+
1619
1658
  this.channelCollection = new ChannelCollection(
1620
- getSummaryForDatastores(baseSnapshot, metadata),
1659
+ snapshot,
1621
1660
  parentContext,
1622
1661
  this.mc.logger,
1623
1662
  (props) => this.garbageCollector.nodeUpdated(props),
@@ -1660,24 +1699,6 @@ export class ContainerRuntime
1660
1699
  createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }),
1661
1700
  );
1662
1701
 
1663
- this.pendingStateManager = new PendingStateManager(
1664
- {
1665
- applyStashedOp: this.applyStashedOp.bind(this),
1666
- clientId: () => this.clientId,
1667
- close: this.closeFn,
1668
- connected: () => this.connected,
1669
- reSubmit: (message: IPendingBatchMessage) => {
1670
- this.reSubmit(message);
1671
- this.flush();
1672
- },
1673
- reSubmitBatch: this.reSubmitBatch.bind(this),
1674
- isActiveConnection: () => this.innerDeltaManager.active,
1675
- isAttached: () => this.attachState !== AttachState.Detached,
1676
- },
1677
- pendingRuntimeState?.pending,
1678
- this.logger,
1679
- );
1680
-
1681
1702
  const disablePartialFlush = this.mc.config.getBoolean(
1682
1703
  "Fluid.ContainerRuntime.DisablePartialFlush",
1683
1704
  );
@@ -1729,7 +1750,7 @@ export class ContainerRuntime
1729
1750
  let oldClientId = this.clientId;
1730
1751
  this.on("connected", () => {
1731
1752
  const clientId = this.clientId;
1732
- assert(clientId !== undefined, "can't be undefined");
1753
+ assert(clientId !== undefined, 0x975 /* can't be undefined */);
1733
1754
  (audience as unknown as TypedEventEmitter<IAudienceEvents>).emit(
1734
1755
  "selfChanged",
1735
1756
  { clientId: oldClientId },
@@ -2321,6 +2342,7 @@ export class ContainerRuntime
2321
2342
  let newState: boolean;
2322
2343
 
2323
2344
  try {
2345
+ this.submitIdAllocationOpIfNeeded(true);
2324
2346
  // replay the ops
2325
2347
  this.pendingStateManager.replayPendingStates();
2326
2348
  } finally {
@@ -2373,8 +2395,6 @@ export class ContainerRuntime
2373
2395
  return;
2374
2396
  case ContainerMessageType.BlobAttach:
2375
2397
  return;
2376
- case ContainerMessageType.ChunkedOp:
2377
- throw new Error("chunkedOp not expected here");
2378
2398
  case ContainerMessageType.Rejoin:
2379
2399
  throw new Error("rejoin not expected here");
2380
2400
  case ContainerMessageType.GC:
@@ -2387,7 +2407,7 @@ export class ContainerRuntime
2387
2407
  const compatBehavior = opContents.compatDetails?.behavior;
2388
2408
  if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
2389
2409
  const error = DataProcessingError.create(
2390
- "Stashed runtime message of unknown type",
2410
+ "Stashed runtime message of unexpected type",
2391
2411
  "applyStashedOp",
2392
2412
  undefined /* sequencedMessage */,
2393
2413
  {
@@ -2420,7 +2440,7 @@ export class ContainerRuntime
2420
2440
  for (const range of ops) {
2421
2441
  compressor.finalizeCreationRange(range);
2422
2442
  }
2423
- assert(this.pendingIdCompressorOps.length === 0, "No new ops added");
2443
+ assert(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
2424
2444
  this._idCompressor = compressor;
2425
2445
  })
2426
2446
  .catch((error) => {
@@ -2434,8 +2454,11 @@ export class ContainerRuntime
2434
2454
  public setConnectionState(connected: boolean, clientId?: string) {
2435
2455
  // Validate we have consistent state
2436
2456
  const currentClientId = this._audience.getSelf()?.clientId;
2437
- assert(clientId === currentClientId, "input clientId does not match Audience");
2438
- assert(this.clientId === currentClientId, "this.clientId does not match Audience");
2457
+ assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
2458
+ assert(
2459
+ this.clientId === currentClientId,
2460
+ 0x978 /* this.clientId does not match Audience */,
2461
+ );
2439
2462
 
2440
2463
  if (connected && this.idCompressorMode === "delayed") {
2441
2464
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -2582,6 +2605,17 @@ export class ContainerRuntime
2582
2605
  */
2583
2606
  private processCore(messageWithContext: MessageWithContext) {
2584
2607
  const { message, local } = messageWithContext;
2608
+
2609
+ // Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
2610
+ // Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
2611
+ if (
2612
+ this.deltaManager.minimumSequenceNumber <
2613
+ messageWithContext.message.minimumSequenceNumber
2614
+ ) {
2615
+ messageWithContext.message.minimumSequenceNumber =
2616
+ this.deltaManager.minimumSequenceNumber;
2617
+ }
2618
+
2585
2619
  // Surround the actual processing of the operation with messages to the schedule manager indicating
2586
2620
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
2587
2621
  // messages once a batch has been fully processed.
@@ -2672,7 +2706,7 @@ export class ContainerRuntime
2672
2706
  } else {
2673
2707
  assert(
2674
2708
  this.pendingIdCompressorOps.length === 0,
2675
- "there should be no pending ops!",
2709
+ 0x979 /* there should be no pending ops! */,
2676
2710
  );
2677
2711
  this._idCompressor.finalizeCreationRange(range);
2678
2712
  }
@@ -3204,7 +3238,7 @@ export class ContainerRuntime
3204
3238
 
3205
3239
  return { stats, summary };
3206
3240
  } finally {
3207
- this.mc.logger.sendTelemetryEvent({
3241
+ summaryLogger.sendTelemetryEvent({
3208
3242
  eventName: "SummarizeTelemetry",
3209
3243
  details: telemetryContext.serialize(),
3210
3244
  });
@@ -3880,14 +3914,16 @@ export class ContainerRuntime
3880
3914
  public async uploadBlob(
3881
3915
  blob: ArrayBufferLike,
3882
3916
  signal?: AbortSignal,
3883
- ): Promise<IFluidHandle<ArrayBufferLike>> {
3917
+ ): Promise<IFluidHandleInternal<ArrayBufferLike>> {
3884
3918
  this.verifyNotClosed();
3885
3919
  return this.blobManager.createBlob(blob, signal);
3886
3920
  }
3887
3921
 
3888
- private submitIdAllocationOpIfNeeded(): void {
3922
+ private submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false): void {
3889
3923
  if (this._idCompressor) {
3890
- const idRange = this._idCompressor.takeNextCreationRange();
3924
+ const idRange = resubmitOutstandingRanges
3925
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
3926
+ : this._idCompressor.takeNextCreationRange();
3891
3927
  // Don't include the idRange if there weren't any Ids allocated
3892
3928
  if (idRange?.ids !== undefined) {
3893
3929
  const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
@@ -4103,11 +4139,15 @@ export class ContainerRuntime
4103
4139
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
4104
4140
  break;
4105
4141
  case ContainerMessageType.IdAllocation: {
4106
- this.submit(message, localOpMetadata);
4142
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
4143
+ // avoid being submitted out of order. For example, if the pending state manager contained
4144
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
4145
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
4146
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
4147
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
4148
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
4107
4149
  break;
4108
4150
  }
4109
- case ContainerMessageType.ChunkedOp:
4110
- throw new Error(`chunkedOp not expected here`);
4111
4151
  case ContainerMessageType.BlobAttach:
4112
4152
  this.blobManager.reSubmit(opMetadata);
4113
4153
  break;
@@ -4134,7 +4174,7 @@ export class ContainerRuntime
4134
4174
  });
4135
4175
  } else {
4136
4176
  const error = DataProcessingError.create(
4137
- "Resubmitting runtime message of unknown type",
4177
+ "Resubmitting runtime message of unexpected type",
4138
4178
  "reSubmitCore",
4139
4179
  undefined /* sequencedMessage */,
4140
4180
  {
package/src/dataStore.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { AttachState } from "@fluidframework/container-definitions";
7
- import { FluidObject, IFluidHandle } from "@fluidframework/core-interfaces";
7
+ import { FluidObject, type IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
8
8
  import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
9
9
  import {
10
10
  AliasResult,
@@ -169,7 +169,7 @@ class DataStore implements IDataStore {
169
169
  /**
170
170
  * {@inheritDoc @fluidframework/runtime-definitions#IDataStore.entryPoint}
171
171
  */
172
- get entryPoint(): IFluidHandle<FluidObject> {
172
+ get entryPoint(): IFluidHandleInternal<FluidObject> {
173
173
  return this.fluidDataStoreChannel.entryPoint;
174
174
  }
175
175