@fluidframework/container-loader 2.21.0 → 2.22.1
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/.mocharc.cjs +3 -0
- package/CHANGELOG.md +4 -0
- package/README.md +1 -0
- package/dist/container.d.ts +2 -2
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +3 -4
- package/dist/container.js.map +1 -1
- package/dist/loader.js +1 -1
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol/quorum.js +4 -4
- package/dist/protocol/quorum.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -4
- package/dist/utils.js.map +1 -1
- package/lib/container.d.ts +2 -2
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +3 -4
- package/lib/container.js.map +1 -1
- package/lib/loader.js +1 -1
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol/quorum.js +4 -4
- package/lib/protocol/quorum.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +2 -4
- package/lib/utils.js.map +1 -1
- package/package.json +14 -14
- package/src/container.ts +9 -8
- package/src/packageVersion.ts +1 -1
- package/src/utils.ts +2 -5
package/lib/loader.js
CHANGED
|
@@ -109,7 +109,7 @@ export class Loader {
|
|
|
109
109
|
throw new Error(message);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
request.headers
|
|
112
|
+
request.headers ??= {};
|
|
113
113
|
// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
|
|
114
114
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
115
115
|
request.headers[LoaderHeader.version] =
|
package/lib/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.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 {\n\tIContainer,\n\tIFluidCodeDetails,\n\tIFluidModule,\n\tIHostLoader,\n\tILoader,\n\tILoaderOptions as ILoaderOptions1,\n\tIProvideFluidCodeDetailsComparer,\n\tLoaderHeader,\n} from \"@fluidframework/container-definitions/internal\";\nimport {\n\tFluidObject,\n\tIConfigProviderBase,\n\tIRequest,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { IClientDetails } from \"@fluidframework/driver-definitions\";\nimport {\n\tIDocumentServiceFactory,\n\tIDocumentStorageService,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tMonitoringContext,\n\tPerformanceEvent,\n\tcreateChildMonitoringContext,\n\tmixinMonitoringContext,\n\tsessionStorageConfigProvider,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { Container } from \"./container.js\";\nimport { DebugLogger } from \"./debugLogger.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { ProtocolHandlerBuilder } from \"./protocol.js\";\nimport type { IPendingContainerState } from \"./serializedStateManager.js\";\nimport {\n\tgetAttachedContainerStateFromSerializedContainer,\n\ttryParseCompatibleResolvedUrl,\n} from \"./utils.js\";\n\nfunction ensureResolvedUrlDefined(\n\tresolved: IResolvedUrl | undefined,\n): asserts resolved is IResolvedUrl {\n\tif (resolved === undefined) {\n\t\tthrow new Error(`Object is not a IResolveUrl.`);\n\t}\n}\n/**\n * @internal\n */\nexport class RelativeLoader implements ILoader {\n\tconstructor(\n\t\tprivate readonly container: Container,\n\t\tprivate readonly loader: ILoader | undefined,\n\t) {}\n\n\tpublic async resolve(request: IRequest): Promise<IContainer> {\n\t\tif (request.url.startsWith(\"/\")) {\n\t\t\tensureResolvedUrlDefined(this.container.resolvedUrl);\n\t\t\tconst container = await this.container.clone(\n\t\t\t\t{\n\t\t\t\t\tresolvedUrl: { ...this.container.resolvedUrl },\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tversion: request.headers?.[LoaderHeader.version] ?? undefined,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tloadMode: request.headers?.[LoaderHeader.loadMode],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tcanReconnect: request.headers?.[LoaderHeader.reconnect],\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tclientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn container;\n\t\t}\n\n\t\tif (this.loader === undefined) {\n\t\t\tthrow new Error(\"Cannot resolve external containers\");\n\t\t}\n\t\treturn this.loader.resolve(request);\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n * @deprecated Use {@link @fluidframework/container-definitions#ILoaderOptions} instead\n */\nexport interface ILoaderOptions extends ILoaderOptions1 {\n\t/**\n\t *\n\t * @deprecated No longer needed or used (initially introduced to test single-commit summaries).\n\t * Driver layer can enable single-commit summaries via document service policies if needed.\n\t * ADO #9098: To remove declaration and usage from code.\n\t */\n\tsummarizeProtocolTree?: boolean;\n}\n\n/**\n * @deprecated IFluidModuleWithDetails interface is moved to\n * {@link @fluidframework/container-definitions#IFluidModuleWithDetails}\n * to have all the code loading modules in one package. #8193\n * Encapsulates a module entry point with corresponding code details.\n * @legacy\n * @alpha\n */\nexport interface IFluidModuleWithDetails {\n\t/**\n\t * Fluid code module that implements the runtime factory needed to instantiate the container runtime.\n\t */\n\tmodule: IFluidModule;\n\t/**\n\t * Code details associated with the module. Represents a document schema this module supports.\n\t * If the code loader implements the {@link @fluidframework/core-interfaces#IFluidCodeDetailsComparer} interface,\n\t * it'll be called to determine whether the module code details satisfy the new code proposal in the quorum.\n\t */\n\tdetails: IFluidCodeDetails;\n}\n\n/**\n * @deprecated ICodeDetailsLoader interface is moved to {@link @fluidframework/container-definitions#ICodeDetailsLoader}\n * to have code loading modules in one package. #8193\n * Fluid code loader resolves a code module matching the document schema, i.e. code details, such as\n * a package name and package version range.\n * @legacy\n * @alpha\n */\nexport interface ICodeDetailsLoader extends Partial<IProvideFluidCodeDetailsComparer> {\n\t/**\n\t * Load the code module (package) that is capable to interact with the document.\n\t *\n\t * @param source - Code proposal that articulates the current schema the document is written in.\n\t * @returns Code module entry point along with the code details associated with it.\n\t */\n\tload(source: IFluidCodeDetails): Promise<IFluidModuleWithDetails>;\n}\n\n/**\n * Services and properties necessary for creating a loader\n * @legacy\n * @alpha\n */\nexport interface ILoaderProps {\n\t/**\n\t * The url resolver used by the loader for resolving external urls\n\t * into Fluid urls such that the container specified by the\n\t * external url can be loaded.\n\t */\n\treadonly urlResolver: IUrlResolver;\n\t/**\n\t * The document service factory take the Fluid url provided\n\t * by the resolved url and constructs all the necessary services\n\t * for communication with the container's server.\n\t */\n\treadonly documentServiceFactory: IDocumentServiceFactory;\n\t/**\n\t * The code loader handles loading the necessary code\n\t * for running a container once it is loaded.\n\t */\n\treadonly codeLoader: ICodeDetailsLoader;\n\n\t/**\n\t * A property bag of options used by various layers\n\t * to control features\n\t */\n\treadonly options?: ILoaderOptions;\n\n\t/**\n\t * Scope is provided to all container and is a set of shared\n\t * services for container's to integrate with their host environment.\n\t */\n\treadonly scope?: FluidObject;\n\n\t/**\n\t * The logger that all telemetry should be pushed to.\n\t */\n\treadonly logger?: ITelemetryBaseLogger;\n\n\t/**\n\t * Blobs storage for detached containers.\n\t */\n\treadonly detachedBlobStorage?: IDetachedBlobStorage;\n\n\t/**\n\t * The configuration provider which may be used to control features.\n\t */\n\treadonly configProvider?: IConfigProviderBase;\n\n\t/**\n\t * Optional property for allowing the container to use a custom\n\t * protocol implementation for handling the quorum and/or the audience.\n\t */\n\treadonly protocolHandlerBuilder?: ProtocolHandlerBuilder;\n}\n\n/**\n * Services and properties used by and exposed by the loader\n * @legacy\n * @alpha\n */\nexport interface ILoaderServices {\n\t/**\n\t * The url resolver used by the loader for resolving external urls\n\t * into Fluid urls such that the container specified by the\n\t * external url can be loaded.\n\t */\n\treadonly urlResolver: IUrlResolver;\n\t/**\n\t * The document service factory take the Fluid url provided\n\t * by the resolved url and constructs all the necessary services\n\t * for communication with the container's server.\n\t */\n\treadonly documentServiceFactory: IDocumentServiceFactory;\n\t/**\n\t * The code loader handles loading the necessary code\n\t * for running a container once it is loaded.\n\t */\n\treadonly codeLoader: ICodeDetailsLoader;\n\n\t/**\n\t * A property bag of options used by various layers\n\t * to control features\n\t */\n\treadonly options: ILoaderOptions;\n\n\t/**\n\t * Scope is provided to all container and is a set of shared\n\t * services for container's to integrate with their host environment.\n\t */\n\treadonly scope: FluidObject;\n\n\t/**\n\t * The logger downstream consumers should construct their loggers from\n\t */\n\treadonly subLogger: ITelemetryLoggerExt;\n\n\t/**\n\t * Blobs storage for detached containers.\n\t * @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\n\t */\n\treadonly detachedBlobStorage?: IDetachedBlobStorage;\n\n\t/**\n\t * Optional property for allowing the container to use a custom\n\t * protocol implementation for handling the quorum and/or the audience.\n\t */\n\treadonly protocolHandlerBuilder?: ProtocolHandlerBuilder;\n}\n\n/**\n * Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support\n * blobs in detached containers.\n * @legacy\n * @alpha\n *\n * @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\n */\nexport type IDetachedBlobStorage = Pick<IDocumentStorageService, \"createBlob\" | \"readBlob\"> & {\n\tsize: number;\n\t/**\n\t * Return an array of all blob IDs present in storage\n\t */\n\tgetBlobIds(): string[];\n\n\t/**\n\t * After the container is attached, the detached blob storage is no longer needed and will be disposed.\n\t */\n\tdispose?(): void;\n};\n\n/**\n * Manages Fluid resource loading\n * @legacy\n * @alpha\n */\nexport class Loader implements IHostLoader {\n\tpublic readonly services: ILoaderServices;\n\tprivate readonly mc: MonitoringContext;\n\n\tconstructor(loaderProps: ILoaderProps) {\n\t\tconst {\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory,\n\t\t\tcodeLoader,\n\t\t\toptions,\n\t\t\tscope,\n\t\t\tlogger,\n\t\t\tdetachedBlobStorage,\n\t\t\tconfigProvider,\n\t\t\tprotocolHandlerBuilder,\n\t\t} = loaderProps;\n\n\t\tconst telemetryProps = {\n\t\t\tloaderId: uuid(),\n\t\t\tloaderVersion: pkgVersion,\n\t\t};\n\n\t\tconst subMc = mixinMonitoringContext(\n\t\t\tDebugLogger.mixinDebugLogger(\"fluid:telemetry\", logger, {\n\t\t\t\tall: telemetryProps,\n\t\t\t}),\n\t\t\tsessionStorageConfigProvider.value,\n\t\t\tconfigProvider,\n\t\t);\n\n\t\tthis.services = {\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory,\n\t\t\tcodeLoader,\n\t\t\toptions: options ?? {},\n\t\t\tscope:\n\t\t\t\toptions?.provideScopeLoader === false ? { ...scope } : { ...scope, ILoader: this },\n\t\t\tdetachedBlobStorage,\n\t\t\tprotocolHandlerBuilder,\n\t\t\tsubLogger: subMc.logger,\n\t\t};\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: this.services.subLogger,\n\t\t\tnamespace: \"Loader\",\n\t\t});\n\t}\n\n\tpublic async createDetachedContainer(\n\t\tcodeDetails: IFluidCodeDetails,\n\t\tcreateDetachedProps?: {\n\t\t\tcanReconnect?: boolean;\n\t\t\tclientDetailsOverride?: IClientDetails;\n\t\t},\n\t): Promise<IContainer> {\n\t\treturn Container.createDetached(\n\t\t\t{\n\t\t\t\t...createDetachedProps,\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t\tcodeDetails,\n\t\t);\n\t}\n\n\tpublic async rehydrateDetachedContainerFromSnapshot(\n\t\tsnapshot: string,\n\t\tcreateDetachedProps?: {\n\t\t\tcanReconnect?: boolean;\n\t\t\tclientDetailsOverride?: IClientDetails;\n\t\t},\n\t): Promise<IContainer> {\n\t\treturn Container.rehydrateDetachedFromSnapshot(\n\t\t\t{\n\t\t\t\t...createDetachedProps,\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t\tsnapshot,\n\t\t);\n\t}\n\n\tpublic async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {\n\t\tconst eventName = pendingLocalState === undefined ? \"Resolve\" : \"ResolveWithPendingState\";\n\t\treturn PerformanceEvent.timedExecAsync(this.mc.logger, { eventName }, async () => {\n\t\t\treturn this.resolveCore(\n\t\t\t\trequest,\n\t\t\t\tgetAttachedContainerStateFromSerializedContainer(pendingLocalState),\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async resolveCore(\n\t\trequest: IRequest,\n\t\tpendingLocalState?: IPendingContainerState,\n\t): Promise<Container> {\n\t\tconst resolvedAsFluid = await this.services.urlResolver.resolve(request);\n\t\tensureResolvedUrlDefined(resolvedAsFluid);\n\n\t\t// Parse URL into data stores\n\t\tconst parsed = tryParseCompatibleResolvedUrl(resolvedAsFluid.url);\n\t\tif (parsed === undefined) {\n\t\t\tthrow new Error(`Invalid URL ${resolvedAsFluid.url}`);\n\t\t}\n\n\t\tif (pendingLocalState !== undefined) {\n\t\t\tconst parsedPendingUrl = tryParseCompatibleResolvedUrl(pendingLocalState.url);\n\t\t\tif (\n\t\t\t\tparsedPendingUrl?.id !== parsed.id ||\n\t\t\t\tparsedPendingUrl?.path.replace(/\\/$/, \"\") !== parsed.path.replace(/\\/$/, \"\")\n\t\t\t) {\n\t\t\t\tconst message = `URL ${resolvedAsFluid.url} does not match pending state URL ${pendingLocalState.url}`;\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\t\t}\n\n\t\trequest.headers ??= {};\n\t\t// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\trequest.headers[LoaderHeader.version] =\n\t\t\tparsed.version ?? request.headers[LoaderHeader.version];\n\n\t\treturn this.loadContainer(request, resolvedAsFluid, pendingLocalState);\n\t}\n\n\tprivate async loadContainer(\n\t\trequest: IRequest,\n\t\tresolvedUrl: IResolvedUrl,\n\t\tpendingLocalState?: IPendingContainerState,\n\t): Promise<Container> {\n\t\treturn Container.load(\n\t\t\t{\n\t\t\t\tresolvedUrl,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tversion: request.headers?.[LoaderHeader.version] ?? undefined,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tloadMode: request.headers?.[LoaderHeader.loadMode],\n\t\t\t\tpendingLocalState,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tcanReconnect: request.headers?.[LoaderHeader.reconnect],\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tclientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.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 {\n\tIContainer,\n\tIFluidCodeDetails,\n\tIFluidModule,\n\tIHostLoader,\n\tILoader,\n\tILoaderOptions as ILoaderOptions1,\n\tIProvideFluidCodeDetailsComparer,\n\tLoaderHeader,\n} from \"@fluidframework/container-definitions/internal\";\nimport {\n\tFluidObject,\n\tIConfigProviderBase,\n\tIRequest,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { IClientDetails } from \"@fluidframework/driver-definitions\";\nimport {\n\tIDocumentServiceFactory,\n\tIDocumentStorageService,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tITelemetryLoggerExt,\n\tMonitoringContext,\n\tPerformanceEvent,\n\tcreateChildMonitoringContext,\n\tmixinMonitoringContext,\n\tsessionStorageConfigProvider,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { Container } from \"./container.js\";\nimport { DebugLogger } from \"./debugLogger.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport { ProtocolHandlerBuilder } from \"./protocol.js\";\nimport type { IPendingContainerState } from \"./serializedStateManager.js\";\nimport {\n\tgetAttachedContainerStateFromSerializedContainer,\n\ttryParseCompatibleResolvedUrl,\n} from \"./utils.js\";\n\nfunction ensureResolvedUrlDefined(\n\tresolved: IResolvedUrl | undefined,\n): asserts resolved is IResolvedUrl {\n\tif (resolved === undefined) {\n\t\tthrow new Error(`Object is not a IResolveUrl.`);\n\t}\n}\n/**\n * @internal\n */\nexport class RelativeLoader implements ILoader {\n\tconstructor(\n\t\tprivate readonly container: Container,\n\t\tprivate readonly loader: ILoader | undefined,\n\t) {}\n\n\tpublic async resolve(request: IRequest): Promise<IContainer> {\n\t\tif (request.url.startsWith(\"/\")) {\n\t\t\tensureResolvedUrlDefined(this.container.resolvedUrl);\n\t\t\tconst container = await this.container.clone(\n\t\t\t\t{\n\t\t\t\t\tresolvedUrl: { ...this.container.resolvedUrl },\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tversion: request.headers?.[LoaderHeader.version] ?? undefined,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tloadMode: request.headers?.[LoaderHeader.loadMode],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tcanReconnect: request.headers?.[LoaderHeader.reconnect],\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\tclientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn container;\n\t\t}\n\n\t\tif (this.loader === undefined) {\n\t\t\tthrow new Error(\"Cannot resolve external containers\");\n\t\t}\n\t\treturn this.loader.resolve(request);\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n * @deprecated Use {@link @fluidframework/container-definitions#ILoaderOptions} instead\n */\nexport interface ILoaderOptions extends ILoaderOptions1 {\n\t/**\n\t *\n\t * @deprecated No longer needed or used (initially introduced to test single-commit summaries).\n\t * Driver layer can enable single-commit summaries via document service policies if needed.\n\t * ADO #9098: To remove declaration and usage from code.\n\t */\n\tsummarizeProtocolTree?: boolean;\n}\n\n/**\n * @deprecated IFluidModuleWithDetails interface is moved to\n * {@link @fluidframework/container-definitions#IFluidModuleWithDetails}\n * to have all the code loading modules in one package. #8193\n * Encapsulates a module entry point with corresponding code details.\n * @legacy\n * @alpha\n */\nexport interface IFluidModuleWithDetails {\n\t/**\n\t * Fluid code module that implements the runtime factory needed to instantiate the container runtime.\n\t */\n\tmodule: IFluidModule;\n\t/**\n\t * Code details associated with the module. Represents a document schema this module supports.\n\t * If the code loader implements the {@link @fluidframework/core-interfaces#IFluidCodeDetailsComparer} interface,\n\t * it'll be called to determine whether the module code details satisfy the new code proposal in the quorum.\n\t */\n\tdetails: IFluidCodeDetails;\n}\n\n/**\n * @deprecated ICodeDetailsLoader interface is moved to {@link @fluidframework/container-definitions#ICodeDetailsLoader}\n * to have code loading modules in one package. #8193\n * Fluid code loader resolves a code module matching the document schema, i.e. code details, such as\n * a package name and package version range.\n * @legacy\n * @alpha\n */\nexport interface ICodeDetailsLoader extends Partial<IProvideFluidCodeDetailsComparer> {\n\t/**\n\t * Load the code module (package) that is capable to interact with the document.\n\t *\n\t * @param source - Code proposal that articulates the current schema the document is written in.\n\t * @returns Code module entry point along with the code details associated with it.\n\t */\n\tload(source: IFluidCodeDetails): Promise<IFluidModuleWithDetails>;\n}\n\n/**\n * Services and properties necessary for creating a loader\n * @legacy\n * @alpha\n */\nexport interface ILoaderProps {\n\t/**\n\t * The url resolver used by the loader for resolving external urls\n\t * into Fluid urls such that the container specified by the\n\t * external url can be loaded.\n\t */\n\treadonly urlResolver: IUrlResolver;\n\t/**\n\t * The document service factory take the Fluid url provided\n\t * by the resolved url and constructs all the necessary services\n\t * for communication with the container's server.\n\t */\n\treadonly documentServiceFactory: IDocumentServiceFactory;\n\t/**\n\t * The code loader handles loading the necessary code\n\t * for running a container once it is loaded.\n\t */\n\treadonly codeLoader: ICodeDetailsLoader;\n\n\t/**\n\t * A property bag of options used by various layers\n\t * to control features\n\t */\n\treadonly options?: ILoaderOptions;\n\n\t/**\n\t * Scope is provided to all container and is a set of shared\n\t * services for container's to integrate with their host environment.\n\t */\n\treadonly scope?: FluidObject;\n\n\t/**\n\t * The logger that all telemetry should be pushed to.\n\t */\n\treadonly logger?: ITelemetryBaseLogger;\n\n\t/**\n\t * Blobs storage for detached containers.\n\t */\n\treadonly detachedBlobStorage?: IDetachedBlobStorage;\n\n\t/**\n\t * The configuration provider which may be used to control features.\n\t */\n\treadonly configProvider?: IConfigProviderBase;\n\n\t/**\n\t * Optional property for allowing the container to use a custom\n\t * protocol implementation for handling the quorum and/or the audience.\n\t */\n\treadonly protocolHandlerBuilder?: ProtocolHandlerBuilder;\n}\n\n/**\n * Services and properties used by and exposed by the loader\n * @legacy\n * @alpha\n */\nexport interface ILoaderServices {\n\t/**\n\t * The url resolver used by the loader for resolving external urls\n\t * into Fluid urls such that the container specified by the\n\t * external url can be loaded.\n\t */\n\treadonly urlResolver: IUrlResolver;\n\t/**\n\t * The document service factory take the Fluid url provided\n\t * by the resolved url and constructs all the necessary services\n\t * for communication with the container's server.\n\t */\n\treadonly documentServiceFactory: IDocumentServiceFactory;\n\t/**\n\t * The code loader handles loading the necessary code\n\t * for running a container once it is loaded.\n\t */\n\treadonly codeLoader: ICodeDetailsLoader;\n\n\t/**\n\t * A property bag of options used by various layers\n\t * to control features\n\t */\n\treadonly options: ILoaderOptions;\n\n\t/**\n\t * Scope is provided to all container and is a set of shared\n\t * services for container's to integrate with their host environment.\n\t */\n\treadonly scope: FluidObject;\n\n\t/**\n\t * The logger downstream consumers should construct their loggers from\n\t */\n\treadonly subLogger: ITelemetryLoggerExt;\n\n\t/**\n\t * Blobs storage for detached containers.\n\t * @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\n\t */\n\treadonly detachedBlobStorage?: IDetachedBlobStorage;\n\n\t/**\n\t * Optional property for allowing the container to use a custom\n\t * protocol implementation for handling the quorum and/or the audience.\n\t */\n\treadonly protocolHandlerBuilder?: ProtocolHandlerBuilder;\n}\n\n/**\n * Subset of IDocumentStorageService which only supports createBlob() and readBlob(). This is used to support\n * blobs in detached containers.\n * @legacy\n * @alpha\n *\n * @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\n */\nexport type IDetachedBlobStorage = Pick<IDocumentStorageService, \"createBlob\" | \"readBlob\"> & {\n\tsize: number;\n\t/**\n\t * Return an array of all blob IDs present in storage\n\t */\n\tgetBlobIds(): string[];\n\n\t/**\n\t * After the container is attached, the detached blob storage is no longer needed and will be disposed.\n\t */\n\tdispose?(): void;\n};\n\n/**\n * Manages Fluid resource loading\n * @legacy\n * @alpha\n */\nexport class Loader implements IHostLoader {\n\tpublic readonly services: ILoaderServices;\n\tprivate readonly mc: MonitoringContext;\n\n\tconstructor(loaderProps: ILoaderProps) {\n\t\tconst {\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory,\n\t\t\tcodeLoader,\n\t\t\toptions,\n\t\t\tscope,\n\t\t\tlogger,\n\t\t\tdetachedBlobStorage,\n\t\t\tconfigProvider,\n\t\t\tprotocolHandlerBuilder,\n\t\t} = loaderProps;\n\n\t\tconst telemetryProps = {\n\t\t\tloaderId: uuid(),\n\t\t\tloaderVersion: pkgVersion,\n\t\t};\n\n\t\tconst subMc = mixinMonitoringContext(\n\t\t\tDebugLogger.mixinDebugLogger(\"fluid:telemetry\", logger, {\n\t\t\t\tall: telemetryProps,\n\t\t\t}),\n\t\t\tsessionStorageConfigProvider.value,\n\t\t\tconfigProvider,\n\t\t);\n\n\t\tthis.services = {\n\t\t\turlResolver,\n\t\t\tdocumentServiceFactory,\n\t\t\tcodeLoader,\n\t\t\toptions: options ?? {},\n\t\t\tscope:\n\t\t\t\toptions?.provideScopeLoader === false ? { ...scope } : { ...scope, ILoader: this },\n\t\t\tdetachedBlobStorage,\n\t\t\tprotocolHandlerBuilder,\n\t\t\tsubLogger: subMc.logger,\n\t\t};\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: this.services.subLogger,\n\t\t\tnamespace: \"Loader\",\n\t\t});\n\t}\n\n\tpublic async createDetachedContainer(\n\t\tcodeDetails: IFluidCodeDetails,\n\t\tcreateDetachedProps?: {\n\t\t\tcanReconnect?: boolean;\n\t\t\tclientDetailsOverride?: IClientDetails;\n\t\t},\n\t): Promise<IContainer> {\n\t\treturn Container.createDetached(\n\t\t\t{\n\t\t\t\t...createDetachedProps,\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t\tcodeDetails,\n\t\t);\n\t}\n\n\tpublic async rehydrateDetachedContainerFromSnapshot(\n\t\tsnapshot: string,\n\t\tcreateDetachedProps?: {\n\t\t\tcanReconnect?: boolean;\n\t\t\tclientDetailsOverride?: IClientDetails;\n\t\t},\n\t): Promise<IContainer> {\n\t\treturn Container.rehydrateDetachedFromSnapshot(\n\t\t\t{\n\t\t\t\t...createDetachedProps,\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t\tsnapshot,\n\t\t);\n\t}\n\n\tpublic async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {\n\t\tconst eventName = pendingLocalState === undefined ? \"Resolve\" : \"ResolveWithPendingState\";\n\t\treturn PerformanceEvent.timedExecAsync(this.mc.logger, { eventName }, async () => {\n\t\t\treturn this.resolveCore(\n\t\t\t\trequest,\n\t\t\t\tgetAttachedContainerStateFromSerializedContainer(pendingLocalState),\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async resolveCore(\n\t\trequest: IRequest,\n\t\tpendingLocalState?: IPendingContainerState,\n\t): Promise<Container> {\n\t\tconst resolvedAsFluid = await this.services.urlResolver.resolve(request);\n\t\tensureResolvedUrlDefined(resolvedAsFluid);\n\n\t\t// Parse URL into data stores\n\t\tconst parsed = tryParseCompatibleResolvedUrl(resolvedAsFluid.url);\n\t\tif (parsed === undefined) {\n\t\t\tthrow new Error(`Invalid URL ${resolvedAsFluid.url}`);\n\t\t}\n\n\t\tif (pendingLocalState !== undefined) {\n\t\t\tconst parsedPendingUrl = tryParseCompatibleResolvedUrl(pendingLocalState.url);\n\t\t\tif (\n\t\t\t\tparsedPendingUrl?.id !== parsed.id ||\n\t\t\t\tparsedPendingUrl?.path.replace(/\\/$/, \"\") !== parsed.path.replace(/\\/$/, \"\")\n\t\t\t) {\n\t\t\t\tconst message = `URL ${resolvedAsFluid.url} does not match pending state URL ${pendingLocalState.url}`;\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\t\t}\n\n\t\trequest.headers ??= {};\n\t\t// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\trequest.headers[LoaderHeader.version] =\n\t\t\tparsed.version ?? request.headers[LoaderHeader.version];\n\n\t\treturn this.loadContainer(request, resolvedAsFluid, pendingLocalState);\n\t}\n\n\tprivate async loadContainer(\n\t\trequest: IRequest,\n\t\tresolvedUrl: IResolvedUrl,\n\t\tpendingLocalState?: IPendingContainerState,\n\t): Promise<Container> {\n\t\treturn Container.load(\n\t\t\t{\n\t\t\t\tresolvedUrl,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tversion: request.headers?.[LoaderHeader.version] ?? undefined,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tloadMode: request.headers?.[LoaderHeader.loadMode],\n\t\t\t\tpendingLocalState,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tcanReconnect: request.headers?.[LoaderHeader.reconnect],\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tclientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],\n\t\t\t\t...this.services,\n\t\t\t},\n\t\t);\n\t}\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/container-loader";
|
|
8
|
-
export declare const pkgVersion = "2.
|
|
8
|
+
export declare const pkgVersion = "2.22.1";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.22.1\";\n"]}
|
package/lib/protocol/quorum.js
CHANGED
|
@@ -36,7 +36,7 @@ export class QuorumClients extends TypedEventEmitter {
|
|
|
36
36
|
* @returns a snapshot of the clients in the quorum
|
|
37
37
|
*/
|
|
38
38
|
snapshot() {
|
|
39
|
-
this.snapshotCache
|
|
39
|
+
this.snapshotCache ??= [...this.members];
|
|
40
40
|
return this.snapshotCache;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
@@ -107,12 +107,12 @@ export class QuorumProposals extends TypedEventEmitter {
|
|
|
107
107
|
* @returns arrays of proposals and values
|
|
108
108
|
*/
|
|
109
109
|
snapshot() {
|
|
110
|
-
this.proposalsSnapshotCache
|
|
110
|
+
this.proposalsSnapshotCache ??= [...this.proposals].map(([sequenceNumber, proposal]) => [
|
|
111
111
|
sequenceNumber,
|
|
112
112
|
{ sequenceNumber, key: proposal.key, value: proposal.value },
|
|
113
113
|
[], // rejections, which has been removed
|
|
114
|
-
])
|
|
115
|
-
this.valuesSnapshotCache
|
|
114
|
+
]);
|
|
115
|
+
this.valuesSnapshotCache ??= [...this.values];
|
|
116
116
|
return {
|
|
117
117
|
proposals: this.proposalsSnapshotCache,
|
|
118
118
|
values: this.valuesSnapshotCache,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../../src/protocol/quorum.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IQuorumClients, ISequencedClient } from \"@fluidframework/driver-definitions\";\nimport {\n\tISequencedDocumentMessage,\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumProposals,\n\tISequencedProposal,\n} from \"@fluidframework/driver-definitions/internal\";\nimport events_pkg from \"events_pkg\";\nconst { EventEmitter } = events_pkg;\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: unknown,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @legacy\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @legacy\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @legacy\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= [...this.members];\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient): void {\n\t\tassert(!!clientId, 0x9a0 /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x9a1 /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string): void {\n\t\tassert(!!clientId, 0x9a2 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x9a3 /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: unknown) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= [...this.proposals].map(([sequenceNumber, proposal]) => [\n\t\t\tsequenceNumber,\n\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t[], // rejections, which has been removed\n\t\t]);\n\t\tthis.valuesSnapshotCache ??= [...this.values];\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): unknown {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: unknown): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t): void => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number): void => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = (): void => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(new Error(\"Client disconnected without successfully sending proposal\"));\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = (): void => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = (): void => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: unknown,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t): void {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x9a4 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean): void {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate readonly isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: unknown) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(\n\t\t\t\tsequenceNumber: number,\n\t\t\t\tkey: string,\n\t\t\t\tvalue: unknown,\n\t\t\t\tapprovalSequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close(): void {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): unknown {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient): void {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string): void {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: unknown): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: unknown,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t): void {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string): void {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"quorum.js","sourceRoot":"","sources":["../../src/protocol/quorum.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IQuorumClients, ISequencedClient } from \"@fluidframework/driver-definitions\";\nimport {\n\tISequencedDocumentMessage,\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumProposals,\n\tISequencedProposal,\n} from \"@fluidframework/driver-definitions/internal\";\nimport events_pkg from \"events_pkg\";\nconst { EventEmitter } = events_pkg;\n\n/**\n * Structure for tracking proposals that have been sequenced but not approved yet.\n */\nclass PendingProposal implements ISequencedProposal {\n\tconstructor(\n\t\tpublic readonly sequenceNumber: number,\n\t\tpublic readonly key: string,\n\t\tpublic readonly value: unknown,\n\t\tpublic readonly local: boolean,\n\t) {}\n}\n\n/**\n * Snapshot format for a QuorumClients\n * @legacy\n * @alpha\n */\nexport type QuorumClientsSnapshot = [string, ISequencedClient][];\n\n/**\n * Snapshot format for a QuorumProposals\n * @legacy\n * @alpha\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport type QuorumProposalsSnapshot = {\n\tproposals: [number, ISequencedProposal, string[]][];\n\tvalues: [string, ICommittedProposal][];\n};\n\n/**\n * Snapshot format for a Quorum\n * @legacy\n * @alpha\n */\nexport interface IQuorumSnapshot {\n\tmembers: QuorumClientsSnapshot;\n\tproposals: QuorumProposalsSnapshot[\"proposals\"];\n\tvalues: QuorumProposalsSnapshot[\"values\"];\n}\n\n/**\n * The QuorumClients is used to track members joining and leaving the collaboration session.\n * @internal\n */\nexport class QuorumClients\n\textends TypedEventEmitter<IQuorumClients[\"on\"]>\n\timplements IQuorumClients\n{\n\tprivate readonly members: Map<string, ISequencedClient>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate snapshotCache: QuorumClientsSnapshot | undefined;\n\n\tconstructor(snapshot: QuorumClientsSnapshot) {\n\t\tsuper();\n\n\t\tthis.members = new Map(snapshot);\n\t\tthis.snapshotCache = snapshot;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumClients\n\t * @returns a snapshot of the clients in the quorum\n\t */\n\tpublic snapshot(): QuorumClientsSnapshot {\n\t\tthis.snapshotCache ??= [...this.members];\n\n\t\treturn this.snapshotCache;\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient): void {\n\t\tassert(!!clientId, 0x9a0 /* clientId has to be non-empty string */);\n\t\tassert(!this.members.has(clientId), 0x9a1 /* clientId not found */);\n\t\tthis.members.set(clientId, details);\n\t\tthis.emit(\"addMember\", clientId, details);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string): void {\n\t\tassert(!!clientId, 0x9a2 /* clientId has to be non-empty string */);\n\t\tassert(this.members.has(clientId), 0x9a3 /* clientId not found */);\n\t\tthis.members.delete(clientId);\n\t\tthis.emit(\"removeMember\", clientId);\n\n\t\t// clear the cache\n\t\tthis.snapshotCache = undefined;\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\n/**\n * The QuorumProposals holds a key/value store. Proposed values become finalized in the store once all connected\n * clients have seen the proposal.\n * @internal\n */\nexport class QuorumProposals\n\textends TypedEventEmitter<IQuorumProposals[\"on\"]>\n\timplements IQuorumProposals\n{\n\tprivate readonly proposals: Map<number, PendingProposal>;\n\tprivate readonly values: Map<string, ICommittedProposal>;\n\tprivate isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\t// Event emitter for changes to the environment that affect pending proposal promises.\n\tprivate readonly stateEvents = new EventEmitter();\n\n\t/**\n\t * Cached snapshot state, to avoid unnecessary deep clones on repeated snapshot calls.\n\t * Cleared immediately (set to undefined) when the cache becomes invalid.\n\t */\n\tprivate proposalsSnapshotCache: QuorumProposalsSnapshot[\"proposals\"] | undefined;\n\tprivate valuesSnapshotCache: QuorumProposalsSnapshot[\"values\"] | undefined;\n\n\tconstructor(\n\t\tsnapshot: QuorumProposalsSnapshot,\n\t\tprivate readonly sendProposal: (key: string, value: unknown) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.proposals = new Map(\n\t\t\tsnapshot.proposals.map(([, proposal]) => {\n\t\t\t\treturn [\n\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\tnew PendingProposal(\n\t\t\t\t\t\tproposal.sequenceNumber,\n\t\t\t\t\t\tproposal.key,\n\t\t\t\t\t\tproposal.value,\n\t\t\t\t\t\tfalse, // local\n\t\t\t\t\t),\n\t\t\t\t] as [number, PendingProposal];\n\t\t\t}),\n\t\t);\n\t\tthis.values = new Map(snapshot.values);\n\t\tthis.proposalsSnapshotCache = snapshot.proposals;\n\t\tthis.valuesSnapshotCache = snapshot.values;\n\t}\n\n\t/**\n\t * Snapshots the current state of the QuorumProposals\n\t * @returns arrays of proposals and values\n\t */\n\tpublic snapshot(): QuorumProposalsSnapshot {\n\t\tthis.proposalsSnapshotCache ??= [...this.proposals].map(([sequenceNumber, proposal]) => [\n\t\t\tsequenceNumber,\n\t\t\t{ sequenceNumber, key: proposal.key, value: proposal.value },\n\t\t\t[], // rejections, which has been removed\n\t\t]);\n\t\tthis.valuesSnapshotCache ??= [...this.values];\n\n\t\treturn {\n\t\t\tproposals: this.proposalsSnapshotCache,\n\t\t\tvalues: this.valuesSnapshotCache,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.values.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): unknown {\n\t\treturn this.values.get(key)?.value;\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will either:\n\t * - Resolve when the proposal is accepted\n\t * - Reject if the proposal fails to send or if the QuorumProposals is disposed\n\t */\n\tpublic async propose(key: string, value: unknown): Promise<void> {\n\t\tconst clientSequenceNumber = this.sendProposal(key, value);\n\t\tif (clientSequenceNumber < 0) {\n\t\t\tthis.emit(\"error\", { eventName: \"ProposalInDisconnectedState\", key });\n\t\t\tthrow new Error(\"Can't propose in disconnected state\");\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t// The sequence number that our proposal was assigned and went pending.\n\t\t\t// If undefined, then it's not sequenced yet.\n\t\t\tlet thisProposalSequenceNumber: number | undefined;\n\n\t\t\t// A proposal goes through two phases before this promise resolves:\n\t\t\t// 1. Sequencing - waiting for the proposal to be ack'd by the server.\n\t\t\t// 2. Approval - waiting for the proposal to be approved by connected clients.\n\t\t\tconst localProposalSequencedHandler = (\n\t\t\t\tsequencedCSN: number,\n\t\t\t\tsequenceNumber: number,\n\t\t\t): void => {\n\t\t\t\tif (sequencedCSN === clientSequenceNumber) {\n\t\t\t\t\tthisProposalSequenceNumber = sequenceNumber;\n\t\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\t\tthis.stateEvents.on(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst localProposalApprovedHandler = (sequenceNumber: number): void => {\n\t\t\t\t// Proposals can be uniquely identified by the sequenceNumber they were assigned.\n\t\t\t\tif (sequenceNumber === thisProposalSequenceNumber) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tremoveListeners();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// There are two error flows we consider: disconnect and disposal.\n\t\t\t// If we get disconnected before the proposal is sequenced, it has one of two possible futures:\n\t\t\t// 1. We reconnect and see the proposal was sequenced in the meantime.\n\t\t\t// -> The promise can still resolve, once it is approved.\n\t\t\t// 2. We reconnect and see the proposal was not sequenced in the meantime, so it will never sequence.\n\t\t\t// -> The promise rejects.\n\t\t\tconst disconnectedHandler = (): void => {\n\t\t\t\t// If we haven't seen the ack by the time we disconnect, we hope to see it by the time we reconnect.\n\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\tthis.stateEvents.once(\"connected\", () => {\n\t\t\t\t\t\t// If we don't see the ack by the time reconnection finishes, it failed to send.\n\t\t\t\t\t\tif (thisProposalSequenceNumber === undefined) {\n\t\t\t\t\t\t\treject(new Error(\"Client disconnected without successfully sending proposal\"));\n\t\t\t\t\t\t\tremoveListeners();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\t// If the QuorumProposals is disposed of, we assume something catastrophic has happened\n\t\t\t// All outstanding proposals are considered rejected.\n\t\t\tconst disposedHandler = (): void => {\n\t\t\t\treject(new Error(\"QuorumProposals was disposed\"));\n\t\t\t\tremoveListeners();\n\t\t\t};\n\t\t\t// Convenience function to clean up our listeners.\n\t\t\tconst removeListeners = (): void => {\n\t\t\t\tthis.stateEvents.off(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\t\tthis.stateEvents.off(\"localProposalApproved\", localProposalApprovedHandler);\n\t\t\t\tthis.stateEvents.off(\"disconnected\", disconnectedHandler);\n\t\t\t\tthis.stateEvents.off(\"disposed\", disposedHandler);\n\t\t\t};\n\t\t\tthis.stateEvents.on(\"localProposalSequenced\", localProposalSequencedHandler);\n\t\t\tthis.stateEvents.on(\"disconnected\", disconnectedHandler);\n\t\t\tthis.stateEvents.on(\"disposed\", disposedHandler);\n\t\t});\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: unknown,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t): void {\n\t\tassert(!this.proposals.has(sequenceNumber), 0x9a4 /* sequenceNumber not found */);\n\n\t\tconst proposal = new PendingProposal(sequenceNumber, key, value, local);\n\t\tthis.proposals.set(sequenceNumber, proposal);\n\n\t\t// Legacy event, from rejection support. May still have some use for clients to learn that a proposal is\n\t\t// likely to be approved soon.\n\t\tthis.emit(\"addProposal\", proposal);\n\n\t\tif (local) {\n\t\t\tthis.stateEvents.emit(\"localProposalSequenced\", clientSequenceNumber, sequenceNumber);\n\t\t}\n\n\t\t// clear the proposal cache\n\t\tthis.proposalsSnapshotCache = undefined;\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tconst msn = message.minimumSequenceNumber;\n\n\t\t// Accept proposals proposals whose sequenceNumber is <= the minimumSequenceNumber\n\n\t\t// Return a sorted list of approved proposals. We sort so that we apply them in their sequence number order\n\t\t// TODO this can be optimized if necessary to avoid the linear search+sort\n\t\tconst completed: PendingProposal[] = [];\n\t\tfor (const [sequenceNumber, proposal] of this.proposals) {\n\t\t\tif (sequenceNumber <= msn) {\n\t\t\t\tcompleted.push(proposal);\n\t\t\t}\n\t\t}\n\t\tcompleted.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n\n\t\tfor (const proposal of completed) {\n\t\t\tconst committedProposal: ICommittedProposal = {\n\t\t\t\tapprovalSequenceNumber: message.sequenceNumber,\n\t\t\t\t// No longer used. We still stamp a -1 for compat with older versions of the quorum.\n\t\t\t\t// Can be removed after 0.1035 and higher is ubiquitous.\n\t\t\t\tcommitSequenceNumber: -1,\n\t\t\t\tkey: proposal.key,\n\t\t\t\tsequenceNumber: proposal.sequenceNumber,\n\t\t\t\tvalue: proposal.value,\n\t\t\t};\n\n\t\t\tthis.values.set(committedProposal.key, committedProposal);\n\n\t\t\t// clear the values cache\n\t\t\tthis.valuesSnapshotCache = undefined;\n\n\t\t\t// check if there are multiple proposals with matching keys\n\t\t\tlet proposalSettled = false;\n\t\t\tlet proposalKeySeen = false;\n\t\t\tfor (const [, p] of this.proposals) {\n\t\t\t\tif (p.key === committedProposal.key) {\n\t\t\t\t\tif (proposalKeySeen) {\n\t\t\t\t\t\t// set proposalSettled to false if matching proposal key is not unique\n\t\t\t\t\t\tproposalSettled = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// set proposalSettled to true if the proposal key match is unique thus far\n\t\t\t\t\t\tproposalSettled = true;\n\t\t\t\t\t}\n\t\t\t\t\tproposalKeySeen = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.emit(\n\t\t\t\t\"approveProposal\",\n\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\tcommittedProposal.key,\n\t\t\t\tcommittedProposal.value,\n\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t);\n\n\t\t\t// emit approveProposalComplete when all pending proposals are processed\n\t\t\tif (proposalSettled) {\n\t\t\t\tthis.emit(\n\t\t\t\t\t\"approveProposalComplete\",\n\t\t\t\t\tcommittedProposal.sequenceNumber,\n\t\t\t\t\tcommittedProposal.key,\n\t\t\t\t\tcommittedProposal.value,\n\t\t\t\t\tcommittedProposal.approvalSequenceNumber,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.proposals.delete(proposal.sequenceNumber);\n\n\t\t\t// clear the proposals cache\n\t\t\tthis.proposalsSnapshotCache = undefined;\n\t\t\tif (proposal.local) {\n\t\t\t\tthis.stateEvents.emit(\"localProposalApproved\", proposal.sequenceNumber);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic setConnectionState(connected: boolean): void {\n\t\tif (connected) {\n\t\t\tthis.stateEvents.emit(\"connected\");\n\t\t} else {\n\t\t\tthis.stateEvents.emit(\"disconnected\");\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.isDisposed = true;\n\t\tthis.stateEvents.emit(\"disposed\");\n\t}\n}\n\n/**\n * A quorum represents all clients currently within the collaboration window. As well as the values\n * they have agreed upon and any pending proposals.\n * @internal\n */\nexport class Quorum extends TypedEventEmitter<IQuorum[\"on\"]> implements IQuorum {\n\tprivate readonly quorumClients: QuorumClients;\n\tprivate readonly quorumProposals: QuorumProposals;\n\tprivate readonly isDisposed: boolean = false;\n\tpublic get disposed(): boolean {\n\t\treturn this.isDisposed;\n\t}\n\n\tconstructor(\n\t\tmembers: QuorumClientsSnapshot,\n\t\tproposals: QuorumProposalsSnapshot[\"proposals\"],\n\t\tvalues: QuorumProposalsSnapshot[\"values\"],\n\t\tsendProposal: (key: string, value: unknown) => number,\n\t) {\n\t\tsuper();\n\n\t\tthis.quorumClients = new QuorumClients(members);\n\t\tthis.quorumClients.on(\"addMember\", (clientId: string, details: ISequencedClient) => {\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t});\n\t\tthis.quorumClients.on(\"removeMember\", (clientId: string) => {\n\t\t\tthis.emit(\"removeMember\", clientId);\n\t\t});\n\n\t\tthis.quorumProposals = new QuorumProposals({ proposals, values }, sendProposal);\n\t\tthis.quorumProposals.on(\"addProposal\", (proposal: ISequencedProposal) => {\n\t\t\tthis.emit(\"addProposal\", proposal);\n\t\t});\n\t\tthis.quorumProposals.on(\n\t\t\t\"approveProposal\",\n\t\t\t(\n\t\t\t\tsequenceNumber: number,\n\t\t\t\tkey: string,\n\t\t\t\tvalue: unknown,\n\t\t\t\tapprovalSequenceNumber: number,\n\t\t\t) => {\n\t\t\t\tthis.emit(\"approveProposal\", sequenceNumber, key, value, approvalSequenceNumber);\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic close(): void {\n\t\tthis.removeAllListeners();\n\t}\n\n\t/**\n\t * Snapshots the entire quorum\n\t * @returns a quorum snapshot\n\t */\n\tpublic snapshot(): IQuorumSnapshot {\n\t\tconst members = this.quorumClients.snapshot();\n\t\tconst { proposals, values } = this.quorumProposals.snapshot();\n\t\treturn {\n\t\t\tmembers,\n\t\t\tproposals,\n\t\t\tvalues,\n\t\t};\n\t}\n\n\t/**\n\t * Returns whether the quorum has achieved a consensus for the given key.\n\t */\n\tpublic has(key: string): boolean {\n\t\treturn this.quorumProposals.has(key);\n\t}\n\n\t/**\n\t * Returns the consensus value for the given key\n\t */\n\tpublic get(key: string): unknown {\n\t\treturn this.quorumProposals.get(key);\n\t}\n\n\t/**\n\t * Adds a new client to the quorum\n\t */\n\tpublic addMember(clientId: string, details: ISequencedClient): void {\n\t\tthis.quorumClients.addMember(clientId, details);\n\t}\n\n\t/**\n\t * Removes a client from the quorum\n\t */\n\tpublic removeMember(clientId: string): void {\n\t\tthis.quorumClients.removeMember(clientId);\n\t}\n\n\t/**\n\t * Retrieves all the members in the quorum\n\t */\n\tpublic getMembers(): Map<string, ISequencedClient> {\n\t\treturn this.quorumClients.getMembers();\n\t}\n\n\t/**\n\t * Retrieves a specific member of the quorum\n\t */\n\tpublic getMember(clientId: string): ISequencedClient | undefined {\n\t\treturn this.quorumClients.getMember(clientId);\n\t}\n\n\t/**\n\t * Proposes a new value. Returns a promise that will resolve when the proposal is either accepted, or reject if\n\t * the proposal fails to send.\n\t */\n\tpublic async propose(key: string, value: unknown): Promise<void> {\n\t\treturn this.quorumProposals.propose(key, value);\n\t}\n\n\t/**\n\t * Begins tracking a new proposal\n\t */\n\tpublic addProposal(\n\t\tkey: string,\n\t\tvalue: unknown,\n\t\tsequenceNumber: number,\n\t\tlocal: boolean,\n\t\tclientSequenceNumber: number,\n\t): void {\n\t\treturn this.quorumProposals.addProposal(\n\t\t\tkey,\n\t\t\tvalue,\n\t\t\tsequenceNumber,\n\t\t\tlocal,\n\t\t\tclientSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number. If the MSN advances past the sequence number for any proposal then it\n\t * becomes an approved value.\n\t */\n\tpublic updateMinimumSequenceNumber(message: ISequencedDocumentMessage): void {\n\t\tthis.quorumProposals.updateMinimumSequenceNumber(message);\n\t}\n\n\tpublic setConnectionState(connected: boolean, clientId?: string): void {\n\t\tthis.quorumProposals.setConnectionState(connected);\n\t}\n\n\tpublic dispose(): void {\n\t\tthrow new Error(\"Not implemented.\");\n\t}\n}\n"]}
|
package/lib/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,YAAY,EAAe,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAEN,mBAAmB,EACnB,aAAa,EACb,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,uBAAuB,EACvB,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAGnC,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,aAAa,EACb,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,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;;;;;;GAMG;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;;;;;;;;;GASG;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;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,YAAY,EAAe,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAEN,mBAAmB,EACnB,aAAa,EACb,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,uBAAuB,EACvB,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAGnC,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,aAAa,EACb,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,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;;;;;;GAMG;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;;;;;;;;;GASG;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;AAqDD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,GAAG,aAAa,CAchF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,YAAY,EAAE,aAAa,EAC3B,sBAAsB,EAAE,MAAM,GAC5B,SAAS,CAaX;AAqBD,eAAO,MAAM,8CAA8C,8BAC/B,YAAY,KACrC,iBAYF,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,OAAO,GACZ,KAAK,IAAI,mCAAmC,CAO9C;AAoBD;;;;GAIG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAqBhC;AAED;;;GAGG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,sBAAsB,GAAG,SAAS,CAIpC;AAED;;;GAGG;AAEH,eAAO,MAAM,SAAS,6BACf,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,KAC9B,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAsB7B,CAAC;AAEF,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,IAAI,EAAE,aAAa,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
|
package/lib/utils.js
CHANGED
|
@@ -69,9 +69,7 @@ function convertSummaryToSnapshotAndBlobs(summary) {
|
|
|
69
69
|
unreferenced: summary.unreferenced,
|
|
70
70
|
groupId: summary.groupId,
|
|
71
71
|
};
|
|
72
|
-
const
|
|
73
|
-
for (const key of keys) {
|
|
74
|
-
const summaryObject = summary.tree[key];
|
|
72
|
+
for (const [key, summaryObject] of Object.entries(summary.tree)) {
|
|
75
73
|
switch (summaryObject.type) {
|
|
76
74
|
case SummaryType.Tree: {
|
|
77
75
|
const innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);
|
|
@@ -172,7 +170,7 @@ export const combineSnapshotTreeAndSnapshotBlobs = (baseSnapshot, snapshotBlobs)
|
|
|
172
170
|
const blobsContents = {};
|
|
173
171
|
// Process blobs in the current level
|
|
174
172
|
for (const [, id] of Object.entries(baseSnapshot.blobs)) {
|
|
175
|
-
if (snapshotBlobs[id]) {
|
|
173
|
+
if (snapshotBlobs[id] !== undefined) {
|
|
176
174
|
blobsContents[id] = stringToBuffer(snapshotBlobs[id], "utf8");
|
|
177
175
|
}
|
|
178
176
|
}
|
package/lib/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 {\n\tUint8ArrayToString,\n\tbufferToString,\n\tstringToBuffer,\n} from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { ISummaryTree, SummaryType } from \"@fluidframework/driver-definitions\";\nimport {\n\tDriverErrorTypes,\n\tIDocumentAttributes,\n\tISnapshotTree,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tIDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tLoggingError,\n\tUsageError,\n\ttype IFluidErrorBase,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingContainerState,\n\tIPendingDetachedContainerState,\n\tISnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.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 * @legacy\n * @alpha\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 * @legacy\n * @alpha\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\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): SnapshotWithBlobs {\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 innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);\n\t\t\t\ttreeNode.trees[key] = innerSnapshot.baseSnapshot;\n\t\t\t\tblobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };\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\t}\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}\n\t\t\tdefault: {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\tconst pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };\n\treturn pendingSnapshot;\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): ISnapshotInfo {\n\tassert(\n\t\tsnapshot.sequenceNumber !== undefined,\n\t\t0x93a /* Snapshot sequence number is missing */,\n\t);\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: ISnapshotInfo,\n\tsnapshotSequenceNumber: number,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBufferLike>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\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): SnapshotWithBlobs {\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): SnapshotWithBlobs => {\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: unknown,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t(error as Partial<IFluidErrorBase>)?.errorType ===\n\t\t\tDriverErrorTypes.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\n/**\n * Parses the given string into {@link IPendingDetachedContainerState} format,\n * with validation (if invalid, throws a UsageError).\n * This is the inverse of the JSON.stringify call in {@link Container.serialize}\n */\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst { baseSnapshot, snapshotBlobs } =\n\t\t\tgetSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\tbaseSnapshot,\n\t\t\tsnapshotBlobs,\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 * Blindly parses the given string into {@link IPendingContainerState} format.\n * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}\n */\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined {\n\treturn serializedContainer === undefined\n\t\t? undefined\n\t\t: (JSON.parse(serializedContainer) as IPendingContainerState);\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 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const runSingle = <A extends any[], R>(\n\tfunc: (...args: A) => Promise<R>,\n): ((...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): Promise<R> => {\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\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\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 {\n\tUint8ArrayToString,\n\tbufferToString,\n\tstringToBuffer,\n} from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { ISummaryTree, SummaryType } from \"@fluidframework/driver-definitions\";\nimport {\n\tDriverErrorTypes,\n\tIDocumentAttributes,\n\tISnapshotTree,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tIDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tLoggingError,\n\tUsageError,\n\ttype IFluidErrorBase,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingContainerState,\n\tIPendingDetachedContainerState,\n\tISnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.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 * @legacy\n * @alpha\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 * @legacy\n * @alpha\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\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): SnapshotWithBlobs {\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\tfor (const [key, summaryObject] of Object.entries(summary.tree)) {\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);\n\t\t\t\ttreeNode.trees[key] = innerSnapshot.baseSnapshot;\n\t\t\t\tblobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };\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\t}\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}\n\t\t\tdefault: {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\tconst pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };\n\treturn pendingSnapshot;\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): ISnapshotInfo {\n\tassert(\n\t\tsnapshot.sequenceNumber !== undefined,\n\t\t0x93a /* Snapshot sequence number is missing */,\n\t);\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: ISnapshotInfo,\n\tsnapshotSequenceNumber: number,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBufferLike>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\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): SnapshotWithBlobs {\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): SnapshotWithBlobs => {\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] !== undefined) {\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: unknown,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t(error as Partial<IFluidErrorBase>)?.errorType ===\n\t\t\tDriverErrorTypes.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\n/**\n * Parses the given string into {@link IPendingDetachedContainerState} format,\n * with validation (if invalid, throws a UsageError).\n * This is the inverse of the JSON.stringify call in {@link Container.serialize}\n */\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst { baseSnapshot, snapshotBlobs } =\n\t\t\tgetSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\tbaseSnapshot,\n\t\t\tsnapshotBlobs,\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 * Blindly parses the given string into {@link IPendingContainerState} format.\n * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}\n */\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined {\n\treturn serializedContainer === undefined\n\t\t? undefined\n\t\t: (JSON.parse(serializedContainer) as IPendingContainerState);\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 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const runSingle = <A extends any[], R>(\n\tfunc: (...args: A) => Promise<R>,\n): ((...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): Promise<R> => {\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\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-loader",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.1",
|
|
4
4
|
"description": "Fluid container loader",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -119,13 +119,13 @@
|
|
|
119
119
|
"temp-directory": "nyc/.nyc_output"
|
|
120
120
|
},
|
|
121
121
|
"dependencies": {
|
|
122
|
-
"@fluid-internal/client-utils": "~2.
|
|
123
|
-
"@fluidframework/container-definitions": "~2.
|
|
124
|
-
"@fluidframework/core-interfaces": "~2.
|
|
125
|
-
"@fluidframework/core-utils": "~2.
|
|
126
|
-
"@fluidframework/driver-definitions": "~2.
|
|
127
|
-
"@fluidframework/driver-utils": "~2.
|
|
128
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
122
|
+
"@fluid-internal/client-utils": "~2.22.1",
|
|
123
|
+
"@fluidframework/container-definitions": "~2.22.1",
|
|
124
|
+
"@fluidframework/core-interfaces": "~2.22.1",
|
|
125
|
+
"@fluidframework/core-utils": "~2.22.1",
|
|
126
|
+
"@fluidframework/driver-definitions": "~2.22.1",
|
|
127
|
+
"@fluidframework/driver-utils": "~2.22.1",
|
|
128
|
+
"@fluidframework/telemetry-utils": "~2.22.1",
|
|
129
129
|
"@types/events_pkg": "npm:@types/events@^3.0.0",
|
|
130
130
|
"@ungap/structured-clone": "^1.2.0",
|
|
131
131
|
"debug": "^4.3.4",
|
|
@@ -136,13 +136,13 @@
|
|
|
136
136
|
"devDependencies": {
|
|
137
137
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
138
138
|
"@biomejs/biome": "~1.9.3",
|
|
139
|
-
"@fluid-internal/client-utils": "~2.
|
|
140
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
141
|
-
"@fluid-private/test-loader-utils": "~2.
|
|
139
|
+
"@fluid-internal/client-utils": "~2.22.1",
|
|
140
|
+
"@fluid-internal/mocha-test-setup": "~2.22.1",
|
|
141
|
+
"@fluid-private/test-loader-utils": "~2.22.1",
|
|
142
142
|
"@fluid-tools/build-cli": "^0.51.0",
|
|
143
143
|
"@fluidframework/build-common": "^2.0.3",
|
|
144
144
|
"@fluidframework/build-tools": "^0.51.0",
|
|
145
|
-
"@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.
|
|
145
|
+
"@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.22.0",
|
|
146
146
|
"@fluidframework/eslint-config-fluid": "^5.7.3",
|
|
147
147
|
"@microsoft/api-extractor": "7.47.8",
|
|
148
148
|
"@types/debug": "^4.1.5",
|
|
@@ -211,8 +211,8 @@
|
|
|
211
211
|
"test": "npm run test:mocha",
|
|
212
212
|
"test:coverage": "c8 npm test",
|
|
213
213
|
"test:mocha": "npm run test:mocha:esm && echo skipping cjs to avoid overhead - npm run test:mocha:cjs",
|
|
214
|
-
"test:mocha:cjs": "mocha --recursive \"dist/test/**/*.spec.*js\"
|
|
215
|
-
"test:mocha:esm": "mocha --recursive \"lib/test/**/*.spec.*js\"
|
|
214
|
+
"test:mocha:cjs": "mocha --recursive \"dist/test/**/*.spec.*js\"",
|
|
215
|
+
"test:mocha:esm": "mocha --recursive \"lib/test/**/*.spec.*js\"",
|
|
216
216
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
217
217
|
"tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
|
|
218
218
|
"tsc:watch": "npm run place:cjs:package-stub && fluid-tsc commonjs --project ./tsconfig.cjs.json --watch",
|
package/src/container.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
IContainer,
|
|
23
23
|
IContainerEvents,
|
|
24
24
|
IContainerLoadMode,
|
|
25
|
+
IDeltaManager,
|
|
25
26
|
IFluidCodeDetails,
|
|
26
27
|
IFluidCodeDetailsComparer,
|
|
27
28
|
IFluidModuleWithDetails,
|
|
@@ -30,9 +31,9 @@ import {
|
|
|
30
31
|
IProvideRuntimeFactory,
|
|
31
32
|
IRuntime,
|
|
32
33
|
isFluidCodeDetails,
|
|
33
|
-
IDeltaManager,
|
|
34
34
|
ReadOnlyInfo,
|
|
35
35
|
type ILoader,
|
|
36
|
+
type ILoaderOptions,
|
|
36
37
|
} from "@fluidframework/container-definitions/internal";
|
|
37
38
|
import {
|
|
38
39
|
FluidObject,
|
|
@@ -129,7 +130,8 @@ import {
|
|
|
129
130
|
import { DeltaManager, IConnectionArgs } from "./deltaManager.js";
|
|
130
131
|
import { validateRuntimeCompatibility } from "./layerCompatState.js";
|
|
131
132
|
// eslint-disable-next-line import/no-deprecated
|
|
132
|
-
import { IDetachedBlobStorage
|
|
133
|
+
import { IDetachedBlobStorage } from "./loader.js";
|
|
134
|
+
import { RelativeLoader } from "./loader.js";
|
|
133
135
|
import {
|
|
134
136
|
serializeMemoryDetachedBlobStorage,
|
|
135
137
|
createMemoryDetachedBlobStorage,
|
|
@@ -226,7 +228,6 @@ export interface IContainerCreateProps {
|
|
|
226
228
|
* A property bag of options used by various layers
|
|
227
229
|
* to control features
|
|
228
230
|
*/
|
|
229
|
-
// eslint-disable-next-line import/no-deprecated
|
|
230
231
|
readonly options: ILoaderOptions;
|
|
231
232
|
|
|
232
233
|
/**
|
|
@@ -488,7 +489,6 @@ export class Container
|
|
|
488
489
|
private readonly urlResolver: IUrlResolver;
|
|
489
490
|
private readonly serviceFactory: IDocumentServiceFactory;
|
|
490
491
|
private readonly codeLoader: ICodeDetailsLoader;
|
|
491
|
-
// eslint-disable-next-line import/no-deprecated
|
|
492
492
|
private readonly options: ILoaderOptions;
|
|
493
493
|
private readonly scope: FluidObject;
|
|
494
494
|
private readonly subLogger: ITelemetryLoggerExt;
|
|
@@ -994,10 +994,11 @@ export class Container
|
|
|
994
994
|
? summaryTree
|
|
995
995
|
: combineAppAndProtocolSummary(summaryTree, this.captureProtocolSummary());
|
|
996
996
|
|
|
997
|
-
//
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
997
|
+
// Feature gate to enable single-commit summaries. The expected enablement is through driver layer's policies,
|
|
998
|
+
// but here we also specify config setting to use for testing purposes.
|
|
999
|
+
const enableSummarizeProtocolTree = this.mc.config.getBoolean(
|
|
1000
|
+
"Fluid.Container.summarizeProtocolTree2",
|
|
1001
|
+
);
|
|
1001
1002
|
|
|
1002
1003
|
this.detachedBlobStorage =
|
|
1003
1004
|
detachedBlobStorage ??
|
package/src/packageVersion.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -145,10 +145,7 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): SnapshotWithBl
|
|
|
145
145
|
unreferenced: summary.unreferenced,
|
|
146
146
|
groupId: summary.groupId,
|
|
147
147
|
};
|
|
148
|
-
const
|
|
149
|
-
for (const key of keys) {
|
|
150
|
-
const summaryObject = summary.tree[key];
|
|
151
|
-
|
|
148
|
+
for (const [key, summaryObject] of Object.entries(summary.tree)) {
|
|
152
149
|
switch (summaryObject.type) {
|
|
153
150
|
case SummaryType.Tree: {
|
|
154
151
|
const innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);
|
|
@@ -280,7 +277,7 @@ export const combineSnapshotTreeAndSnapshotBlobs = (
|
|
|
280
277
|
|
|
281
278
|
// Process blobs in the current level
|
|
282
279
|
for (const [, id] of Object.entries(baseSnapshot.blobs)) {
|
|
283
|
-
if (snapshotBlobs[id]) {
|
|
280
|
+
if (snapshotBlobs[id] !== undefined) {
|
|
284
281
|
blobsContents[id] = stringToBuffer(snapshotBlobs[id], "utf8");
|
|
285
282
|
}
|
|
286
283
|
}
|