@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.
- package/api-report/container-loader.api.md +3 -1
- package/dist/attachment.d.ts.map +1 -1
- package/dist/attachment.js.map +1 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +12 -5
- package/dist/container.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +7 -2
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/loader.d.ts +7 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js.map +1 -1
- package/dist/memoryBlobStorage.d.ts +9 -0
- package/dist/memoryBlobStorage.d.ts.map +1 -0
- package/dist/memoryBlobStorage.js +58 -0
- package/dist/memoryBlobStorage.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/serializedStateManager.d.ts +6 -0
- package/dist/serializedStateManager.d.ts.map +1 -1
- package/dist/serializedStateManager.js.map +1 -1
- package/lib/attachment.d.ts.map +1 -1
- package/lib/attachment.js.map +1 -1
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +12 -5
- package/lib/container.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +7 -2
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/loader.d.ts +7 -0
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js.map +1 -1
- package/lib/memoryBlobStorage.d.ts +9 -0
- package/lib/memoryBlobStorage.d.ts.map +1 -0
- package/lib/memoryBlobStorage.js +52 -0
- package/lib/memoryBlobStorage.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/serializedStateManager.d.ts +6 -0
- package/lib/serializedStateManager.d.ts.map +1 -1
- package/lib/serializedStateManager.js.map +1 -1
- package/package.json +10 -10
- package/src/attachment.ts +2 -0
- package/src/container.ts +19 -5
- package/src/containerStorageAdapter.ts +4 -0
- package/src/loader.ts +8 -0
- package/src/memoryBlobStorage.ts +79 -0
- package/src/packageVersion.ts +1 -1
- 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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
+
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -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
|
|