@fluidframework/container-loader 2.0.0-rc.1.0.4 → 2.0.0-rc.2.0.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.
- package/{.eslintrc.js → .eslintrc.cjs} +5 -6
- package/{.mocharc.js → .mocharc.cjs} +1 -1
- package/CHANGELOG.md +48 -0
- package/README.md +3 -3
- package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
- package/api-extractor-lint.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/container-loader.api.md +2 -2
- package/dist/attachment.d.ts +115 -0
- package/dist/attachment.d.ts.map +1 -0
- package/dist/attachment.js +83 -0
- package/dist/attachment.js.map +1 -0
- package/dist/audience.d.ts +9 -4
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +10 -4
- package/dist/audience.js.map +1 -1
- package/dist/connectionManager.d.ts +3 -3
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +17 -18
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts +1 -0
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js +1 -0
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +7 -7
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +32 -32
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container-loader-alpha.d.ts +2 -1
- package/dist/container-loader-beta.d.ts +3 -0
- package/dist/container-loader-public.d.ts +3 -0
- package/dist/container-loader-untrimmed.d.ts +5 -5
- package/dist/container.d.ts +29 -27
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +219 -284
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +3 -2
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +2 -1
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +5 -6
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +14 -21
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts +5 -5
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +6 -6
- package/dist/deltaManager.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +3 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +13 -17
- package/dist/loader.js.map +1 -1
- package/dist/location-redirection-utilities/index.d.ts +1 -1
- package/dist/location-redirection-utilities/index.d.ts.map +1 -1
- package/dist/location-redirection-utilities/index.js +3 -3
- package/dist/location-redirection-utilities/index.js.map +1 -1
- package/dist/package.json +3 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +1 -3
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +2 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +8 -6
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/serializedStateManager.d.ts +44 -0
- package/dist/serializedStateManager.d.ts.map +1 -0
- package/dist/serializedStateManager.js +149 -0
- package/dist/serializedStateManager.js.map +1 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/utils.d.ts +16 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +107 -32
- package/dist/utils.js.map +1 -1
- package/lib/attachment.d.ts +115 -0
- package/lib/attachment.d.ts.map +1 -0
- package/lib/attachment.js +79 -0
- package/lib/attachment.js.map +1 -0
- package/lib/{audience.d.mts → audience.d.ts} +14 -5
- package/lib/audience.d.ts.map +1 -0
- package/lib/{audience.mjs → audience.js} +14 -4
- package/lib/audience.js.map +1 -0
- package/lib/{catchUpMonitor.d.mts → catchUpMonitor.d.ts} +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -0
- package/lib/{catchUpMonitor.mjs → catchUpMonitor.js} +1 -1
- package/lib/catchUpMonitor.js.map +1 -0
- package/lib/{connectionManager.d.mts → connectionManager.d.ts} +4 -4
- package/lib/connectionManager.d.ts.map +1 -0
- package/lib/{connectionManager.mjs → connectionManager.js} +7 -10
- package/lib/connectionManager.js.map +1 -0
- package/lib/{connectionState.d.mts → connectionState.d.ts} +2 -1
- package/lib/connectionState.d.ts.map +1 -0
- package/lib/{connectionState.mjs → connectionState.js} +2 -1
- package/lib/connectionState.js.map +1 -0
- package/lib/{connectionStateHandler.d.mts → connectionStateHandler.d.ts} +8 -8
- package/lib/connectionStateHandler.d.ts.map +1 -0
- package/lib/{connectionStateHandler.mjs → connectionStateHandler.js} +3 -3
- package/lib/connectionStateHandler.js.map +1 -0
- package/lib/{container-loader-alpha.d.mts → container-loader-alpha.d.ts} +2 -1
- package/lib/{container-loader-beta.d.mts → container-loader-beta.d.ts} +3 -0
- package/lib/{container-loader-public.d.mts → container-loader-public.d.ts} +3 -0
- package/lib/{container-loader-untrimmed.d.mts → container-loader-untrimmed.d.ts} +5 -5
- package/lib/{container.d.mts → container.d.ts} +30 -28
- package/lib/container.d.ts.map +1 -0
- package/lib/{container.mjs → container.js} +179 -247
- package/lib/container.js.map +1 -0
- package/lib/{containerContext.d.mts → containerContext.d.ts} +4 -3
- package/lib/containerContext.d.ts.map +1 -0
- package/lib/{containerContext.mjs → containerContext.js} +3 -2
- package/lib/containerContext.js.map +1 -0
- package/lib/{containerStorageAdapter.d.mts → containerStorageAdapter.d.ts} +6 -7
- package/lib/containerStorageAdapter.d.ts.map +1 -0
- package/lib/{containerStorageAdapter.mjs → containerStorageAdapter.js} +13 -20
- package/lib/containerStorageAdapter.js.map +1 -0
- package/lib/{contracts.d.mts → contracts.d.ts} +4 -4
- package/lib/contracts.d.ts.map +1 -0
- package/lib/{contracts.mjs → contracts.js} +1 -1
- package/lib/contracts.js.map +1 -0
- package/lib/{debugLogger.d.mts → debugLogger.d.ts} +1 -1
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/{debugLogger.mjs → debugLogger.js} +2 -1
- package/lib/debugLogger.js.map +1 -0
- package/lib/{deltaManager.d.mts → deltaManager.d.ts} +6 -6
- package/lib/deltaManager.d.ts.map +1 -0
- package/lib/{deltaManager.mjs → deltaManager.js} +4 -4
- package/lib/deltaManager.js.map +1 -0
- package/lib/{deltaQueue.d.mts → deltaQueue.d.ts} +1 -1
- package/lib/deltaQueue.d.ts.map +1 -0
- package/lib/{deltaQueue.mjs → deltaQueue.js} +1 -1
- package/lib/deltaQueue.js.map +1 -0
- package/lib/{disposal.d.mts → disposal.d.ts} +1 -1
- package/lib/disposal.d.ts.map +1 -0
- package/lib/{disposal.mjs → disposal.js} +1 -1
- package/lib/disposal.js.map +1 -0
- package/lib/{error.d.mts → error.d.ts} +1 -1
- package/lib/error.d.ts.map +1 -0
- package/lib/{error.mjs → error.js} +1 -1
- package/lib/error.js.map +1 -0
- package/lib/{index.d.mts → index.d.ts} +7 -7
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/{loader.d.mts → loader.d.ts} +4 -4
- package/lib/loader.d.ts.map +1 -0
- package/lib/{loader.mjs → loader.js} +7 -11
- package/lib/loader.js.map +1 -0
- package/lib/location-redirection-utilities/{index.mjs → index.d.ts} +2 -2
- package/lib/location-redirection-utilities/index.d.ts.map +1 -0
- package/lib/location-redirection-utilities/{index.d.mts → index.js} +2 -2
- package/lib/location-redirection-utilities/index.js.map +1 -0
- package/lib/location-redirection-utilities/{resolveWithLocationRedirection.d.mts → resolveWithLocationRedirection.d.ts} +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/lib/location-redirection-utilities/{resolveWithLocationRedirection.mjs → resolveWithLocationRedirection.js} +1 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -0
- package/lib/{noopHeuristic.d.mts → noopHeuristic.d.ts} +1 -1
- package/lib/noopHeuristic.d.ts.map +1 -0
- package/lib/{noopHeuristic.mjs → noopHeuristic.js} +1 -1
- package/lib/noopHeuristic.js.map +1 -0
- package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
- package/lib/packageVersion.js.map +1 -0
- package/lib/{protocol.d.mts → protocol.d.ts} +1 -1
- package/lib/protocol.d.ts.map +1 -0
- package/lib/{protocol.mjs → protocol.js} +1 -1
- package/lib/protocol.js.map +1 -0
- package/lib/{protocolTreeDocumentStorageService.d.mts → protocolTreeDocumentStorageService.d.ts} +2 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -0
- package/lib/{protocolTreeDocumentStorageService.mjs → protocolTreeDocumentStorageService.js} +2 -4
- package/lib/protocolTreeDocumentStorageService.js.map +1 -0
- package/lib/{quorum.d.mts → quorum.d.ts} +5 -1
- package/lib/quorum.d.ts.map +1 -0
- package/lib/{quorum.mjs → quorum.js} +1 -1
- package/lib/quorum.js.map +1 -0
- package/lib/{retriableDocumentStorageService.d.mts → retriableDocumentStorageService.d.ts} +3 -3
- package/lib/retriableDocumentStorageService.d.ts.map +1 -0
- package/lib/{retriableDocumentStorageService.mjs → retriableDocumentStorageService.js} +10 -8
- package/lib/retriableDocumentStorageService.js.map +1 -0
- package/lib/serializedStateManager.d.ts +44 -0
- package/lib/serializedStateManager.d.ts.map +1 -0
- package/lib/serializedStateManager.js +145 -0
- package/lib/serializedStateManager.js.map +1 -0
- package/lib/test/attachment.spec.js +380 -0
- package/lib/test/attachment.spec.js.map +1 -0
- package/lib/test/catchUpMonitor.spec.js +88 -0
- package/lib/test/catchUpMonitor.spec.js.map +1 -0
- package/lib/test/connectionManager.spec.js +201 -0
- package/lib/test/connectionManager.spec.js.map +1 -0
- package/lib/test/connectionStateHandler.spec.js +555 -0
- package/lib/test/connectionStateHandler.spec.js.map +1 -0
- package/lib/test/container.spec.js +64 -0
- package/lib/test/container.spec.js.map +1 -0
- package/lib/test/deltaManager.spec.js +405 -0
- package/lib/test/deltaManager.spec.js.map +1 -0
- package/lib/test/loader.spec.js +212 -0
- package/lib/test/loader.spec.js.map +1 -0
- package/lib/test/locationRedirectionTests.spec.js +44 -0
- package/lib/test/locationRedirectionTests.spec.js.map +1 -0
- package/lib/test/serializedStateManager.spec.js +148 -0
- package/lib/test/serializedStateManager.spec.js.map +1 -0
- package/lib/test/snapshotConversionTest.spec.js +79 -0
- package/lib/test/snapshotConversionTest.spec.js.map +1 -0
- package/lib/test/types/validateContainerLoaderPrevious.generated.js +38 -0
- package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +1 -0
- package/lib/test/utils.spec.js +31 -0
- package/lib/test/utils.spec.js.map +1 -0
- package/lib/{utils.d.mts → utils.d.ts} +17 -12
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +206 -0
- package/lib/utils.js.map +1 -0
- package/package.json +63 -63
- package/src/attachment.ts +222 -0
- package/src/audience.ts +9 -3
- package/src/connectionManager.ts +9 -11
- package/src/connectionState.ts +1 -0
- package/src/connectionStateHandler.ts +8 -7
- package/src/container.ts +297 -323
- package/src/containerContext.ts +2 -1
- package/src/containerStorageAdapter.ts +21 -26
- package/src/contracts.ts +3 -3
- package/src/debugLogger.ts +2 -2
- package/src/deltaManager.ts +8 -8
- package/src/error.ts +2 -2
- package/src/index.ts +6 -6
- package/src/loader.ts +9 -13
- package/src/location-redirection-utilities/index.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/protocolTreeDocumentStorageService.ts +1 -3
- package/src/retriableDocumentStorageService.ts +18 -8
- package/src/serializedStateManager.ts +217 -0
- package/src/utils.ts +140 -43
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +2 -5
- package/lib/audience.d.mts.map +0 -1
- package/lib/audience.mjs.map +0 -1
- package/lib/catchUpMonitor.d.mts.map +0 -1
- package/lib/catchUpMonitor.mjs.map +0 -1
- package/lib/connectionManager.d.mts.map +0 -1
- package/lib/connectionManager.mjs.map +0 -1
- package/lib/connectionState.d.mts.map +0 -1
- package/lib/connectionState.mjs.map +0 -1
- package/lib/connectionStateHandler.d.mts.map +0 -1
- package/lib/connectionStateHandler.mjs.map +0 -1
- package/lib/container.d.mts.map +0 -1
- package/lib/container.mjs.map +0 -1
- package/lib/containerContext.d.mts.map +0 -1
- package/lib/containerContext.mjs.map +0 -1
- package/lib/containerStorageAdapter.d.mts.map +0 -1
- package/lib/containerStorageAdapter.mjs.map +0 -1
- package/lib/contracts.d.mts.map +0 -1
- package/lib/contracts.mjs.map +0 -1
- package/lib/debugLogger.d.mts.map +0 -1
- package/lib/debugLogger.mjs.map +0 -1
- package/lib/deltaManager.d.mts.map +0 -1
- package/lib/deltaManager.mjs.map +0 -1
- package/lib/deltaQueue.d.mts.map +0 -1
- package/lib/deltaQueue.mjs.map +0 -1
- package/lib/disposal.d.mts.map +0 -1
- package/lib/disposal.mjs.map +0 -1
- package/lib/error.d.mts.map +0 -1
- package/lib/error.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -10
- package/lib/index.mjs.map +0 -1
- package/lib/loader.d.mts.map +0 -1
- package/lib/loader.mjs.map +0 -1
- package/lib/location-redirection-utilities/index.d.mts.map +0 -1
- package/lib/location-redirection-utilities/index.mjs.map +0 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +0 -1
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +0 -1
- package/lib/noopHeuristic.d.mts.map +0 -1
- package/lib/noopHeuristic.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/protocol.d.mts.map +0 -1
- package/lib/protocol.mjs.map +0 -1
- package/lib/protocolTreeDocumentStorageService.d.mts.map +0 -1
- package/lib/protocolTreeDocumentStorageService.mjs.map +0 -1
- package/lib/quorum.d.mts.map +0 -1
- package/lib/quorum.mjs.map +0 -1
- package/lib/retriableDocumentStorageService.d.mts.map +0 -1
- package/lib/retriableDocumentStorageService.mjs.map +0 -1
- package/lib/utils.d.mts.map +0 -1
- package/lib/utils.mjs +0 -133
- package/lib/utils.mjs.map +0 -1
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,sCAAsC,CAAC;AAEhG,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAEnC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC;AAIhE,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAiBjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AA2ED,eAAO,MAAM,8CAA8C,8BAC/B,YAAY,KACrC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,yBAAyB,CAAA;CAYzD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,eAAO,MAAM,mCAAmC,iBACjC,aAAa,iBACZ,yBAAyB,KACtC,6BAwBF,CAAC;AAEF,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,GAAG,GACR,KAAK,IAAI,mCAAmC,CAM9C;AAoBD,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAkBhC;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,sFAsBrB,CAAC"}
|
package/dist/utils.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isDeltaStreamConnectionForbiddenError = exports.
|
|
8
|
-
const url_1 = require("url");
|
|
7
|
+
exports.runSingle = exports.getDetachedContainerStateFromSerializedContainer = exports.isDeltaStreamConnectionForbiddenError = exports.combineSnapshotTreeAndSnapshotBlobs = exports.getProtocolSnapshotTree = exports.getSnapshotTreeAndBlobsFromSerializedContainer = exports.combineAppAndProtocolSummary = exports.tryParseCompatibleResolvedUrl = void 0;
|
|
9
8
|
const uuid_1 = require("uuid");
|
|
10
9
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
11
10
|
const core_utils_1 = require("@fluidframework/core-utils");
|
|
@@ -23,7 +22,7 @@ const driver_definitions_1 = require("@fluidframework/driver-definitions");
|
|
|
23
22
|
* @internal
|
|
24
23
|
*/
|
|
25
24
|
function tryParseCompatibleResolvedUrl(url) {
|
|
26
|
-
const parsed =
|
|
25
|
+
const parsed = new URL(url);
|
|
27
26
|
if (typeof parsed.pathname !== "string") {
|
|
28
27
|
throw new telemetry_utils_1.LoggingError("Failed to parse pathname");
|
|
29
28
|
}
|
|
@@ -31,7 +30,13 @@ function tryParseCompatibleResolvedUrl(url) {
|
|
|
31
30
|
const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/;
|
|
32
31
|
const match = regex.exec(parsed.pathname);
|
|
33
32
|
return match?.length === 3
|
|
34
|
-
? {
|
|
33
|
+
? {
|
|
34
|
+
id: match[1],
|
|
35
|
+
path: match[2],
|
|
36
|
+
query,
|
|
37
|
+
// URLSearchParams returns null if the param is not provided.
|
|
38
|
+
version: parsed.searchParams.get("version") ?? undefined,
|
|
39
|
+
}
|
|
35
40
|
: undefined;
|
|
36
41
|
}
|
|
37
42
|
exports.tryParseCompatibleResolvedUrl = tryParseCompatibleResolvedUrl;
|
|
@@ -55,30 +60,27 @@ function combineAppAndProtocolSummary(appSummary, protocolSummary) {
|
|
|
55
60
|
}
|
|
56
61
|
exports.combineAppAndProtocolSummary = combineAppAndProtocolSummary;
|
|
57
62
|
/**
|
|
58
|
-
* Converts summary
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* snapshot tree for each blob in the summary tree. One will be the regular
|
|
62
|
-
* path pointing to a uniquely generated ID. Then there will be another
|
|
63
|
-
* entry with the path as that uniquely generated ID, and value as the
|
|
64
|
-
* blob contents as a base-64 string.
|
|
65
|
-
* @param summary - summary to convert
|
|
63
|
+
* Converts a summary to snapshot tree and separate its blob contents
|
|
64
|
+
* to align detached container format with IPendingContainerState
|
|
65
|
+
* @param summary - ISummaryTree
|
|
66
66
|
*/
|
|
67
|
-
function
|
|
67
|
+
function convertSummaryToSnapshotAndBlobs(summary) {
|
|
68
|
+
let blobContents = {};
|
|
68
69
|
const treeNode = {
|
|
69
70
|
blobs: {},
|
|
70
|
-
blobsContents: {},
|
|
71
71
|
trees: {},
|
|
72
72
|
id: (0, uuid_1.v4)(),
|
|
73
73
|
unreferenced: summary.unreferenced,
|
|
74
|
+
groupId: summary.groupId,
|
|
74
75
|
};
|
|
75
76
|
const keys = Object.keys(summary.tree);
|
|
76
77
|
for (const key of keys) {
|
|
77
78
|
const summaryObject = summary.tree[key];
|
|
78
79
|
switch (summaryObject.type) {
|
|
79
80
|
case protocol_definitions_1.SummaryType.Tree: {
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
const { tree, blobs } = convertSummaryToSnapshotAndBlobs(summaryObject);
|
|
82
|
+
treeNode.trees[key] = tree;
|
|
83
|
+
blobContents = { ...blobContents, ...blobs };
|
|
82
84
|
break;
|
|
83
85
|
}
|
|
84
86
|
case protocol_definitions_1.SummaryType.Attachment:
|
|
@@ -87,10 +89,10 @@ function convertSummaryToSnapshotWithEmbeddedBlobContents(summary) {
|
|
|
87
89
|
case protocol_definitions_1.SummaryType.Blob: {
|
|
88
90
|
const blobId = (0, uuid_1.v4)();
|
|
89
91
|
treeNode.blobs[key] = blobId;
|
|
90
|
-
const
|
|
91
|
-
? (0, client_utils_1.
|
|
92
|
-
:
|
|
93
|
-
|
|
92
|
+
const contentString = summaryObject.content instanceof Uint8Array
|
|
93
|
+
? (0, client_utils_1.Uint8ArrayToString)(summaryObject.content)
|
|
94
|
+
: summaryObject.content;
|
|
95
|
+
blobContents[blobId] = contentString;
|
|
94
96
|
break;
|
|
95
97
|
}
|
|
96
98
|
case protocol_definitions_1.SummaryType.Handle:
|
|
@@ -101,42 +103,115 @@ function convertSummaryToSnapshotWithEmbeddedBlobContents(summary) {
|
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
|
-
return treeNode;
|
|
106
|
+
return { tree: treeNode, blobs: blobContents };
|
|
105
107
|
}
|
|
106
108
|
/**
|
|
107
|
-
*
|
|
109
|
+
* Converts summary parts into a SnapshotTree and its blob contents.
|
|
108
110
|
* @param protocolSummaryTree - Protocol Summary Tree
|
|
109
111
|
* @param appSummaryTree - App Summary Tree
|
|
110
112
|
*/
|
|
111
|
-
function
|
|
112
|
-
// Shallow copy is fine, since we are doing a deep clone below.
|
|
113
|
+
function convertProtocolAndAppSummaryToSnapshotAndBlobs(protocolSummaryTree, appSummaryTree) {
|
|
113
114
|
const combinedSummary = {
|
|
114
115
|
type: protocol_definitions_1.SummaryType.Tree,
|
|
115
116
|
tree: { ...appSummaryTree.tree },
|
|
116
117
|
};
|
|
117
118
|
combinedSummary.tree[".protocol"] = protocolSummaryTree;
|
|
118
|
-
const snapshotTreeWithBlobContents =
|
|
119
|
+
const snapshotTreeWithBlobContents = convertSummaryToSnapshotAndBlobs(combinedSummary);
|
|
119
120
|
return snapshotTreeWithBlobContents;
|
|
120
121
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// a detached container can be rehydrated.
|
|
124
|
-
const getSnapshotTreeFromSerializedContainer = (detachedContainerSnapshot) => {
|
|
125
|
-
(0, core_utils_1.assert)((0, driver_utils_1.isCombinedAppAndProtocolSummary)(detachedContainerSnapshot), 0x1e0 /* "Protocol and App summary trees should be present" */);
|
|
122
|
+
const getSnapshotTreeAndBlobsFromSerializedContainer = (detachedContainerSnapshot) => {
|
|
123
|
+
(0, core_utils_1.assert)((0, driver_utils_1.isCombinedAppAndProtocolSummary)(detachedContainerSnapshot), 0x8e6 /* Protocol and App summary trees should be present */);
|
|
126
124
|
const protocolSummaryTree = detachedContainerSnapshot.tree[".protocol"];
|
|
127
125
|
const appSummaryTree = detachedContainerSnapshot.tree[".app"];
|
|
128
|
-
const snapshotTreeWithBlobContents =
|
|
126
|
+
const snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotAndBlobs(protocolSummaryTree, appSummaryTree);
|
|
129
127
|
return snapshotTreeWithBlobContents;
|
|
130
128
|
};
|
|
131
|
-
exports.
|
|
129
|
+
exports.getSnapshotTreeAndBlobsFromSerializedContainer = getSnapshotTreeAndBlobsFromSerializedContainer;
|
|
132
130
|
function getProtocolSnapshotTree(snapshot) {
|
|
133
131
|
return ".protocol" in snapshot.trees ? snapshot.trees[".protocol"] : snapshot;
|
|
134
132
|
}
|
|
135
133
|
exports.getProtocolSnapshotTree = getProtocolSnapshotTree;
|
|
134
|
+
const combineSnapshotTreeAndSnapshotBlobs = (baseSnapshot, snapshotBlobs) => {
|
|
135
|
+
const blobsContents = {};
|
|
136
|
+
// Process blobs in the current level
|
|
137
|
+
for (const [, id] of Object.entries(baseSnapshot.blobs)) {
|
|
138
|
+
if (snapshotBlobs[id]) {
|
|
139
|
+
blobsContents[id] = (0, client_utils_1.stringToBuffer)(snapshotBlobs[id], "utf8");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Recursively process trees in the current level
|
|
143
|
+
const trees = {};
|
|
144
|
+
for (const [path, tree] of Object.entries(baseSnapshot.trees)) {
|
|
145
|
+
trees[path] = (0, exports.combineSnapshotTreeAndSnapshotBlobs)(tree, snapshotBlobs);
|
|
146
|
+
}
|
|
147
|
+
// Create a new snapshot tree with blob contents and processed trees
|
|
148
|
+
const snapshotTreeWithBlobContents = {
|
|
149
|
+
...baseSnapshot,
|
|
150
|
+
blobsContents,
|
|
151
|
+
trees,
|
|
152
|
+
};
|
|
153
|
+
return snapshotTreeWithBlobContents;
|
|
154
|
+
};
|
|
155
|
+
exports.combineSnapshotTreeAndSnapshotBlobs = combineSnapshotTreeAndSnapshotBlobs;
|
|
136
156
|
function isDeltaStreamConnectionForbiddenError(error) {
|
|
137
157
|
return (typeof error === "object" &&
|
|
138
158
|
error !== null &&
|
|
139
159
|
error?.errorType === driver_definitions_1.DriverErrorTypes.deltaStreamConnectionForbidden);
|
|
140
160
|
}
|
|
141
161
|
exports.isDeltaStreamConnectionForbiddenError = isDeltaStreamConnectionForbiddenError;
|
|
162
|
+
/**
|
|
163
|
+
* Validates format in parsed string get from detached container
|
|
164
|
+
* serialization using IPendingDetachedContainerState format.
|
|
165
|
+
*/
|
|
166
|
+
function isPendingDetachedContainerState(detachedContainerState) {
|
|
167
|
+
if (detachedContainerState?.attached === undefined ||
|
|
168
|
+
detachedContainerState?.baseSnapshot === undefined ||
|
|
169
|
+
detachedContainerState?.snapshotBlobs === undefined ||
|
|
170
|
+
detachedContainerState?.hasAttachmentBlobs === undefined) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
function getDetachedContainerStateFromSerializedContainer(serializedContainer) {
|
|
176
|
+
const hasBlobsSummaryTree = ".hasAttachmentBlobs";
|
|
177
|
+
const parsedContainerState = JSON.parse(serializedContainer);
|
|
178
|
+
if (isPendingDetachedContainerState(parsedContainerState)) {
|
|
179
|
+
return parsedContainerState;
|
|
180
|
+
}
|
|
181
|
+
else if ((0, driver_utils_1.isCombinedAppAndProtocolSummary)(parsedContainerState)) {
|
|
182
|
+
const { tree, blobs } = (0, exports.getSnapshotTreeAndBlobsFromSerializedContainer)(parsedContainerState);
|
|
183
|
+
const detachedContainerState = {
|
|
184
|
+
attached: false,
|
|
185
|
+
baseSnapshot: tree,
|
|
186
|
+
snapshotBlobs: blobs,
|
|
187
|
+
hasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,
|
|
188
|
+
};
|
|
189
|
+
return detachedContainerState;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
throw new telemetry_utils_1.UsageError("Cannot rehydrate detached container. Incorrect format");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.getDetachedContainerStateFromSerializedContainer = getDetachedContainerStateFromSerializedContainer;
|
|
196
|
+
/**
|
|
197
|
+
* Ensures only a single instance of the provided async function is running.
|
|
198
|
+
* If there are multiple calls they will all get the same promise to wait on.
|
|
199
|
+
*/
|
|
200
|
+
const runSingle = (func) => {
|
|
201
|
+
let running;
|
|
202
|
+
// don't mark this function async, so we return the same promise,
|
|
203
|
+
// rather than one that is wrapped due to async
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
205
|
+
return (...args) => {
|
|
206
|
+
if (running !== undefined) {
|
|
207
|
+
if (!(0, core_utils_1.compareArrays)(running.args, args)) {
|
|
208
|
+
return Promise.reject(new telemetry_utils_1.UsageError("Subsequent calls cannot use different arguments."));
|
|
209
|
+
}
|
|
210
|
+
return running.result;
|
|
211
|
+
}
|
|
212
|
+
running = { args, result: func(...args).finally(() => (running = undefined)) };
|
|
213
|
+
return running.result;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
exports.runSingle = runSingle;
|
|
142
217
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { parse } from \"url\";\nimport { v4 as uuid } from \"uuid\";\nimport { stringToBuffer, Uint8ArrayToArrayBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, unreachableCase } from \"@fluidframework/core-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @internal\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Null means do not use snapshots, undefined means load latest snapshot\n\t * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.\n\t * If needed, can add undefined which is treated by Container.load() as load latest snapshot.\n\t */\n\tversion: string | null | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @internal\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = parse(url, true);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? { id: match[1], path: match[2], query, version: parsed.query.version as string }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts summary tree (for upload) to snapshot tree (for download).\n * Summary tree blobs contain contents, but snapshot tree blobs normally\n * contain IDs pointing to storage. This will create 2 blob entries in the\n * snapshot tree for each blob in the summary tree. One will be the regular\n * path pointing to a uniquely generated ID. Then there will be another\n * entry with the path as that uniquely generated ID, and value as the\n * blob contents as a base-64 string.\n * @param summary - summary to convert\n */\nfunction convertSummaryToSnapshotWithEmbeddedBlobContents(\n\tsummary: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\tconst treeNode: ISnapshotTreeWithBlobContents = {\n\t\tblobs: {},\n\t\tblobsContents: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\ttreeNode.trees[key] =\n\t\t\t\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentBuffer =\n\t\t\t\t\ttypeof summaryObject.content === \"string\"\n\t\t\t\t\t\t? stringToBuffer(summaryObject.content, \"utf8\")\n\t\t\t\t\t\t: Uint8ArrayToArrayBuffer(summaryObject.content);\n\t\t\t\ttreeNode.blobsContents[blobId] = contentBuffer;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn treeNode;\n}\n\n/**\n * Combine and convert protocol and app summary tree to format which is readable by container while rehydrating.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nexport function convertProtocolAndAppSummaryToSnapshotTree(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\t// Shallow copy is fine, since we are doing a deep clone below.\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents =\n\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\n// This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which\n// a detached container can be rehydrated.\nexport const getSnapshotTreeFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshotTreeWithBlobContents => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x1e0 /* \"Protocol and App summary trees should be present\" */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { v4 as uuid } from \"uuid\";\nimport { Uint8ArrayToString, stringToBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError, UsageError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport { IPendingDetachedContainerState } from \"./container.js\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @internal\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Undefined means load latest snapshot, otherwise it's version ID passed to IDocumentStorageService.getVersions()\n\t * to figure out what snapshot to use.\n\t */\n\tversion: string | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @internal\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = new URL(url);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? {\n\t\t\t\tid: match[1],\n\t\t\t\tpath: match[2],\n\t\t\t\tquery,\n\t\t\t\t// URLSearchParams returns null if the param is not provided.\n\t\t\t\tversion: parsed.searchParams.get(\"version\") ?? undefined,\n\t\t }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts a summary to snapshot tree and separate its blob contents\n * to align detached container format with IPendingContainerState\n * @param summary - ISummaryTree\n */\nfunction convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {\n\ttree: ISnapshotTree;\n\tblobs: ISerializableBlobContents;\n} {\n\tlet blobContents: ISerializableBlobContents = {};\n\tconst treeNode: ISnapshotTree = {\n\t\tblobs: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t\tgroupId: summary.groupId,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst { tree, blobs } = convertSummaryToSnapshotAndBlobs(summaryObject);\n\t\t\t\ttreeNode.trees[key] = tree;\n\t\t\t\tblobContents = { ...blobContents, ...blobs };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentString: string =\n\t\t\t\t\tsummaryObject.content instanceof Uint8Array\n\t\t\t\t\t\t? Uint8ArrayToString(summaryObject.content)\n\t\t\t\t\t\t: summaryObject.content;\n\t\t\t\tblobContents[blobId] = contentString;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn { tree: treeNode, blobs: blobContents };\n}\n\n/**\n * Converts summary parts into a SnapshotTree and its blob contents.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nfunction convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): { tree: ISnapshotTree; blobs: ISerializableBlobContents } {\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents = convertSummaryToSnapshotAndBlobs(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\nexport const getSnapshotTreeAndBlobsFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): { tree: ISnapshotTree; blobs: ISerializableBlobContents } => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x8e6 /* Protocol and App summary trees should be present */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport const combineSnapshotTreeAndSnapshotBlobs = (\n\tbaseSnapshot: ISnapshotTree,\n\tsnapshotBlobs: ISerializableBlobContents,\n): ISnapshotTreeWithBlobContents => {\n\tconst blobsContents: { [path: string]: ArrayBufferLike } = {};\n\n\t// Process blobs in the current level\n\tfor (const [, id] of Object.entries(baseSnapshot.blobs)) {\n\t\tif (snapshotBlobs[id]) {\n\t\t\tblobsContents[id] = stringToBuffer(snapshotBlobs[id], \"utf8\");\n\t\t}\n\t}\n\n\t// Recursively process trees in the current level\n\tconst trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};\n\tfor (const [path, tree] of Object.entries(baseSnapshot.trees)) {\n\t\ttrees[path] = combineSnapshotTreeAndSnapshotBlobs(tree, snapshotBlobs);\n\t}\n\n\t// Create a new snapshot tree with blob contents and processed trees\n\tconst snapshotTreeWithBlobContents: ISnapshotTreeWithBlobContents = {\n\t\t...baseSnapshot,\n\t\tblobsContents,\n\t\ttrees,\n\t};\n\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n\n/**\n * Validates format in parsed string get from detached container\n * serialization using IPendingDetachedContainerState format.\n */\nfunction isPendingDetachedContainerState(\n\tdetachedContainerState: IPendingDetachedContainerState,\n): detachedContainerState is IPendingDetachedContainerState {\n\tif (\n\t\tdetachedContainerState?.attached === undefined ||\n\t\tdetachedContainerState?.baseSnapshot === undefined ||\n\t\tdetachedContainerState?.snapshotBlobs === undefined ||\n\t\tdetachedContainerState?.hasAttachmentBlobs === undefined\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst { tree, blobs } =\n\t\t\tgetSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\tbaseSnapshot: tree,\n\t\t\tsnapshotBlobs: blobs,\n\t\t\thasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,\n\t\t};\n\t\treturn detachedContainerState;\n\t} else {\n\t\tthrow new UsageError(\"Cannot rehydrate detached container. Incorrect format\");\n\t}\n}\n\n/**\n * Ensures only a single instance of the provided async function is running.\n * If there are multiple calls they will all get the same promise to wait on.\n */\nexport const runSingle = <A extends any[], R>(func: (...args: A) => Promise<R>) => {\n\tlet running:\n\t\t| {\n\t\t\t\targs: A;\n\t\t\t\tresult: Promise<R>;\n\t\t }\n\t\t| undefined;\n\t// don't mark this function async, so we return the same promise,\n\t// rather than one that is wrapped due to async\n\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\treturn (...args: A) => {\n\t\tif (running !== undefined) {\n\t\t\tif (!compareArrays(running.args, args)) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew UsageError(\"Subsequent calls cannot use different arguments.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn running.result;\n\t\t}\n\t\trunning = { args, result: func(...args).finally(() => (running = undefined)) };\n\t\treturn running.result;\n\t};\n};\n"]}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { AttachState } from "@fluidframework/container-definitions";
|
|
6
|
+
import { CombinedAppAndProtocolSummary } from "@fluidframework/driver-utils";
|
|
7
|
+
import { ISnapshotTree, ISummaryTree } from "@fluidframework/protocol-definitions";
|
|
8
|
+
import { IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
9
|
+
import { ISerializableBlobContents } from "./containerStorageAdapter.js";
|
|
10
|
+
import { IDetachedBlobStorage } from "./index.js";
|
|
11
|
+
/**
|
|
12
|
+
* The default state a newly created detached container will have.
|
|
13
|
+
* All but the state are optional and undefined, they just exist
|
|
14
|
+
* to make the union easy to deal with for both Detached types
|
|
15
|
+
*/
|
|
16
|
+
export interface DetachedDefaultData {
|
|
17
|
+
readonly state: AttachState.Detached;
|
|
18
|
+
readonly blobs?: undefined;
|
|
19
|
+
readonly summary?: undefined;
|
|
20
|
+
readonly redirectTable?: undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This always follows DetachedDefaultData when there are
|
|
24
|
+
* outstanding blobs in the detached blob storage.
|
|
25
|
+
* The redirect table will get filled up to include data
|
|
26
|
+
* about the blobs as they are uploaded.
|
|
27
|
+
*/
|
|
28
|
+
export interface DetachedDataWithOutstandingBlobs {
|
|
29
|
+
readonly state: AttachState.Detached;
|
|
30
|
+
readonly blobs: "outstanding";
|
|
31
|
+
readonly summary?: undefined;
|
|
32
|
+
readonly redirectTable: Map<string, string>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* This state always follows DetachedDataWithOutstandingBlobs.
|
|
36
|
+
* It signals that all outstanding blobs are done being uploaded,
|
|
37
|
+
* so the container can move to the attaching state.
|
|
38
|
+
*/
|
|
39
|
+
export interface AttachingDataWithBlobs {
|
|
40
|
+
readonly state: AttachState.Attaching;
|
|
41
|
+
readonly blobs: "done";
|
|
42
|
+
readonly summary: CombinedAppAndProtocolSummary;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* This always follows DefaultDetachedState when there are
|
|
46
|
+
* no blobs in the detached blob storage. Because there are
|
|
47
|
+
* no blobs we can immediately get the summary and transition
|
|
48
|
+
* to the attaching state.
|
|
49
|
+
*/
|
|
50
|
+
export interface AttachingDataWithoutBlobs {
|
|
51
|
+
readonly state: AttachState.Attaching;
|
|
52
|
+
readonly summary: CombinedAppAndProtocolSummary;
|
|
53
|
+
readonly blobs: "none";
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The final attachment state which signals the container is fully attached.
|
|
57
|
+
* The baseSnapshotAndBlobs will only be enabled when offline load is enabled.
|
|
58
|
+
*/
|
|
59
|
+
export interface AttachedData {
|
|
60
|
+
readonly state: AttachState.Attached;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A union of all the attachment data types for
|
|
64
|
+
* tracking across all container attachment states
|
|
65
|
+
*/
|
|
66
|
+
export type AttachmentData = DetachedDefaultData | DetachedDataWithOutstandingBlobs | AttachingDataWithoutBlobs | AttachingDataWithBlobs | AttachedData;
|
|
67
|
+
/**
|
|
68
|
+
* The data and services necessary for runRetriableAttachProcess.
|
|
69
|
+
*/
|
|
70
|
+
export interface AttachProcessProps {
|
|
71
|
+
/**
|
|
72
|
+
* The initial attachment data this call should start with
|
|
73
|
+
*/
|
|
74
|
+
readonly initialAttachmentData: Exclude<AttachmentData, AttachedData>;
|
|
75
|
+
/**
|
|
76
|
+
* The caller should use this callback to keep track of the current
|
|
77
|
+
* attachment data, and perform any other operations necessary
|
|
78
|
+
* for dealing with attachment state changes, like emitting events
|
|
79
|
+
*
|
|
80
|
+
* @param attachmentData - the updated attachment data */
|
|
81
|
+
readonly setAttachmentData: (attachmentData: AttachmentData) => void;
|
|
82
|
+
/**
|
|
83
|
+
* The caller should create and or get services based on the data, and its own information.
|
|
84
|
+
* @param data - the data to create services from,
|
|
85
|
+
* the summary property being the most relevant part of the data.
|
|
86
|
+
* @returns A compatible storage service
|
|
87
|
+
*/
|
|
88
|
+
readonly createOrGetStorageService: (data: ISummaryTree | undefined) => Promise<Pick<IDocumentStorageService, "createBlob" | "uploadSummaryWithContext">>;
|
|
89
|
+
/**
|
|
90
|
+
* The detached blob storage if it exists.
|
|
91
|
+
*/
|
|
92
|
+
readonly detachedBlobStorage?: Pick<IDetachedBlobStorage, "getBlobIds" | "readBlob" | "size">;
|
|
93
|
+
/**
|
|
94
|
+
* The caller should create the attachment summary for the container.
|
|
95
|
+
* @param redirectTable - Maps local blob ids to remote blobs ids.
|
|
96
|
+
* @returns The attachment summary for the container.
|
|
97
|
+
*/
|
|
98
|
+
readonly createAttachmentSummary: (redirectTable?: Map<string, string>) => CombinedAppAndProtocolSummary;
|
|
99
|
+
/**
|
|
100
|
+
* Whether offline load is enabled or not.
|
|
101
|
+
*/
|
|
102
|
+
readonly offlineLoadEnabled: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Executes the attach process state machine based on the provided data and services.
|
|
106
|
+
* This method is retriable on failure. Based on the provided initialAttachmentData
|
|
107
|
+
* this method will resume the attachment process and attempt to complete it.
|
|
108
|
+
*
|
|
109
|
+
* @param props - The data and services necessary to run the attachment process
|
|
110
|
+
*/
|
|
111
|
+
export declare const runRetriableAttachProcess: (props: AttachProcessProps) => Promise<{
|
|
112
|
+
tree: ISnapshotTree;
|
|
113
|
+
blobs: ISerializableBlobContents;
|
|
114
|
+
} | undefined>;
|
|
115
|
+
//# sourceMappingURL=attachment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;CAChD;AAED;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACvB,mBAAmB,GACnB,gCAAgC,GAChC,yBAAyB,GACzB,sBAAsB,GACtB,YAAY,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAEtE;;;;;8DAK0D;IAC1D,QAAQ,CAAC,iBAAiB,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,IAAI,CAAC;IAErE;;;;;OAKG;IACH,QAAQ,CAAC,yBAAyB,EAAE,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,KAC1B,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,YAAY,GAAG,0BAA0B,CAAC,CAAC,CAAC;IAEvF;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;IAE9F;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,CACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,6BAA6B,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,UAC9B,kBAAkB,KACvB,QAAQ;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,yBAAyB,CAAA;CAAE,GAAG,SAAS,CAqF/E,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { AttachState } from "@fluidframework/container-definitions";
|
|
6
|
+
import { assert } from "@fluidframework/core-utils";
|
|
7
|
+
import { getSnapshotTreeAndBlobsFromSerializedContainer } from "./utils.js";
|
|
8
|
+
/**
|
|
9
|
+
* Executes the attach process state machine based on the provided data and services.
|
|
10
|
+
* This method is retriable on failure. Based on the provided initialAttachmentData
|
|
11
|
+
* this method will resume the attachment process and attempt to complete it.
|
|
12
|
+
*
|
|
13
|
+
* @param props - The data and services necessary to run the attachment process
|
|
14
|
+
*/
|
|
15
|
+
export const runRetriableAttachProcess = async (props) => {
|
|
16
|
+
const { detachedBlobStorage, createOrGetStorageService, setAttachmentData, createAttachmentSummary, offlineLoadEnabled, } = props;
|
|
17
|
+
let currentData = props.initialAttachmentData;
|
|
18
|
+
if (currentData.blobs === undefined) {
|
|
19
|
+
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
20
|
+
const outstandingAttachmentBlobs = detachedBlobStorage !== undefined && detachedBlobStorage.size > 0;
|
|
21
|
+
// Determine the next phase of attaching which depends on if there are attachment blobs
|
|
22
|
+
// if there are, we will stay detached, so an empty file can be created, and the blobs
|
|
23
|
+
// uploaded, otherwise we will get the summary to create the file with and move to attaching
|
|
24
|
+
currentData = outstandingAttachmentBlobs
|
|
25
|
+
? {
|
|
26
|
+
state: AttachState.Detached,
|
|
27
|
+
blobs: "outstanding",
|
|
28
|
+
redirectTable: new Map(),
|
|
29
|
+
}
|
|
30
|
+
: {
|
|
31
|
+
state: AttachState.Attaching,
|
|
32
|
+
summary: props.createAttachmentSummary(),
|
|
33
|
+
blobs: "none",
|
|
34
|
+
};
|
|
35
|
+
setAttachmentData(currentData);
|
|
36
|
+
}
|
|
37
|
+
// this has to run here, as it is what creates the file
|
|
38
|
+
// and we need to file for all possible cases after this point
|
|
39
|
+
const storage = await createOrGetStorageService(currentData.summary);
|
|
40
|
+
if (currentData.blobs === "outstanding") {
|
|
41
|
+
const { redirectTable } = currentData;
|
|
42
|
+
// upload blobs to storage
|
|
43
|
+
assert(!!detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
44
|
+
// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
|
|
45
|
+
// support blob handles that only know about the local IDs
|
|
46
|
+
while (redirectTable.size < detachedBlobStorage.size) {
|
|
47
|
+
const newIds = detachedBlobStorage.getBlobIds().filter((id) => !redirectTable.has(id));
|
|
48
|
+
for (const id of newIds) {
|
|
49
|
+
const blob = await detachedBlobStorage.readBlob(id);
|
|
50
|
+
const response = await storage.createBlob(blob);
|
|
51
|
+
redirectTable.set(id, response.id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
setAttachmentData((currentData = {
|
|
55
|
+
state: AttachState.Attaching,
|
|
56
|
+
summary: createAttachmentSummary(redirectTable),
|
|
57
|
+
blobs: "done",
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
assert(currentData.state === AttachState.Attaching, 0x8e2 /* must be attaching by this point */);
|
|
61
|
+
if (currentData.blobs === "done") {
|
|
62
|
+
// done means outstanding blobs were uploaded.
|
|
63
|
+
// in that case an empty file was created, the blobs were uploaded
|
|
64
|
+
// and now this finally uploads the summary
|
|
65
|
+
await storage.uploadSummaryWithContext(currentData.summary, {
|
|
66
|
+
referenceSequenceNumber: 0,
|
|
67
|
+
ackHandle: undefined,
|
|
68
|
+
proposalHandle: undefined,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const snapshot = offlineLoadEnabled
|
|
72
|
+
? getSnapshotTreeAndBlobsFromSerializedContainer(currentData.summary)
|
|
73
|
+
: undefined;
|
|
74
|
+
setAttachmentData((currentData = {
|
|
75
|
+
state: AttachState.Attached,
|
|
76
|
+
}));
|
|
77
|
+
return snapshot;
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { CombinedAppAndProtocolSummary } from \"@fluidframework/driver-utils\";\nimport { ISnapshotTree, ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { getSnapshotTreeAndBlobsFromSerializedContainer } from \"./utils.js\";\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport { IDetachedBlobStorage } from \"./index.js\";\n\n/**\n * The default state a newly created detached container will have.\n * All but the state are optional and undefined, they just exist\n * to make the union easy to deal with for both Detached types\n */\nexport interface DetachedDefaultData {\n\treadonly state: AttachState.Detached;\n\treadonly blobs?: undefined;\n\treadonly summary?: undefined;\n\treadonly redirectTable?: undefined;\n}\n\n/**\n * This always follows DetachedDefaultData when there are\n * outstanding blobs in the detached blob storage.\n * The redirect table will get filled up to include data\n * about the blobs as they are uploaded.\n */\nexport interface DetachedDataWithOutstandingBlobs {\n\treadonly state: AttachState.Detached;\n\treadonly blobs: \"outstanding\";\n\treadonly summary?: undefined;\n\treadonly redirectTable: Map<string, string>;\n}\n\n/**\n * This state always follows DetachedDataWithOutstandingBlobs.\n * It signals that all outstanding blobs are done being uploaded,\n * so the container can move to the attaching state.\n */\nexport interface AttachingDataWithBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly blobs: \"done\";\n\treadonly summary: CombinedAppAndProtocolSummary;\n}\n\n/**\n * This always follows DefaultDetachedState when there are\n * no blobs in the detached blob storage. Because there are\n * no blobs we can immediately get the summary and transition\n * to the attaching state.\n */\nexport interface AttachingDataWithoutBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly summary: CombinedAppAndProtocolSummary;\n\treadonly blobs: \"none\";\n}\n\n/**\n * The final attachment state which signals the container is fully attached.\n * The baseSnapshotAndBlobs will only be enabled when offline load is enabled.\n */\nexport interface AttachedData {\n\treadonly state: AttachState.Attached;\n}\n\n/**\n * A union of all the attachment data types for\n * tracking across all container attachment states\n */\nexport type AttachmentData =\n\t| DetachedDefaultData\n\t| DetachedDataWithOutstandingBlobs\n\t| AttachingDataWithoutBlobs\n\t| AttachingDataWithBlobs\n\t| AttachedData;\n\n/**\n * The data and services necessary for runRetriableAttachProcess.\n */\nexport interface AttachProcessProps {\n\t/**\n\t * The initial attachment data this call should start with\n\t */\n\treadonly initialAttachmentData: Exclude<AttachmentData, AttachedData>;\n\n\t/**\n\t * The caller should use this callback to keep track of the current\n\t * attachment data, and perform any other operations necessary\n\t * for dealing with attachment state changes, like emitting events\n\t *\n\t * @param attachmentData - the updated attachment data\t */\n\treadonly setAttachmentData: (attachmentData: AttachmentData) => void;\n\n\t/**\n\t * The caller should create and or get services based on the data, and its own information.\n\t * @param data - the data to create services from,\n\t * the summary property being the most relevant part of the data.\n\t * @returns A compatible storage service\n\t */\n\treadonly createOrGetStorageService: (\n\t\tdata: ISummaryTree | undefined,\n\t) => Promise<Pick<IDocumentStorageService, \"createBlob\" | \"uploadSummaryWithContext\">>;\n\n\t/**\n\t * The detached blob storage if it exists.\n\t */\n\treadonly detachedBlobStorage?: Pick<IDetachedBlobStorage, \"getBlobIds\" | \"readBlob\" | \"size\">;\n\n\t/**\n\t * The caller should create the attachment summary for the container.\n\t * @param redirectTable - Maps local blob ids to remote blobs ids.\n\t * @returns The attachment summary for the container.\n\t */\n\treadonly createAttachmentSummary: (\n\t\tredirectTable?: Map<string, string>,\n\t) => CombinedAppAndProtocolSummary;\n\n\t/**\n\t * Whether offline load is enabled or not.\n\t */\n\treadonly offlineLoadEnabled: boolean;\n}\n\n/**\n * Executes the attach process state machine based on the provided data and services.\n * This method is retriable on failure. Based on the provided initialAttachmentData\n * this method will resume the attachment process and attempt to complete it.\n *\n * @param props - The data and services necessary to run the attachment process\n */\nexport const runRetriableAttachProcess = async (\n\tprops: AttachProcessProps,\n): Promise<{ tree: ISnapshotTree; blobs: ISerializableBlobContents } | undefined> => {\n\tconst {\n\t\tdetachedBlobStorage,\n\t\tcreateOrGetStorageService,\n\t\tsetAttachmentData,\n\t\tcreateAttachmentSummary,\n\t\tofflineLoadEnabled,\n\t} = props;\n\tlet currentData: AttachmentData = props.initialAttachmentData;\n\n\tif (currentData.blobs === undefined) {\n\t\t// If attachment blobs were uploaded in detached state we will go through a different attach flow\n\t\tconst outstandingAttachmentBlobs =\n\t\t\tdetachedBlobStorage !== undefined && detachedBlobStorage.size > 0;\n\t\t// Determine the next phase of attaching which depends on if there are attachment blobs\n\t\t// if there are, we will stay detached, so an empty file can be created, and the blobs\n\t\t// uploaded, otherwise we will get the summary to create the file with and move to attaching\n\t\tcurrentData = outstandingAttachmentBlobs\n\t\t\t? {\n\t\t\t\t\tstate: AttachState.Detached,\n\t\t\t\t\tblobs: \"outstanding\",\n\t\t\t\t\tredirectTable: new Map<string, string>(),\n\t\t\t }\n\t\t\t: {\n\t\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\t\tsummary: props.createAttachmentSummary(),\n\t\t\t\t\tblobs: \"none\",\n\t\t\t };\n\t\tsetAttachmentData(currentData);\n\t}\n\n\t// this has to run here, as it is what creates the file\n\t// and we need to file for all possible cases after this point\n\tconst storage = await createOrGetStorageService(currentData.summary);\n\n\tif (currentData.blobs === \"outstanding\") {\n\t\tconst { redirectTable } = currentData;\n\t\t// upload blobs to storage\n\t\tassert(!!detachedBlobStorage, 0x24e /* \"assertion for type narrowing\" */);\n\n\t\t// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to\n\t\t// support blob handles that only know about the local IDs\n\t\twhile (redirectTable.size < detachedBlobStorage.size) {\n\t\t\tconst newIds = detachedBlobStorage.getBlobIds().filter((id) => !redirectTable.has(id));\n\t\t\tfor (const id of newIds) {\n\t\t\t\tconst blob = await detachedBlobStorage.readBlob(id);\n\t\t\t\tconst response = await storage.createBlob(blob);\n\t\t\t\tredirectTable.set(id, response.id);\n\t\t\t}\n\t\t}\n\t\tsetAttachmentData(\n\t\t\t(currentData = {\n\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\tsummary: createAttachmentSummary(redirectTable),\n\t\t\t\tblobs: \"done\",\n\t\t\t}),\n\t\t);\n\t}\n\n\tassert(\n\t\tcurrentData.state === AttachState.Attaching,\n\t\t0x8e2 /* must be attaching by this point */,\n\t);\n\n\tif (currentData.blobs === \"done\") {\n\t\t// done means outstanding blobs were uploaded.\n\t\t// in that case an empty file was created, the blobs were uploaded\n\t\t// and now this finally uploads the summary\n\t\tawait storage.uploadSummaryWithContext(currentData.summary, {\n\t\t\treferenceSequenceNumber: 0,\n\t\t\tackHandle: undefined,\n\t\t\tproposalHandle: undefined,\n\t\t});\n\t}\n\n\tconst snapshot = offlineLoadEnabled\n\t\t? getSnapshotTreeAndBlobsFromSerializedContainer(currentData.summary)\n\t\t: undefined;\n\n\tsetAttachmentData(\n\t\t(currentData = {\n\t\t\tstate: AttachState.Attached,\n\t\t}),\n\t);\n\treturn snapshot;\n};\n"]}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from "@fluid-internal/client-utils";
|
|
3
6
|
import { IAudienceOwner } from "@fluidframework/container-definitions";
|
|
4
7
|
import { IClient } from "@fluidframework/protocol-definitions";
|
|
5
8
|
/**
|
|
@@ -19,12 +22,18 @@ export declare class Audience extends EventEmitter implements IAudienceOwner {
|
|
|
19
22
|
*/
|
|
20
23
|
removeMember(clientId: string): boolean;
|
|
21
24
|
/**
|
|
22
|
-
* Retrieves all the members in the audience
|
|
25
|
+
* Retrieves all the members in the audience.
|
|
26
|
+
*
|
|
27
|
+
* @remarks When the container is disconnected, this will keep returning the audience as it was last seen before the
|
|
28
|
+
* container disconnected.
|
|
23
29
|
*/
|
|
24
30
|
getMembers(): Map<string, IClient>;
|
|
25
31
|
/**
|
|
26
|
-
* Retrieves a specific member of the audience
|
|
32
|
+
* Retrieves a specific member of the audience.
|
|
33
|
+
*
|
|
34
|
+
* @remarks When the container is disconnected, this will keep returning members from the audience as it was last seen
|
|
35
|
+
* before the container disconnected.
|
|
27
36
|
*/
|
|
28
37
|
getMember(clientId: string): IClient | undefined;
|
|
29
38
|
}
|
|
30
|
-
//# sourceMappingURL=audience.d.
|
|
39
|
+
//# sourceMappingURL=audience.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audience.d.ts","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAE/D;;GAEG;AACH,qBAAa,QAAS,SAAQ,YAAa,YAAW,cAAc;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;;IAQ/C,EAAE,CACR,KAAK,EAAE,WAAW,GAAG,cAAc,EACnC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GACnD,IAAI;IAKP;;OAEG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAenD;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAW9C;;;;;OAKG;IACI,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAIzC;;;;;OAKG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;CAGvD"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from "@fluid-internal/client-utils";
|
|
2
6
|
import { assert } from "@fluidframework/core-utils";
|
|
3
7
|
/**
|
|
4
8
|
* Audience represents all clients connected to the op stream.
|
|
@@ -44,16 +48,22 @@ export class Audience extends EventEmitter {
|
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
/**
|
|
47
|
-
* Retrieves all the members in the audience
|
|
51
|
+
* Retrieves all the members in the audience.
|
|
52
|
+
*
|
|
53
|
+
* @remarks When the container is disconnected, this will keep returning the audience as it was last seen before the
|
|
54
|
+
* container disconnected.
|
|
48
55
|
*/
|
|
49
56
|
getMembers() {
|
|
50
57
|
return new Map(this.members);
|
|
51
58
|
}
|
|
52
59
|
/**
|
|
53
|
-
* Retrieves a specific member of the audience
|
|
60
|
+
* Retrieves a specific member of the audience.
|
|
61
|
+
*
|
|
62
|
+
* @remarks When the container is disconnected, this will keep returning members from the audience as it was last seen
|
|
63
|
+
* before the container disconnected.
|
|
54
64
|
*/
|
|
55
65
|
getMember(clientId) {
|
|
56
66
|
return this.members.get(clientId);
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
|
-
//# sourceMappingURL=audience.
|
|
69
|
+
//# sourceMappingURL=audience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audience.js","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAIpD;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,YAAY;IAGzC;QACC,KAAK,EAAE,CAAC;QAHQ,YAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QAIrD,kHAAkH;QAClH,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAMM,EAAE,CAAC,KAAa,EAAE,QAAkC;QAC1D,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAgB;QAClD,mGAAmG;QACnG,+FAA+F;QAC/F,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,CACL,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAClD,KAAK,CAAC,wDAAwD,CAC9D,CAAC;SACF;aAAM;YACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SAC1C;IACF,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,QAAgB;QACnC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE;YAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;SACZ;aAAM;YACN,OAAO,KAAK,CAAC;SACb;IACF,CAAC;IAED;;;;;OAKG;IACI,UAAU;QAChB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACI,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { EventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { IAudienceOwner } from \"@fluidframework/container-definitions\";\nimport { IClient } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Audience represents all clients connected to the op stream.\n */\nexport class Audience extends EventEmitter implements IAudienceOwner {\n\tprivate readonly members = new Map<string, IClient>();\n\n\tconstructor() {\n\t\tsuper();\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t}\n\n\tpublic on(\n\t\tevent: \"addMember\" | \"removeMember\",\n\t\tlistener: (clientId: string, client: IClient) => void,\n\t): this;\n\tpublic on(event: string, listener: (...args: any[]) => void): this {\n\t\treturn super.on(event, listener);\n\t}\n\n\t/**\n\t * Adds a new client to the audience\n\t */\n\tpublic addMember(clientId: string, details: IClient) {\n\t\t// Given that signal delivery is unreliable process, we might observe same client being added twice\n\t\t// In such case we should see exactly same payload (IClient), and should not raise event twice!\n\t\tif (this.members.has(clientId)) {\n\t\t\tconst client = this.members.get(clientId);\n\t\t\tassert(\n\t\t\t\tJSON.stringify(client) === JSON.stringify(details),\n\t\t\t\t0x4b2 /* new client has different payload from existing one */,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.members.set(clientId, details);\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a client from the audience. Only emits an event if a client is actually removed\n\t * @returns if a client was removed from the audience\n\t */\n\tpublic removeMember(clientId: string): boolean {\n\t\tconst removedClient = this.members.get(clientId);\n\t\tif (removedClient !== undefined) {\n\t\t\tthis.members.delete(clientId);\n\t\t\tthis.emit(\"removeMember\", clientId, removedClient);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all the members in the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning the audience as it was last seen before the\n\t * container disconnected.\n\t */\n\tpublic getMembers(): Map<string, IClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning members from the audience as it was last seen\n\t * before the container disconnected.\n\t */\n\tpublic getMember(clientId: string): IClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catchUpMonitor.d.ts","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAGtE,oCAAoC;AACpC,KAAK,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAEnC,mGAAmG;AACnG,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC;AAE1C;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IAepD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAf1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAKxB;IAEF;;OAEG;gBAEe,YAAY,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,gBAAgB;IAerC,QAAQ,EAAE,OAAO,CAAS;IAC1B,OAAO;CAQd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catchUpMonitor.js","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAUpD;;;GAGG;AACH,MAAM,OAAO,cAAc;IAW1B;;OAEG;IACH,YACkB,YAAqC,EACrC,QAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAyB;QACrC,aAAQ,GAAR,QAAQ,CAAkB;QAdpC,aAAQ,GAAY,KAAK,CAAC;QAEjB,cAAS,GAAG,CAAC,OAA0D,EAAE,EAAE;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aAChB;QACF,CAAC,CAAC;QAsBK,aAAQ,GAAY,KAAK,CAAC;QAbhC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;QAE5D,MAAM,CACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAC5D,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE3C,wEAAwE;QACxE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1E,CAAC;IAGM,OAAO;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\n\n/** @see CatchUpMonitor for usage */\ntype CaughtUpListener = () => void;\n\n/** Monitor that emits an event when a Container has caught up to a given point in the op stream */\nexport type ICatchUpMonitor = IDisposable;\n\n/**\n * Monitors a Container's DeltaManager, notifying listeners when all ops have been processed\n * that were known at the time the monitor was created.\n */\nexport class CatchUpMonitor implements ICatchUpMonitor {\n\tprivate readonly targetSeqNumber: number;\n\tprivate caughtUp: boolean = false;\n\n\tprivate readonly opHandler = (message: Pick<ISequencedDocumentMessage, \"sequenceNumber\">) => {\n\t\tif (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {\n\t\t\tthis.caughtUp = true;\n\t\t\tthis.listener();\n\t\t}\n\t};\n\n\t/**\n\t * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.\n\t */\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<any, any>,\n\t\tprivate readonly listener: CaughtUpListener,\n\t) {\n\t\tthis.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\n\t\tassert(\n\t\t\tthis.targetSeqNumber >= this.deltaManager.lastSequenceNumber,\n\t\t\t0x37c /* Cannot wait for seqNumber below last processed sequence number */,\n\t\t);\n\n\t\tthis.deltaManager.on(\"op\", this.opHandler);\n\n\t\t// Simulate the last processed op to set caughtUp in case we already are\n\t\tthis.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });\n\t}\n\n\tpublic disposed: boolean = false;\n\tpublic dispose() {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.disposed = true;\n\n\t\tthis.deltaManager.off(\"op\", this.opHandler);\n\t}\n}\n"]}
|