@fluidframework/odsp-driver 3.0.2 → 3.1.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/CHANGELOG.md +10 -0
- package/README.md +30 -34
- package/api-report/odsp-driver.legacy.alpha.api.md +5 -1
- package/api-report/odsp-driver.legacy.beta.api.md +5 -1
- package/api-report/odsp-driver.point-in-time.legacy.beta.api.md +2 -1
- package/dist/epochTracker.d.ts +4 -3
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +9 -5
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts +2 -2
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +12 -7
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.d.ts +1 -1
- package/dist/getFileLink.d.ts.map +1 -1
- package/dist/getFileLink.js +16 -11
- package/dist/getFileLink.js.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.js +1 -1
- package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/odspDocumentDeltaConnection.js +6 -3
- package/dist/odspDocumentDeltaConnection.js.map +1 -1
- package/dist/odspDocumentServiceFactory.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactory.js +1 -0
- package/dist/odspDocumentServiceFactory.js.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.d.ts +4 -1
- package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.js +11 -5
- package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
- package/dist/odspDocumentStorageManager.d.ts.map +1 -1
- package/dist/odspDocumentStorageManager.js +11 -11
- package/dist/odspDocumentStorageManager.js.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.d.ts +5 -0
- package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.js +3 -1
- package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/dist/odspVersionManager/odspFileVersionFetcher.d.ts +1 -0
- package/dist/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
- package/dist/odspVersionManager/odspFileVersionFetcher.js +6 -2
- package/dist/odspVersionManager/odspFileVersionFetcher.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/pointInTimeDriver/createPointInTimeDocumentService.d.ts +1 -1
- package/dist/pointInTimeDriver/createPointInTimeDocumentService.d.ts.map +1 -1
- package/dist/pointInTimeDriver/createPointInTimeDocumentService.js +5 -4
- package/dist/pointInTimeDriver/createPointInTimeDocumentService.js.map +1 -1
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +1 -1
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js +21 -1
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
- package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
- package/dist/prefetchLatestSnapshot.js +2 -2
- package/dist/prefetchLatestSnapshot.js.map +1 -1
- package/dist/requestHeaders.d.ts +19 -0
- package/dist/requestHeaders.d.ts.map +1 -0
- package/dist/requestHeaders.js +48 -0
- package/dist/requestHeaders.js.map +1 -0
- package/lib/epochTracker.d.ts +4 -3
- package/lib/epochTracker.d.ts.map +1 -1
- package/lib/epochTracker.js +9 -5
- package/lib/epochTracker.js.map +1 -1
- package/lib/fetchSnapshot.d.ts +2 -2
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +12 -7
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/getFileLink.d.ts +1 -1
- package/lib/getFileLink.d.ts.map +1 -1
- package/lib/getFileLink.js +16 -11
- package/lib/getFileLink.js.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/lib/odspDelayLoadedDeltaStream.js +1 -1
- package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
- package/lib/odspDocumentDeltaConnection.d.ts +1 -1
- package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/lib/odspDocumentDeltaConnection.js +6 -3
- package/lib/odspDocumentDeltaConnection.js.map +1 -1
- package/lib/odspDocumentServiceFactory.d.ts.map +1 -1
- package/lib/odspDocumentServiceFactory.js +1 -0
- package/lib/odspDocumentServiceFactory.js.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.d.ts +4 -1
- package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.js +11 -5
- package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
- package/lib/odspDocumentStorageManager.d.ts.map +1 -1
- package/lib/odspDocumentStorageManager.js +11 -11
- package/lib/odspDocumentStorageManager.js.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.d.ts +5 -0
- package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/lib/odspDriverUrlResolverForShareLink.js +3 -1
- package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/lib/odspVersionManager/odspFileVersionFetcher.d.ts +1 -0
- package/lib/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
- package/lib/odspVersionManager/odspFileVersionFetcher.js +6 -2
- package/lib/odspVersionManager/odspFileVersionFetcher.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/pointInTimeDriver/createPointInTimeDocumentService.d.ts +1 -1
- package/lib/pointInTimeDriver/createPointInTimeDocumentService.d.ts.map +1 -1
- package/lib/pointInTimeDriver/createPointInTimeDocumentService.js +5 -4
- package/lib/pointInTimeDriver/createPointInTimeDocumentService.js.map +1 -1
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +1 -1
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js +21 -1
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
- package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
- package/lib/prefetchLatestSnapshot.js +2 -2
- package/lib/prefetchLatestSnapshot.js.map +1 -1
- package/lib/requestHeaders.d.ts +19 -0
- package/lib/requestHeaders.d.ts.map +1 -0
- package/lib/requestHeaders.js +44 -0
- package/lib/requestHeaders.js.map +1 -0
- package/package.json +11 -11
- package/src/epochTracker.ts +9 -1
- package/src/fetchSnapshot.ts +17 -4
- package/src/getFileLink.ts +21 -7
- package/src/odspDelayLoadedDeltaStream.ts +1 -0
- package/src/odspDocumentDeltaConnection.ts +6 -0
- package/src/odspDocumentServiceFactory.ts +1 -0
- package/src/odspDocumentServiceFactoryCore.ts +14 -2
- package/src/odspDocumentStorageManager.ts +13 -3
- package/src/odspDriverUrlResolverForShareLink.ts +8 -0
- package/src/odspVersionManager/DEV.md +5 -1
- package/src/odspVersionManager/odspFileVersionFetcher.ts +7 -2
- package/src/packageVersion.ts +1 -1
- package/src/pointInTimeDriver/createPointInTimeDocumentService.ts +5 -1
- package/src/pointInTimeDriver/odspPointInTimeDocumentService.ts +40 -10
- package/src/prefetchLatestSnapshot.ts +4 -0
- package/src/requestHeaders.ts +56 -0
|
@@ -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 type { IRequest, ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { PromiseCache } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIContainerPackageInfo,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tIOdspResolvedUrl,\n\tIdentityType,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { type OdspFluidDataStoreLocator, SharingLinkHeader } from \"./contractsPublic.js\";\nimport { createOdspUrl } from \"./createOdspUrl.js\";\nimport { getFileLink } from \"./getFileLink.js\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver.js\";\nimport {\n\tgetLocatorFromOdspUrl,\n\tlocatorQueryParamName,\n\tstoreLocatorInOdspUrl,\n} from \"./odspFluidFileLink.js\";\nimport {\n\tappendNavParam,\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\tgetContainerPackageName,\n} from \"./odspUtils.js\";\n\n/**\n * Properties passed to the code responsible for fetching share link for a file.\n * @legacy\n * @beta\n */\nexport interface ShareLinkFetcherProps {\n\t/**\n\t * Callback method that is used to fetch access token necessary to call API that produces share link\n\t */\n\ttokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>;\n\t/**\n\t * Identity type determining the shape of share link as it differs for Enterprise and Consumer users.\n\t */\n\tidentityType: 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 * @legacy\n * @beta\n */\nexport class OdspDriverUrlResolverForShareLink implements IUrlResolver {\n\tprivate readonly logger: TelemetryLoggerExt;\n\tprivate readonly sharingLinkCache = new PromiseCache<string, string>();\n\tprivate readonly shareLinkFetcherProps: ShareLinkFetcherProps | undefined;\n\n\t/**\n\t * Creates url resolver instance\n\t * @param shareLinkFetcherProps - properties used when fetching share link.\n\t * Can be set as 'undefined' for cases where share link is not needed. Currently, only\n\t * getAbsoluteUrl() method requires share link.\n\t * @param logger - logger object that is used as telemetry sink\n\t * @param appName - application name hint that is encoded with url produced by getAbsoluteUrl() method.\n\t * This hint is used by link handling logic which determines which app to redirect to when user\n\t * navigates directly to the link.\n\t * @param getContext - callback function which is used to get context for given resolved url. If context\n\t * is returned then it will be embedded into url returned by getAbsoluteUrl() method.\n\t * @param containerPackageInfo - container package information which will be used to extract the container package name.\n\t */\n\tpublic constructor(\n\t\tshareLinkFetcherProps?: ShareLinkFetcherProps | undefined,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tprivate readonly appName?: string,\n\t\tprivate readonly getContext?: (\n\t\t\tresolvedUrl: IOdspResolvedUrl,\n\t\t\tdataStorePath: string,\n\t\t) => Promise<string | undefined>,\n\t\tprivate readonly containerPackageInfo?: IContainerPackageInfo,\n\t) {\n\t\tthis.logger = createOdspLogger(logger);\n\t\tif (shareLinkFetcherProps) {\n\t\t\tthis.shareLinkFetcherProps = {\n\t\t\t\t...shareLinkFetcherProps,\n\t\t\t\ttokenFetcher: shareLinkFetcherProps.tokenFetcher,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Takes an already generated data store url (from requestUrl) and appends a path to the\n\t * existing data store information.\n\t */\n\tpublic appendDataStorePath(requestUrl: URL, pathToAppend: string): string | undefined {\n\t\tconst fluidInfo = getLocatorFromOdspUrl(requestUrl);\n\n\t\tif (!fluidInfo) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst parsingUrl = new URL(\n\t\t\tfluidInfo.dataStorePath,\n\t\t\t`${requestUrl.protocol}//${requestUrl.hostname}`,\n\t\t);\n\t\t// Determine if the caller is passing a query parameter or path since processing will be different.\n\t\tif (pathToAppend.startsWith(\"/?\") || pathToAppend.startsWith(\"?\")) {\n\t\t\tconst queryParams = new URLSearchParams(pathToAppend);\n\t\t\tfor (const [key, value] of queryParams.entries()) {\n\t\t\t\tparsingUrl.searchParams.append(key, value);\n\t\t\t}\n\t\t\tfluidInfo.dataStorePath = `${parsingUrl.pathname}${parsingUrl.search}`;\n\t\t} else {\n\t\t\tfluidInfo.dataStorePath = `${parsingUrl.pathname}${\n\t\t\t\tparsingUrl.pathname.endsWith(\"/\") || pathToAppend.startsWith(\"/\") ? \"\" : \"/\"\n\t\t\t}${pathToAppend}/${parsingUrl.search}`;\n\t\t}\n\t\tstoreLocatorInOdspUrl(requestUrl, fluidInfo);\n\n\t\treturn requestUrl.href;\n\t}\n\n\tprivate getKey(resolvedUrl: IOdspResolvedUrl): string {\n\t\treturn `${resolvedUrl.siteUrl},${resolvedUrl.driveId},${resolvedUrl.itemId}`;\n\t}\n\n\t/**\n\t * Resolves request URL into driver details\n\t */\n\tpublic async resolve(request: IRequest): Promise<IOdspResolvedUrl> {\n\t\tconst requestToBeResolved = { headers: request.headers, url: request.url };\n\t\tconst isSharingLinkToRedeem =\n\t\t\trequestToBeResolved.headers?.[SharingLinkHeader.isSharingLinkToRedeem];\n\t\tconst isRedemptionNonDurable =\n\t\t\trequestToBeResolved.headers?.[SharingLinkHeader.isRedemptionNonDurable];\n\t\ttry {\n\t\t\tconst url = new URL(request.url);\n\n\t\t\tconst odspFluidInfo = getLocatorFromOdspUrl(url);\n\t\t\tif (odspFluidInfo) {\n\t\t\t\trequestToBeResolved.url = createOdspUrl(odspFluidInfo);\n\t\t\t}\n\t\t} catch {\n\t\t\t// If the locator throws some error, then try to resolve the request as it is.\n\t\t}\n\n\t\tconst odspResolvedUrl = await new OdspDriverUrlResolver().resolve(requestToBeResolved);\n\n\t\todspResolvedUrl.context = await this.getContext?.(\n\t\t\todspResolvedUrl,\n\t\t\todspResolvedUrl.dataStorePath ?? \"\",\n\t\t);\n\n\t\todspResolvedUrl.appName = this.appName;\n\n\t\todspResolvedUrl.codeHint = odspResolvedUrl.codeHint?.containerPackageName\n\t\t\t? odspResolvedUrl.codeHint\n\t\t\t: { containerPackageName: getContainerPackageName(this.containerPackageInfo) };\n\n\t\tif (isSharingLinkToRedeem) {\n\t\t\t// We need to remove the nav param if set by host when setting the sharelink as otherwise the shareLinkId\n\t\t\t// when redeeming the share link during the redeem fallback for trees latest call becomes greater than\n\t\t\t// the eligible length.\n\t\t\todspResolvedUrl.shareLinkInfo = Object.assign(odspResolvedUrl.shareLinkInfo ?? {}, {\n\t\t\t\tsharingLinkToRedeem: this.removeNavParam(request.url),\n\t\t\t\tisRedemptionNonDurable: isRedemptionNonDurable ?? false,\n\t\t\t});\n\t\t}\n\t\tif (odspResolvedUrl.itemId) {\n\t\t\t// Kick start the sharing link request if we don't have it already as a performance optimization.\n\t\t\t// For detached create new, we don't have an item id yet and therefore cannot generate a share link\n\t\t\tthis.getShareLinkPromise(odspResolvedUrl).catch(() => {});\n\t\t}\n\t\treturn odspResolvedUrl;\n\t}\n\n\tprivate removeNavParam(link: string): string {\n\t\tconst url = new URL(link);\n\t\tconst params = new URLSearchParams(url.search);\n\t\tparams.delete(locatorQueryParamName);\n\t\turl.search = params.toString();\n\t\treturn url.href;\n\t}\n\n\tprivate async getShareLinkPromise(resolvedUrl: IOdspResolvedUrl): Promise<string> {\n\t\tif (this.shareLinkFetcherProps === undefined) {\n\t\t\tthrow new Error(\"Failed to get share link because share link fetcher props are missing\");\n\t\t}\n\n\t\tif (!(resolvedUrl.siteUrl && resolvedUrl.driveId && resolvedUrl.itemId)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Failed to get share link because necessary information is missing \" +\n\t\t\t\t\t\"(e.g. siteUrl, driveId or itemId)\",\n\t\t\t);\n\t\t}\n\n\t\tconst key = this.getKey(resolvedUrl);\n\t\tconst cachedLinkPromise = this.sharingLinkCache.get(key);\n\t\tif (cachedLinkPromise) {\n\t\t\treturn cachedLinkPromise;\n\t\t}\n\t\tconst newLinkPromise = getFileLink(\n\t\t\tthis.shareLinkFetcherProps.tokenFetcher,\n\t\t\tresolvedUrl,\n\t\t\tthis.logger,\n\t\t).catch((error) => {\n\t\t\t// This should imply that error is a non-retriable error.\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"FluidFileUrlError\" }, error);\n\t\t\tthis.sharingLinkCache.remove(key);\n\t\t\tthrow error;\n\t\t});\n\t\tthis.sharingLinkCache.add(key, async () => newLinkPromise);\n\t\treturn newLinkPromise;\n\t}\n\n\t/**\n\t * Requests a driver + data store storage URL. Note that this method requires share link to be fetched\n\t * and it will throw in case share link fetcher props were not specified when instance was created.\n\t * @param resolvedUrl - The driver resolved URL\n\t * @param dataStorePath - The relative data store path URL.\n\t * For requesting a driver URL, this value should always be '/'. If an empty string is passed, then dataStorePath\n\t * will be extracted from the resolved url if present.\n\t * @param packageInfoSource - optional, represents container package information to be included in url.\n\t */\n\tpublic async getAbsoluteUrl(\n\t\tresolvedUrl: IResolvedUrl,\n\t\tdataStorePath: string,\n\t\tpackageInfoSource?: IContainerPackageInfo,\n\t): Promise<string> {\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\t\tconst shareLink = await this.getShareLinkPromise(odspResolvedUrl);\n\n\t\treturn this.appendLocatorParams(shareLink, resolvedUrl, dataStorePath, packageInfoSource);\n\t}\n\n\t/**\n\t * Appends the store locator properties to the provided base URL. This function is useful for scenarios where an application\n\t * has a base URL (for example a sharing link) of the Fluid file, but does not have the locator information that would be used by Fluid\n\t * to load the file later.\n\t * @param baseUrl - The input URL on which the locator params will be appended.\n\t * @param resolvedUrl - odsp-driver's resolvedURL object.\n\t * @param dataStorePath - The relative data store path URL.\n\t * For requesting a driver URL, this value should always be '/'. If an empty string is passed, then dataStorePath\n\t * will be extracted from the resolved url if present.\n\t * @returns The provided base URL appended with odsp-specific locator information\n\t */\n\tpublic async appendLocatorParams(\n\t\tbaseUrl: string,\n\t\tresolvedUrl: IResolvedUrl,\n\t\tdataStorePath: string,\n\t\tpackageInfoSource?: IContainerPackageInfo,\n\t): Promise<string> {\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\t\t// If the user has passed an empty dataStorePath, then extract it from the resolved url.\n\t\tconst actualDataStorePath = dataStorePath || (odspResolvedUrl.dataStorePath ?? \"\");\n\n\t\todspResolvedUrl.context = await this.getContext?.(odspResolvedUrl, actualDataStorePath);\n\n\t\t/**\n\t\t * containerPackageName can be provided by various ways, in the order of priority:\n\t\t * 1. packageInfoSource - passed by the call of appendLocatorParams\n\t\t * 2. odspResolvedUrl.codeHint?.containerPackageName - passed by the odsp-driver's resolvedURL object\n\t\t * 3. this.containerPackageInfo - passed by the constructor of OdspDrvierUrlResolverForShareLink\n\t\t * */\n\t\tconst containerPackageName: string | undefined =\n\t\t\tgetContainerPackageName(packageInfoSource) ??\n\t\t\todspResolvedUrl.codeHint?.containerPackageName ??\n\t\t\tgetContainerPackageName(this.containerPackageInfo);\n\n\t\todspResolvedUrl.appName = this.appName;\n\n\t\treturn appendNavParam(baseUrl, odspResolvedUrl, actualDataStorePath, containerPackageName);\n\t}\n\n\t/**\n\t * Crafts a supported document/driver URL\n\t */\n\tpublic static createDocumentUrl(\n\t\tbaseUrl: string,\n\t\tdriverInfo: OdspFluidDataStoreLocator,\n\t): string {\n\t\tconst url = new URL(baseUrl);\n\n\t\tstoreLocatorInOdspUrl(url, driverInfo);\n\n\t\treturn url.href;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspDriverUrlResolverForShareLink.js","sourceRoot":"","sources":["../src/odspDriverUrlResolverForShareLink.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,kEAAmE;AAcnE,6DAAyF;AACzF,yDAAmD;AACnD,qDAA+C;AAC/C,2DAAyD;AACzD,yEAAmE;AACnE,iEAIgC;AAChC,iDAKwB;AAuBxB;;;;;;GAMG;AACH,MAAa,iCAAiC;IAqB3B;IACA;IAIA;IAzBD,MAAM,CAAqB;IAC3B,gBAAgB,GAAG,IAAI,uBAAY,EAAkB,CAAC;IACtD,qBAAqB,CAAoC;IAE1E;;;;;;;;;;;;OAYG;IACH,YACC,qBAAyD,EACzD,MAA6B,EACZ,OAAgB,EAChB,UAGe,EACf,oBAA4C;QAL5C,YAAO,GAAP,OAAO,CAAS;QAChB,eAAU,GAAV,UAAU,CAGK;QACf,yBAAoB,GAApB,oBAAoB,CAAwB;QAE7D,IAAI,CAAC,MAAM,GAAG,IAAA,+BAAgB,EAAC,MAAM,CAAC,CAAC;QACvC,IAAI,qBAAqB,EAAE,CAAC;YAC3B,IAAI,CAAC,qBAAqB,GAAG;gBAC5B,GAAG,qBAAqB;gBACxB,YAAY,EAAE,qBAAqB,CAAC,YAAY;gBAChD,cAAc,EAAE,IAAA,sCAAkB,EAAC,qBAAqB,CAAC,cAAc,CAAC;aACxE,CAAC;QACH,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,mBAAmB,CAAC,UAAe,EAAE,YAAoB;QAC/D,MAAM,SAAS,GAAG,IAAA,4CAAqB,EAAC,UAAU,CAAC,CAAC;QAEpD,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,GAAG,CACzB,SAAS,CAAC,aAAa,EACvB,GAAG,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,EAAE,CAChD,CAAC;QACF,mGAAmG;QACnG,IAAI,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,YAAY,CAAC,CAAC;YACtD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClD,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC5C,CAAC;YACD,SAAS,CAAC,aAAa,GAAG,GAAG,UAAU,CAAC,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;QACxE,CAAC;aAAM,CAAC;YACP,SAAS,CAAC,aAAa,GAAG,GAAG,UAAU,CAAC,QAAQ,GAC/C,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAC1E,GAAG,YAAY,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACxC,CAAC;QACD,IAAA,4CAAqB,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAE7C,OAAO,UAAU,CAAC,IAAI,CAAC;IACxB,CAAC;IAEO,MAAM,CAAC,WAA6B;QAC3C,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IAC9E,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,OAAO,CAAC,OAAiB;QACrC,MAAM,mBAAmB,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC3E,MAAM,qBAAqB,GAC1B,mBAAmB,CAAC,OAAO,EAAE,CAAC,sCAAiB,CAAC,qBAAqB,CAAC,CAAC;QACxE,MAAM,sBAAsB,GAC3B,mBAAmB,CAAC,OAAO,EAAE,CAAC,sCAAiB,CAAC,sBAAsB,CAAC,CAAC;QACzE,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAEjC,MAAM,aAAa,GAAG,IAAA,4CAAqB,EAAC,GAAG,CAAC,CAAC;YACjD,IAAI,aAAa,EAAE,CAAC;gBACnB,mBAAmB,CAAC,GAAG,GAAG,IAAA,gCAAa,EAAC,aAAa,CAAC,CAAC;YACxD,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,8EAA8E;QAC/E,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,IAAI,gDAAqB,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAEvF,eAAe,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAChD,eAAe,EACf,eAAe,CAAC,aAAa,IAAI,EAAE,CACnC,CAAC;QAEF,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAEvC,eAAe,CAAC,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,oBAAoB;YACxE,CAAC,CAAC,eAAe,CAAC,QAAQ;YAC1B,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAA,sCAAuB,EAAC,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAEhF,IAAI,qBAAqB,EAAE,CAAC;YAC3B,yGAAyG;YACzG,sGAAsG;YACtG,uBAAuB;YACvB,eAAe,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,aAAa,IAAI,EAAE,EAAE;gBAClF,mBAAmB,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC;gBACrD,sBAAsB,EAAE,sBAAsB,IAAI,KAAK;aACvD,CAAC,CAAC;QACJ,CAAC;QACD,IAAI,eAAe,CAAC,MAAM,EAAE,CAAC;YAC5B,iGAAiG;YACjG,mGAAmG;YACnG,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,eAAe,CAAC;IACxB,CAAC;IAEO,cAAc,CAAC,IAAY;QAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,4CAAqB,CAAC,CAAC;QACrC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,IAAI,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,WAA6B;QAC9D,IAAI,IAAI,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CACd,oEAAoE;gBACnE,mCAAmC,CACpC,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACrC,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzD,IAAI,iBAAiB,EAAE,CAAC;YACvB,OAAO,iBAAiB,CAAC;QAC1B,CAAC;QACD,MAAM,cAAc,GAAG,IAAA,4BAAW,EACjC,IAAI,CAAC,qBAAqB,CAAC,YAAY,EACvC,WAAW,EACX,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,qBAAqB,CAAC,cAAc,CACzC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACjB,yDAAyD;YACzD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,EAAE,KAAK,CAAC,CAAC;YACtE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,KAAK,CAAC;QACb,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,cAAc,CAAC,CAAC;QAC3D,OAAO,cAAc,CAAC;IACvB,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,cAAc,CAC1B,WAAyB,EACzB,aAAqB,EACrB,iBAAyC;QAEzC,MAAM,eAAe,GAAG,IAAA,iCAAkB,EAAC,WAAW,CAAC,CAAC;QAExD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC;QAElE,OAAO,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;IAC3F,CAAC;IAED;;;;;;;;;;OAUG;IACI,KAAK,CAAC,mBAAmB,CAC/B,OAAe,EACf,WAAyB,EACzB,aAAqB,EACrB,iBAAyC;QAEzC,MAAM,eAAe,GAAG,IAAA,iCAAkB,EAAC,WAAW,CAAC,CAAC;QAExD,wFAAwF;QACxF,MAAM,mBAAmB,GAAG,aAAa,IAAI,CAAC,eAAe,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QAEnF,eAAe,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;QAExF;;;;;aAKK;QACL,MAAM,oBAAoB,GACzB,IAAA,sCAAuB,EAAC,iBAAiB,CAAC;YAC1C,eAAe,CAAC,QAAQ,EAAE,oBAAoB;YAC9C,IAAA,sCAAuB,EAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAEpD,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAEvC,OAAO,IAAA,6BAAc,EAAC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,CAAC,CAAC;IAC5F,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,iBAAiB,CAC9B,OAAe,EACf,UAAqC;QAErC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAE7B,IAAA,4CAAqB,EAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEvC,OAAO,GAAG,CAAC,IAAI,CAAC;IACjB,CAAC;CACD;AA9OD,8EA8OC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IRequest, ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { PromiseCache } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIContainerPackageInfo,\n\tIResolvedUrl,\n\tIUrlResolver,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tIOdspResolvedUrl,\n\tIdentityType,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { type OdspFluidDataStoreLocator, SharingLinkHeader } from \"./contractsPublic.js\";\nimport { createOdspUrl } from \"./createOdspUrl.js\";\nimport { getFileLink } from \"./getFileLink.js\";\nimport { copyRequestHeaders } from \"./requestHeaders.js\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver.js\";\nimport {\n\tgetLocatorFromOdspUrl,\n\tlocatorQueryParamName,\n\tstoreLocatorInOdspUrl,\n} from \"./odspFluidFileLink.js\";\nimport {\n\tappendNavParam,\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\tgetContainerPackageName,\n} from \"./odspUtils.js\";\n\n/**\n * Properties passed to the code responsible for fetching share link for a file.\n * @legacy\n * @beta\n */\nexport interface ShareLinkFetcherProps {\n\t/**\n\t * Callback method that is used to fetch access token necessary to call API that produces share link\n\t */\n\ttokenFetcher: TokenFetcher<OdspResourceTokenFetchOptions>;\n\t/**\n\t * Identity type determining the shape of share link as it differs for Enterprise and Consumer users.\n\t */\n\tidentityType: IdentityType;\n\t/**\n\t * Host-owned attribution metadata for ODSP requests made while resolving share links.\n\t * Driver-owned headers take precedence on case-insensitive collisions.\n\t */\n\trequestHeaders?: Readonly<Record<string, string>>;\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 * @legacy\n * @beta\n */\nexport class OdspDriverUrlResolverForShareLink implements IUrlResolver {\n\tprivate readonly logger: TelemetryLoggerExt;\n\tprivate readonly sharingLinkCache = new PromiseCache<string, string>();\n\tprivate readonly shareLinkFetcherProps: ShareLinkFetcherProps | undefined;\n\n\t/**\n\t * Creates url resolver instance\n\t * @param shareLinkFetcherProps - properties used when fetching share link.\n\t * Can be set as 'undefined' for cases where share link is not needed. Currently, only\n\t * getAbsoluteUrl() method requires share link.\n\t * @param logger - logger object that is used as telemetry sink\n\t * @param appName - application name hint that is encoded with url produced by getAbsoluteUrl() method.\n\t * This hint is used by link handling logic which determines which app to redirect to when user\n\t * navigates directly to the link.\n\t * @param getContext - callback function which is used to get context for given resolved url. If context\n\t * is returned then it will be embedded into url returned by getAbsoluteUrl() method.\n\t * @param containerPackageInfo - container package information which will be used to extract the container package name.\n\t */\n\tpublic constructor(\n\t\tshareLinkFetcherProps?: ShareLinkFetcherProps | undefined,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tprivate readonly appName?: string,\n\t\tprivate readonly getContext?: (\n\t\t\tresolvedUrl: IOdspResolvedUrl,\n\t\t\tdataStorePath: string,\n\t\t) => Promise<string | undefined>,\n\t\tprivate readonly containerPackageInfo?: IContainerPackageInfo,\n\t) {\n\t\tthis.logger = createOdspLogger(logger);\n\t\tif (shareLinkFetcherProps) {\n\t\t\tthis.shareLinkFetcherProps = {\n\t\t\t\t...shareLinkFetcherProps,\n\t\t\t\ttokenFetcher: shareLinkFetcherProps.tokenFetcher,\n\t\t\t\trequestHeaders: copyRequestHeaders(shareLinkFetcherProps.requestHeaders),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Takes an already generated data store url (from requestUrl) and appends a path to the\n\t * existing data store information.\n\t */\n\tpublic appendDataStorePath(requestUrl: URL, pathToAppend: string): string | undefined {\n\t\tconst fluidInfo = getLocatorFromOdspUrl(requestUrl);\n\n\t\tif (!fluidInfo) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst parsingUrl = new URL(\n\t\t\tfluidInfo.dataStorePath,\n\t\t\t`${requestUrl.protocol}//${requestUrl.hostname}`,\n\t\t);\n\t\t// Determine if the caller is passing a query parameter or path since processing will be different.\n\t\tif (pathToAppend.startsWith(\"/?\") || pathToAppend.startsWith(\"?\")) {\n\t\t\tconst queryParams = new URLSearchParams(pathToAppend);\n\t\t\tfor (const [key, value] of queryParams.entries()) {\n\t\t\t\tparsingUrl.searchParams.append(key, value);\n\t\t\t}\n\t\t\tfluidInfo.dataStorePath = `${parsingUrl.pathname}${parsingUrl.search}`;\n\t\t} else {\n\t\t\tfluidInfo.dataStorePath = `${parsingUrl.pathname}${\n\t\t\t\tparsingUrl.pathname.endsWith(\"/\") || pathToAppend.startsWith(\"/\") ? \"\" : \"/\"\n\t\t\t}${pathToAppend}/${parsingUrl.search}`;\n\t\t}\n\t\tstoreLocatorInOdspUrl(requestUrl, fluidInfo);\n\n\t\treturn requestUrl.href;\n\t}\n\n\tprivate getKey(resolvedUrl: IOdspResolvedUrl): string {\n\t\treturn `${resolvedUrl.siteUrl},${resolvedUrl.driveId},${resolvedUrl.itemId}`;\n\t}\n\n\t/**\n\t * Resolves request URL into driver details\n\t */\n\tpublic async resolve(request: IRequest): Promise<IOdspResolvedUrl> {\n\t\tconst requestToBeResolved = { headers: request.headers, url: request.url };\n\t\tconst isSharingLinkToRedeem =\n\t\t\trequestToBeResolved.headers?.[SharingLinkHeader.isSharingLinkToRedeem];\n\t\tconst isRedemptionNonDurable =\n\t\t\trequestToBeResolved.headers?.[SharingLinkHeader.isRedemptionNonDurable];\n\t\ttry {\n\t\t\tconst url = new URL(request.url);\n\n\t\t\tconst odspFluidInfo = getLocatorFromOdspUrl(url);\n\t\t\tif (odspFluidInfo) {\n\t\t\t\trequestToBeResolved.url = createOdspUrl(odspFluidInfo);\n\t\t\t}\n\t\t} catch {\n\t\t\t// If the locator throws some error, then try to resolve the request as it is.\n\t\t}\n\n\t\tconst odspResolvedUrl = await new OdspDriverUrlResolver().resolve(requestToBeResolved);\n\n\t\todspResolvedUrl.context = await this.getContext?.(\n\t\t\todspResolvedUrl,\n\t\t\todspResolvedUrl.dataStorePath ?? \"\",\n\t\t);\n\n\t\todspResolvedUrl.appName = this.appName;\n\n\t\todspResolvedUrl.codeHint = odspResolvedUrl.codeHint?.containerPackageName\n\t\t\t? odspResolvedUrl.codeHint\n\t\t\t: { containerPackageName: getContainerPackageName(this.containerPackageInfo) };\n\n\t\tif (isSharingLinkToRedeem) {\n\t\t\t// We need to remove the nav param if set by host when setting the sharelink as otherwise the shareLinkId\n\t\t\t// when redeeming the share link during the redeem fallback for trees latest call becomes greater than\n\t\t\t// the eligible length.\n\t\t\todspResolvedUrl.shareLinkInfo = Object.assign(odspResolvedUrl.shareLinkInfo ?? {}, {\n\t\t\t\tsharingLinkToRedeem: this.removeNavParam(request.url),\n\t\t\t\tisRedemptionNonDurable: isRedemptionNonDurable ?? false,\n\t\t\t});\n\t\t}\n\t\tif (odspResolvedUrl.itemId) {\n\t\t\t// Kick start the sharing link request if we don't have it already as a performance optimization.\n\t\t\t// For detached create new, we don't have an item id yet and therefore cannot generate a share link\n\t\t\tthis.getShareLinkPromise(odspResolvedUrl).catch(() => {});\n\t\t}\n\t\treturn odspResolvedUrl;\n\t}\n\n\tprivate removeNavParam(link: string): string {\n\t\tconst url = new URL(link);\n\t\tconst params = new URLSearchParams(url.search);\n\t\tparams.delete(locatorQueryParamName);\n\t\turl.search = params.toString();\n\t\treturn url.href;\n\t}\n\n\tprivate async getShareLinkPromise(resolvedUrl: IOdspResolvedUrl): Promise<string> {\n\t\tif (this.shareLinkFetcherProps === undefined) {\n\t\t\tthrow new Error(\"Failed to get share link because share link fetcher props are missing\");\n\t\t}\n\n\t\tif (!(resolvedUrl.siteUrl && resolvedUrl.driveId && resolvedUrl.itemId)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Failed to get share link because necessary information is missing \" +\n\t\t\t\t\t\"(e.g. siteUrl, driveId or itemId)\",\n\t\t\t);\n\t\t}\n\n\t\tconst key = this.getKey(resolvedUrl);\n\t\tconst cachedLinkPromise = this.sharingLinkCache.get(key);\n\t\tif (cachedLinkPromise) {\n\t\t\treturn cachedLinkPromise;\n\t\t}\n\t\tconst newLinkPromise = getFileLink(\n\t\t\tthis.shareLinkFetcherProps.tokenFetcher,\n\t\t\tresolvedUrl,\n\t\t\tthis.logger,\n\t\t\tthis.shareLinkFetcherProps.requestHeaders,\n\t\t).catch((error) => {\n\t\t\t// This should imply that error is a non-retriable error.\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"FluidFileUrlError\" }, error);\n\t\t\tthis.sharingLinkCache.remove(key);\n\t\t\tthrow error;\n\t\t});\n\t\tthis.sharingLinkCache.add(key, async () => newLinkPromise);\n\t\treturn newLinkPromise;\n\t}\n\n\t/**\n\t * Requests a driver + data store storage URL. Note that this method requires share link to be fetched\n\t * and it will throw in case share link fetcher props were not specified when instance was created.\n\t * @param resolvedUrl - The driver resolved URL\n\t * @param dataStorePath - The relative data store path URL.\n\t * For requesting a driver URL, this value should always be '/'. If an empty string is passed, then dataStorePath\n\t * will be extracted from the resolved url if present.\n\t * @param packageInfoSource - optional, represents container package information to be included in url.\n\t */\n\tpublic async getAbsoluteUrl(\n\t\tresolvedUrl: IResolvedUrl,\n\t\tdataStorePath: string,\n\t\tpackageInfoSource?: IContainerPackageInfo,\n\t): Promise<string> {\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\t\tconst shareLink = await this.getShareLinkPromise(odspResolvedUrl);\n\n\t\treturn this.appendLocatorParams(shareLink, resolvedUrl, dataStorePath, packageInfoSource);\n\t}\n\n\t/**\n\t * Appends the store locator properties to the provided base URL. This function is useful for scenarios where an application\n\t * has a base URL (for example a sharing link) of the Fluid file, but does not have the locator information that would be used by Fluid\n\t * to load the file later.\n\t * @param baseUrl - The input URL on which the locator params will be appended.\n\t * @param resolvedUrl - odsp-driver's resolvedURL object.\n\t * @param dataStorePath - The relative data store path URL.\n\t * For requesting a driver URL, this value should always be '/'. If an empty string is passed, then dataStorePath\n\t * will be extracted from the resolved url if present.\n\t * @returns The provided base URL appended with odsp-specific locator information\n\t */\n\tpublic async appendLocatorParams(\n\t\tbaseUrl: string,\n\t\tresolvedUrl: IResolvedUrl,\n\t\tdataStorePath: string,\n\t\tpackageInfoSource?: IContainerPackageInfo,\n\t): Promise<string> {\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\t\t// If the user has passed an empty dataStorePath, then extract it from the resolved url.\n\t\tconst actualDataStorePath = dataStorePath || (odspResolvedUrl.dataStorePath ?? \"\");\n\n\t\todspResolvedUrl.context = await this.getContext?.(odspResolvedUrl, actualDataStorePath);\n\n\t\t/**\n\t\t * containerPackageName can be provided by various ways, in the order of priority:\n\t\t * 1. packageInfoSource - passed by the call of appendLocatorParams\n\t\t * 2. odspResolvedUrl.codeHint?.containerPackageName - passed by the odsp-driver's resolvedURL object\n\t\t * 3. this.containerPackageInfo - passed by the constructor of OdspDrvierUrlResolverForShareLink\n\t\t * */\n\t\tconst containerPackageName: string | undefined =\n\t\t\tgetContainerPackageName(packageInfoSource) ??\n\t\t\todspResolvedUrl.codeHint?.containerPackageName ??\n\t\t\tgetContainerPackageName(this.containerPackageInfo);\n\n\t\todspResolvedUrl.appName = this.appName;\n\n\t\treturn appendNavParam(baseUrl, odspResolvedUrl, actualDataStorePath, containerPackageName);\n\t}\n\n\t/**\n\t * Crafts a supported document/driver URL\n\t */\n\tpublic static createDocumentUrl(\n\t\tbaseUrl: string,\n\t\tdriverInfo: OdspFluidDataStoreLocator,\n\t): string {\n\t\tconst url = new URL(baseUrl);\n\n\t\tstoreLocatorInOdspUrl(url, driverInfo);\n\n\t\treturn url.href;\n\t}\n}\n"]}
|
|
@@ -53,6 +53,7 @@ export interface OdspFileVersionFetcherProps {
|
|
|
53
53
|
readonly getAuthHeader: InstrumentedStorageTokenFetcher;
|
|
54
54
|
readonly epochTracker: EpochTracker;
|
|
55
55
|
readonly logger: TelemetryLoggerExt;
|
|
56
|
+
readonly requestHeaders?: Readonly<Record<string, string>>;
|
|
56
57
|
}
|
|
57
58
|
/**
|
|
58
59
|
* Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspFileVersionFetcher.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EACX,aAAa,EACb,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"odspFileVersionFetcher.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EACX,aAAa,EACb,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAQvD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACvC;;OAEG;IACH,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAClD;;;OAGG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD;;;OAGG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3E;AAmBD;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,+BAA+B,CAAC;IACxD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3D;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,2BAA2B,GAChC,uBAAuB,CAkIzB"}
|
|
@@ -21,11 +21,12 @@ const odspSnapshotParser_js_1 = require("../odspSnapshotParser.js");
|
|
|
21
21
|
const odspUrlHelper_js_1 = require("../odspUrlHelper.js");
|
|
22
22
|
const odspUtils_js_1 = require("../odspUtils.js");
|
|
23
23
|
const packageVersion_js_1 = require("../packageVersion.js");
|
|
24
|
+
const requestHeaders_js_1 = require("../requestHeaders.js");
|
|
24
25
|
/**
|
|
25
26
|
* Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
|
|
26
27
|
*/
|
|
27
28
|
function createOdspFileVersionFetcher(props) {
|
|
28
|
-
const { urlParts, getAuthHeader, epochTracker, logger } = props;
|
|
29
|
+
const { urlParts, getAuthHeader, epochTracker, logger, requestHeaders } = props;
|
|
29
30
|
const { siteUrl, driveId, itemId } = urlParts;
|
|
30
31
|
const listFileVersions = async () => (0, odspUtils_js_1.getWithRetryForTokenRefresh)(async (options) => {
|
|
31
32
|
const method = "GET";
|
|
@@ -100,7 +101,10 @@ function createOdspFileVersionFetcher(props) {
|
|
|
100
101
|
const method = "GET";
|
|
101
102
|
const token = await getAuthHeader({ ...options, request: { url, method } }, scenarioName);
|
|
102
103
|
const headers = (0, getUrlAndHeadersWithAuth_js_1.getHeadersWithAuth)(token);
|
|
103
|
-
const response = await (0, odspUtils_js_1.fetchArray)(url, {
|
|
104
|
+
const response = await (0, odspUtils_js_1.fetchArray)(url, {
|
|
105
|
+
method,
|
|
106
|
+
headers: (0, requestHeaders_js_1.mergeRequestHeaders)(requestHeaders, headers),
|
|
107
|
+
});
|
|
104
108
|
return response.headers.get("x-fluid-epoch") ?? undefined;
|
|
105
109
|
});
|
|
106
110
|
const getLiveDocumentEpoch = async () =>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspFileVersionFetcher.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.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\n/*\n * An {@link IOdspFileVersionFetcher} backed by the ODSP REST APIs:\n * - GET /_api/v2.1/.../versions -- enumerate the file's versions.\n * - GET /_api/v2.1/.../versions/{label}/opStream/snapshots/trees/latest?blobs=2 -- fetch a version's\n * snapshot and read its sequence number, parsed with the driver's snapshot parser.\n * - GET /_api/v2.1/.../[versions/{label}/]opStream/snapshots/trees/latest?blobs=0 -- read a version's\n * or the live document's ODSP epoch (`x-fluid-epoch`) to compare their lineage.\n */\n\nimport { NonRetryableError } from \"@fluidframework/driver-utils/internal\";\nimport { OdspErrorTypes } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type {\n\tIOdspUrlParts,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { currentReadVersion, parseCompactSnapshotResponse } from \"../compactSnapshotParser.js\";\nimport type { IOdspSnapshot } from \"../contracts.js\";\nimport type { EpochTracker } from \"../epochTracker.js\";\nimport { getHeadersWithAuth } from \"../getUrlAndHeadersWithAuth.js\";\nimport { convertOdspSnapshotToSnapshotTreeAndBlobs } from \"../odspSnapshotParser.js\";\nimport { getApiRoot } from \"../odspUrlHelper.js\";\nimport { fetchArray, getWithRetryForTokenRefresh } from \"../odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"../packageVersion.js\";\n\n/**\n * A single ODSP file version, as listed by the file's version history.\n */\nexport interface OdspFileVersionRef {\n\t/**\n\t * The version's label (e.g. `\"42.0\"`), used to address the version when fetching it.\n\t */\n\treadonly versionId: string;\n\t/**\n\t * Last-modified timestamp of this version, ISO-8601.\n\t */\n\treadonly lastModifiedDateTime: string;\n}\n\n/**\n * Provides a file's versions and resolves each version's Fluid sequence number. Injected into\n * the version manager so the selection logic does not depend on how versions are fetched.\n */\nexport interface IOdspFileVersionFetcher {\n\t/**\n\t * Enumerate the file's versions, newest-first.\n\t */\n\tlistFileVersions(): Promise<OdspFileVersionRef[]>;\n\t/**\n\t * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a\n\t * wrong value.\n\t */\n\tresolveSequenceNumber(versionId: string): Promise<number>;\n\t/**\n\t * Read the live document's current ODSP epoch (`x-fluid-epoch`), or `undefined`. Epoch identifies\n\t * the file's binary lineage and changes on a version restore or download-then-reupload; compared\n\t * with {@link IOdspFileVersionFetcher.getRecoverableVersionEpoch} to confirm a base is on the live\n\t * document's lineage.\n\t */\n\tgetLiveDocumentEpoch(): Promise<string | undefined>;\n\t/**\n\t * Read the ODSP epoch of a specific file version, or `undefined`. See\n\t * {@link IOdspFileVersionFetcher.getLiveDocumentEpoch}.\n\t */\n\tgetRecoverableVersionEpoch(versionId: string): Promise<string | undefined>;\n}\n\n/**\n * Raw shape of a OneDrive/SharePoint driveItem version (an entry in the `/versions` response).\n * @see https://learn.microsoft.com/en-us/onedrive/developer/rest-api/resources/driveitemversion\n */\ninterface IDriveItemVersion {\n\t/** The version's label, e.g. \"42.0\". */\n\treadonly id: string;\n\treadonly lastModifiedDateTime: string;\n}\n\n/** A single page of the driveItem `/versions` response. */\ninterface IDriveItemVersionsPage {\n\treadonly value?: IDriveItemVersion[];\n\t/** Absolute URL of the next page, present only while more versions remain. */\n\treadonly \"@odata.nextLink\"?: string;\n}\n\n/**\n * Inputs needed to make authenticated requests against a specific ODSP file.\n */\nexport interface OdspFileVersionFetcherProps {\n\treadonly urlParts: IOdspUrlParts;\n\treadonly getAuthHeader: InstrumentedStorageTokenFetcher;\n\treadonly epochTracker: EpochTracker;\n\treadonly logger: TelemetryLoggerExt;\n}\n\n/**\n * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.\n */\nexport function createOdspFileVersionFetcher(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspFileVersionFetcher {\n\tconst { urlParts, getAuthHeader, epochTracker, logger } = props;\n\tconst { siteUrl, driveId, itemId } = urlParts;\n\n\tconst listFileVersions = async (): Promise<OdspFileVersionRef[]> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst versions: OdspFileVersionRef[] = [];\n\t\t\t// The file's version history (distinct from the driver's snapshot list), from the same API\n\t\t\t// root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.\n\t\t\t// A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base\n\t\t\t// version beyond the first page would be missed and wrongly reported as \"no base version\".\n\t\t\tlet url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;\n\t\t\tdo {\n\t\t\t\tconst token = await getAuthHeader(\n\t\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\t\"FileVersions\",\n\t\t\t\t);\n\t\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t\tconst response = await epochTracker.fetchAndParseAsJSON<{\n\t\t\t\t\tvalue?: IDriveItemVersion[];\n\t\t\t\t}>(url, { method, headers }, \"versions\");\n\t\t\t\tconst page = response.content as IDriveItemVersionsPage;\n\t\t\t\t// The API returns versions newest-first.\n\t\t\t\tfor (const version of page.value ?? []) {\n\t\t\t\t\tversions.push({\n\t\t\t\t\t\tversionId: version.id,\n\t\t\t\t\t\tlastModifiedDateTime: version.lastModifiedDateTime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\turl = page[\"@odata.nextLink\"] ?? \"\";\n\t\t\t} while (url);\n\t\t\treturn versions;\n\t\t});\n\n\tconst resolveSequenceNumber = async (versionId: string): Promise<number> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t// The sequence number lives in the version snapshot's `.protocol/attributes` blob, so fetch the\n\t\t\t// version-scoped snapshot with `blobs=2` to inline it. No op stream needed.\n\t\t\tconst url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(\n\t\t\t\tversionId,\n\t\t\t)}/opStream/snapshots/trees/latest?blobs=2`;\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"FileVersionSnapshot\",\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t// The snapshot comes back as JSON or \"ms-fluid\" (ODSP's compact binary form). Accept both and\n\t\t\t// pin the binary version (as the driver's snapshot fetch does) so the parser can read it.\n\t\t\theaders.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;\n\t\t\tconst response = await epochTracker.fetch(url, { method, headers }, \"treesLatest\");\n\t\t\tconst contentType = response.headers.get(\"content-type\") ?? \"\";\n\t\t\tlet sequenceNumber: number | undefined;\n\t\t\tif (contentType.includes(\"application/json\")) {\n\t\t\t\t// JSON framing: read it with the driver's JSON snapshot parser.\n\t\t\t\tconst snapshotJson = (await response.content.json()) as IOdspSnapshot;\n\t\t\t\tsequenceNumber =\n\t\t\t\t\tconvertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;\n\t\t\t} else if (contentType.includes(\"application/ms-fluid\")) {\n\t\t\t\t// ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.\n\t\t\t\tconst bytes = new Uint8Array(await response.content.arrayBuffer());\n\t\t\t\tsequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;\n\t\t\t} else {\n\t\t\t\t// Neither framing (e.g. an HTML error page). Throw the driver's typed bad-response error\n\t\t\t\t// (like fetchSnapshot.ts): canRetry=false stops the loader re-driving, while the\n\t\t\t\t// incorrectServerResponse errorType still earns one wire-retry from getWithRetryForTokenRefresh.\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t`ODSP file version ${versionId} snapshot returned an unexpected content-type`,\n\t\t\t\t\tOdspErrorTypes.incorrectServerResponse,\n\t\t\t\t\t{ driverVersion, contentType, accept: headers.accept },\n\t\t\t\t);\n\t\t\t}\n\t\t\t// The sequence number must be a non-negative integer; a missing or malformed one throws the same\n\t\t\t// typed error as above rather than feeding a wrong value into base selection.\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\ttypeof sequenceNumber === \"number\" &&\n\t\t\t\t\tNumber.isInteger(sequenceNumber) &&\n\t\t\t\t\tsequenceNumber >= 0\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t`ODSP file version ${versionId} snapshot has a missing or invalid sequenceNumber (${String(sequenceNumber)})`,\n\t\t\t\t\tOdspErrorTypes.incorrectServerResponse,\n\t\t\t\t\t{ driverVersion, contentType, accept: headers.accept },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn sequenceNumber;\n\t\t});\n\n\tconst itemRoot = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}`;\n\n\t// Reads the `x-fluid-epoch` header from `url`. Deliberately uses the raw fetch helper instead of\n\t// `epochTracker.fetch`: the whole point is to COMPARE the base version's epoch against the live\n\t// document's epoch, but the shared EpochTracker pins to the first epoch it sees and throws on the\n\t// second (divergent) read - so it could never yield two epochs to compare. `fetchArray` also lets\n\t// the body (JSON or ms-fluid binary) be consumed and discarded; only the header is needed.\n\tconst readEpoch = async (url: string, scenarioName: string): Promise<string | undefined> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\tconst response = await fetchArray(url, { method, headers });\n\t\t\treturn response.headers.get(\"x-fluid-epoch\") ?? undefined;\n\t\t});\n\n\tconst getLiveDocumentEpoch = async (): Promise<string | undefined> =>\n\t\t// The (unversioned) live snapshot endpoint is a current-file read, so its epoch is the live\n\t\t// document's epoch. `blobs=0` keeps the response to the tree metadata.\n\t\treadEpoch(`${itemRoot}/opStream/snapshots/trees/latest?blobs=0`, \"LiveEpoch\");\n\n\tconst getRecoverableVersionEpoch = async (versionId: string): Promise<string | undefined> =>\n\t\treadEpoch(\n\t\t\t`${itemRoot}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=0`,\n\t\t\t\"FileVersionEpoch\",\n\t\t);\n\n\treturn {\n\t\tlistFileVersions,\n\t\tresolveSequenceNumber,\n\t\tgetLiveDocumentEpoch,\n\t\tgetRecoverableVersionEpoch,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"odspFileVersionFetcher.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.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\n/*\n * An {@link IOdspFileVersionFetcher} backed by the ODSP REST APIs:\n * - GET /_api/v2.1/.../versions -- enumerate the file's versions.\n * - GET /_api/v2.1/.../versions/{label}/opStream/snapshots/trees/latest?blobs=2 -- fetch a version's\n * snapshot and read its sequence number, parsed with the driver's snapshot parser.\n * - GET /_api/v2.1/.../[versions/{label}/]opStream/snapshots/trees/latest?blobs=0 -- read a version's\n * or the live document's ODSP epoch (`x-fluid-epoch`) to compare their lineage.\n */\n\nimport { NonRetryableError } from \"@fluidframework/driver-utils/internal\";\nimport { OdspErrorTypes } from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type {\n\tIOdspUrlParts,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { currentReadVersion, parseCompactSnapshotResponse } from \"../compactSnapshotParser.js\";\nimport type { IOdspSnapshot } from \"../contracts.js\";\nimport type { EpochTracker } from \"../epochTracker.js\";\nimport { getHeadersWithAuth } from \"../getUrlAndHeadersWithAuth.js\";\nimport { convertOdspSnapshotToSnapshotTreeAndBlobs } from \"../odspSnapshotParser.js\";\nimport { getApiRoot } from \"../odspUrlHelper.js\";\nimport { fetchArray, getWithRetryForTokenRefresh } from \"../odspUtils.js\";\nimport { pkgVersion as driverVersion } from \"../packageVersion.js\";\nimport { mergeRequestHeaders } from \"../requestHeaders.js\";\n\n/**\n * A single ODSP file version, as listed by the file's version history.\n */\nexport interface OdspFileVersionRef {\n\t/**\n\t * The version's label (e.g. `\"42.0\"`), used to address the version when fetching it.\n\t */\n\treadonly versionId: string;\n\t/**\n\t * Last-modified timestamp of this version, ISO-8601.\n\t */\n\treadonly lastModifiedDateTime: string;\n}\n\n/**\n * Provides a file's versions and resolves each version's Fluid sequence number. Injected into\n * the version manager so the selection logic does not depend on how versions are fetched.\n */\nexport interface IOdspFileVersionFetcher {\n\t/**\n\t * Enumerate the file's versions, newest-first.\n\t */\n\tlistFileVersions(): Promise<OdspFileVersionRef[]>;\n\t/**\n\t * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a\n\t * wrong value.\n\t */\n\tresolveSequenceNumber(versionId: string): Promise<number>;\n\t/**\n\t * Read the live document's current ODSP epoch (`x-fluid-epoch`), or `undefined`. Epoch identifies\n\t * the file's binary lineage and changes on a version restore or download-then-reupload; compared\n\t * with {@link IOdspFileVersionFetcher.getRecoverableVersionEpoch} to confirm a base is on the live\n\t * document's lineage.\n\t */\n\tgetLiveDocumentEpoch(): Promise<string | undefined>;\n\t/**\n\t * Read the ODSP epoch of a specific file version, or `undefined`. See\n\t * {@link IOdspFileVersionFetcher.getLiveDocumentEpoch}.\n\t */\n\tgetRecoverableVersionEpoch(versionId: string): Promise<string | undefined>;\n}\n\n/**\n * Raw shape of a OneDrive/SharePoint driveItem version (an entry in the `/versions` response).\n * @see https://learn.microsoft.com/en-us/onedrive/developer/rest-api/resources/driveitemversion\n */\ninterface IDriveItemVersion {\n\t/** The version's label, e.g. \"42.0\". */\n\treadonly id: string;\n\treadonly lastModifiedDateTime: string;\n}\n\n/** A single page of the driveItem `/versions` response. */\ninterface IDriveItemVersionsPage {\n\treadonly value?: IDriveItemVersion[];\n\t/** Absolute URL of the next page, present only while more versions remain. */\n\treadonly \"@odata.nextLink\"?: string;\n}\n\n/**\n * Inputs needed to make authenticated requests against a specific ODSP file.\n */\nexport interface OdspFileVersionFetcherProps {\n\treadonly urlParts: IOdspUrlParts;\n\treadonly getAuthHeader: InstrumentedStorageTokenFetcher;\n\treadonly epochTracker: EpochTracker;\n\treadonly logger: TelemetryLoggerExt;\n\treadonly requestHeaders?: Readonly<Record<string, string>>;\n}\n\n/**\n * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.\n */\nexport function createOdspFileVersionFetcher(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspFileVersionFetcher {\n\tconst { urlParts, getAuthHeader, epochTracker, logger, requestHeaders } = props;\n\tconst { siteUrl, driveId, itemId } = urlParts;\n\n\tconst listFileVersions = async (): Promise<OdspFileVersionRef[]> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst versions: OdspFileVersionRef[] = [];\n\t\t\t// The file's version history (distinct from the driver's snapshot list), from the same API\n\t\t\t// root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.\n\t\t\t// A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base\n\t\t\t// version beyond the first page would be missed and wrongly reported as \"no base version\".\n\t\t\tlet url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;\n\t\t\tdo {\n\t\t\t\tconst token = await getAuthHeader(\n\t\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\t\"FileVersions\",\n\t\t\t\t);\n\t\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t\tconst response = await epochTracker.fetchAndParseAsJSON<{\n\t\t\t\t\tvalue?: IDriveItemVersion[];\n\t\t\t\t}>(url, { method, headers }, \"versions\");\n\t\t\t\tconst page = response.content as IDriveItemVersionsPage;\n\t\t\t\t// The API returns versions newest-first.\n\t\t\t\tfor (const version of page.value ?? []) {\n\t\t\t\t\tversions.push({\n\t\t\t\t\t\tversionId: version.id,\n\t\t\t\t\t\tlastModifiedDateTime: version.lastModifiedDateTime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\turl = page[\"@odata.nextLink\"] ?? \"\";\n\t\t\t} while (url);\n\t\t\treturn versions;\n\t\t});\n\n\tconst resolveSequenceNumber = async (versionId: string): Promise<number> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t// The sequence number lives in the version snapshot's `.protocol/attributes` blob, so fetch the\n\t\t\t// version-scoped snapshot with `blobs=2` to inline it. No op stream needed.\n\t\t\tconst url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(\n\t\t\t\tversionId,\n\t\t\t)}/opStream/snapshots/trees/latest?blobs=2`;\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"FileVersionSnapshot\",\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t// The snapshot comes back as JSON or \"ms-fluid\" (ODSP's compact binary form). Accept both and\n\t\t\t// pin the binary version (as the driver's snapshot fetch does) so the parser can read it.\n\t\t\theaders.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;\n\t\t\tconst response = await epochTracker.fetch(url, { method, headers }, \"treesLatest\");\n\t\t\tconst contentType = response.headers.get(\"content-type\") ?? \"\";\n\t\t\tlet sequenceNumber: number | undefined;\n\t\t\tif (contentType.includes(\"application/json\")) {\n\t\t\t\t// JSON framing: read it with the driver's JSON snapshot parser.\n\t\t\t\tconst snapshotJson = (await response.content.json()) as IOdspSnapshot;\n\t\t\t\tsequenceNumber =\n\t\t\t\t\tconvertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;\n\t\t\t} else if (contentType.includes(\"application/ms-fluid\")) {\n\t\t\t\t// ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.\n\t\t\t\tconst bytes = new Uint8Array(await response.content.arrayBuffer());\n\t\t\t\tsequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;\n\t\t\t} else {\n\t\t\t\t// Neither framing (e.g. an HTML error page). Throw the driver's typed bad-response error\n\t\t\t\t// (like fetchSnapshot.ts): canRetry=false stops the loader re-driving, while the\n\t\t\t\t// incorrectServerResponse errorType still earns one wire-retry from getWithRetryForTokenRefresh.\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t`ODSP file version ${versionId} snapshot returned an unexpected content-type`,\n\t\t\t\t\tOdspErrorTypes.incorrectServerResponse,\n\t\t\t\t\t{ driverVersion, contentType, accept: headers.accept },\n\t\t\t\t);\n\t\t\t}\n\t\t\t// The sequence number must be a non-negative integer; a missing or malformed one throws the same\n\t\t\t// typed error as above rather than feeding a wrong value into base selection.\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\ttypeof sequenceNumber === \"number\" &&\n\t\t\t\t\tNumber.isInteger(sequenceNumber) &&\n\t\t\t\t\tsequenceNumber >= 0\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new NonRetryableError(\n\t\t\t\t\t`ODSP file version ${versionId} snapshot has a missing or invalid sequenceNumber (${String(sequenceNumber)})`,\n\t\t\t\t\tOdspErrorTypes.incorrectServerResponse,\n\t\t\t\t\t{ driverVersion, contentType, accept: headers.accept },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn sequenceNumber;\n\t\t});\n\n\tconst itemRoot = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}`;\n\n\t// Reads the `x-fluid-epoch` header from `url`. Deliberately uses the raw fetch helper instead of\n\t// `epochTracker.fetch`: the whole point is to COMPARE the base version's epoch against the live\n\t// document's epoch, but the shared EpochTracker pins to the first epoch it sees and throws on the\n\t// second (divergent) read - so it could never yield two epochs to compare. `fetchArray` also lets\n\t// the body (JSON or ms-fluid binary) be consumed and discarded; only the header is needed.\n\tconst readEpoch = async (url: string, scenarioName: string): Promise<string | undefined> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\tscenarioName,\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\tconst response = await fetchArray(url, {\n\t\t\t\tmethod,\n\t\t\t\theaders: mergeRequestHeaders(requestHeaders, headers),\n\t\t\t});\n\t\t\treturn response.headers.get(\"x-fluid-epoch\") ?? undefined;\n\t\t});\n\n\tconst getLiveDocumentEpoch = async (): Promise<string | undefined> =>\n\t\t// The (unversioned) live snapshot endpoint is a current-file read, so its epoch is the live\n\t\t// document's epoch. `blobs=0` keeps the response to the tree metadata.\n\t\treadEpoch(`${itemRoot}/opStream/snapshots/trees/latest?blobs=0`, \"LiveEpoch\");\n\n\tconst getRecoverableVersionEpoch = async (versionId: string): Promise<string | undefined> =>\n\t\treadEpoch(\n\t\t\t`${itemRoot}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=0`,\n\t\t\t\"FileVersionEpoch\",\n\t\t);\n\n\treturn {\n\t\tlistFileVersions,\n\t\tresolveSequenceNumber,\n\t\tgetLiveDocumentEpoch,\n\t\tgetRecoverableVersionEpoch,\n\t};\n}\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/odsp-driver";
|
|
11
|
-
exports.pkgVersion = "3.0
|
|
11
|
+
exports.pkgVersion = "3.1.0";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"3.0
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/odsp-driver\";\nexport const pkgVersion = \"3.1.0\";\n"]}
|
|
@@ -29,6 +29,6 @@ export declare function createPointInTimeDocumentService(props: IOdspPointInTime
|
|
|
29
29
|
* Creates the point-in-time service with replaceable dependencies for testing.
|
|
30
30
|
* @internal
|
|
31
31
|
*/
|
|
32
|
-
export declare function createPointInTimeDocumentServiceCore({ resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer, persistedCache, getStorageToken, createDocumentService, }: IOdspPointInTimeDocumentServiceImplementationProps, dependencies?: IPointInTimeDocumentServiceDependencies): Promise<OdspPointInTimeDocumentService>;
|
|
32
|
+
export declare function createPointInTimeDocumentServiceCore({ resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer, persistedCache, getStorageToken, requestHeaders, createDocumentService, }: IOdspPointInTimeDocumentServiceImplementationProps, dependencies?: IPointInTimeDocumentServiceDependencies): Promise<OdspPointInTimeDocumentService>;
|
|
33
33
|
export {};
|
|
34
34
|
//# sourceMappingURL=createPointInTimeDocumentService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPointInTimeDocumentService.d.ts","sourceRoot":"","sources":["../../src/pointInTimeDriver/createPointInTimeDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,gBAAgB,EAChB,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EACX,gBAAgB,EAEhB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAA6B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlF,OAAO,KAAK,EAAE,kDAAkD,EAAE,MAAM,sCAAsC,CAAC;AAM/G,OAAO,EAEN,KAAK,mBAAmB,EAExB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,UAAU,uCAAuC;IAChD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAC/B,eAAe,EAAE,gBAAgB,EACjC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,YAAY,KACtB,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACxD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAC7B,WAAW,EAAE,YAAY,EACzB,WAAW,EAAE,MAAM,KACf,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1C;
|
|
1
|
+
{"version":3,"file":"createPointInTimeDocumentService.d.ts","sourceRoot":"","sources":["../../src/pointInTimeDriver/createPointInTimeDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,gBAAgB,EAChB,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EACX,gBAAgB,EAEhB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAA6B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlF,OAAO,KAAK,EAAE,kDAAkD,EAAE,MAAM,sCAAsC,CAAC;AAM/G,OAAO,EAEN,KAAK,mBAAmB,EAExB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,UAAU,uCAAuC;IAChD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAC/B,eAAe,EAAE,gBAAgB,EACjC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,YAAY,KACtB,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACxD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAC7B,WAAW,EAAE,YAAY,EACzB,WAAW,EAAE,MAAM,KACf,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1C;AAiDD;;;;;;;;;;GAUG;AACH,wBAAsB,gCAAgC,CACrD,KAAK,EAAE,kDAAkD,GACvD,OAAO,CAAC,gBAAgB,CAAC,CAE3B;AAED;;;GAGG;AACH,wBAAsB,oCAAoC,CACzD,EACC,WAAW,EACX,oBAAoB,EACpB,MAAM,EACN,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,qBAAqB,GACrB,EAAE,kDAAkD,EACrD,YAAY,GAAE,uCAA4C,GACxD,OAAO,CAAC,8BAA8B,CAAC,CAoEzC"}
|
|
@@ -14,7 +14,7 @@ const odspDriverUrlResolver_js_1 = require("../odspDriverUrlResolver.js");
|
|
|
14
14
|
const odspUtils_js_1 = require("../odspUtils.js");
|
|
15
15
|
const odspVersionManager_js_1 = require("../odspVersionManager/odspVersionManager.js");
|
|
16
16
|
const odspPointInTimeDocumentService_js_1 = require("./odspPointInTimeDocumentService.js");
|
|
17
|
-
async function createVersionManager(odspResolvedUrl, logger, epochTracker, getStorageToken) {
|
|
17
|
+
async function createVersionManager(odspResolvedUrl, logger, epochTracker, getStorageToken, requestHeaders) {
|
|
18
18
|
const urlParts = {
|
|
19
19
|
siteUrl: odspResolvedUrl.siteUrl,
|
|
20
20
|
driveId: odspResolvedUrl.driveId,
|
|
@@ -26,6 +26,7 @@ async function createVersionManager(odspResolvedUrl, logger, epochTracker, getSt
|
|
|
26
26
|
getAuthHeader,
|
|
27
27
|
epochTracker,
|
|
28
28
|
logger,
|
|
29
|
+
requestHeaders,
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
async function resolveFileVersion(resolvedUrl, fileVersion) {
|
|
@@ -63,7 +64,7 @@ async function createPointInTimeDocumentService(props) {
|
|
|
63
64
|
* Creates the point-in-time service with replaceable dependencies for testing.
|
|
64
65
|
* @internal
|
|
65
66
|
*/
|
|
66
|
-
async function createPointInTimeDocumentServiceCore({ resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer, persistedCache, getStorageToken, createDocumentService, }, dependencies = {}) {
|
|
67
|
+
async function createPointInTimeDocumentServiceCore({ resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer, persistedCache, getStorageToken, requestHeaders, createDocumentService, }, dependencies = {}) {
|
|
67
68
|
const odspLogger = (0, odspUtils_js_1.createOdspLogger)(logger);
|
|
68
69
|
const extLogger = (0, internal_2.createChildLogger)({ logger: odspLogger });
|
|
69
70
|
const odspResolvedUrl = (0, odspUtils_js_1.getOdspResolvedUrl)(resolvedUrl);
|
|
@@ -71,9 +72,9 @@ async function createPointInTimeDocumentServiceCore({ resolvedUrl, targetSequenc
|
|
|
71
72
|
resolvedUrl: odspResolvedUrl,
|
|
72
73
|
docId: odspResolvedUrl.hashedDocumentId,
|
|
73
74
|
fileVersion: odspResolvedUrl.fileVersion,
|
|
74
|
-
}, extLogger, clientIsSummarizer);
|
|
75
|
+
}, extLogger, clientIsSummarizer, requestHeaders);
|
|
75
76
|
const versionManager = await (dependencies.createVersionManager ??
|
|
76
|
-
(async (url, versionLogger, epochTracker) => createVersionManager(url, versionLogger, epochTracker, getStorageToken)))(odspResolvedUrl, extLogger, cacheAndTracker.epochTracker);
|
|
77
|
+
(async (url, versionLogger, epochTracker) => createVersionManager(url, versionLogger, epochTracker, getStorageToken, requestHeaders)))(odspResolvedUrl, extLogger, cacheAndTracker.epochTracker);
|
|
77
78
|
const baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);
|
|
78
79
|
if (baseResult.kind === "noBaseVersion") {
|
|
79
80
|
const oldestResolvedSequenceDetail = baseResult.oldestResolvedSeq === undefined
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPointInTimeDocumentService.js","sourceRoot":"","sources":["../../src/pointInTimeDriver/createPointInTimeDocumentService.ts"],"names":[],"mappings":";AAAA;;;GAGG;;
|
|
1
|
+
{"version":3,"file":"createPointInTimeDocumentService.js","sourceRoot":"","sources":["../../src/pointInTimeDriver/createPointInTimeDocumentService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIDocumentService,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { UsageError } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tIOdspResolvedUrl,\n\tIOdspUrlParts,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tcreateChildLogger,\n\ttype TelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { createOdspCacheAndTracker, type EpochTracker } from \"../epochTracker.js\";\nimport { NonPersistentCache } from \"../odspCache.js\";\nimport { OdspDriverUrlResolver } from \"../odspDriverUrlResolver.js\";\nimport type { IOdspPointInTimeDocumentServiceImplementationProps } from \"../odspDocumentServiceFactoryCore.js\";\nimport {\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\ttoInstrumentedOdspStorageTokenFetcher,\n} from \"../odspUtils.js\";\nimport {\n\tcreateOdspVersionManager,\n\ttype IOdspVersionManager,\n\t// eslint-disable-next-line import-x/no-internal-modules -- the feature implementation owns version selection\n} from \"../odspVersionManager/odspVersionManager.js\";\n\nimport { OdspPointInTimeDocumentService } from \"./odspPointInTimeDocumentService.js\";\n\ninterface IPointInTimeDocumentServiceDependencies {\n\treadonly createVersionManager?: (\n\t\todspResolvedUrl: IOdspResolvedUrl,\n\t\tlogger: TelemetryLoggerExt,\n\t\tepochTracker: EpochTracker,\n\t) => IOdspVersionManager | Promise<IOdspVersionManager>;\n\treadonly resolveFileVersion?: (\n\t\tresolvedUrl: IResolvedUrl,\n\t\tfileVersion: string,\n\t) => IResolvedUrl | Promise<IResolvedUrl>;\n}\n\nasync function createVersionManager(\n\todspResolvedUrl: IOdspResolvedUrl,\n\tlogger: TelemetryLoggerExt,\n\tepochTracker: EpochTracker,\n\tgetStorageToken: IOdspPointInTimeDocumentServiceImplementationProps[\"getStorageToken\"],\n\trequestHeaders?: Readonly<Record<string, string>>,\n): Promise<IOdspVersionManager> {\n\tconst urlParts: IOdspUrlParts = {\n\t\tsiteUrl: odspResolvedUrl.siteUrl,\n\t\tdriveId: odspResolvedUrl.driveId,\n\t\titemId: odspResolvedUrl.itemId,\n\t};\n\tconst getAuthHeader = toInstrumentedOdspStorageTokenFetcher(\n\t\tlogger,\n\t\turlParts,\n\t\tgetStorageToken,\n\t);\n\treturn createOdspVersionManager({\n\t\turlParts,\n\t\tgetAuthHeader,\n\t\tepochTracker,\n\t\tlogger,\n\t\trequestHeaders,\n\t});\n}\n\nasync function resolveFileVersion(\n\tresolvedUrl: IResolvedUrl,\n\tfileVersion: string,\n): Promise<IResolvedUrl> {\n\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\tconst query = new URLSearchParams({\n\t\tdriveId: odspResolvedUrl.driveId,\n\t\titemId: odspResolvedUrl.itemId,\n\t\tfileVersion,\n\t});\n\tif (odspResolvedUrl.dataStorePath !== undefined) {\n\t\tquery.set(\"path\", odspResolvedUrl.dataStorePath);\n\t}\n\tif (odspResolvedUrl.codeHint?.containerPackageName !== undefined) {\n\t\tquery.set(\"containerPackageName\", odspResolvedUrl.codeHint.containerPackageName);\n\t}\n\treturn new OdspDriverUrlResolver().resolve({\n\t\turl: `${odspResolvedUrl.siteUrl}?${query.toString()}`,\n\t});\n}\n\n/**\n * ODSP's point-in-time document service implementation.\n *\n * @remarks Import this function from the dedicated point-in-time entrypoint and inject it through\n * {@link IOdspDocumentServiceFactoryOptions.pointInTimeDocumentServiceImplementation}.\n *\n * @param props - ODSP service dependencies and point-in-time load parameters supplied by the factory.\n * @returns A read-only ODSP document service materialized at the requested sequence number.\n *\n * @legacy @beta\n */\nexport async function createPointInTimeDocumentService(\n\tprops: IOdspPointInTimeDocumentServiceImplementationProps,\n): Promise<IDocumentService> {\n\treturn createPointInTimeDocumentServiceCore(props);\n}\n\n/**\n * Creates the point-in-time service with replaceable dependencies for testing.\n * @internal\n */\nexport async function createPointInTimeDocumentServiceCore(\n\t{\n\t\tresolvedUrl,\n\t\ttargetSequenceNumber,\n\t\tlogger,\n\t\tclientIsSummarizer,\n\t\tpersistedCache,\n\t\tgetStorageToken,\n\t\trequestHeaders,\n\t\tcreateDocumentService,\n\t}: IOdspPointInTimeDocumentServiceImplementationProps,\n\tdependencies: IPointInTimeDocumentServiceDependencies = {},\n): Promise<OdspPointInTimeDocumentService> {\n\tconst odspLogger = createOdspLogger(logger);\n\tconst extLogger = createChildLogger({ logger: odspLogger });\n\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\tconst cacheAndTracker = createOdspCacheAndTracker(\n\t\tpersistedCache,\n\t\tnew NonPersistentCache(),\n\t\t{\n\t\t\tresolvedUrl: odspResolvedUrl,\n\t\t\tdocId: odspResolvedUrl.hashedDocumentId,\n\t\t\tfileVersion: odspResolvedUrl.fileVersion,\n\t\t},\n\t\textLogger,\n\t\tclientIsSummarizer,\n\t\trequestHeaders,\n\t);\n\n\tconst versionManager = await (\n\t\tdependencies.createVersionManager ??\n\t\t(async (url, versionLogger, epochTracker) =>\n\t\t\tcreateVersionManager(url, versionLogger, epochTracker, getStorageToken, requestHeaders))\n\t)(odspResolvedUrl, extLogger, cacheAndTracker.epochTracker);\n\tconst baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);\n\tif (baseResult.kind === \"noBaseVersion\") {\n\t\tconst oldestResolvedSequenceDetail =\n\t\t\tbaseResult.oldestResolvedSeq === undefined\n\t\t\t\t? \"\"\n\t\t\t\t: ` The oldest resolved file version is at sequence number ${baseResult.oldestResolvedSeq}.`;\n\t\tthrow new UsageError(\n\t\t\t`No ODSP file version is available at or before sequence number ${targetSequenceNumber}.${oldestResolvedSequenceDetail}`,\n\t\t);\n\t}\n\n\tconst recoverableResolvedUrl = await (dependencies.resolveFileVersion ?? resolveFileVersion)(\n\t\tresolvedUrl,\n\t\tbaseResult.base.versionId,\n\t);\n\tconst recoverableDocumentService = await createDocumentService(\n\t\trecoverableResolvedUrl,\n\t\todspLogger,\n\t\tcacheAndTracker,\n\t\tclientIsSummarizer,\n\t);\n\tlet liveDocumentService: IDocumentService;\n\ttry {\n\t\tliveDocumentService = await createDocumentService(\n\t\t\tresolvedUrl,\n\t\t\todspLogger,\n\t\t\tcacheAndTracker,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t} catch (error) {\n\t\ttry {\n\t\t\trecoverableDocumentService.dispose();\n\t\t} catch (disposeError) {\n\t\t\textLogger.sendErrorEvent(\n\t\t\t\t{ eventName: \"PointInTimeRecoverableDocumentServiceDisposeError\" },\n\t\t\t\tdisposeError,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t}\n\treturn new OdspPointInTimeDocumentService(\n\t\trecoverableResolvedUrl,\n\t\trecoverableDocumentService,\n\t\tliveDocumentService,\n\t\ttargetSequenceNumber,\n\t);\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
6
|
-
import type
|
|
6
|
+
import { type IClient, type IDocumentDeltaConnection, type IDocumentDeltaStorageService, type IDocumentService, type IDocumentServiceEvents, type IDocumentServicePolicies, type IDocumentStorageService, type IResolvedUrl } from "@fluidframework/driver-definitions/internal";
|
|
7
7
|
/**
|
|
8
8
|
* A read-only document service that materializes a document at a target sequence number by combining
|
|
9
9
|
* a recoverable snapshot with a bounded replay of live ops.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspPointInTimeDocumentService.d.ts","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"odspPointInTimeDocumentService.d.ts","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAEN,KAAK,OAAO,EACZ,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EAIjB,MAAM,6CAA6C,CAAC;AA2BrD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,8BACZ,SAAQ,iBAAiB,CAAC,sBAAsB,CAChD,YAAW,gBAAgB;aAGV,WAAW,EAAE,YAAY;IAGzC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBALrB,WAAW,EAAE,YAAY,EAGxB,0BAA0B,EAAE,gBAAgB,EAC5C,mBAAmB,EAAE,gBAAgB,EACrC,oBAAoB,EAAE,MAAM;IAQ9C,SAAgB,QAAQ,EAAE,wBAAwB,CAAyB;IAEpE,OAAO,IAAI,IAAI;IAMT,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAKpD,qBAAqB,IAAI,OAAO,CAAC,4BAA4B,CAAC;IAgB9D,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAStF,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAEpC;CACF"}
|
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.OdspPointInTimeDocumentService = void 0;
|
|
8
8
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
9
|
+
const internal_1 = require("@fluidframework/driver-definitions/internal");
|
|
10
|
+
const internal_2 = require("@fluidframework/driver-utils/internal");
|
|
11
|
+
/**
|
|
12
|
+
* Forces point-in-time snapshot reads to bypass caches while forwarding all other storage operations
|
|
13
|
+
* to the selected historical document service.
|
|
14
|
+
*/
|
|
15
|
+
class PointInTimeDocumentStorageService extends internal_2.DocumentStorageServiceProxy {
|
|
16
|
+
async getSnapshot(snapshotFetchOptions) {
|
|
17
|
+
return super.getSnapshot({
|
|
18
|
+
...snapshotFetchOptions,
|
|
19
|
+
fetchSource: internal_1.FetchSource.noCache,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async getVersions(
|
|
23
|
+
// eslint-disable-next-line @rushstack/no-new-null -- IDocumentStorageService is a legacy API that requires null.
|
|
24
|
+
versionId, count, scenarioName) {
|
|
25
|
+
return super.getVersions(versionId, count, scenarioName, internal_1.FetchSource.noCache);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
9
28
|
/**
|
|
10
29
|
* A read-only document service that materializes a document at a target sequence number by combining
|
|
11
30
|
* a recoverable snapshot with a bounded replay of live ops.
|
|
@@ -53,7 +72,8 @@ class OdspPointInTimeDocumentService extends client_utils_1.TypedEventEmitter {
|
|
|
53
72
|
this.liveDocumentService.dispose();
|
|
54
73
|
}
|
|
55
74
|
async connectToStorage() {
|
|
56
|
-
|
|
75
|
+
const storage = await this.recoverableDocumentService.connectToStorage();
|
|
76
|
+
return new PointInTimeDocumentStorageService(storage);
|
|
57
77
|
}
|
|
58
78
|
async connectToDeltaStorage() {
|
|
59
79
|
const liveDeltaStorage = await this.liveDocumentService.connectToDeltaStorage();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspPointInTimeDocumentService.js","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentService.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;
|
|
1
|
+
{"version":3,"file":"odspPointInTimeDocumentService.js","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentService.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AACjE,0EAaqD;AACrD,oEAAoF;AAEpF;;;GAGG;AACH,MAAM,iCAAkC,SAAQ,sCAA2B;IAC1D,KAAK,CAAC,WAAW,CAChC,oBAA4C;QAE5C,OAAO,KAAK,CAAC,WAAW,CAAC;YACxB,GAAG,oBAAoB;YACvB,WAAW,EAAE,sBAAW,CAAC,OAAO;SAChC,CAAC,CAAC;IACJ,CAAC;IAEe,KAAK,CAAC,WAAW;IAChC,iHAAiH;IACjH,SAAwB,EACxB,KAAa,EACb,YAAqB;QAErB,OAAO,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,sBAAW,CAAC,OAAO,CAAC,CAAC;IAC/E,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,8BACZ,SAAQ,gCAAyC;IAIhC;IAGC;IACA;IACA;IANlB,YACiB,WAAyB;IACzC,4FAA4F;IAC5F,sFAAsF;IACrE,0BAA4C,EAC5C,mBAAqC,EACrC,oBAA4B;QAE7C,KAAK,EAAE,CAAC;QAPQ,gBAAW,GAAX,WAAW,CAAc;QAGxB,+BAA0B,GAA1B,0BAA0B,CAAkB;QAC5C,wBAAmB,GAAnB,mBAAmB,CAAkB;QACrC,yBAAoB,GAApB,oBAAoB,CAAQ;QAG7C,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,gBAAgB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC3E,CAAC;IAED,+FAA+F;IAC/F,qEAAqE;IACrD,QAAQ,GAA6B,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAEpE,OAAO;QACb,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC3E,IAAI,CAAC,0BAA0B,CAAC,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,gBAAgB;QAC5B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,gBAAgB,EAAE,CAAC;QACzE,OAAO,IAAI,iCAAiC,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;IAEM,KAAK,CAAC,qBAAqB;QACjC,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,CAAC;QAChF,oEAAoE;QACpE,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAChD,OAAO;YACN,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CACjE,gBAAgB,CAAC,aAAa,CAC7B,IAAI,EACJ,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,EACtD,WAAW,EACX,UAAU,EACV,WAAW,CACX;SACF,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,OAAgB;QACjD,0FAA0F;QAC1F,yFAAyF;QACzF,8DAA8D;QAC9D,MAAM,IAAI,KAAK,CACd,2FAA2F,CAC3F,CAAC;IACH,CAAC;IAEgB,qBAAqB,GAAG,CAAC,QAAgC,EAAQ,EAAE;QACnF,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC;CACF;AA3DD,wEA2DC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport {\n\tFetchSource,\n\ttype IClient,\n\ttype IDocumentDeltaConnection,\n\ttype IDocumentDeltaStorageService,\n\ttype IDocumentService,\n\ttype IDocumentServiceEvents,\n\ttype IDocumentServicePolicies,\n\ttype IDocumentStorageService,\n\ttype IResolvedUrl,\n\ttype ISnapshot,\n\ttype ISnapshotFetchOptions,\n\ttype IVersion,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { DocumentStorageServiceProxy } from \"@fluidframework/driver-utils/internal\";\n\n/**\n * Forces point-in-time snapshot reads to bypass caches while forwarding all other storage operations\n * to the selected historical document service.\n */\nclass PointInTimeDocumentStorageService extends DocumentStorageServiceProxy {\n\tpublic override async getSnapshot(\n\t\tsnapshotFetchOptions?: ISnapshotFetchOptions,\n\t): Promise<ISnapshot> {\n\t\treturn super.getSnapshot({\n\t\t\t...snapshotFetchOptions,\n\t\t\tfetchSource: FetchSource.noCache,\n\t\t});\n\t}\n\n\tpublic override async getVersions(\n\t\t// eslint-disable-next-line @rushstack/no-new-null -- IDocumentStorageService is a legacy API that requires null.\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t): Promise<IVersion[]> {\n\t\treturn super.getVersions(versionId, count, scenarioName, FetchSource.noCache);\n\t}\n}\n\n/**\n * A read-only document service that materializes a document at a target sequence number by combining\n * a recoverable snapshot with a bounded replay of live ops.\n *\n * @remarks\n * Storage (the snapshot) is served from the closest file version at or before the target sequence\n * number. The ops needed to advance from that snapshot to the target are read from the live\n * document's delta storage, bounded so that no op past the target is ever fetched.\n *\n * The service advertises the {@link IDocumentServicePolicies.storageOnly} policy. This reuses the\n * loader's \"frozen\" load mechanism: the connection manager synthesizes a read-only frozen delta\n * stream instead of opening a live socket, and forces the container read-only. The delta manager\n * still catches up from the snapshot's sequence number through delta storage, which is exactly the\n * bounded replay we want. As a result no live delta-stream connection is ever established.\n *\n * Op availability is enforced by the delta storage stack itself: it validates that fetched batches\n * are contiguous from the requested start, keeps requesting until the bounded range is fully\n * delivered, and fails the fetch if the ops never materialize. So a stream that completes has\n * necessarily served the whole bridge, and no additional checks are needed here.\n *\n * @internal\n */\nexport class OdspPointInTimeDocumentService\n\textends TypedEventEmitter<IDocumentServiceEvents>\n\timplements IDocumentService\n{\n\tpublic constructor(\n\t\tpublic readonly resolvedUrl: IResolvedUrl,\n\t\t// Serves the snapshot: a read-only document service bound to the closest file version at or\n\t\t// before the target sequence number. Its storage is the base we replay ops on top of.\n\t\tprivate readonly recoverableDocumentService: IDocumentService,\n\t\tprivate readonly liveDocumentService: IDocumentService,\n\t\tprivate readonly targetSequenceNumber: number,\n\t) {\n\t\tsuper();\n\t\tthis.liveDocumentService.on(\"metadataUpdate\", this.metadataUpdateHandler);\n\t}\n\n\t// storageOnly makes the connection manager synthesize a read-only frozen delta stream (no live\n\t// socket) and force the container read-only - see the class remarks.\n\tpublic readonly policies: IDocumentServicePolicies = { storageOnly: true };\n\n\tpublic dispose(): void {\n\t\tthis.liveDocumentService.off(\"metadataUpdate\", this.metadataUpdateHandler);\n\t\tthis.recoverableDocumentService.dispose();\n\t\tthis.liveDocumentService.dispose();\n\t}\n\n\tpublic async connectToStorage(): Promise<IDocumentStorageService> {\n\t\tconst storage = await this.recoverableDocumentService.connectToStorage();\n\t\treturn new PointInTimeDocumentStorageService(storage);\n\t}\n\n\tpublic async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {\n\t\tconst liveDeltaStorage = await this.liveDocumentService.connectToDeltaStorage();\n\t\t// The exclusive upper bound needed to include the target op itself.\n\t\tconst boundedTo = this.targetSequenceNumber + 1;\n\t\treturn {\n\t\t\tfetchMessages: (from, to, abortSignal, cachedOnly, fetchReason) =>\n\t\t\t\tliveDeltaStorage.fetchMessages(\n\t\t\t\t\tfrom,\n\t\t\t\t\tto === undefined ? boundedTo : Math.min(to, boundedTo),\n\t\t\t\t\tabortSignal,\n\t\t\t\t\tcachedOnly,\n\t\t\t\t\tfetchReason,\n\t\t\t\t),\n\t\t};\n\t}\n\n\tpublic async connectToDeltaStream(_client: IClient): Promise<IDocumentDeltaConnection> {\n\t\t// Unreachable under normal flow: the connection manager short-circuits on the storageOnly\n\t\t// policy and synthesizes a frozen delta stream before ever calling connectToDeltaStream.\n\t\t// Reaching here indicates a regression of that short-circuit.\n\t\tthrow new Error(\n\t\t\t\"OdspPointInTimeDocumentService is storage-only; connectToDeltaStream should not be called\",\n\t\t);\n\t}\n\n\tprivate readonly metadataUpdateHandler = (metadata: Record<string, string>): void => {\n\t\tthis.emit(\"metadataUpdate\", metadata);\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefetchLatestSnapshot.d.ts","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EACX,eAAe,EACf,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAGX,gBAAgB,EAChB,6BAA6B,EAC7B,YAAY,EAEZ,MAAM,kDAAkD,CAAC;AAO1D,OAAO,EAEN,KAAK,yBAAyB,EAG9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAUlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,YAAY,CAAC,6BAA6B,CAAC,EAC5D,cAAc,EAAE,eAAe,EAC/B,uCAAuC,EAAE,OAAO,EAChD,MAAM,EAAE,oBAAoB,EAC5B,wBAAwB,EAAE,gBAAgB,GAAG,SAAS,EACtD,oBAAoB,GAAE,OAAc,EACpC,0BAA0B,CAAC,EAAE,OAAO,EACpC,wBAAwB,CAAC,EAAE,yBAAyB,EACpD,0BAA0B,CAAC,EAAE,0BAA0B,GACrD,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"prefetchLatestSnapshot.d.ts","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,KAAK,EACX,eAAe,EACf,YAAY,EACZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAGX,gBAAgB,EAChB,6BAA6B,EAC7B,YAAY,EAEZ,MAAM,kDAAkD,CAAC;AAO1D,OAAO,EAEN,KAAK,yBAAyB,EAG9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAUlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,YAAY,CAAC,6BAA6B,CAAC,EAC5D,cAAc,EAAE,eAAe,EAC/B,uCAAuC,EAAE,OAAO,EAChD,MAAM,EAAE,oBAAoB,EAC5B,wBAAwB,EAAE,gBAAgB,GAAG,SAAS,EACtD,oBAAoB,GAAE,OAAc,EACpC,0BAA0B,CAAC,EAAE,OAAO,EACpC,wBAAwB,CAAC,EAAE,yBAAyB,EACpD,0BAA0B,CAAC,EAAE,0BAA0B,GACrD,OAAO,CAAC,OAAO,CAAC,CAiHlB"}
|
|
@@ -49,7 +49,7 @@ async function prefetchLatestSnapshot(resolvedUrl, getStorageToken, persistedCac
|
|
|
49
49
|
};
|
|
50
50
|
const getAuthHeader = (0, odspUtils_js_1.toInstrumentedOdspStorageTokenFetcher)(odspLogger, resolvedUrlData, getStorageToken);
|
|
51
51
|
const snapshotDownloader = async (finalOdspResolvedUrl, storageTokenFetcher, tokenFetchOptions, loadingGroupId, snapshotOptions, controller) => {
|
|
52
|
-
return (0, fetchSnapshot_js_1.downloadSnapshot)(finalOdspResolvedUrl, storageTokenFetcher, tokenFetchOptions, loadingGroupId, snapshotOptions, odspLogger, undefined, controller);
|
|
52
|
+
return (0, fetchSnapshot_js_1.downloadSnapshot)(finalOdspResolvedUrl, storageTokenFetcher, tokenFetchOptions, loadingGroupId, snapshotOptions, odspLogger, undefined, controller, undefined, undefined, odspDocumentServiceFactory?.requestHeaders);
|
|
53
53
|
};
|
|
54
54
|
const snapshotKey = (0, odspUtils_js_1.createCacheSnapshotKey)(odspResolvedUrl, useGroupIdsForSnapshotFetch);
|
|
55
55
|
let cacheP;
|
|
@@ -67,7 +67,7 @@ async function prefetchLatestSnapshot(resolvedUrl, getStorageToken, persistedCac
|
|
|
67
67
|
const nonPersistentCacheKey = (0, internal_2.getKeyForCacheEntry)(snapshotKey);
|
|
68
68
|
const snapshotNonPersistentCache = odspDocumentServiceFactory?.snapshotPrefetchResultCache;
|
|
69
69
|
snapshotNonPersistentCache?.add(nonPersistentCacheKey, async () => snapshotContentsWithEpochP.promise);
|
|
70
|
-
await (0, fetchSnapshot_js_1.fetchSnapshotWithRedeem)(odspResolvedUrl, getAuthHeader, hostSnapshotFetchOptions, odspLogger, snapshotDownloader, putInCache, removeEntries, loadingGroupIds, enableRedeemFallback)
|
|
70
|
+
await (0, fetchSnapshot_js_1.fetchSnapshotWithRedeem)(odspResolvedUrl, getAuthHeader, hostSnapshotFetchOptions, odspLogger, snapshotDownloader, putInCache, removeEntries, loadingGroupIds, enableRedeemFallback, odspDocumentServiceFactory?.requestHeaders)
|
|
71
71
|
.then(async (value) => {
|
|
72
72
|
(0, internal_1.assert)(!!snapshotEpoch, 0x585 /* prefetched snapshot should have a valid epoch */);
|
|
73
73
|
snapshotContentsWithEpochP.resolve({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefetchLatestSnapshot.js","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPersistedCache,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { getKeyForCacheEntry } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tIOdspResolvedUrl,\n\tIOdspUrlParts,\n\tISnapshotOptions,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tPerformanceEvent,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { IVersionedValueWithEpoch } from \"./contracts.js\";\nimport {\n\ttype ISnapshotRequestAndResponseOptions,\n\ttype SnapshotFormatSupportType,\n\tdownloadSnapshot,\n\tfetchSnapshotWithRedeem,\n} from \"./fetchSnapshot.js\";\nimport type { IPrefetchSnapshotContents } from \"./odspCache.js\";\nimport type { OdspDocumentServiceFactory } from \"./odspDocumentServiceFactory.js\";\nimport {\n\tcreateCacheSnapshotKey,\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\tsnapshotWithLoadingGroupIdSupported,\n\ttoInstrumentedOdspStorageTokenFetcher,\n\ttype TokenFetchOptionsEx,\n} from \"./odspUtils.js\";\n\n/**\n * Function to prefetch the snapshot and cached it in the persistent cache, so that when the container is loaded\n * the cached latest snapshot could be used and removes the network call from the critical path.\n *\n * @param resolvedUrl - Resolved url to fetch the snapshot.\n * @param getStorageToken - function that can provide the storage token for a given site. This is\n * is also referred to as the \"VROOM\" token in SPO.\n * @param persistedCache - Cache to store the fetched snapshot.\n * @param _forceAccessTokenViaAuthorizationHeader - Deprecated and not used.\n * @param logger - Logger to have telemetry events.\n * @param hostSnapshotFetchOptions - Options to fetch the snapshot if any. Otherwise default will be used.\n * @param enableRedeemFallback - True to have the sharing link redeem fallback in case the Trees Latest/Redeem\n * 1RT call fails with redeem error. During fallback it will first redeem the sharing link and then make\n * the Trees latest call.\n * Note: this can be considered deprecated - it will be replaced with `snapshotFormatFetchType`.\n * @param _fetchBinarySnapshotFormat - Deprecated and not used.\n * @param _snapshotFormatFetchType - Deprecated and not used.\n * @param odspDocumentServiceFactory - factory to access the non persistent cache and store the prefetch promise.\n *\n * @returns `true` if the snapshot is cached, `false` otherwise.\n * @legacy\n * @beta\n */\nexport async function prefetchLatestSnapshot(\n\tresolvedUrl: IResolvedUrl,\n\tgetStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>,\n\tpersistedCache: IPersistedCache,\n\t_forceAccessTokenViaAuthorizationHeader: boolean,\n\tlogger: ITelemetryBaseLogger,\n\thostSnapshotFetchOptions: ISnapshotOptions | undefined,\n\tenableRedeemFallback: boolean = true,\n\t_fetchBinarySnapshotFormat?: boolean,\n\t_snapshotFormatFetchType?: SnapshotFormatSupportType,\n\todspDocumentServiceFactory?: OdspDocumentServiceFactory,\n): Promise<boolean> {\n\tconst mc = createChildMonitoringContext({ logger, namespace: \"PrefetchSnapshot\" });\n\tconst odspLogger = createOdspLogger(mc.logger);\n\tconst useGroupIdsForSnapshotFetch = snapshotWithLoadingGroupIdSupported(mc.config);\n\t// For prefetch, we just want to fetch the ungrouped data and want to use the new API if the\n\t// feature gate is set, so provide an empty array.\n\tconst loadingGroupIds = useGroupIdsForSnapshotFetch ? [] : undefined;\n\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\tconst resolvedUrlData: IOdspUrlParts = {\n\t\tsiteUrl: odspResolvedUrl.siteUrl,\n\t\tdriveId: odspResolvedUrl.driveId,\n\t\titemId: odspResolvedUrl.itemId,\n\t};\n\tconst getAuthHeader = toInstrumentedOdspStorageTokenFetcher(\n\t\todspLogger,\n\t\tresolvedUrlData,\n\t\tgetStorageToken,\n\t);\n\n\tconst snapshotDownloader = async (\n\t\tfinalOdspResolvedUrl: IOdspResolvedUrl,\n\t\tstorageTokenFetcher: InstrumentedStorageTokenFetcher,\n\t\ttokenFetchOptions: TokenFetchOptionsEx,\n\t\tloadingGroupId: string[] | undefined,\n\t\tsnapshotOptions: ISnapshotOptions | undefined,\n\t\tcontroller?: AbortController,\n\t): Promise<ISnapshotRequestAndResponseOptions> => {\n\t\treturn downloadSnapshot(\n\t\t\tfinalOdspResolvedUrl,\n\t\t\tstorageTokenFetcher,\n\t\t\ttokenFetchOptions,\n\t\t\tloadingGroupId,\n\t\t\tsnapshotOptions,\n\t\t\todspLogger,\n\t\t\tundefined,\n\t\t\tcontroller,\n\t\t);\n\t};\n\tconst snapshotKey = createCacheSnapshotKey(odspResolvedUrl, useGroupIdsForSnapshotFetch);\n\tlet cacheP: Promise<void> | undefined;\n\tlet snapshotEpoch: string | undefined;\n\tconst putInCache = async (valueWithEpoch: IVersionedValueWithEpoch): Promise<void> => {\n\t\tsnapshotEpoch = valueWithEpoch.fluidEpoch;\n\t\tcacheP = persistedCache.put(snapshotKey, valueWithEpoch);\n\t\treturn cacheP;\n\t};\n\n\tconst removeEntries = async (): Promise<void> =>\n\t\tpersistedCache.removeEntries(snapshotKey.file);\n\treturn PerformanceEvent.timedExecAsync(\n\t\todspLogger,\n\t\t{ eventName: \"PrefetchLatestSnapshot\" },\n\t\tasync () => {\n\t\t\tconst prefetchStartTime = performanceNow();\n\t\t\t// Add the deferred promise to the cache, so that it can be leveraged while loading the container.\n\t\t\tconst snapshotContentsWithEpochP = new Deferred<IPrefetchSnapshotContents>();\n\t\t\tconst nonPersistentCacheKey = getKeyForCacheEntry(snapshotKey);\n\t\t\tconst snapshotNonPersistentCache =\n\t\t\t\todspDocumentServiceFactory?.snapshotPrefetchResultCache;\n\t\t\tsnapshotNonPersistentCache?.add(\n\t\t\t\tnonPersistentCacheKey,\n\t\t\t\tasync () => snapshotContentsWithEpochP.promise,\n\t\t\t);\n\t\t\tawait fetchSnapshotWithRedeem(\n\t\t\t\todspResolvedUrl,\n\t\t\t\tgetAuthHeader,\n\t\t\t\thostSnapshotFetchOptions,\n\t\t\t\todspLogger,\n\t\t\t\tsnapshotDownloader,\n\t\t\t\tputInCache,\n\t\t\t\tremoveEntries,\n\t\t\t\tloadingGroupIds,\n\t\t\t\tenableRedeemFallback,\n\t\t\t)\n\t\t\t\t.then(async (value) => {\n\t\t\t\t\tassert(!!snapshotEpoch, 0x585 /* prefetched snapshot should have a valid epoch */);\n\t\t\t\t\tsnapshotContentsWithEpochP.resolve({\n\t\t\t\t\t\t...value,\n\t\t\t\t\t\tfluidEpoch: snapshotEpoch,\n\t\t\t\t\t\tprefetchStartTime,\n\t\t\t\t\t});\n\t\t\t\t\tassert(cacheP !== undefined, 0x1e7 /* \"caching was not performed!\" */);\n\t\t\t\t\tawait cacheP;\n\t\t\t\t\t// Schedule it to remove from cache after 5s.\n\t\t\t\t\t// 1. While it's in snapshotNonPersistentCache: Load flow will use this value and will not attempt\n\t\t\t\t\t// to fetch snapshot from network again. That's the best from perf POV, but cache will not be\n\t\t\t\t\t// updated if we keep it in this cache, thus we want to eventually remove snapshot from this cache.\n\t\t\t\t\t// 2. After it's removed from snapshotNonPersistentCache: snapshot is present in persistent cache,\n\t\t\t\t\t// so we sill still use it (in accordance with cache policy controlled by host). But load flow will\n\t\t\t\t\t// also fetch snapshot (in parallel) from storage and update cache. This is fine long term,\n\t\t\t\t\t// but is an extra cost (unneeded network call). However since it is 5s older, new network call\n\t\t\t\t\t// will update the snapshot in cache.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tsnapshotNonPersistentCache?.remove(nonPersistentCacheKey);\n\t\t\t\t\t}, 5000);\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\t// Remove it from the non persistent cache if an error occurred.\n\t\t\t\t\tsnapshotNonPersistentCache?.remove(nonPersistentCacheKey);\n\t\t\t\t\tsnapshotContentsWithEpochP.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t\treturn true;\n\t\t},\n\t).catch(async (error) => {\n\t\todspLogger.sendErrorEvent({ eventName: \"PrefetchLatestSnapshotError\" }, error);\n\t\treturn false;\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"prefetchLatestSnapshot.js","sourceRoot":"","sources":["../src/prefetchLatestSnapshot.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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert, Deferred } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPersistedCache,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { getKeyForCacheEntry } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tIOdspResolvedUrl,\n\tIOdspUrlParts,\n\tISnapshotOptions,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tPerformanceEvent,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { IVersionedValueWithEpoch } from \"./contracts.js\";\nimport {\n\ttype ISnapshotRequestAndResponseOptions,\n\ttype SnapshotFormatSupportType,\n\tdownloadSnapshot,\n\tfetchSnapshotWithRedeem,\n} from \"./fetchSnapshot.js\";\nimport type { IPrefetchSnapshotContents } from \"./odspCache.js\";\nimport type { OdspDocumentServiceFactory } from \"./odspDocumentServiceFactory.js\";\nimport {\n\tcreateCacheSnapshotKey,\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\tsnapshotWithLoadingGroupIdSupported,\n\ttoInstrumentedOdspStorageTokenFetcher,\n\ttype TokenFetchOptionsEx,\n} from \"./odspUtils.js\";\n\n/**\n * Function to prefetch the snapshot and cached it in the persistent cache, so that when the container is loaded\n * the cached latest snapshot could be used and removes the network call from the critical path.\n *\n * @param resolvedUrl - Resolved url to fetch the snapshot.\n * @param getStorageToken - function that can provide the storage token for a given site. This is\n * is also referred to as the \"VROOM\" token in SPO.\n * @param persistedCache - Cache to store the fetched snapshot.\n * @param _forceAccessTokenViaAuthorizationHeader - Deprecated and not used.\n * @param logger - Logger to have telemetry events.\n * @param hostSnapshotFetchOptions - Options to fetch the snapshot if any. Otherwise default will be used.\n * @param enableRedeemFallback - True to have the sharing link redeem fallback in case the Trees Latest/Redeem\n * 1RT call fails with redeem error. During fallback it will first redeem the sharing link and then make\n * the Trees latest call.\n * Note: this can be considered deprecated - it will be replaced with `snapshotFormatFetchType`.\n * @param _fetchBinarySnapshotFormat - Deprecated and not used.\n * @param _snapshotFormatFetchType - Deprecated and not used.\n * @param odspDocumentServiceFactory - factory to access the non persistent cache and store the prefetch promise.\n *\n * @returns `true` if the snapshot is cached, `false` otherwise.\n * @legacy\n * @beta\n */\nexport async function prefetchLatestSnapshot(\n\tresolvedUrl: IResolvedUrl,\n\tgetStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>,\n\tpersistedCache: IPersistedCache,\n\t_forceAccessTokenViaAuthorizationHeader: boolean,\n\tlogger: ITelemetryBaseLogger,\n\thostSnapshotFetchOptions: ISnapshotOptions | undefined,\n\tenableRedeemFallback: boolean = true,\n\t_fetchBinarySnapshotFormat?: boolean,\n\t_snapshotFormatFetchType?: SnapshotFormatSupportType,\n\todspDocumentServiceFactory?: OdspDocumentServiceFactory,\n): Promise<boolean> {\n\tconst mc = createChildMonitoringContext({ logger, namespace: \"PrefetchSnapshot\" });\n\tconst odspLogger = createOdspLogger(mc.logger);\n\tconst useGroupIdsForSnapshotFetch = snapshotWithLoadingGroupIdSupported(mc.config);\n\t// For prefetch, we just want to fetch the ungrouped data and want to use the new API if the\n\t// feature gate is set, so provide an empty array.\n\tconst loadingGroupIds = useGroupIdsForSnapshotFetch ? [] : undefined;\n\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\tconst resolvedUrlData: IOdspUrlParts = {\n\t\tsiteUrl: odspResolvedUrl.siteUrl,\n\t\tdriveId: odspResolvedUrl.driveId,\n\t\titemId: odspResolvedUrl.itemId,\n\t};\n\tconst getAuthHeader = toInstrumentedOdspStorageTokenFetcher(\n\t\todspLogger,\n\t\tresolvedUrlData,\n\t\tgetStorageToken,\n\t);\n\n\tconst snapshotDownloader = async (\n\t\tfinalOdspResolvedUrl: IOdspResolvedUrl,\n\t\tstorageTokenFetcher: InstrumentedStorageTokenFetcher,\n\t\ttokenFetchOptions: TokenFetchOptionsEx,\n\t\tloadingGroupId: string[] | undefined,\n\t\tsnapshotOptions: ISnapshotOptions | undefined,\n\t\tcontroller?: AbortController,\n\t): Promise<ISnapshotRequestAndResponseOptions> => {\n\t\treturn downloadSnapshot(\n\t\t\tfinalOdspResolvedUrl,\n\t\t\tstorageTokenFetcher,\n\t\t\ttokenFetchOptions,\n\t\t\tloadingGroupId,\n\t\t\tsnapshotOptions,\n\t\t\todspLogger,\n\t\t\tundefined,\n\t\t\tcontroller,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\todspDocumentServiceFactory?.requestHeaders,\n\t\t);\n\t};\n\tconst snapshotKey = createCacheSnapshotKey(odspResolvedUrl, useGroupIdsForSnapshotFetch);\n\tlet cacheP: Promise<void> | undefined;\n\tlet snapshotEpoch: string | undefined;\n\tconst putInCache = async (valueWithEpoch: IVersionedValueWithEpoch): Promise<void> => {\n\t\tsnapshotEpoch = valueWithEpoch.fluidEpoch;\n\t\tcacheP = persistedCache.put(snapshotKey, valueWithEpoch);\n\t\treturn cacheP;\n\t};\n\n\tconst removeEntries = async (): Promise<void> =>\n\t\tpersistedCache.removeEntries(snapshotKey.file);\n\treturn PerformanceEvent.timedExecAsync(\n\t\todspLogger,\n\t\t{ eventName: \"PrefetchLatestSnapshot\" },\n\t\tasync () => {\n\t\t\tconst prefetchStartTime = performanceNow();\n\t\t\t// Add the deferred promise to the cache, so that it can be leveraged while loading the container.\n\t\t\tconst snapshotContentsWithEpochP = new Deferred<IPrefetchSnapshotContents>();\n\t\t\tconst nonPersistentCacheKey = getKeyForCacheEntry(snapshotKey);\n\t\t\tconst snapshotNonPersistentCache =\n\t\t\t\todspDocumentServiceFactory?.snapshotPrefetchResultCache;\n\t\t\tsnapshotNonPersistentCache?.add(\n\t\t\t\tnonPersistentCacheKey,\n\t\t\t\tasync () => snapshotContentsWithEpochP.promise,\n\t\t\t);\n\t\t\tawait fetchSnapshotWithRedeem(\n\t\t\t\todspResolvedUrl,\n\t\t\t\tgetAuthHeader,\n\t\t\t\thostSnapshotFetchOptions,\n\t\t\t\todspLogger,\n\t\t\t\tsnapshotDownloader,\n\t\t\t\tputInCache,\n\t\t\t\tremoveEntries,\n\t\t\t\tloadingGroupIds,\n\t\t\t\tenableRedeemFallback,\n\t\t\t\todspDocumentServiceFactory?.requestHeaders,\n\t\t\t)\n\t\t\t\t.then(async (value) => {\n\t\t\t\t\tassert(!!snapshotEpoch, 0x585 /* prefetched snapshot should have a valid epoch */);\n\t\t\t\t\tsnapshotContentsWithEpochP.resolve({\n\t\t\t\t\t\t...value,\n\t\t\t\t\t\tfluidEpoch: snapshotEpoch,\n\t\t\t\t\t\tprefetchStartTime,\n\t\t\t\t\t});\n\t\t\t\t\tassert(cacheP !== undefined, 0x1e7 /* \"caching was not performed!\" */);\n\t\t\t\t\tawait cacheP;\n\t\t\t\t\t// Schedule it to remove from cache after 5s.\n\t\t\t\t\t// 1. While it's in snapshotNonPersistentCache: Load flow will use this value and will not attempt\n\t\t\t\t\t// to fetch snapshot from network again. That's the best from perf POV, but cache will not be\n\t\t\t\t\t// updated if we keep it in this cache, thus we want to eventually remove snapshot from this cache.\n\t\t\t\t\t// 2. After it's removed from snapshotNonPersistentCache: snapshot is present in persistent cache,\n\t\t\t\t\t// so we sill still use it (in accordance with cache policy controlled by host). But load flow will\n\t\t\t\t\t// also fetch snapshot (in parallel) from storage and update cache. This is fine long term,\n\t\t\t\t\t// but is an extra cost (unneeded network call). However since it is 5s older, new network call\n\t\t\t\t\t// will update the snapshot in cache.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tsnapshotNonPersistentCache?.remove(nonPersistentCacheKey);\n\t\t\t\t\t}, 5000);\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\t// Remove it from the non persistent cache if an error occurred.\n\t\t\t\t\tsnapshotNonPersistentCache?.remove(nonPersistentCacheKey);\n\t\t\t\t\tsnapshotContentsWithEpochP.reject(error);\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t\treturn true;\n\t\t},\n\t).catch(async (error) => {\n\t\todspLogger.sendErrorEvent({ eventName: \"PrefetchLatestSnapshotError\" }, error);\n\t\treturn false;\n\t});\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Creates an immutable snapshot of host-provided per-session headers after removing names owned by
|
|
7
|
+
* the ODSP driver. The factory, URL resolver, epoch tracker, and Socket.IO connection use the
|
|
8
|
+
* returned value so later host mutations cannot change an active document session or override
|
|
9
|
+
* authentication and protocol headers.
|
|
10
|
+
*/
|
|
11
|
+
export declare function copyRequestHeaders(requestHeaders: Readonly<Record<string, string>> | undefined): Readonly<Record<string, string>> | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Adds sanitized host headers to one ODSP request. Request-specific headers are applied last, so
|
|
14
|
+
* driver-generated values win case-insensitive collisions. ODSP fetch paths use this helper for
|
|
15
|
+
* snapshot, delta, blob, share-link, file-link, and version requests; Socket.IO applies the copied
|
|
16
|
+
* headers separately as Node.js `extraHeaders`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mergeRequestHeaders(hostHeaders: Readonly<Record<string, string>> | undefined, requestHeaders: HeadersInit | undefined): HeadersInit | undefined;
|
|
19
|
+
//# sourceMappingURL=requestHeaders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestHeaders.d.ts","sourceRoot":"","sources":["../src/requestHeaders.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GAC1D,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAU9C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACzD,cAAc,EAAE,WAAW,GAAG,SAAS,GACrC,WAAW,GAAG,SAAS,CAazB"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.copyRequestHeaders = copyRequestHeaders;
|
|
8
|
+
exports.mergeRequestHeaders = mergeRequestHeaders;
|
|
9
|
+
const driverOwnedHeaderNames = new Set([
|
|
10
|
+
"authorization",
|
|
11
|
+
"content-type",
|
|
12
|
+
"x-fluid-epoch",
|
|
13
|
+
"x-http-method-override",
|
|
14
|
+
"x-requeststats",
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Creates an immutable snapshot of host-provided per-session headers after removing names owned by
|
|
18
|
+
* the ODSP driver. The factory, URL resolver, epoch tracker, and Socket.IO connection use the
|
|
19
|
+
* returned value so later host mutations cannot change an active document session or override
|
|
20
|
+
* authentication and protocol headers.
|
|
21
|
+
*/
|
|
22
|
+
function copyRequestHeaders(requestHeaders) {
|
|
23
|
+
if (requestHeaders === undefined || Object.keys(requestHeaders).length === 0) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const copiedHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => !driverOwnedHeaderNames.has(name.toLowerCase())));
|
|
27
|
+
return Object.keys(copiedHeaders).length === 0 ? undefined : Object.freeze(copiedHeaders);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Adds sanitized host headers to one ODSP request. Request-specific headers are applied last, so
|
|
31
|
+
* driver-generated values win case-insensitive collisions. ODSP fetch paths use this helper for
|
|
32
|
+
* snapshot, delta, blob, share-link, file-link, and version requests; Socket.IO applies the copied
|
|
33
|
+
* headers separately as Node.js `extraHeaders`.
|
|
34
|
+
*/
|
|
35
|
+
function mergeRequestHeaders(hostHeaders, requestHeaders) {
|
|
36
|
+
const safeHostHeaders = copyRequestHeaders(hostHeaders);
|
|
37
|
+
if (safeHostHeaders === undefined) {
|
|
38
|
+
return requestHeaders;
|
|
39
|
+
}
|
|
40
|
+
const merged = new Headers(safeHostHeaders);
|
|
41
|
+
if (requestHeaders !== undefined) {
|
|
42
|
+
for (const [key, value] of new Headers(requestHeaders)) {
|
|
43
|
+
merged.set(key, value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return Object.fromEntries(merged);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=requestHeaders.js.map
|