@fluidframework/container-loader 2.63.0-359962 → 2.63.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 (75) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/container-loader.legacy.alpha.api.md +28 -0
  3. package/dist/container.d.ts.map +1 -1
  4. package/dist/container.js +10 -6
  5. package/dist/container.js.map +1 -1
  6. package/dist/containerStorageAdapter.d.ts +6 -12
  7. package/dist/containerStorageAdapter.d.ts.map +1 -1
  8. package/dist/containerStorageAdapter.js +8 -13
  9. package/dist/containerStorageAdapter.js.map +1 -1
  10. package/dist/createAndLoadContainerUtils.d.ts +13 -0
  11. package/dist/createAndLoadContainerUtils.d.ts.map +1 -1
  12. package/dist/createAndLoadContainerUtils.js +117 -1
  13. package/dist/createAndLoadContainerUtils.js.map +1 -1
  14. package/dist/index.d.ts +2 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/legacyAlpha.d.ts +6 -1
  19. package/dist/packageVersion.d.ts +1 -1
  20. package/dist/packageVersion.d.ts.map +1 -1
  21. package/dist/packageVersion.js +1 -1
  22. package/dist/packageVersion.js.map +1 -1
  23. package/dist/serializedStateManager.d.ts +2 -2
  24. package/dist/serializedStateManager.d.ts.map +1 -1
  25. package/dist/serializedStateManager.js +2 -1
  26. package/dist/serializedStateManager.js.map +1 -1
  27. package/dist/summarizerResultTypes.d.ts +96 -0
  28. package/dist/summarizerResultTypes.d.ts.map +1 -0
  29. package/dist/summarizerResultTypes.js +9 -0
  30. package/dist/summarizerResultTypes.js.map +1 -0
  31. package/dist/utils.d.ts +1 -2
  32. package/dist/utils.d.ts.map +1 -1
  33. package/dist/utils.js +12 -11
  34. package/dist/utils.js.map +1 -1
  35. package/lib/container.d.ts.map +1 -1
  36. package/lib/container.js +11 -7
  37. package/lib/container.js.map +1 -1
  38. package/lib/containerStorageAdapter.d.ts +6 -12
  39. package/lib/containerStorageAdapter.d.ts.map +1 -1
  40. package/lib/containerStorageAdapter.js +9 -14
  41. package/lib/containerStorageAdapter.js.map +1 -1
  42. package/lib/createAndLoadContainerUtils.d.ts +13 -0
  43. package/lib/createAndLoadContainerUtils.d.ts.map +1 -1
  44. package/lib/createAndLoadContainerUtils.js +115 -0
  45. package/lib/createAndLoadContainerUtils.js.map +1 -1
  46. package/lib/index.d.ts +2 -1
  47. package/lib/index.d.ts.map +1 -1
  48. package/lib/index.js +1 -1
  49. package/lib/index.js.map +1 -1
  50. package/lib/legacyAlpha.d.ts +6 -1
  51. package/lib/packageVersion.d.ts +1 -1
  52. package/lib/packageVersion.d.ts.map +1 -1
  53. package/lib/packageVersion.js +1 -1
  54. package/lib/packageVersion.js.map +1 -1
  55. package/lib/serializedStateManager.d.ts +2 -2
  56. package/lib/serializedStateManager.d.ts.map +1 -1
  57. package/lib/serializedStateManager.js +2 -1
  58. package/lib/serializedStateManager.js.map +1 -1
  59. package/lib/summarizerResultTypes.d.ts +96 -0
  60. package/lib/summarizerResultTypes.d.ts.map +1 -0
  61. package/lib/summarizerResultTypes.js +6 -0
  62. package/lib/summarizerResultTypes.js.map +1 -0
  63. package/lib/utils.d.ts +1 -2
  64. package/lib/utils.d.ts.map +1 -1
  65. package/lib/utils.js +12 -11
  66. package/lib/utils.js.map +1 -1
  67. package/package.json +11 -11
  68. package/src/container.ts +13 -11
  69. package/src/containerStorageAdapter.ts +9 -12
  70. package/src/createAndLoadContainerUtils.ts +174 -0
  71. package/src/index.ts +7 -0
  72. package/src/packageVersion.ts +1 -1
  73. package/src/serializedStateManager.ts +6 -3
  74. package/src/summarizerResultTypes.ts +115 -0
  75. package/src/utils.ts +15 -14
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
6
+ import { bufferToString } from "@fluid-internal/client-utils";
7
7
  import type {
8
8
  ISnapshotTreeWithBlobContents,
9
9
  IContainerStorageService,
@@ -71,6 +71,11 @@ export class ContainerStorageAdapter
71
71
  return this._loadedGroupIdSnapshots;
72
72
  }
73
73
 
74
+ /**
75
+ * ArrayBufferLikes containing blobs from a snapshot
76
+ */
77
+ private readonly blobContents: { [id: string]: ArrayBufferLike } = {};
78
+
74
79
  /**
75
80
  * An adapter that ensures we're using detachedBlobStorage up until we connect to a real service, and then
76
81
  * after connecting to a real service augments it with retry and combined summary tree enforcement.
@@ -84,10 +89,6 @@ export class ContainerStorageAdapter
84
89
  public constructor(
85
90
  detachedBlobStorage: MemoryDetachedBlobStorage | undefined,
86
91
  private readonly logger: ITelemetryLoggerExt,
87
- /**
88
- * ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
89
- */
90
- private readonly blobContents: { [id: string]: ArrayBufferLike | string } = {},
91
92
  private loadingGroupIdSnapshotsFromPendingState:
92
93
  | Record<string, SerializedSnapshotInfo>
93
94
  | undefined,
@@ -143,9 +144,9 @@ export class ContainerStorageAdapter
143
144
  );
144
145
  }
145
146
 
146
- public loadSnapshotFromSnapshotBlobs(snapshotBlobs: ISerializableBlobContents): void {
147
- for (const [id, value] of Object.entries(snapshotBlobs)) {
148
- this.blobContents[id] = value;
147
+ public cacheSnapshotBlobs(snapshotBlobs: Map<string, ArrayBuffer>): void {
148
+ for (const [id, value] of snapshotBlobs.entries()) {
149
+ this.blobContents[id] ??= value;
149
150
  }
150
151
  }
151
152
 
@@ -220,10 +221,6 @@ export class ContainerStorageAdapter
220
221
  public async readBlob(id: string): Promise<ArrayBufferLike> {
221
222
  const maybeBlob = this.blobContents[id];
222
223
  if (maybeBlob !== undefined) {
223
- if (typeof maybeBlob === "string") {
224
- const blob = stringToBuffer(maybeBlob, "utf8");
225
- return blob;
226
- }
227
224
  return maybeBlob;
228
225
  }
229
226
  return this._storageService.readBlob(id);
@@ -9,6 +9,7 @@ import type {
9
9
  IFluidCodeDetails,
10
10
  IContainerPolicies,
11
11
  } from "@fluidframework/container-definitions/internal";
12
+ import { LoaderHeader } from "@fluidframework/container-definitions/internal";
12
13
  import type {
13
14
  FluidObject,
14
15
  IConfigProviderBase,
@@ -20,10 +21,44 @@ import type {
20
21
  IDocumentServiceFactory,
21
22
  IUrlResolver,
22
23
  } from "@fluidframework/driver-definitions/internal";
24
+ import { DriverHeader } from "@fluidframework/driver-definitions/internal";
25
+ import {
26
+ GenericError,
27
+ normalizeError,
28
+ createChildMonitoringContext,
29
+ mixinMonitoringContext,
30
+ sessionStorageConfigProvider,
31
+ PerformanceEvent,
32
+ isFluidError,
33
+ } from "@fluidframework/telemetry-utils/internal";
34
+ import { v4 as uuid } from "uuid";
23
35
 
36
+ import { DebugLogger } from "./debugLogger.js";
24
37
  import { createFrozenDocumentServiceFactory } from "./frozenServices.js";
25
38
  import { Loader } from "./loader.js";
39
+ import { pkgVersion } from "./packageVersion.js";
26
40
  import type { ProtocolHandlerBuilder } from "./protocol.js";
41
+ import type {
42
+ LoadSummarizerSummaryResult,
43
+ OnDemandSummaryResults,
44
+ SummarizeOnDemandResults,
45
+ } from "./summarizerResultTypes.js";
46
+
47
+ interface OnDemandSummarizeResultsPromises {
48
+ readonly summarySubmitted: Promise<SummarizeOnDemandResults["summarySubmitted"]>;
49
+ readonly summaryOpBroadcasted: Promise<SummarizeOnDemandResults["summaryOpBroadcasted"]>;
50
+ }
51
+
52
+ interface OnDemandSummarizeOptions {
53
+ readonly reason?: string;
54
+ readonly retryOnFailure?: boolean;
55
+ readonly fullTree?: boolean;
56
+ }
57
+
58
+ interface SummarizerLike {
59
+ readonly ISummarizer?: SummarizerLike;
60
+ summarizeOnDemand(options: OnDemandSummarizeOptions): OnDemandSummarizeResultsPromises;
61
+ }
27
62
 
28
63
  /**
29
64
  * Properties necessary for creating and loading a container.
@@ -103,6 +138,15 @@ export interface ILoadExistingContainerProps extends ICreateAndLoadContainerProp
103
138
  readonly pendingLocalState?: string | undefined;
104
139
  }
105
140
 
141
+ /**
142
+ * Props used to load summarizer container.
143
+ * @legacy @alpha
144
+ */
145
+ export type ILoadSummarizerContainerProps = Omit<
146
+ ILoadExistingContainerProps,
147
+ "pendingLocalState"
148
+ >;
149
+
106
150
  /**
107
151
  * Props used to create a detached container.
108
152
  * @legacy @beta
@@ -200,3 +244,133 @@ export async function loadFrozenContainerFromPendingState(
200
244
  documentServiceFactory: createFrozenDocumentServiceFactory(props.documentServiceFactory),
201
245
  });
202
246
  }
247
+
248
+ /**
249
+ * Loads a summarizer container with the required headers, triggers an on-demand summary, and then closes it.
250
+ * Returns success/failure and an optional error for host-side handling.
251
+ *
252
+ * @legacy @alpha
253
+ */
254
+ export async function loadSummarizerContainerAndMakeSummary(
255
+ loadSummarizerContainerProps: ILoadSummarizerContainerProps,
256
+ ): Promise<LoadSummarizerSummaryResult> {
257
+ const { logger, configProvider, request: originalRequest } = loadSummarizerContainerProps;
258
+ const telemetryProps = {
259
+ loaderId: uuid(),
260
+ loaderVersion: pkgVersion,
261
+ };
262
+
263
+ const subMc = mixinMonitoringContext(
264
+ DebugLogger.mixinDebugLogger("fluid:telemetry", logger, {
265
+ all: telemetryProps,
266
+ }),
267
+ sessionStorageConfigProvider.value,
268
+ configProvider,
269
+ );
270
+ const mc = createChildMonitoringContext({
271
+ logger: subMc.logger,
272
+ namespace: "SummarizerOnDemand",
273
+ });
274
+ return PerformanceEvent.timedExecAsync(
275
+ mc.logger,
276
+ { eventName: "SummarizerOnDemandSummary" },
277
+ async (event) => {
278
+ const baseHeaders = originalRequest.headers;
279
+ const request = {
280
+ ...originalRequest,
281
+ headers: {
282
+ ...baseHeaders,
283
+ [LoaderHeader.cache]: false,
284
+ [LoaderHeader.clientDetails]: {
285
+ capabilities: { interactive: false },
286
+ type: "summarizer",
287
+ },
288
+ [DriverHeader.summarizingClient]: true,
289
+ [LoaderHeader.reconnect]: false,
290
+ },
291
+ };
292
+
293
+ const container = await loadExistingContainer({
294
+ ...loadSummarizerContainerProps,
295
+ request,
296
+ });
297
+
298
+ let summarySubmitted: SummarizeOnDemandResults["summarySubmitted"];
299
+ let summaryOpBroadcasted: SummarizeOnDemandResults["summaryOpBroadcasted"];
300
+ try {
301
+ if (container.getEntryPoint === undefined) {
302
+ throw new GenericError("container.getEntryPoint() is undefined");
303
+ }
304
+ const fluidObject = (await container.getEntryPoint()) as FluidObject<SummarizerLike>;
305
+ const summarizer = fluidObject?.ISummarizer;
306
+ if (summarizer === undefined) {
307
+ throw new GenericError("Summarizer entry point not available");
308
+ }
309
+ // Host controlled feature gate for fullTree
310
+ // Default value will be false
311
+ const fullTreeGate =
312
+ mc.config.getBoolean("Fluid.Summarizer.FullTree.OnDemand") === true;
313
+
314
+ const summarizeResults: OnDemandSummarizeResultsPromises =
315
+ summarizer.summarizeOnDemand({
316
+ reason: "summaryOnRequest",
317
+ retryOnFailure: true,
318
+ fullTree: fullTreeGate,
319
+ });
320
+ [summarySubmitted, summaryOpBroadcasted] = await Promise.all([
321
+ summarizeResults.summarySubmitted,
322
+ summarizeResults.summaryOpBroadcasted,
323
+ ]);
324
+
325
+ const summaryResults: OnDemandSummaryResults = {
326
+ summarySubmitted: summarySubmitted.success,
327
+ summaryInfo: summarySubmitted.success
328
+ ? {
329
+ stage: summarySubmitted.data.stage,
330
+ handle: summaryOpBroadcasted.success
331
+ ? summaryOpBroadcasted.data.summarizeOp.contents.handle
332
+ : undefined,
333
+ }
334
+ : {},
335
+ summaryOpBroadcasted: summaryOpBroadcasted.success,
336
+ };
337
+
338
+ if (summarySubmitted.success && summaryOpBroadcasted.success) {
339
+ event.end({
340
+ success: true,
341
+ summarySubmitted: true,
342
+ summaryOpBroadcasted: true,
343
+ });
344
+ return {
345
+ success: true,
346
+ summaryResults,
347
+ };
348
+ }
349
+
350
+ const failureError =
351
+ summarySubmitted.success === false
352
+ ? summarySubmitted.error
353
+ : summaryOpBroadcasted.success === false
354
+ ? summaryOpBroadcasted.error
355
+ : new GenericError("On demand summary failed");
356
+
357
+ event.end({
358
+ success: false,
359
+ summarySubmitted: summarySubmitted.success,
360
+ summaryOpBroadcasted: summaryOpBroadcasted.success,
361
+ });
362
+ return {
363
+ success: false,
364
+ error: failureError,
365
+ };
366
+ } catch (error) {
367
+ event.cancel({ success: false }, error);
368
+ const caughtError = isFluidError(error) ? error : normalizeError(error);
369
+ return { success: false, error: caughtError };
370
+ } finally {
371
+ container.dispose();
372
+ }
373
+ },
374
+ { start: true, end: true, cancel: "generic" },
375
+ );
376
+ }
package/src/index.ts CHANGED
@@ -11,12 +11,19 @@ export {
11
11
  loadExistingContainer,
12
12
  rehydrateDetachedContainer,
13
13
  loadFrozenContainerFromPendingState,
14
+ loadSummarizerContainerAndMakeSummary,
14
15
  type ICreateAndLoadContainerProps,
15
16
  type ICreateDetachedContainerProps,
16
17
  type ILoadExistingContainerProps,
18
+ type ILoadSummarizerContainerProps,
17
19
  type IRehydrateDetachedContainerProps,
18
20
  type ILoadFrozenContainerFromPendingStateProps,
19
21
  } from "./createAndLoadContainerUtils.js";
22
+ export type {
23
+ LoadSummarizerSummaryResult,
24
+ OnDemandSummaryResults,
25
+ SummaryStage,
26
+ } from "./summarizerResultTypes.js";
20
27
  export {
21
28
  type ICodeDetailsLoader,
22
29
  type IFluidModuleWithDetails,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.63.0-359962";
9
+ export const pkgVersion = "2.63.0";
@@ -32,6 +32,7 @@ import {
32
32
 
33
33
  import {
34
34
  getBlobContentsFromTree,
35
+ type ContainerStorageAdapter,
35
36
  type ISerializableBlobContents,
36
37
  } from "./containerStorageAdapter.js";
37
38
  import {
@@ -133,8 +134,8 @@ interface ISnapshotInfo {
133
134
  }
134
135
 
135
136
  export type ISerializedStateManagerDocumentStorageService = Pick<
136
- IDocumentStorageService,
137
- "getSnapshot" | "getSnapshotTree" | "getVersions" | "readBlob"
137
+ ContainerStorageAdapter,
138
+ "getSnapshot" | "getSnapshotTree" | "getVersions" | "readBlob" | "cacheSnapshotBlobs"
138
139
  > & {
139
140
  loadedGroupIdSnapshots: Record<string, ISnapshot>;
140
141
  };
@@ -300,11 +301,13 @@ export class SerializedStateManager implements IDisposable {
300
301
  return { snapshot, version, attributes };
301
302
  } else {
302
303
  const { baseSnapshot, snapshotBlobs, savedOps } = pendingLocalState;
303
- const attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshot);
304
304
  const blobContents = new Map<string, ArrayBuffer>();
305
305
  for (const [id, value] of Object.entries(snapshotBlobs)) {
306
306
  blobContents.set(id, stringToBuffer(value, "utf8"));
307
307
  }
308
+ this.storageAdapter.cacheSnapshotBlobs(blobContents);
309
+ const attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshot);
310
+
308
311
  const snapshot: ISnapshot = {
309
312
  sequenceNumber: attributes.sequenceNumber,
310
313
  snapshotTree: baseSnapshot,
@@ -0,0 +1,115 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type { IErrorBase } from "@fluidframework/core-interfaces";
7
+ import type {
8
+ ISequencedDocumentMessage,
9
+ ISummaryAck,
10
+ ISummaryContent,
11
+ ISummaryTree,
12
+ MessageType,
13
+ } from "@fluidframework/driver-definitions/internal";
14
+
15
+ export const summarizerRequestUrl = "_summarizer";
16
+
17
+ /**
18
+ * Stages of summary process.
19
+ *
20
+ * Stages:
21
+ *
22
+ * 1. "base" - stopped before the summary tree was even generated, and the result only contains the base data
23
+ *
24
+ * 2. "generate" - the summary tree was generated, and the result will contain that tree + stats
25
+ *
26
+ * 3. "upload" - the summary was uploaded to storage, and the result contains the server-provided handle
27
+ *
28
+ * 4. "submit" - the summarize op was submitted, and the result contains the op client sequence number.
29
+ *
30
+ * @legacy @alpha
31
+ */
32
+ export type SummaryStage = "base" | "generate" | "upload" | "submit" | "unknown";
33
+
34
+ type OnDemandSummaryStageResult<TSuccess> =
35
+ | {
36
+ readonly success: true;
37
+ readonly data: TSuccess;
38
+ }
39
+ | {
40
+ readonly success: false;
41
+ readonly error: IErrorBase;
42
+ };
43
+
44
+ interface ISummaryOpMessage extends ISequencedDocumentMessage {
45
+ type: MessageType.Summarize;
46
+ contents: ISummaryContent;
47
+ }
48
+
49
+ interface ISummaryAckMessage extends ISequencedDocumentMessage {
50
+ type: MessageType.SummaryAck;
51
+ contents: ISummaryAck;
52
+ }
53
+
54
+ /**
55
+ * @internal
56
+ */
57
+ export interface SummarizeOnDemandResults {
58
+ readonly summarySubmitted: OnDemandSummaryStageResult<{
59
+ readonly stage: SummaryStage;
60
+ readonly summaryTree?: ISummaryTree;
61
+ readonly handle?: string;
62
+ }>;
63
+ readonly summaryOpBroadcasted: OnDemandSummaryStageResult<{
64
+ readonly broadcastDuration: number;
65
+ readonly summarizeOp: ISummaryOpMessage;
66
+ }>;
67
+ readonly receivedSummaryAckOrNack: OnDemandSummaryStageResult<{
68
+ readonly summaryAckOp: ISummaryAckMessage;
69
+ readonly ackNackDuration: number;
70
+ }>;
71
+ }
72
+
73
+ /**
74
+ * Results from an on-demand summary request.
75
+ * @legacy @alpha
76
+ */
77
+ export interface OnDemandSummaryResults {
78
+ /**
79
+ * True if summary was generated, uploaded, and submitted.
80
+ */
81
+ readonly summarySubmitted: boolean;
82
+
83
+ /**
84
+ * Information about the summary that was submitted, if any.
85
+ */
86
+ readonly summaryInfo: {
87
+ /**
88
+ * Stage at which summary process ended.
89
+ */
90
+ readonly stage?: SummaryStage;
91
+ /**
92
+ * Handle of the complete summary.
93
+ */
94
+ readonly handle?: string;
95
+ };
96
+
97
+ /**
98
+ * True if summarize op broadcast was observed.
99
+ */
100
+ readonly summaryOpBroadcasted: boolean;
101
+ }
102
+
103
+ /**
104
+ * Outcome from {@link loadSummarizerContainerAndMakeSummary}.
105
+ * @legacy @alpha
106
+ */
107
+ export type LoadSummarizerSummaryResult =
108
+ | {
109
+ readonly success: true;
110
+ readonly summaryResults: OnDemandSummaryResults;
111
+ }
112
+ | {
113
+ readonly success: false;
114
+ readonly error: IErrorBase;
115
+ };
package/src/utils.ts CHANGED
@@ -274,33 +274,34 @@ export function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree
274
274
  return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
275
275
  }
276
276
 
277
- export const combineSnapshotTreeAndSnapshotBlobs = (
278
- baseSnapshot: ISnapshotTree,
279
- snapshotBlobs: ISerializableBlobContents,
280
- ): ISnapshotTreeWithBlobContents => {
281
- const blobsContents: { [path: string]: ArrayBufferLike } = {};
277
+ export const combineSnapshotTreeAndSnapshotBlobs = ({
278
+ blobContents,
279
+ snapshotTree,
280
+ }: Pick<ISnapshot, "blobContents" | "snapshotTree">): ISnapshotTreeWithBlobContents => {
281
+ const currentTreeBlobs: { [path: string]: ArrayBufferLike } = {};
282
282
 
283
283
  // Process blobs in the current level
284
- for (const [, id] of Object.entries(baseSnapshot.blobs)) {
285
- if (snapshotBlobs[id] !== undefined) {
286
- blobsContents[id] = stringToBuffer(snapshotBlobs[id], "utf8");
284
+ for (const [, id] of Object.entries(snapshotTree.blobs)) {
285
+ const blob = blobContents.get(id);
286
+ if (blob !== undefined) {
287
+ currentTreeBlobs[id] = blob;
287
288
  }
288
289
  }
289
290
 
290
291
  // Recursively process trees in the current level
291
292
  const trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};
292
- for (const [path, tree] of Object.entries(baseSnapshot.trees)) {
293
- trees[path] = combineSnapshotTreeAndSnapshotBlobs(tree, snapshotBlobs);
293
+ for (const [path, tree] of Object.entries(snapshotTree.trees)) {
294
+ trees[path] = combineSnapshotTreeAndSnapshotBlobs({ snapshotTree: tree, blobContents });
294
295
  }
295
296
 
296
297
  // Create a new snapshot tree with blob contents and processed trees
297
- const snapshotTreeWithBlobContents: ISnapshotTreeWithBlobContents = {
298
- ...baseSnapshot,
299
- blobsContents,
298
+ const snapshot: ISnapshotTreeWithBlobContents = {
299
+ ...snapshotTree,
300
+ blobsContents: currentTreeBlobs,
300
301
  trees,
301
302
  };
302
303
 
303
- return snapshotTreeWithBlobContents;
304
+ return snapshot;
304
305
  };
305
306
 
306
307
  export function isDeltaStreamConnectionForbiddenError(