@fluidframework/container-loader 2.93.0 → 2.101.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/api-report/container-loader.legacy.alpha.api.md +13 -1
  3. package/dist/captureReferencedContents.d.ts +154 -0
  4. package/dist/captureReferencedContents.d.ts.map +1 -0
  5. package/dist/captureReferencedContents.js +349 -0
  6. package/dist/captureReferencedContents.js.map +1 -0
  7. package/dist/connectionManager.d.ts +2 -1
  8. package/dist/connectionManager.d.ts.map +1 -1
  9. package/dist/connectionManager.js +39 -8
  10. package/dist/connectionManager.js.map +1 -1
  11. package/dist/connectionStateHandler.d.ts.map +1 -1
  12. package/dist/connectionStateHandler.js +3 -1
  13. package/dist/connectionStateHandler.js.map +1 -1
  14. package/dist/container.d.ts.map +1 -1
  15. package/dist/container.js +13 -4
  16. package/dist/container.js.map +1 -1
  17. package/dist/containerStorageAdapter.d.ts +20 -2
  18. package/dist/containerStorageAdapter.d.ts.map +1 -1
  19. package/dist/containerStorageAdapter.js +2 -2
  20. package/dist/containerStorageAdapter.js.map +1 -1
  21. package/dist/createAndLoadContainerUtils.d.ts +95 -0
  22. package/dist/createAndLoadContainerUtils.d.ts.map +1 -1
  23. package/dist/createAndLoadContainerUtils.js +137 -11
  24. package/dist/createAndLoadContainerUtils.js.map +1 -1
  25. package/dist/frozenServices.d.ts +113 -30
  26. package/dist/frozenServices.d.ts.map +1 -1
  27. package/dist/frozenServices.js +236 -58
  28. package/dist/frozenServices.js.map +1 -1
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +5 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/legacyAlpha.d.ts +2 -0
  34. package/dist/loader.d.ts +1 -1
  35. package/dist/loader.d.ts.map +1 -1
  36. package/dist/loader.js +1 -1
  37. package/dist/loader.js.map +1 -1
  38. package/dist/loaderLayerCompatState.d.ts +1 -1
  39. package/dist/packageVersion.d.ts +1 -1
  40. package/dist/packageVersion.d.ts.map +1 -1
  41. package/dist/packageVersion.js +1 -1
  42. package/dist/packageVersion.js.map +1 -1
  43. package/dist/pendingLocalStateStore.d.ts.map +1 -1
  44. package/dist/pendingLocalStateStore.js +9 -3
  45. package/dist/pendingLocalStateStore.js.map +1 -1
  46. package/dist/retriableDocumentStorageService.d.ts +2 -1
  47. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  48. package/dist/retriableDocumentStorageService.js +3 -2
  49. package/dist/retriableDocumentStorageService.js.map +1 -1
  50. package/dist/serializedStateManager.d.ts +16 -1
  51. package/dist/serializedStateManager.d.ts.map +1 -1
  52. package/dist/serializedStateManager.js +11 -1
  53. package/dist/serializedStateManager.js.map +1 -1
  54. package/lib/captureReferencedContents.d.ts +154 -0
  55. package/lib/captureReferencedContents.d.ts.map +1 -0
  56. package/lib/captureReferencedContents.js +338 -0
  57. package/lib/captureReferencedContents.js.map +1 -0
  58. package/lib/connectionManager.d.ts +2 -1
  59. package/lib/connectionManager.d.ts.map +1 -1
  60. package/lib/connectionManager.js +40 -9
  61. package/lib/connectionManager.js.map +1 -1
  62. package/lib/connectionStateHandler.d.ts.map +1 -1
  63. package/lib/connectionStateHandler.js +3 -1
  64. package/lib/connectionStateHandler.js.map +1 -1
  65. package/lib/container.d.ts.map +1 -1
  66. package/lib/container.js +14 -5
  67. package/lib/container.js.map +1 -1
  68. package/lib/containerStorageAdapter.d.ts +20 -2
  69. package/lib/containerStorageAdapter.d.ts.map +1 -1
  70. package/lib/containerStorageAdapter.js +2 -2
  71. package/lib/containerStorageAdapter.js.map +1 -1
  72. package/lib/createAndLoadContainerUtils.d.ts +95 -0
  73. package/lib/createAndLoadContainerUtils.d.ts.map +1 -1
  74. package/lib/createAndLoadContainerUtils.js +128 -3
  75. package/lib/createAndLoadContainerUtils.js.map +1 -1
  76. package/lib/frozenServices.d.ts +113 -30
  77. package/lib/frozenServices.d.ts.map +1 -1
  78. package/lib/frozenServices.js +233 -57
  79. package/lib/frozenServices.js.map +1 -1
  80. package/lib/index.d.ts +2 -1
  81. package/lib/index.d.ts.map +1 -1
  82. package/lib/index.js +2 -1
  83. package/lib/index.js.map +1 -1
  84. package/lib/legacyAlpha.d.ts +2 -0
  85. package/lib/loader.d.ts +1 -1
  86. package/lib/loader.d.ts.map +1 -1
  87. package/lib/loader.js +2 -2
  88. package/lib/loader.js.map +1 -1
  89. package/lib/loaderLayerCompatState.d.ts +1 -1
  90. package/lib/packageVersion.d.ts +1 -1
  91. package/lib/packageVersion.d.ts.map +1 -1
  92. package/lib/packageVersion.js +1 -1
  93. package/lib/packageVersion.js.map +1 -1
  94. package/lib/pendingLocalStateStore.d.ts.map +1 -1
  95. package/lib/pendingLocalStateStore.js +9 -3
  96. package/lib/pendingLocalStateStore.js.map +1 -1
  97. package/lib/retriableDocumentStorageService.d.ts +2 -1
  98. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  99. package/lib/retriableDocumentStorageService.js +3 -2
  100. package/lib/retriableDocumentStorageService.js.map +1 -1
  101. package/lib/serializedStateManager.d.ts +16 -1
  102. package/lib/serializedStateManager.d.ts.map +1 -1
  103. package/lib/serializedStateManager.js +11 -1
  104. package/lib/serializedStateManager.js.map +1 -1
  105. package/package.json +13 -13
  106. package/src/captureReferencedContents.ts +446 -0
  107. package/src/connectionManager.ts +47 -8
  108. package/src/connectionStateHandler.ts +14 -9
  109. package/src/container.ts +18 -4
  110. package/src/containerStorageAdapter.ts +22 -2
  111. package/src/createAndLoadContainerUtils.ts +229 -2
  112. package/src/frozenServices.ts +285 -64
  113. package/src/index.ts +7 -0
  114. package/src/loader.ts +4 -2
  115. package/src/packageVersion.ts +1 -1
  116. package/src/pendingLocalStateStore.ts +8 -1
  117. package/src/retriableDocumentStorageService.ts +11 -4
  118. package/src/serializedStateManager.ts +28 -1
@@ -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\ttype IContainer,\n\ttype IFluidCodeDetails,\n\ttype IFluidModule,\n\ttype IHostLoader,\n\ttype ILoader,\n\ttype ILoaderOptions,\n\ttype IProvideFluidCodeDetailsComparer,\n\tLoaderHeader,\n} from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tFluidObject,\n\tIConfigProviderBase,\n\tIRequest,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { IClientDetails } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentServiceFactory,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\ttype MonitoringContext,\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 type { 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 * @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 @beta\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 @beta\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 @beta\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 * 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 @beta\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 * 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 * Manages Fluid resource loading\n * @legacy @beta\n *\n * @remarks The Loader class is deprecated and will be removed in a future release. Use the free-form functions instead (See issue #24450 for more details).\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\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\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\ttype IContainer,\n\ttype IFluidCodeDetails,\n\ttype IFluidModule,\n\ttype IHostLoader,\n\ttype ILoader,\n\ttype ILoaderOptions,\n\ttype IProvideFluidCodeDetailsComparer,\n\tLoaderHeader,\n} from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tFluidObject,\n\tIConfigProviderBase,\n\tIRequest,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { IClientDetails } from \"@fluidframework/driver-definitions\";\nimport type {\n\tIDocumentServiceFactory,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype MonitoringContext,\n\tPerformanceEvent,\n\tcreateChildMonitoringContext,\n\tmixinMonitoringContext,\n\tsessionStorageConfigProvider,\n\ttoITelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n// eslint-disable-next-line import-x/no-internal-modules -- Needed to avoid specialized /internal ITelemetryLoggerExt\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/legacy\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { Container } from \"./container.js\";\nimport { DebugLogger } from \"./debugLogger.js\";\nimport { pkgVersion } from \"./packageVersion.js\";\nimport type { 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 * @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 @beta\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 @beta\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 @beta\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 * 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 @beta\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 * 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 * Manages Fluid resource loading\n * @legacy @beta\n *\n * @remarks The Loader class is deprecated and will be removed in a future release. Use the free-form functions instead (See issue #24450 for more details).\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\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\tprotocolHandlerBuilder,\n\t\t\tsubLogger: toITelemetryLoggerExt(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"]}
@@ -13,7 +13,7 @@ export declare const loaderCoreCompatDetails: {
13
13
  /**
14
14
  * The package version of the Loader layer.
15
15
  */
16
- readonly pkgVersion: "2.93.0";
16
+ readonly pkgVersion: "2.101.0";
17
17
  /**
18
18
  * The current generation of the Loader layer.
19
19
  */
@@ -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.93.0";
8
+ export declare const pkgVersion = "2.101.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,WAAW,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,YAAY,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/container-loader";
11
- exports.pkgVersion = "2.93.0";
11
+ exports.pkgVersion = "2.101.0";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,kCAAkC,CAAC;AAC7C,QAAA,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.93.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,kCAAkC,CAAC;AAC7C,QAAA,UAAU,GAAG,SAAS,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.101.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pendingLocalStateStore.d.ts","sourceRoot":"","sources":["../src/pendingLocalStateStore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,sBAAsB,CAAC,IAAI;;IAOvC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO;IAIvB;;;;;;;;OAQG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI;IAiC/C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAcnC;;OAEG;IACH,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC;IAI9B;;OAEG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;CAG7C"}
1
+ {"version":3,"file":"pendingLocalStateStore.d.ts","sourceRoot":"","sources":["../src/pendingLocalStateStore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,sBAAsB,CAAC,IAAI;;IAQvC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO;IAIvB;;;;;;;;OAQG;IACH,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI;IAuC/C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAcnC;;OAEG;IACH,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC;IAI9B;;OAEG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;CAG7C"}
@@ -14,7 +14,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
14
14
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
15
15
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
16
16
  };
17
- var _PendingLocalStateStore_firstUrl, _PendingLocalStateStore_pendingStates, _PendingLocalStateStore_savedOps, _PendingLocalStateStore_blobs, _PendingLocalStateStore_loadingGroups;
17
+ var _PendingLocalStateStore_firstUrl, _PendingLocalStateStore_pendingStates, _PendingLocalStateStore_savedOps, _PendingLocalStateStore_blobs, _PendingLocalStateStore_attachmentBlobs, _PendingLocalStateStore_loadingGroups;
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.PendingLocalStateStore = void 0;
20
20
  const internal_1 = require("@fluidframework/telemetry-utils/internal");
@@ -53,6 +53,7 @@ class PendingLocalStateStore {
53
53
  _PendingLocalStateStore_pendingStates.set(this, new Map());
54
54
  _PendingLocalStateStore_savedOps.set(this, {});
55
55
  _PendingLocalStateStore_blobs.set(this, {});
56
+ _PendingLocalStateStore_attachmentBlobs.set(this, {});
56
57
  _PendingLocalStateStore_loadingGroups.set(this, {});
57
58
  }
58
59
  /**
@@ -96,7 +97,7 @@ class PendingLocalStateStore {
96
97
  */
97
98
  set(key, pendingLocalState) {
98
99
  const state = (0, utils_js_1.getAttachedContainerStateFromSerializedContainer)(pendingLocalState);
99
- const { savedOps, snapshotBlobs, loadedGroupIdSnapshots, url } = state;
100
+ const { savedOps, snapshotBlobs, attachmentBlobContents, loadedGroupIdSnapshots, url } = state;
100
101
  // Normalize URL by removing trailing slash for comparison
101
102
  const normalizedUrl = url.replace(/\/$/, "");
102
103
  const normalizedFirstUrl = __classPrivateFieldGet(this, _PendingLocalStateStore_firstUrl, "f")?.replace(/\/$/, "");
@@ -110,6 +111,11 @@ class PendingLocalStateStore {
110
111
  for (const [id, blob] of Object.entries(snapshotBlobs)) {
111
112
  snapshotBlobs[id] = __classPrivateFieldGet(this, _PendingLocalStateStore_blobs, "f")[id] ??= blob;
112
113
  }
114
+ if (attachmentBlobContents !== undefined) {
115
+ for (const [id, blob] of Object.entries(attachmentBlobContents)) {
116
+ attachmentBlobContents[id] = __classPrivateFieldGet(this, _PendingLocalStateStore_attachmentBlobs, "f")[id] ??= blob;
117
+ }
118
+ }
113
119
  if (loadedGroupIdSnapshots !== undefined) {
114
120
  for (const [id, lg] of Object.entries(loadedGroupIdSnapshots)) {
115
121
  if (__classPrivateFieldGet(this, _PendingLocalStateStore_loadingGroups, "f")[id] === undefined ||
@@ -152,7 +158,7 @@ class PendingLocalStateStore {
152
158
  /**
153
159
  * Makes the store iterable with `for...of` loops.
154
160
  */
155
- [(_PendingLocalStateStore_firstUrl = new WeakMap(), _PendingLocalStateStore_pendingStates = new WeakMap(), _PendingLocalStateStore_savedOps = new WeakMap(), _PendingLocalStateStore_blobs = new WeakMap(), _PendingLocalStateStore_loadingGroups = new WeakMap(), Symbol.iterator)]() {
161
+ [(_PendingLocalStateStore_firstUrl = new WeakMap(), _PendingLocalStateStore_pendingStates = new WeakMap(), _PendingLocalStateStore_savedOps = new WeakMap(), _PendingLocalStateStore_blobs = new WeakMap(), _PendingLocalStateStore_attachmentBlobs = new WeakMap(), _PendingLocalStateStore_loadingGroups = new WeakMap(), Symbol.iterator)]() {
156
162
  return this.entries();
157
163
  }
158
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pendingLocalStateStore.js","sourceRoot":"","sources":["../src/pendingLocalStateStore.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 type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type {\n\tIPendingContainerState,\n\tSerializedSnapshotInfo,\n} from \"./serializedStateManager.js\";\nimport { getAttachedContainerStateFromSerializedContainer } from \"./utils.js\";\n\n/**\n * A Map-like store for managing pending local container states from attached containers.\n * Optimizes storage by deduplicating shared resources across stored states.\n *\n * @example\n * ```typescript\n * const store = new PendingLocalStateStore<string>();\n *\n * // Store pending state\n * const pendingState = await attachedContainer.getPendingLocalState();\n * store.set(\"session1\", pendingState);\n *\n * // Load from stored state\n * const restored = store.get(\"session1\");\n * const newContainer = await loadFrozenContainerFromPendingState({\n * pendingLocalState: restored,\n * // ... other loader options\n * });\n * ```\n *\n * @remarks\n * Only use with attached containers from the same URL. Only store strings\n * returned by `container.getPendingLocalState()`.\n *\n * @typeParam TKey - The type of keys used to identify stored states\n *\n * @legacy @alpha\n */\nexport class PendingLocalStateStore<TKey> {\n\t#firstUrl: string | undefined;\n\treadonly #pendingStates = new Map<TKey, IPendingContainerState>();\n\treadonly #savedOps: Record<number, ISequencedDocumentMessage> = {};\n\treadonly #blobs: Record<string, string> = {};\n\treadonly #loadingGroups: Record<string, SerializedSnapshotInfo> = {};\n\n\t/**\n\t * Removes all stored pending states.\n\t */\n\tclear(): void {\n\t\treturn this.#pendingStates.clear();\n\t}\n\n\t/**\n\t * Removes the pending state for the specified key.\n\t *\n\t * @param key - The key to remove\n\t * @returns `true` if the state existed and was removed, `false` otherwise\n\t */\n\tdelete(key: TKey): boolean {\n\t\treturn this.#pendingStates.delete(key);\n\t}\n\n\t/**\n\t * Retrieves the serialized pending state for the specified key.\n\t *\n\t * @param key - The key to retrieve\n\t * @returns The serialized state as a JSON string, or `undefined` if not found\n\t */\n\tget(key: TKey): string | undefined {\n\t\treturn JSON.stringify(this.#pendingStates.get(key));\n\t}\n\n\t/**\n\t * Checks whether a pending state exists for the specified key.\n\t */\n\thas(key: TKey): boolean {\n\t\treturn this.#pendingStates.has(key);\n\t}\n\n\t/**\n\t * Stores a pending state from `container.getPendingLocalState()`.\n\t *\n\t * @param key - The key to associate with the state\n\t * @param pendingLocalState - String returned by `getPendingLocalState()` from an attached container\n\t * @returns This store instance for method chaining\n\t *\n\t * @throws When storing states from different container URLs\n\t */\n\tset(key: TKey, pendingLocalState: string): this {\n\t\tconst state = getAttachedContainerStateFromSerializedContainer(pendingLocalState);\n\t\tconst { savedOps, snapshotBlobs, loadedGroupIdSnapshots, url } = state;\n\n\t\t// Normalize URL by removing trailing slash for comparison\n\t\tconst normalizedUrl = url.replace(/\\/$/, \"\");\n\t\tconst normalizedFirstUrl = this.#firstUrl?.replace(/\\/$/, \"\");\n\t\tthis.#firstUrl ??= url;\n\t\tif (normalizedFirstUrl !== undefined && normalizedFirstUrl !== normalizedUrl) {\n\t\t\tthrow new UsageError(\"PendingLocalStateStore can only be used with a single container.\");\n\t\t}\n\n\t\tfor (let i = 0; i < savedOps.length; i++) {\n\t\t\tsavedOps[i] = this.#savedOps[savedOps[i].sequenceNumber] ??= savedOps[i];\n\t\t}\n\t\tfor (const [id, blob] of Object.entries(snapshotBlobs)) {\n\t\t\tsnapshotBlobs[id] = this.#blobs[id] ??= blob;\n\t\t}\n\t\tif (loadedGroupIdSnapshots !== undefined) {\n\t\t\tfor (const [id, lg] of Object.entries(loadedGroupIdSnapshots)) {\n\t\t\t\tif (\n\t\t\t\t\tthis.#loadingGroups[id] === undefined ||\n\t\t\t\t\tlg.snapshotSequenceNumber < this.#loadingGroups[id].snapshotSequenceNumber\n\t\t\t\t) {\n\t\t\t\t\tloadedGroupIdSnapshots[id] = this.#loadingGroups[id] = lg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.#pendingStates.set(key, state);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of stored pending states.\n\t */\n\tget size(): number {\n\t\treturn this.#pendingStates.size;\n\t}\n\n\t/**\n\t * Returns an iterator over [key, serializedState] pairs.\n\t */\n\tentries(): Iterator<[TKey, string]> {\n\t\tconst iterator = this.#pendingStates.entries();\n\t\treturn {\n\t\t\tnext: (): IteratorResult<[TKey, string]> => {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tconst { done, value } = iterator.next();\n\t\t\t\tif (done === true) {\n\t\t\t\t\treturn { done, value: undefined };\n\t\t\t\t}\n\t\t\t\treturn { done, value: [value[0], JSON.stringify(value[1])] };\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Returns an iterator over the stored keys.\n\t */\n\tkeys(): IterableIterator<TKey> {\n\t\treturn this.#pendingStates.keys();\n\t}\n\n\t/**\n\t * Makes the store iterable with `for...of` loops.\n\t */\n\t[Symbol.iterator](): Iterator<[TKey, string]> {\n\t\treturn this.entries();\n\t}\n}\n"]}
1
+ {"version":3,"file":"pendingLocalStateStore.js","sourceRoot":"","sources":["../src/pendingLocalStateStore.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 type { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type {\n\tIPendingContainerState,\n\tSerializedSnapshotInfo,\n} from \"./serializedStateManager.js\";\nimport { getAttachedContainerStateFromSerializedContainer } from \"./utils.js\";\n\n/**\n * A Map-like store for managing pending local container states from attached containers.\n * Optimizes storage by deduplicating shared resources across stored states.\n *\n * @example\n * ```typescript\n * const store = new PendingLocalStateStore<string>();\n *\n * // Store pending state\n * const pendingState = await attachedContainer.getPendingLocalState();\n * store.set(\"session1\", pendingState);\n *\n * // Load from stored state\n * const restored = store.get(\"session1\");\n * const newContainer = await loadFrozenContainerFromPendingState({\n * pendingLocalState: restored,\n * // ... other loader options\n * });\n * ```\n *\n * @remarks\n * Only use with attached containers from the same URL. Only store strings\n * returned by `container.getPendingLocalState()`.\n *\n * @typeParam TKey - The type of keys used to identify stored states\n *\n * @legacy @alpha\n */\nexport class PendingLocalStateStore<TKey> {\n\t#firstUrl: string | undefined;\n\treadonly #pendingStates = new Map<TKey, IPendingContainerState>();\n\treadonly #savedOps: Record<number, ISequencedDocumentMessage> = {};\n\treadonly #blobs: Record<string, string> = {};\n\treadonly #attachmentBlobs: Record<string, string> = {};\n\treadonly #loadingGroups: Record<string, SerializedSnapshotInfo> = {};\n\n\t/**\n\t * Removes all stored pending states.\n\t */\n\tclear(): void {\n\t\treturn this.#pendingStates.clear();\n\t}\n\n\t/**\n\t * Removes the pending state for the specified key.\n\t *\n\t * @param key - The key to remove\n\t * @returns `true` if the state existed and was removed, `false` otherwise\n\t */\n\tdelete(key: TKey): boolean {\n\t\treturn this.#pendingStates.delete(key);\n\t}\n\n\t/**\n\t * Retrieves the serialized pending state for the specified key.\n\t *\n\t * @param key - The key to retrieve\n\t * @returns The serialized state as a JSON string, or `undefined` if not found\n\t */\n\tget(key: TKey): string | undefined {\n\t\treturn JSON.stringify(this.#pendingStates.get(key));\n\t}\n\n\t/**\n\t * Checks whether a pending state exists for the specified key.\n\t */\n\thas(key: TKey): boolean {\n\t\treturn this.#pendingStates.has(key);\n\t}\n\n\t/**\n\t * Stores a pending state from `container.getPendingLocalState()`.\n\t *\n\t * @param key - The key to associate with the state\n\t * @param pendingLocalState - String returned by `getPendingLocalState()` from an attached container\n\t * @returns This store instance for method chaining\n\t *\n\t * @throws When storing states from different container URLs\n\t */\n\tset(key: TKey, pendingLocalState: string): this {\n\t\tconst state = getAttachedContainerStateFromSerializedContainer(pendingLocalState);\n\t\tconst { savedOps, snapshotBlobs, attachmentBlobContents, loadedGroupIdSnapshots, url } =\n\t\t\tstate;\n\n\t\t// Normalize URL by removing trailing slash for comparison\n\t\tconst normalizedUrl = url.replace(/\\/$/, \"\");\n\t\tconst normalizedFirstUrl = this.#firstUrl?.replace(/\\/$/, \"\");\n\t\tthis.#firstUrl ??= url;\n\t\tif (normalizedFirstUrl !== undefined && normalizedFirstUrl !== normalizedUrl) {\n\t\t\tthrow new UsageError(\"PendingLocalStateStore can only be used with a single container.\");\n\t\t}\n\n\t\tfor (let i = 0; i < savedOps.length; i++) {\n\t\t\tsavedOps[i] = this.#savedOps[savedOps[i].sequenceNumber] ??= savedOps[i];\n\t\t}\n\t\tfor (const [id, blob] of Object.entries(snapshotBlobs)) {\n\t\t\tsnapshotBlobs[id] = this.#blobs[id] ??= blob;\n\t\t}\n\t\tif (attachmentBlobContents !== undefined) {\n\t\t\tfor (const [id, blob] of Object.entries(attachmentBlobContents)) {\n\t\t\t\tattachmentBlobContents[id] = this.#attachmentBlobs[id] ??= blob;\n\t\t\t}\n\t\t}\n\t\tif (loadedGroupIdSnapshots !== undefined) {\n\t\t\tfor (const [id, lg] of Object.entries(loadedGroupIdSnapshots)) {\n\t\t\t\tif (\n\t\t\t\t\tthis.#loadingGroups[id] === undefined ||\n\t\t\t\t\tlg.snapshotSequenceNumber < this.#loadingGroups[id].snapshotSequenceNumber\n\t\t\t\t) {\n\t\t\t\t\tloadedGroupIdSnapshots[id] = this.#loadingGroups[id] = lg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.#pendingStates.set(key, state);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of stored pending states.\n\t */\n\tget size(): number {\n\t\treturn this.#pendingStates.size;\n\t}\n\n\t/**\n\t * Returns an iterator over [key, serializedState] pairs.\n\t */\n\tentries(): Iterator<[TKey, string]> {\n\t\tconst iterator = this.#pendingStates.entries();\n\t\treturn {\n\t\t\tnext: (): IteratorResult<[TKey, string]> => {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tconst { done, value } = iterator.next();\n\t\t\t\tif (done === true) {\n\t\t\t\t\treturn { done, value: undefined };\n\t\t\t\t}\n\t\t\t\treturn { done, value: [value[0], JSON.stringify(value[1])] };\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Returns an iterator over the stored keys.\n\t */\n\tkeys(): IterableIterator<TKey> {\n\t\treturn this.#pendingStates.keys();\n\t}\n\n\t/**\n\t * Makes the store iterable with `for...of` loops.\n\t */\n\t[Symbol.iterator](): Iterator<[TKey, string]> {\n\t\treturn this.entries();\n\t}\n}\n"]}
@@ -9,9 +9,10 @@ import { type ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/intern
9
9
  export declare class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
10
10
  private readonly internalStorageServiceP;
11
11
  private readonly logger;
12
+ private readonly maxRetries?;
12
13
  private _disposed;
13
14
  private internalStorageService;
14
- constructor(internalStorageServiceP: Promise<IDocumentStorageService>, logger: ITelemetryLoggerExt);
15
+ constructor(internalStorageServiceP: Promise<IDocumentStorageService>, logger: ITelemetryLoggerExt, maxRetries?: number | undefined);
15
16
  get policies(): IDocumentStorageServicePolicies | undefined;
16
17
  get disposed(): boolean;
17
18
  dispose(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,KAAK,EACX,WAAW,EACX,uBAAuB,EACvB,+BAA+B,EAC/B,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,qBAAa,+BAAgC,YAAW,uBAAuB,EAAE,WAAW;IAI1F,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,sBAAsB,CAAsC;gBAElD,uBAAuB,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACzD,MAAM,EAAE,mBAAmB;IAO7C,IAAW,QAAQ,IAAI,+BAA+B,GAAG,SAAS,CAKjE;IACD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IACM,OAAO,IAAI,IAAI;IAIT,eAAe,CAC3B,OAAO,CAAC,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,MAAM,GAEnB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAUnB,WAAW,CAAC,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC;IAe7E,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAO9C,WAAW,CAGvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUT,wBAAwB,CACpC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC;IA8BL,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAO9D,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO5E,OAAO,CAAC,oBAAoB;YAiBd,YAAY;CAM1B"}
1
+ {"version":3,"file":"retriableDocumentStorageService.d.ts","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,KAAK,EACX,WAAW,EACX,uBAAuB,EACvB,+BAA+B,EAC/B,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACN,KAAK,mBAAmB,EAGxB,MAAM,0CAA0C,CAAC;AAElD,qBAAa,+BAAgC,YAAW,uBAAuB,EAAE,WAAW;IAI1F,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAL7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,sBAAsB,CAAsC;gBAElD,uBAAuB,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACzD,MAAM,EAAE,mBAAmB,EAC3B,UAAU,CAAC,oBAAQ;IAOrC,IAAW,QAAQ,IAAI,+BAA+B,GAAG,SAAS,CAKjE;IACD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IACM,OAAO,IAAI,IAAI;IAIT,eAAe,CAC3B,OAAO,CAAC,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,MAAM,GAEnB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAUnB,WAAW,CAAC,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC;IAe7E,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAO9C,WAAW,CAGvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUT,wBAAwB,CACpC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC;IA8BL,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAO9D,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO5E,OAAO,CAAC,oBAAoB;YAiBd,YAAY;CAY1B"}
@@ -9,9 +9,10 @@ const internal_1 = require("@fluidframework/core-utils/internal");
9
9
  const internal_2 = require("@fluidframework/driver-utils/internal");
10
10
  const internal_3 = require("@fluidframework/telemetry-utils/internal");
11
11
  class RetriableDocumentStorageService {
12
- constructor(internalStorageServiceP, logger) {
12
+ constructor(internalStorageServiceP, logger, maxRetries) {
13
13
  this.internalStorageServiceP = internalStorageServiceP;
14
14
  this.logger = logger;
15
+ this.maxRetries = maxRetries;
15
16
  this._disposed = false;
16
17
  this.internalStorageServiceP
17
18
  .then((s) => (this.internalStorageService = s))
@@ -88,7 +89,7 @@ class RetriableDocumentStorageService {
88
89
  async runWithRetry(api, callName) {
89
90
  return (0, internal_2.runWithRetry)(api, callName, this.logger, {
90
91
  onRetry: (_delayInMs, error) => this.checkStorageDisposed(callName, error),
91
- });
92
+ }, this.maxRetries);
92
93
  }
93
94
  }
94
95
  exports.RetriableDocumentStorageService = RetriableDocumentStorageService;
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,kEAA6D;AAa7D,oEAAqE;AACrE,uEAIkD;AAElD,MAAa,+BAA+B;IAG3C,YACkB,uBAAyD,EACzD,MAA2B;QAD3B,4BAAuB,GAAvB,uBAAuB,CAAkC;QACzD,WAAM,GAAN,MAAM,CAAqB;QAJrC,cAAS,GAAG,KAAK,CAAC;QAMzB,IAAI,CAAC,uBAAuB;aAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC,CAAC;aAC9C,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,IAAW,QAAQ;QAClB,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACzD,CAAC;IACD,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IACM,OAAO;QACb,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACvB,CAAC;IAEM,KAAK,CAAC,eAAe,CAC3B,OAAkB,EAClB,YAAqB;QAGrB,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CACV,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAC7C,CAAC,CAAC,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC,CACxC,EACF,yBAAyB,CACzB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,oBAA4C;QACpE,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CACV,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAC7C,IAAI,CAAC,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACjC,OAAO,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;YAC5C,CAAC;YACD,MAAM,IAAI,qBAAU,CACnB,sFAAsF,CACtF,CAAC;QACH,CAAC,CAAC,EACH,qBAAqB,CACrB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,EAAU;QAC/B,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAC1E,kBAAkB,CAClB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,WAAW;IACvB,8BAA8B;IAC9B,kDAAkD;IAClD,SAAwB,EACxB,KAAa,EACb,YAAqB,EACrB,WAAyB;QAEzB,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CACV,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAC7C,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,CAC1D,EACF,qBAAqB,CACrB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,wBAAwB,CACpC,OAAqB,EACrB,OAAwB;QAExB,6CAA6C;QAC7C,yFAAyF;QACzF,uGAAuG;QACvG,4GAA4G;QAC5G,mGAAmG;QACnG,0GAA0G;QAC1G,4GAA4G;QAC5G,8BAA8B;QAC9B,kEAAkE;QAClE,IAAA,iBAAM,EACL,CAAC,OAAO,CAAC,uBAAuB,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAC7E,KAAK,CAAC,kEAAkE,CACxE,CAAC;QACF,IAAI,OAAO,CAAC,uBAAuB,KAAK,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CACpD,CAAC,CAAC,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAC5C,CAAC;QACH,CAAC;QAED,4DAA4D;QAC5D,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CACV,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAC7C,CAAC,CAAC,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAC5C,EACF,kCAAkC,CAClC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,MAAsB;QAClD,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EACrF,yBAAyB,CACzB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,IAAqB;QAC5C,OAAO,IAAI,CAAC,YAAY,CACvB,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAC9E,oBAAoB,CACpB,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,QAAgB,EAAE,KAAc;QAC5D,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAC7B;gBACC,SAAS,EAAE,GAAG,QAAQ,yBAAyB;gBAC/C,aAAa,EAAE,QAAQ,EAAE,gDAAgD;aACzE,EACD,KAAK,CACL,CAAC;YACF,4DAA4D;YAC5D,MAAM,IAAI,uBAAY,CAAC,2CAA2C,EAAE;gBACnE,QAAQ,EAAE,KAAK;aACf,CAAC,CAAC;QACJ,CAAC;QACD,OAAO;IACR,CAAC;IAEO,KAAK,CAAC,YAAY,CAAI,GAAqB,EAAE,QAAgB;QACpE,OAAO,IAAA,uBAAY,EAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;YAC/C,OAAO,EAAE,CAAC,UAAkB,EAAE,KAAc,EAAE,EAAE,CAC/C,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC;SAC3C,CAAC,CAAC;IACJ,CAAC;CACD;AApJD,0EAoJC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISummaryHandle, ISummaryTree } from \"@fluidframework/driver-definitions\";\nimport type {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISnapshot,\n\tISnapshotFetchOptions,\n\tISummaryContext,\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { runWithRetry } from \"@fluidframework/driver-utils/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tGenericError,\n\tUsageError,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tprivate internalStorageService: IDocumentStorageService | undefined;\n\tconstructor(\n\t\tprivate readonly internalStorageServiceP: Promise<IDocumentStorageService>,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.internalStorageServiceP\n\t\t\t.then((s) => (this.internalStorageService = s))\n\t\t\t.catch(() => {});\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.policies;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t\t// eslint-disable-next-line @rushstack/no-new-null -- API used below returns null\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getSnapshotTree(version, scenarioName),\n\t\t\t\t),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) => {\n\t\t\t\t\tif (s.getSnapshot !== undefined) {\n\t\t\t\t\t\treturn s.getSnapshot(snapshotFetchOptions);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"getSnapshot api should exist on internal storage in RetriableDocStorageService class\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\"storage_getSnapshot\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\t// API used below returns null\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getVersions(versionId, count, scenarioName, fetchSource),\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageServiceP.then(async (s) =>\n\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t\t),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown): void {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(api, callName, this.logger, {\n\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.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 type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { ISummaryHandle, ISummaryTree } from \"@fluidframework/driver-definitions\";\nimport type {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISnapshot,\n\tISnapshotFetchOptions,\n\tISummaryContext,\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tIVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { runWithRetry } from \"@fluidframework/driver-utils/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tGenericError,\n\tUsageError,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tprivate internalStorageService: IDocumentStorageService | undefined;\n\tconstructor(\n\t\tprivate readonly internalStorageServiceP: Promise<IDocumentStorageService>,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly maxRetries?: number,\n\t) {\n\t\tthis.internalStorageServiceP\n\t\t\t.then((s) => (this.internalStorageService = s))\n\t\t\t.catch(() => {});\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.policies;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose(): void {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t\t// eslint-disable-next-line @rushstack/no-new-null -- API used below returns null\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getSnapshotTree(version, scenarioName),\n\t\t\t\t),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) => {\n\t\t\t\t\tif (s.getSnapshot !== undefined) {\n\t\t\t\t\t\treturn s.getSnapshot(snapshotFetchOptions);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"getSnapshot api should exist on internal storage in RetriableDocStorageService class\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\"storage_getSnapshot\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\t// API used below returns null\n\t\t// eslint-disable-next-line @rushstack/no-new-null\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getVersions(versionId, count, scenarioName, fetchSource),\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageServiceP.then(async (s) =>\n\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t\t),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown): void {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(\n\t\t\tapi,\n\t\t\tcallName,\n\t\t\tthis.logger,\n\t\t\t{\n\t\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t\t},\n\t\t\tthis.maxRetries,\n\t\t);\n\t}\n}\n"]}
@@ -7,7 +7,7 @@ import type { IEventProvider, IEvent, ITelemetryBaseLogger } from "@fluidframewo
7
7
  import type { IDisposable } from "@fluidframework/core-interfaces/internal";
8
8
  import { type IDocumentStorageService, type IResolvedUrl, type ISnapshot, type IDocumentAttributes, type ISnapshotTree, type IVersion, type ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
9
9
  import { type MonitoringContext } from "@fluidframework/telemetry-utils/internal";
10
- import { type ContainerStorageAdapter, type ISerializableBlobContents } from "./containerStorageAdapter.js";
10
+ import { type ContainerStorageAdapter, type IBase64BlobContents, type ISerializableBlobContents } from "./containerStorageAdapter.js";
11
11
  /**
12
12
  * This is very similar to {@link @fluidframework/protocol-definitions/internal#ISnapshot}, but the difference is
13
13
  * that the blobs of ISnapshot are of type ArrayBufferLike, while the blobs of this interface are serializable because
@@ -48,6 +48,21 @@ export interface IPendingContainerState extends SnapshotWithBlobs {
48
48
  * Any group snapshots (aka delay-loaded) we've downloaded from the service for this container
49
49
  */
50
50
  loadedGroupIdSnapshots?: Record<string, SerializedSnapshotInfo>;
51
+ /**
52
+ * Attachment blob contents inlined by storage id, encoded as base64.
53
+ *
54
+ * Carried separately from {@link SnapshotWithBlobs.snapshotBlobs} because
55
+ * attachment blobs may contain arbitrary binary payloads, and the
56
+ * UTF-8 encoding used for `snapshotBlobs` (which holds JSON/text the
57
+ * runtime authors) would corrupt non-UTF-8 byte sequences with
58
+ * replacement characters. Populated by `captureFullContainerState`; the
59
+ * live container's pending-state path leaves this `undefined` because
60
+ * it does not inline attachment blob contents.
61
+ *
62
+ * On load, entries are decoded from base64 and merged into the same
63
+ * blob cache that `snapshotBlobs` populates.
64
+ */
65
+ attachmentBlobContents?: IBase64BlobContents;
51
66
  /**
52
67
  * All ops since base snapshot sequence number up to the latest op
53
68
  * seen when the container was closed. Used to apply stashed (saved pending)
@@ -1 +1 @@
1
- {"version":3,"file":"serializedStateManager.d.ts","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serializedStateManager.d.ts","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":"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"}
@@ -112,11 +112,21 @@ class SerializedStateManager {
112
112
  return { snapshot, version, attributes };
113
113
  }
114
114
  else {
115
- const { baseSnapshot, snapshotBlobs, savedOps } = pendingLocalState;
115
+ const { baseSnapshot, snapshotBlobs, attachmentBlobContents, savedOps } = pendingLocalState;
116
116
  const blobContents = new Map();
117
+ // Structural snapshot blobs (snapshot trees, `.attributes`, `.redirectTable`)
118
+ // are JSON/text the runtime authored, so UTF-8 round-trip is lossless.
117
119
  for (const [id, value] of Object.entries(snapshotBlobs)) {
118
120
  blobContents.set(id, (0, client_utils_1.stringToBuffer)(value, "utf8"));
119
121
  }
122
+ // Attachment blobs are base64-encoded — see IPendingContainerState
123
+ // docs. Decoded after structural blobs because storage-id collisions
124
+ // between the two namespaces should resolve to the binary form.
125
+ if (attachmentBlobContents !== undefined) {
126
+ for (const [id, value] of Object.entries(attachmentBlobContents)) {
127
+ blobContents.set(id, (0, client_utils_1.stringToBuffer)(value, "base64"));
128
+ }
129
+ }
120
130
  this.storageAdapter.cacheSnapshotBlobs(blobContents);
121
131
  const attributes = await (0, utils_js_1.getDocumentAttributes)(this.storageAdapter, baseSnapshot);
122
132
  const snapshot = {
@@ -1 +1 @@
1
- {"version":3,"file":"serializedStateManager.js","sourceRoot":"","sources":["../src/serializedStateManager.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 { stringToBuffer } from \"@fluid-internal/client-utils\";\nimport type { IRuntime } from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tIEventProvider,\n\tIEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFetchSource,\n\ttype IDocumentStorageService,\n\ttype IResolvedUrl,\n\ttype ISnapshot,\n\ttype IDocumentAttributes,\n\ttype ISnapshotTree,\n\ttype IVersion,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { getSnapshotTree, isInstanceOfISnapshot } from \"@fluidframework/driver-utils/internal\";\nimport {\n\ttype MonitoringContext,\n\tPerformanceEvent,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetBlobContentsFromTree,\n\ttype ContainerStorageAdapter,\n\ttype ISerializableBlobContents,\n} from \"./containerStorageAdapter.js\";\nimport { SnapshotRefresher } from \"./snapshotRefresher.js\";\nimport {\n\tconvertISnapshotToSnapshotWithBlobs,\n\tconvertSnapshotToSnapshotInfo,\n\tgetDocumentAttributes,\n} from \"./utils.js\";\n\n/**\n * This is very similar to {@link @fluidframework/protocol-definitions/internal#ISnapshot}, but the difference is\n * that the blobs of ISnapshot are of type ArrayBufferLike, while the blobs of this interface are serializable because\n * they are already converted to string.\n */\nexport interface SnapshotWithBlobs {\n\t/**\n\t * Snapshot from which container initially loaded.\n\t */\n\tbaseSnapshot: ISnapshotTree;\n\t/**\n\t * Serializable blobs from the base snapshot. Used to load offline since\n\t * storage is not available.\n\t */\n\tsnapshotBlobs: ISerializableBlobContents;\n}\n\n/**\n * State saved by a container at close time, to be used to load a new instance\n * of the container to the same state\n *\n * This is very similar to {@link @fluidframework/protocol-definitions/internal#ISnapshot}, but the difference is\n * that the blobs of ISnapshot are of type ArrayBufferLike, while the blobs of this interface are serializable because\n * they are already converted to string.\n *\n * @internal\n */\nexport interface IPendingContainerState extends SnapshotWithBlobs {\n\t/**\n\t * This container was attached (as opposed to IPendingDetachedContainerState.attached which is false)\n\t */\n\tattached: true;\n\t/**\n\t * Runtime-specific state that will be needed to properly rehydrate\n\t * (it's included in ContainerContext passed to instantiateRuntime)\n\t */\n\tpendingRuntimeState: unknown;\n\t/**\n\t * Any group snapshots (aka delay-loaded) we've downloaded from the service for this container\n\t */\n\tloadedGroupIdSnapshots?: Record<string, SerializedSnapshotInfo>;\n\t/**\n\t * All ops since base snapshot sequence number up to the latest op\n\t * seen when the container was closed. Used to apply stashed (saved pending)\n\t * ops at the same sequence number at which they were made.\n\t */\n\tsavedOps: ISequencedDocumentMessage[];\n\t/**\n\t * The Container's URL in the service, needed to hook up the driver during rehydration\n\t */\n\turl: string;\n\t/**\n\t * If the Container was connected when serialized, its clientId. Used as the initial clientId upon rehydration, until reconnected.\n\t */\n\tclientId?: string;\n}\n\n/**\n * State saved by a container in detached state, to be used to load a new instance\n * of the container to the same state (rehydrate)\n * @internal\n */\nexport interface IPendingDetachedContainerState extends SnapshotWithBlobs {\n\t/**\n\t * This container was not attached (as opposed to IPendingContainerState.attached which is true)\n\t */\n\tattached: false;\n\t/**\n\t * Indicates whether we expect the rehydrated container to have non-empty Detached Blob Storage\n\t */\n\thasAttachmentBlobs: boolean;\n\t/**\n\t * Used by the memory blob storage to persisted attachment blobs\n\t */\n\tattachmentBlobs?: string;\n\t/**\n\t * Runtime-specific state that will be needed to properly rehydrate\n\t * (it's included in ContainerContext passed to instantiateRuntime)\n\t */\n\tpendingRuntimeState?: unknown;\n}\n\nexport interface SerializedSnapshotInfo extends SnapshotWithBlobs {\n\tsnapshotSequenceNumber: number;\n}\n\nexport interface ISnapshotInfo {\n\tsnapshotSequenceNumber: number;\n\tsnapshotFetchedTime?: number | undefined;\n\tsnapshot: ISnapshot | ISnapshotTree;\n}\n\nexport type ISerializedStateManagerDocumentStorageService = Pick<\n\tContainerStorageAdapter,\n\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\" | \"readBlob\" | \"cacheSnapshotBlobs\"\n> & {\n\tloadedGroupIdSnapshots: Record<string, ISnapshot>;\n};\n\ninterface ISerializerEvent extends IEvent {\n\t(event: \"saved\", listener: (dirty: boolean) => void): void;\n}\n\n/**\n * Helper class to manage the state of the container needed for proper serialization.\n *\n * It holds the pendingLocalState the container was rehydrated from (if any),\n * as well as the snapshot to be used for serialization.\n * It also keeps track of container dirty state and which local ops have been processed\n */\nexport class SerializedStateManager implements IDisposable {\n\tprivate readonly processedOps: ISequencedDocumentMessage[] = [];\n\tprivate readonly mc: MonitoringContext;\n\tprivate snapshotInfo: ISnapshotInfo | undefined;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\tprivate lastSavedOpSequenceNumber: number = 0;\n\tprivate readonly snapshotRefresher: SnapshotRefresher | undefined;\n\t#disposed: boolean = false;\n\n\t/**\n\t * @param subLogger - Container's logger to use as parent for our logger\n\t * @param storageAdapter - Storage adapter for fetching snapshots\n\t * @param offlineLoadEnabled - Is serializing/rehydrating containers allowed?\n\t * @param containerEvent - Source of the \"saved\" event when the container has all its pending state uploaded\n\t * @param containerDirty - Is the container \"dirty\"? That's the opposite of \"saved\" - there is pending state that may not have been received yet by the service.\n\t */\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tcontainerEvent: IEventProvider<ISerializerEvent>,\n\t\tprivate readonly containerDirty: () => boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tsnapshotRefreshTimeoutMs?: number,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\n\t\tthis.snapshotRefresher = this.offlineLoadEnabled\n\t\t\t? new SnapshotRefresher(\n\t\t\t\t\tsubLogger,\n\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t\tthis.offlineLoadEnabled,\n\t\t\t\t\tthis.supportGetSnapshotApi,\n\t\t\t\t\t(snapshot: ISnapshotInfo) => this.handleSnapshotRefreshed(snapshot),\n\t\t\t\t\tsnapshotRefreshTimeoutMs,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\t\tcontainerEvent.on(\"saved\", () => this.updateSnapshotAndProcessedOpsMaybe());\n\t}\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\tdispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.snapshotRefresher?.dispose();\n\t}\n\n\tprivate verifyNotDisposed(): void {\n\t\tif (this.#disposed) {\n\t\t\tthrow new Error(\"SerializedStateManager used after dispose.\");\n\t\t}\n\t}\n\n\t/**\n\t * Promise that will resolve (or reject) once we've tried to download the latest snapshot(s) from storage\n\t * only intended to be used for testing purposes.\n\t * @returns The snapshot sequence number associated with the latest fetched snapshot\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.snapshotRefresher?.refreshSnapshotP;\n\t}\n\n\t/**\n\t * Called whenever an incoming op is processed by the Container\n\t */\n\tpublic addProcessedOp(message: ISequencedDocumentMessage): void {\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.processedOps.push(message);\n\t\t\tthis.updateSnapshotAndProcessedOpsMaybe();\n\t\t}\n\t}\n\n\t/**\n\t * This wraps the basic functionality of fetching the snapshot for this container during Container load.\n\t *\n\t * If we have pendingLocalState, we get the snapshot from there.\n\t * Otherwise, fetch it from storage (according to specifiedVersion if provided).\n\t *\n\t * @param specifiedVersion - If a version is specified and we don't have pendingLocalState, fetch this version from storage.\n\t * @param pendingLocalState - The pendingLocalState being rehydrated, if any (undefined when loading directly from storage)\n\t * @returns The snapshot to boot the container from\n\t */\n\tpublic async fetchSnapshot(\n\t\tspecifiedVersion: string | undefined,\n\t\tpendingLocalState: IPendingContainerState | undefined,\n\t): Promise<{\n\t\tsnapshot: ISnapshot | ISnapshotTree;\n\t\tversion: IVersion | undefined;\n\t\tattributes: IDocumentAttributes;\n\t}> {\n\t\tthis.verifyNotDisposed();\n\t\tif (pendingLocalState === undefined) {\n\t\t\tconst { snapshot, version } = await getSnapshot(\n\t\t\t\tthis.mc,\n\t\t\t\tthis.storageAdapter,\n\t\t\t\tthis.supportGetSnapshotApi(),\n\t\t\t\tspecifiedVersion,\n\t\t\t);\n\t\t\tconst baseSnapshotTree: ISnapshotTree | undefined = getSnapshotTree(snapshot);\n\t\t\tconst attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshotTree);\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\tthis.snapshotRefresher?.startTimer();\n\t\t\t\tthis.snapshotInfo = {\n\t\t\t\t\tsnapshot,\n\t\t\t\t\tsnapshotSequenceNumber: attributes.sequenceNumber,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { snapshot, version, attributes };\n\t\t} else {\n\t\t\tconst { baseSnapshot, snapshotBlobs, savedOps } = pendingLocalState;\n\t\t\tconst blobContents = new Map<string, ArrayBuffer>();\n\t\t\tfor (const [id, value] of Object.entries(snapshotBlobs)) {\n\t\t\t\tblobContents.set(id, stringToBuffer(value, \"utf8\"));\n\t\t\t}\n\t\t\tthis.storageAdapter.cacheSnapshotBlobs(blobContents);\n\t\t\tconst attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshot);\n\n\t\t\tconst snapshot: ISnapshot = {\n\t\t\t\tsequenceNumber: attributes.sequenceNumber,\n\t\t\t\tsnapshotTree: baseSnapshot,\n\t\t\t\tblobContents,\n\t\t\t\tlatestSequenceNumber: undefined,\n\t\t\t\tops: [],\n\t\t\t\tsnapshotFormatV: 1,\n\t\t\t};\n\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\t// special case handle. Obtaining the last saved op seq num to avoid\n\t\t\t\t// refreshing the snapshot before we have processed it. It could cause\n\t\t\t\t// a subsequent stashing to have a newer snapshot than allowed.\n\t\t\t\tif (savedOps.length > 0) {\n\t\t\t\t\tconst savedOpsSize = savedOps.length;\n\t\t\t\t\tthis.lastSavedOpSequenceNumber = savedOps[savedOpsSize - 1].sequenceNumber;\n\t\t\t\t}\n\n\t\t\t\tthis.snapshotInfo = {\n\t\t\t\t\tsnapshot,\n\t\t\t\t\tsnapshotSequenceNumber: attributes.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis.snapshotRefresher?.tryRefreshSnapshot();\n\t\t\t}\n\t\t\treturn { snapshot, version: undefined, attributes };\n\t\t}\n\t}\n\n\t/**\n\t * Handles the snapshotRefreshed event from SnapshotRefresher.\n\t * Decides whether to accept the new snapshot based on processed ops.\n\t * @returns The snapshot sequence number if updated, -1 otherwise\n\t */\n\tprivate handleSnapshotRefreshed(latestSnapshot: ISnapshotInfo): number {\n\t\tthis.latestSnapshot = latestSnapshot;\n\t\treturn this.updateSnapshotAndProcessedOpsMaybe();\n\t}\n\n\t/**\n\t * Updates class snapshot and processedOps if we have a new snapshot and it's among processedOps range.\n\t */\n\tprivate updateSnapshotAndProcessedOpsMaybe(): number {\n\t\tconst snapshotSequenceNumber = this.latestSnapshot?.snapshotSequenceNumber;\n\t\tif (\n\t\t\tthis.#disposed ||\n\t\t\tsnapshotSequenceNumber === undefined ||\n\t\t\tthis.processedOps.length === 0 ||\n\t\t\tthis.processedOps[this.processedOps.length - 1].sequenceNumber <\n\t\t\t\tthis.lastSavedOpSequenceNumber ||\n\t\t\tthis.containerDirty()\n\t\t) {\n\t\t\t// can't refresh latest snapshot until we have processed the ops up to it.\n\t\t\t// Pending state would be behind the latest snapshot.\n\t\t\treturn -1;\n\t\t}\n\t\tconst firstProcessedOpSequenceNumber = this.processedOps[0].sequenceNumber;\n\t\tconst lastProcessedOpSequenceNumber =\n\t\t\tthis.processedOps[this.processedOps.length - 1].sequenceNumber;\n\n\t\tif (snapshotSequenceNumber < firstProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq number is older than our first processed op, which could mean we're fetching\n\t\t\t// the same snapshot that we already have or snapshot is too old, implicating an unexpected behavior.\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"OldSnapshotFetchWhileRefreshing\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t\tlastProcessedOpSequenceNumber,\n\t\t\t\tstashedSnapshotSequenceNumber: this.snapshotInfo?.snapshotSequenceNumber,\n\t\t\t});\n\t\t\tthis.latestSnapshot = undefined;\n\t\t\tthis.snapshotRefresher?.clearLatestSnapshot();\n\t\t\tthis.snapshotRefresher?.restartTimer();\n\t\t} else if (snapshotSequenceNumber <= lastProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq num is between the first and last processed op.\n\t\t\t// Remove the ops that are already part of the snapshot\n\t\t\tthis.processedOps.splice(0, snapshotSequenceNumber - firstProcessedOpSequenceNumber + 1);\n\t\t\tthis.snapshotInfo = this.latestSnapshot;\n\t\t\tthis.latestSnapshot = undefined;\n\t\t\tthis.snapshotRefresher?.clearLatestSnapshot();\n\t\t\tthis.snapshotRefresher?.restartTimer();\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"SnapshotRefreshed\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t\tnewFirstProcessedOpSequenceNumber:\n\t\t\t\t\tthis.processedOps.length === 0 ? undefined : this.processedOps[0].sequenceNumber,\n\t\t\t});\n\t\t}\n\t\treturn snapshotSequenceNumber;\n\t}\n\n\t/**\n\t * When the Container attaches, we need to stash the initial snapshot (a form of the attach summary).\n\t * This method is only meant to be used by Container.attach() to set the initial\n\t * base snapshot when attaching.\n\t * @param snapshot - snapshot and blobs collected while attaching (a form of the attach summary)\n\t */\n\tpublic setInitialSnapshot(snapshot: ISnapshot): void {\n\t\tthis.verifyNotDisposed();\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.snapshotInfo = {\n\t\t\t\tsnapshot,\n\t\t\t\tsnapshotSequenceNumber: snapshot.sequenceNumber ?? 0,\n\t\t\t\tsnapshotFetchedTime: Date.now(),\n\t\t\t};\n\t\t\tthis.snapshotRefresher?.startTimer();\n\t\t}\n\t}\n\n\t/**\n\t * Assembles and serializes the {@link IPendingContainerState} for the container,\n\t * to be stored and used to rehydrate the container at a later time.\n\t */\n\tpublic async getPendingLocalState(\n\t\tclientId: string | undefined,\n\t\truntime: Pick<IRuntime, \"getPendingLocalState\">,\n\t\tresolvedUrl: IResolvedUrl,\n\t): Promise<string> {\n\t\tthis.verifyNotDisposed();\n\t\tif (!this.offlineLoadEnabled) {\n\t\t\tthrow new UsageError(\"Can't get pending local state unless offline load is enabled\");\n\t\t}\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tthis.mc.logger,\n\t\t\t{\n\t\t\t\teventName: \"getPendingLocalState\",\n\t\t\t\tdetails: {\n\t\t\t\t\tnotifyImminentClosure: false,\n\t\t\t\t\tsessionExpiryTimerStarted: undefined,\n\t\t\t\t\tsnapshotSequenceNumber: undefined,\n\t\t\t\t\tprocessedOpsSize: this.processedOps.length,\n\t\t\t\t},\n\t\t\t\tclientId,\n\t\t\t},\n\t\t\tasync () => {\n\t\t\t\tassert(this.snapshotInfo !== undefined, 0x8e5 /* no base data */);\n\t\t\t\tconst pendingRuntimeState = await runtime.getPendingLocalState({\n\t\t\t\t\tnotifyImminentClosure: false,\n\t\t\t\t\tsnapshotSequenceNumber: this.snapshotInfo.snapshotSequenceNumber,\n\t\t\t\t\tsessionExpiryTimerStarted: this.snapshotInfo.snapshotFetchedTime,\n\t\t\t\t});\n\t\t\t\t// This conversion is required because ArrayBufferLike doesn't survive JSON.stringify\n\t\t\t\tconst loadedGroupIdSnapshots: Record<string, SerializedSnapshotInfo> = {};\n\t\t\t\tlet hasGroupIdSnapshots = false;\n\t\t\t\tconst groupIdSnapshots = Object.entries(this.storageAdapter.loadedGroupIdSnapshots);\n\t\t\t\tif (groupIdSnapshots.length > 0) {\n\t\t\t\t\tfor (const [groupId, snapshot] of groupIdSnapshots) {\n\t\t\t\t\t\thasGroupIdSnapshots = true;\n\t\t\t\t\t\tloadedGroupIdSnapshots[groupId] = convertSnapshotToSnapshotInfo(snapshot);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst snapshotWithBlobs: SnapshotWithBlobs = isInstanceOfISnapshot(\n\t\t\t\t\tthis.snapshotInfo.snapshot,\n\t\t\t\t)\n\t\t\t\t\t? convertISnapshotToSnapshotWithBlobs(this.snapshotInfo.snapshot)\n\t\t\t\t\t: await convertSnapshotTreeToSnapshotWithBlobs(\n\t\t\t\t\t\t\tthis.snapshotInfo.snapshot,\n\t\t\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t\t\t);\n\n\t\t\t\tconst pendingState: IPendingContainerState = {\n\t\t\t\t\tattached: true,\n\t\t\t\t\tpendingRuntimeState,\n\t\t\t\t\t...snapshotWithBlobs,\n\t\t\t\t\tloadedGroupIdSnapshots: hasGroupIdSnapshots ? loadedGroupIdSnapshots : undefined,\n\t\t\t\t\tsavedOps: this.processedOps,\n\t\t\t\t\turl: resolvedUrl.url,\n\t\t\t\t\tclientId,\n\t\t\t\t};\n\n\t\t\t\treturn JSON.stringify(pendingState);\n\t\t\t},\n\t\t);\n\t}\n}\n\nasync function convertSnapshotTreeToSnapshotWithBlobs(\n\tsnapshot: ISnapshotTree,\n\tstorageAdapter: ISerializedStateManagerDocumentStorageService,\n): Promise<SnapshotWithBlobs> {\n\tconst snapshotBlobs = await getBlobContentsFromTree(snapshot, storageAdapter);\n\treturn {\n\t\tbaseSnapshot: snapshot,\n\t\tsnapshotBlobs,\n\t};\n}\n\n/**\n * Retrieves the most recent snapshot and returns its info.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @returns a SnapshotInfo object containing the snapshot tree, snapshot blobs and its sequence number.\n */\nexport async function getLatestSnapshotInfo(\n\tmc: MonitoringContext,\n\tstorageAdapter: ISerializedStateManagerDocumentStorageService,\n\tsupportGetSnapshotApi: boolean,\n): Promise<ISnapshotInfo | undefined> {\n\treturn PerformanceEvent.timedExecAsync<ISnapshotInfo | undefined>(\n\t\tmc.logger,\n\t\t{ eventName: \"GetLatestSnapshotInfo\" },\n\t\tasync (event) => {\n\t\t\ttry {\n\t\t\t\t// get the latest non cached snapshot version\n\t\t\t\tconst specifiedVersion: IVersion[] = await storageAdapter.getVersions(\n\t\t\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tnull,\n\t\t\t\t\t1,\n\t\t\t\t\t\"getLatestSnapshotInfo\",\n\t\t\t\t\tFetchSource.noCache,\n\t\t\t\t);\n\t\t\t\tconst { snapshot: baseSnapshot } = await getSnapshot(\n\t\t\t\t\tmc,\n\t\t\t\t\tstorageAdapter,\n\t\t\t\t\tsupportGetSnapshotApi,\n\t\t\t\t\tspecifiedVersion[0]?.id,\n\t\t\t\t);\n\n\t\t\t\tconst { sequenceNumber, snapshotTree } = isInstanceOfISnapshot(baseSnapshot)\n\t\t\t\t\t? baseSnapshot\n\t\t\t\t\t: { snapshotTree: baseSnapshot, sequenceNumber: undefined };\n\n\t\t\t\tconst snapshotSequenceNumber: number =\n\t\t\t\t\tsequenceNumber ??\n\t\t\t\t\t(await getDocumentAttributes(storageAdapter, snapshotTree).then(\n\t\t\t\t\t\t(a) => a.sequenceNumber,\n\t\t\t\t\t));\n\t\t\t\treturn {\n\t\t\t\t\tsnapshot: baseSnapshot,\n\t\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\t\tsnapshotFetchedTime: Date.now(),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tevent.cancel(undefined, error);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t);\n}\n\n/**\n * Retrieves a snapshot from the storage adapter and transforms it into an ISnapshotTree object.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns An ISnapshotTree and its version.\n */\nasync function getSnapshot(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<\n\t\tIDocumentStorageService,\n\t\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\"\n\t>,\n\tsupportGetSnapshotApi: boolean,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot: ISnapshot | ISnapshotTree; version?: IVersion }> {\n\tconst { snapshot, version } = supportGetSnapshotApi\n\t\t? await fetchISnapshot(mc, storageAdapter, specifiedVersion)\n\t\t: await fetchISnapshotTree(mc, storageAdapter, specifiedVersion);\n\tassert(snapshot !== undefined, 0x8e4 /* Snapshot should exist */);\n\treturn { snapshot, version };\n}\n\n/**\n * Fetches an ISnapshot from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing a getSnapshot method to retrieve the ISnapshot and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshot(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshot\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshot; version?: IVersion }> {\n\tconst snapshot = await storageAdapter.getSnapshot?.({ versionId: specifiedVersion });\n\tconst version: IVersion | undefined =\n\t\tsnapshot?.snapshotTree.id === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: snapshot.snapshotTree.id,\n\t\t\t\t\ttreeId: snapshot.snapshotTree.id,\n\t\t\t\t};\n\n\tif (snapshot === undefined && specifiedVersion !== undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotTreeFailed\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n\n/**\n * Fetches an ISnapshotTree from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the ISnapshotTree and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshotTree(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshotTree\" | \"getVersions\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {\n\t// API uses null\n\t// eslint-disable-next-line unicorn/no-null\n\tconst versions = await storageAdapter.getVersions(specifiedVersion ?? null, 1);\n\tconst version = versions[0];\n\n\tif (version === undefined && specifiedVersion !== undefined) {\n\t\t// We should have a defined version to load from if specified version requested\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"NoVersionFoundWhenSpecified\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t}\n\tconst snapshot = (await storageAdapter.getSnapshotTree(version)) ?? undefined;\n\n\tif (snapshot === undefined && version !== undefined) {\n\t\tmc.logger.sendErrorEvent({ eventName: \"getSnapshotTreeFailed\", id: version.id });\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n"]}
1
+ {"version":3,"file":"serializedStateManager.js","sourceRoot":"","sources":["../src/serializedStateManager.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 { stringToBuffer } from \"@fluid-internal/client-utils\";\nimport type { IRuntime } from \"@fluidframework/container-definitions/internal\";\nimport type {\n\tIEventProvider,\n\tIEvent,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFetchSource,\n\ttype IDocumentStorageService,\n\ttype IResolvedUrl,\n\ttype ISnapshot,\n\ttype IDocumentAttributes,\n\ttype ISnapshotTree,\n\ttype IVersion,\n\ttype ISequencedDocumentMessage,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { getSnapshotTree, isInstanceOfISnapshot } from \"@fluidframework/driver-utils/internal\";\nimport {\n\ttype MonitoringContext,\n\tPerformanceEvent,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetBlobContentsFromTree,\n\ttype ContainerStorageAdapter,\n\ttype IBase64BlobContents,\n\ttype ISerializableBlobContents,\n} from \"./containerStorageAdapter.js\";\nimport { SnapshotRefresher } from \"./snapshotRefresher.js\";\nimport {\n\tconvertISnapshotToSnapshotWithBlobs,\n\tconvertSnapshotToSnapshotInfo,\n\tgetDocumentAttributes,\n} from \"./utils.js\";\n\n/**\n * This is very similar to {@link @fluidframework/protocol-definitions/internal#ISnapshot}, but the difference is\n * that the blobs of ISnapshot are of type ArrayBufferLike, while the blobs of this interface are serializable because\n * they are already converted to string.\n */\nexport interface SnapshotWithBlobs {\n\t/**\n\t * Snapshot from which container initially loaded.\n\t */\n\tbaseSnapshot: ISnapshotTree;\n\t/**\n\t * Serializable blobs from the base snapshot. Used to load offline since\n\t * storage is not available.\n\t */\n\tsnapshotBlobs: ISerializableBlobContents;\n}\n\n/**\n * State saved by a container at close time, to be used to load a new instance\n * of the container to the same state\n *\n * This is very similar to {@link @fluidframework/protocol-definitions/internal#ISnapshot}, but the difference is\n * that the blobs of ISnapshot are of type ArrayBufferLike, while the blobs of this interface are serializable because\n * they are already converted to string.\n *\n * @internal\n */\nexport interface IPendingContainerState extends SnapshotWithBlobs {\n\t/**\n\t * This container was attached (as opposed to IPendingDetachedContainerState.attached which is false)\n\t */\n\tattached: true;\n\t/**\n\t * Runtime-specific state that will be needed to properly rehydrate\n\t * (it's included in ContainerContext passed to instantiateRuntime)\n\t */\n\tpendingRuntimeState: unknown;\n\t/**\n\t * Any group snapshots (aka delay-loaded) we've downloaded from the service for this container\n\t */\n\tloadedGroupIdSnapshots?: Record<string, SerializedSnapshotInfo>;\n\t/**\n\t * Attachment blob contents inlined by storage id, encoded as base64.\n\t *\n\t * Carried separately from {@link SnapshotWithBlobs.snapshotBlobs} because\n\t * attachment blobs may contain arbitrary binary payloads, and the\n\t * UTF-8 encoding used for `snapshotBlobs` (which holds JSON/text the\n\t * runtime authors) would corrupt non-UTF-8 byte sequences with\n\t * replacement characters. Populated by `captureFullContainerState`; the\n\t * live container's pending-state path leaves this `undefined` because\n\t * it does not inline attachment blob contents.\n\t *\n\t * On load, entries are decoded from base64 and merged into the same\n\t * blob cache that `snapshotBlobs` populates.\n\t */\n\tattachmentBlobContents?: IBase64BlobContents;\n\t/**\n\t * All ops since base snapshot sequence number up to the latest op\n\t * seen when the container was closed. Used to apply stashed (saved pending)\n\t * ops at the same sequence number at which they were made.\n\t */\n\tsavedOps: ISequencedDocumentMessage[];\n\t/**\n\t * The Container's URL in the service, needed to hook up the driver during rehydration\n\t */\n\turl: string;\n\t/**\n\t * If the Container was connected when serialized, its clientId. Used as the initial clientId upon rehydration, until reconnected.\n\t */\n\tclientId?: string;\n}\n\n/**\n * State saved by a container in detached state, to be used to load a new instance\n * of the container to the same state (rehydrate)\n * @internal\n */\nexport interface IPendingDetachedContainerState extends SnapshotWithBlobs {\n\t/**\n\t * This container was not attached (as opposed to IPendingContainerState.attached which is true)\n\t */\n\tattached: false;\n\t/**\n\t * Indicates whether we expect the rehydrated container to have non-empty Detached Blob Storage\n\t */\n\thasAttachmentBlobs: boolean;\n\t/**\n\t * Used by the memory blob storage to persisted attachment blobs\n\t */\n\tattachmentBlobs?: string;\n\t/**\n\t * Runtime-specific state that will be needed to properly rehydrate\n\t * (it's included in ContainerContext passed to instantiateRuntime)\n\t */\n\tpendingRuntimeState?: unknown;\n}\n\nexport interface SerializedSnapshotInfo extends SnapshotWithBlobs {\n\tsnapshotSequenceNumber: number;\n}\n\nexport interface ISnapshotInfo {\n\tsnapshotSequenceNumber: number;\n\tsnapshotFetchedTime?: number | undefined;\n\tsnapshot: ISnapshot | ISnapshotTree;\n}\n\nexport type ISerializedStateManagerDocumentStorageService = Pick<\n\tContainerStorageAdapter,\n\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\" | \"readBlob\" | \"cacheSnapshotBlobs\"\n> & {\n\tloadedGroupIdSnapshots: Record<string, ISnapshot>;\n};\n\ninterface ISerializerEvent extends IEvent {\n\t(event: \"saved\", listener: (dirty: boolean) => void): void;\n}\n\n/**\n * Helper class to manage the state of the container needed for proper serialization.\n *\n * It holds the pendingLocalState the container was rehydrated from (if any),\n * as well as the snapshot to be used for serialization.\n * It also keeps track of container dirty state and which local ops have been processed\n */\nexport class SerializedStateManager implements IDisposable {\n\tprivate readonly processedOps: ISequencedDocumentMessage[] = [];\n\tprivate readonly mc: MonitoringContext;\n\tprivate snapshotInfo: ISnapshotInfo | undefined;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\tprivate lastSavedOpSequenceNumber: number = 0;\n\tprivate readonly snapshotRefresher: SnapshotRefresher | undefined;\n\t#disposed: boolean = false;\n\n\t/**\n\t * @param subLogger - Container's logger to use as parent for our logger\n\t * @param storageAdapter - Storage adapter for fetching snapshots\n\t * @param offlineLoadEnabled - Is serializing/rehydrating containers allowed?\n\t * @param containerEvent - Source of the \"saved\" event when the container has all its pending state uploaded\n\t * @param containerDirty - Is the container \"dirty\"? That's the opposite of \"saved\" - there is pending state that may not have been received yet by the service.\n\t */\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tcontainerEvent: IEventProvider<ISerializerEvent>,\n\t\tprivate readonly containerDirty: () => boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tsnapshotRefreshTimeoutMs?: number,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\n\t\tthis.snapshotRefresher = this.offlineLoadEnabled\n\t\t\t? new SnapshotRefresher(\n\t\t\t\t\tsubLogger,\n\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t\tthis.offlineLoadEnabled,\n\t\t\t\t\tthis.supportGetSnapshotApi,\n\t\t\t\t\t(snapshot: ISnapshotInfo) => this.handleSnapshotRefreshed(snapshot),\n\t\t\t\t\tsnapshotRefreshTimeoutMs,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\t\tcontainerEvent.on(\"saved\", () => this.updateSnapshotAndProcessedOpsMaybe());\n\t}\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\tdispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.snapshotRefresher?.dispose();\n\t}\n\n\tprivate verifyNotDisposed(): void {\n\t\tif (this.#disposed) {\n\t\t\tthrow new Error(\"SerializedStateManager used after dispose.\");\n\t\t}\n\t}\n\n\t/**\n\t * Promise that will resolve (or reject) once we've tried to download the latest snapshot(s) from storage\n\t * only intended to be used for testing purposes.\n\t * @returns The snapshot sequence number associated with the latest fetched snapshot\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.snapshotRefresher?.refreshSnapshotP;\n\t}\n\n\t/**\n\t * Called whenever an incoming op is processed by the Container\n\t */\n\tpublic addProcessedOp(message: ISequencedDocumentMessage): void {\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.processedOps.push(message);\n\t\t\tthis.updateSnapshotAndProcessedOpsMaybe();\n\t\t}\n\t}\n\n\t/**\n\t * This wraps the basic functionality of fetching the snapshot for this container during Container load.\n\t *\n\t * If we have pendingLocalState, we get the snapshot from there.\n\t * Otherwise, fetch it from storage (according to specifiedVersion if provided).\n\t *\n\t * @param specifiedVersion - If a version is specified and we don't have pendingLocalState, fetch this version from storage.\n\t * @param pendingLocalState - The pendingLocalState being rehydrated, if any (undefined when loading directly from storage)\n\t * @returns The snapshot to boot the container from\n\t */\n\tpublic async fetchSnapshot(\n\t\tspecifiedVersion: string | undefined,\n\t\tpendingLocalState: IPendingContainerState | undefined,\n\t): Promise<{\n\t\tsnapshot: ISnapshot | ISnapshotTree;\n\t\tversion: IVersion | undefined;\n\t\tattributes: IDocumentAttributes;\n\t}> {\n\t\tthis.verifyNotDisposed();\n\t\tif (pendingLocalState === undefined) {\n\t\t\tconst { snapshot, version } = await getSnapshot(\n\t\t\t\tthis.mc,\n\t\t\t\tthis.storageAdapter,\n\t\t\t\tthis.supportGetSnapshotApi(),\n\t\t\t\tspecifiedVersion,\n\t\t\t);\n\t\t\tconst baseSnapshotTree: ISnapshotTree | undefined = getSnapshotTree(snapshot);\n\t\t\tconst attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshotTree);\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\tthis.snapshotRefresher?.startTimer();\n\t\t\t\tthis.snapshotInfo = {\n\t\t\t\t\tsnapshot,\n\t\t\t\t\tsnapshotSequenceNumber: attributes.sequenceNumber,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { snapshot, version, attributes };\n\t\t} else {\n\t\t\tconst { baseSnapshot, snapshotBlobs, attachmentBlobContents, savedOps } =\n\t\t\t\tpendingLocalState;\n\t\t\tconst blobContents = new Map<string, ArrayBuffer>();\n\t\t\t// Structural snapshot blobs (snapshot trees, `.attributes`, `.redirectTable`)\n\t\t\t// are JSON/text the runtime authored, so UTF-8 round-trip is lossless.\n\t\t\tfor (const [id, value] of Object.entries(snapshotBlobs)) {\n\t\t\t\tblobContents.set(id, stringToBuffer(value, \"utf8\"));\n\t\t\t}\n\t\t\t// Attachment blobs are base64-encoded — see IPendingContainerState\n\t\t\t// docs. Decoded after structural blobs because storage-id collisions\n\t\t\t// between the two namespaces should resolve to the binary form.\n\t\t\tif (attachmentBlobContents !== undefined) {\n\t\t\t\tfor (const [id, value] of Object.entries(attachmentBlobContents)) {\n\t\t\t\t\tblobContents.set(id, stringToBuffer(value, \"base64\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.storageAdapter.cacheSnapshotBlobs(blobContents);\n\t\t\tconst attributes = await getDocumentAttributes(this.storageAdapter, baseSnapshot);\n\n\t\t\tconst snapshot: ISnapshot = {\n\t\t\t\tsequenceNumber: attributes.sequenceNumber,\n\t\t\t\tsnapshotTree: baseSnapshot,\n\t\t\t\tblobContents,\n\t\t\t\tlatestSequenceNumber: undefined,\n\t\t\t\tops: [],\n\t\t\t\tsnapshotFormatV: 1,\n\t\t\t};\n\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\t// special case handle. Obtaining the last saved op seq num to avoid\n\t\t\t\t// refreshing the snapshot before we have processed it. It could cause\n\t\t\t\t// a subsequent stashing to have a newer snapshot than allowed.\n\t\t\t\tif (savedOps.length > 0) {\n\t\t\t\t\tconst savedOpsSize = savedOps.length;\n\t\t\t\t\tthis.lastSavedOpSequenceNumber = savedOps[savedOpsSize - 1].sequenceNumber;\n\t\t\t\t}\n\n\t\t\t\tthis.snapshotInfo = {\n\t\t\t\t\tsnapshot,\n\t\t\t\t\tsnapshotSequenceNumber: attributes.sequenceNumber,\n\t\t\t\t};\n\t\t\t\tthis.snapshotRefresher?.tryRefreshSnapshot();\n\t\t\t}\n\t\t\treturn { snapshot, version: undefined, attributes };\n\t\t}\n\t}\n\n\t/**\n\t * Handles the snapshotRefreshed event from SnapshotRefresher.\n\t * Decides whether to accept the new snapshot based on processed ops.\n\t * @returns The snapshot sequence number if updated, -1 otherwise\n\t */\n\tprivate handleSnapshotRefreshed(latestSnapshot: ISnapshotInfo): number {\n\t\tthis.latestSnapshot = latestSnapshot;\n\t\treturn this.updateSnapshotAndProcessedOpsMaybe();\n\t}\n\n\t/**\n\t * Updates class snapshot and processedOps if we have a new snapshot and it's among processedOps range.\n\t */\n\tprivate updateSnapshotAndProcessedOpsMaybe(): number {\n\t\tconst snapshotSequenceNumber = this.latestSnapshot?.snapshotSequenceNumber;\n\t\tif (\n\t\t\tthis.#disposed ||\n\t\t\tsnapshotSequenceNumber === undefined ||\n\t\t\tthis.processedOps.length === 0 ||\n\t\t\tthis.processedOps[this.processedOps.length - 1].sequenceNumber <\n\t\t\t\tthis.lastSavedOpSequenceNumber ||\n\t\t\tthis.containerDirty()\n\t\t) {\n\t\t\t// can't refresh latest snapshot until we have processed the ops up to it.\n\t\t\t// Pending state would be behind the latest snapshot.\n\t\t\treturn -1;\n\t\t}\n\t\tconst firstProcessedOpSequenceNumber = this.processedOps[0].sequenceNumber;\n\t\tconst lastProcessedOpSequenceNumber =\n\t\t\tthis.processedOps[this.processedOps.length - 1].sequenceNumber;\n\n\t\tif (snapshotSequenceNumber < firstProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq number is older than our first processed op, which could mean we're fetching\n\t\t\t// the same snapshot that we already have or snapshot is too old, implicating an unexpected behavior.\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"OldSnapshotFetchWhileRefreshing\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t\tlastProcessedOpSequenceNumber,\n\t\t\t\tstashedSnapshotSequenceNumber: this.snapshotInfo?.snapshotSequenceNumber,\n\t\t\t});\n\t\t\tthis.latestSnapshot = undefined;\n\t\t\tthis.snapshotRefresher?.clearLatestSnapshot();\n\t\t\tthis.snapshotRefresher?.restartTimer();\n\t\t} else if (snapshotSequenceNumber <= lastProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq num is between the first and last processed op.\n\t\t\t// Remove the ops that are already part of the snapshot\n\t\t\tthis.processedOps.splice(0, snapshotSequenceNumber - firstProcessedOpSequenceNumber + 1);\n\t\t\tthis.snapshotInfo = this.latestSnapshot;\n\t\t\tthis.latestSnapshot = undefined;\n\t\t\tthis.snapshotRefresher?.clearLatestSnapshot();\n\t\t\tthis.snapshotRefresher?.restartTimer();\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"SnapshotRefreshed\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t\tnewFirstProcessedOpSequenceNumber:\n\t\t\t\t\tthis.processedOps.length === 0 ? undefined : this.processedOps[0].sequenceNumber,\n\t\t\t});\n\t\t}\n\t\treturn snapshotSequenceNumber;\n\t}\n\n\t/**\n\t * When the Container attaches, we need to stash the initial snapshot (a form of the attach summary).\n\t * This method is only meant to be used by Container.attach() to set the initial\n\t * base snapshot when attaching.\n\t * @param snapshot - snapshot and blobs collected while attaching (a form of the attach summary)\n\t */\n\tpublic setInitialSnapshot(snapshot: ISnapshot): void {\n\t\tthis.verifyNotDisposed();\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.snapshotInfo = {\n\t\t\t\tsnapshot,\n\t\t\t\tsnapshotSequenceNumber: snapshot.sequenceNumber ?? 0,\n\t\t\t\tsnapshotFetchedTime: Date.now(),\n\t\t\t};\n\t\t\tthis.snapshotRefresher?.startTimer();\n\t\t}\n\t}\n\n\t/**\n\t * Assembles and serializes the {@link IPendingContainerState} for the container,\n\t * to be stored and used to rehydrate the container at a later time.\n\t */\n\tpublic async getPendingLocalState(\n\t\tclientId: string | undefined,\n\t\truntime: Pick<IRuntime, \"getPendingLocalState\">,\n\t\tresolvedUrl: IResolvedUrl,\n\t): Promise<string> {\n\t\tthis.verifyNotDisposed();\n\t\tif (!this.offlineLoadEnabled) {\n\t\t\tthrow new UsageError(\"Can't get pending local state unless offline load is enabled\");\n\t\t}\n\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tthis.mc.logger,\n\t\t\t{\n\t\t\t\teventName: \"getPendingLocalState\",\n\t\t\t\tdetails: {\n\t\t\t\t\tnotifyImminentClosure: false,\n\t\t\t\t\tsessionExpiryTimerStarted: undefined,\n\t\t\t\t\tsnapshotSequenceNumber: undefined,\n\t\t\t\t\tprocessedOpsSize: this.processedOps.length,\n\t\t\t\t},\n\t\t\t\tclientId,\n\t\t\t},\n\t\t\tasync () => {\n\t\t\t\tassert(this.snapshotInfo !== undefined, 0x8e5 /* no base data */);\n\t\t\t\tconst pendingRuntimeState = await runtime.getPendingLocalState({\n\t\t\t\t\tnotifyImminentClosure: false,\n\t\t\t\t\tsnapshotSequenceNumber: this.snapshotInfo.snapshotSequenceNumber,\n\t\t\t\t\tsessionExpiryTimerStarted: this.snapshotInfo.snapshotFetchedTime,\n\t\t\t\t});\n\t\t\t\t// This conversion is required because ArrayBufferLike doesn't survive JSON.stringify\n\t\t\t\tconst loadedGroupIdSnapshots: Record<string, SerializedSnapshotInfo> = {};\n\t\t\t\tlet hasGroupIdSnapshots = false;\n\t\t\t\tconst groupIdSnapshots = Object.entries(this.storageAdapter.loadedGroupIdSnapshots);\n\t\t\t\tif (groupIdSnapshots.length > 0) {\n\t\t\t\t\tfor (const [groupId, snapshot] of groupIdSnapshots) {\n\t\t\t\t\t\thasGroupIdSnapshots = true;\n\t\t\t\t\t\tloadedGroupIdSnapshots[groupId] = convertSnapshotToSnapshotInfo(snapshot);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst snapshotWithBlobs: SnapshotWithBlobs = isInstanceOfISnapshot(\n\t\t\t\t\tthis.snapshotInfo.snapshot,\n\t\t\t\t)\n\t\t\t\t\t? convertISnapshotToSnapshotWithBlobs(this.snapshotInfo.snapshot)\n\t\t\t\t\t: await convertSnapshotTreeToSnapshotWithBlobs(\n\t\t\t\t\t\t\tthis.snapshotInfo.snapshot,\n\t\t\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t\t\t);\n\n\t\t\t\tconst pendingState: IPendingContainerState = {\n\t\t\t\t\tattached: true,\n\t\t\t\t\tpendingRuntimeState,\n\t\t\t\t\t...snapshotWithBlobs,\n\t\t\t\t\tloadedGroupIdSnapshots: hasGroupIdSnapshots ? loadedGroupIdSnapshots : undefined,\n\t\t\t\t\tsavedOps: this.processedOps,\n\t\t\t\t\turl: resolvedUrl.url,\n\t\t\t\t\tclientId,\n\t\t\t\t};\n\n\t\t\t\treturn JSON.stringify(pendingState);\n\t\t\t},\n\t\t);\n\t}\n}\n\nasync function convertSnapshotTreeToSnapshotWithBlobs(\n\tsnapshot: ISnapshotTree,\n\tstorageAdapter: ISerializedStateManagerDocumentStorageService,\n): Promise<SnapshotWithBlobs> {\n\tconst snapshotBlobs = await getBlobContentsFromTree(snapshot, storageAdapter);\n\treturn {\n\t\tbaseSnapshot: snapshot,\n\t\tsnapshotBlobs,\n\t};\n}\n\n/**\n * Retrieves the most recent snapshot and returns its info.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @returns a SnapshotInfo object containing the snapshot tree, snapshot blobs and its sequence number.\n */\nexport async function getLatestSnapshotInfo(\n\tmc: MonitoringContext,\n\tstorageAdapter: ISerializedStateManagerDocumentStorageService,\n\tsupportGetSnapshotApi: boolean,\n): Promise<ISnapshotInfo | undefined> {\n\treturn PerformanceEvent.timedExecAsync<ISnapshotInfo | undefined>(\n\t\tmc.logger,\n\t\t{ eventName: \"GetLatestSnapshotInfo\" },\n\t\tasync (event) => {\n\t\t\ttry {\n\t\t\t\t// get the latest non cached snapshot version\n\t\t\t\tconst specifiedVersion: IVersion[] = await storageAdapter.getVersions(\n\t\t\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\t\t\tnull,\n\t\t\t\t\t1,\n\t\t\t\t\t\"getLatestSnapshotInfo\",\n\t\t\t\t\tFetchSource.noCache,\n\t\t\t\t);\n\t\t\t\tconst { snapshot: baseSnapshot } = await getSnapshot(\n\t\t\t\t\tmc,\n\t\t\t\t\tstorageAdapter,\n\t\t\t\t\tsupportGetSnapshotApi,\n\t\t\t\t\tspecifiedVersion[0]?.id,\n\t\t\t\t);\n\n\t\t\t\tconst { sequenceNumber, snapshotTree } = isInstanceOfISnapshot(baseSnapshot)\n\t\t\t\t\t? baseSnapshot\n\t\t\t\t\t: { snapshotTree: baseSnapshot, sequenceNumber: undefined };\n\n\t\t\t\tconst snapshotSequenceNumber: number =\n\t\t\t\t\tsequenceNumber ??\n\t\t\t\t\t(await getDocumentAttributes(storageAdapter, snapshotTree).then(\n\t\t\t\t\t\t(a) => a.sequenceNumber,\n\t\t\t\t\t));\n\t\t\t\treturn {\n\t\t\t\t\tsnapshot: baseSnapshot,\n\t\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\t\tsnapshotFetchedTime: Date.now(),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tevent.cancel(undefined, error);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t);\n}\n\n/**\n * Retrieves a snapshot from the storage adapter and transforms it into an ISnapshotTree object.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns An ISnapshotTree and its version.\n */\nasync function getSnapshot(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<\n\t\tIDocumentStorageService,\n\t\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\"\n\t>,\n\tsupportGetSnapshotApi: boolean,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot: ISnapshot | ISnapshotTree; version?: IVersion }> {\n\tconst { snapshot, version } = supportGetSnapshotApi\n\t\t? await fetchISnapshot(mc, storageAdapter, specifiedVersion)\n\t\t: await fetchISnapshotTree(mc, storageAdapter, specifiedVersion);\n\tassert(snapshot !== undefined, 0x8e4 /* Snapshot should exist */);\n\treturn { snapshot, version };\n}\n\n/**\n * Fetches an ISnapshot from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing a getSnapshot method to retrieve the ISnapshot and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshot(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshot\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshot; version?: IVersion }> {\n\tconst snapshot = await storageAdapter.getSnapshot?.({ versionId: specifiedVersion });\n\tconst version: IVersion | undefined =\n\t\tsnapshot?.snapshotTree.id === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: snapshot.snapshotTree.id,\n\t\t\t\t\ttreeId: snapshot.snapshotTree.id,\n\t\t\t\t};\n\n\tif (snapshot === undefined && specifiedVersion !== undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotTreeFailed\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n\n/**\n * Fetches an ISnapshotTree from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the ISnapshotTree and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshotTree(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshotTree\" | \"getVersions\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {\n\t// API uses null\n\t// eslint-disable-next-line unicorn/no-null\n\tconst versions = await storageAdapter.getVersions(specifiedVersion ?? null, 1);\n\tconst version = versions[0];\n\n\tif (version === undefined && specifiedVersion !== undefined) {\n\t\t// We should have a defined version to load from if specified version requested\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"NoVersionFoundWhenSpecified\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t}\n\tconst snapshot = (await storageAdapter.getSnapshotTree(version)) ?? undefined;\n\n\tif (snapshot === undefined && version !== undefined) {\n\t\tmc.logger.sendErrorEvent({ eventName: \"getSnapshotTreeFailed\", id: version.id });\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n"]}