@fluidframework/container-loader 2.101.1 → 2.103.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 (119) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/api-report/container-loader.legacy.alpha.api.md +21 -8
  3. package/api-report/container-loader.legacy.beta.api.md +19 -6
  4. package/dist/connectionManager.d.ts +2 -2
  5. package/dist/connectionManager.d.ts.map +1 -1
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts +3 -3
  8. package/dist/connectionStateHandler.d.ts.map +1 -1
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts +15 -0
  11. package/dist/container.d.ts.map +1 -1
  12. package/dist/container.js +13 -0
  13. package/dist/container.js.map +1 -1
  14. package/dist/containerContext.d.ts +3 -3
  15. package/dist/containerContext.d.ts.map +1 -1
  16. package/dist/containerContext.js.map +1 -1
  17. package/dist/containerStorageAdapter.d.ts +2 -2
  18. package/dist/containerStorageAdapter.d.ts.map +1 -1
  19. package/dist/containerStorageAdapter.js.map +1 -1
  20. package/dist/createAndLoadContainerUtils.d.ts +111 -19
  21. package/dist/createAndLoadContainerUtils.d.ts.map +1 -1
  22. package/dist/createAndLoadContainerUtils.js +101 -19
  23. package/dist/createAndLoadContainerUtils.js.map +1 -1
  24. package/dist/debugLogger.d.ts +2 -2
  25. package/dist/debugLogger.d.ts.map +1 -1
  26. package/dist/debugLogger.js.map +1 -1
  27. package/dist/deltaManager.d.ts +2 -2
  28. package/dist/deltaManager.d.ts.map +1 -1
  29. package/dist/deltaManager.js.map +1 -1
  30. package/dist/error.d.ts +2 -2
  31. package/dist/error.d.ts.map +1 -1
  32. package/dist/error.js.map +1 -1
  33. package/dist/frozenServices.d.ts.map +1 -1
  34. package/dist/frozenServices.js +15 -2
  35. package/dist/frozenServices.js.map +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/legacy.d.ts +3 -0
  40. package/dist/legacyAlpha.d.ts +3 -0
  41. package/dist/loaderLayerCompatState.d.ts +2 -2
  42. package/dist/packageVersion.d.ts +1 -1
  43. package/dist/packageVersion.js +1 -1
  44. package/dist/packageVersion.js.map +1 -1
  45. package/dist/retriableDocumentStorageService.d.ts +2 -2
  46. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  47. package/dist/retriableDocumentStorageService.js.map +1 -1
  48. package/dist/snapshotRefresher.d.ts.map +1 -1
  49. package/dist/snapshotRefresher.js +1 -2
  50. package/dist/snapshotRefresher.js.map +1 -1
  51. package/dist/utils.d.ts.map +1 -1
  52. package/dist/utils.js +13 -1
  53. package/dist/utils.js.map +1 -1
  54. package/lib/connectionManager.d.ts +2 -2
  55. package/lib/connectionManager.d.ts.map +1 -1
  56. package/lib/connectionManager.js.map +1 -1
  57. package/lib/connectionStateHandler.d.ts +3 -3
  58. package/lib/connectionStateHandler.d.ts.map +1 -1
  59. package/lib/connectionStateHandler.js.map +1 -1
  60. package/lib/container.d.ts +15 -0
  61. package/lib/container.d.ts.map +1 -1
  62. package/lib/container.js +13 -0
  63. package/lib/container.js.map +1 -1
  64. package/lib/containerContext.d.ts +3 -3
  65. package/lib/containerContext.d.ts.map +1 -1
  66. package/lib/containerContext.js.map +1 -1
  67. package/lib/containerStorageAdapter.d.ts +2 -2
  68. package/lib/containerStorageAdapter.d.ts.map +1 -1
  69. package/lib/containerStorageAdapter.js.map +1 -1
  70. package/lib/createAndLoadContainerUtils.d.ts +111 -19
  71. package/lib/createAndLoadContainerUtils.d.ts.map +1 -1
  72. package/lib/createAndLoadContainerUtils.js +85 -3
  73. package/lib/createAndLoadContainerUtils.js.map +1 -1
  74. package/lib/debugLogger.d.ts +2 -2
  75. package/lib/debugLogger.d.ts.map +1 -1
  76. package/lib/debugLogger.js.map +1 -1
  77. package/lib/deltaManager.d.ts +2 -2
  78. package/lib/deltaManager.d.ts.map +1 -1
  79. package/lib/deltaManager.js.map +1 -1
  80. package/lib/error.d.ts +2 -2
  81. package/lib/error.d.ts.map +1 -1
  82. package/lib/error.js.map +1 -1
  83. package/lib/frozenServices.d.ts.map +1 -1
  84. package/lib/frozenServices.js +15 -2
  85. package/lib/frozenServices.js.map +1 -1
  86. package/lib/index.d.ts +1 -1
  87. package/lib/index.d.ts.map +1 -1
  88. package/lib/index.js.map +1 -1
  89. package/lib/legacy.d.ts +3 -0
  90. package/lib/legacyAlpha.d.ts +3 -0
  91. package/lib/loaderLayerCompatState.d.ts +2 -2
  92. package/lib/packageVersion.d.ts +1 -1
  93. package/lib/packageVersion.js +1 -1
  94. package/lib/packageVersion.js.map +1 -1
  95. package/lib/retriableDocumentStorageService.d.ts +2 -2
  96. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  97. package/lib/retriableDocumentStorageService.js.map +1 -1
  98. package/lib/snapshotRefresher.d.ts.map +1 -1
  99. package/lib/snapshotRefresher.js +1 -2
  100. package/lib/snapshotRefresher.js.map +1 -1
  101. package/lib/utils.d.ts.map +1 -1
  102. package/lib/utils.js +13 -1
  103. package/lib/utils.js.map +1 -1
  104. package/package.json +12 -12
  105. package/src/connectionManager.ts +2 -2
  106. package/src/connectionStateHandler.ts +3 -3
  107. package/src/container.ts +22 -0
  108. package/src/containerContext.ts +3 -3
  109. package/src/containerStorageAdapter.ts +3 -3
  110. package/src/createAndLoadContainerUtils.ts +227 -24
  111. package/src/debugLogger.ts +2 -2
  112. package/src/deltaManager.ts +3 -3
  113. package/src/error.ts +2 -2
  114. package/src/frozenServices.ts +18 -2
  115. package/src/index.ts +3 -0
  116. package/src/packageVersion.ts +1 -1
  117. package/src/retriableDocumentStorageService.ts +2 -2
  118. package/src/snapshotRefresher.ts +1 -2
  119. package/src/utils.ts +12 -1
@@ -1 +1 @@
1
- {"version":3,"file":"frozenServices.js","sourceRoot":"","sources":["../src/frozenServices.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { isPromiseLike } from \"@fluidframework/core-utils/internal\";\nimport {\n\tScopeType,\n\ttype ConnectionMode,\n\ttype IClient,\n\ttype IClientConfiguration,\n\ttype IDocumentDeltaConnection,\n\ttype IDocumentDeltaConnectionEvents,\n\ttype IDocumentDeltaStorageService,\n\ttype IDocumentMessage,\n\ttype IDocumentService,\n\ttype IDocumentServiceEvents,\n\ttype IDocumentServiceFactory,\n\ttype IDocumentServicePolicies,\n\ttype IDocumentStorageService,\n\ttype IResolvedUrl,\n\ttype ISequencedDocumentMessage,\n\ttype ISignalClient,\n\ttype ISignalMessage,\n\ttype ITokenClaims,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IConnectionStateChangeReason } from \"./contracts.js\";\n\n/**\n * Creates an `IDocumentServiceFactory` that produces a \"frozen\" document service: one whose\n * delta stream never sends or receives ops, and whose storage service only supports\n * `IDocumentStorageService.readBlob`. Used to load a container from pending local state\n * without re-establishing a live connection.\n *\n * @param factory - The underlying factory to wrap. Its storage backs blob reads; all other\n * storage operations throw. May be omitted when blob fetches are not required.\n * @param readOnly - When `true` (the default), the document service advertises the\n * `IDocumentServicePolicies.storageOnly` policy, which causes the loader to surface the\n * container as read-only (see `IContainer.readOnlyInfo`).\n *\n * When `false`, the container is loaded as writable so the runtime will accept DDS submissions.\n * The connection itself stays `Connected`: `ConnectionManager.sendMessages` recognizes the\n * `WritableFrozenDeltaStream` as the live connection and short-circuits — the message is dropped\n * at the network layer rather than triggering a read→write reconnect. Local DDS state continues\n * to update via optimistic apply, and submitted ops accumulate in the runtime's pending-state\n * manager, which is exactly the state needed to capture pending local state. Use `false` when\n * callers want to accrue and capture pending state without publishing it.\n * @returns A factory that produces frozen document services.\n * @legacy @alpha\n */\nexport function createFrozenDocumentServiceFactory(\n\tfactory?: IDocumentServiceFactory | Promise<IDocumentServiceFactory>,\n\treadOnly: boolean = true,\n): IDocumentServiceFactory {\n\tif (factory instanceof FrozenDocumentServiceFactory) {\n\t\t// Already wrapped. Reuse if readOnly matches; otherwise unwrap and rewrap so the caller's\n\t\t// most recent readOnly intent wins (silently honoring caller intent rather than dropping\n\t\t// the new argument).\n\t\treturn factory.readOnly === readOnly\n\t\t\t? factory\n\t\t\t: new FrozenDocumentServiceFactory(readOnly, factory.inner);\n\t}\n\treturn new FrozenDocumentServiceFactory(readOnly, factory);\n}\n\nexport class FrozenDocumentServiceFactory implements IDocumentServiceFactory {\n\tconstructor(\n\t\tpublic readonly readOnly: boolean,\n\t\tpublic readonly inner?: IDocumentServiceFactory | Promise<IDocumentServiceFactory>,\n\t) {}\n\n\tasync createDocumentService(resolvedUrl: IResolvedUrl): Promise<IDocumentService> {\n\t\tconst factory = isPromiseLike(this.inner) ? await this.inner : this.inner;\n\t\treturn new FrozenDocumentService(\n\t\t\tresolvedUrl,\n\t\t\tthis.readOnly,\n\t\t\tawait factory?.createDocumentService(resolvedUrl),\n\t\t);\n\t}\n\tasync createContainer(): Promise<IDocumentService> {\n\t\tthrow new Error(\"The FrozenDocumentServiceFactory cannot be used to create containers.\");\n\t}\n}\n\nclass FrozenDocumentService\n\textends TypedEventEmitter<IDocumentServiceEvents>\n\timplements IDocumentService\n{\n\t// Tracks every storage instance handed out by `connectToStorage` so `dispose()` can cascade\n\t// disposal to each one (rejecting their hanging `createBlob` deferreds). A Set rather than\n\t// a single field because `IDocumentService.connectToStorage` is a public API that can be\n\t// called more than once — we cannot assume the Container holds a single instance.\n\tprivate readonly storageServices = new Set<FrozenDocumentStorageService>();\n\n\tconstructor(\n\t\tpublic readonly resolvedUrl: IResolvedUrl,\n\t\tprivate readonly readOnly: boolean,\n\t\tprivate readonly documentService?: IDocumentService,\n\t) {\n\t\tsuper();\n\t\t// When readOnly, advertise the storageOnly policy. The connectionManager short-circuits\n\t\t// on it: it synthesizes a FrozenDeltaStream itself and never calls\n\t\t// connectToDeltaStream, and the readOnlyInfo getter forces the container to read-only\n\t\t// because the live connection is a FrozenDeltaStream.\n\t\t//\n\t\t// Audit (2026-05-05): the only consumer of `policies.storageOnly` as a frozen-container\n\t\t// signal is `ConnectionManager` (synthesizing a `FrozenDeltaStream` when set). All other\n\t\t// matches in the loader/runtime/driver layers are either drivers reading their own\n\t\t// policies (e.g. local-driver) or `IReadOnlyInfo.storageOnly`, which is derived from the\n\t\t// live connection — not the policy. So the writable-frozen container is intentionally\n\t\t// indistinguishable from a normal container at the policies layer; downstream behavior\n\t\t// flows through the live `WritableFrozenDeltaStream` instead.\n\t\tthis.policies = readOnly ? { storageOnly: true } : {};\n\t}\n\n\tpublic readonly policies: IDocumentServicePolicies;\n\tasync connectToStorage(): Promise<IDocumentStorageService> {\n\t\tconst storage = new FrozenDocumentStorageService(\n\t\t\tthis.readOnly,\n\t\t\tawait this.documentService?.connectToStorage(),\n\t\t);\n\t\tthis.storageServices.add(storage);\n\t\treturn storage;\n\t}\n\tasync connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n\t\treturn frozenDocumentDeltaStorageService;\n\t}\n\tasync connectToDeltaStream(_client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tif (this.readOnly) {\n\t\t\t// connectionManager short-circuits via policies.storageOnly before reaching here\n\t\t\t// in the read-only path; reaching this branch indicates a non-connectionManager\n\t\t\t// consumer or a regression of the short-circuit. Throw to surface the misuse\n\t\t\t// rather than silently produce a working stream.\n\t\t\tthrow new Error(\n\t\t\t\t\"FrozenDocumentService is read-only; connectToDeltaStream should not be called (connectionManager short-circuits via policies.storageOnly)\",\n\t\t\t);\n\t\t}\n\t\t// Writable path: hand out a fresh WritableFrozenDeltaStream regardless of client.mode\n\t\t// or whether this is the initial connect or a reconnect. The stream's own mode is\n\t\t// \"read\" (advertising \"write\" would imply quorum membership we cannot honor), and\n\t\t// `ConnectionManager.sendMessages` short-circuits on WritableFrozenDeltaStream so\n\t\t// outbound writes never reach a real network. The per-instance clientId minted in\n\t\t// FrozenDeltaStreamBase prevents pendingStateManager 0x173 on replay across reconnects.\n\t\treturn new WritableFrozenDeltaStream();\n\t}\n\tdispose(error?: unknown): void {\n\t\t// Cascade disposal to each storage instance so any hanging `createBlob` promises (the\n\t\t// writable-frozen pending-blob mechanism) reject and the BlobManager can release its\n\t\t// references. Without this, hung promises remain held by BlobManager closures for the\n\t\t// lifetime of the process.\n\t\tfor (const storage of this.storageServices) {\n\t\t\tstorage.dispose();\n\t\t}\n\t\tthis.storageServices.clear();\n\t\t// Forward disposal to the wrapped service. We own its lifetime (it was created for us\n\t\t// by the wrapping factory and is never exposed to callers), so the contract from\n\t\t// `IDocumentService.dispose` (\"called by storage consumer when done with storage\")\n\t\t// applies here.\n\t\tthis.documentService?.dispose(error);\n\t}\n}\n\nconst frozenDocumentStorageServiceHandler = (): never => {\n\tthrow new Error(\"Operations are not supported on the FrozenDocumentStorageService.\");\n};\n\nclass FrozenDocumentStorageService implements IDocumentStorageService, IDisposable {\n\t// Single deferred shared by every in-flight `createBlob` call. The writable-frozen\n\t// `createBlob` returns this promise so the BlobManager keeps the blob in `uploading`\n\t// state (see comment in the constructor). Rejecting the deferred on disposal fans the\n\t// rejection out to every awaiter at once — and to any future `createBlob` calls too,\n\t// since they receive the already-rejected promise.\n\tprivate readonly disposalDeferred: {\n\t\treadonly promise: Promise<never>;\n\t\treadonly reject: (error: Error) => void;\n\t};\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\n\tconstructor(\n\t\treadOnly: boolean,\n\t\tprivate readonly documentStorageService?: IDocumentStorageService,\n\t) {\n\t\tlet rejectFn!: (error: Error) => void;\n\t\tconst promise = new Promise<never>((_, reject) => {\n\t\t\trejectFn = reject;\n\t\t});\n\t\t// Attach a no-op catch so node doesn't log an unhandled-rejection warning when\n\t\t// dispose runs before any caller has awaited the promise. Callers awaiting the\n\t\t// original promise still observe the rejection.\n\t\tpromise.catch(() => {});\n\t\tthis.disposalDeferred = { promise, reject: rejectFn };\n\n\t\t// In the writable-frozen path, `createBlob` returns a never-resolving promise instead\n\t\t// of throwing. This keeps the BlobManager's `localBlobCache` entry in the `uploading`\n\t\t// state: `getPendingBlobs` downgrades `uploading` blobs to `localOnly` in pending\n\t\t// state, so the blob survives `getPendingLocalState`. A subsequent live load runs\n\t\t// `sharePendingBlobs`, which re-enters `uploadAndAttach` against the real storage to\n\t\t// complete the upload. Throwing here would instead delete the cache entry (in\n\t\t// `uploadAndAttach`'s catch handler) and lose the blob — defeating the whole point of\n\t\t// accruing pending state.\n\t\tthis.createBlob = readOnly\n\t\t\t? frozenDocumentStorageServiceHandler\n\t\t\t: async () => this.disposalDeferred.promise;\n\t}\n\n\tgetSnapshotTree = frozenDocumentStorageServiceHandler;\n\tgetSnapshot = frozenDocumentStorageServiceHandler;\n\tgetVersions = frozenDocumentStorageServiceHandler;\n\tcreateBlob: IDocumentStorageService[\"createBlob\"];\n\treadBlob =\n\t\tthis.documentStorageService?.readBlob.bind(this.documentStorageService) ??\n\t\tfrozenDocumentStorageServiceHandler;\n\tuploadSummaryWithContext = frozenDocumentStorageServiceHandler;\n\tdownloadSummary = frozenDocumentStorageServiceHandler;\n\n\tpublic dispose(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposed = true;\n\t\t// Don't propagate any caller-supplied error here. `IDocumentService.dispose` already\n\t\t// logs the Container's error path; the createBlob deferred's consumer (BlobManager)\n\t\t// only needs the \"this storage is going away\" signal — not a chain of error causes.\n\t\tthis.disposalDeferred.reject(new Error(\"FrozenDocumentStorageService is disposed\"));\n\t}\n}\n\nconst frozenDocumentDeltaStorageService: IDocumentDeltaStorageService = {\n\tfetchMessages: () => ({\n\t\tread: async () => ({\n\t\t\tdone: true,\n\t\t}),\n\t}),\n};\n\nconst clientFrozenDeltaStream: IClient = {\n\tmode: \"read\",\n\tdetails: { capabilities: { interactive: true } },\n\tpermission: [],\n\tuser: { id: \"storage-only client\" }, // we need some \"fake\" ID here.\n\tscopes: [],\n};\n\nconst clientIdFrozenDeltaStream: string = \"storage-only client\";\n\n// Cast rationale: ITokenClaims requires tenantId/documentId/user/iat/exp/ver, but a frozen\n// delta stream has no tenant or session to draw real values from — it's a synthetic\n// in-process connection that never reaches a service. Inventing sentinel values would imply\n// quorum membership we cannot honor; only `scopes` actually drives behavior here (DocRead vs\n// DocWrite gates readOnlyInfo). The cast is the honest representation of \"this connection\n// has no claims worth populating.\"\n/* eslint-disable @typescript-eslint/consistent-type-assertions */\nconst readOnlyClaims: ITokenClaims = { scopes: [ScopeType.DocRead] } as ITokenClaims;\nconst writableClaims: ITokenClaims = {\n\tscopes: [ScopeType.DocRead, ScopeType.DocWrite],\n} as ITokenClaims;\n/* eslint-enable @typescript-eslint/consistent-type-assertions */\n\n/**\n * Inert `IDocumentDeltaConnection` for frozen container loads. Has no server upstream:\n * op and signal streams are empty, and `initialClients` contains only its own synthetic\n * read-only client — which lets the connection state handler observe \"self\" in the audience\n * and transition the container to Connected without waiting for a real join op or signal.\n *\n * Two concrete variants share this base — see their JSDoc for variant-specific details:\n *\n * - {@link FrozenDeltaStream} — read-only.\n * - {@link WritableFrozenDeltaStream} — writable.\n *\n * Both variants nack any incoming `submit`: this connection has no upstream and\n * `ConnectionManager.sendMessages` recognizes `WritableFrozenDeltaStream` and drops messages\n * before they reach `submit`, so under normal flow it should never fire. A nack reaching the\n * connectionManager surfaces the misuse — and may close the container — which is the right\n * defensive signal that something has bypassed the expected flow.\n *\n * `submitSignal` is a silent no-op for both variants. Signals are ephemeral and best-effort —\n * runtime/presence subsystems may submit them at any point in the writable-frozen lifetime, and\n * dropping them is the correct behavior here (we have no upstream). Closing the container or\n * triggering a reconnect on a stray signal would be strictly worse than dropping it.\n */\nabstract class FrozenDeltaStreamBase\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\tpublic readonly clientId: string;\n\tpublic readonly claims: ITokenClaims;\n\tpublic readonly initialClients: ISignalClient[];\n\tpublic readonly mode: ConnectionMode = \"read\";\n\tpublic readonly existing: boolean = true;\n\tpublic readonly maxMessageSize: number = 0;\n\tpublic readonly version: string = \"\";\n\tpublic readonly initialMessages: ISequencedDocumentMessage[] = [];\n\tpublic readonly initialSignals: ISignalMessage[] = [];\n\tpublic readonly serviceConfiguration: IClientConfiguration = {\n\t\tmaxMessageSize: 0,\n\t\tblockSize: 0,\n\t};\n\tpublic readonly checkpointSequenceNumber?: number | undefined = undefined;\n\n\tconstructor(clientId: string, claims: ITokenClaims) {\n\t\tsuper();\n\t\tthis.clientId = clientId;\n\t\tthis.claims = claims;\n\t\t// initialClients mirrors clientId so the audience handler observes \"self\" and\n\t\t// transitions the container to Connected without waiting for a real join op or signal.\n\t\tthis.initialClients = [{ client: clientFrozenDeltaStream, clientId }];\n\t}\n\n\tsubmit(messages: IDocumentMessage[]): void {\n\t\t// Defensive nack: nothing should send on a frozen delta stream. If this fires, an\n\t\t// invariant in connectionManager has changed and we want it to surface loudly.\n\t\tthis.emit(\n\t\t\t\"nack\",\n\t\t\tthis.clientId,\n\t\t\tmessages.map((operation) => ({\n\t\t\t\toperation,\n\t\t\t\tcontent: { message: \"Cannot submit on a frozen delta stream\", code: 403 },\n\t\t\t})),\n\t\t);\n\t}\n\n\tsubmitSignal(_message: unknown): void {\n\t\t// Intentional no-op. See class JSDoc for rationale.\n\t}\n\n\tprivate _disposed = false;\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\n/**\n * Read-only variant of {@link FrozenDeltaStreamBase}. Claims show only `DocRead`. Used by\n * storage-only loads (where `connectionManager` synthesizes one directly via\n * `policies.storageOnly`) and by the forbidden / out-of-storage fallback paths.\n * {@link isFrozenDeltaStreamConnection} matches this variant and drives the read-only forcing\n * in `ConnectionManager.readOnlyInfo`. Uses the historical `\"storage-only client\"` constant\n * `clientId`, preserving existing behavior for any consumer that keys off it.\n *\n * `storageOnlyReason` and `readonlyConnectionReason` are surfaced through `IContainer.readOnlyInfo`\n * for diagnostics on the fallback paths (`isDeltaStreamConnectionForbiddenError`,\n * `outOfStorageError`).\n */\nexport class FrozenDeltaStream extends FrozenDeltaStreamBase {\n\tpublic readonly storageOnlyReason: string | undefined;\n\tpublic readonly readonlyConnectionReason: IConnectionStateChangeReason | undefined;\n\n\tconstructor(options?: {\n\t\tstorageOnlyReason?: string;\n\t\treadonlyConnectionReason?: IConnectionStateChangeReason;\n\t}) {\n\t\t// Constant clientId: preserves the pre-PR `\"storage-only client\"` identity for any\n\t\t// consumer that keys off it. The 0x173 replay-assert risk that motivates per-instance\n\t\t// clientIds applies only to the writable variant, where the runtime accumulates dirty\n\t\t// pending ops across reconnects; the read-only variant does not.\n\t\tsuper(clientIdFrozenDeltaStream, readOnlyClaims);\n\t\tthis.storageOnlyReason = options?.storageOnlyReason;\n\t\tthis.readonlyConnectionReason = options?.readonlyConnectionReason;\n\t}\n}\n\n/**\n * Variant of {@link FrozenDeltaStreamBase} that appears to support writing but remains\n * \"frozen\" — no messages are actually sent or received. The stream itself does not enforce\n * the no-send guarantee; that lives in `ConnectionManager.sendMessages`, which recognizes\n * any `WritableFrozenDeltaStream` (via {@link isWritableFrozenDeltaStreamConnection}) and\n * short-circuits before its read-mode upgrade branch. Submitted ops are dropped at the\n * connection-manager layer, so the container stays `Connected` and the runtime accumulates\n * them in `pendingStateManager`.\n *\n * \"Appears writable\" mechanics: claims include `DocWrite` so the container surfaces as\n * writable; not matched by {@link isFrozenDeltaStreamConnection}, so `readOnlyInfo` reports\n * `readonly: false`. Connection mode stays `\"read\"` (advertising `\"write\"` would imply quorum\n * membership we cannot honor).\n *\n * Each instance mints a fresh `frozen-delta-stream/<uuid>` `clientId` to avoid\n * `pendingStateManager` `0x173` (`replayPendingStates called twice for same clientId!`) on\n * reconnect with dirty pending ops. Sibling (not subclass) of `FrozenDeltaStream` so\n * `instanceof` cleanly distinguishes the two for `ConnectionManager`'s short-circuits.\n */\nexport class WritableFrozenDeltaStream extends FrozenDeltaStreamBase {\n\tconstructor() {\n\t\tsuper(`frozen-delta-stream/${uuid()}`, writableClaims);\n\t}\n}\n\n/**\n * Recognizes the read-only variant of {@link FrozenDeltaStreamBase}. Drives the storage-only\n * forcing in `ConnectionManager.readOnlyInfo`: only the read-only variant should make the\n * container surface as read-only. {@link WritableFrozenDeltaStream} is a sibling class, not\n * a subclass, so `instanceof FrozenDeltaStream` already excludes it.\n */\nexport function isFrozenDeltaStreamConnection(\n\tconnection: unknown,\n): connection is FrozenDeltaStream {\n\treturn connection instanceof FrozenDeltaStream;\n}\n\n/**\n * Recognizes the writable variant of {@link FrozenDeltaStreamBase}. Drives the\n * `ConnectionManager.sendMessages` short-circuit: writable-frozen submits must be dropped at\n * the network layer instead of triggering a read→write reconnect. Sibling (not subclass) of\n * {@link FrozenDeltaStream}, so `instanceof WritableFrozenDeltaStream` excludes the read-only\n * variant.\n */\nexport function isWritableFrozenDeltaStreamConnection(\n\tconnection: unknown,\n): connection is WritableFrozenDeltaStream {\n\treturn connection instanceof WritableFrozenDeltaStream;\n}\n"]}
1
+ {"version":3,"file":"frozenServices.js","sourceRoot":"","sources":["../src/frozenServices.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { isPromiseLike } from \"@fluidframework/core-utils/internal\";\nimport {\n\tScopeType,\n\ttype ConnectionMode,\n\ttype IClient,\n\ttype IClientConfiguration,\n\ttype IDocumentDeltaConnection,\n\ttype IDocumentDeltaConnectionEvents,\n\ttype IDocumentDeltaStorageService,\n\ttype IDocumentMessage,\n\ttype IDocumentService,\n\ttype IDocumentServiceEvents,\n\ttype IDocumentServiceFactory,\n\ttype IDocumentServicePolicies,\n\ttype IDocumentStorageService,\n\ttype IResolvedUrl,\n\ttype ISequencedDocumentMessage,\n\ttype ISignalClient,\n\ttype ISignalMessage,\n\ttype ITokenClaims,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { IConnectionStateChangeReason } from \"./contracts.js\";\n\n/**\n * Creates an `IDocumentServiceFactory` that produces a \"frozen\" document service: one whose\n * delta stream never sends or receives ops, and whose storage service only supports\n * `IDocumentStorageService.readBlob`. Used to load a container from pending local state\n * without re-establishing a live connection.\n *\n * @param factory - The underlying factory to wrap. Its storage backs blob reads; all other\n * storage operations throw. May be omitted when blob fetches are not required.\n * @param readOnly - When `true` (the default), the document service advertises the\n * `IDocumentServicePolicies.storageOnly` policy, which causes the loader to surface the\n * container as read-only (see `IContainer.readOnlyInfo`).\n *\n * When `false`, the container is loaded as writable so the runtime will accept DDS submissions.\n * The connection itself stays `Connected`: `ConnectionManager.sendMessages` recognizes the\n * `WritableFrozenDeltaStream` as the live connection and short-circuits — the message is dropped\n * at the network layer rather than triggering a read→write reconnect. Local DDS state continues\n * to update via optimistic apply, and submitted ops accumulate in the runtime's pending-state\n * manager, which is exactly the state needed to capture pending local state. Use `false` when\n * callers want to accrue and capture pending state without publishing it.\n * @returns A factory that produces frozen document services.\n * @legacy @alpha\n */\nexport function createFrozenDocumentServiceFactory(\n\tfactory?: IDocumentServiceFactory | Promise<IDocumentServiceFactory>,\n\treadOnly: boolean = true,\n): IDocumentServiceFactory {\n\tif (factory instanceof FrozenDocumentServiceFactory) {\n\t\t// Already wrapped. Reuse if readOnly matches; otherwise unwrap and rewrap so the caller's\n\t\t// most recent readOnly intent wins (silently honoring caller intent rather than dropping\n\t\t// the new argument).\n\t\treturn factory.readOnly === readOnly\n\t\t\t? factory\n\t\t\t: new FrozenDocumentServiceFactory(readOnly, factory.inner);\n\t}\n\treturn new FrozenDocumentServiceFactory(readOnly, factory);\n}\n\nexport class FrozenDocumentServiceFactory implements IDocumentServiceFactory {\n\tconstructor(\n\t\tpublic readonly readOnly: boolean,\n\t\tpublic readonly inner?: IDocumentServiceFactory | Promise<IDocumentServiceFactory>,\n\t) {}\n\n\tasync createDocumentService(resolvedUrl: IResolvedUrl): Promise<IDocumentService> {\n\t\tconst factory = isPromiseLike(this.inner) ? await this.inner : this.inner;\n\t\treturn new FrozenDocumentService(\n\t\t\tresolvedUrl,\n\t\t\tthis.readOnly,\n\t\t\tawait factory?.createDocumentService(resolvedUrl),\n\t\t);\n\t}\n\tasync createContainer(): Promise<IDocumentService> {\n\t\tthrow new Error(\"The FrozenDocumentServiceFactory cannot be used to create containers.\");\n\t}\n}\n\nclass FrozenDocumentService\n\textends TypedEventEmitter<IDocumentServiceEvents>\n\timplements IDocumentService\n{\n\t// Tracks every storage instance handed out by `connectToStorage` so `dispose()` can cascade\n\t// disposal to each one (rejecting their hanging `createBlob` deferreds). A Set rather than\n\t// a single field because `IDocumentService.connectToStorage` is a public API that can be\n\t// called more than once — we cannot assume the Container holds a single instance.\n\tprivate readonly storageServices = new Set<FrozenDocumentStorageService>();\n\n\tconstructor(\n\t\tpublic readonly resolvedUrl: IResolvedUrl,\n\t\tprivate readonly readOnly: boolean,\n\t\tprivate readonly documentService?: IDocumentService,\n\t) {\n\t\tsuper();\n\t\t// When readOnly, advertise the storageOnly policy. The connectionManager short-circuits\n\t\t// on it: it synthesizes a FrozenDeltaStream itself and never calls\n\t\t// connectToDeltaStream, and the readOnlyInfo getter forces the container to read-only\n\t\t// because the live connection is a FrozenDeltaStream.\n\t\t//\n\t\t// Audit (2026-05-05): the only consumer of `policies.storageOnly` as a frozen-container\n\t\t// signal is `ConnectionManager` (synthesizing a `FrozenDeltaStream` when set). All other\n\t\t// matches in the loader/runtime/driver layers are either drivers reading their own\n\t\t// policies (e.g. local-driver) or `IReadOnlyInfo.storageOnly`, which is derived from the\n\t\t// live connection — not the policy. So the writable-frozen container is intentionally\n\t\t// indistinguishable from a normal container at the policies layer; downstream behavior\n\t\t// flows through the live `WritableFrozenDeltaStream` instead.\n\t\tthis.policies = readOnly ? { storageOnly: true } : {};\n\t}\n\n\tpublic readonly policies: IDocumentServicePolicies;\n\tasync connectToStorage(): Promise<IDocumentStorageService> {\n\t\tconst storage = new FrozenDocumentStorageService(\n\t\t\tthis.readOnly,\n\t\t\tawait this.documentService?.connectToStorage(),\n\t\t);\n\t\tthis.storageServices.add(storage);\n\t\treturn storage;\n\t}\n\tasync connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n\t\treturn frozenDocumentDeltaStorageService;\n\t}\n\tasync connectToDeltaStream(_client: IClient): Promise<IDocumentDeltaConnection> {\n\t\tif (this.readOnly) {\n\t\t\t// connectionManager short-circuits via policies.storageOnly before reaching here\n\t\t\t// in the read-only path; reaching this branch indicates a non-connectionManager\n\t\t\t// consumer or a regression of the short-circuit. Throw to surface the misuse\n\t\t\t// rather than silently produce a working stream.\n\t\t\tthrow new Error(\n\t\t\t\t\"FrozenDocumentService is read-only; connectToDeltaStream should not be called (connectionManager short-circuits via policies.storageOnly)\",\n\t\t\t);\n\t\t}\n\t\t// Writable path: hand out a fresh WritableFrozenDeltaStream regardless of client.mode\n\t\t// or whether this is the initial connect or a reconnect. The stream's own mode is\n\t\t// \"read\" (advertising \"write\" would imply quorum membership we cannot honor), and\n\t\t// `ConnectionManager.sendMessages` short-circuits on WritableFrozenDeltaStream so\n\t\t// outbound writes never reach a real network. The per-instance clientId minted in\n\t\t// FrozenDeltaStreamBase prevents pendingStateManager 0x173 on replay across reconnects.\n\t\treturn new WritableFrozenDeltaStream();\n\t}\n\tdispose(error?: unknown): void {\n\t\t// Cascade disposal to each storage instance so any hanging `createBlob` promises (the\n\t\t// writable-frozen pending-blob mechanism) reject and the BlobManager can release its\n\t\t// references. Without this, hung promises remain held by BlobManager closures for the\n\t\t// lifetime of the process.\n\t\tfor (const storage of this.storageServices) {\n\t\t\tstorage.dispose();\n\t\t}\n\t\tthis.storageServices.clear();\n\t\t// Forward disposal to the wrapped service. We own its lifetime (it was created for us\n\t\t// by the wrapping factory and is never exposed to callers), so the contract from\n\t\t// `IDocumentService.dispose` (\"called by storage consumer when done with storage\")\n\t\t// applies here.\n\t\tthis.documentService?.dispose(error);\n\t}\n}\n\nconst frozenDocumentStorageServiceHandler = (): never => {\n\tthrow new UsageError(\"Operations are not supported on the FrozenDocumentStorageService.\");\n};\n\n/**\n * Distinct from {@link frozenDocumentStorageServiceHandler} because callers\n * that hit this path are almost always exercising a fully-offline frozen load\n * whose pending state was produced by {@link getPendingLocalState} (which omits\n * inlined attachment blobs) rather than {@link captureFullContainerState}. A\n * generic \"operation not supported\" is technically true but unhelpful; this\n * message names the missing precondition and the API that produces it.\n */\nconst frozenReadBlobOfflineHandler = async (): Promise<never> => {\n\tthrow new UsageError(\n\t\t\"Attempted to read an attachment blob from a frozen-loaded container without a live storage service. \" +\n\t\t\t\"Fully-offline frozen loads must use pending state produced by `captureFullContainerState`, which inlines all referenced attachment blobs.\",\n\t);\n};\n\nclass FrozenDocumentStorageService implements IDocumentStorageService, IDisposable {\n\t// Single deferred shared by every in-flight `createBlob` call. The writable-frozen\n\t// `createBlob` returns this promise so the BlobManager keeps the blob in `uploading`\n\t// state (see comment in the constructor). Rejecting the deferred on disposal fans the\n\t// rejection out to every awaiter at once — and to any future `createBlob` calls too,\n\t// since they receive the already-rejected promise.\n\tprivate readonly disposalDeferred: {\n\t\treadonly promise: Promise<never>;\n\t\treadonly reject: (error: Error) => void;\n\t};\n\n\tprivate _disposed = false;\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\n\n\tconstructor(\n\t\treadOnly: boolean,\n\t\tprivate readonly documentStorageService?: IDocumentStorageService,\n\t) {\n\t\tlet rejectFn!: (error: Error) => void;\n\t\tconst promise = new Promise<never>((_, reject) => {\n\t\t\trejectFn = reject;\n\t\t});\n\t\t// Attach a no-op catch so node doesn't log an unhandled-rejection warning when\n\t\t// dispose runs before any caller has awaited the promise. Callers awaiting the\n\t\t// original promise still observe the rejection.\n\t\tpromise.catch(() => {});\n\t\tthis.disposalDeferred = { promise, reject: rejectFn };\n\n\t\t// In the writable-frozen path, `createBlob` returns a never-resolving promise instead\n\t\t// of throwing. This keeps the BlobManager's `localBlobCache` entry in the `uploading`\n\t\t// state: `getPendingBlobs` downgrades `uploading` blobs to `localOnly` in pending\n\t\t// state, so the blob survives `getPendingLocalState`. A subsequent live load runs\n\t\t// `sharePendingBlobs`, which re-enters `uploadAndAttach` against the real storage to\n\t\t// complete the upload. Throwing here would instead delete the cache entry (in\n\t\t// `uploadAndAttach`'s catch handler) and lose the blob — defeating the whole point of\n\t\t// accruing pending state.\n\t\tthis.createBlob = readOnly\n\t\t\t? frozenDocumentStorageServiceHandler\n\t\t\t: async () => this.disposalDeferred.promise;\n\t}\n\n\tgetSnapshotTree = frozenDocumentStorageServiceHandler;\n\tgetSnapshot = frozenDocumentStorageServiceHandler;\n\tgetVersions = frozenDocumentStorageServiceHandler;\n\tcreateBlob: IDocumentStorageService[\"createBlob\"];\n\treadBlob =\n\t\tthis.documentStorageService?.readBlob.bind(this.documentStorageService) ??\n\t\tfrozenReadBlobOfflineHandler;\n\tuploadSummaryWithContext = frozenDocumentStorageServiceHandler;\n\tdownloadSummary = frozenDocumentStorageServiceHandler;\n\n\tpublic dispose(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposed = true;\n\t\t// Don't propagate any caller-supplied error here. `IDocumentService.dispose` already\n\t\t// logs the Container's error path; the createBlob deferred's consumer (BlobManager)\n\t\t// only needs the \"this storage is going away\" signal — not a chain of error causes.\n\t\tthis.disposalDeferred.reject(new Error(\"FrozenDocumentStorageService is disposed\"));\n\t}\n}\n\nconst frozenDocumentDeltaStorageService: IDocumentDeltaStorageService = {\n\tfetchMessages: () => ({\n\t\tread: async () => ({\n\t\t\tdone: true,\n\t\t}),\n\t}),\n};\n\nconst clientFrozenDeltaStream: IClient = {\n\tmode: \"read\",\n\tdetails: { capabilities: { interactive: true } },\n\tpermission: [],\n\tuser: { id: \"storage-only client\" }, // we need some \"fake\" ID here.\n\tscopes: [],\n};\n\nconst clientIdFrozenDeltaStream: string = \"storage-only client\";\n\n// Cast rationale: ITokenClaims requires tenantId/documentId/user/iat/exp/ver, but a frozen\n// delta stream has no tenant or session to draw real values from — it's a synthetic\n// in-process connection that never reaches a service. Inventing sentinel values would imply\n// quorum membership we cannot honor; only `scopes` actually drives behavior here (DocRead vs\n// DocWrite gates readOnlyInfo). The cast is the honest representation of \"this connection\n// has no claims worth populating.\"\n/* eslint-disable @typescript-eslint/consistent-type-assertions */\nconst readOnlyClaims: ITokenClaims = { scopes: [ScopeType.DocRead] } as ITokenClaims;\nconst writableClaims: ITokenClaims = {\n\tscopes: [ScopeType.DocRead, ScopeType.DocWrite],\n} as ITokenClaims;\n/* eslint-enable @typescript-eslint/consistent-type-assertions */\n\n/**\n * Inert `IDocumentDeltaConnection` for frozen container loads. Has no server upstream:\n * op and signal streams are empty, and `initialClients` contains only its own synthetic\n * read-only client — which lets the connection state handler observe \"self\" in the audience\n * and transition the container to Connected without waiting for a real join op or signal.\n *\n * Two concrete variants share this base — see their JSDoc for variant-specific details:\n *\n * - {@link FrozenDeltaStream} — read-only.\n * - {@link WritableFrozenDeltaStream} — writable.\n *\n * Both variants nack any incoming `submit`: this connection has no upstream and\n * `ConnectionManager.sendMessages` recognizes `WritableFrozenDeltaStream` and drops messages\n * before they reach `submit`, so under normal flow it should never fire. A nack reaching the\n * connectionManager surfaces the misuse — and may close the container — which is the right\n * defensive signal that something has bypassed the expected flow.\n *\n * `submitSignal` is a silent no-op for both variants. Signals are ephemeral and best-effort —\n * runtime/presence subsystems may submit them at any point in the writable-frozen lifetime, and\n * dropping them is the correct behavior here (we have no upstream). Closing the container or\n * triggering a reconnect on a stray signal would be strictly worse than dropping it.\n */\nabstract class FrozenDeltaStreamBase\n\textends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n\timplements IDocumentDeltaConnection, IDisposable\n{\n\tpublic readonly clientId: string;\n\tpublic readonly claims: ITokenClaims;\n\tpublic readonly initialClients: ISignalClient[];\n\tpublic readonly mode: ConnectionMode = \"read\";\n\tpublic readonly existing: boolean = true;\n\tpublic readonly maxMessageSize: number = 0;\n\tpublic readonly version: string = \"\";\n\tpublic readonly initialMessages: ISequencedDocumentMessage[] = [];\n\tpublic readonly initialSignals: ISignalMessage[] = [];\n\tpublic readonly serviceConfiguration: IClientConfiguration = {\n\t\tmaxMessageSize: 0,\n\t\tblockSize: 0,\n\t};\n\tpublic readonly checkpointSequenceNumber?: number | undefined = undefined;\n\n\tconstructor(clientId: string, claims: ITokenClaims) {\n\t\tsuper();\n\t\tthis.clientId = clientId;\n\t\tthis.claims = claims;\n\t\t// initialClients mirrors clientId so the audience handler observes \"self\" and\n\t\t// transitions the container to Connected without waiting for a real join op or signal.\n\t\tthis.initialClients = [{ client: clientFrozenDeltaStream, clientId }];\n\t}\n\n\tsubmit(messages: IDocumentMessage[]): void {\n\t\t// Defensive nack: nothing should send on a frozen delta stream. If this fires, an\n\t\t// invariant in connectionManager has changed and we want it to surface loudly.\n\t\tthis.emit(\n\t\t\t\"nack\",\n\t\t\tthis.clientId,\n\t\t\tmessages.map((operation) => ({\n\t\t\t\toperation,\n\t\t\t\tcontent: { message: \"Cannot submit on a frozen delta stream\", code: 403 },\n\t\t\t})),\n\t\t);\n\t}\n\n\tsubmitSignal(_message: unknown): void {\n\t\t// Intentional no-op. See class JSDoc for rationale.\n\t}\n\n\tprivate _disposed = false;\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\n/**\n * Read-only variant of {@link FrozenDeltaStreamBase}. Claims show only `DocRead`. Used by\n * storage-only loads (where `connectionManager` synthesizes one directly via\n * `policies.storageOnly`) and by the forbidden / out-of-storage fallback paths.\n * {@link isFrozenDeltaStreamConnection} matches this variant and drives the read-only forcing\n * in `ConnectionManager.readOnlyInfo`. Uses the historical `\"storage-only client\"` constant\n * `clientId`, preserving existing behavior for any consumer that keys off it.\n *\n * `storageOnlyReason` and `readonlyConnectionReason` are surfaced through `IContainer.readOnlyInfo`\n * for diagnostics on the fallback paths (`isDeltaStreamConnectionForbiddenError`,\n * `outOfStorageError`).\n */\nexport class FrozenDeltaStream extends FrozenDeltaStreamBase {\n\tpublic readonly storageOnlyReason: string | undefined;\n\tpublic readonly readonlyConnectionReason: IConnectionStateChangeReason | undefined;\n\n\tconstructor(options?: {\n\t\tstorageOnlyReason?: string;\n\t\treadonlyConnectionReason?: IConnectionStateChangeReason;\n\t}) {\n\t\t// Constant clientId: preserves the pre-PR `\"storage-only client\"` identity for any\n\t\t// consumer that keys off it. The 0x173 replay-assert risk that motivates per-instance\n\t\t// clientIds applies only to the writable variant, where the runtime accumulates dirty\n\t\t// pending ops across reconnects; the read-only variant does not.\n\t\tsuper(clientIdFrozenDeltaStream, readOnlyClaims);\n\t\tthis.storageOnlyReason = options?.storageOnlyReason;\n\t\tthis.readonlyConnectionReason = options?.readonlyConnectionReason;\n\t}\n}\n\n/**\n * Variant of {@link FrozenDeltaStreamBase} that appears to support writing but remains\n * \"frozen\" — no messages are actually sent or received. The stream itself does not enforce\n * the no-send guarantee; that lives in `ConnectionManager.sendMessages`, which recognizes\n * any `WritableFrozenDeltaStream` (via {@link isWritableFrozenDeltaStreamConnection}) and\n * short-circuits before its read-mode upgrade branch. Submitted ops are dropped at the\n * connection-manager layer, so the container stays `Connected` and the runtime accumulates\n * them in `pendingStateManager`.\n *\n * \"Appears writable\" mechanics: claims include `DocWrite` so the container surfaces as\n * writable; not matched by {@link isFrozenDeltaStreamConnection}, so `readOnlyInfo` reports\n * `readonly: false`. Connection mode stays `\"read\"` (advertising `\"write\"` would imply quorum\n * membership we cannot honor).\n *\n * Each instance mints a fresh `frozen-delta-stream/<uuid>` `clientId` to avoid\n * `pendingStateManager` `0x173` (`replayPendingStates called twice for same clientId!`) on\n * reconnect with dirty pending ops. Sibling (not subclass) of `FrozenDeltaStream` so\n * `instanceof` cleanly distinguishes the two for `ConnectionManager`'s short-circuits.\n */\nexport class WritableFrozenDeltaStream extends FrozenDeltaStreamBase {\n\tconstructor() {\n\t\tsuper(`frozen-delta-stream/${uuid()}`, writableClaims);\n\t}\n}\n\n/**\n * Recognizes the read-only variant of {@link FrozenDeltaStreamBase}. Drives the storage-only\n * forcing in `ConnectionManager.readOnlyInfo`: only the read-only variant should make the\n * container surface as read-only. {@link WritableFrozenDeltaStream} is a sibling class, not\n * a subclass, so `instanceof FrozenDeltaStream` already excludes it.\n */\nexport function isFrozenDeltaStreamConnection(\n\tconnection: unknown,\n): connection is FrozenDeltaStream {\n\treturn connection instanceof FrozenDeltaStream;\n}\n\n/**\n * Recognizes the writable variant of {@link FrozenDeltaStreamBase}. Drives the\n * `ConnectionManager.sendMessages` short-circuit: writable-frozen submits must be dropped at\n * the network layer instead of triggering a read→write reconnect. Sibling (not subclass) of\n * {@link FrozenDeltaStream}, so `instanceof WritableFrozenDeltaStream` excludes the read-only\n * variant.\n */\nexport function isWritableFrozenDeltaStreamConnection(\n\tconnection: unknown,\n): connection is WritableFrozenDeltaStream {\n\treturn connection instanceof WritableFrozenDeltaStream;\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  export { ConnectionState } from "./connectionState.js";
6
6
  export { type ContainerAlpha, waitContainerToCatchUp, asLegacyAlpha } from "./container.js";
7
7
  export { createFrozenDocumentServiceFactory } from "./frozenServices.js";
8
- export { captureFullContainerState, createDetachedContainer, loadExistingContainer, rehydrateDetachedContainer, loadFrozenContainerFromPendingState, loadSummarizerContainerAndMakeSummary, type ICaptureFullContainerStateProps, type ICreateAndLoadContainerProps, type ICreateDetachedContainerProps, type ILoadExistingContainerProps, type ILoadSummarizerContainerProps, type IRehydrateDetachedContainerProps, type ILoadFrozenContainerFromPendingStateProps, } from "./createAndLoadContainerUtils.js";
8
+ export { captureFullContainerState, createDetachedContainer, loadExistingContainer, rehydrateDetachedContainer, loadFrozenContainerFromPendingState, loadSummarizerContainerAndMakeSummary, type ICaptureFullContainerStateProps, type IContainerDriverServices, type IContainerHostProps, type IContainerLoadDriverProps, type ICreateAndLoadContainerProps, type ICreateDetachedContainerProps, type ILoadExistingContainerProps, type ILoadSummarizerContainerProps, type IRehydrateDetachedContainerProps, type ILoadFrozenContainerFromPendingStateProps, } from "./createAndLoadContainerUtils.js";
9
9
  export type { LoadSummarizerSummaryResult, OnDemandSummaryResults, SummaryStage, } from "./summarizerResultTypes.js";
10
10
  export { type ICodeDetailsLoader, type IFluidModuleWithDetails, type ILoaderProps, type ILoaderServices, Loader, } from "./loader.js";
11
11
  export { driverSupportRequirementsForLoader, loaderCoreCompatDetails, runtimeSupportRequirementsForLoader, loaderCompatDetailsForRuntime, } from "./loaderLayerCompatState.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,cAAc,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EACN,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,mCAAmC,EACnC,qCAAqC,EACrC,KAAK,+BAA+B,EACpC,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,gCAAgC,EACrC,KAAK,yCAAyC,GAC9C,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,YAAY,GACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,kCAAkC,EAClC,uBAAuB,EACvB,mCAAmC,EACnC,6BAA6B,GAC7B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACN,0BAA0B,EAC1B,sCAAsC,GACtC,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EACN,6BAA6B,EAC7B,KAAK,UAAU,GACf,MAAM,YAAY,CAAC;AACpB,YAAY,EACX,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,uBAAuB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,2BAA2B,EAC3B,mBAAmB,EACnB,KAAK,oBAAoB,GACzB,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,KAAK,cAAc,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EACN,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,mCAAmC,EACnC,qCAAqC,EACrC,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,gCAAgC,EACrC,KAAK,yCAAyC,GAC9C,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,YAAY,GACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,kCAAkC,EAClC,uBAAuB,EACvB,mCAAmC,EACnC,6BAA6B,GAC7B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACN,0BAA0B,EAC1B,sCAAsC,GACtC,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EACN,6BAA6B,EAC7B,KAAK,UAAU,GACf,MAAM,YAAY,CAAC;AACpB,YAAY,EACX,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,uBAAuB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,2BAA2B,EAC3B,mBAAmB,EACnB,KAAK,oBAAoB,GACzB,MAAM,gCAAgC,CAAC"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAuB,sBAAsB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EACN,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,mCAAmC,EACnC,qCAAqC,GAQrC,MAAM,kCAAkC,CAAC;AAM1C,OAAO,EAKN,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,kCAAkC,EAClC,uBAAuB,EACvB,mCAAmC,EACnC,6BAA6B,GAC7B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACN,0BAA0B,EAC1B,sCAAsC,GACtC,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EACN,6BAA6B,GAE7B,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,2BAA2B,EAC3B,mBAAmB,GAEnB,MAAM,gCAAgC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { ConnectionState } from \"./connectionState.js\";\nexport { type ContainerAlpha, waitContainerToCatchUp, asLegacyAlpha } from \"./container.js\";\nexport { createFrozenDocumentServiceFactory } from \"./frozenServices.js\";\nexport {\n\tcaptureFullContainerState,\n\tcreateDetachedContainer,\n\tloadExistingContainer,\n\trehydrateDetachedContainer,\n\tloadFrozenContainerFromPendingState,\n\tloadSummarizerContainerAndMakeSummary,\n\ttype ICaptureFullContainerStateProps,\n\ttype ICreateAndLoadContainerProps,\n\ttype ICreateDetachedContainerProps,\n\ttype ILoadExistingContainerProps,\n\ttype ILoadSummarizerContainerProps,\n\ttype IRehydrateDetachedContainerProps,\n\ttype ILoadFrozenContainerFromPendingStateProps,\n} from \"./createAndLoadContainerUtils.js\";\nexport type {\n\tLoadSummarizerSummaryResult,\n\tOnDemandSummaryResults,\n\tSummaryStage,\n} from \"./summarizerResultTypes.js\";\nexport {\n\ttype ICodeDetailsLoader,\n\ttype IFluidModuleWithDetails,\n\ttype ILoaderProps,\n\ttype ILoaderServices,\n\tLoader,\n} from \"./loader.js\";\nexport {\n\tdriverSupportRequirementsForLoader,\n\tloaderCoreCompatDetails,\n\truntimeSupportRequirementsForLoader,\n\tloaderCompatDetailsForRuntime,\n} from \"./loaderLayerCompatState.js\";\nexport { loadContainerPaused } from \"./loadPaused.js\";\nexport {\n\tisLocationRedirectionError,\n\tresolveWithLocationRedirectionHandling,\n} from \"./location-redirection-utilities/index.js\";\nexport type { IProtocolHandler, ProtocolHandlerBuilder } from \"./protocol.js\";\nexport {\n\ttryParseCompatibleResolvedUrl,\n\ttype IParsedUrl,\n} from \"./utils.js\";\nexport type {\n\tIBaseProtocolHandler,\n\tIScribeProtocolState,\n\tIQuorumSnapshot,\n\tQuorumClientsSnapshot,\n\tQuorumProposalsSnapshot,\n} from \"./protocol/index.js\";\nexport { PendingLocalStateStore } from \"./pendingLocalStateStore.js\";\nexport {\n\textractBlobAttachReferences,\n\twireFormatConstants,\n\ttype IBlobAttachReference,\n} from \"./captureReferencedContents.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAuB,sBAAsB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EAAE,kCAAkC,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EACN,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,mCAAmC,EACnC,qCAAqC,GAWrC,MAAM,kCAAkC,CAAC;AAM1C,OAAO,EAKN,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,kCAAkC,EAClC,uBAAuB,EACvB,mCAAmC,EACnC,6BAA6B,GAC7B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACN,0BAA0B,EAC1B,sCAAsC,GACtC,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EACN,6BAA6B,GAE7B,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACN,2BAA2B,EAC3B,mBAAmB,GAEnB,MAAM,gCAAgC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { ConnectionState } from \"./connectionState.js\";\nexport { type ContainerAlpha, waitContainerToCatchUp, asLegacyAlpha } from \"./container.js\";\nexport { createFrozenDocumentServiceFactory } from \"./frozenServices.js\";\nexport {\n\tcaptureFullContainerState,\n\tcreateDetachedContainer,\n\tloadExistingContainer,\n\trehydrateDetachedContainer,\n\tloadFrozenContainerFromPendingState,\n\tloadSummarizerContainerAndMakeSummary,\n\ttype ICaptureFullContainerStateProps,\n\ttype IContainerDriverServices,\n\ttype IContainerHostProps,\n\ttype IContainerLoadDriverProps,\n\ttype ICreateAndLoadContainerProps,\n\ttype ICreateDetachedContainerProps,\n\ttype ILoadExistingContainerProps,\n\ttype ILoadSummarizerContainerProps,\n\ttype IRehydrateDetachedContainerProps,\n\ttype ILoadFrozenContainerFromPendingStateProps,\n} from \"./createAndLoadContainerUtils.js\";\nexport type {\n\tLoadSummarizerSummaryResult,\n\tOnDemandSummaryResults,\n\tSummaryStage,\n} from \"./summarizerResultTypes.js\";\nexport {\n\ttype ICodeDetailsLoader,\n\ttype IFluidModuleWithDetails,\n\ttype ILoaderProps,\n\ttype ILoaderServices,\n\tLoader,\n} from \"./loader.js\";\nexport {\n\tdriverSupportRequirementsForLoader,\n\tloaderCoreCompatDetails,\n\truntimeSupportRequirementsForLoader,\n\tloaderCompatDetailsForRuntime,\n} from \"./loaderLayerCompatState.js\";\nexport { loadContainerPaused } from \"./loadPaused.js\";\nexport {\n\tisLocationRedirectionError,\n\tresolveWithLocationRedirectionHandling,\n} from \"./location-redirection-utilities/index.js\";\nexport type { IProtocolHandler, ProtocolHandlerBuilder } from \"./protocol.js\";\nexport {\n\ttryParseCompatibleResolvedUrl,\n\ttype IParsedUrl,\n} from \"./utils.js\";\nexport type {\n\tIBaseProtocolHandler,\n\tIScribeProtocolState,\n\tIQuorumSnapshot,\n\tQuorumClientsSnapshot,\n\tQuorumProposalsSnapshot,\n} from \"./protocol/index.js\";\nexport { PendingLocalStateStore } from \"./pendingLocalStateStore.js\";\nexport {\n\textractBlobAttachReferences,\n\twireFormatConstants,\n\ttype IBlobAttachReference,\n} from \"./captureReferencedContents.js\";\n"]}
package/lib/legacy.d.ts CHANGED
@@ -16,6 +16,9 @@ export {
16
16
  // #region @legacyBeta APIs
17
17
  IBaseProtocolHandler,
18
18
  ICodeDetailsLoader,
19
+ IContainerDriverServices,
20
+ IContainerHostProps,
21
+ IContainerLoadDriverProps,
19
22
  ICreateAndLoadContainerProps,
20
23
  ICreateDetachedContainerProps,
21
24
  IFluidModuleWithDetails,
@@ -16,6 +16,9 @@ export {
16
16
  // #region @legacyBeta APIs
17
17
  IBaseProtocolHandler,
18
18
  ICodeDetailsLoader,
19
+ IContainerDriverServices,
20
+ IContainerHostProps,
21
+ IContainerLoadDriverProps,
19
22
  ICreateAndLoadContainerProps,
20
23
  ICreateDetachedContainerProps,
21
24
  IFluidModuleWithDetails,
@@ -13,11 +13,11 @@ export declare const loaderCoreCompatDetails: {
13
13
  /**
14
14
  * The package version of the Loader layer.
15
15
  */
16
- readonly pkgVersion: "2.101.1";
16
+ readonly pkgVersion: "2.103.0";
17
17
  /**
18
18
  * The current generation of the Loader layer.
19
19
  */
20
- readonly generation: 6;
20
+ readonly generation: 7;
21
21
  };
22
22
  /**
23
23
  * Loader's compatibility details that is exposed to the Runtime layer.
@@ -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.101.1";
8
+ export declare const pkgVersion = "2.103.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-loader";
8
- export const pkgVersion = "2.101.1";
8
+ export const pkgVersion = "2.103.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,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.1\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,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.103.0\";\n"]}
@@ -5,14 +5,14 @@
5
5
  import type { IDisposable } from "@fluidframework/core-interfaces";
6
6
  import type { ISummaryHandle, ISummaryTree } from "@fluidframework/driver-definitions";
7
7
  import type { FetchSource, IDocumentStorageService, IDocumentStorageServicePolicies, ISnapshot, ISnapshotFetchOptions, ISummaryContext, ICreateBlobResponse, ISnapshotTree, IVersion } from "@fluidframework/driver-definitions/internal";
8
- import { type ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
8
+ import { type TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
9
9
  export declare class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
10
10
  private readonly internalStorageServiceP;
11
11
  private readonly logger;
12
12
  private readonly maxRetries?;
13
13
  private _disposed;
14
14
  private internalStorageService;
15
- constructor(internalStorageServiceP: Promise<IDocumentStorageService>, logger: ITelemetryLoggerExt, maxRetries?: number | undefined);
15
+ constructor(internalStorageServiceP: Promise<IDocumentStorageService>, logger: TelemetryLoggerExt, maxRetries?: number | undefined);
16
16
  get policies(): IDocumentStorageServicePolicies | undefined;
17
17
  get disposed(): boolean;
18
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;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"}
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,kBAAkB,EAGvB,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,kBAAkB,EAC1B,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"}
@@ -1 +1 @@
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"]}
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 TelemetryLoggerExt,\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: TelemetryLoggerExt,\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotRefresher.d.ts","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAEN,KAAK,6CAA6C,EAClD,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AAyBrC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAyBnD,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,cAAc,CAA4B;IAGlD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,cAAc,CAS7B;IACF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA+B;gBAIvE,SAAS,EAAE,oBAAoB,EACd,cAAc,EAAE,6CAA6C,EAC7D,kBAAkB,EAAE,OAAO,EAC3B,qBAAqB,EAAE,MAAM,OAAO,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,EACzE,wBAAwB,CAAC,EAAE,MAAM;IAmB3B,kBAAkB,IAAI,IAAI;IAYjC;;;;;OAKG;YACW,qBAAqB;IAsCnC;;;OAGG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,UAAU,IAAI,IAAI;IAIzB;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;;OAGG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAEzD;IAED;;OAEG;IACI,OAAO,IAAI,IAAI;CAItB"}
1
+ {"version":3,"file":"snapshotRefresher.d.ts","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAEN,KAAK,6CAA6C,EAClD,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AAyBrC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAyBnD,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,cAAc,CAA4B;IAGlD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,cAAc,CAS7B;IACF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA+B;gBAIvE,SAAS,EAAE,oBAAoB,EACd,cAAc,EAAE,6CAA6C,EAC7D,kBAAkB,EAAE,OAAO,EAC3B,qBAAqB,EAAE,MAAM,OAAO,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,EACzE,wBAAwB,CAAC,EAAE,MAAM;IAkB3B,kBAAkB,IAAI,IAAI;IAYjC;;;;;OAKG;YACW,qBAAqB;IAsCnC;;;OAGG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,UAAU,IAAI,IAAI;IAIzB;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;;OAGG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAEzD;IAED;;OAEG;IACI,OAAO,IAAI,IAAI;CAItB"}
@@ -79,8 +79,7 @@ export class SnapshotRefresher {
79
79
  });
80
80
  this.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;
81
81
  __classPrivateFieldSet(this, _SnapshotRefresher_snapshotRefreshEnabled, this.offlineLoadEnabled &&
82
- (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ??
83
- this.mc.config.getBoolean("Fluid.Container.enableOfflineFull")) === true, "f");
82
+ (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ?? false), "f");
84
83
  this.refreshTimer = __classPrivateFieldGet(this, _SnapshotRefresher_snapshotRefreshEnabled, "f")
85
84
  ? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())
86
85
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotRefresher.js","sourceRoot":"","sources":["../src/snapshotRefresher.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 { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert, Timer } from \"@fluidframework/core-utils/internal\";\nimport { FetchSource } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tcreateChildMonitoringContext,\n\ttype MonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetLatestSnapshotInfo,\n\ttype ISerializedStateManagerDocumentStorageService,\n\ttype ISnapshotInfo,\n} from \"./serializedStateManager.js\";\n\nclass RefreshPromiseTracker {\n\tpublic get hasPromise(): boolean {\n\t\treturn this.#promise !== undefined;\n\t}\n\tpublic get promise(): Promise<number> | undefined {\n\t\treturn this.#promise;\n\t}\n\tconstructor(private readonly catchHandler: (error: Error) => void) {}\n\n\t#promise: Promise<number> | undefined;\n\tsetPromise(p: Promise<number>): void {\n\t\tif (this.hasPromise) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cannot start new snapshot refresh while a refresh is already in progress\",\n\t\t\t);\n\t\t}\n\t\tthis.#promise = p.finally(() => {\n\t\t\tthis.#promise = undefined;\n\t\t});\n\t\tp.catch(this.catchHandler);\n\t}\n}\n\n/**\n * Manages periodic refresh of the latest snapshot for a document.\n *\n * `SnapshotRefresher` polls the storage service for the most recent snapshot and, when a newer\n * snapshot is discovered, invokes the provided `onSnapshotRefreshed` callback with the updated\n * snapshot metadata. It is responsible for:\n *\n * - Tracking the most recent snapshot that has been observed.\n * - Scheduling and managing refresh attempts via an internal timer.\n * - Emitting telemetry for successful and failed refresh attempts.\n *\n * The refresh behavior can be configured via constructor arguments, including whether offline\n * loading and the `getSnapshot` API are supported, as well as the refresh timeout. Callers\n * should dispose this instance when snapshot refresh is no longer needed to stop any pending\n * timers and prevent further refresh attempts.\n */\nexport class SnapshotRefresher implements IDisposable {\n\tprivate readonly mc: MonitoringContext;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\t#disposed: boolean = false;\n\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\n\tprivate readonly refreshTracker = new RefreshPromiseTracker(\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\t(error) =>\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"RefreshLatestSnapshotFailed\",\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t),\n\t);\n\tprivate readonly refreshTimer: Timer | undefined;\n\tprivate readonly snapshotRefreshTimeoutMs: number = 60 * 60 * 24 * 1000;\n\treadonly #snapshotRefreshEnabled: boolean;\n\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tprivate readonly onSnapshotRefreshed: (snapshot: ISnapshotInfo) => number,\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.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;\n\n\t\tthis.#snapshotRefreshEnabled =\n\t\t\tthis.offlineLoadEnabled &&\n\t\t\t(this.mc.config.getBoolean(\"Fluid.Container.enableOfflineSnapshotRefresh\") ??\n\t\t\t\tthis.mc.config.getBoolean(\"Fluid.Container.enableOfflineFull\")) === true;\n\n\t\tthis.refreshTimer = this.#snapshotRefreshEnabled\n\t\t\t? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())\n\t\t\t: undefined;\n\t}\n\n\tpublic tryRefreshSnapshot(): void {\n\t\tif (\n\t\t\tthis.#snapshotRefreshEnabled &&\n\t\t\t!this.#disposed &&\n\t\t\t!this.refreshTracker.hasPromise &&\n\t\t\tthis.latestSnapshot === undefined\n\t\t) {\n\t\t\t// Don't block on the refresh snapshot call - it is for the next time we serialize, not booting this incarnation\n\t\t\tthis.refreshTracker.setPromise(this.refreshLatestSnapshot(this.supportGetSnapshotApi()));\n\t\t}\n\t}\n\n\t/**\n\t * Fetch the latest snapshot for the container, including delay-loaded groupIds if pendingLocalState was provided and contained any groupIds.\n\t * Note that this will update the StorageAdapter's cached snapshots for the groupIds (if present)\n\t *\n\t * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree (must be true to fetch by groupIds)\n\t */\n\tprivate async refreshLatestSnapshot(supportGetSnapshotApi: boolean): Promise<number> {\n\t\tthis.latestSnapshot = await getLatestSnapshotInfo(\n\t\t\tthis.mc,\n\t\t\tthis.storageAdapter,\n\t\t\tsupportGetSnapshotApi,\n\t\t);\n\n\t\tif (this.#disposed) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// These are loading groupIds that the containerRuntime has requested over its lifetime.\n\t\t// We will fetch the latest snapshot for the groupIds, which will update storageAdapter.loadedGroupIdSnapshots's cache\n\t\tconst downloadedGroupIds = Object.keys(this.storageAdapter.loadedGroupIdSnapshots);\n\t\tif (supportGetSnapshotApi && downloadedGroupIds.length > 0) {\n\t\t\tassert(\n\t\t\t\tthis.storageAdapter.getSnapshot !== undefined,\n\t\t\t\t0x972 /* getSnapshot should exist */,\n\t\t\t);\n\t\t\t// (This is a separate network call from above because it requires work for storage to add a special base groupId)\n\t\t\tconst snapshot = await this.storageAdapter.getSnapshot({\n\t\t\t\tversionId: undefined,\n\t\t\t\tscenarioName: \"getLatestSnapshotInfo\",\n\t\t\t\tcacheSnapshot: false,\n\t\t\t\tloadingGroupIds: downloadedGroupIds,\n\t\t\t\tfetchSource: FetchSource.noCache,\n\t\t\t});\n\t\t\tassert(snapshot !== undefined, 0x973 /* Snapshot should exist */);\n\t\t}\n\n\t\t// Notify the manager about the fetched snapshot - let it decide what to do with it\n\t\tconst result =\n\t\t\tthis.latestSnapshot === undefined ? -1 : this.onSnapshotRefreshed(this.latestSnapshot);\n\n\t\tthis.refreshTimer?.restart();\n\t\treturn result;\n\t}\n\n\t/**\n\t * Clears the latest snapshot after it's been consumed by the manager.\n\t * This allows the next refresh cycle to proceed.\n\t */\n\tpublic clearLatestSnapshot(): void {\n\t\tthis.latestSnapshot = undefined;\n\t}\n\n\t/**\n\t * Starts the refresh timer.\n\t */\n\tpublic startTimer(): void {\n\t\tthis.refreshTimer?.start();\n\t}\n\n\t/**\n\t * Restarts the refresh timer.\n\t */\n\tpublic restartTimer(): void {\n\t\tthis.refreshTimer?.restart();\n\t}\n\n\t/**\n\t * Gets the current refresh promise for testing purposes.\n\t * @returns The snapshot sequence number promise, or undefined if no refresh is in progress\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.refreshTracker.promise;\n\t}\n\n\t/**\n\t * Disposes the refresher and clears the timer.\n\t */\n\tpublic dispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.refreshTimer?.clear();\n\t}\n}\n"]}
1
+ {"version":3,"file":"snapshotRefresher.js","sourceRoot":"","sources":["../src/snapshotRefresher.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 { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert, Timer } from \"@fluidframework/core-utils/internal\";\nimport { FetchSource } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tcreateChildMonitoringContext,\n\ttype MonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetLatestSnapshotInfo,\n\ttype ISerializedStateManagerDocumentStorageService,\n\ttype ISnapshotInfo,\n} from \"./serializedStateManager.js\";\n\nclass RefreshPromiseTracker {\n\tpublic get hasPromise(): boolean {\n\t\treturn this.#promise !== undefined;\n\t}\n\tpublic get promise(): Promise<number> | undefined {\n\t\treturn this.#promise;\n\t}\n\tconstructor(private readonly catchHandler: (error: Error) => void) {}\n\n\t#promise: Promise<number> | undefined;\n\tsetPromise(p: Promise<number>): void {\n\t\tif (this.hasPromise) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cannot start new snapshot refresh while a refresh is already in progress\",\n\t\t\t);\n\t\t}\n\t\tthis.#promise = p.finally(() => {\n\t\t\tthis.#promise = undefined;\n\t\t});\n\t\tp.catch(this.catchHandler);\n\t}\n}\n\n/**\n * Manages periodic refresh of the latest snapshot for a document.\n *\n * `SnapshotRefresher` polls the storage service for the most recent snapshot and, when a newer\n * snapshot is discovered, invokes the provided `onSnapshotRefreshed` callback with the updated\n * snapshot metadata. It is responsible for:\n *\n * - Tracking the most recent snapshot that has been observed.\n * - Scheduling and managing refresh attempts via an internal timer.\n * - Emitting telemetry for successful and failed refresh attempts.\n *\n * The refresh behavior can be configured via constructor arguments, including whether offline\n * loading and the `getSnapshot` API are supported, as well as the refresh timeout. Callers\n * should dispose this instance when snapshot refresh is no longer needed to stop any pending\n * timers and prevent further refresh attempts.\n */\nexport class SnapshotRefresher implements IDisposable {\n\tprivate readonly mc: MonitoringContext;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\t#disposed: boolean = false;\n\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\n\tprivate readonly refreshTracker = new RefreshPromiseTracker(\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\t(error) =>\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"RefreshLatestSnapshotFailed\",\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t),\n\t);\n\tprivate readonly refreshTimer: Timer | undefined;\n\tprivate readonly snapshotRefreshTimeoutMs: number = 60 * 60 * 24 * 1000;\n\treadonly #snapshotRefreshEnabled: boolean;\n\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tprivate readonly onSnapshotRefreshed: (snapshot: ISnapshotInfo) => number,\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.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;\n\n\t\tthis.#snapshotRefreshEnabled =\n\t\t\tthis.offlineLoadEnabled &&\n\t\t\t(this.mc.config.getBoolean(\"Fluid.Container.enableOfflineSnapshotRefresh\") ?? false);\n\n\t\tthis.refreshTimer = this.#snapshotRefreshEnabled\n\t\t\t? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())\n\t\t\t: undefined;\n\t}\n\n\tpublic tryRefreshSnapshot(): void {\n\t\tif (\n\t\t\tthis.#snapshotRefreshEnabled &&\n\t\t\t!this.#disposed &&\n\t\t\t!this.refreshTracker.hasPromise &&\n\t\t\tthis.latestSnapshot === undefined\n\t\t) {\n\t\t\t// Don't block on the refresh snapshot call - it is for the next time we serialize, not booting this incarnation\n\t\t\tthis.refreshTracker.setPromise(this.refreshLatestSnapshot(this.supportGetSnapshotApi()));\n\t\t}\n\t}\n\n\t/**\n\t * Fetch the latest snapshot for the container, including delay-loaded groupIds if pendingLocalState was provided and contained any groupIds.\n\t * Note that this will update the StorageAdapter's cached snapshots for the groupIds (if present)\n\t *\n\t * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree (must be true to fetch by groupIds)\n\t */\n\tprivate async refreshLatestSnapshot(supportGetSnapshotApi: boolean): Promise<number> {\n\t\tthis.latestSnapshot = await getLatestSnapshotInfo(\n\t\t\tthis.mc,\n\t\t\tthis.storageAdapter,\n\t\t\tsupportGetSnapshotApi,\n\t\t);\n\n\t\tif (this.#disposed) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// These are loading groupIds that the containerRuntime has requested over its lifetime.\n\t\t// We will fetch the latest snapshot for the groupIds, which will update storageAdapter.loadedGroupIdSnapshots's cache\n\t\tconst downloadedGroupIds = Object.keys(this.storageAdapter.loadedGroupIdSnapshots);\n\t\tif (supportGetSnapshotApi && downloadedGroupIds.length > 0) {\n\t\t\tassert(\n\t\t\t\tthis.storageAdapter.getSnapshot !== undefined,\n\t\t\t\t0x972 /* getSnapshot should exist */,\n\t\t\t);\n\t\t\t// (This is a separate network call from above because it requires work for storage to add a special base groupId)\n\t\t\tconst snapshot = await this.storageAdapter.getSnapshot({\n\t\t\t\tversionId: undefined,\n\t\t\t\tscenarioName: \"getLatestSnapshotInfo\",\n\t\t\t\tcacheSnapshot: false,\n\t\t\t\tloadingGroupIds: downloadedGroupIds,\n\t\t\t\tfetchSource: FetchSource.noCache,\n\t\t\t});\n\t\t\tassert(snapshot !== undefined, 0x973 /* Snapshot should exist */);\n\t\t}\n\n\t\t// Notify the manager about the fetched snapshot - let it decide what to do with it\n\t\tconst result =\n\t\t\tthis.latestSnapshot === undefined ? -1 : this.onSnapshotRefreshed(this.latestSnapshot);\n\n\t\tthis.refreshTimer?.restart();\n\t\treturn result;\n\t}\n\n\t/**\n\t * Clears the latest snapshot after it's been consumed by the manager.\n\t * This allows the next refresh cycle to proceed.\n\t */\n\tpublic clearLatestSnapshot(): void {\n\t\tthis.latestSnapshot = undefined;\n\t}\n\n\t/**\n\t * Starts the refresh timer.\n\t */\n\tpublic startTimer(): void {\n\t\tthis.refreshTimer?.start();\n\t}\n\n\t/**\n\t * Restarts the refresh timer.\n\t */\n\tpublic restartTimer(): void {\n\t\tthis.refreshTimer?.restart();\n\t}\n\n\t/**\n\t * Gets the current refresh promise for testing purposes.\n\t * @returns The snapshot sequence number promise, or undefined if no refresh is in progress\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.refreshTracker.promise;\n\t}\n\n\t/**\n\t * Disposes the refresher and clears the timer.\n\t */\n\tpublic dispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.refreshTimer?.clear();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,KAAK,6BAA6B,EAClC,KAAK,mCAAmC,EAGxC,MAAM,uCAAuC,CAAC;AAS/C,OAAO,KAAK,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,EACtB,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAiBjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AA+DD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,GAAG,sBAAsB,CAczF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,YAAY,EAAE,sBAAsB,GAClC,SAAS,CAaX;AAqBD,eAAO,MAAM,mCAAmC,8BACpB,YAAY,KACrC,SAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,eAAO,MAAM,mCAAmC,oCAG7C,KAAK,SAAS,EAAE,cAAc,GAAG,cAAc,CAAC,KAAG,6BAyBrD,CAAC;AAEF,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,OAAO,GACZ,KAAK,IAAI,mCAAmC,CAO9C;AAmBD;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,SAAS,GAAG,iBAAiB,CAS1F;AAED;;;;GAIG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAmBhC;AAED;;;GAGG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,sBAAsB,CAAC;AAC1B,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,sBAAsB,GAAG,SAAS,CAAC;AAStC;;;GAGG;AAEH,eAAO,MAAM,SAAS,6BACf,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,KAC9B,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAsB7B,CAAC;AAEF,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,IAAI,EAAE,aAAa,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,KAAK,6BAA6B,EAClC,KAAK,mCAAmC,EAGxC,MAAM,uCAAuC,CAAC;AAS/C,OAAO,KAAK,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,EACtB,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CA4BjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AA+DD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,GAAG,sBAAsB,CAczF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,YAAY,EAAE,sBAAsB,GAClC,SAAS,CAaX;AAqBD,eAAO,MAAM,mCAAmC,8BACpB,YAAY,KACrC,SAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,eAAO,MAAM,mCAAmC,oCAG7C,KAAK,SAAS,EAAE,cAAc,GAAG,cAAc,CAAC,KAAG,6BAyBrD,CAAC;AAEF,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,OAAO,GACZ,KAAK,IAAI,mCAAmC,CAO9C;AAmBD;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,SAAS,GAAG,iBAAiB,CAS1F;AAED;;;;GAIG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAmBhC;AAED;;;GAGG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,sBAAsB,CAAC;AAC1B,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,sBAAsB,GAAG,SAAS,CAAC;AAStC;;;GAGG;AAEH,eAAO,MAAM,SAAS,6BACf,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,KAC9B,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAsB7B,CAAC;AAEF,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,IAAI,EAAE,aAAa,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
package/lib/utils.js CHANGED
@@ -19,7 +19,19 @@ import { v4 as uuid } from "uuid";
19
19
  * @legacy @beta
20
20
  */
21
21
  export function tryParseCompatibleResolvedUrl(url) {
22
- const parsed = new URL(url);
22
+ // `new URL(...)` throws `TypeError` for any string that isn't a well-formed
23
+ // absolute URL. The `try*` name in this function's identifier implies a
24
+ // non-throwing contract on bad input, and callers all gate on `=== undefined`
25
+ // to surface their own errors — letting the built-in throw escape here would
26
+ // bypass those caller-supplied error messages for the broadest class of bad
27
+ // URLs ("not absolute", "invalid characters", etc.).
28
+ let parsed;
29
+ try {
30
+ parsed = new URL(url);
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
23
35
  if (typeof parsed.pathname !== "string") {
24
36
  throw new LoggingError("Failed to parse pathname");
25
37
  }
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tbufferToString,\n\tstringToBuffer,\n\tUint8ArrayToArrayBuffer,\n} from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { type ISummaryTree, SummaryType } from \"@fluidframework/driver-definitions\";\nimport {\n\tDriverErrorTypes,\n\ttype IDocumentAttributes,\n\ttype ISnapshotTree,\n\ttype IDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype CombinedAppAndProtocolSummary,\n\ttype DeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tLoggingError,\n\tUsageError,\n\ttype IFluidErrorBase,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingContainerState,\n\tIPendingDetachedContainerState,\n\tSerializedSnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.js\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @legacy @beta\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Undefined means load latest snapshot, otherwise it's version ID passed to IDocumentStorageService.getVersions()\n\t * to figure out what snapshot to use.\n\t */\n\tversion: string | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @legacy @beta\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = new URL(url);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? {\n\t\t\t\tid: match[1],\n\t\t\t\tpath: match[2],\n\t\t\t\tquery,\n\t\t\t\t// URLSearchParams returns null if the param is not provided.\n\t\t\t\tversion: parsed.searchParams.get(\"version\") ?? undefined,\n\t\t\t}\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts a summary to snapshot tree and separate its blob contents\n * to align detached container format with IPendingContainerState\n * @param summary - ISummaryTree\n */\nfunction convertSummaryToISnapshot(\n\tsummary: ISummaryTree,\n\tblobContents = new Map<string, ArrayBuffer>(),\n): ISnapshot {\n\tconst snapshotTree: ISnapshotTree = {\n\t\tblobs: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t\tgroupId: summary.groupId,\n\t};\n\n\tfor (const [key, summaryObject] of Object.entries(summary.tree)) {\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst innerSnapshot = convertSummaryToISnapshot(summaryObject, blobContents);\n\t\t\t\tsnapshotTree.trees[key] = innerSnapshot.snapshotTree;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment: {\n\t\t\t\tsnapshotTree.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\tsnapshotTree.blobs[key] = blobId;\n\t\t\t\tblobContents.set(\n\t\t\t\t\tblobId,\n\t\t\t\t\tsummaryObject.content instanceof Uint8Array\n\t\t\t\t\t\t? Uint8ArrayToArrayBuffer(summaryObject.content)\n\t\t\t\t\t\t: stringToBuffer(summaryObject.content, \"utf8\"),\n\t\t\t\t);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle: {\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tblobContents,\n\t\tlatestSequenceNumber: undefined,\n\t\tops: [],\n\t\tsequenceNumber: 0,\n\t\tsnapshotFormatV: 1,\n\t\tsnapshotTree,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): SerializedSnapshotInfo {\n\tassert(\n\t\tsnapshot.sequenceNumber !== undefined,\n\t\t0x93a /* Snapshot sequence number is missing */,\n\t);\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: SerializedSnapshotInfo,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBuffer>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotInfo.snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\n}\n\n/**\n * Converts summary parts into a SnapshotTree and its blob contents.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nfunction convertProtocolAndAppSummaryToISnapshot(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshot {\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents = convertSummaryToISnapshot(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\nexport const getISnapshotFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshot => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x8e6 /* Protocol and App summary trees should be present */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToISnapshot(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport const combineSnapshotTreeAndSnapshotBlobs = ({\n\tblobContents,\n\tsnapshotTree,\n}: Pick<ISnapshot, \"blobContents\" | \"snapshotTree\">): ISnapshotTreeWithBlobContents => {\n\tconst currentTreeBlobs: { [path: string]: ArrayBufferLike } = {};\n\n\t// Process blobs in the current level\n\tfor (const [, id] of Object.entries(snapshotTree.blobs)) {\n\t\tconst blob = blobContents.get(id);\n\t\tif (blob !== undefined) {\n\t\t\tcurrentTreeBlobs[id] = blob;\n\t\t}\n\t}\n\n\t// Recursively process trees in the current level\n\tconst trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};\n\tfor (const [path, tree] of Object.entries(snapshotTree.trees)) {\n\t\ttrees[path] = combineSnapshotTreeAndSnapshotBlobs({ snapshotTree: tree, blobContents });\n\t}\n\n\t// Create a new snapshot tree with blob contents and processed trees\n\tconst snapshot: ISnapshotTreeWithBlobContents = {\n\t\t...snapshotTree,\n\t\tblobsContents: currentTreeBlobs,\n\t\ttrees,\n\t};\n\n\treturn snapshot;\n};\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: unknown,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t(error as Partial<IFluidErrorBase>)?.errorType ===\n\t\t\tDriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n\n/**\n * Validates format in parsed string get from detached container\n * serialization using IPendingDetachedContainerState format.\n */\nfunction isPendingDetachedContainerState(\n\tdetachedContainerState: IPendingDetachedContainerState,\n): detachedContainerState is IPendingDetachedContainerState {\n\tif (\n\t\tdetachedContainerState?.attached === undefined ||\n\t\tdetachedContainerState?.baseSnapshot === undefined ||\n\t\tdetachedContainerState?.snapshotBlobs === undefined ||\n\t\tdetachedContainerState?.hasAttachmentBlobs === undefined\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n/**\n * Converts an ISnapshot to a SnapshotWithBlobs, extracting and serializing its blob contents.\n * @param snapshot - The ISnapshot to convert.\n * @returns A SnapshotWithBlobs containing the base snapshot and serialized blob contents.\n */\nexport function convertISnapshotToSnapshotWithBlobs(snapshot: ISnapshot): SnapshotWithBlobs {\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [id, blob] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[id] = bufferToString(blob, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t};\n}\n\n/**\n * Parses the given string into {@link IPendingDetachedContainerState} format,\n * with validation (if invalid, throws a UsageError).\n * This is the inverse of the JSON.stringify call in {@link Container.serialize}\n */\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst snapshot = getISnapshotFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\t...convertISnapshotToSnapshotWithBlobs(snapshot),\n\t\t\thasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,\n\t\t};\n\t\treturn detachedContainerState;\n\t} else {\n\t\tthrow new UsageError(\"Cannot rehydrate detached container. Incorrect format\");\n\t}\n}\n\n/**\n * Blindly parses the given string into {@link IPendingContainerState} format.\n * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}\n */\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingContainerState;\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined;\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined {\n\treturn serializedContainer === undefined\n\t\t? undefined\n\t\t: (JSON.parse(serializedContainer) as IPendingContainerState);\n}\n\n/**\n * Ensures only a single instance of the provided async function is running.\n * If there are multiple calls they will all get the same promise to wait on.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const runSingle = <A extends any[], R>(\n\tfunc: (...args: A) => Promise<R>,\n): ((...args: A) => Promise<R>) => {\n\tlet running:\n\t\t| {\n\t\t\t\targs: A;\n\t\t\t\tresult: Promise<R>;\n\t\t }\n\t\t| undefined;\n\t// don't mark this function async, so we return the same promise,\n\t// rather than one that is wrapped due to async\n\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\treturn (...args: A): Promise<R> => {\n\t\tif (running !== undefined) {\n\t\t\tif (!compareArrays(running.args, args)) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew UsageError(\"Subsequent calls cannot use different arguments.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn running.result;\n\t\t}\n\t\trunning = { args, result: func(...args).finally(() => (running = undefined)) };\n\t\treturn running.result;\n\t};\n};\n\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tbufferToString,\n\tstringToBuffer,\n\tUint8ArrayToArrayBuffer,\n} from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { type ISummaryTree, SummaryType } from \"@fluidframework/driver-definitions\";\nimport {\n\tDriverErrorTypes,\n\ttype IDocumentAttributes,\n\ttype ISnapshotTree,\n\ttype IDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\ttype CombinedAppAndProtocolSummary,\n\ttype DeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tLoggingError,\n\tUsageError,\n\ttype IFluidErrorBase,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport type { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingContainerState,\n\tIPendingDetachedContainerState,\n\tSerializedSnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.js\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @legacy @beta\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Undefined means load latest snapshot, otherwise it's version ID passed to IDocumentStorageService.getVersions()\n\t * to figure out what snapshot to use.\n\t */\n\tversion: string | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @legacy @beta\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\t// `new URL(...)` throws `TypeError` for any string that isn't a well-formed\n\t// absolute URL. The `try*` name in this function's identifier implies a\n\t// non-throwing contract on bad input, and callers all gate on `=== undefined`\n\t// to surface their own errors — letting the built-in throw escape here would\n\t// bypass those caller-supplied error messages for the broadest class of bad\n\t// URLs (\"not absolute\", \"invalid characters\", etc.).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? {\n\t\t\t\tid: match[1],\n\t\t\t\tpath: match[2],\n\t\t\t\tquery,\n\t\t\t\t// URLSearchParams returns null if the param is not provided.\n\t\t\t\tversion: parsed.searchParams.get(\"version\") ?? undefined,\n\t\t\t}\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts a summary to snapshot tree and separate its blob contents\n * to align detached container format with IPendingContainerState\n * @param summary - ISummaryTree\n */\nfunction convertSummaryToISnapshot(\n\tsummary: ISummaryTree,\n\tblobContents = new Map<string, ArrayBuffer>(),\n): ISnapshot {\n\tconst snapshotTree: ISnapshotTree = {\n\t\tblobs: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t\tgroupId: summary.groupId,\n\t};\n\n\tfor (const [key, summaryObject] of Object.entries(summary.tree)) {\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst innerSnapshot = convertSummaryToISnapshot(summaryObject, blobContents);\n\t\t\t\tsnapshotTree.trees[key] = innerSnapshot.snapshotTree;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment: {\n\t\t\t\tsnapshotTree.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\tsnapshotTree.blobs[key] = blobId;\n\t\t\t\tblobContents.set(\n\t\t\t\t\tblobId,\n\t\t\t\t\tsummaryObject.content instanceof Uint8Array\n\t\t\t\t\t\t? Uint8ArrayToArrayBuffer(summaryObject.content)\n\t\t\t\t\t\t: stringToBuffer(summaryObject.content, \"utf8\"),\n\t\t\t\t);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle: {\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tblobContents,\n\t\tlatestSequenceNumber: undefined,\n\t\tops: [],\n\t\tsequenceNumber: 0,\n\t\tsnapshotFormatV: 1,\n\t\tsnapshotTree,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): SerializedSnapshotInfo {\n\tassert(\n\t\tsnapshot.sequenceNumber !== undefined,\n\t\t0x93a /* Snapshot sequence number is missing */,\n\t);\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: SerializedSnapshotInfo,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBuffer>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotInfo.snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\n}\n\n/**\n * Converts summary parts into a SnapshotTree and its blob contents.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nfunction convertProtocolAndAppSummaryToISnapshot(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshot {\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents = convertSummaryToISnapshot(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\nexport const getISnapshotFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshot => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x8e6 /* Protocol and App summary trees should be present */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToISnapshot(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport const combineSnapshotTreeAndSnapshotBlobs = ({\n\tblobContents,\n\tsnapshotTree,\n}: Pick<ISnapshot, \"blobContents\" | \"snapshotTree\">): ISnapshotTreeWithBlobContents => {\n\tconst currentTreeBlobs: { [path: string]: ArrayBufferLike } = {};\n\n\t// Process blobs in the current level\n\tfor (const [, id] of Object.entries(snapshotTree.blobs)) {\n\t\tconst blob = blobContents.get(id);\n\t\tif (blob !== undefined) {\n\t\t\tcurrentTreeBlobs[id] = blob;\n\t\t}\n\t}\n\n\t// Recursively process trees in the current level\n\tconst trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};\n\tfor (const [path, tree] of Object.entries(snapshotTree.trees)) {\n\t\ttrees[path] = combineSnapshotTreeAndSnapshotBlobs({ snapshotTree: tree, blobContents });\n\t}\n\n\t// Create a new snapshot tree with blob contents and processed trees\n\tconst snapshot: ISnapshotTreeWithBlobContents = {\n\t\t...snapshotTree,\n\t\tblobsContents: currentTreeBlobs,\n\t\ttrees,\n\t};\n\n\treturn snapshot;\n};\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: unknown,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t(error as Partial<IFluidErrorBase>)?.errorType ===\n\t\t\tDriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n\n/**\n * Validates format in parsed string get from detached container\n * serialization using IPendingDetachedContainerState format.\n */\nfunction isPendingDetachedContainerState(\n\tdetachedContainerState: IPendingDetachedContainerState,\n): detachedContainerState is IPendingDetachedContainerState {\n\tif (\n\t\tdetachedContainerState?.attached === undefined ||\n\t\tdetachedContainerState?.baseSnapshot === undefined ||\n\t\tdetachedContainerState?.snapshotBlobs === undefined ||\n\t\tdetachedContainerState?.hasAttachmentBlobs === undefined\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n/**\n * Converts an ISnapshot to a SnapshotWithBlobs, extracting and serializing its blob contents.\n * @param snapshot - The ISnapshot to convert.\n * @returns A SnapshotWithBlobs containing the base snapshot and serialized blob contents.\n */\nexport function convertISnapshotToSnapshotWithBlobs(snapshot: ISnapshot): SnapshotWithBlobs {\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [id, blob] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[id] = bufferToString(blob, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t};\n}\n\n/**\n * Parses the given string into {@link IPendingDetachedContainerState} format,\n * with validation (if invalid, throws a UsageError).\n * This is the inverse of the JSON.stringify call in {@link Container.serialize}\n */\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst snapshot = getISnapshotFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\t...convertISnapshotToSnapshotWithBlobs(snapshot),\n\t\t\thasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,\n\t\t};\n\t\treturn detachedContainerState;\n\t} else {\n\t\tthrow new UsageError(\"Cannot rehydrate detached container. Incorrect format\");\n\t}\n}\n\n/**\n * Blindly parses the given string into {@link IPendingContainerState} format.\n * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}\n */\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingContainerState;\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined;\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined {\n\treturn serializedContainer === undefined\n\t\t? undefined\n\t\t: (JSON.parse(serializedContainer) as IPendingContainerState);\n}\n\n/**\n * Ensures only a single instance of the provided async function is running.\n * If there are multiple calls they will all get the same promise to wait on.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const runSingle = <A extends any[], R>(\n\tfunc: (...args: A) => Promise<R>,\n): ((...args: A) => Promise<R>) => {\n\tlet running:\n\t\t| {\n\t\t\t\targs: A;\n\t\t\t\tresult: Promise<R>;\n\t\t }\n\t\t| undefined;\n\t// don't mark this function async, so we return the same promise,\n\t// rather than one that is wrapped due to async\n\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\treturn (...args: A): Promise<R> => {\n\t\tif (running !== undefined) {\n\t\t\tif (!compareArrays(running.args, args)) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew UsageError(\"Subsequent calls cannot use different arguments.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn running.result;\n\t\t}\n\t\trunning = { args, result: func(...args).finally(() => (running = undefined)) };\n\t\treturn running.result;\n\t};\n};\n\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.101.1",
3
+ "version": "2.103.0",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -129,13 +129,13 @@
129
129
  "temp-directory": "nyc/.nyc_output"
130
130
  },
131
131
  "dependencies": {
132
- "@fluid-internal/client-utils": "~2.101.1",
133
- "@fluidframework/container-definitions": "~2.101.1",
134
- "@fluidframework/core-interfaces": "~2.101.1",
135
- "@fluidframework/core-utils": "~2.101.1",
136
- "@fluidframework/driver-definitions": "~2.101.1",
137
- "@fluidframework/driver-utils": "~2.101.1",
138
- "@fluidframework/telemetry-utils": "~2.101.1",
132
+ "@fluid-internal/client-utils": "~2.103.0",
133
+ "@fluidframework/container-definitions": "~2.103.0",
134
+ "@fluidframework/core-interfaces": "~2.103.0",
135
+ "@fluidframework/core-utils": "~2.103.0",
136
+ "@fluidframework/driver-definitions": "~2.103.0",
137
+ "@fluidframework/driver-utils": "~2.103.0",
138
+ "@fluidframework/telemetry-utils": "~2.103.0",
139
139
  "debug": "^4.3.4",
140
140
  "double-ended-queue": "^2.1.0-0",
141
141
  "events_pkg": "npm:events@^3.1.0",
@@ -144,13 +144,13 @@
144
144
  "devDependencies": {
145
145
  "@arethetypeswrong/cli": "^0.18.2",
146
146
  "@biomejs/biome": "~2.4.5",
147
- "@fluid-internal/client-utils": "~2.101.1",
148
- "@fluid-internal/mocha-test-setup": "~2.101.1",
149
- "@fluid-private/test-loader-utils": "~2.101.1",
147
+ "@fluid-internal/client-utils": "~2.103.0",
148
+ "@fluid-internal/mocha-test-setup": "~2.103.0",
149
+ "@fluid-private/test-loader-utils": "~2.103.0",
150
150
  "@fluid-tools/build-cli": "^0.65.0",
151
151
  "@fluidframework/build-common": "^2.0.3",
152
152
  "@fluidframework/build-tools": "^0.65.0",
153
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.92.0",
153
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.101.0",
154
154
  "@fluidframework/eslint-config-fluid": "^9.0.0",
155
155
  "@microsoft/api-extractor": "7.58.1",
156
156
  "@types/debug": "^4.1.5",