@fluidframework/container-loader 2.0.0-rc.3.0.0 → 2.0.0-rc.3.0.10

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 (55) hide show
  1. package/api-report/container-loader.api.md +3 -1
  2. package/dist/attachment.d.ts.map +1 -1
  3. package/dist/attachment.js.map +1 -1
  4. package/dist/container.d.ts.map +1 -1
  5. package/dist/container.js +16 -5
  6. package/dist/container.js.map +1 -1
  7. package/dist/containerStorageAdapter.d.ts.map +1 -1
  8. package/dist/containerStorageAdapter.js +7 -2
  9. package/dist/containerStorageAdapter.js.map +1 -1
  10. package/dist/loader.d.ts +7 -0
  11. package/dist/loader.d.ts.map +1 -1
  12. package/dist/loader.js.map +1 -1
  13. package/dist/memoryBlobStorage.d.ts +9 -0
  14. package/dist/memoryBlobStorage.d.ts.map +1 -0
  15. package/dist/memoryBlobStorage.js +60 -0
  16. package/dist/memoryBlobStorage.js.map +1 -0
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.d.ts.map +1 -1
  19. package/dist/packageVersion.js +1 -1
  20. package/dist/packageVersion.js.map +1 -1
  21. package/dist/serializedStateManager.d.ts +6 -0
  22. package/dist/serializedStateManager.d.ts.map +1 -1
  23. package/dist/serializedStateManager.js.map +1 -1
  24. package/lib/attachment.d.ts.map +1 -1
  25. package/lib/attachment.js.map +1 -1
  26. package/lib/container.d.ts.map +1 -1
  27. package/lib/container.js +16 -5
  28. package/lib/container.js.map +1 -1
  29. package/lib/containerStorageAdapter.d.ts.map +1 -1
  30. package/lib/containerStorageAdapter.js +7 -2
  31. package/lib/containerStorageAdapter.js.map +1 -1
  32. package/lib/loader.d.ts +7 -0
  33. package/lib/loader.d.ts.map +1 -1
  34. package/lib/loader.js.map +1 -1
  35. package/lib/memoryBlobStorage.d.ts +9 -0
  36. package/lib/memoryBlobStorage.d.ts.map +1 -0
  37. package/lib/memoryBlobStorage.js +54 -0
  38. package/lib/memoryBlobStorage.js.map +1 -0
  39. package/lib/packageVersion.d.ts +1 -1
  40. package/lib/packageVersion.d.ts.map +1 -1
  41. package/lib/packageVersion.js +1 -1
  42. package/lib/packageVersion.js.map +1 -1
  43. package/lib/serializedStateManager.d.ts +6 -0
  44. package/lib/serializedStateManager.d.ts.map +1 -1
  45. package/lib/serializedStateManager.js.map +1 -1
  46. package/package.json +13 -13
  47. package/src/attachment.ts +2 -0
  48. package/src/container.ts +24 -4
  49. package/src/containerStorageAdapter.ts +4 -0
  50. package/src/loader.ts +8 -0
  51. package/src/memoryBlobStorage.ts +83 -0
  52. package/src/packageVersion.ts +1 -1
  53. package/src/serializedStateManager.ts +6 -0
  54. package/dist/public.d.ts +0 -14
  55. package/lib/public.d.ts +0 -14
package/src/attachment.ts CHANGED
@@ -9,6 +9,7 @@ import { IDocumentStorageService } from "@fluidframework/driver-definitions/inte
9
9
  import { CombinedAppAndProtocolSummary } from "@fluidframework/driver-utils/internal";
10
10
  import { ISummaryTree } from "@fluidframework/protocol-definitions";
11
11
 
12
+ // eslint-disable-next-line import/no-deprecated
12
13
  import { IDetachedBlobStorage } from "./loader.js";
13
14
  import type { SnapshotWithBlobs } from "./serializedStateManager.js";
14
15
  import { getSnapshotTreeAndBlobsFromSerializedContainer } from "./utils.js";
@@ -110,6 +111,7 @@ export interface AttachProcessProps {
110
111
  /**
111
112
  * The detached blob storage if it exists.
112
113
  */
114
+ // eslint-disable-next-line import/no-deprecated
113
115
  readonly detachedBlobStorage?: Pick<IDetachedBlobStorage, "getBlobIds" | "readBlob" | "size">;
114
116
 
115
117
  /**
package/src/container.ts CHANGED
@@ -109,6 +109,7 @@ import {
109
109
  getPackageName,
110
110
  } from "./contracts.js";
111
111
  import { DeltaManager, IConnectionArgs } from "./deltaManager.js";
112
+ // eslint-disable-next-line import/no-deprecated
112
113
  import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader.js";
113
114
  import { NoopHeuristic } from "./noopHeuristic.js";
114
115
  import { pkgVersion } from "./packageVersion.js";
@@ -134,6 +135,11 @@ import {
134
135
  getSnapshotTreeAndBlobsFromSerializedContainer,
135
136
  runSingle,
136
137
  } from "./utils.js";
138
+ import {
139
+ serializeMemoryDetachedBlobStorage,
140
+ createMemoryDetachedBlobStorage,
141
+ tryInitializeMemoryDetachedBlobStorage,
142
+ } from "./memoryBlobStorage.js";
137
143
 
138
144
  const detachedContainerRefSeqNumber = 0;
139
145
 
@@ -221,6 +227,7 @@ export interface IContainerCreateProps {
221
227
  /**
222
228
  * Blobs storage for detached containers.
223
229
  */
230
+ // eslint-disable-next-line import/no-deprecated
224
231
  readonly detachedBlobStorage?: IDetachedBlobStorage;
225
232
 
226
233
  /**
@@ -472,6 +479,7 @@ export class Container
472
479
  private readonly options: ILoaderOptions;
473
480
  private readonly scope: FluidObject;
474
481
  private readonly subLogger: ITelemetryLoggerExt;
482
+ // eslint-disable-next-line import/no-deprecated
475
483
  private readonly detachedBlobStorage: IDetachedBlobStorage | undefined;
476
484
  private readonly protocolHandlerBuilder: ProtocolHandlerBuilder;
477
485
  private readonly client: IClient;
@@ -750,7 +758,6 @@ export class Container
750
758
  // Tracking alternative ways to handle this in AB#4129.
751
759
  this.options = { ...options };
752
760
  this.scope = scope;
753
- this.detachedBlobStorage = detachedBlobStorage;
754
761
  this.protocolHandlerBuilder =
755
762
  protocolHandlerBuilder ??
756
763
  ((
@@ -916,8 +923,14 @@ export class Container
916
923
  this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
917
924
  options.summarizeProtocolTree;
918
925
 
926
+ this.detachedBlobStorage =
927
+ detachedBlobStorage ??
928
+ (this.mc.config.getBoolean("Fluid.Container.MemoryBlobStorageEnabled") === true
929
+ ? createMemoryDetachedBlobStorage()
930
+ : undefined);
931
+
919
932
  this.storageAdapter = new ContainerStorageAdapter(
920
- detachedBlobStorage,
933
+ this.detachedBlobStorage,
921
934
  this.mc.logger,
922
935
  pendingLocalState?.snapshotBlobs,
923
936
  addProtocolSummaryIfMissing,
@@ -1167,7 +1180,9 @@ export class Container
1167
1180
  baseSnapshot,
1168
1181
  snapshotBlobs,
1169
1182
  pendingRuntimeState,
1170
- hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1183
+ hasAttachmentBlobs:
1184
+ this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0,
1185
+ attachmentBlobs: serializeMemoryDetachedBlobStorage(this.detachedBlobStorage),
1171
1186
  };
1172
1187
  return JSON.stringify(detachedContainerState);
1173
1188
  }
@@ -1284,6 +1299,7 @@ export class Container
1284
1299
  const snapshotWithBlobs = await attachP;
1285
1300
  this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
1286
1301
  if (!this.closed) {
1302
+ this.detachedBlobStorage?.dispose?.();
1287
1303
  this.handleDeltaConnectionArg(
1288
1304
  {
1289
1305
  fetchOpsFromStorage: false,
@@ -1774,11 +1790,15 @@ export class Container
1774
1790
  baseSnapshot,
1775
1791
  snapshotBlobs,
1776
1792
  hasAttachmentBlobs,
1793
+ attachmentBlobs,
1777
1794
  pendingRuntimeState,
1778
1795
  }: IPendingDetachedContainerState) {
1779
1796
  if (hasAttachmentBlobs) {
1797
+ if (attachmentBlobs !== undefined) {
1798
+ tryInitializeMemoryDetachedBlobStorage(this.detachedBlobStorage, attachmentBlobs);
1799
+ }
1780
1800
  assert(
1781
- !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1801
+ this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0,
1782
1802
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1783
1803
  );
1784
1804
  }
@@ -26,6 +26,7 @@ import {
26
26
  } from "@fluidframework/protocol-definitions";
27
27
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
28
28
 
29
+ // eslint-disable-next-line import/no-deprecated
29
30
  import { IDetachedBlobStorage } from "./loader.js";
30
31
  import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService.js";
31
32
  import { RetriableDocumentStorageService } from "./retriableDocumentStorageService.js";
@@ -63,6 +64,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
63
64
  * @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
64
65
  */
65
66
  public constructor(
67
+ // eslint-disable-next-line import/no-deprecated
66
68
  detachedBlobStorage: IDetachedBlobStorage | undefined,
67
69
  private readonly logger: ITelemetryLoggerExt,
68
70
  /**
@@ -178,6 +180,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
178
180
  */
179
181
  class BlobOnlyStorage implements IDocumentStorageService {
180
182
  constructor(
183
+ // eslint-disable-next-line import/no-deprecated
181
184
  private readonly detachedStorage: IDetachedBlobStorage | undefined,
182
185
  private readonly logger: ITelemetryLoggerExt,
183
186
  ) {}
@@ -190,6 +193,7 @@ class BlobOnlyStorage implements IDocumentStorageService {
190
193
  return this.verifyStorage().readBlob(blobId);
191
194
  }
192
195
 
196
+ // eslint-disable-next-line import/no-deprecated
193
197
  private verifyStorage(): IDetachedBlobStorage {
194
198
  if (this.detachedStorage === undefined) {
195
199
  throw new UsageError("Real storage calls not allowed in Unattached container");
package/src/loader.ts CHANGED
@@ -225,6 +225,7 @@ export interface ILoaderServices {
225
225
 
226
226
  /**
227
227
  * Blobs storage for detached containers.
228
+ * @deprecated - IDetachedBlobStorage will be removed in a future release without a replacement. Blobs created while detached will be stored in memory to align with attached container behavior. AB#8049
228
229
  */
229
230
  readonly detachedBlobStorage?: IDetachedBlobStorage;
230
231
 
@@ -239,6 +240,8 @@ export interface ILoaderServices {
239
240
  * Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support
240
241
  * blobs in detached containers.
241
242
  * @alpha
243
+ *
244
+ * @deprecated - IDetachedBlobStorage will be removed in a future release without a replacement. Blobs created while detached will be stored in memory to align with attached container behavior. AB#8049
242
245
  */
243
246
  export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" | "readBlob"> & {
244
247
  size: number;
@@ -246,6 +249,11 @@ export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" |
246
249
  * Return an array of all blob IDs present in storage
247
250
  */
248
251
  getBlobIds(): string[];
252
+
253
+ /**
254
+ * After the container is attached, the detached blob storage is no longer needed and will be disposed.
255
+ */
256
+ dispose?(): void;
249
257
  };
250
258
 
251
259
  /**
@@ -0,0 +1,83 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type { ICreateBlobResponse } from "@fluidframework/protocol-definitions";
7
+ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
8
+ import { assert, isObject } from "@fluidframework/core-utils/internal";
9
+ // eslint-disable-next-line import/no-deprecated
10
+ import type { IDetachedBlobStorage } from "./loader.js";
11
+
12
+ const MemoryDetachedBlobStorageIdentifier = Symbol();
13
+
14
+ // eslint-disable-next-line import/no-deprecated
15
+ interface MemoryDetachedBlobStorage extends IDetachedBlobStorage {
16
+ [MemoryDetachedBlobStorageIdentifier]: typeof MemoryDetachedBlobStorageIdentifier;
17
+ initialize(attachmentBlobs: string[]): void;
18
+ serialize(): string | undefined;
19
+ }
20
+
21
+ function isMemoryDetachedBlobStorage(
22
+ // eslint-disable-next-line import/no-deprecated
23
+ detachedStorage: IDetachedBlobStorage | undefined,
24
+ ): detachedStorage is MemoryDetachedBlobStorage {
25
+ return (
26
+ isObject(detachedStorage) &&
27
+ MemoryDetachedBlobStorageIdentifier in detachedStorage &&
28
+ detachedStorage[MemoryDetachedBlobStorageIdentifier] === MemoryDetachedBlobStorageIdentifier
29
+ );
30
+ }
31
+
32
+ export function serializeMemoryDetachedBlobStorage(
33
+ // eslint-disable-next-line import/no-deprecated
34
+ detachedStorage: IDetachedBlobStorage | undefined,
35
+ ): string | undefined {
36
+ if (
37
+ detachedStorage !== undefined &&
38
+ detachedStorage.size > 0 &&
39
+ isMemoryDetachedBlobStorage(detachedStorage)
40
+ ) {
41
+ return detachedStorage.serialize();
42
+ }
43
+ }
44
+
45
+ export function tryInitializeMemoryDetachedBlobStorage(
46
+ // eslint-disable-next-line import/no-deprecated
47
+ detachedStorage: IDetachedBlobStorage | undefined,
48
+ attachmentBlobs: string,
49
+ ) {
50
+ if (!isMemoryDetachedBlobStorage(detachedStorage)) {
51
+ throw new Error(
52
+ "DetachedBlobStorage was not provided to the loader during serialize so cannot be provided during rehydrate.",
53
+ );
54
+ }
55
+
56
+ assert(detachedStorage.size === 0, "Blob storage already initialized");
57
+ const maybeAttachmentBlobs = JSON.parse(attachmentBlobs);
58
+ assert(Array.isArray(maybeAttachmentBlobs), "Invalid attachmentBlobs");
59
+
60
+ detachedStorage.initialize(maybeAttachmentBlobs);
61
+ }
62
+
63
+ // eslint-disable-next-line import/no-deprecated
64
+ export function createMemoryDetachedBlobStorage(): IDetachedBlobStorage {
65
+ const blobs: ArrayBufferLike[] = [];
66
+ const storage: MemoryDetachedBlobStorage = {
67
+ [MemoryDetachedBlobStorageIdentifier]: MemoryDetachedBlobStorageIdentifier,
68
+ createBlob: async (file: ArrayBufferLike): Promise<ICreateBlobResponse> => ({
69
+ id: `${blobs.push(file) - 1}`,
70
+ }),
71
+ readBlob: async (id: string): Promise<ArrayBufferLike> =>
72
+ blobs[Number(id)] ?? Promise.reject(new Error(`Blob not found: ${id}`)),
73
+ get size() {
74
+ return blobs.length;
75
+ },
76
+ getBlobIds: (): string[] => blobs.map((_, i) => `${i}`),
77
+ dispose: () => blobs.splice(0),
78
+ serialize: () => JSON.stringify(blobs.map((b) => bufferToString(b, "utf-8"))),
79
+ initialize: (attachmentBlobs: string[]) =>
80
+ blobs.push(...attachmentBlobs.map((maybeBlob) => stringToBuffer(maybeBlob, "utf-8"))),
81
+ };
82
+ return storage;
83
+ }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-rc.3.0.0";
9
+ export const pkgVersion = "2.0.0-rc.3.0.10";
@@ -68,6 +68,12 @@ export interface IPendingContainerState extends SnapshotWithBlobs {
68
68
  export interface IPendingDetachedContainerState extends SnapshotWithBlobs {
69
69
  attached: false;
70
70
  hasAttachmentBlobs: boolean;
71
+ /** Used by the memory blob storage to persisted attachment blobs */
72
+ attachmentBlobs?: string;
73
+ /**
74
+ * Runtime-specific state that will be needed to properly rehydrate
75
+ * (it's included in ContainerContext passed to instantiateRuntime)
76
+ */
71
77
  pendingRuntimeState?: unknown;
72
78
  }
73
79
 
package/dist/public.d.ts DELETED
@@ -1,14 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- /*
7
- * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints" in @fluidframework/build-tools.
9
- */
10
-
11
- export {
12
- // public APIs
13
- ConnectionState
14
- } from "./index.js";
package/lib/public.d.ts DELETED
@@ -1,14 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- /*
7
- * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints" in @fluidframework/build-tools.
9
- */
10
-
11
- export {
12
- // public APIs
13
- ConnectionState
14
- } from "./index.js";