@fluidframework/container-loader 2.0.0-rc.4.0.0 → 2.0.0-rc.4.0.2
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 +2 -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 +2 -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 +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-loader",
|
|
3
|
-
"version": "2.0.0-rc.4.0.
|
|
3
|
+
"version": "2.0.0-rc.4.0.2",
|
|
4
4
|
"description": "Fluid container loader",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -117,15 +117,15 @@
|
|
|
117
117
|
"temp-directory": "nyc/.nyc_output"
|
|
118
118
|
},
|
|
119
119
|
"dependencies": {
|
|
120
|
-
"@fluid-internal/client-utils": ">=2.0.0-rc.4.0.
|
|
121
|
-
"@fluidframework/container-definitions": ">=2.0.0-rc.4.0.
|
|
122
|
-
"@fluidframework/core-interfaces": ">=2.0.0-rc.4.0.
|
|
123
|
-
"@fluidframework/core-utils": ">=2.0.0-rc.4.0.
|
|
124
|
-
"@fluidframework/driver-definitions": ">=2.0.0-rc.4.0.
|
|
125
|
-
"@fluidframework/driver-utils": ">=2.0.0-rc.4.0.
|
|
120
|
+
"@fluid-internal/client-utils": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
121
|
+
"@fluidframework/container-definitions": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
122
|
+
"@fluidframework/core-interfaces": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
123
|
+
"@fluidframework/core-utils": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
124
|
+
"@fluidframework/driver-definitions": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
125
|
+
"@fluidframework/driver-utils": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
126
126
|
"@fluidframework/protocol-base": "^4.0.0",
|
|
127
127
|
"@fluidframework/protocol-definitions": "^3.2.0",
|
|
128
|
-
"@fluidframework/telemetry-utils": ">=2.0.0-rc.4.0.
|
|
128
|
+
"@fluidframework/telemetry-utils": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
129
129
|
"@ungap/structured-clone": "^1.2.0",
|
|
130
130
|
"debug": "^4.3.4",
|
|
131
131
|
"double-ended-queue": "^2.1.0-0",
|
|
@@ -134,8 +134,8 @@
|
|
|
134
134
|
"devDependencies": {
|
|
135
135
|
"@arethetypeswrong/cli": "^0.15.2",
|
|
136
136
|
"@biomejs/biome": "^1.6.2",
|
|
137
|
-
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.4.0.
|
|
138
|
-
"@fluid-private/test-loader-utils": ">=2.0.0-rc.4.0.
|
|
137
|
+
"@fluid-internal/mocha-test-setup": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
138
|
+
"@fluid-private/test-loader-utils": ">=2.0.0-rc.4.0.2 <2.0.0-rc.4.1.0",
|
|
139
139
|
"@fluid-tools/build-cli": "^0.38.0",
|
|
140
140
|
"@fluidframework/build-common": "^2.0.3",
|
|
141
141
|
"@fluidframework/build-tools": "^0.38.0",
|
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
|
@@ -111,6 +111,7 @@ import {
|
|
|
111
111
|
getPackageName,
|
|
112
112
|
} from "./contracts.js";
|
|
113
113
|
import { DeltaManager, IConnectionArgs } from "./deltaManager.js";
|
|
114
|
+
// eslint-disable-next-line import/no-deprecated
|
|
114
115
|
import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader.js";
|
|
115
116
|
import { NoopHeuristic } from "./noopHeuristic.js";
|
|
116
117
|
import { pkgVersion } from "./packageVersion.js";
|
|
@@ -136,6 +137,11 @@ import {
|
|
|
136
137
|
getSnapshotTreeAndBlobsFromSerializedContainer,
|
|
137
138
|
runSingle,
|
|
138
139
|
} from "./utils.js";
|
|
140
|
+
import {
|
|
141
|
+
serializeMemoryDetachedBlobStorage,
|
|
142
|
+
createMemoryDetachedBlobStorage,
|
|
143
|
+
tryInitializeMemoryDetachedBlobStorage,
|
|
144
|
+
} from "./memoryBlobStorage.js";
|
|
139
145
|
|
|
140
146
|
const detachedContainerRefSeqNumber = 0;
|
|
141
147
|
|
|
@@ -218,6 +224,7 @@ export interface IContainerCreateProps {
|
|
|
218
224
|
/**
|
|
219
225
|
* Blobs storage for detached containers.
|
|
220
226
|
*/
|
|
227
|
+
// eslint-disable-next-line import/no-deprecated
|
|
221
228
|
readonly detachedBlobStorage?: IDetachedBlobStorage;
|
|
222
229
|
|
|
223
230
|
/**
|
|
@@ -465,7 +472,8 @@ export class Container
|
|
|
465
472
|
private readonly options: ILoaderOptions;
|
|
466
473
|
private readonly scope: FluidObject;
|
|
467
474
|
private readonly subLogger: ITelemetryLoggerExt;
|
|
468
|
-
|
|
475
|
+
// eslint-disable-next-line import/no-deprecated
|
|
476
|
+
private readonly detachedBlobStorage: IDetachedBlobStorage;
|
|
469
477
|
private readonly protocolHandlerBuilder: ProtocolHandlerBuilder;
|
|
470
478
|
private readonly client: IClient;
|
|
471
479
|
|
|
@@ -767,7 +775,7 @@ export class Container
|
|
|
767
775
|
// Tracking alternative ways to handle this in AB#4129.
|
|
768
776
|
this.options = { ...options };
|
|
769
777
|
this.scope = scope;
|
|
770
|
-
this.detachedBlobStorage = detachedBlobStorage;
|
|
778
|
+
this.detachedBlobStorage = detachedBlobStorage ?? createMemoryDetachedBlobStorage();
|
|
771
779
|
this.protocolHandlerBuilder =
|
|
772
780
|
protocolHandlerBuilder ??
|
|
773
781
|
((
|
|
@@ -944,7 +952,7 @@ export class Container
|
|
|
944
952
|
options.summarizeProtocolTree;
|
|
945
953
|
|
|
946
954
|
this.storageAdapter = new ContainerStorageAdapter(
|
|
947
|
-
detachedBlobStorage,
|
|
955
|
+
this.detachedBlobStorage,
|
|
948
956
|
this.mc.logger,
|
|
949
957
|
pendingLocalState?.snapshotBlobs,
|
|
950
958
|
pendingLocalState?.loadedGroupIdSnapshots,
|
|
@@ -1208,7 +1216,8 @@ export class Container
|
|
|
1208
1216
|
baseSnapshot,
|
|
1209
1217
|
snapshotBlobs,
|
|
1210
1218
|
pendingRuntimeState,
|
|
1211
|
-
hasAttachmentBlobs:
|
|
1219
|
+
hasAttachmentBlobs: this.detachedBlobStorage.size > 0,
|
|
1220
|
+
attachmentBlobs: serializeMemoryDetachedBlobStorage(this.detachedBlobStorage),
|
|
1212
1221
|
};
|
|
1213
1222
|
return JSON.stringify(detachedContainerState);
|
|
1214
1223
|
}
|
|
@@ -1328,6 +1337,7 @@ export class Container
|
|
|
1328
1337
|
this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
|
|
1329
1338
|
|
|
1330
1339
|
if (!this.closed) {
|
|
1340
|
+
this.detachedBlobStorage.dispose?.();
|
|
1331
1341
|
this.handleDeltaConnectionArg(attachProps?.deltaConnection, {
|
|
1332
1342
|
fetchOpsFromStorage: false,
|
|
1333
1343
|
reason: { text: "createDetached" },
|
|
@@ -1760,11 +1770,15 @@ export class Container
|
|
|
1760
1770
|
baseSnapshot,
|
|
1761
1771
|
snapshotBlobs,
|
|
1762
1772
|
hasAttachmentBlobs,
|
|
1773
|
+
attachmentBlobs,
|
|
1763
1774
|
pendingRuntimeState,
|
|
1764
1775
|
}: IPendingDetachedContainerState) {
|
|
1765
1776
|
if (hasAttachmentBlobs) {
|
|
1777
|
+
if (attachmentBlobs !== undefined) {
|
|
1778
|
+
tryInitializeMemoryDetachedBlobStorage(this.detachedBlobStorage, attachmentBlobs);
|
|
1779
|
+
}
|
|
1766
1780
|
assert(
|
|
1767
|
-
|
|
1781
|
+
this.detachedBlobStorage.size > 0,
|
|
1768
1782
|
0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
|
|
1769
1783
|
);
|
|
1770
1784
|
}
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "@fluidframework/protocol-definitions";
|
|
27
27
|
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
|
|
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";
|
|
@@ -79,6 +80,7 @@ export class ContainerStorageAdapter
|
|
|
79
80
|
* @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
|
|
80
81
|
*/
|
|
81
82
|
public constructor(
|
|
83
|
+
// eslint-disable-next-line import/no-deprecated
|
|
82
84
|
detachedBlobStorage: IDetachedBlobStorage | undefined,
|
|
83
85
|
private readonly logger: ITelemetryLoggerExt,
|
|
84
86
|
/**
|
|
@@ -233,6 +235,7 @@ export class ContainerStorageAdapter
|
|
|
233
235
|
*/
|
|
234
236
|
class BlobOnlyStorage implements IDocumentStorageService {
|
|
235
237
|
constructor(
|
|
238
|
+
// eslint-disable-next-line import/no-deprecated
|
|
236
239
|
private readonly detachedStorage: IDetachedBlobStorage | undefined,
|
|
237
240
|
private readonly logger: ITelemetryLoggerExt,
|
|
238
241
|
) {}
|
|
@@ -245,6 +248,7 @@ class BlobOnlyStorage implements IDocumentStorageService {
|
|
|
245
248
|
return this.verifyStorage().readBlob(blobId);
|
|
246
249
|
}
|
|
247
250
|
|
|
251
|
+
// eslint-disable-next-line import/no-deprecated
|
|
248
252
|
private verifyStorage(): IDetachedBlobStorage {
|
|
249
253
|
if (this.detachedStorage === undefined) {
|
|
250
254
|
throw new UsageError("Real storage calls not allowed in Unattached container");
|
package/src/loader.ts
CHANGED
|
@@ -227,6 +227,7 @@ export interface ILoaderServices {
|
|
|
227
227
|
|
|
228
228
|
/**
|
|
229
229
|
* Blobs storage for detached containers.
|
|
230
|
+
* @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
|
|
230
231
|
*/
|
|
231
232
|
readonly detachedBlobStorage?: IDetachedBlobStorage;
|
|
232
233
|
|
|
@@ -241,6 +242,8 @@ export interface ILoaderServices {
|
|
|
241
242
|
* Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support
|
|
242
243
|
* blobs in detached containers.
|
|
243
244
|
* @alpha
|
|
245
|
+
*
|
|
246
|
+
* @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
|
|
244
247
|
*/
|
|
245
248
|
export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" | "readBlob"> & {
|
|
246
249
|
size: number;
|
|
@@ -248,6 +251,11 @@ export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" |
|
|
|
248
251
|
* Return an array of all blob IDs present in storage
|
|
249
252
|
*/
|
|
250
253
|
getBlobIds(): string[];
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* After the container is attached, the detached blob storage is no longer needed and will be disposed.
|
|
257
|
+
*/
|
|
258
|
+
dispose?(): void;
|
|
251
259
|
};
|
|
252
260
|
|
|
253
261
|
/**
|
|
@@ -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
|
@@ -93,6 +93,8 @@ export interface IPendingDetachedContainerState extends SnapshotWithBlobs {
|
|
|
93
93
|
attached: false;
|
|
94
94
|
/** Indicates whether we expect the rehydrated container to have non-empty Detached Blob Storage */
|
|
95
95
|
hasAttachmentBlobs: boolean;
|
|
96
|
+
/** Used by the memory blob storage to persisted attachment blobs */
|
|
97
|
+
attachmentBlobs?: string;
|
|
96
98
|
/**
|
|
97
99
|
* Runtime-specific state that will be needed to properly rehydrate
|
|
98
100
|
* (it's included in ContainerContext passed to instantiateRuntime)
|