@fluidframework/odsp-driver 0.56.5 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createFile.d.ts.map +1 -1
- package/dist/createFile.js +4 -3
- package/dist/createFile.js.map +1 -1
- package/dist/createOdspUrl.d.ts.map +1 -1
- package/dist/createOdspUrl.js.map +1 -1
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +3 -2
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +1 -0
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.d.ts.map +1 -1
- package/dist/getFileLink.js +3 -2
- package/dist/getFileLink.js.map +1 -1
- package/dist/getQueryString.d.ts.map +1 -1
- package/dist/getQueryString.js.map +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts +6 -6
- package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/odspDocumentDeltaConnection.js +1 -0
- package/dist/odspDocumentDeltaConnection.js.map +1 -1
- package/dist/odspDocumentService.d.ts.map +1 -1
- package/dist/odspDocumentService.js +3 -2
- package/dist/odspDocumentService.js.map +1 -1
- package/dist/odspDocumentStorageManager.d.ts.map +1 -1
- package/dist/odspDocumentStorageManager.js +7 -6
- package/dist/odspDocumentStorageManager.js.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.js +2 -1
- package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/dist/odspSummaryUploadManager.d.ts.map +1 -1
- package/dist/odspSummaryUploadManager.js +4 -1
- package/dist/odspSummaryUploadManager.js.map +1 -1
- package/dist/odspUtils.d.ts.map +1 -1
- package/dist/odspUtils.js +6 -6
- package/dist/odspUtils.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/retryUtils.js.map +1 -1
- package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/dist/zipItDataRepresentationUtils.js +2 -0
- package/dist/zipItDataRepresentationUtils.js.map +1 -1
- package/lib/createFile.d.ts.map +1 -1
- package/lib/createFile.js +4 -3
- package/lib/createFile.js.map +1 -1
- package/lib/createOdspUrl.d.ts.map +1 -1
- package/lib/createOdspUrl.js.map +1 -1
- package/lib/epochTracker.d.ts.map +1 -1
- package/lib/epochTracker.js +3 -2
- package/lib/epochTracker.js.map +1 -1
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +1 -0
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/getFileLink.d.ts.map +1 -1
- package/lib/getFileLink.js +3 -2
- package/lib/getFileLink.js.map +1 -1
- package/lib/getQueryString.d.ts.map +1 -1
- package/lib/getQueryString.js.map +1 -1
- package/lib/odspDocumentDeltaConnection.d.ts +6 -6
- package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/lib/odspDocumentDeltaConnection.js +1 -0
- package/lib/odspDocumentDeltaConnection.js.map +1 -1
- package/lib/odspDocumentService.d.ts.map +1 -1
- package/lib/odspDocumentService.js +3 -2
- package/lib/odspDocumentService.js.map +1 -1
- package/lib/odspDocumentStorageManager.d.ts.map +1 -1
- package/lib/odspDocumentStorageManager.js +7 -6
- package/lib/odspDocumentStorageManager.js.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.js +2 -1
- package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/lib/odspSummaryUploadManager.d.ts.map +1 -1
- package/lib/odspSummaryUploadManager.js +4 -1
- package/lib/odspSummaryUploadManager.js.map +1 -1
- package/lib/odspUtils.d.ts.map +1 -1
- package/lib/odspUtils.js +9 -9
- package/lib/odspUtils.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/retryUtils.js.map +1 -1
- package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/lib/zipItDataRepresentationUtils.js +2 -0
- package/lib/zipItDataRepresentationUtils.js.map +1 -1
- package/package.json +8 -8
- package/src/createFile.ts +6 -3
- package/src/createOdspUrl.ts +1 -1
- package/src/epochTracker.ts +4 -2
- package/src/fetchSnapshot.ts +7 -6
- package/src/getFileLink.ts +5 -2
- package/src/getQueryString.ts +1 -1
- package/src/odspDocumentDeltaConnection.ts +9 -8
- package/src/odspDocumentService.ts +4 -2
- package/src/odspDocumentStorageManager.ts +12 -8
- package/src/odspDriverUrlResolverForShareLink.ts +3 -1
- package/src/odspSummaryUploadManager.ts +4 -1
- package/src/odspUtils.ts +14 -9
- package/src/packageVersion.ts +1 -1
- package/src/retryUtils.ts +1 -1
- package/src/zipItDataRepresentationUtils.ts +2 -0
|
@@ -15,6 +15,7 @@ const getUrlAndHeadersWithAuth_1 = require("./getUrlAndHeadersWithAuth");
|
|
|
15
15
|
const odspUtils_1 = require("./odspUtils");
|
|
16
16
|
const epochTracker_1 = require("./epochTracker");
|
|
17
17
|
const odspSummaryUploadManager_1 = require("./odspSummaryUploadManager");
|
|
18
|
+
const packageVersion_1 = require("./packageVersion");
|
|
18
19
|
/* eslint-disable max-len */
|
|
19
20
|
// An implementation of Promise.race that gives you the winner of the promise race
|
|
20
21
|
async function promiseRaceWithWinner(promises) {
|
|
@@ -391,10 +392,10 @@ class OdspDocumentStorageService {
|
|
|
391
392
|
}, async () => this.epochTracker.fetchAndParseAsJSON(url, { headers }, "versions"));
|
|
392
393
|
const versionsResponse = response.content;
|
|
393
394
|
if (!versionsResponse) {
|
|
394
|
-
throw new driver_utils_1.NonRetryableError("getVersionsReturnedNoResponse", "No response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError);
|
|
395
|
+
throw new driver_utils_1.NonRetryableError("getVersionsReturnedNoResponse", "No response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError, { driverVersion: packageVersion_1.pkgVersion });
|
|
395
396
|
}
|
|
396
397
|
if (!Array.isArray(versionsResponse.value)) {
|
|
397
|
-
throw new driver_utils_1.NonRetryableError("getVersionsReturnedNonArrayResponse", "Incorrect response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError);
|
|
398
|
+
throw new driver_utils_1.NonRetryableError("getVersionsReturnedNonArrayResponse", "Incorrect response from /versions endpoint", driver_definitions_1.DriverErrorType.genericNetworkError, { driverVersion: packageVersion_1.pkgVersion });
|
|
398
399
|
}
|
|
399
400
|
return versionsResponse.value.map((version) => {
|
|
400
401
|
// Parse the date from the message
|
|
@@ -492,7 +493,7 @@ class OdspDocumentStorageService {
|
|
|
492
493
|
await common_utils_1.delay(1000 * ((_a = result.retryAfter) !== null && _a !== void 0 ? _a : 1));
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
|
-
const id = await
|
|
496
|
+
const id = await this.odspSummaryUploadManager.writeSummaryTree(summary, context);
|
|
496
497
|
return id;
|
|
497
498
|
}
|
|
498
499
|
async downloadSummary(commit) {
|
|
@@ -506,17 +507,17 @@ class OdspDocumentStorageService {
|
|
|
506
507
|
}
|
|
507
508
|
checkSnapshotUrl() {
|
|
508
509
|
if (!this.snapshotUrl) {
|
|
509
|
-
throw new driver_utils_1.NonRetryableError("noSnapshotUrlProvided", "Method failed because no snapshot url was available", driver_definitions_1.DriverErrorType.genericError);
|
|
510
|
+
throw new driver_utils_1.NonRetryableError("noSnapshotUrlProvided", "Method failed because no snapshot url was available", driver_definitions_1.DriverErrorType.genericError, { driverVersion: packageVersion_1.pkgVersion });
|
|
510
511
|
}
|
|
511
512
|
}
|
|
512
513
|
checkAttachmentPOSTUrl() {
|
|
513
514
|
if (!this.attachmentPOSTUrl) {
|
|
514
|
-
throw new driver_utils_1.NonRetryableError("noAttachmentPOSTUrlProvided", "Method failed because no attachment POST url was available", driver_definitions_1.DriverErrorType.genericError);
|
|
515
|
+
throw new driver_utils_1.NonRetryableError("noAttachmentPOSTUrlProvided", "Method failed because no attachment POST url was available", driver_definitions_1.DriverErrorType.genericError, { driverVersion: packageVersion_1.pkgVersion });
|
|
515
516
|
}
|
|
516
517
|
}
|
|
517
518
|
checkAttachmentGETUrl() {
|
|
518
519
|
if (!this.attachmentGETUrl) {
|
|
519
|
-
throw new driver_utils_1.NonRetryableError("noAttachmentGETUrlWasProvided", "Method failed because no attachment GET url was available", driver_definitions_1.DriverErrorType.genericError);
|
|
520
|
+
throw new driver_utils_1.NonRetryableError("noAttachmentGETUrlWasProvided", "Method failed because no attachment GET url was available", driver_definitions_1.DriverErrorType.genericError, { driverVersion: packageVersion_1.pkgVersion });
|
|
520
521
|
}
|
|
521
522
|
}
|
|
522
523
|
async readTree(id) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDocumentStorageManager.js","sourceRoot":"","sources":["../src/odspDocumentStorageManager.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 { default as AbortController } from \"abort-controller\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n assert,\n delay,\n} from \"@fluidframework/common-utils\";\nimport {\n PerformanceEvent,\n} from \"@fluidframework/telemetry-utils\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport {\n ISummaryContext,\n IDocumentStorageService,\n LoaderCachingPolicy,\n DriverErrorType,\n} from \"@fluidframework/driver-definitions\";\nimport { RateLimiter, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport {\n IOdspResolvedUrl,\n ISnapshotOptions,\n OdspErrorType,\n InstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport {\n IDocumentStorageGetVersionsResponse,\n HostStoragePolicyInternal,\n IVersionedValueWithEpoch,\n ISnapshotCachedEntry,\n} from \"./contracts\";\nimport { downloadSnapshot, fetchSnapshot, fetchSnapshotWithRedeem } from \"./fetchSnapshot\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { IOdspCache } from \"./odspCache\";\nimport {\n createCacheSnapshotKey,\n getWithRetryForTokenRefresh,\n ISnapshotContents,\n} from \"./odspUtils\";\nimport { defaultCacheExpiryTimeoutMs, EpochTracker } from \"./epochTracker\";\nimport { OdspSummaryUploadManager } from \"./odspSummaryUploadManager\";\nimport { FlushResult } from \"./odspDocumentDeltaConnection\";\n\n/* eslint-disable max-len */\n\n// An implementation of Promise.race that gives you the winner of the promise race\nasync function promiseRaceWithWinner<T>(promises: Promise<T>[]): Promise<{ index: number, value: T }> {\n return new Promise((resolve, reject) => {\n promises.forEach((p, index) => {\n p.then((v) => resolve({ index, value: v })).catch(reject);\n });\n });\n}\n\nclass BlobCache {\n // Save the timeout so we can cancel and reschedule it as needed\n private blobCacheTimeout: ReturnType<typeof setTimeout> | undefined;\n // If the defer flag is set when the timeout fires, we'll reschedule rather than clear immediately\n // This deferral approach is used (rather than clearing/resetting the timer) as current calling patterns trigger\n // too many calls to setTimeout/clearTimeout.\n private deferBlobCacheClear: boolean = false;\n\n private readonly _blobCache: Map<string, ArrayBuffer> = new Map();\n\n // Tracks all blob IDs evicted from cache\n private readonly blobsEvicted: Set<string> = new Set();\n\n // Initial time-out to purge data from cache\n // If this time out is very small, then we purge blobs from cache too soon and that results in a lot of\n // requests to storage, which brings down perf and may trip protection limits causing 429s\n private blobCacheTimeoutDuration = 2 * 60 * 1000;\n\n // SPO does not keep old snapshots around for long, so we are running chances of not\n // being able to rehydrate data store / DDS in the future if we purge anything (and with blob de-duping,\n // even if blob read by runtime, it could be read again in the future)\n // So for now, purging is disabled.\n private readonly purgeEnabled = false;\n\n public get value() {\n return this._blobCache;\n }\n\n public addBlobs(blobs: Map<string, ArrayBuffer>) {\n blobs.forEach((value, blobId) => {\n this._blobCache.set(blobId, value);\n });\n // Reset the timer on cache set\n this.scheduleClearBlobsCache();\n }\n\n /**\n * Schedule a timer for clearing the blob cache or defer the current one.\n */\n private scheduleClearBlobsCache() {\n if (this.blobCacheTimeout !== undefined) {\n // If we already have an outstanding timer, just signal that we should defer the clear\n this.deferBlobCacheClear = true;\n } else if (this.purgeEnabled) {\n // If we don't have an outstanding timer, set a timer\n // When the timer runs out, we'll decide whether to proceed with the cache clear or reset the timer\n const clearCacheOrDefer = () => {\n this.blobCacheTimeout = undefined;\n if (this.deferBlobCacheClear) {\n this.deferBlobCacheClear = false;\n this.scheduleClearBlobsCache();\n } else {\n // NOTE: Slightly better algorithm here would be to purge either only big blobs,\n // or sort them by size and purge enough big blobs to leave only 256Kb of small blobs in cache\n // Purging is optimizing memory footprint. But count controls potential number of storage requests\n // We want to optimize both - memory footprint and number of future requests to storage.\n // Note that Container can realize data store or DDS on-demand at any point in time, so we do not\n // control when blobs will be used.\n this._blobCache.forEach((_, blobId) => this.blobsEvicted.add(blobId));\n this._blobCache.clear();\n }\n };\n this.blobCacheTimeout = setTimeout(clearCacheOrDefer, this.blobCacheTimeoutDuration);\n // any future storage reads that get into the cache should be cleared from cache rather quickly -\n // there is not much value in keeping them longer\n this.blobCacheTimeoutDuration = 10 * 1000;\n }\n }\n\n public getBlob(blobId: string) {\n // Reset the timer on attempted cache read\n this.scheduleClearBlobsCache();\n const blobContent = this._blobCache.get(blobId);\n const evicted = this.blobsEvicted.has(blobId);\n return { blobContent, evicted };\n }\n\n public setBlob(blobId: string, blob: ArrayBuffer) {\n // This API is called as result of cache miss and reading blob from storage.\n // Runtime never reads same blob twice.\n // The only reason we may get read request for same blob is blob de-duping in summaries.\n // Note that the bigger the size, the less likely blobs are the same, so there is very little benefit of caching big blobs.\n // Images are the only exception - user may insert same image twice. But we currently do not de-dup them - only snapshot\n // blobs are de-duped.\n const size = blob.byteLength;\n if (size < 256 * 1024) {\n // Reset the timer on cache set\n this.scheduleClearBlobsCache();\n return this._blobCache.set(blobId, blob);\n } else {\n // we evicted it here by not caching.\n this.blobsEvicted.add(blobId);\n }\n }\n}\n\nexport class OdspDocumentStorageService implements IDocumentStorageService {\n readonly policies = {\n // By default, ODSP tells the container not to prefetch/cache.\n caching: LoaderCachingPolicy.NoCaching,\n\n // ODSP storage works better if it has less number of blobs / edges\n // Runtime creating many small blobs results in sub-optimal perf.\n // 2K seems like the sweat spot:\n // The smaller the number, less blobs we aggregate. Most storages are very likely to have notion\n // of minimal \"cluster\" size, so having small blobs is wasteful\n // At the same time increasing the limit ensure that more blobs with user content are aggregated,\n // reducing possibility for de-duping of same blobs (i.e. .attributes rolled into aggregate blob\n // are not reused across data stores, or even within data store, resulting in duplication of content)\n // Note that duplication of content should not have significant impact for bytes over wire as\n // compression of http payload mostly takes care of it, but it does impact storage size and in-memory sizes.\n minBlobSize: 2048,\n maximumCacheDurationMs: defaultCacheExpiryTimeoutMs,\n };\n\n private readonly commitCache: Map<string, api.ISnapshotTree> = new Map();\n\n private readonly attributesBlobHandles: Set<string> = new Set();\n\n private readonly odspSummaryUploadManager: OdspSummaryUploadManager;\n private _ops: api.ISequencedDocumentMessage[] | undefined;\n\n private firstVersionCall = true;\n private _snapshotSequenceNumber: number | undefined;\n\n private readonly documentId: string;\n private readonly snapshotUrl: string | undefined;\n private readonly attachmentPOSTUrl: string | undefined;\n private readonly attachmentGETUrl: string | undefined;\n // Driver specified limits for snapshot size and time.\n /**\n * NOTE: While commit cfff6e3 added restrictions to prevent large payloads, snapshot failures will continue to\n * happen until blob request throttling is implemented. Until then, as a temporary fix we set arbitrarily large\n * snapshot size and timeout limits so that such failures are unlikely to occur.\n */\n private readonly maxSnapshotSizeLimit = 500000000; // 500 MB\n private readonly maxSnapshotFetchTimeout = 120000; // 2 min\n\n // limits the amount of parallel \"attachment\" blob uploads\n private readonly createBlobRateLimiter = new RateLimiter(1);\n\n private readonly blobCache = new BlobCache();\n\n public set ops(ops: api.ISequencedDocumentMessage[] | undefined) {\n assert(this._ops === undefined, 0x0a5 /* \"Trying to set ops when they are already set!\" */);\n this._ops = ops;\n }\n\n public get ops(): api.ISequencedDocumentMessage[] | undefined {\n return this._ops;\n }\n\n public get snapshotSequenceNumber() {\n return this._snapshotSequenceNumber;\n }\n\n constructor(\n private readonly odspResolvedUrl: IOdspResolvedUrl,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n private readonly logger: ITelemetryLogger,\n private readonly fetchFullSnapshot: boolean,\n private readonly cache: IOdspCache,\n private readonly hostPolicy: HostStoragePolicyInternal,\n private readonly epochTracker: EpochTracker,\n private readonly flushCallback: () => Promise<FlushResult>,\n ) {\n this.documentId = this.odspResolvedUrl.hashedDocumentId;\n this.snapshotUrl = this.odspResolvedUrl.endpoints.snapshotStorageUrl;\n this.attachmentPOSTUrl = this.odspResolvedUrl.endpoints.attachmentPOSTStorageUrl;\n this.attachmentGETUrl = this.odspResolvedUrl.endpoints.attachmentGETStorageUrl;\n this.odspSummaryUploadManager = new OdspSummaryUploadManager(\n this.snapshotUrl,\n getStorageToken,\n logger,\n epochTracker,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n }\n\n public get repositoryUrl(): string {\n return \"\";\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<api.ICreateBlobResponse> {\n this.checkAttachmentPOSTUrl();\n\n const response = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"CreateBlob\");\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.attachmentPOSTUrl}/content`,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/octet-stream\";\n\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"createBlob\",\n size: file.byteLength,\n waitQueueLength: this.createBlobRateLimiter.waitQueueLength,\n },\n async (event) => {\n const res = await this.createBlobRateLimiter.schedule(async () =>\n this.epochTracker.fetchAndParseAsJSON<api.ICreateBlobResponse>(\n url,\n {\n body: file,\n headers,\n method: \"POST\",\n },\n \"createBlob\",\n ));\n event.end({\n blobId: res.content.id,\n ...res.propsToLog,\n });\n return res;\n },\n );\n });\n\n return response.content;\n }\n\n private async readBlobCore(blobId: string): Promise<ArrayBuffer> {\n const { blobContent, evicted } = this.blobCache.getBlob(blobId);\n let blob = blobContent;\n\n if (blob === undefined) {\n this.checkAttachmentGETUrl();\n\n blob = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"GetBlob\");\n const unAuthedUrl = `${this.attachmentGETUrl}/${encodeURIComponent(blobId)}/content`;\n const { url, headers } = getUrlAndHeadersWithAuth(\n unAuthedUrl,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"readDataBlob\",\n blobId,\n evicted,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n waitQueueLength: this.epochTracker.rateLimiter.waitQueueLength,\n },\n async (event) => {\n const res = await this.epochTracker.fetchArray(url, { headers }, \"blob\");\n event.end({\n waitQueueLength: this.epochTracker.rateLimiter.waitQueueLength,\n ...res.propsToLog,\n attempts: options.refresh ? 2 : 1,\n });\n const cacheControl = res.headers.get(\"cache-control\");\n if (cacheControl === undefined || !(cacheControl.includes(\"private\") || cacheControl.includes(\"public\"))) {\n this.logger.sendErrorEvent({\n eventName: \"NonCacheableBlob\",\n cacheControl,\n blobId,\n ...res.propsToLog,\n });\n }\n return res.content;\n },\n );\n });\n this.blobCache.setBlob(blobId, blob);\n }\n\n return blob;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.readBlobCore(blobId);\n }\n\n public async getSnapshotTree(version?: api.IVersion): Promise<api.ISnapshotTree | null> {\n if (!this.snapshotUrl) {\n return null;\n }\n\n let id: string;\n if (!version || !version.id) {\n const versions = await this.getVersions(null, 1);\n if (!versions || versions.length === 0) {\n return null;\n }\n id = versions[0].id;\n } else {\n id = version.id;\n }\n\n const snapshotTree = await this.readTree(id);\n if (!snapshotTree) {\n return null;\n }\n // Decode commit paths\n const commits = {};\n\n for (const key of Object.keys(snapshotTree.commits)) {\n commits[decodeURIComponent(key)] = snapshotTree.commits[key];\n }\n\n let finalTree: api.ISnapshotTree;\n // For container loaded from detach new summary, we will not have a commit for \".app\" in downloaded summary as the client uploaded both\n // \".app\" and \".protocol\" trees by itself. For other summaries, we will have \".app\" as commit because client previously only uploaded the\n // app summary.\n if (commits && commits[\".app\"]) {\n // The latest snapshot is a summary\n // attempt to read .protocol from commits for backwards compat\n finalTree = await this.readSummaryTree(commits[\".protocol\"] || snapshotTree.trees[\".protocol\"], commits[\".app\"] as string);\n } else {\n if (snapshotTree.blobs) {\n const attributesBlob = snapshotTree.blobs.attributes;\n if (attributesBlob) {\n this.attributesBlobHandles.add(attributesBlob);\n }\n }\n\n snapshotTree.commits = commits;\n\n // When we upload the container snapshot, we upload appTree in \".app\" and protocol tree in \".protocol\"\n // So when we request the snapshot we get \".app\" as tree and not as commit node as in the case just above.\n const appTree = snapshotTree.trees[\".app\"];\n const protocolTree = snapshotTree.trees[\".protocol\"];\n finalTree = this.combineProtocolAndAppSnapshotTree(appTree, protocolTree);\n }\n return finalTree;\n }\n\n public async getVersions(blobid: string | null, count: number): Promise<api.IVersion[]> {\n // Regular load workflow uses blobId === documentID to indicate \"latest\".\n if (blobid !== this.documentId && blobid) {\n // FluidFetch & FluidDebugger tools use empty sting to query for versions\n // In such case we need to make a call against SPO to give full picture to the tool.\n // Otherwise, each commit calls getVersions but odsp doesn't have a history for each commit\n // return the blobid as is\n return [\n {\n id: blobid,\n treeId: undefined!,\n },\n ];\n }\n\n // Can't really make a call if we do not have URL\n if (!this.snapshotUrl) {\n return [];\n }\n\n // If count is one, we can use the trees/latest API, which returns the latest version and trees in a single request for better performance\n // Do it only once - we might get more here due to summarizer - it needs only container tree, not full snapshot.\n if (this.firstVersionCall && count === 1 && (blobid === null || blobid === this.documentId)) {\n const hostSnapshotOptions = this.hostPolicy.snapshotOptions;\n const odspSnapshotCacheValue: ISnapshotContents = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"ObtainSnapshot\" },\n async (event: PerformanceEvent) => {\n const props = {};\n let retrievedSnapshot: ISnapshotContents | undefined;\n // Here's the logic to grab the persistent cache snapshot implemented by the host\n // Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions\n const cachedSnapshotP: Promise<ISnapshotContents | undefined> =\n this.epochTracker.get(createCacheSnapshotKey(this.odspResolvedUrl))\n .then(async (snapshotCachedEntry: ISnapshotCachedEntry) => {\n if (snapshotCachedEntry !== undefined) {\n // If the cached entry does not contain the entry time, then assign it a default of 30 days old.\n const age = Date.now() - (snapshotCachedEntry.cacheEntryTime ??\n (Date.now() - 30 * 24 * 60 * 60 * 1000));\n\n // Record the cache age\n // eslint-disable-next-line @typescript-eslint/dot-notation\n props[\"cacheEntryAge\"] = age;\n }\n\n return snapshotCachedEntry;\n });\n\n // Based on the concurrentSnapshotFetch policy:\n // Either retrieve both the network and cache snapshots concurrently and pick the first to return,\n // or grab the cache value and then the network value if the cache value returns undefined.\n let method: string;\n if (this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {\n const networkSnapshotP = this.fetchSnapshot(hostSnapshotOptions);\n\n // Ensure that failures on both paths are ignored initially.\n // I.e. if cache fails for some reason, we will proceed with network result.\n // And vice versa - if (for example) client is offline and network request fails first, we\n // do want to attempt to succeed with cached data!\n const promiseRaceWinner = await promiseRaceWithWinner([\n cachedSnapshotP.catch(() => undefined),\n networkSnapshotP.catch(() => undefined),\n ]);\n retrievedSnapshot = promiseRaceWinner.value;\n method = promiseRaceWinner.index === 0 ? \"cache\" : \"network\";\n\n if (retrievedSnapshot === undefined) {\n // if network failed -> wait for cache ( then return network failure)\n // If cache returned empty or failed -> wait for network (success of failure)\n if (promiseRaceWinner.index === 1) {\n retrievedSnapshot = await cachedSnapshotP;\n method = \"cache\";\n }\n if (retrievedSnapshot === undefined) {\n retrievedSnapshot = await networkSnapshotP;\n method = \"network\";\n }\n }\n } else {\n // Note: There's a race condition here - another caller may come past the undefined check\n // while the first caller is awaiting later async code in this block.\n\n retrievedSnapshot = await cachedSnapshotP;\n\n method = retrievedSnapshot !== undefined ? \"cache\" : \"network\";\n\n if (retrievedSnapshot === undefined) {\n retrievedSnapshot = await this.fetchSnapshot(hostSnapshotOptions);\n }\n }\n if (method === \"network\") {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n props[\"cacheEntryAge\"] = undefined;\n }\n event.end({ ...props, method });\n return retrievedSnapshot;\n },\n );\n\n // Successful call, make network calls only\n this.firstVersionCall = false;\n\n this._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;\n const { snapshotTree, blobs, ops } = odspSnapshotCacheValue;\n // id should be undefined in case of just ops in snapshot.\n let id: string | undefined;\n if (snapshotTree) {\n id = snapshotTree.id;\n assert(id !== undefined, 0x221 /* \"Root tree should contain the id\" */);\n this.setRootTree(id, snapshotTree);\n }\n if (blobs) {\n this.initBlobsCache(blobs);\n }\n\n this.ops = ops;\n return id ? [{ id, treeId: undefined! }] : [];\n }\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"GetVersions\");\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/versions?count=${count}`,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n\n // Fetch the latest snapshot versions for the document\n const response = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getVersions\",\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n },\n async () => this.epochTracker.fetchAndParseAsJSON<IDocumentStorageGetVersionsResponse>(url, { headers }, \"versions\"),\n );\n const versionsResponse = response.content;\n if (!versionsResponse) {\n throw new NonRetryableError(\n \"getVersionsReturnedNoResponse\",\n \"No response from /versions endpoint\",\n DriverErrorType.genericNetworkError);\n }\n if (!Array.isArray(versionsResponse.value)) {\n throw new NonRetryableError(\n \"getVersionsReturnedNonArrayResponse\",\n \"Incorrect response from /versions endpoint\",\n DriverErrorType.genericNetworkError);\n }\n return versionsResponse.value.map((version) => {\n // Parse the date from the message\n let date: string | undefined;\n for (const rec of version.message.split(\"\\n\")) {\n const index = rec.indexOf(\":\");\n if (index !== -1 && rec.substr(0, index) === \"Date\") {\n date = rec.substr(index + 1).trim();\n break;\n }\n }\n return {\n date,\n id: version.id,\n treeId: undefined!,\n };\n });\n });\n }\n\n private async fetchSnapshot(hostSnapshotOptions: ISnapshotOptions | undefined) {\n return this.fetchSnapshotCore(hostSnapshotOptions).catch((error) => {\n // Issue #5895:\n // If we are offline, this error is retryable. But that means that RetriableDocumentStorageService\n // will run in circles calling getSnapshotTree, which would result in OdspDocumentStorageService class\n // going getVersions / individual blob download path. This path is very slow, and will not work with\n // delay-loaded data stores and ODSP storage deleting old snapshots and blobs.\n if (typeof error === \"object\" && error !== null) {\n error.canRetry = false;\n }\n throw error;\n });\n }\n\n private async fetchSnapshotCore(hostSnapshotOptions: ISnapshotOptions | undefined) {\n const snapshotOptions: ISnapshotOptions = {\n mds: this.maxSnapshotSizeLimit,\n ...hostSnapshotOptions,\n timeout: hostSnapshotOptions?.timeout ? Math.min(hostSnapshotOptions.timeout, this.maxSnapshotFetchTimeout) : this.maxSnapshotFetchTimeout,\n };\n\n // No limit on size of snapshot or time to fetch, as otherwise we fail all clients to summarize\n if (this.hostPolicy.summarizerClient) {\n snapshotOptions.mds = undefined;\n snapshotOptions.timeout = undefined;\n }\n\n const snapshotDownloader = async (\n finalOdspResolvedUrl: IOdspResolvedUrl,\n storageToken: string,\n options: ISnapshotOptions | undefined,\n controller?: AbortController,\n ) => {\n return downloadSnapshot(\n finalOdspResolvedUrl,\n storageToken,\n this.logger,\n options,\n this.hostPolicy.fetchBinarySnapshotFormat,\n controller,\n this.epochTracker,\n );\n };\n const putInCache = async (valueWithEpoch: IVersionedValueWithEpoch) => {\n return this.cache.persistedCache.put(\n createCacheSnapshotKey(this.odspResolvedUrl),\n // Epoch tracker will add the epoch and version to the value here. So just send value to cache.\n valueWithEpoch.value,\n );\n };\n const removeEntries = async () => this.cache.persistedCache.removeEntries();\n try {\n const odspSnapshot = await fetchSnapshotWithRedeem(\n this.odspResolvedUrl,\n this.getStorageToken,\n snapshotOptions,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n putInCache,\n removeEntries,\n this.hostPolicy.enableRedeemFallback,\n );\n return odspSnapshot;\n } catch (error) {\n const errorType = error.errorType;\n // If the snapshot size is too big and the host specified the size limitation(specified in hostSnapshotOptions), then don't try to fetch the snapshot again.\n if ((errorType === OdspErrorType.snapshotTooBig && hostSnapshotOptions?.mds !== undefined) && (this.hostPolicy.summarizerClient !== true)) {\n throw error;\n }\n // If the first snapshot request was with blobs and we either timed out or the size was too big, then try to fetch without blobs.\n if ((errorType === OdspErrorType.snapshotTooBig || errorType === OdspErrorType.fetchTimeout) && snapshotOptions.blobs) {\n this.logger.sendErrorEvent({\n eventName: \"TreeLatest_SecondCall\",\n errorType,\n });\n const snapshotOptionsWithoutBlobs: ISnapshotOptions = { ...snapshotOptions, blobs: 0, mds: undefined, timeout: undefined };\n const odspSnapshot = await fetchSnapshotWithRedeem(\n this.odspResolvedUrl,\n this.getStorageToken,\n snapshotOptionsWithoutBlobs,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n putInCache,\n removeEntries,\n this.hostPolicy.enableRedeemFallback,\n );\n return odspSnapshot;\n }\n throw error;\n }\n }\n\n public async write(tree: api.ITree, parents: string[], message: string): Promise<api.IVersion> {\n this.checkSnapshotUrl();\n\n throw new Error(\"Not supported\");\n }\n\n public async uploadSummaryWithContext(summary: api.ISummaryTree, context: ISummaryContext): Promise<string> {\n this.checkSnapshotUrl();\n\n // Enable flushing only if we have single commit summary and this is not the initial summary for an empty file\n if (\".protocol\" in summary.tree && context.ackHandle !== undefined) {\n let retry = 0;\n for (;;) {\n const result = await this.flushCallback();\n const seq = result.lastPersistedSequenceNumber;\n if (seq !== undefined && seq >= context.referenceSequenceNumber) {\n break;\n }\n\n retry++;\n if (retry > 3) {\n this.logger.sendErrorEvent({\n eventName: \"FlushFailure\",\n ...result,\n retry,\n referenceSequenceNumber: context.referenceSequenceNumber,\n });\n break;\n }\n\n this.logger.sendPerformanceEvent({\n eventName: \"FlushExtraCall\",\n ...result,\n retry,\n referenceSequenceNumber: context.referenceSequenceNumber,\n });\n\n await delay(1000 * (result.retryAfter ?? 1));\n }\n }\n\n const id = await PerformanceEvent.timedExecAsync(this.logger,\n { eventName: \"uploadSummaryWithContext\" },\n async () => this.odspSummaryUploadManager.writeSummaryTree(summary, context));\n return id;\n }\n\n public async downloadSummary(commit: api.ISummaryHandle): Promise<api.ISummaryTree> {\n throw new Error(\"Not implemented yet\");\n }\n\n private setRootTree(id: string, tree: api.ISnapshotTree) {\n this.commitCache.set(id, tree);\n }\n\n private initBlobsCache(blobs: Map<string, ArrayBuffer>) {\n this.blobCache.addBlobs(blobs);\n }\n\n private checkSnapshotUrl() {\n if (!this.snapshotUrl) {\n throw new NonRetryableError(\n \"noSnapshotUrlProvided\",\n \"Method failed because no snapshot url was available\",\n DriverErrorType.genericError);\n }\n }\n\n private checkAttachmentPOSTUrl() {\n if (!this.attachmentPOSTUrl) {\n throw new NonRetryableError(\n \"noAttachmentPOSTUrlProvided\",\n \"Method failed because no attachment POST url was available\",\n DriverErrorType.genericError);\n }\n }\n\n private checkAttachmentGETUrl() {\n if (!this.attachmentGETUrl) {\n throw new NonRetryableError(\n \"noAttachmentGETUrlWasProvided\",\n \"Method failed because no attachment GET url was available\",\n DriverErrorType.genericError);\n }\n }\n\n private async readTree(id: string): Promise<api.ISnapshotTree | null> {\n if (!this.snapshotUrl) {\n return null;\n }\n let tree = this.commitCache.get(id);\n if (!tree) {\n tree = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"ReadCommit\");\n const snapshotDownloader = async (url: string, fetchOptions: {[index: string]: any}) => {\n return this.epochTracker.fetchAndParseAsJSON(\n url,\n fetchOptions,\n \"snapshotTree\",\n );\n };\n const snapshot = await fetchSnapshot(\n this.snapshotUrl!,\n storageToken,\n id,\n this.fetchFullSnapshot,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n );\n let treeId = \"\";\n if (snapshot.snapshotTree) {\n assert(snapshot.snapshotTree.id !== undefined, 0x222 /* \"Root tree should contain the id!!\" */);\n treeId = snapshot.snapshotTree.id;\n this.setRootTree(treeId, snapshot.snapshotTree);\n }\n if (snapshot.blobs) {\n this.initBlobsCache(snapshot.blobs);\n }\n // If the version id doesn't match with the id of the tree, then use the id of first tree which in that case\n // will be the actual id of tree to be fetched.\n return this.commitCache.get(id) ?? this.commitCache.get(treeId);\n });\n }\n\n if (!tree) {\n return null;\n }\n\n return tree;\n }\n\n /**\n * Reads a summary tree\n * @param protocolTreeOrId - Protocol snapshot tree or id of the protocol tree\n * @param appTreeId - Id of the app tree\n */\n private async readSummaryTree(protocolTreeOrId: api.ISnapshotTree | string, appTreeId: string): Promise<api.ISnapshotTree> {\n // Load the app and protocol trees and return them\n let hierarchicalProtocolTree: api.ISnapshotTree | null;\n if (typeof (protocolTreeOrId) === \"string\") {\n // Backwards compat for older summaries\n hierarchicalProtocolTree = await this.readTree(protocolTreeOrId);\n } else {\n hierarchicalProtocolTree = protocolTreeOrId;\n }\n\n const hierarchicalAppTree = await this.readTree(appTreeId);\n if (!hierarchicalProtocolTree) {\n throw new Error(\"Invalid protocol tree\");\n }\n\n if (!hierarchicalAppTree) {\n throw new Error(\"Invalid app tree\");\n }\n\n if (hierarchicalProtocolTree.blobs) {\n const attributesBlob = hierarchicalProtocolTree.blobs.attributes;\n if (attributesBlob) {\n this.attributesBlobHandles.add(attributesBlob);\n }\n }\n return this.combineProtocolAndAppSnapshotTree(hierarchicalAppTree, hierarchicalProtocolTree);\n }\n\n private combineProtocolAndAppSnapshotTree(\n hierarchicalAppTree: api.ISnapshotTree,\n hierarchicalProtocolTree: api.ISnapshotTree,\n ) {\n const summarySnapshotTree: api.ISnapshotTree = {\n blobs: {\n ...hierarchicalAppTree.blobs,\n },\n commits: {\n ...hierarchicalAppTree.commits,\n },\n trees: {\n ...hierarchicalAppTree.trees,\n // the app tree could have a .protocol\n // in that case we want to server protocol to override it\n \".protocol\": hierarchicalProtocolTree,\n },\n };\n\n return summarySnapshotTree;\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
|
1
|
+
{"version":3,"file":"odspDocumentStorageManager.js","sourceRoot":"","sources":["../src/odspDocumentStorageManager.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 { default as AbortController } from \"abort-controller\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n assert,\n delay,\n} from \"@fluidframework/common-utils\";\nimport {\n PerformanceEvent,\n} from \"@fluidframework/telemetry-utils\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport {\n ISummaryContext,\n IDocumentStorageService,\n LoaderCachingPolicy,\n DriverErrorType,\n} from \"@fluidframework/driver-definitions\";\nimport { RateLimiter, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport {\n IOdspResolvedUrl,\n ISnapshotOptions,\n OdspErrorType,\n InstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport {\n IDocumentStorageGetVersionsResponse,\n HostStoragePolicyInternal,\n IVersionedValueWithEpoch,\n ISnapshotCachedEntry,\n} from \"./contracts\";\nimport { downloadSnapshot, fetchSnapshot, fetchSnapshotWithRedeem } from \"./fetchSnapshot\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { IOdspCache } from \"./odspCache\";\nimport {\n createCacheSnapshotKey,\n getWithRetryForTokenRefresh,\n ISnapshotContents,\n} from \"./odspUtils\";\nimport { defaultCacheExpiryTimeoutMs, EpochTracker } from \"./epochTracker\";\nimport { OdspSummaryUploadManager } from \"./odspSummaryUploadManager\";\nimport { FlushResult } from \"./odspDocumentDeltaConnection\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\n/* eslint-disable max-len */\n\n// An implementation of Promise.race that gives you the winner of the promise race\nasync function promiseRaceWithWinner<T>(promises: Promise<T>[]): Promise<{ index: number, value: T }> {\n return new Promise((resolve, reject) => {\n promises.forEach((p, index) => {\n p.then((v) => resolve({ index, value: v })).catch(reject);\n });\n });\n}\n\nclass BlobCache {\n // Save the timeout so we can cancel and reschedule it as needed\n private blobCacheTimeout: ReturnType<typeof setTimeout> | undefined;\n // If the defer flag is set when the timeout fires, we'll reschedule rather than clear immediately\n // This deferral approach is used (rather than clearing/resetting the timer) as current calling patterns trigger\n // too many calls to setTimeout/clearTimeout.\n private deferBlobCacheClear: boolean = false;\n\n private readonly _blobCache: Map<string, ArrayBuffer> = new Map();\n\n // Tracks all blob IDs evicted from cache\n private readonly blobsEvicted: Set<string> = new Set();\n\n // Initial time-out to purge data from cache\n // If this time out is very small, then we purge blobs from cache too soon and that results in a lot of\n // requests to storage, which brings down perf and may trip protection limits causing 429s\n private blobCacheTimeoutDuration = 2 * 60 * 1000;\n\n // SPO does not keep old snapshots around for long, so we are running chances of not\n // being able to rehydrate data store / DDS in the future if we purge anything (and with blob de-duping,\n // even if blob read by runtime, it could be read again in the future)\n // So for now, purging is disabled.\n private readonly purgeEnabled = false;\n\n public get value() {\n return this._blobCache;\n }\n\n public addBlobs(blobs: Map<string, ArrayBuffer>) {\n blobs.forEach((value, blobId) => {\n this._blobCache.set(blobId, value);\n });\n // Reset the timer on cache set\n this.scheduleClearBlobsCache();\n }\n\n /**\n * Schedule a timer for clearing the blob cache or defer the current one.\n */\n private scheduleClearBlobsCache() {\n if (this.blobCacheTimeout !== undefined) {\n // If we already have an outstanding timer, just signal that we should defer the clear\n this.deferBlobCacheClear = true;\n } else if (this.purgeEnabled) {\n // If we don't have an outstanding timer, set a timer\n // When the timer runs out, we'll decide whether to proceed with the cache clear or reset the timer\n const clearCacheOrDefer = () => {\n this.blobCacheTimeout = undefined;\n if (this.deferBlobCacheClear) {\n this.deferBlobCacheClear = false;\n this.scheduleClearBlobsCache();\n } else {\n // NOTE: Slightly better algorithm here would be to purge either only big blobs,\n // or sort them by size and purge enough big blobs to leave only 256Kb of small blobs in cache\n // Purging is optimizing memory footprint. But count controls potential number of storage requests\n // We want to optimize both - memory footprint and number of future requests to storage.\n // Note that Container can realize data store or DDS on-demand at any point in time, so we do not\n // control when blobs will be used.\n this._blobCache.forEach((_, blobId) => this.blobsEvicted.add(blobId));\n this._blobCache.clear();\n }\n };\n this.blobCacheTimeout = setTimeout(clearCacheOrDefer, this.blobCacheTimeoutDuration);\n // any future storage reads that get into the cache should be cleared from cache rather quickly -\n // there is not much value in keeping them longer\n this.blobCacheTimeoutDuration = 10 * 1000;\n }\n }\n\n public getBlob(blobId: string) {\n // Reset the timer on attempted cache read\n this.scheduleClearBlobsCache();\n const blobContent = this._blobCache.get(blobId);\n const evicted = this.blobsEvicted.has(blobId);\n return { blobContent, evicted };\n }\n\n public setBlob(blobId: string, blob: ArrayBuffer) {\n // This API is called as result of cache miss and reading blob from storage.\n // Runtime never reads same blob twice.\n // The only reason we may get read request for same blob is blob de-duping in summaries.\n // Note that the bigger the size, the less likely blobs are the same, so there is very little benefit of caching big blobs.\n // Images are the only exception - user may insert same image twice. But we currently do not de-dup them - only snapshot\n // blobs are de-duped.\n const size = blob.byteLength;\n if (size < 256 * 1024) {\n // Reset the timer on cache set\n this.scheduleClearBlobsCache();\n return this._blobCache.set(blobId, blob);\n } else {\n // we evicted it here by not caching.\n this.blobsEvicted.add(blobId);\n }\n }\n}\n\nexport class OdspDocumentStorageService implements IDocumentStorageService {\n readonly policies = {\n // By default, ODSP tells the container not to prefetch/cache.\n caching: LoaderCachingPolicy.NoCaching,\n\n // ODSP storage works better if it has less number of blobs / edges\n // Runtime creating many small blobs results in sub-optimal perf.\n // 2K seems like the sweat spot:\n // The smaller the number, less blobs we aggregate. Most storages are very likely to have notion\n // of minimal \"cluster\" size, so having small blobs is wasteful\n // At the same time increasing the limit ensure that more blobs with user content are aggregated,\n // reducing possibility for de-duping of same blobs (i.e. .attributes rolled into aggregate blob\n // are not reused across data stores, or even within data store, resulting in duplication of content)\n // Note that duplication of content should not have significant impact for bytes over wire as\n // compression of http payload mostly takes care of it, but it does impact storage size and in-memory sizes.\n minBlobSize: 2048,\n maximumCacheDurationMs: defaultCacheExpiryTimeoutMs,\n };\n\n private readonly commitCache: Map<string, api.ISnapshotTree> = new Map();\n\n private readonly attributesBlobHandles: Set<string> = new Set();\n\n private readonly odspSummaryUploadManager: OdspSummaryUploadManager;\n private _ops: api.ISequencedDocumentMessage[] | undefined;\n\n private firstVersionCall = true;\n private _snapshotSequenceNumber: number | undefined;\n\n private readonly documentId: string;\n private readonly snapshotUrl: string | undefined;\n private readonly attachmentPOSTUrl: string | undefined;\n private readonly attachmentGETUrl: string | undefined;\n // Driver specified limits for snapshot size and time.\n /**\n * NOTE: While commit cfff6e3 added restrictions to prevent large payloads, snapshot failures will continue to\n * happen until blob request throttling is implemented. Until then, as a temporary fix we set arbitrarily large\n * snapshot size and timeout limits so that such failures are unlikely to occur.\n */\n private readonly maxSnapshotSizeLimit = 500000000; // 500 MB\n private readonly maxSnapshotFetchTimeout = 120000; // 2 min\n\n // limits the amount of parallel \"attachment\" blob uploads\n private readonly createBlobRateLimiter = new RateLimiter(1);\n\n private readonly blobCache = new BlobCache();\n\n public set ops(ops: api.ISequencedDocumentMessage[] | undefined) {\n assert(this._ops === undefined, 0x0a5 /* \"Trying to set ops when they are already set!\" */);\n this._ops = ops;\n }\n\n public get ops(): api.ISequencedDocumentMessage[] | undefined {\n return this._ops;\n }\n\n public get snapshotSequenceNumber() {\n return this._snapshotSequenceNumber;\n }\n\n constructor(\n private readonly odspResolvedUrl: IOdspResolvedUrl,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n private readonly logger: ITelemetryLogger,\n private readonly fetchFullSnapshot: boolean,\n private readonly cache: IOdspCache,\n private readonly hostPolicy: HostStoragePolicyInternal,\n private readonly epochTracker: EpochTracker,\n private readonly flushCallback: () => Promise<FlushResult>,\n ) {\n this.documentId = this.odspResolvedUrl.hashedDocumentId;\n this.snapshotUrl = this.odspResolvedUrl.endpoints.snapshotStorageUrl;\n this.attachmentPOSTUrl = this.odspResolvedUrl.endpoints.attachmentPOSTStorageUrl;\n this.attachmentGETUrl = this.odspResolvedUrl.endpoints.attachmentGETStorageUrl;\n this.odspSummaryUploadManager = new OdspSummaryUploadManager(\n this.snapshotUrl,\n getStorageToken,\n logger,\n epochTracker,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n }\n\n public get repositoryUrl(): string {\n return \"\";\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<api.ICreateBlobResponse> {\n this.checkAttachmentPOSTUrl();\n\n const response = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"CreateBlob\");\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.attachmentPOSTUrl}/content`,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/octet-stream\";\n\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"createBlob\",\n size: file.byteLength,\n waitQueueLength: this.createBlobRateLimiter.waitQueueLength,\n },\n async (event) => {\n const res = await this.createBlobRateLimiter.schedule(async () =>\n this.epochTracker.fetchAndParseAsJSON<api.ICreateBlobResponse>(\n url,\n {\n body: file,\n headers,\n method: \"POST\",\n },\n \"createBlob\",\n ));\n event.end({\n blobId: res.content.id,\n ...res.propsToLog,\n });\n return res;\n },\n );\n });\n\n return response.content;\n }\n\n private async readBlobCore(blobId: string): Promise<ArrayBuffer> {\n const { blobContent, evicted } = this.blobCache.getBlob(blobId);\n let blob = blobContent;\n\n if (blob === undefined) {\n this.checkAttachmentGETUrl();\n\n blob = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"GetBlob\");\n const unAuthedUrl = `${this.attachmentGETUrl}/${encodeURIComponent(blobId)}/content`;\n const { url, headers } = getUrlAndHeadersWithAuth(\n unAuthedUrl,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n\n return PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"readDataBlob\",\n blobId,\n evicted,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n waitQueueLength: this.epochTracker.rateLimiter.waitQueueLength,\n },\n async (event) => {\n const res = await this.epochTracker.fetchArray(url, { headers }, \"blob\");\n event.end({\n waitQueueLength: this.epochTracker.rateLimiter.waitQueueLength,\n ...res.propsToLog,\n attempts: options.refresh ? 2 : 1,\n });\n const cacheControl = res.headers.get(\"cache-control\");\n if (cacheControl === undefined || !(cacheControl.includes(\"private\") || cacheControl.includes(\"public\"))) {\n this.logger.sendErrorEvent({\n eventName: \"NonCacheableBlob\",\n cacheControl,\n blobId,\n ...res.propsToLog,\n });\n }\n return res.content;\n },\n );\n });\n this.blobCache.setBlob(blobId, blob);\n }\n\n return blob;\n }\n\n public async readBlob(blobId: string): Promise<ArrayBufferLike> {\n return this.readBlobCore(blobId);\n }\n\n public async getSnapshotTree(version?: api.IVersion): Promise<api.ISnapshotTree | null> {\n if (!this.snapshotUrl) {\n return null;\n }\n\n let id: string;\n if (!version || !version.id) {\n const versions = await this.getVersions(null, 1);\n if (!versions || versions.length === 0) {\n return null;\n }\n id = versions[0].id;\n } else {\n id = version.id;\n }\n\n const snapshotTree = await this.readTree(id);\n if (!snapshotTree) {\n return null;\n }\n // Decode commit paths\n const commits = {};\n\n for (const key of Object.keys(snapshotTree.commits)) {\n commits[decodeURIComponent(key)] = snapshotTree.commits[key];\n }\n\n let finalTree: api.ISnapshotTree;\n // For container loaded from detach new summary, we will not have a commit for \".app\" in downloaded summary as the client uploaded both\n // \".app\" and \".protocol\" trees by itself. For other summaries, we will have \".app\" as commit because client previously only uploaded the\n // app summary.\n if (commits && commits[\".app\"]) {\n // The latest snapshot is a summary\n // attempt to read .protocol from commits for backwards compat\n finalTree = await this.readSummaryTree(commits[\".protocol\"] || snapshotTree.trees[\".protocol\"], commits[\".app\"] as string);\n } else {\n if (snapshotTree.blobs) {\n const attributesBlob = snapshotTree.blobs.attributes;\n if (attributesBlob) {\n this.attributesBlobHandles.add(attributesBlob);\n }\n }\n\n snapshotTree.commits = commits;\n\n // When we upload the container snapshot, we upload appTree in \".app\" and protocol tree in \".protocol\"\n // So when we request the snapshot we get \".app\" as tree and not as commit node as in the case just above.\n const appTree = snapshotTree.trees[\".app\"];\n const protocolTree = snapshotTree.trees[\".protocol\"];\n finalTree = this.combineProtocolAndAppSnapshotTree(appTree, protocolTree);\n }\n return finalTree;\n }\n\n public async getVersions(blobid: string | null, count: number): Promise<api.IVersion[]> {\n // Regular load workflow uses blobId === documentID to indicate \"latest\".\n if (blobid !== this.documentId && blobid) {\n // FluidFetch & FluidDebugger tools use empty sting to query for versions\n // In such case we need to make a call against SPO to give full picture to the tool.\n // Otherwise, each commit calls getVersions but odsp doesn't have a history for each commit\n // return the blobid as is\n return [\n {\n id: blobid,\n treeId: undefined!,\n },\n ];\n }\n\n // Can't really make a call if we do not have URL\n if (!this.snapshotUrl) {\n return [];\n }\n\n // If count is one, we can use the trees/latest API, which returns the latest version and trees in a single request for better performance\n // Do it only once - we might get more here due to summarizer - it needs only container tree, not full snapshot.\n if (this.firstVersionCall && count === 1 && (blobid === null || blobid === this.documentId)) {\n const hostSnapshotOptions = this.hostPolicy.snapshotOptions;\n const odspSnapshotCacheValue: ISnapshotContents = await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"ObtainSnapshot\" },\n async (event: PerformanceEvent) => {\n const props = {};\n let retrievedSnapshot: ISnapshotContents | undefined;\n // Here's the logic to grab the persistent cache snapshot implemented by the host\n // Epoch tracker is responsible for communicating with the persistent cache, handling epochs and cache versions\n const cachedSnapshotP: Promise<ISnapshotContents | undefined> =\n this.epochTracker.get(createCacheSnapshotKey(this.odspResolvedUrl))\n .then(async (snapshotCachedEntry: ISnapshotCachedEntry) => {\n if (snapshotCachedEntry !== undefined) {\n // If the cached entry does not contain the entry time, then assign it a default of 30 days old.\n const age = Date.now() - (snapshotCachedEntry.cacheEntryTime ??\n (Date.now() - 30 * 24 * 60 * 60 * 1000));\n\n // Record the cache age\n // eslint-disable-next-line @typescript-eslint/dot-notation\n props[\"cacheEntryAge\"] = age;\n }\n\n return snapshotCachedEntry;\n });\n\n // Based on the concurrentSnapshotFetch policy:\n // Either retrieve both the network and cache snapshots concurrently and pick the first to return,\n // or grab the cache value and then the network value if the cache value returns undefined.\n let method: string;\n if (this.hostPolicy.concurrentSnapshotFetch && !this.hostPolicy.summarizerClient) {\n const networkSnapshotP = this.fetchSnapshot(hostSnapshotOptions);\n\n // Ensure that failures on both paths are ignored initially.\n // I.e. if cache fails for some reason, we will proceed with network result.\n // And vice versa - if (for example) client is offline and network request fails first, we\n // do want to attempt to succeed with cached data!\n const promiseRaceWinner = await promiseRaceWithWinner([\n cachedSnapshotP.catch(() => undefined),\n networkSnapshotP.catch(() => undefined),\n ]);\n retrievedSnapshot = promiseRaceWinner.value;\n method = promiseRaceWinner.index === 0 ? \"cache\" : \"network\";\n\n if (retrievedSnapshot === undefined) {\n // if network failed -> wait for cache ( then return network failure)\n // If cache returned empty or failed -> wait for network (success of failure)\n if (promiseRaceWinner.index === 1) {\n retrievedSnapshot = await cachedSnapshotP;\n method = \"cache\";\n }\n if (retrievedSnapshot === undefined) {\n retrievedSnapshot = await networkSnapshotP;\n method = \"network\";\n }\n }\n } else {\n // Note: There's a race condition here - another caller may come past the undefined check\n // while the first caller is awaiting later async code in this block.\n\n retrievedSnapshot = await cachedSnapshotP;\n\n method = retrievedSnapshot !== undefined ? \"cache\" : \"network\";\n\n if (retrievedSnapshot === undefined) {\n retrievedSnapshot = await this.fetchSnapshot(hostSnapshotOptions);\n }\n }\n if (method === \"network\") {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n props[\"cacheEntryAge\"] = undefined;\n }\n event.end({ ...props, method });\n return retrievedSnapshot;\n },\n );\n\n // Successful call, make network calls only\n this.firstVersionCall = false;\n\n this._snapshotSequenceNumber = odspSnapshotCacheValue.sequenceNumber;\n const { snapshotTree, blobs, ops } = odspSnapshotCacheValue;\n // id should be undefined in case of just ops in snapshot.\n let id: string | undefined;\n if (snapshotTree) {\n id = snapshotTree.id;\n assert(id !== undefined, 0x221 /* \"Root tree should contain the id\" */);\n this.setRootTree(id, snapshotTree);\n }\n if (blobs) {\n this.initBlobsCache(blobs);\n }\n\n this.ops = ops;\n return id ? [{ id, treeId: undefined! }] : [];\n }\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"GetVersions\");\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/versions?count=${count}`,\n storageToken,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n );\n\n // Fetch the latest snapshot versions for the document\n const response = await PerformanceEvent.timedExecAsync(\n this.logger,\n {\n eventName: \"getVersions\",\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n },\n async () => this.epochTracker.fetchAndParseAsJSON<IDocumentStorageGetVersionsResponse>(url, { headers }, \"versions\"),\n );\n const versionsResponse = response.content;\n if (!versionsResponse) {\n throw new NonRetryableError(\n \"getVersionsReturnedNoResponse\",\n \"No response from /versions endpoint\",\n DriverErrorType.genericNetworkError,\n { driverVersion });\n }\n if (!Array.isArray(versionsResponse.value)) {\n throw new NonRetryableError(\n \"getVersionsReturnedNonArrayResponse\",\n \"Incorrect response from /versions endpoint\",\n DriverErrorType.genericNetworkError,\n { driverVersion });\n }\n return versionsResponse.value.map((version) => {\n // Parse the date from the message\n let date: string | undefined;\n for (const rec of version.message.split(\"\\n\")) {\n const index = rec.indexOf(\":\");\n if (index !== -1 && rec.substr(0, index) === \"Date\") {\n date = rec.substr(index + 1).trim();\n break;\n }\n }\n return {\n date,\n id: version.id,\n treeId: undefined!,\n };\n });\n });\n }\n\n private async fetchSnapshot(hostSnapshotOptions: ISnapshotOptions | undefined) {\n return this.fetchSnapshotCore(hostSnapshotOptions).catch((error) => {\n // Issue #5895:\n // If we are offline, this error is retryable. But that means that RetriableDocumentStorageService\n // will run in circles calling getSnapshotTree, which would result in OdspDocumentStorageService class\n // going getVersions / individual blob download path. This path is very slow, and will not work with\n // delay-loaded data stores and ODSP storage deleting old snapshots and blobs.\n if (typeof error === \"object\" && error !== null) {\n error.canRetry = false;\n }\n throw error;\n });\n }\n\n private async fetchSnapshotCore(hostSnapshotOptions: ISnapshotOptions | undefined) {\n const snapshotOptions: ISnapshotOptions = {\n mds: this.maxSnapshotSizeLimit,\n ...hostSnapshotOptions,\n timeout: hostSnapshotOptions?.timeout ? Math.min(hostSnapshotOptions.timeout, this.maxSnapshotFetchTimeout) : this.maxSnapshotFetchTimeout,\n };\n\n // No limit on size of snapshot or time to fetch, as otherwise we fail all clients to summarize\n if (this.hostPolicy.summarizerClient) {\n snapshotOptions.mds = undefined;\n snapshotOptions.timeout = undefined;\n }\n\n const snapshotDownloader = async (\n finalOdspResolvedUrl: IOdspResolvedUrl,\n storageToken: string,\n options: ISnapshotOptions | undefined,\n controller?: AbortController,\n ) => {\n return downloadSnapshot(\n finalOdspResolvedUrl,\n storageToken,\n this.logger,\n options,\n this.hostPolicy.fetchBinarySnapshotFormat,\n controller,\n this.epochTracker,\n );\n };\n const putInCache = async (valueWithEpoch: IVersionedValueWithEpoch) => {\n return this.cache.persistedCache.put(\n createCacheSnapshotKey(this.odspResolvedUrl),\n // Epoch tracker will add the epoch and version to the value here. So just send value to cache.\n valueWithEpoch.value,\n );\n };\n const removeEntries = async () => this.cache.persistedCache.removeEntries();\n try {\n const odspSnapshot = await fetchSnapshotWithRedeem(\n this.odspResolvedUrl,\n this.getStorageToken,\n snapshotOptions,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n putInCache,\n removeEntries,\n this.hostPolicy.enableRedeemFallback,\n );\n return odspSnapshot;\n } catch (error) {\n const errorType = error.errorType;\n // If the snapshot size is too big and the host specified the size limitation(specified in hostSnapshotOptions), then don't try to fetch the snapshot again.\n if ((errorType === OdspErrorType.snapshotTooBig && hostSnapshotOptions?.mds !== undefined) && (this.hostPolicy.summarizerClient !== true)) {\n throw error;\n }\n // If the first snapshot request was with blobs and we either timed out or the size was too big, then try to fetch without blobs.\n if ((errorType === OdspErrorType.snapshotTooBig || errorType === OdspErrorType.fetchTimeout) && snapshotOptions.blobs) {\n this.logger.sendErrorEvent({\n eventName: \"TreeLatest_SecondCall\",\n errorType,\n });\n const snapshotOptionsWithoutBlobs: ISnapshotOptions = { ...snapshotOptions, blobs: 0, mds: undefined, timeout: undefined };\n const odspSnapshot = await fetchSnapshotWithRedeem(\n this.odspResolvedUrl,\n this.getStorageToken,\n snapshotOptionsWithoutBlobs,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n putInCache,\n removeEntries,\n this.hostPolicy.enableRedeemFallback,\n );\n return odspSnapshot;\n }\n throw error;\n }\n }\n\n public async write(tree: api.ITree, parents: string[], message: string): Promise<api.IVersion> {\n this.checkSnapshotUrl();\n\n throw new Error(\"Not supported\");\n }\n\n public async uploadSummaryWithContext(summary: api.ISummaryTree, context: ISummaryContext): Promise<string> {\n this.checkSnapshotUrl();\n\n // Enable flushing only if we have single commit summary and this is not the initial summary for an empty file\n if (\".protocol\" in summary.tree && context.ackHandle !== undefined) {\n let retry = 0;\n for (;;) {\n const result = await this.flushCallback();\n const seq = result.lastPersistedSequenceNumber;\n if (seq !== undefined && seq >= context.referenceSequenceNumber) {\n break;\n }\n\n retry++;\n if (retry > 3) {\n this.logger.sendErrorEvent({\n eventName: \"FlushFailure\",\n ...result,\n retry,\n referenceSequenceNumber: context.referenceSequenceNumber,\n });\n break;\n }\n\n this.logger.sendPerformanceEvent({\n eventName: \"FlushExtraCall\",\n ...result,\n retry,\n referenceSequenceNumber: context.referenceSequenceNumber,\n });\n\n await delay(1000 * (result.retryAfter ?? 1));\n }\n }\n\n const id = await this.odspSummaryUploadManager.writeSummaryTree(summary, context);\n return id;\n }\n\n public async downloadSummary(commit: api.ISummaryHandle): Promise<api.ISummaryTree> {\n throw new Error(\"Not implemented yet\");\n }\n\n private setRootTree(id: string, tree: api.ISnapshotTree) {\n this.commitCache.set(id, tree);\n }\n\n private initBlobsCache(blobs: Map<string, ArrayBuffer>) {\n this.blobCache.addBlobs(blobs);\n }\n\n private checkSnapshotUrl() {\n if (!this.snapshotUrl) {\n throw new NonRetryableError(\n \"noSnapshotUrlProvided\",\n \"Method failed because no snapshot url was available\",\n DriverErrorType.genericError,\n { driverVersion });\n }\n }\n\n private checkAttachmentPOSTUrl() {\n if (!this.attachmentPOSTUrl) {\n throw new NonRetryableError(\n \"noAttachmentPOSTUrlProvided\",\n \"Method failed because no attachment POST url was available\",\n DriverErrorType.genericError,\n { driverVersion });\n }\n }\n\n private checkAttachmentGETUrl() {\n if (!this.attachmentGETUrl) {\n throw new NonRetryableError(\n \"noAttachmentGETUrlWasProvided\",\n \"Method failed because no attachment GET url was available\",\n DriverErrorType.genericError,\n { driverVersion });\n }\n }\n\n private async readTree(id: string): Promise<api.ISnapshotTree | null> {\n if (!this.snapshotUrl) {\n return null;\n }\n let tree = this.commitCache.get(id);\n if (!tree) {\n tree = await getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"ReadCommit\");\n const snapshotDownloader = async (url: string, fetchOptions: {[index: string]: any}) => {\n return this.epochTracker.fetchAndParseAsJSON(\n url,\n fetchOptions,\n \"snapshotTree\",\n );\n };\n const snapshot = await fetchSnapshot(\n this.snapshotUrl!,\n storageToken,\n id,\n this.fetchFullSnapshot,\n !!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,\n this.logger,\n snapshotDownloader,\n );\n let treeId = \"\";\n if (snapshot.snapshotTree) {\n assert(snapshot.snapshotTree.id !== undefined, 0x222 /* \"Root tree should contain the id!!\" */);\n treeId = snapshot.snapshotTree.id;\n this.setRootTree(treeId, snapshot.snapshotTree);\n }\n if (snapshot.blobs) {\n this.initBlobsCache(snapshot.blobs);\n }\n // If the version id doesn't match with the id of the tree, then use the id of first tree which in that case\n // will be the actual id of tree to be fetched.\n return this.commitCache.get(id) ?? this.commitCache.get(treeId);\n });\n }\n\n if (!tree) {\n return null;\n }\n\n return tree;\n }\n\n /**\n * Reads a summary tree\n * @param protocolTreeOrId - Protocol snapshot tree or id of the protocol tree\n * @param appTreeId - Id of the app tree\n */\n private async readSummaryTree(protocolTreeOrId: api.ISnapshotTree | string, appTreeId: string): Promise<api.ISnapshotTree> {\n // Load the app and protocol trees and return them\n let hierarchicalProtocolTree: api.ISnapshotTree | null;\n if (typeof (protocolTreeOrId) === \"string\") {\n // Backwards compat for older summaries\n hierarchicalProtocolTree = await this.readTree(protocolTreeOrId);\n } else {\n hierarchicalProtocolTree = protocolTreeOrId;\n }\n\n const hierarchicalAppTree = await this.readTree(appTreeId);\n if (!hierarchicalProtocolTree) {\n throw new Error(\"Invalid protocol tree\");\n }\n\n if (!hierarchicalAppTree) {\n throw new Error(\"Invalid app tree\");\n }\n\n if (hierarchicalProtocolTree.blobs) {\n const attributesBlob = hierarchicalProtocolTree.blobs.attributes;\n if (attributesBlob) {\n this.attributesBlobHandles.add(attributesBlob);\n }\n }\n return this.combineProtocolAndAppSnapshotTree(hierarchicalAppTree, hierarchicalProtocolTree);\n }\n\n private combineProtocolAndAppSnapshotTree(\n hierarchicalAppTree: api.ISnapshotTree,\n hierarchicalProtocolTree: api.ISnapshotTree,\n ) {\n const summarySnapshotTree: api.ISnapshotTree = {\n blobs: {\n ...hierarchicalAppTree.blobs,\n },\n commits: {\n ...hierarchicalAppTree.commits,\n },\n trees: {\n ...hierarchicalAppTree.trees,\n // the app tree could have a .protocol\n // in that case we want to server protocol to override it\n \".protocol\": hierarchicalProtocolTree,\n },\n };\n\n return summarySnapshotTree;\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDriverUrlResolverForShareLink.d.ts","sourceRoot":"","sources":["../src/odspDriverUrlResolverForShareLink.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAkB,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAoB,MAAM,oCAAoC,CAAC;AAG5F,OAAO,EACH,gBAAgB,EAChB,YAAY,EAEZ,6BAA6B,EAC7B,YAAY,EAEf,MAAM,yCAAyC,CAAC;AAOjD,OAAO,EAAE,yBAAyB,EAAqB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"odspDriverUrlResolverForShareLink.d.ts","sourceRoot":"","sources":["../src/odspDriverUrlResolverForShareLink.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAkB,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAoB,MAAM,oCAAoC,CAAC;AAG5F,OAAO,EACH,gBAAgB,EAChB,YAAY,EAEZ,6BAA6B,EAC7B,YAAY,EAEf,MAAM,yCAAyC,CAAC;AAOjD,OAAO,EAAE,yBAAyB,EAAqB,MAAM,mBAAmB,CAAC;AAOjF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC,6BAA6B,CAAC,CAAC;IAC1D;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC;CAC9B;AAED;;;;GAIG;AACH,qBAAa,iCAAkC,YAAW,YAAY;IAkB9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAjB7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsC;IACvE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAoC;IAE1E;;;;;;;;;OASG;gBAEC,qBAAqB,CAAC,EAAE,qBAAqB,GAAG,SAAS,EACzD,MAAM,CAAC,EAAE,oBAAoB,EACZ,OAAO,CAAC,oBAAQ;IAWrC;;;OAGG;IACI,mBAAmB,CAAC,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAyBrF,OAAO,CAAC,MAAM;IAId;;OAEG;IACU,OAAO,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+BlE,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,0BAA0B;YAsBpB,mBAAmB;IA8BjC;;;;;OAKG;IACU,cAAc,CACvB,WAAW,EAAE,YAAY,EACzB,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,iBAAiB,GAChC,OAAO,CAAC,MAAM,CAAC;IAwBlB;;OAEG;WACW,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,yBAAyB;IAQtF;;OAEG;WACW,cAAc,CAAC,OAAO,EAAE,yBAAyB;CAGlE"}
|
|
@@ -16,6 +16,7 @@ const createOdspUrl_1 = require("./createOdspUrl");
|
|
|
16
16
|
const odspDriverUrlResolver_1 = require("./odspDriverUrlResolver");
|
|
17
17
|
const odspUtils_1 = require("./odspUtils");
|
|
18
18
|
const getFileLink_1 = require("./getFileLink");
|
|
19
|
+
const packageVersion_1 = require("./packageVersion");
|
|
19
20
|
/**
|
|
20
21
|
* Resolver to resolve urls like the ones created by createOdspUrl which is driver inner
|
|
21
22
|
* url format and the ones which have things like driveId, siteId, itemId etc encoded in nav param.
|
|
@@ -109,7 +110,7 @@ class OdspDriverUrlResolverForShareLink {
|
|
|
109
110
|
return async (options) => {
|
|
110
111
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, { eventName: "GetSharingLinkToken" }, async (event) => tokenFetcher(options).then((tokenResponse) => {
|
|
111
112
|
if (tokenResponse === null) {
|
|
112
|
-
throw new driver_utils_1.NonRetryableError("shareLinkTokenIsNull", "Token callback returned null", odsp_driver_definitions_1.OdspErrorType.fetchTokenError);
|
|
113
|
+
throw new driver_utils_1.NonRetryableError("shareLinkTokenIsNull", "Token callback returned null", odsp_driver_definitions_1.OdspErrorType.fetchTokenError, { driverVersion: packageVersion_1.pkgVersion });
|
|
113
114
|
}
|
|
114
115
|
event.end({ fromCache: odsp_driver_definitions_1.isTokenFromCache(tokenResponse) });
|
|
115
116
|
return tokenResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspDriverUrlResolverForShareLink.js","sourceRoot":"","sources":["../src/odspDriverUrlResolverForShareLink.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 { PromiseCache } from \"@fluidframework/common-utils\";\nimport { IFluidCodeDetails, IRequest, isFluidPackage } from \"@fluidframework/core-interfaces\";\nimport { IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ITelemetryBaseLogger, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspResolvedUrl,\n IdentityType,\n isTokenFromCache,\n OdspResourceTokenFetchOptions,\n TokenFetcher,\n OdspErrorType,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport {\n getLocatorFromOdspUrl,\n storeLocatorInOdspUrl,\n encodeOdspFluidDataStoreLocator,\n locatorQueryParamName,\n} from \"./odspFluidFileLink\";\nimport { OdspFluidDataStoreLocator, SharingLinkHeader } from \"./contractsPublic\";\nimport { createOdspUrl } from \"./createOdspUrl\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver\";\nimport { getOdspResolvedUrl, createOdspLogger } from \"./odspUtils\";\nimport { getFileLink } from \"./getFileLink\";\n\n/**\n * Properties passed to the code responsible for fetching share link for a file.\n */\nexport interface ShareLinkFetcherProps {\n /**\n * Callback method that is used to fetch access token necessary to call API that produces share link\n */\n tokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>;\n /**\n * Identity type determining the shape of share link as it differs for Enterprise and Consumer users.\n */\n identityType: IdentityType;\n}\n\n/**\n * Resolver to resolve urls like the ones created by createOdspUrl which is driver inner\n * url format and the ones which have things like driveId, siteId, itemId etc encoded in nav param.\n * This resolver also handles share links and try to generate one for the use by the app.\n */\nexport class OdspDriverUrlResolverForShareLink implements IUrlResolver {\n private readonly logger: ITelemetryLogger;\n private readonly sharingLinkCache = new PromiseCache<string, string>();\n private readonly shareLinkFetcherProps: ShareLinkFetcherProps | undefined;\n\n /**\n * Creates url resolver instance\n * @param shareLinkFetcherProps - properties used when fetching share link.\n * Can be set as 'undefined' for cases where share link is not needed. Currently, only\n * getAbsoluteUrl() method requires share link.\n * @param logger - logger object that is used as telemetry sink\n * @param appName - application name hint that is encoded with url produced by getAbsoluteUrl() method.\n * This hint is used by link handling logic which determines which app to redirect to when user\n * navigates directly to the link.\n */\n public constructor(\n shareLinkFetcherProps?: ShareLinkFetcherProps | undefined,\n logger?: ITelemetryBaseLogger,\n private readonly appName?: string,\n ) {\n this.logger = createOdspLogger(logger);\n if (shareLinkFetcherProps) {\n this.shareLinkFetcherProps = {\n ...shareLinkFetcherProps,\n tokenFetcher: this.toInstrumentedTokenFetcher(this.logger, shareLinkFetcherProps.tokenFetcher),\n };\n }\n }\n\n /**\n * Takes an already generated data store url (from requestUrl) and appends a path to the\n * existing data store information.\n */\n public appendDataStorePath(requestUrl: URL, pathToAppend: string): string | undefined {\n const fluidInfo = getLocatorFromOdspUrl(requestUrl);\n\n if (!fluidInfo) {\n return undefined;\n }\n\n const parsingUrl = new URL(fluidInfo.dataStorePath, `${requestUrl.protocol}//${requestUrl.hostname}`);\n // Determine if the caller is passing a query parameter or path since processing will be different.\n if (pathToAppend.startsWith(\"/?\") || pathToAppend.startsWith(\"?\")) {\n const queryParams = new URLSearchParams(pathToAppend);\n queryParams.forEach((value: string, key: string) => {\n parsingUrl.searchParams.append(key, value);\n });\n fluidInfo.dataStorePath = `${parsingUrl.pathname}${parsingUrl.search}`;\n } else {\n fluidInfo.dataStorePath = `${parsingUrl.pathname}${\n parsingUrl.pathname.endsWith(\"/\") || pathToAppend.startsWith(\"/\") ? \"\" : \"/\"\n }${pathToAppend}/${parsingUrl.search}`;\n }\n storeLocatorInOdspUrl(requestUrl, fluidInfo);\n\n return requestUrl.href;\n }\n\n private getKey(resolvedUrl: IOdspResolvedUrl): string {\n return `${resolvedUrl.siteUrl},${resolvedUrl.driveId},${resolvedUrl.itemId}`;\n }\n\n /**\n * Resolves request URL into driver details\n */\n public async resolve(request: IRequest): Promise<IOdspResolvedUrl> {\n const requestToBeResolved = { headers: request.headers, url: request.url };\n const isSharingLinkToRedeem = requestToBeResolved.headers?.[SharingLinkHeader.isSharingLinkToRedeem];\n try {\n const url = new URL(request.url);\n\n const odspFluidInfo = getLocatorFromOdspUrl(url);\n if (odspFluidInfo) {\n requestToBeResolved.url = createOdspUrl(odspFluidInfo);\n }\n } catch {\n // If the locator throws some error, then try to resolve the request as it is.\n }\n\n const odspResolvedUrl = await new OdspDriverUrlResolver().resolve(requestToBeResolved);\n\n if (isSharingLinkToRedeem) {\n // We need to remove the nav param if set by host when setting the sharelink as otherwise the shareLinkId\n // when redeeming the share link during the redeem fallback for trees latest call becomes greater than\n // the eligible length.\n odspResolvedUrl.shareLinkInfo = Object.assign(odspResolvedUrl.shareLinkInfo || {},\n {sharingLinkToRedeem: this.removeNavParam(request.url)});\n }\n if (odspResolvedUrl.itemId) {\n // Kick start the sharing link request if we don't have it already as a performance optimization.\n // For detached create new, we don't have an item id yet and therefore cannot generate a share link\n this.getShareLinkPromise(odspResolvedUrl).catch(() => {});\n }\n return odspResolvedUrl;\n }\n\n private removeNavParam(link: string): string {\n const url = new URL(link);\n const params = new URLSearchParams(url.search);\n params.delete(locatorQueryParamName);\n url.search = params.toString();\n return url.href;\n }\n\n private toInstrumentedTokenFetcher(\n logger: ITelemetryLogger,\n tokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>,\n ): TokenFetcher<OdspResourceTokenFetchOptions> {\n return async (options: OdspResourceTokenFetchOptions) => {\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"GetSharingLinkToken\" },\n async (event) => tokenFetcher(options).then((tokenResponse) => {\n if (tokenResponse === null) {\n throw new NonRetryableError(\n \"shareLinkTokenIsNull\",\n \"Token callback returned null\",\n OdspErrorType.fetchTokenError);\n }\n event.end({ fromCache: isTokenFromCache(tokenResponse) });\n return tokenResponse;\n }));\n };\n }\n\n private async getShareLinkPromise(resolvedUrl: IOdspResolvedUrl): Promise<string> {\n if (this.shareLinkFetcherProps === undefined) {\n throw new Error(\"Failed to get share link because share link fetcher props are missing\");\n }\n\n if (!(resolvedUrl.siteUrl && resolvedUrl.driveId && resolvedUrl.itemId)) {\n throw new Error(\"Failed to get share link because necessary information is missing \" +\n \"(e.g. siteUrl, driveId or itemId)\");\n }\n\n const key = this.getKey(resolvedUrl);\n const cachedLinkPromise = this.sharingLinkCache.get(key);\n if (cachedLinkPromise) {\n return cachedLinkPromise;\n }\n const newLinkPromise = getFileLink(\n this.shareLinkFetcherProps.tokenFetcher,\n resolvedUrl,\n this.shareLinkFetcherProps.identityType,\n this.logger,\n ).catch((error) => {\n // This should imply that error is a non-retriable error.\n this.logger.sendErrorEvent({ eventName: \"FluidFileUrlError\" }, error);\n this.sharingLinkCache.remove(key);\n throw error;\n });\n this.sharingLinkCache.add(key, async () => newLinkPromise);\n return newLinkPromise;\n }\n\n /**\n * Requests a driver + data store storage URL. Note that this method requires share link to be fetched\n * and it will throw in case share link fetcher props were not specified when instance was created.\n * @param resolvedUrl - The driver resolved URL\n * @param request - The relative data store path URL. For requesting a driver URL, this value should always be '/'\n */\n public async getAbsoluteUrl(\n resolvedUrl: IResolvedUrl,\n dataStorePath: string,\n codeDetails?: IFluidCodeDetails,\n ): Promise<string> {\n const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n const shareLink = await this.getShareLinkPromise(odspResolvedUrl);\n\n const shareLinkUrl = new URL(shareLink);\n\n const containerPackageName =\n isFluidPackage(codeDetails?.package) ? codeDetails?.package.name : codeDetails?.package ??\n odspResolvedUrl.codeHint?.containerPackageName;\n\n storeLocatorInOdspUrl(shareLinkUrl, {\n siteUrl: odspResolvedUrl.siteUrl,\n driveId: odspResolvedUrl.driveId,\n itemId: odspResolvedUrl.itemId,\n dataStorePath,\n appName: this.appName,\n containerPackageName,\n fileVersion: odspResolvedUrl.fileVersion,\n });\n\n return shareLinkUrl.href;\n }\n\n /**\n * Crafts a supported document/driver URL\n */\n public static createDocumentUrl(baseUrl: string, driverInfo: OdspFluidDataStoreLocator) {\n const url = new URL(baseUrl);\n\n storeLocatorInOdspUrl(url, driverInfo);\n\n return url.href;\n }\n\n /**\n * Crafts a supported data store nav param\n */\n public static createNavParam(locator: OdspFluidDataStoreLocator) {\n return encodeOdspFluidDataStoreLocator(locator);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDriverUrlResolverForShareLink.js","sourceRoot":"","sources":["../src/odspDriverUrlResolverForShareLink.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 { PromiseCache } from \"@fluidframework/common-utils\";\nimport { IFluidCodeDetails, IRequest, isFluidPackage } from \"@fluidframework/core-interfaces\";\nimport { IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ITelemetryBaseLogger, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspResolvedUrl,\n IdentityType,\n isTokenFromCache,\n OdspResourceTokenFetchOptions,\n TokenFetcher,\n OdspErrorType,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport {\n getLocatorFromOdspUrl,\n storeLocatorInOdspUrl,\n encodeOdspFluidDataStoreLocator,\n locatorQueryParamName,\n} from \"./odspFluidFileLink\";\nimport { OdspFluidDataStoreLocator, SharingLinkHeader } from \"./contractsPublic\";\nimport { createOdspUrl } from \"./createOdspUrl\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver\";\nimport { getOdspResolvedUrl, createOdspLogger } from \"./odspUtils\";\nimport { getFileLink } from \"./getFileLink\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\n/**\n * Properties passed to the code responsible for fetching share link for a file.\n */\nexport interface ShareLinkFetcherProps {\n /**\n * Callback method that is used to fetch access token necessary to call API that produces share link\n */\n tokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>;\n /**\n * Identity type determining the shape of share link as it differs for Enterprise and Consumer users.\n */\n identityType: IdentityType;\n}\n\n/**\n * Resolver to resolve urls like the ones created by createOdspUrl which is driver inner\n * url format and the ones which have things like driveId, siteId, itemId etc encoded in nav param.\n * This resolver also handles share links and try to generate one for the use by the app.\n */\nexport class OdspDriverUrlResolverForShareLink implements IUrlResolver {\n private readonly logger: ITelemetryLogger;\n private readonly sharingLinkCache = new PromiseCache<string, string>();\n private readonly shareLinkFetcherProps: ShareLinkFetcherProps | undefined;\n\n /**\n * Creates url resolver instance\n * @param shareLinkFetcherProps - properties used when fetching share link.\n * Can be set as 'undefined' for cases where share link is not needed. Currently, only\n * getAbsoluteUrl() method requires share link.\n * @param logger - logger object that is used as telemetry sink\n * @param appName - application name hint that is encoded with url produced by getAbsoluteUrl() method.\n * This hint is used by link handling logic which determines which app to redirect to when user\n * navigates directly to the link.\n */\n public constructor(\n shareLinkFetcherProps?: ShareLinkFetcherProps | undefined,\n logger?: ITelemetryBaseLogger,\n private readonly appName?: string,\n ) {\n this.logger = createOdspLogger(logger);\n if (shareLinkFetcherProps) {\n this.shareLinkFetcherProps = {\n ...shareLinkFetcherProps,\n tokenFetcher: this.toInstrumentedTokenFetcher(this.logger, shareLinkFetcherProps.tokenFetcher),\n };\n }\n }\n\n /**\n * Takes an already generated data store url (from requestUrl) and appends a path to the\n * existing data store information.\n */\n public appendDataStorePath(requestUrl: URL, pathToAppend: string): string | undefined {\n const fluidInfo = getLocatorFromOdspUrl(requestUrl);\n\n if (!fluidInfo) {\n return undefined;\n }\n\n const parsingUrl = new URL(fluidInfo.dataStorePath, `${requestUrl.protocol}//${requestUrl.hostname}`);\n // Determine if the caller is passing a query parameter or path since processing will be different.\n if (pathToAppend.startsWith(\"/?\") || pathToAppend.startsWith(\"?\")) {\n const queryParams = new URLSearchParams(pathToAppend);\n queryParams.forEach((value: string, key: string) => {\n parsingUrl.searchParams.append(key, value);\n });\n fluidInfo.dataStorePath = `${parsingUrl.pathname}${parsingUrl.search}`;\n } else {\n fluidInfo.dataStorePath = `${parsingUrl.pathname}${\n parsingUrl.pathname.endsWith(\"/\") || pathToAppend.startsWith(\"/\") ? \"\" : \"/\"\n }${pathToAppend}/${parsingUrl.search}`;\n }\n storeLocatorInOdspUrl(requestUrl, fluidInfo);\n\n return requestUrl.href;\n }\n\n private getKey(resolvedUrl: IOdspResolvedUrl): string {\n return `${resolvedUrl.siteUrl},${resolvedUrl.driveId},${resolvedUrl.itemId}`;\n }\n\n /**\n * Resolves request URL into driver details\n */\n public async resolve(request: IRequest): Promise<IOdspResolvedUrl> {\n const requestToBeResolved = { headers: request.headers, url: request.url };\n const isSharingLinkToRedeem = requestToBeResolved.headers?.[SharingLinkHeader.isSharingLinkToRedeem];\n try {\n const url = new URL(request.url);\n\n const odspFluidInfo = getLocatorFromOdspUrl(url);\n if (odspFluidInfo) {\n requestToBeResolved.url = createOdspUrl(odspFluidInfo);\n }\n } catch {\n // If the locator throws some error, then try to resolve the request as it is.\n }\n\n const odspResolvedUrl = await new OdspDriverUrlResolver().resolve(requestToBeResolved);\n\n if (isSharingLinkToRedeem) {\n // We need to remove the nav param if set by host when setting the sharelink as otherwise the shareLinkId\n // when redeeming the share link during the redeem fallback for trees latest call becomes greater than\n // the eligible length.\n odspResolvedUrl.shareLinkInfo = Object.assign(odspResolvedUrl.shareLinkInfo || {},\n {sharingLinkToRedeem: this.removeNavParam(request.url)});\n }\n if (odspResolvedUrl.itemId) {\n // Kick start the sharing link request if we don't have it already as a performance optimization.\n // For detached create new, we don't have an item id yet and therefore cannot generate a share link\n this.getShareLinkPromise(odspResolvedUrl).catch(() => {});\n }\n return odspResolvedUrl;\n }\n\n private removeNavParam(link: string): string {\n const url = new URL(link);\n const params = new URLSearchParams(url.search);\n params.delete(locatorQueryParamName);\n url.search = params.toString();\n return url.href;\n }\n\n private toInstrumentedTokenFetcher(\n logger: ITelemetryLogger,\n tokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>,\n ): TokenFetcher<OdspResourceTokenFetchOptions> {\n return async (options: OdspResourceTokenFetchOptions) => {\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"GetSharingLinkToken\" },\n async (event) => tokenFetcher(options).then((tokenResponse) => {\n if (tokenResponse === null) {\n throw new NonRetryableError(\n \"shareLinkTokenIsNull\",\n \"Token callback returned null\",\n OdspErrorType.fetchTokenError,\n { driverVersion });\n }\n event.end({ fromCache: isTokenFromCache(tokenResponse) });\n return tokenResponse;\n }));\n };\n }\n\n private async getShareLinkPromise(resolvedUrl: IOdspResolvedUrl): Promise<string> {\n if (this.shareLinkFetcherProps === undefined) {\n throw new Error(\"Failed to get share link because share link fetcher props are missing\");\n }\n\n if (!(resolvedUrl.siteUrl && resolvedUrl.driveId && resolvedUrl.itemId)) {\n throw new Error(\"Failed to get share link because necessary information is missing \" +\n \"(e.g. siteUrl, driveId or itemId)\");\n }\n\n const key = this.getKey(resolvedUrl);\n const cachedLinkPromise = this.sharingLinkCache.get(key);\n if (cachedLinkPromise) {\n return cachedLinkPromise;\n }\n const newLinkPromise = getFileLink(\n this.shareLinkFetcherProps.tokenFetcher,\n resolvedUrl,\n this.shareLinkFetcherProps.identityType,\n this.logger,\n ).catch((error) => {\n // This should imply that error is a non-retriable error.\n this.logger.sendErrorEvent({ eventName: \"FluidFileUrlError\" }, error);\n this.sharingLinkCache.remove(key);\n throw error;\n });\n this.sharingLinkCache.add(key, async () => newLinkPromise);\n return newLinkPromise;\n }\n\n /**\n * Requests a driver + data store storage URL. Note that this method requires share link to be fetched\n * and it will throw in case share link fetcher props were not specified when instance was created.\n * @param resolvedUrl - The driver resolved URL\n * @param request - The relative data store path URL. For requesting a driver URL, this value should always be '/'\n */\n public async getAbsoluteUrl(\n resolvedUrl: IResolvedUrl,\n dataStorePath: string,\n codeDetails?: IFluidCodeDetails,\n ): Promise<string> {\n const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n const shareLink = await this.getShareLinkPromise(odspResolvedUrl);\n\n const shareLinkUrl = new URL(shareLink);\n\n const containerPackageName =\n isFluidPackage(codeDetails?.package) ? codeDetails?.package.name : codeDetails?.package ??\n odspResolvedUrl.codeHint?.containerPackageName;\n\n storeLocatorInOdspUrl(shareLinkUrl, {\n siteUrl: odspResolvedUrl.siteUrl,\n driveId: odspResolvedUrl.driveId,\n itemId: odspResolvedUrl.itemId,\n dataStorePath,\n appName: this.appName,\n containerPackageName,\n fileVersion: odspResolvedUrl.fileVersion,\n });\n\n return shareLinkUrl.href;\n }\n\n /**\n * Crafts a supported document/driver URL\n */\n public static createDocumentUrl(baseUrl: string, driverInfo: OdspFluidDataStoreLocator) {\n const url = new URL(baseUrl);\n\n storeLocatorInOdspUrl(url, driverInfo);\n\n return url.href;\n }\n\n /**\n * Crafts a supported data store nav param\n */\n public static createNavParam(locator: OdspFluidDataStoreLocator) {\n return encodeOdspFluidDataStoreLocator(locator);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspSummaryUploadManager.d.ts","sourceRoot":"","sources":["../src/odspSummaryUploadManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE,OAAO,KAAK,GAAG,MAAM,sCAAsC,CAAC;AAC5D,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAU1F,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C;;;GAGG;AACH,qBAAa,wBAAwB;IAM7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,sCAAsC;IAR3D,OAAO,CAAC,yBAAyB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAGlB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,+BAA+B,EACjE,MAAM,EAAE,gBAAgB,EACP,YAAY,EAAE,YAAY,EAC1B,sCAAsC,EAAE,OAAO;IAKvD,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,eAAe;
|
|
1
|
+
{"version":3,"file":"odspSummaryUploadManager.d.ts","sourceRoot":"","sources":["../src/odspSummaryUploadManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE,OAAO,KAAK,GAAG,MAAM,sCAAsC,CAAC;AAC5D,OAAO,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAU1F,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C;;;GAGG;AACH,qBAAa,wBAAwB;IAM7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,sCAAsC;IAR3D,OAAO,CAAC,yBAAyB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAGlB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,+BAA+B,EACjE,MAAM,EAAE,gBAAgB,EACP,YAAY,EAAE,YAAY,EAC1B,sCAAsC,EAAE,OAAO;IAKvD,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,eAAe;YAqBhE,oBAAoB;IA4DlC;;;;;;;;OAQG;YACW,4BAA4B;CAuG7C"}
|
|
@@ -46,7 +46,9 @@ class OdspSummaryUploadManager {
|
|
|
46
46
|
async writeSummaryTree(tree, context) {
|
|
47
47
|
// If the last proposed handle is not the proposed handle of the acked summary(could happen when the last summary get nacked),
|
|
48
48
|
// then re-initialize the caches with the previous ones else just update the previous caches with the caches from acked summary.
|
|
49
|
-
if
|
|
49
|
+
// Don't bother logging if lastSummaryProposalHandle hasn't been set before; only log on a positive mismatch.
|
|
50
|
+
if (this.lastSummaryProposalHandle !== undefined &&
|
|
51
|
+
this.lastSummaryProposalHandle !== context.proposalHandle) {
|
|
50
52
|
this.mc.logger.sendTelemetryEvent({
|
|
51
53
|
eventName: "LastSummaryProposedHandleMismatch",
|
|
52
54
|
ackedSummaryProposedHandle: context.proposalHandle,
|
|
@@ -87,6 +89,7 @@ class OdspSummaryUploadManager {
|
|
|
87
89
|
headers: Object.keys(headers).length !== 0 ? true : undefined,
|
|
88
90
|
blobs,
|
|
89
91
|
size: postBody.length,
|
|
92
|
+
referenceSequenceNumber,
|
|
90
93
|
}, async () => {
|
|
91
94
|
const response = await this.epochTracker.fetchAndParseAsJSON(url, {
|
|
92
95
|
body: postBody,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspSummaryUploadManager.js","sourceRoot":"","sources":["../src/odspSummaryUploadManager.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 { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Uint8ArrayToString, unreachableCase } from \"@fluidframework/common-utils\";\nimport { ISummaryContext } from \"@fluidframework/driver-definitions\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions\";\nimport { loggerToMonitoringContext, MonitoringContext, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspSummaryPayload,\n IWriteSummaryResponse,\n IOdspSummaryTree,\n IOdspSummaryTreeBaseEntry,\n OdspSummaryTreeEntry,\n OdspSummaryTreeValue,\n} from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils\";\n\n/* eslint-disable max-len */\n\n/**\n * This class manages a summary upload. When it receives a call to upload summary, it converts the summary tree into\n * a snapshot tree and then uploads that to the server.\n */\nexport class OdspSummaryUploadManager {\n // Last proposed handle of the uploaded app summary.\n private lastSummaryProposalHandle: string | undefined;\n private readonly mc: MonitoringContext;\n\n constructor(\n private readonly snapshotUrl: string,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n logger: ITelemetryLogger,\n private readonly epochTracker: EpochTracker,\n private readonly forceAccessTokenViaAuthorizationHeader: boolean,\n ) {\n this.mc = loggerToMonitoringContext(logger);\n }\n\n public async writeSummaryTree(tree: api.ISummaryTree, context: ISummaryContext) {\n // If the last proposed handle is not the proposed handle of the acked summary(could happen when the last summary get nacked),\n // then re-initialize the caches with the previous ones else just update the previous caches with the caches from acked summary.\n if (context.proposalHandle !== this.lastSummaryProposalHandle) {\n this.mc.logger.sendTelemetryEvent({\n eventName: \"LastSummaryProposedHandleMismatch\",\n ackedSummaryProposedHandle: context.proposalHandle,\n lastSummaryProposalHandle: this.lastSummaryProposalHandle,\n });\n }\n const result = await this.writeSummaryTreeCore(context.ackHandle, context.referenceSequenceNumber, tree);\n const id = result ? result.id : undefined;\n if (!result || !id) {\n throw new Error(`Failed to write summary tree`);\n }\n this.lastSummaryProposalHandle = id;\n return id;\n }\n\n private async writeSummaryTreeCore(\n parentHandle: string | undefined,\n referenceSequenceNumber: number,\n tree: api.ISummaryTree,\n ): Promise<IWriteSummaryResponse> {\n const { snapshotTree, blobs } = await this.convertSummaryToSnapshotTree(\n parentHandle,\n tree,\n \".app\",\n \"\",\n );\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries!,\n message: \"app\",\n sequenceNumber: referenceSequenceNumber,\n // no ack handle implies this is initial summary after empty file creation.\n // send container payload so server will use it without a summary op\n type: parentHandle === undefined ? \"container\" : \"channel\",\n };\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"WriteSummaryTree\");\n\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/snapshot`,\n storageToken,\n this.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/json\";\n if (parentHandle) {\n headers[\"If-Match\"] = `fluid:containerid=${parentHandle}`;\n }\n\n const postBody = JSON.stringify(snapshot);\n\n return PerformanceEvent.timedExecAsync(this.mc.logger,\n {\n eventName: \"uploadSummary\",\n attempt: options.refresh ? 2 : 1,\n hasClaims: !!options.claims,\n hasTenantId: !!options.tenantId,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n blobs,\n size: postBody.length,\n },\n async () => {\n const response = await this.epochTracker.fetchAndParseAsJSON<IWriteSummaryResponse>(\n url,\n {\n body: postBody,\n headers,\n method: \"POST\",\n },\n \"uploadSummary\");\n return response.content;\n });\n });\n }\n\n /**\n * Following are the goals of this function.\n * a.) Converts the summary tree to a snapshot/odsp tree to be uploaded. Always upload full snapshot tree.\n * @param parentHandle - Handle of the last uploaded summary or detach new summary.\n * @param tree - Summary Tree which will be converted to snapshot tree to be uploaded.\n * @param rootNodeName - Root node name of the summary tree.\n * @param path - Current path of node which is getting evaluated.\n * @param markUnreferencedNodes - True if we should mark unreferenced nodes.\n */\n private async convertSummaryToSnapshotTree(\n parentHandle: string | undefined,\n tree: api.ISummaryTree,\n rootNodeName: string,\n path: string = \"\",\n markUnreferencedNodes: boolean = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.MarkUnreferencedNodes\") ?? true,\n ) {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [] as OdspSummaryTreeEntry[],\n };\n\n let blobs = 0;\n const keys = Object.keys(tree.tree);\n for (const key of keys) {\n const summaryObject = tree.tree[key];\n\n let id: string | undefined;\n let value: OdspSummaryTreeValue | undefined;\n\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is\n // true (which is the only value it can have), the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n const currentPath = path === \"\" ? `${rootNodeName}/${key}` : `${path}/${key}`;\n switch (summaryObject.type) {\n case api.SummaryType.Tree: {\n const result = await this.convertSummaryToSnapshotTree(\n parentHandle,\n summaryObject,\n rootNodeName,\n currentPath);\n value = result.snapshotTree;\n unreferenced = markUnreferencedNodes ? summaryObject.unreferenced : undefined;\n blobs += result.blobs;\n break;\n }\n case api.SummaryType.Blob: {\n if (typeof summaryObject.content === \"string\") {\n value = {\n type: \"blob\",\n content: summaryObject.content,\n encoding: \"utf-8\",\n };\n } else {\n value = {\n type: \"blob\",\n content: Uint8ArrayToString(summaryObject.content, \"base64\"),\n encoding: \"base64\",\n };\n }\n blobs++;\n break;\n }\n case api.SummaryType.Handle: {\n if (!parentHandle) {\n throw Error(\"Parent summary does not exist to reference by handle.\");\n }\n let handlePath = summaryObject.handle;\n if (handlePath.length > 0 && !handlePath.startsWith(\"/\")) {\n handlePath = `/${handlePath}`;\n }\n const pathKey = `${rootNodeName}${handlePath}`;\n id = `${parentHandle}/${pathKey}`;\n break;\n }\n case api.SummaryType.Attachment: {\n id = summaryObject.id;\n break;\n }\n default: {\n unreachableCase(summaryObject, `Unknown type: ${(summaryObject as any).type}`);\n }\n }\n\n const baseEntry: IOdspSummaryTreeBaseEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n };\n\n let entry: OdspSummaryTreeEntry;\n\n if (value) {\n assert(id === undefined, 0x0ad /* \"Snapshot entry has both a tree value and a referenced id!\" */);\n entry = {\n value,\n ...baseEntry,\n unreferenced,\n };\n } else if (id) {\n entry = {\n ...baseEntry,\n id,\n };\n } else {\n throw new Error(`Invalid tree entry for ${summaryObject.type}`);\n }\n\n snapshotTree.entries!.push(entry);\n }\n\n return { snapshotTree, blobs };\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
|
1
|
+
{"version":3,"file":"odspSummaryUploadManager.js","sourceRoot":"","sources":["../src/odspSummaryUploadManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;AAGH,+DAA2F;AAE3F,iEAA2D;AAC3D,0EAA4D;AAE5D,qEAAiH;AAUjH,yEAAsE;AACtE,2CAA0D;AAE1D,4BAA4B;AAE5B;;;GAGG;AACH,MAAa,wBAAwB;IAKjC,YACqB,WAAmB,EACnB,eAAgD,EACjE,MAAwB,EACP,YAA0B,EAC1B,sCAA+C;QAJ/C,gBAAW,GAAX,WAAW,CAAQ;QACnB,oBAAe,GAAf,eAAe,CAAiC;QAEhD,iBAAY,GAAZ,YAAY,CAAc;QAC1B,2CAAsC,GAAtC,sCAAsC,CAAS;QAEhE,IAAI,CAAC,EAAE,GAAG,2CAAyB,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAAC,IAAsB,EAAE,OAAwB;QAC1E,8HAA8H;QAC9H,gIAAgI;QAChI,6GAA6G;QAC7G,IAAI,IAAI,CAAC,yBAAyB,KAAK,SAAS;YAC5C,IAAI,CAAC,yBAAyB,KAAK,OAAO,CAAC,cAAc,EAAE;YAC3D,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBAC9B,SAAS,EAAE,mCAAmC;gBAC9C,0BAA0B,EAAE,OAAO,CAAC,cAAc;gBAClD,yBAAyB,EAAE,IAAI,CAAC,yBAAyB;aAC5D,CAAC,CAAC;SACN;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;QACzG,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;SACnD;QACD,IAAI,CAAC,yBAAyB,GAAG,EAAE,CAAC;QACpC,OAAO,EAAE,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAC9B,YAAgC,EAChC,uBAA+B,EAC/B,IAAsB;QAEtB,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,4BAA4B,CACnE,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,EAAE,CACL,CAAC;QACF,MAAM,QAAQ,GAAwB;YAClC,OAAO,EAAE,YAAY,CAAC,OAAQ;YAC9B,OAAO,EAAE,KAAK;YACd,cAAc,EAAE,uBAAuB;YACvC,2EAA2E;YAC3E,oEAAoE;YACpE,IAAI,EAAE,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;SAC7D,CAAC;QAEF,OAAO,uCAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACjD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YAE7E,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,mDAAwB,CAC7C,GAAG,IAAI,CAAC,WAAW,WAAW,EAC9B,YAAY,EACZ,IAAI,CAAC,sCAAsC,CAC9C,CAAC;YACF,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,IAAI,YAAY,EAAE;gBACd,OAAO,CAAC,UAAU,CAAC,GAAG,qBAAqB,YAAY,EAAE,CAAC;aAC7D;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAE1C,OAAO,kCAAgB,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EACjD;gBACI,SAAS,EAAE,eAAe;gBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;gBAC3B,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ;gBAC/B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBAC7D,KAAK;gBACL,IAAI,EAAE,QAAQ,CAAC,MAAM;gBACrB,uBAAuB;aAC1B,EACD,KAAK,IAAI,EAAE;gBACP,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,mBAAmB,CACxD,GAAG,EACH;oBACI,IAAI,EAAE,QAAQ;oBACd,OAAO;oBACP,MAAM,EAAE,MAAM;iBACjB,EACD,eAAe,CAAC,CAAC;gBACrB,OAAO,QAAQ,CAAC,OAAO,CAAC;YAC5B,CAAC,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,4BAA4B,CACtC,YAAgC,EAChC,IAAsB,EACtB,YAAoB,EACpB,IAAiB,EACjB,qBAA6G;;6BAD7G,EAAA,SAAiB;8CACjB,EAAA,8BAAiC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,yCAAyC,CAAC,mCAAI,IAAI;QAE7G,MAAM,YAAY,GAAqB;YACnC,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,EAA4B;SACxC,CAAC;QAEF,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACpB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAErC,IAAI,EAAsB,CAAC;YAC3B,IAAI,KAAuC,CAAC;YAE5C,yGAAyG;YACzG,sGAAsG;YACtG,yFAAyF;YACzF,IAAI,YAA8B,CAAC;YACnC,MAAM,WAAW,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,YAAY,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;YAC9E,QAAQ,aAAa,CAAC,IAAI,EAAE;gBACxB,KAAK,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;oBACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,4BAA4B,CAClD,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,CAAC,CAAC;oBACjB,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;oBAC5B,YAAY,GAAG,qBAAqB,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;oBAC9E,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;oBACtB,MAAM;iBACT;gBACD,KAAK,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;oBACvB,IAAI,OAAO,aAAa,CAAC,OAAO,KAAK,QAAQ,EAAE;wBAC3C,KAAK,GAAG;4BACJ,IAAI,EAAE,MAAM;4BACZ,OAAO,EAAE,aAAa,CAAC,OAAO;4BAC9B,QAAQ,EAAE,OAAO;yBACpB,CAAC;qBACL;yBAAM;wBACH,KAAK,GAAG;4BACJ,IAAI,EAAE,MAAM;4BACZ,OAAO,EAAE,iCAAkB,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC;4BAC5D,QAAQ,EAAE,QAAQ;yBACrB,CAAC;qBACL;oBACD,KAAK,EAAE,CAAC;oBACR,MAAM;iBACT;gBACD,KAAK,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBACzB,IAAI,CAAC,YAAY,EAAE;wBACf,MAAM,KAAK,CAAC,uDAAuD,CAAC,CAAC;qBACxE;oBACD,IAAI,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC;oBACtC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;wBACtD,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;qBACjC;oBACD,MAAM,OAAO,GAAG,GAAG,YAAY,GAAG,UAAU,EAAE,CAAC;oBAC/C,EAAE,GAAG,GAAG,YAAY,IAAI,OAAO,EAAE,CAAC;oBAClC,MAAM;iBACT;gBACD,KAAK,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;oBAC7B,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC;oBACtB,MAAM;iBACT;gBACD,OAAO,CAAC,CAAC;oBACL,8BAAe,CAAC,aAAa,EAAE,iBAAkB,aAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;iBAClF;aACJ;YAED,MAAM,SAAS,GAA8B;gBACzC,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC;gBAC7B,IAAI,EAAE,0BAAU,CAAC,aAAa,CAAC;aAClC,CAAC;YAEF,IAAI,KAA2B,CAAC;YAEhC,IAAI,KAAK,EAAE;gBACP,qBAAM,CAAC,EAAE,KAAK,SAAS,EAAE,KAAK,CAAC,iEAAiE,CAAC,CAAC;gBAClG,KAAK,iCACD,KAAK,IACF,SAAS,KACZ,YAAY,GACf,CAAC;aACL;iBAAM,IAAI,EAAE,EAAE;gBACX,KAAK,mCACE,SAAS,KACZ,EAAE,GACL,CAAC;aACL;iBAAM;gBACH,MAAM,IAAI,KAAK,CAAC,0BAA0B,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;aACnE;YAED,YAAY,CAAC,OAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACrC;QAED,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;CACJ;AAhND,4DAgNC;AAED,2BAA2B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Uint8ArrayToString, unreachableCase } from \"@fluidframework/common-utils\";\nimport { ISummaryContext } from \"@fluidframework/driver-definitions\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions\";\nimport { loggerToMonitoringContext, MonitoringContext, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspSummaryPayload,\n IWriteSummaryResponse,\n IOdspSummaryTree,\n IOdspSummaryTreeBaseEntry,\n OdspSummaryTreeEntry,\n OdspSummaryTreeValue,\n} from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils\";\n\n/* eslint-disable max-len */\n\n/**\n * This class manages a summary upload. When it receives a call to upload summary, it converts the summary tree into\n * a snapshot tree and then uploads that to the server.\n */\nexport class OdspSummaryUploadManager {\n // Last proposed handle of the uploaded app summary.\n private lastSummaryProposalHandle: string | undefined;\n private readonly mc: MonitoringContext;\n\n constructor(\n private readonly snapshotUrl: string,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n logger: ITelemetryLogger,\n private readonly epochTracker: EpochTracker,\n private readonly forceAccessTokenViaAuthorizationHeader: boolean,\n ) {\n this.mc = loggerToMonitoringContext(logger);\n }\n\n public async writeSummaryTree(tree: api.ISummaryTree, context: ISummaryContext) {\n // If the last proposed handle is not the proposed handle of the acked summary(could happen when the last summary get nacked),\n // then re-initialize the caches with the previous ones else just update the previous caches with the caches from acked summary.\n // Don't bother logging if lastSummaryProposalHandle hasn't been set before; only log on a positive mismatch.\n if (this.lastSummaryProposalHandle !== undefined &&\n this.lastSummaryProposalHandle !== context.proposalHandle) {\n this.mc.logger.sendTelemetryEvent({\n eventName: \"LastSummaryProposedHandleMismatch\",\n ackedSummaryProposedHandle: context.proposalHandle,\n lastSummaryProposalHandle: this.lastSummaryProposalHandle,\n });\n }\n const result = await this.writeSummaryTreeCore(context.ackHandle, context.referenceSequenceNumber, tree);\n const id = result ? result.id : undefined;\n if (!result || !id) {\n throw new Error(`Failed to write summary tree`);\n }\n this.lastSummaryProposalHandle = id;\n return id;\n }\n\n private async writeSummaryTreeCore(\n parentHandle: string | undefined,\n referenceSequenceNumber: number,\n tree: api.ISummaryTree,\n ): Promise<IWriteSummaryResponse> {\n const { snapshotTree, blobs } = await this.convertSummaryToSnapshotTree(\n parentHandle,\n tree,\n \".app\",\n \"\",\n );\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries!,\n message: \"app\",\n sequenceNumber: referenceSequenceNumber,\n // no ack handle implies this is initial summary after empty file creation.\n // send container payload so server will use it without a summary op\n type: parentHandle === undefined ? \"container\" : \"channel\",\n };\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"WriteSummaryTree\");\n\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/snapshot`,\n storageToken,\n this.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/json\";\n if (parentHandle) {\n headers[\"If-Match\"] = `fluid:containerid=${parentHandle}`;\n }\n\n const postBody = JSON.stringify(snapshot);\n\n return PerformanceEvent.timedExecAsync(this.mc.logger,\n {\n eventName: \"uploadSummary\",\n attempt: options.refresh ? 2 : 1,\n hasClaims: !!options.claims,\n hasTenantId: !!options.tenantId,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n blobs,\n size: postBody.length,\n referenceSequenceNumber,\n },\n async () => {\n const response = await this.epochTracker.fetchAndParseAsJSON<IWriteSummaryResponse>(\n url,\n {\n body: postBody,\n headers,\n method: \"POST\",\n },\n \"uploadSummary\");\n return response.content;\n });\n });\n }\n\n /**\n * Following are the goals of this function.\n * a.) Converts the summary tree to a snapshot/odsp tree to be uploaded. Always upload full snapshot tree.\n * @param parentHandle - Handle of the last uploaded summary or detach new summary.\n * @param tree - Summary Tree which will be converted to snapshot tree to be uploaded.\n * @param rootNodeName - Root node name of the summary tree.\n * @param path - Current path of node which is getting evaluated.\n * @param markUnreferencedNodes - True if we should mark unreferenced nodes.\n */\n private async convertSummaryToSnapshotTree(\n parentHandle: string | undefined,\n tree: api.ISummaryTree,\n rootNodeName: string,\n path: string = \"\",\n markUnreferencedNodes: boolean = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.MarkUnreferencedNodes\") ?? true,\n ) {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [] as OdspSummaryTreeEntry[],\n };\n\n let blobs = 0;\n const keys = Object.keys(tree.tree);\n for (const key of keys) {\n const summaryObject = tree.tree[key];\n\n let id: string | undefined;\n let value: OdspSummaryTreeValue | undefined;\n\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is\n // true (which is the only value it can have), the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n const currentPath = path === \"\" ? `${rootNodeName}/${key}` : `${path}/${key}`;\n switch (summaryObject.type) {\n case api.SummaryType.Tree: {\n const result = await this.convertSummaryToSnapshotTree(\n parentHandle,\n summaryObject,\n rootNodeName,\n currentPath);\n value = result.snapshotTree;\n unreferenced = markUnreferencedNodes ? summaryObject.unreferenced : undefined;\n blobs += result.blobs;\n break;\n }\n case api.SummaryType.Blob: {\n if (typeof summaryObject.content === \"string\") {\n value = {\n type: \"blob\",\n content: summaryObject.content,\n encoding: \"utf-8\",\n };\n } else {\n value = {\n type: \"blob\",\n content: Uint8ArrayToString(summaryObject.content, \"base64\"),\n encoding: \"base64\",\n };\n }\n blobs++;\n break;\n }\n case api.SummaryType.Handle: {\n if (!parentHandle) {\n throw Error(\"Parent summary does not exist to reference by handle.\");\n }\n let handlePath = summaryObject.handle;\n if (handlePath.length > 0 && !handlePath.startsWith(\"/\")) {\n handlePath = `/${handlePath}`;\n }\n const pathKey = `${rootNodeName}${handlePath}`;\n id = `${parentHandle}/${pathKey}`;\n break;\n }\n case api.SummaryType.Attachment: {\n id = summaryObject.id;\n break;\n }\n default: {\n unreachableCase(summaryObject, `Unknown type: ${(summaryObject as any).type}`);\n }\n }\n\n const baseEntry: IOdspSummaryTreeBaseEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n };\n\n let entry: OdspSummaryTreeEntry;\n\n if (value) {\n assert(id === undefined, 0x0ad /* \"Snapshot entry has both a tree value and a referenced id!\" */);\n entry = {\n value,\n ...baseEntry,\n unreferenced,\n };\n } else if (id) {\n entry = {\n ...baseEntry,\n id,\n };\n } else {\n throw new Error(`Invalid tree entry for ${summaryObject.type}`);\n }\n\n snapshotTree.entries!.push(entry);\n }\n\n return { snapshotTree, blobs };\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
package/dist/odspUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspUtils.d.ts","sourceRoot":"","sources":["../src/odspUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAClH,OAAO,EAAE,YAAY,EAAmB,MAAM,oCAAoC,CAAC;AASnF,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAOhG,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EAIjB,6BAA6B,EAC7B,cAAc,EACd,YAAY,EACZ,WAAW,EAEX,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,eAAO,MAAM,iCAAiC,sCAAsC,CAAC;AAErF,4DAA4D;AAC5D,eAAO,MAAM,SAAS,QAAS,MAAM,WAAwB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAC9B,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAChC,GAAG,EAAE,yBAAyB,EAAE,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC1D,2DAA2D;IAC3D,aAAa,CAAC,EAAE,GAAG,CAAC;CACvB;AAUD;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,CAAC,CAAC,cAoBrG;AAED,wBAAsB,WAAW,CAC7B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GAAG,SAAS,GACrC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"odspUtils.d.ts","sourceRoot":"","sources":["../src/odspUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAClH,OAAO,EAAE,YAAY,EAAmB,MAAM,oCAAoC,CAAC;AASnF,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAOhG,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EAIjB,6BAA6B,EAC7B,cAAc,EACd,YAAY,EACZ,WAAW,EAEX,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,eAAO,MAAM,iCAAiC,sCAAsC,CAAC;AAErF,4DAA4D;AAC5D,eAAO,MAAM,SAAS,QAAS,MAAM,WAAwB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAC9B,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAChC,GAAG,EAAE,yBAAyB,EAAE,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC1D,2DAA2D;IAC3D,aAAa,CAAC,EAAE,GAAG,CAAC;CACvB;AAUD;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,CAAC,CAAC,cAoBrG;AAED,wBAAsB,WAAW,CAC7B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GAAG,SAAS,GACrC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CA2DlC;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC5B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GAAG,SAAS,GACrC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAWrC;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,CAAC,EAC7C,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GAAG,SAAS,GACrC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CA2B3B;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,gBAAgB,CAG9E;AAED,eAAO,MAAM,gBAAgB,0GAQnB,CAAC;AAEX,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa;;;;;EAqBxD;AAED,wBAAgB,8BAA8B,CAC1C,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,EAAE,YAAY,CAAC,6BAA6B,CAAC,EACzD,gBAAgB,EAAE,OAAO,GAC1B,+BAA+B,CAqDjC;AAED,wBAAgB,sBAAsB,CAAC,eAAe,EAAE,gBAAgB,GAAG,WAAW,CAUrF"}
|