@fluidframework/odsp-driver 0.57.2 → 0.58.1000

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/contracts.d.ts +4 -0
  2. package/dist/contracts.d.ts.map +1 -1
  3. package/dist/contracts.js.map +1 -1
  4. package/dist/createFile.d.ts.map +1 -1
  5. package/dist/createFile.js +3 -3
  6. package/dist/createFile.js.map +1 -1
  7. package/dist/epochTracker.d.ts.map +1 -1
  8. package/dist/epochTracker.js +2 -3
  9. package/dist/epochTracker.js.map +1 -1
  10. package/dist/fetchSnapshot.d.ts.map +1 -1
  11. package/dist/fetchSnapshot.js +66 -25
  12. package/dist/fetchSnapshot.js.map +1 -1
  13. package/dist/getFileLink.js +2 -2
  14. package/dist/getFileLink.js.map +1 -1
  15. package/dist/odspCache.d.ts +8 -3
  16. package/dist/odspCache.d.ts.map +1 -1
  17. package/dist/odspCache.js +1 -1
  18. package/dist/odspCache.js.map +1 -1
  19. package/dist/odspDocumentDeltaConnection.js +1 -1
  20. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  21. package/dist/odspDocumentService.d.ts +5 -0
  22. package/dist/odspDocumentService.d.ts.map +1 -1
  23. package/dist/odspDocumentService.js +88 -25
  24. package/dist/odspDocumentService.js.map +1 -1
  25. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  26. package/dist/odspDocumentStorageManager.js +5 -5
  27. package/dist/odspDocumentStorageManager.js.map +1 -1
  28. package/dist/odspDriverUrlResolver.d.ts +2 -2
  29. package/dist/odspDriverUrlResolver.d.ts.map +1 -1
  30. package/dist/odspDriverUrlResolver.js +14 -3
  31. package/dist/odspDriverUrlResolver.js.map +1 -1
  32. package/dist/odspDriverUrlResolverForShareLink.d.ts +2 -2
  33. package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  34. package/dist/odspDriverUrlResolverForShareLink.js +15 -4
  35. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  36. package/dist/odspError.d.ts.map +1 -1
  37. package/dist/odspError.js +2 -2
  38. package/dist/odspError.js.map +1 -1
  39. package/dist/odspUtils.d.ts.map +1 -1
  40. package/dist/odspUtils.js +10 -10
  41. package/dist/odspUtils.js.map +1 -1
  42. package/dist/packageVersion.d.ts +1 -1
  43. package/dist/packageVersion.d.ts.map +1 -1
  44. package/dist/packageVersion.js +1 -1
  45. package/dist/packageVersion.js.map +1 -1
  46. package/dist/retryErrorsStorageAdapter.js +1 -1
  47. package/dist/retryErrorsStorageAdapter.js.map +1 -1
  48. package/dist/vroom.d.ts +2 -1
  49. package/dist/vroom.d.ts.map +1 -1
  50. package/dist/vroom.js +6 -2
  51. package/dist/vroom.js.map +1 -1
  52. package/dist/zipItDataRepresentationUtils.js +1 -1
  53. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  54. package/lib/contracts.d.ts +4 -0
  55. package/lib/contracts.d.ts.map +1 -1
  56. package/lib/contracts.js.map +1 -1
  57. package/lib/createFile.d.ts.map +1 -1
  58. package/lib/createFile.js +3 -3
  59. package/lib/createFile.js.map +1 -1
  60. package/lib/epochTracker.d.ts.map +1 -1
  61. package/lib/epochTracker.js +2 -3
  62. package/lib/epochTracker.js.map +1 -1
  63. package/lib/fetchSnapshot.d.ts.map +1 -1
  64. package/lib/fetchSnapshot.js +66 -25
  65. package/lib/fetchSnapshot.js.map +1 -1
  66. package/lib/getFileLink.js +2 -2
  67. package/lib/getFileLink.js.map +1 -1
  68. package/lib/odspCache.d.ts +8 -3
  69. package/lib/odspCache.d.ts.map +1 -1
  70. package/lib/odspCache.js +1 -1
  71. package/lib/odspCache.js.map +1 -1
  72. package/lib/odspDocumentDeltaConnection.js +1 -1
  73. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  74. package/lib/odspDocumentService.d.ts +5 -0
  75. package/lib/odspDocumentService.d.ts.map +1 -1
  76. package/lib/odspDocumentService.js +88 -25
  77. package/lib/odspDocumentService.js.map +1 -1
  78. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  79. package/lib/odspDocumentStorageManager.js +5 -5
  80. package/lib/odspDocumentStorageManager.js.map +1 -1
  81. package/lib/odspDriverUrlResolver.d.ts +2 -2
  82. package/lib/odspDriverUrlResolver.d.ts.map +1 -1
  83. package/lib/odspDriverUrlResolver.js +15 -4
  84. package/lib/odspDriverUrlResolver.js.map +1 -1
  85. package/lib/odspDriverUrlResolverForShareLink.d.ts +2 -2
  86. package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  87. package/lib/odspDriverUrlResolverForShareLink.js +15 -4
  88. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  89. package/lib/odspError.d.ts.map +1 -1
  90. package/lib/odspError.js +2 -2
  91. package/lib/odspError.js.map +1 -1
  92. package/lib/odspUtils.d.ts.map +1 -1
  93. package/lib/odspUtils.js +10 -10
  94. package/lib/odspUtils.js.map +1 -1
  95. package/lib/packageVersion.d.ts +1 -1
  96. package/lib/packageVersion.d.ts.map +1 -1
  97. package/lib/packageVersion.js +1 -1
  98. package/lib/packageVersion.js.map +1 -1
  99. package/lib/retryErrorsStorageAdapter.js +1 -1
  100. package/lib/retryErrorsStorageAdapter.js.map +1 -1
  101. package/lib/vroom.d.ts +2 -1
  102. package/lib/vroom.d.ts.map +1 -1
  103. package/lib/vroom.js +6 -2
  104. package/lib/vroom.js.map +1 -1
  105. package/lib/zipItDataRepresentationUtils.js +1 -1
  106. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  107. package/package.json +12 -12
  108. package/src/contracts.ts +5 -0
  109. package/src/createFile.ts +2 -4
  110. package/src/epochTracker.ts +5 -4
  111. package/src/fetchSnapshot.ts +66 -33
  112. package/src/getFileLink.ts +0 -2
  113. package/src/odspCache.ts +3 -3
  114. package/src/odspDocumentDeltaConnection.ts +1 -1
  115. package/src/odspDocumentService.ts +110 -28
  116. package/src/odspDocumentStorageManager.ts +1 -6
  117. package/src/odspDriverUrlResolver.ts +18 -5
  118. package/src/odspDriverUrlResolverForShareLink.ts +17 -9
  119. package/src/odspError.ts +1 -2
  120. package/src/odspUtils.ts +10 -13
  121. package/src/packageVersion.ts +1 -1
  122. package/src/retryErrorsStorageAdapter.ts +1 -1
  123. package/src/vroom.ts +6 -0
  124. package/src/zipItDataRepresentationUtils.ts +1 -2
package/lib/createFile.js CHANGED
@@ -28,7 +28,7 @@ const isInvalidFileName = (fileName) => {
28
28
  export async function createNewFluidFile(getStorageToken, newFileInfo, logger, createNewSummary, epochTracker, fileEntry, createNewCaching, forceAccessTokenViaAuthorizationHeader) {
29
29
  // Check for valid filename before the request to create file is actually made.
30
30
  if (isInvalidFileName(newFileInfo.filename)) {
31
- throw new NonRetryableError("createNewInvalidFilename", "Invalid filename", OdspErrorType.invalidFileNameError, { driverVersion });
31
+ throw new NonRetryableError("Invalid filename for createNew", OdspErrorType.invalidFileNameError, { driverVersion });
32
32
  }
33
33
  let itemId;
34
34
  let summaryHandle = "";
@@ -84,7 +84,7 @@ export async function createNewEmptyFluidFile(getStorageToken, newFileInfo, logg
84
84
  }, "createFile"), "createFile", logger);
85
85
  const content = fetchResponse.content;
86
86
  if (!content || !content.id) {
87
- throw new NonRetryableError("createEmptyFileNoItemId", "ODSP CreateFile call returned no item ID", DriverErrorType.incorrectServerResponse, { driverVersion });
87
+ throw new NonRetryableError("ODSP CreateFile call returned no item ID (for empty file)", DriverErrorType.incorrectServerResponse, { driverVersion });
88
88
  }
89
89
  event.end(Object.assign({ headers: Object.keys(headers).length !== 0 ? true : undefined }, fetchResponse.propsToLog));
90
90
  return content.id;
@@ -111,7 +111,7 @@ export async function createNewFluidFileFromSummary(getStorageToken, newFileInfo
111
111
  }, "createFile"), "createFile", logger);
112
112
  const content = fetchResponse.content;
113
113
  if (!content || !content.itemId) {
114
- throw new NonRetryableError("createFileNoItemId", "ODSP CreateFile call returned no item ID", DriverErrorType.incorrectServerResponse, { driverVersion });
114
+ throw new NonRetryableError("ODSP CreateFile call returned no item ID", DriverErrorType.incorrectServerResponse, { driverVersion });
115
115
  }
116
116
  event.end(Object.assign({ headers: Object.keys(headers).length !== 0 ? true : undefined, attempts: options.refresh ? 2 : 1 }, fetchResponse.propsToLog));
117
117
  return content;
@@ -1 +1 @@
1
- {"version":3,"file":"createFile.js","sourceRoot":"","sources":["../src/createFile.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 { assert, Uint8ArrayToString } from \"@fluidframework/common-utils\";\nimport { getDocAttributesFromProtocolSummary, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport { SummaryType, ISummaryTree, ISummaryBlob } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IFileEntry,\n InstrumentedStorageTokenFetcher,\n IOdspResolvedUrl,\n OdspErrorType,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport {\n IOdspSummaryTree,\n OdspSummaryTreeValue,\n OdspSummaryTreeEntry,\n ICreateFileResponse,\n IOdspSummaryPayload,\n} from \"./contracts\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport {\n createCacheSnapshotKey,\n getWithRetryForTokenRefresh,\n INewFileInfo,\n getOrigin,\n ISnapshotContents,\n} from \"./odspUtils\";\nimport { createOdspUrl } from \"./createOdspUrl\";\nimport { getApiRoot } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver\";\nimport { convertCreateNewSummaryTreeToTreeAndBlobs } from \"./createNewUtils\";\nimport { runWithRetry } from \"./retryUtils\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nconst isInvalidFileName = (fileName: string): boolean => {\n const invalidCharsRegex = /[\"*/:<>?\\\\|]+/g;\n return !!fileName.match(invalidCharsRegex);\n};\n\n/**\n * Creates a new Fluid file.\n * Returns resolved url\n */\nexport async function createNewFluidFile(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n createNewSummary: ISummaryTree | undefined,\n epochTracker: EpochTracker,\n fileEntry: IFileEntry,\n createNewCaching: boolean,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<IOdspResolvedUrl> {\n // Check for valid filename before the request to create file is actually made.\n if (isInvalidFileName(newFileInfo.filename)) {\n throw new NonRetryableError(\n \"createNewInvalidFilename\", \"Invalid filename\", OdspErrorType.invalidFileNameError, { driverVersion });\n }\n\n let itemId: string;\n let summaryHandle: string = \"\";\n let sharingLink: string | undefined;\n let sharingLinkErrorReason: string | undefined;\n if (createNewSummary === undefined) {\n itemId = await createNewEmptyFluidFile(\n getStorageToken, newFileInfo, logger, epochTracker, forceAccessTokenViaAuthorizationHeader);\n } else {\n const content = await createNewFluidFileFromSummary(\n getStorageToken,\n newFileInfo,\n logger,\n createNewSummary,\n epochTracker,\n forceAccessTokenViaAuthorizationHeader,\n );\n itemId = content.itemId;\n summaryHandle = content.id;\n sharingLink = content.sharingLink;\n sharingLinkErrorReason = content.sharingLinkErrorReason;\n }\n\n const odspUrl = createOdspUrl({... newFileInfo, itemId, dataStorePath: \"/\"});\n const resolver = new OdspDriverUrlResolver();\n const odspResolvedUrl = await resolver.resolve({ url: odspUrl });\n fileEntry.docId = odspResolvedUrl.hashedDocumentId;\n fileEntry.resolvedUrl = odspResolvedUrl;\n\n if(sharingLink || sharingLinkErrorReason) {\n odspResolvedUrl.shareLinkInfo = {\n createLink: {\n type: newFileInfo.createLinkType,\n link: sharingLink,\n error: sharingLinkErrorReason,\n },\n };\n }\n\n if (createNewSummary !== undefined && createNewCaching) {\n assert(summaryHandle !== undefined, 0x203 /* \"Summary handle is undefined\" */);\n // converting summary and getting sequence number\n const snapshot: ISnapshotContents = convertCreateNewSummaryTreeToTreeAndBlobs(createNewSummary, summaryHandle);\n // caching the converted summary\n await epochTracker.put(createCacheSnapshotKey(odspResolvedUrl), snapshot);\n }\n return odspResolvedUrl;\n}\n\nexport async function createNewEmptyFluidFile(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n epochTracker: EpochTracker,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<string> {\n const filePath = newFileInfo.filePath ? encodeURIComponent(`/${newFileInfo.filePath}`) : \"\";\n // add .tmp extension to empty file (host is expected to rename)\n const encodedFilename = encodeURIComponent(`${newFileInfo.filename}.tmp`);\n const initialUrl =\n `${getApiRoot(getOrigin(newFileInfo.siteUrl))}/drives/${newFileInfo.driveId}/items/root:/${filePath\n }/${encodedFilename}:/content?@name.conflictBehavior=rename&select=id,name,parentReference`;\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await getStorageToken(options, \"CreateNewFile\");\n\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"createNewEmptyFile\" },\n async (event) => {\n const { url, headers } = getUrlAndHeadersWithAuth(\n initialUrl, storageToken, forceAccessTokenViaAuthorizationHeader);\n headers[\"Content-Type\"] = \"application/json\";\n\n const fetchResponse = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ICreateFileResponse>(\n url,\n {\n body: undefined,\n headers,\n method: \"PUT\",\n },\n \"createFile\",\n ),\n \"createFile\",\n logger,\n );\n\n const content = fetchResponse.content;\n if (!content || !content.id) {\n throw new NonRetryableError(\n \"createEmptyFileNoItemId\",\n \"ODSP CreateFile call returned no item ID\",\n DriverErrorType.incorrectServerResponse,\n { driverVersion });\n }\n event.end({\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n ...fetchResponse.propsToLog,\n });\n return content.id;\n },\n { end: true, cancel: \"error\" });\n });\n}\n\nexport async function createNewFluidFileFromSummary(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n createNewSummary: ISummaryTree,\n epochTracker: EpochTracker,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<ICreateFileResponse> {\n const filePath = newFileInfo.filePath ? encodeURIComponent(`/${newFileInfo.filePath}`) : \"\";\n const encodedFilename = encodeURIComponent(newFileInfo.filename);\n const baseUrl =\n `${getApiRoot(getOrigin(newFileInfo.siteUrl))}/drives/${newFileInfo.driveId}/items/root:` +\n `${filePath}/${encodedFilename}`;\n\n const containerSnapshot = convertSummaryIntoContainerSnapshot(createNewSummary);\n const initialUrl = `${baseUrl}:/opStream/snapshots/snapshot${newFileInfo.createLinkType ?\n `?createLinkType=${newFileInfo.createLinkType}` : \"\"}`;\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await getStorageToken(options, \"CreateNewFile\");\n\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"createNewFile\" },\n async (event) => {\n const { url, headers } = getUrlAndHeadersWithAuth(\n initialUrl, storageToken, forceAccessTokenViaAuthorizationHeader);\n headers[\"Content-Type\"] = \"application/json\";\n\n const fetchResponse = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ICreateFileResponse>(\n url,\n {\n body: JSON.stringify(containerSnapshot),\n headers,\n method: \"POST\",\n },\n \"createFile\",\n ),\n \"createFile\",\n logger,\n );\n\n const content = fetchResponse.content;\n if (!content || !content.itemId) {\n throw new NonRetryableError(\n \"createFileNoItemId\",\n \"ODSP CreateFile call returned no item ID\",\n DriverErrorType.incorrectServerResponse,\n { driverVersion });\n }\n event.end({\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n attempts: options.refresh ? 2 : 1,\n ...fetchResponse.propsToLog,\n });\n return content;\n },\n );\n });\n}\n\nfunction convertSummaryIntoContainerSnapshot(createNewSummary: ISummaryTree) {\n const appSummary = createNewSummary.tree[\".app\"] as ISummaryTree;\n const protocolSummary = createNewSummary.tree[\".protocol\"] as ISummaryTree;\n if (!(appSummary && protocolSummary)) {\n throw new Error(\"App and protocol summary required for create new path!!\");\n }\n const documentAttributes = getDocAttributesFromProtocolSummary(protocolSummary);\n const attributesSummaryBlob: ISummaryBlob = {\n type: SummaryType.Blob,\n content: JSON.stringify(documentAttributes),\n };\n protocolSummary.tree.attributes = attributesSummaryBlob;\n const convertedCreateNewSummary: ISummaryTree = {\n type: SummaryType.Tree,\n tree: {\n \".protocol\": protocolSummary,\n \".app\": appSummary,\n },\n };\n const snapshotTree = convertSummaryToSnapshotTreeForCreateNew(convertedCreateNewSummary);\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries ?? [],\n message: \"app\",\n sequenceNumber: documentAttributes.sequenceNumber,\n type: \"container\",\n };\n return snapshot;\n}\n\n/**\n * Converts a summary tree to ODSP tree\n */\nexport function convertSummaryToSnapshotTreeForCreateNew(summary: ISummaryTree): IOdspSummaryTree {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [],\n };\n\n const keys = Object.keys(summary.tree);\n for (const key of keys) {\n const summaryObject = summary.tree[key];\n\n let value: OdspSummaryTreeValue;\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is true,\n // the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n\n switch (summaryObject.type) {\n case SummaryType.Tree: {\n value = convertSummaryToSnapshotTreeForCreateNew(summaryObject);\n unreferenced = summaryObject.unreferenced;\n break;\n }\n case SummaryType.Blob: {\n const content = typeof summaryObject.content === \"string\" ?\n summaryObject.content : Uint8ArrayToString(summaryObject.content, \"base64\");\n const encoding = typeof summaryObject.content === \"string\" ? \"utf-8\" : \"base64\";\n\n value = {\n type: \"blob\",\n content,\n encoding,\n };\n break;\n }\n case SummaryType.Handle: {\n throw new Error(\"No handle should be present for first summary!!\");\n }\n default: {\n throw new Error(`Unknown tree type ${summaryObject.type}`);\n }\n }\n\n const entry: OdspSummaryTreeEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n value,\n unreferenced,\n };\n snapshotTree.entries?.push(entry);\n }\n\n return snapshotTree;\n}\n"]}
1
+ {"version":3,"file":"createFile.js","sourceRoot":"","sources":["../src/createFile.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 { assert, Uint8ArrayToString } from \"@fluidframework/common-utils\";\nimport { getDocAttributesFromProtocolSummary, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport { SummaryType, ISummaryTree, ISummaryBlob } from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IFileEntry,\n InstrumentedStorageTokenFetcher,\n IOdspResolvedUrl,\n OdspErrorType,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport {\n IOdspSummaryTree,\n OdspSummaryTreeValue,\n OdspSummaryTreeEntry,\n ICreateFileResponse,\n IOdspSummaryPayload,\n} from \"./contracts\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport {\n createCacheSnapshotKey,\n getWithRetryForTokenRefresh,\n INewFileInfo,\n getOrigin,\n ISnapshotContents,\n} from \"./odspUtils\";\nimport { createOdspUrl } from \"./createOdspUrl\";\nimport { getApiRoot } from \"./odspUrlHelper\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver\";\nimport { convertCreateNewSummaryTreeToTreeAndBlobs } from \"./createNewUtils\";\nimport { runWithRetry } from \"./retryUtils\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nconst isInvalidFileName = (fileName: string): boolean => {\n const invalidCharsRegex = /[\"*/:<>?\\\\|]+/g;\n return !!fileName.match(invalidCharsRegex);\n};\n\n/**\n * Creates a new Fluid file.\n * Returns resolved url\n */\nexport async function createNewFluidFile(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n createNewSummary: ISummaryTree | undefined,\n epochTracker: EpochTracker,\n fileEntry: IFileEntry,\n createNewCaching: boolean,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<IOdspResolvedUrl> {\n // Check for valid filename before the request to create file is actually made.\n if (isInvalidFileName(newFileInfo.filename)) {\n throw new NonRetryableError(\n \"Invalid filename for createNew\", OdspErrorType.invalidFileNameError, { driverVersion });\n }\n\n let itemId: string;\n let summaryHandle: string = \"\";\n let sharingLink: string | undefined;\n let sharingLinkErrorReason: string | undefined;\n if (createNewSummary === undefined) {\n itemId = await createNewEmptyFluidFile(\n getStorageToken, newFileInfo, logger, epochTracker, forceAccessTokenViaAuthorizationHeader);\n } else {\n const content = await createNewFluidFileFromSummary(\n getStorageToken,\n newFileInfo,\n logger,\n createNewSummary,\n epochTracker,\n forceAccessTokenViaAuthorizationHeader,\n );\n itemId = content.itemId;\n summaryHandle = content.id;\n sharingLink = content.sharingLink;\n sharingLinkErrorReason = content.sharingLinkErrorReason;\n }\n\n const odspUrl = createOdspUrl({... newFileInfo, itemId, dataStorePath: \"/\"});\n const resolver = new OdspDriverUrlResolver();\n const odspResolvedUrl = await resolver.resolve({ url: odspUrl });\n fileEntry.docId = odspResolvedUrl.hashedDocumentId;\n fileEntry.resolvedUrl = odspResolvedUrl;\n\n if(sharingLink || sharingLinkErrorReason) {\n odspResolvedUrl.shareLinkInfo = {\n createLink: {\n type: newFileInfo.createLinkType,\n link: sharingLink,\n error: sharingLinkErrorReason,\n },\n };\n }\n\n if (createNewSummary !== undefined && createNewCaching) {\n assert(summaryHandle !== undefined, 0x203 /* \"Summary handle is undefined\" */);\n // converting summary and getting sequence number\n const snapshot: ISnapshotContents = convertCreateNewSummaryTreeToTreeAndBlobs(createNewSummary, summaryHandle);\n // caching the converted summary\n await epochTracker.put(createCacheSnapshotKey(odspResolvedUrl), snapshot);\n }\n return odspResolvedUrl;\n}\n\nexport async function createNewEmptyFluidFile(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n epochTracker: EpochTracker,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<string> {\n const filePath = newFileInfo.filePath ? encodeURIComponent(`/${newFileInfo.filePath}`) : \"\";\n // add .tmp extension to empty file (host is expected to rename)\n const encodedFilename = encodeURIComponent(`${newFileInfo.filename}.tmp`);\n const initialUrl =\n `${getApiRoot(getOrigin(newFileInfo.siteUrl))}/drives/${newFileInfo.driveId}/items/root:/${filePath\n }/${encodedFilename}:/content?@name.conflictBehavior=rename&select=id,name,parentReference`;\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await getStorageToken(options, \"CreateNewFile\");\n\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"createNewEmptyFile\" },\n async (event) => {\n const { url, headers } = getUrlAndHeadersWithAuth(\n initialUrl, storageToken, forceAccessTokenViaAuthorizationHeader);\n headers[\"Content-Type\"] = \"application/json\";\n\n const fetchResponse = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ICreateFileResponse>(\n url,\n {\n body: undefined,\n headers,\n method: \"PUT\",\n },\n \"createFile\",\n ),\n \"createFile\",\n logger,\n );\n\n const content = fetchResponse.content;\n if (!content || !content.id) {\n throw new NonRetryableError(\n \"ODSP CreateFile call returned no item ID (for empty file)\",\n DriverErrorType.incorrectServerResponse,\n { driverVersion });\n }\n event.end({\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n ...fetchResponse.propsToLog,\n });\n return content.id;\n },\n { end: true, cancel: \"error\" });\n });\n}\n\nexport async function createNewFluidFileFromSummary(\n getStorageToken: InstrumentedStorageTokenFetcher,\n newFileInfo: INewFileInfo,\n logger: ITelemetryLogger,\n createNewSummary: ISummaryTree,\n epochTracker: EpochTracker,\n forceAccessTokenViaAuthorizationHeader: boolean,\n): Promise<ICreateFileResponse> {\n const filePath = newFileInfo.filePath ? encodeURIComponent(`/${newFileInfo.filePath}`) : \"\";\n const encodedFilename = encodeURIComponent(newFileInfo.filename);\n const baseUrl =\n `${getApiRoot(getOrigin(newFileInfo.siteUrl))}/drives/${newFileInfo.driveId}/items/root:` +\n `${filePath}/${encodedFilename}`;\n\n const containerSnapshot = convertSummaryIntoContainerSnapshot(createNewSummary);\n const initialUrl = `${baseUrl}:/opStream/snapshots/snapshot${newFileInfo.createLinkType ?\n `?createLinkType=${newFileInfo.createLinkType}` : \"\"}`;\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await getStorageToken(options, \"CreateNewFile\");\n\n return PerformanceEvent.timedExecAsync(\n logger,\n { eventName: \"createNewFile\" },\n async (event) => {\n const { url, headers } = getUrlAndHeadersWithAuth(\n initialUrl, storageToken, forceAccessTokenViaAuthorizationHeader);\n headers[\"Content-Type\"] = \"application/json\";\n\n const fetchResponse = await runWithRetry(\n async () => epochTracker.fetchAndParseAsJSON<ICreateFileResponse>(\n url,\n {\n body: JSON.stringify(containerSnapshot),\n headers,\n method: \"POST\",\n },\n \"createFile\",\n ),\n \"createFile\",\n logger,\n );\n\n const content = fetchResponse.content;\n if (!content || !content.itemId) {\n throw new NonRetryableError(\n \"ODSP CreateFile call returned no item ID\",\n DriverErrorType.incorrectServerResponse,\n { driverVersion });\n }\n event.end({\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n attempts: options.refresh ? 2 : 1,\n ...fetchResponse.propsToLog,\n });\n return content;\n },\n );\n });\n}\n\nfunction convertSummaryIntoContainerSnapshot(createNewSummary: ISummaryTree) {\n const appSummary = createNewSummary.tree[\".app\"] as ISummaryTree;\n const protocolSummary = createNewSummary.tree[\".protocol\"] as ISummaryTree;\n if (!(appSummary && protocolSummary)) {\n throw new Error(\"App and protocol summary required for create new path!!\");\n }\n const documentAttributes = getDocAttributesFromProtocolSummary(protocolSummary);\n const attributesSummaryBlob: ISummaryBlob = {\n type: SummaryType.Blob,\n content: JSON.stringify(documentAttributes),\n };\n protocolSummary.tree.attributes = attributesSummaryBlob;\n const convertedCreateNewSummary: ISummaryTree = {\n type: SummaryType.Tree,\n tree: {\n \".protocol\": protocolSummary,\n \".app\": appSummary,\n },\n };\n const snapshotTree = convertSummaryToSnapshotTreeForCreateNew(convertedCreateNewSummary);\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries ?? [],\n message: \"app\",\n sequenceNumber: documentAttributes.sequenceNumber,\n type: \"container\",\n };\n return snapshot;\n}\n\n/**\n * Converts a summary tree to ODSP tree\n */\nexport function convertSummaryToSnapshotTreeForCreateNew(summary: ISummaryTree): IOdspSummaryTree {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [],\n };\n\n const keys = Object.keys(summary.tree);\n for (const key of keys) {\n const summaryObject = summary.tree[key];\n\n let value: OdspSummaryTreeValue;\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is true,\n // the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n\n switch (summaryObject.type) {\n case SummaryType.Tree: {\n value = convertSummaryToSnapshotTreeForCreateNew(summaryObject);\n unreferenced = summaryObject.unreferenced;\n break;\n }\n case SummaryType.Blob: {\n const content = typeof summaryObject.content === \"string\" ?\n summaryObject.content : Uint8ArrayToString(summaryObject.content, \"base64\");\n const encoding = typeof summaryObject.content === \"string\" ? \"utf-8\" : \"base64\";\n\n value = {\n type: \"blob\",\n content,\n encoding,\n };\n break;\n }\n case SummaryType.Handle: {\n throw new Error(\"No handle should be present for first summary!!\");\n }\n default: {\n throw new Error(`Unknown tree type ${summaryObject.type}`);\n }\n }\n\n const entry: OdspSummaryTreeEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n value,\n unreferenced,\n };\n snapshotTree.entries?.push(entry);\n }\n\n return snapshotTree;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.d.ts","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"epochTracker.d.ts","sourceRoot":"","sources":["../src/epochTracker.ts"],"names":[],"mappings":"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"}
@@ -253,7 +253,6 @@ export class EpochTracker {
253
253
  if (isFluidError(error) && error.errorType === DriverErrorType.fileOverwrittenInStorage) {
254
254
  const epochError = this.checkForEpochErrorCore(epochFromResponse);
255
255
  if (epochError !== undefined) {
256
- assert(isFluidError(epochError), 0x21f /* "epochError expected to be thrown by throwOdspNetworkError and of known type" */);
257
256
  epochError.addTelemetryProperties({
258
257
  fromCache,
259
258
  clientEpoch: this.fluidEpoch,
@@ -267,7 +266,7 @@ export class EpochTracker {
267
266
  // If it was categorized as epoch error but the epoch returned in response matches with the client epoch
268
267
  // then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling
269
268
  // time is 1s.
270
- throw new ThrottlingError("coherency409", error.message, 1, { [Odsp409Error]: true, driverVersion });
269
+ throw new ThrottlingError(`Coherency 409: ${error.message}`, 1 /* retryAfterSeconds */, { [Odsp409Error]: true, driverVersion });
271
270
  }
272
271
  }
273
272
  checkForEpochErrorCore(epochFromResponse) {
@@ -277,7 +276,7 @@ export class EpochTracker {
277
276
  if (this.fluidEpoch && epochFromResponse && (this.fluidEpoch !== epochFromResponse)) {
278
277
  // This is similar in nature to how fluidEpochMismatchError (409) is handled.
279
278
  // Difference - client detected mismatch, instead of server detecting it.
280
- return new NonRetryableError("epochMismatch", "Epoch mismatch", DriverErrorType.fileOverwrittenInStorage, { driverVersion });
279
+ return new NonRetryableError("Epoch mismatch", DriverErrorType.fileOverwrittenInStorage, { driverVersion });
281
280
  }
282
281
  }
283
282
  fileEntryFromEntry(entry) {
@@ -1 +1 @@
1
- {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.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 { v4 as uuid } from \"uuid\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { ThrottlingError, RateLimiter, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { IConnected } from \"@fluidframework/protocol-definitions\";\nimport {\n snapshotKey,\n ICacheEntry,\n IEntry,\n IFileEntry,\n IPersistedCache,\n IOdspError,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { PerformanceEvent, isFluidError, normalizeError } from \"@fluidframework/telemetry-utils\";\nimport { fetchAndParseAsJSONHelper, fetchArray, getOdspResolvedUrl, IOdspResponse } from \"./odspUtils\";\nimport {\n IOdspCache,\n INonPersistentCache,\n IPersistedFileCache,\n } from \"./odspCache\";\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nexport type FetchType = \"blob\" | \"createBlob\" | \"createFile\" | \"joinSession\" | \"ops\" | \"test\" | \"snapshotTree\" |\n \"treesLatest\" | \"uploadSummary\" | \"push\" | \"versions\";\n\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n// Please update the README file in odsp-driver-definitions if you change the defaultCacheExpiryTimeoutMs.\nexport const defaultCacheExpiryTimeoutMs: number = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * This class is a wrapper around fetch calls. It adds epoch to the request made so that the\n * server can match it with its epoch value in order to match the version.\n * It also validates the epoch value received in response of fetch calls. If the epoch does not match,\n * then it also clears all the cached entries for the given container.\n */\nexport class EpochTracker implements IPersistedFileCache {\n private _fluidEpoch: string | undefined;\n\n public readonly rateLimiter: RateLimiter;\n private readonly driverId = uuid();\n // This tracks the request number made by the driver instance.\n private networkCallNumber = 1;\n constructor(\n protected readonly cache: IPersistedCache,\n protected readonly fileEntry: IFileEntry,\n protected readonly logger: ITelemetryLogger,\n ) {\n // Limits the max number of concurrent requests to 24.\n this.rateLimiter = new RateLimiter(24);\n }\n\n // public for UT purposes only!\n public setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal) {\n assert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n this._fluidEpoch = epoch;\n\n this.logger.sendTelemetryEvent(\n {\n eventName: \"EpochLearnedFirstTime\",\n epoch,\n fetchType,\n fromCache,\n },\n );\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n try {\n // Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n const value: IVersionedValueWithEpoch = await this.cache.get(this.fileEntryFromEntry(entry));\n // Version mismatch between what the runtime expects and what it recieved.\n // The cached value should not be used\n if (value === undefined || value.version !== persistedCacheValueVersion) {\n return undefined;\n }\n assert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n if (this._fluidEpoch === undefined) {\n this.setEpoch(value.fluidEpoch, true, \"cache\");\n // Epoch mismatch, the cached value is considerably different from what the current state of\n // the runtime and should not be used\n } else if (this._fluidEpoch !== value.fluidEpoch) {\n return undefined;\n }\n // Expire the cached snapshot if it's older than the defaultCacheExpiryTimeoutMs and immediately\n // expire all old caches that do not have cacheEntryTime\n if (entry.type === snapshotKey) {\n const cacheTime = value.value?.cacheEntryTime;\n const currentTime = Date.now();\n if (cacheTime === undefined || currentTime - cacheTime >= defaultCacheExpiryTimeoutMs) {\n this.logger.sendTelemetryEvent(\n {\n eventName: \"odspVersionsCacheExpired\",\n duration: currentTime - cacheTime,\n maxCacheAgeMs: defaultCacheExpiryTimeoutMs,\n });\n await this.removeEntries();\n return undefined;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value.value;\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n return undefined;\n }\n }\n\n public async put(entry: IEntry, value: any) {\n assert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n // For snapshots, the value should have the cacheEntryTime. This will be used to expire snapshots older\n // than the defaultCacheExpiryTimeoutMs.\n if (entry.type === snapshotKey) {\n value.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n }\n const data: IVersionedValueWithEpoch = {\n value,\n version: persistedCacheValueVersion,\n fluidEpoch: this._fluidEpoch,\n };\n return this.cache.put(this.fileEntryFromEntry(entry), data)\n .catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n throw error;\n });\n }\n\n public async removeEntries(): Promise<void> {\n try {\n return await this.cache.removeEntries(this.fileEntry);\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n }\n }\n\n public get fluidEpoch() {\n return this._fluidEpoch;\n }\n\n public async validateEpochFromPush(details: IConnected) {\n const epoch = details.epoch;\n assert(epoch !== undefined, 0x09d /* \"Connection details should contain epoch\" */);\n try {\n this.validateEpochFromResponse(epoch, \"push\");\n } catch (error) {\n await this.checkForEpochError(error, epoch, \"push\");\n throw error;\n }\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n */\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetchAndParseAsJSONHelper<T>(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});\n throw fluidError;\n });\n }\n\n /**\n * Api to fetch the response as it is for given request.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n */\n public async fetchArray(\n url: string,\n fetchOptions: {[index: string]: any},\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetchArray(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});\n throw fluidError;\n });\n }\n\n private addEpochInRequest(\n fetchOptions: RequestInit,\n addInBody: boolean,\n clientCorrelationId: string,\n ) {\n const isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n if (addInBody) {\n const headers: {[key: string]: string} = {};\n headers[\"X-RequestStats\"] = clientCorrelationId;\n if (this.fluidEpoch !== undefined) {\n headers[\"x-fluid-epoch\"] = this.fluidEpoch;\n }\n if (isClpCompliantApp) {\n headers[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n }\n this.addParamInBody(fetchOptions, headers);\n } else {\n const addHeader = (key: string, val: string) => {\n fetchOptions.headers = {\n ...fetchOptions.headers,\n };\n assert(fetchOptions.headers !== undefined, 0x282 /* \"Headers should be present now\" */);\n fetchOptions.headers[key] = val;\n };\n addHeader(\"X-RequestStats\", clientCorrelationId);\n if (this.fluidEpoch !== undefined) {\n addHeader(\"x-fluid-epoch\", this.fluidEpoch);\n }\n if (isClpCompliantApp) {\n addHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n }\n }\n }\n\n private addParamInBody(fetchOptions: RequestInit, headers: {[key: string]: string}) {\n // We use multi part form request for post body where we want to use this.\n // So extract the form boundary to mark the end of form.\n const body = fetchOptions.body;\n assert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n const splitBody = body.split(\"\\r\\n\");\n const firstLine = splitBody.shift();\n assert(firstLine !== undefined && firstLine.startsWith(\"--\"), 0x21e /* \"improper boundary format\" */);\n const formParams = [firstLine];\n Object.entries(headers).forEach(([key, value]) => {\n formParams.push(`${key}: ${value}`);\n });\n splitBody.forEach((value: string) => {\n formParams.push(value);\n });\n fetchOptions.body = formParams.join(\"\\r\\n\");\n }\n\n private formatClientCorrelationId(fetchReason?: string) {\n const items: string[] = [`driverId=${this.driverId}`, `RequestNumber=${this.networkCallNumber++}`];\n if (fetchReason !== undefined) {\n items.push(`fetchReason=${fetchReason}`);\n }\n return items.join(\", \");\n }\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n const error = this.checkForEpochErrorCore(epochFromResponse);\n if (error !== undefined) {\n throw error;\n }\n if (epochFromResponse !== undefined) {\n if (this._fluidEpoch === undefined) {\n this.setEpoch(epochFromResponse, fromCache, fetchType);\n }\n }\n }\n\n private async checkForEpochError(\n error: unknown,\n epochFromResponse: string | null | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n if (isFluidError(error) && error.errorType === DriverErrorType.fileOverwrittenInStorage) {\n const epochError = this.checkForEpochErrorCore(epochFromResponse);\n if (epochError !== undefined) {\n assert(isFluidError(epochError),\n 0x21f /* \"epochError expected to be thrown by throwOdspNetworkError and of known type\" */);\n epochError.addTelemetryProperties({\n fromCache,\n clientEpoch: this.fluidEpoch,\n fetchType,\n });\n this.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n // If the epoch mismatches, then clear all entries for such file entry from cache.\n await this.removeEntries();\n throw epochError;\n }\n // If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n // then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n // time is 1s.\n throw new ThrottlingError(\"coherency409\", error.message, 1, { [Odsp409Error]: true, driverVersion });\n }\n }\n\n private checkForEpochErrorCore(epochFromResponse: string | null | undefined) {\n // If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n // initializes this value. Sometimes response does not contain epoch as it is still in\n // implementation phase at server side. In that case also, don't compare it with our epoch value.\n if (this.fluidEpoch && epochFromResponse && (this.fluidEpoch !== epochFromResponse)) {\n // This is similar in nature to how fluidEpochMismatchError (409) is handled.\n // Difference - client detected mismatch, instead of server detecting it.\n return new NonRetryableError(\n \"epochMismatch\", \"Epoch mismatch\", DriverErrorType.fileOverwrittenInStorage, { driverVersion });\n }\n }\n\n private fileEntryFromEntry(entry: IEntry): ICacheEntry {\n return { ...entry, file: this.fileEntry };\n }\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n private readonly treesLatestDeferral = new Deferred<void>();\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchType,\n fromCache: boolean = false,\n ) {\n super.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n // Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n // That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n // exploring a file.\n this.treesLatestDeferral.resolve();\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n let result = super.get(entry);\n\n // equivalence of what happens in fetchAndParseAsJSON()\n if (entry.type === snapshotKey) {\n result = result\n .then((value) => {\n // If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n // Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n if (value !== undefined) {\n this.treesLatestDeferral.resolve();\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n })\n .catch((error) => {\n this.treesLatestDeferral.reject(error);\n throw error;\n });\n }\n return result;\n }\n\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: {[index: string]: any},\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n // Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n // joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n const completed = this.treesLatestDeferral.isCompleted;\n\n try {\n return await super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody, fetchReason);\n } catch (error) {\n // Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n // Similar, if getVersions failed, we should not do any further storage calls.\n // So treesLatest is the only call that can have parallel joinSession request.\n if (fetchType === \"treesLatest\") {\n this.treesLatestDeferral.reject(error);\n }\n if (fetchType !== \"joinSession\" || error.statusCode < 401 || error.statusCode > 404 || completed) {\n throw error;\n }\n }\n\n // It is joinSession failing with 401..404 error\n // Repeat after waiting for treeLatest succeeding (or fail if it failed).\n // No special handling after first call - if file has been deleted, then it's game over.\n\n // Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n // If we waited too long, we will log error event and proceed with call.\n // It may result in failure for user, but refreshing document would address it.\n // Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n // to unblock the process.\n await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"JoinSessionSyncWait\" },\n async (event) => {\n const timeoutRes = 51; // anything will work here\n let timer: ReturnType<typeof setTimeout>;\n const timeoutP = new Promise<number>((resolve) => {\n timer = setTimeout(() => { resolve(timeoutRes); }, 15000);\n });\n const res = await Promise.race([\n timeoutP,\n // cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n this.treesLatestDeferral.promise.finally(() => clearTimeout(timer))]);\n if (res === timeoutRes) {\n event.cancel();\n }\n },\n { start: true, end: true, cancel: \"generic\" });\n return super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n }\n}\n\nexport interface ICacheAndTracker {\n cache: IOdspCache;\n epochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n persistedCacheArg: IPersistedCache,\n nonpersistentCache: INonPersistentCache,\n fileEntry: IFileEntry,\n logger: ITelemetryLogger): ICacheAndTracker\n{\n const epochTracker = new EpochTrackerWithRedemption(persistedCacheArg, fileEntry, logger);\n return {\n cache: {\n ...nonpersistentCache,\n persistedCache: epochTracker,\n },\n epochTracker,\n };\n}\n"]}
1
+ {"version":3,"file":"epochTracker.js","sourceRoot":"","sources":["../src/epochTracker.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 { v4 as uuid } from \"uuid\";\nimport { assert, Deferred } from \"@fluidframework/common-utils\";\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { ThrottlingError, RateLimiter, NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { IConnected } from \"@fluidframework/protocol-definitions\";\nimport {\n snapshotKey,\n ICacheEntry,\n IEntry,\n IFileEntry,\n IPersistedCache,\n IOdspError,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\nimport { PerformanceEvent, isFluidError, normalizeError } from \"@fluidframework/telemetry-utils\";\nimport { fetchAndParseAsJSONHelper, fetchArray, getOdspResolvedUrl, IOdspResponse } from \"./odspUtils\";\nimport {\n IOdspCache,\n INonPersistentCache,\n IPersistedFileCache,\n } from \"./odspCache\";\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"./contracts\";\nimport { ClpCompliantAppHeader } from \"./contractsPublic\";\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\nexport type FetchType = \"blob\" | \"createBlob\" | \"createFile\" | \"joinSession\" | \"ops\" | \"test\" | \"snapshotTree\" |\n \"treesLatest\" | \"uploadSummary\" | \"push\" | \"versions\";\n\nexport type FetchTypeInternal = FetchType | \"cache\";\n\nexport const Odsp409Error = \"Odsp409Error\";\n\n// Please update the README file in odsp-driver-definitions if you change the defaultCacheExpiryTimeoutMs.\nexport const defaultCacheExpiryTimeoutMs: number = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * This class is a wrapper around fetch calls. It adds epoch to the request made so that the\n * server can match it with its epoch value in order to match the version.\n * It also validates the epoch value received in response of fetch calls. If the epoch does not match,\n * then it also clears all the cached entries for the given container.\n */\nexport class EpochTracker implements IPersistedFileCache {\n private _fluidEpoch: string | undefined;\n\n public readonly rateLimiter: RateLimiter;\n private readonly driverId = uuid();\n // This tracks the request number made by the driver instance.\n private networkCallNumber = 1;\n constructor(\n protected readonly cache: IPersistedCache,\n protected readonly fileEntry: IFileEntry,\n protected readonly logger: ITelemetryLogger,\n ) {\n // Limits the max number of concurrent requests to 24.\n this.rateLimiter = new RateLimiter(24);\n }\n\n // public for UT purposes only!\n public setEpoch(epoch: string, fromCache: boolean, fetchType: FetchTypeInternal) {\n assert(this._fluidEpoch === undefined, 0x1db /* \"epoch exists\" */);\n this._fluidEpoch = epoch;\n\n this.logger.sendTelemetryEvent(\n {\n eventName: \"EpochLearnedFirstTime\",\n epoch,\n fetchType,\n fromCache,\n },\n );\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n try {\n // Return undefined so that the ops/snapshots are grabbed from the server instead of the cache\n const value: IVersionedValueWithEpoch = await this.cache.get(this.fileEntryFromEntry(entry));\n // Version mismatch between what the runtime expects and what it recieved.\n // The cached value should not be used\n if (value === undefined || value.version !== persistedCacheValueVersion) {\n return undefined;\n }\n assert(value.fluidEpoch !== undefined, 0x1dc /* \"all entries have to have epoch\" */);\n if (this._fluidEpoch === undefined) {\n this.setEpoch(value.fluidEpoch, true, \"cache\");\n // Epoch mismatch, the cached value is considerably different from what the current state of\n // the runtime and should not be used\n } else if (this._fluidEpoch !== value.fluidEpoch) {\n return undefined;\n }\n // Expire the cached snapshot if it's older than the defaultCacheExpiryTimeoutMs and immediately\n // expire all old caches that do not have cacheEntryTime\n if (entry.type === snapshotKey) {\n const cacheTime = value.value?.cacheEntryTime;\n const currentTime = Date.now();\n if (cacheTime === undefined || currentTime - cacheTime >= defaultCacheExpiryTimeoutMs) {\n this.logger.sendTelemetryEvent(\n {\n eventName: \"odspVersionsCacheExpired\",\n duration: currentTime - cacheTime,\n maxCacheAgeMs: defaultCacheExpiryTimeoutMs,\n });\n await this.removeEntries();\n return undefined;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value.value;\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"cacheFetchError\", type: entry.type }, error);\n return undefined;\n }\n }\n\n public async put(entry: IEntry, value: any) {\n assert(this._fluidEpoch !== undefined, 0x1dd /* \"no epoch\" */);\n // For snapshots, the value should have the cacheEntryTime. This will be used to expire snapshots older\n // than the defaultCacheExpiryTimeoutMs.\n if (entry.type === snapshotKey) {\n value.cacheEntryTime = value.cacheEntryTime ?? Date.now();\n }\n const data: IVersionedValueWithEpoch = {\n value,\n version: persistedCacheValueVersion,\n fluidEpoch: this._fluidEpoch,\n };\n return this.cache.put(this.fileEntryFromEntry(entry), data)\n .catch((error) => {\n this.logger.sendErrorEvent({ eventName: \"cachePutError\", type: entry.type }, error);\n throw error;\n });\n }\n\n public async removeEntries(): Promise<void> {\n try {\n return await this.cache.removeEntries(this.fileEntry);\n } catch (error) {\n this.logger.sendErrorEvent({ eventName: \"removeCacheEntries\" }, error);\n }\n }\n\n public get fluidEpoch() {\n return this._fluidEpoch;\n }\n\n public async validateEpochFromPush(details: IConnected) {\n const epoch = details.epoch;\n assert(epoch !== undefined, 0x09d /* \"Connection details should contain epoch\" */);\n try {\n this.validateEpochFromResponse(epoch, \"push\");\n } catch (error) {\n await this.checkForEpochError(error, epoch, \"push\");\n throw error;\n }\n }\n\n /**\n * Api to fetch the response for given request and parse it as json.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n */\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: RequestInit,\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetchAndParseAsJSONHelper<T>(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});\n throw fluidError;\n });\n }\n\n /**\n * Api to fetch the response as it is for given request.\n * @param url - url of the request\n * @param fetchOptions - fetch options for request containing body, headers etc.\n * @param fetchType - method for which fetch is called.\n * @param addInBody - Pass True if caller wants to add epoch in post body.\n */\n public async fetchArray(\n url: string,\n fetchOptions: {[index: string]: any},\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ) {\n const clientCorrelationId = this.formatClientCorrelationId(fetchReason);\n // Add epoch in fetch request.\n this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);\n let epochFromResponse: string | undefined;\n return this.rateLimiter.schedule(\n async () => fetchArray(url, fetchOptions),\n ).then((response) => {\n epochFromResponse = response.headers.get(\"x-fluid-epoch\");\n this.validateEpochFromResponse(epochFromResponse, fetchType);\n response.propsToLog.XRequestStatsHeader = clientCorrelationId;\n return response;\n }).catch(async (error) => {\n // Get the server epoch from error in case we don't have it as if undefined we won't be able\n // to mark it as epoch error.\n if (epochFromResponse === undefined) {\n epochFromResponse = (error as IOdspError).serverEpoch;\n }\n await this.checkForEpochError(error, epochFromResponse, fetchType);\n throw error;\n }).catch((error) => {\n const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});\n throw fluidError;\n });\n }\n\n private addEpochInRequest(\n fetchOptions: RequestInit,\n addInBody: boolean,\n clientCorrelationId: string,\n ) {\n const isClpCompliantApp = getOdspResolvedUrl(this.fileEntry.resolvedUrl).isClpCompliantApp;\n if (addInBody) {\n const headers: {[key: string]: string} = {};\n headers[\"X-RequestStats\"] = clientCorrelationId;\n if (this.fluidEpoch !== undefined) {\n headers[\"x-fluid-epoch\"] = this.fluidEpoch;\n }\n if (isClpCompliantApp) {\n headers[ClpCompliantAppHeader.isClpCompliantApp] = isClpCompliantApp.toString();\n }\n this.addParamInBody(fetchOptions, headers);\n } else {\n const addHeader = (key: string, val: string) => {\n fetchOptions.headers = {\n ...fetchOptions.headers,\n };\n assert(fetchOptions.headers !== undefined, 0x282 /* \"Headers should be present now\" */);\n fetchOptions.headers[key] = val;\n };\n addHeader(\"X-RequestStats\", clientCorrelationId);\n if (this.fluidEpoch !== undefined) {\n addHeader(\"x-fluid-epoch\", this.fluidEpoch);\n }\n if (isClpCompliantApp) {\n addHeader(ClpCompliantAppHeader.isClpCompliantApp, isClpCompliantApp.toString());\n }\n }\n }\n\n private addParamInBody(fetchOptions: RequestInit, headers: {[key: string]: string}) {\n // We use multi part form request for post body where we want to use this.\n // So extract the form boundary to mark the end of form.\n const body = fetchOptions.body;\n assert(typeof body === \"string\", 0x21d /* \"body is not string\" */);\n const splitBody = body.split(\"\\r\\n\");\n const firstLine = splitBody.shift();\n assert(firstLine !== undefined && firstLine.startsWith(\"--\"), 0x21e /* \"improper boundary format\" */);\n const formParams = [firstLine];\n Object.entries(headers).forEach(([key, value]) => {\n formParams.push(`${key}: ${value}`);\n });\n splitBody.forEach((value: string) => {\n formParams.push(value);\n });\n fetchOptions.body = formParams.join(\"\\r\\n\");\n }\n\n private formatClientCorrelationId(fetchReason?: string) {\n const items: string[] = [`driverId=${this.driverId}`, `RequestNumber=${this.networkCallNumber++}`];\n if (fetchReason !== undefined) {\n items.push(`fetchReason=${fetchReason}`);\n }\n return items.join(\", \");\n }\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n const error = this.checkForEpochErrorCore(epochFromResponse);\n if (error !== undefined) {\n throw error;\n }\n if (epochFromResponse !== undefined) {\n if (this._fluidEpoch === undefined) {\n this.setEpoch(epochFromResponse, fromCache, fetchType);\n }\n }\n }\n\n private async checkForEpochError(\n error: unknown,\n epochFromResponse: string | null | undefined,\n fetchType: FetchTypeInternal,\n fromCache: boolean = false,\n ) {\n if (isFluidError(error) && error.errorType === DriverErrorType.fileOverwrittenInStorage) {\n const epochError = this.checkForEpochErrorCore(epochFromResponse);\n if (epochError !== undefined) {\n epochError.addTelemetryProperties({\n fromCache,\n clientEpoch: this.fluidEpoch,\n fetchType,\n });\n this.logger.sendErrorEvent({ eventName: \"fileOverwrittenInStorage\" }, epochError);\n // If the epoch mismatches, then clear all entries for such file entry from cache.\n await this.removeEntries();\n throw epochError;\n }\n // If it was categorized as epoch error but the epoch returned in response matches with the client epoch\n // then it was coherency 409, so rethrow it as throttling error so that it can retried. Default throttling\n // time is 1s.\n throw new ThrottlingError(\n `Coherency 409: ${error.message}`,\n 1 /* retryAfterSeconds */,\n { [Odsp409Error]: true, driverVersion });\n }\n }\n\n private checkForEpochErrorCore(epochFromResponse: string | null | undefined) {\n // If epoch is undefined, then don't compare it because initially for createNew or TreesLatest\n // initializes this value. Sometimes response does not contain epoch as it is still in\n // implementation phase at server side. In that case also, don't compare it with our epoch value.\n if (this.fluidEpoch && epochFromResponse && (this.fluidEpoch !== epochFromResponse)) {\n // This is similar in nature to how fluidEpochMismatchError (409) is handled.\n // Difference - client detected mismatch, instead of server detecting it.\n return new NonRetryableError(\n \"Epoch mismatch\", DriverErrorType.fileOverwrittenInStorage, { driverVersion });\n }\n }\n\n private fileEntryFromEntry(entry: IEntry): ICacheEntry {\n return { ...entry, file: this.fileEntry };\n }\n}\n\nexport class EpochTrackerWithRedemption extends EpochTracker {\n private readonly treesLatestDeferral = new Deferred<void>();\n\n protected validateEpochFromResponse(\n epochFromResponse: string | undefined,\n fetchType: FetchType,\n fromCache: boolean = false,\n ) {\n super.validateEpochFromResponse(epochFromResponse, fetchType, fromCache);\n\n // Any successful call means we have access to a file, i.e. any redemption that was required already happened.\n // That covers cases of \"treesLatest\" as well as \"getVersions\" or \"createFile\" - all the ways we can start\n // exploring a file.\n this.treesLatestDeferral.resolve();\n }\n\n public async get(\n entry: IEntry,\n ): Promise<any> {\n let result = super.get(entry);\n\n // equivalence of what happens in fetchAndParseAsJSON()\n if (entry.type === snapshotKey) {\n result = result\n .then((value) => {\n // If there is nothing in cache, we need to wait for network call to complete (and do redemption)\n // Otherwise file was redeemed in prior session, so if joinSession failed, we should not retry\n if (value !== undefined) {\n this.treesLatestDeferral.resolve();\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n })\n .catch((error) => {\n this.treesLatestDeferral.reject(error);\n throw error;\n });\n }\n return result;\n }\n\n public async fetchAndParseAsJSON<T>(\n url: string,\n fetchOptions: {[index: string]: any},\n fetchType: FetchType,\n addInBody: boolean = false,\n fetchReason?: string,\n ): Promise<IOdspResponse<T>> {\n // Optimize the flow if we know that treesLatestDeferral was already completed by the timer we started\n // joinSession call. If we did - there is no reason to repeat the call as it will fail with same error.\n const completed = this.treesLatestDeferral.isCompleted;\n\n try {\n return await super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody, fetchReason);\n } catch (error) {\n // Only handling here treesLatest. If createFile failed, we should never try to do joinSession.\n // Similar, if getVersions failed, we should not do any further storage calls.\n // So treesLatest is the only call that can have parallel joinSession request.\n if (fetchType === \"treesLatest\") {\n this.treesLatestDeferral.reject(error);\n }\n if (fetchType !== \"joinSession\" || error.statusCode < 401 || error.statusCode > 404 || completed) {\n throw error;\n }\n }\n\n // It is joinSession failing with 401..404 error\n // Repeat after waiting for treeLatest succeeding (or fail if it failed).\n // No special handling after first call - if file has been deleted, then it's game over.\n\n // Ensure we have some safety here - we do not want to deadlock if we got logic somewhere wrong.\n // If we waited too long, we will log error event and proceed with call.\n // It may result in failure for user, but refreshing document would address it.\n // Thus we use rather long timeout (not to get these failures as much as possible), but not large enough\n // to unblock the process.\n await PerformanceEvent.timedExecAsync(\n this.logger,\n { eventName: \"JoinSessionSyncWait\" },\n async (event) => {\n const timeoutRes = 51; // anything will work here\n let timer: ReturnType<typeof setTimeout>;\n const timeoutP = new Promise<number>((resolve) => {\n timer = setTimeout(() => { resolve(timeoutRes); }, 15000);\n });\n const res = await Promise.race([\n timeoutP,\n // cancel timeout to unblock UTs (otherwise Node process does not exit for 15 sec)\n this.treesLatestDeferral.promise.finally(() => clearTimeout(timer))]);\n if (res === timeoutRes) {\n event.cancel();\n }\n },\n { start: true, end: true, cancel: \"generic\" });\n return super.fetchAndParseAsJSON<T>(url, fetchOptions, fetchType, addInBody);\n }\n}\n\nexport interface ICacheAndTracker {\n cache: IOdspCache;\n epochTracker: EpochTracker;\n}\n\nexport function createOdspCacheAndTracker(\n persistedCacheArg: IPersistedCache,\n nonpersistentCache: INonPersistentCache,\n fileEntry: IFileEntry,\n logger: ITelemetryLogger): ICacheAndTracker\n{\n const epochTracker = new EpochTrackerWithRedemption(persistedCacheArg, fileEntry, logger);\n return {\n cache: {\n ...nonpersistentCache,\n persistedCache: epochTracker,\n },\n epochTracker,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fetchSnapshot.d.ts","sourceRoot":"","sources":["../src/fetchSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE,OAAO,EACH,gBAAgB,EAChB,gBAAgB,EAEhB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAuC,wBAAwB,EAA8B,MAAM,aAAa,CAAC;AAGxH,OAAO,EAKH,aAAa,EACb,iBAAiB,EACpB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,OAAO,EAC1B,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE;IAAC,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAC3G,OAAO,CAAC,iBAAiB,CAAC,CAwB5B;AAED,wBAAsB,uBAAuB,CACzC,eAAe,EAAE,gBAAgB,EACjC,mBAAmB,EAAE,+BAA+B,EACpD,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CACZ,oBAAoB,EAAE,gBAAgB,EACtC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,UAAU,CAAC,EAAE,eAAe,KAC3B,OAAO,CAAC,kCAAkC,CAAC,EACpD,UAAU,EAAE,CAAC,cAAc,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,EACvE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,oBAAoB,CAAC,EAAE,OAAO,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAqD5B;AAgMD,UAAU,kCAAkC;IACxC,oBAAoB,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAC,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC,CAAC;CAC1C;AAkID,wBAAsB,gBAAgB,CAClC,eAAe,EAAE,gBAAgB,EACjC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,yBAAyB,CAAC,EAAE,OAAO,EACnC,UAAU,CAAC,EAAE,eAAe,EAC5B,YAAY,CAAC,EAAE,YAAY,GAC5B,OAAO,CAAC,kCAAkC,CAAC,CAc7C"}
1
+ {"version":3,"file":"fetchSnapshot.d.ts","sourceRoot":"","sources":["../src/fetchSnapshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAItE,OAAO,EACH,gBAAgB,EAChB,gBAAgB,EAEhB,+BAA+B,EAClC,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EAAuC,wBAAwB,EAA8B,MAAM,aAAa,CAAC;AAGxH,OAAO,EAKH,aAAa,EACb,iBAAiB,EACpB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,OAAO,EAC1B,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE;IAAC,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAC3G,OAAO,CAAC,iBAAiB,CAAC,CAwB5B;AAED,wBAAsB,uBAAuB,CACzC,eAAe,EAAE,gBAAgB,EACjC,mBAAmB,EAAE,+BAA+B,EACpD,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,sCAAsC,EAAE,OAAO,EAC/C,MAAM,EAAE,gBAAgB,EACxB,kBAAkB,EAAE,CACZ,oBAAoB,EAAE,gBAAgB,EACtC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,UAAU,CAAC,EAAE,eAAe,KAC3B,OAAO,CAAC,kCAAkC,CAAC,EACpD,UAAU,EAAE,CAAC,cAAc,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,EACvE,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,oBAAoB,CAAC,EAAE,OAAO,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAqD5B;AAkND,UAAU,kCAAkC;IACxC,oBAAoB,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAC,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC,CAAC;CAC1C;AAiJD,wBAAsB,gBAAgB,CAClC,eAAe,EAAE,gBAAgB,EACjC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,gBAAgB,GAAG,SAAS,EAC7C,yBAAyB,CAAC,EAAE,OAAO,EACnC,UAAU,CAAC,EAAE,eAAe,EAC5B,YAAY,CAAC,EAAE,YAAY,GAC5B,OAAO,CAAC,kCAAkC,CAAC,CAc7C"}
@@ -116,18 +116,28 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
116
116
  // This event measures only successful cases of getLatest call (no tokens, no retries).
117
117
  return PerformanceEvent.timedExecAsync(logger, perfEvent, async (event) => {
118
118
  var _a, _b, _c, _d, _e, _f, _g;
119
- const startTime = performance.now();
120
119
  const response = await snapshotDownloader(odspResolvedUrl, storageToken, snapshotOptions, controller);
121
- const endTime = performance.now();
122
- const overallTime = endTime - startTime;
123
120
  const snapshot = response.odspSnapshotResponse.content;
124
- let dnstime; // domainLookupEnd - domainLookupStart
125
- let redirectTime; // redirectEnd -redirectStart
121
+ // From: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
122
+ // fetchStart: immediately before the browser starts to fetch the resource.
123
+ // requestStart: immediately before the browser starts requesting the resource from the server
124
+ // responseStart: immediately after the browser receives the first byte of the response from the server.
125
+ // responseEnd: immediately after the browser receives the last byte of the resource
126
+ // or immediately before the transport connection is closed, whichever comes first.
127
+ // secureConnectionStart: immediately before the browser starts the handshake process to secure the
128
+ // current connection. If a secure connection is not used, this property returns zero.
129
+ // startTime: Time when the resource fetch started. This value is equivalent to fetchStart.
130
+ // domainLookupStart: immediately before the browser starts the domain name lookup for the resource.
131
+ // domainLookupEnd: immediately after the browser finishes the domain name lookup for the resource.
132
+ // redirectStart: start time of the fetch which that initiates the redirect.
133
+ // redirectEnd: immediately after receiving the last byte of the response of the last redirect.
134
+ let dnsLookupTime; // domainLookupEnd - domainLookupStart
135
+ let redirectTime; // redirectEnd - redirectStart
126
136
  let tcpHandshakeTime; // connectEnd - connectStart
127
- let secureConntime; // connectEnd - secureConnectionStart
128
- let responseTime; // responsEnd - responseStart
129
- let fetchStToRespEndTime; // responseEnd - fetchStart
130
- let reqStToRespEndTime; // responseEnd - requestStart
137
+ let secureConnectionTime; // connectEnd - secureConnectionStart
138
+ let responseNetworkTime; // responsEnd - responseStart
139
+ let fetchStartToResponseEndTime; // responseEnd - fetchStart
140
+ let reqStartToResponseEndTime; // responseEnd - requestStart
131
141
  let networkTime; // responseEnd - startTime
132
142
  const spReqDuration = response.odspSnapshotResponse.headers.get("sprequestduration");
133
143
  // getEntriesByType is only available in browser performance object
@@ -140,24 +150,25 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
140
150
  if ((resource_initiatortype.localeCompare("fetch") === 0)
141
151
  && (resource_name.localeCompare(response.requestUrl) === 0)) {
142
152
  redirectTime = indResTime.redirectEnd - indResTime.redirectStart;
143
- dnstime = indResTime.domainLookupEnd - indResTime.domainLookupStart;
153
+ dnsLookupTime = indResTime.domainLookupEnd - indResTime.domainLookupStart;
144
154
  tcpHandshakeTime = indResTime.connectEnd - indResTime.connectStart;
145
- secureConntime = (indResTime.secureConnectionStart > 0) ?
146
- (indResTime.connectEnd - indResTime.secureConnectionStart) : 0;
147
- responseTime = indResTime.responseEnd - indResTime.responseStart;
148
- fetchStToRespEndTime = (indResTime.fetchStart > 0) ?
149
- (indResTime.responseEnd - indResTime.fetchStart) : 0;
150
- reqStToRespEndTime = (indResTime.requestStart > 0) ?
151
- (indResTime.responseEnd - indResTime.requestStart) : 0;
152
- networkTime = (indResTime.startTime > 0) ? (indResTime.responseEnd - indResTime.startTime) : 0;
153
- if (spReqDuration) {
155
+ secureConnectionTime = (indResTime.secureConnectionStart > 0) ?
156
+ (indResTime.connectEnd - indResTime.secureConnectionStart) : undefined;
157
+ responseNetworkTime = (indResTime.responseStart > 0) ?
158
+ (indResTime.responseEnd - indResTime.responseStart) : undefined;
159
+ fetchStartToResponseEndTime = (indResTime.fetchStart > 0) ?
160
+ (indResTime.responseEnd - indResTime.fetchStart) : undefined;
161
+ reqStartToResponseEndTime = (indResTime.requestStart > 0) ?
162
+ (indResTime.responseEnd - indResTime.requestStart) : undefined;
163
+ networkTime = (indResTime.startTime > 0) ?
164
+ (indResTime.responseEnd - indResTime.fetchStart) : undefined;
165
+ if (spReqDuration !== undefined && networkTime !== undefined) {
154
166
  networkTime = networkTime - parseInt(spReqDuration, 10);
155
167
  }
156
168
  break;
157
169
  }
158
170
  }
159
171
  const { numTrees, numBlobs, encodedBlobsSize } = validateAndEvalBlobsAndTrees(response.odspSnapshotResponse.content);
160
- const clientTime = networkTime ? overallTime - networkTime : undefined;
161
172
  // There are some scenarios in ODSP where we cannot cache, trees/latest will explicitly tell us when we
162
173
  // cannot cache using an HTTP response header.
163
174
  const canCache = response.odspSnapshotResponse.headers.get("disablebrowsercachingofusercontent") !== "true";
@@ -183,7 +194,24 @@ async function fetchLatestSnapshotCore(odspResolvedUrl, storageTokenFetcher, sna
183
194
  putInCache(valueWithEpoch);
184
195
  }
185
196
  event.end(Object.assign({ trees: numTrees, blobs: (_e = (_d = snapshot.blobs) === null || _d === void 0 ? void 0 : _d.size) !== null && _e !== void 0 ? _e : 0, leafNodes: numBlobs, encodedBlobsSize,
186
- sequenceNumber, ops: (_g = (_f = snapshot.ops) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0, headers: Object.keys(response.requestHeaders).length !== 0 ? true : undefined, redirecttime: redirectTime, dnsLookuptime: dnstime, responsenetworkTime: responseTime, tcphandshakeTime: tcpHandshakeTime, secureconnectiontime: secureConntime, fetchstarttorespendtime: fetchStToRespEndTime, reqstarttorespendtime: reqStToRespEndTime, overalltime: overallTime, networktime: networkTime, clienttime: clientTime,
197
+ sequenceNumber, ops: (_g = (_f = snapshot.ops) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0, headers: Object.keys(response.requestHeaders).length !== 0 ? true : undefined,
198
+ // Interval between the first fetch until the last byte of the last redirect.
199
+ redirectTime,
200
+ // Interval between start and finish of the domain name lookup for the resource.
201
+ dnsLookupTime,
202
+ // Interval to receive all (first to last) bytes form the server.
203
+ responseNetworkTime,
204
+ // Time to establish the connection to the server to retrieve the resource.
205
+ tcpHandshakeTime,
206
+ // Time from the end of the connection until the inital handshake process to secure the connection.
207
+ secureConnectionTime,
208
+ // Interval between the initial fetch until the last byte is received.
209
+ fetchStartToResponseEndTime,
210
+ // Interval between starting the request for the resource until receiving the last byte.
211
+ reqStartToResponseEndTime,
212
+ // Interval between starting the request for the resource until receiving the last byte but
213
+ // excluding the Snaphot request duration indicated on the snapshot response header.
214
+ networkTime,
187
215
  // Sharing link telemetry regarding sharing link redeem status and performance. Ex: FRL; dur=100,
188
216
  // Azure Fluid Relay service; desc=S, FRP; desc=False. Here, FRL is the duration taken for redeem,
189
217
  // Azure Fluid Relay service is the redeem status (S means success), and FRP is a flag to indicate
@@ -216,7 +244,13 @@ async function fetchSnapshotContentsCoreV1(odspResolvedUrl, storageToken, snapsh
216
244
  var _a;
217
245
  const snapshotUrl = odspResolvedUrl.endpoints.snapshotStorageUrl;
218
246
  const url = `${snapshotUrl}/trees/latest?ump=1`;
219
- const { body, headers } = getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions);
247
+ // The location of file can move on Spo in which case server returns 308(Permanent Redirect) error.
248
+ // Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
249
+ // This error thrown by server will contain the new redirect location. Look at the 404 error parsing
250
+ // for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
251
+ const header = { "prefer": "manualredirect" };
252
+ const { body, headers } = getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions, header);
253
+ headers.accept = "application/json";
220
254
  const fetchOptions = {
221
255
  body,
222
256
  headers,
@@ -261,7 +295,7 @@ async function fetchSnapshotContentsCoreV2(odspResolvedUrl, storageToken, snapsh
261
295
  requestUrl: fullUrl,
262
296
  };
263
297
  }
264
- function getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions) {
298
+ function getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions, headers) {
265
299
  var _a, _b;
266
300
  const formBoundary = uuid();
267
301
  const formParams = [];
@@ -275,16 +309,23 @@ function getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions) {
275
309
  }
276
310
  });
277
311
  }
312
+ if (headers !== undefined) {
313
+ Object.entries(headers).forEach(([key, value]) => {
314
+ if (value !== undefined) {
315
+ formParams.push(`${key}: ${value}`);
316
+ }
317
+ });
318
+ }
278
319
  if ((_a = odspResolvedUrl.shareLinkInfo) === null || _a === void 0 ? void 0 : _a.sharingLinkToRedeem) {
279
320
  formParams.push(`sl: ${(_b = odspResolvedUrl.shareLinkInfo) === null || _b === void 0 ? void 0 : _b.sharingLinkToRedeem}`);
280
321
  }
281
322
  formParams.push(`_post: 1`);
282
323
  formParams.push(`\r\n--${formBoundary}--`);
283
324
  const postBody = formParams.join("\r\n");
284
- const headers = {
325
+ const header = {
285
326
  "Content-Type": `multipart/form-data;boundary=${formBoundary}`,
286
327
  };
287
- return { body: postBody, headers };
328
+ return { body: postBody, headers: header };
288
329
  }
289
330
  function validateAndEvalBlobsAndTrees(snapshot) {
290
331
  assert(snapshot.snapshotTree !== undefined, 0x200 /* "Returned odsp snapshot is malformed. No trees!" */);