@fluidframework/container-loader 2.0.0-rc.3.0.3 → 2.0.0-rc.3.0.5

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 (51) 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 +12 -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 +58 -0
  16. package/dist/memoryBlobStorage.js.map +1 -0
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.js +1 -1
  19. package/dist/packageVersion.js.map +1 -1
  20. package/dist/serializedStateManager.d.ts +6 -0
  21. package/dist/serializedStateManager.d.ts.map +1 -1
  22. package/dist/serializedStateManager.js.map +1 -1
  23. package/lib/attachment.d.ts.map +1 -1
  24. package/lib/attachment.js.map +1 -1
  25. package/lib/container.d.ts.map +1 -1
  26. package/lib/container.js +12 -5
  27. package/lib/container.js.map +1 -1
  28. package/lib/containerStorageAdapter.d.ts.map +1 -1
  29. package/lib/containerStorageAdapter.js +7 -2
  30. package/lib/containerStorageAdapter.js.map +1 -1
  31. package/lib/loader.d.ts +7 -0
  32. package/lib/loader.d.ts.map +1 -1
  33. package/lib/loader.js.map +1 -1
  34. package/lib/memoryBlobStorage.d.ts +9 -0
  35. package/lib/memoryBlobStorage.d.ts.map +1 -0
  36. package/lib/memoryBlobStorage.js +52 -0
  37. package/lib/memoryBlobStorage.js.map +1 -0
  38. package/lib/packageVersion.d.ts +1 -1
  39. package/lib/packageVersion.js +1 -1
  40. package/lib/packageVersion.js.map +1 -1
  41. package/lib/serializedStateManager.d.ts +6 -0
  42. package/lib/serializedStateManager.d.ts.map +1 -1
  43. package/lib/serializedStateManager.js.map +1 -1
  44. package/package.json +10 -10
  45. package/src/attachment.ts +2 -0
  46. package/src/container.ts +19 -5
  47. package/src/containerStorageAdapter.ts +4 -0
  48. package/src/loader.ts +8 -0
  49. package/src/memoryBlobStorage.ts +79 -0
  50. package/src/packageVersion.ts +1 -1
  51. package/src/serializedStateManager.ts +6 -0
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,7 +479,8 @@ export class Container
472
479
  private readonly options: ILoaderOptions;
473
480
  private readonly scope: FluidObject;
474
481
  private readonly subLogger: ITelemetryLoggerExt;
475
- private readonly detachedBlobStorage: IDetachedBlobStorage | undefined;
482
+ // eslint-disable-next-line import/no-deprecated
483
+ private readonly detachedBlobStorage: IDetachedBlobStorage;
476
484
  private readonly protocolHandlerBuilder: ProtocolHandlerBuilder;
477
485
  private readonly client: IClient;
478
486
 
@@ -750,7 +758,7 @@ 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;
761
+ this.detachedBlobStorage = detachedBlobStorage ?? createMemoryDetachedBlobStorage();
754
762
  this.protocolHandlerBuilder =
755
763
  protocolHandlerBuilder ??
756
764
  ((
@@ -917,7 +925,7 @@ export class Container
917
925
  options.summarizeProtocolTree;
918
926
 
919
927
  this.storageAdapter = new ContainerStorageAdapter(
920
- detachedBlobStorage,
928
+ this.detachedBlobStorage,
921
929
  this.mc.logger,
922
930
  pendingLocalState?.snapshotBlobs,
923
931
  addProtocolSummaryIfMissing,
@@ -1167,7 +1175,8 @@ export class Container
1167
1175
  baseSnapshot,
1168
1176
  snapshotBlobs,
1169
1177
  pendingRuntimeState,
1170
- hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1178
+ hasAttachmentBlobs: this.detachedBlobStorage.size > 0,
1179
+ attachmentBlobs: serializeMemoryDetachedBlobStorage(this.detachedBlobStorage),
1171
1180
  };
1172
1181
  return JSON.stringify(detachedContainerState);
1173
1182
  }
@@ -1284,6 +1293,7 @@ export class Container
1284
1293
  const snapshotWithBlobs = await attachP;
1285
1294
  this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
1286
1295
  if (!this.closed) {
1296
+ this.detachedBlobStorage.dispose?.();
1287
1297
  this.handleDeltaConnectionArg(
1288
1298
  {
1289
1299
  fetchOpsFromStorage: false,
@@ -1774,11 +1784,15 @@ export class Container
1774
1784
  baseSnapshot,
1775
1785
  snapshotBlobs,
1776
1786
  hasAttachmentBlobs,
1787
+ attachmentBlobs,
1777
1788
  pendingRuntimeState,
1778
1789
  }: IPendingDetachedContainerState) {
1779
1790
  if (hasAttachmentBlobs) {
1791
+ if (attachmentBlobs !== undefined) {
1792
+ tryInitializeMemoryDetachedBlobStorage(this.detachedBlobStorage, attachmentBlobs);
1793
+ }
1780
1794
  assert(
1781
- !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
1795
+ this.detachedBlobStorage.size > 0,
1782
1796
  0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
1783
1797
  );
1784
1798
  }
@@ -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,79 @@
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,
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,
35
+ ): string | undefined {
36
+ if (detachedStorage.size > 0 && isMemoryDetachedBlobStorage(detachedStorage)) {
37
+ return detachedStorage.serialize();
38
+ }
39
+ }
40
+
41
+ export function tryInitializeMemoryDetachedBlobStorage(
42
+ // eslint-disable-next-line import/no-deprecated
43
+ detachedStorage: IDetachedBlobStorage,
44
+ attachmentBlobs: string,
45
+ ) {
46
+ if (!isMemoryDetachedBlobStorage(detachedStorage)) {
47
+ throw new Error(
48
+ "DetachedBlobStorage was not provided to the loader during serialize so cannot be provided during rehydrate.",
49
+ );
50
+ }
51
+
52
+ assert(detachedStorage.size === 0, "Blob storage already initialized");
53
+ const maybeAttachmentBlobs = JSON.parse(attachmentBlobs);
54
+ assert(Array.isArray(maybeAttachmentBlobs), "Invalid attachmentBlobs");
55
+
56
+ detachedStorage.initialize(maybeAttachmentBlobs);
57
+ }
58
+
59
+ // eslint-disable-next-line import/no-deprecated
60
+ export function createMemoryDetachedBlobStorage(): IDetachedBlobStorage {
61
+ const blobs: ArrayBufferLike[] = [];
62
+ const storage: MemoryDetachedBlobStorage = {
63
+ [MemoryDetachedBlobStorageIdentifier]: MemoryDetachedBlobStorageIdentifier,
64
+ createBlob: async (file: ArrayBufferLike): Promise<ICreateBlobResponse> => ({
65
+ id: `${blobs.push(file) - 1}`,
66
+ }),
67
+ readBlob: async (id: string): Promise<ArrayBufferLike> =>
68
+ blobs[Number(id)] ?? Promise.reject(new Error(`Blob not found: ${id}`)),
69
+ get size() {
70
+ return blobs.length;
71
+ },
72
+ getBlobIds: (): string[] => blobs.map((_, i) => `${i}`),
73
+ dispose: () => blobs.splice(0),
74
+ serialize: () => JSON.stringify(blobs.map((b) => bufferToString(b, "utf-8"))),
75
+ initialize: (attachmentBlobs: string[]) =>
76
+ blobs.push(...attachmentBlobs.map((maybeBlob) => stringToBuffer(maybeBlob, "utf-8"))),
77
+ };
78
+ return storage;
79
+ }
@@ -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.3";
9
+ export const pkgVersion = "2.0.0-rc.3.0.5";
@@ -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