@fluidframework/odsp-driver 0.58.2002 → 0.58.3000-61081
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compactSnapshotParser.d.ts +1 -0
- package/dist/compactSnapshotParser.d.ts.map +1 -1
- package/dist/compactSnapshotParser.js +8 -6
- package/dist/compactSnapshotParser.js.map +1 -1
- package/dist/epochTracker.d.ts +12 -0
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +18 -22
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts +11 -0
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +53 -68
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/odspDocumentService.d.ts +2 -1
- package/dist/odspDocumentService.d.ts.map +1 -1
- package/dist/odspDocumentService.js +14 -7
- package/dist/odspDocumentService.js.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.d.ts +2 -2
- package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.js +6 -6
- package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
- package/dist/odspDriverUrlResolver.d.ts.map +1 -1
- package/dist/odspDriverUrlResolver.js +3 -1
- package/dist/odspDriverUrlResolver.js.map +1 -1
- package/dist/odspSummaryUploadManager.d.ts.map +1 -1
- package/dist/odspSummaryUploadManager.js +9 -6
- package/dist/odspSummaryUploadManager.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/compactSnapshotParser.d.ts +1 -0
- package/lib/compactSnapshotParser.d.ts.map +1 -1
- package/lib/compactSnapshotParser.js +7 -5
- package/lib/compactSnapshotParser.js.map +1 -1
- package/lib/epochTracker.d.ts +12 -0
- package/lib/epochTracker.d.ts.map +1 -1
- package/lib/epochTracker.js +19 -23
- package/lib/epochTracker.js.map +1 -1
- package/lib/fetchSnapshot.d.ts +11 -0
- package/lib/fetchSnapshot.d.ts.map +1 -1
- package/lib/fetchSnapshot.js +55 -70
- package/lib/fetchSnapshot.js.map +1 -1
- package/lib/odspDocumentService.d.ts +2 -1
- package/lib/odspDocumentService.d.ts.map +1 -1
- package/lib/odspDocumentService.js +14 -7
- package/lib/odspDocumentService.js.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.d.ts +2 -2
- package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/lib/odspDocumentServiceFactoryCore.js +6 -6
- package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
- package/lib/odspDriverUrlResolver.d.ts.map +1 -1
- package/lib/odspDriverUrlResolver.js +4 -2
- package/lib/odspDriverUrlResolver.js.map +1 -1
- package/lib/odspSummaryUploadManager.d.ts.map +1 -1
- package/lib/odspSummaryUploadManager.js +9 -6
- package/lib/odspSummaryUploadManager.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +15 -10
- package/src/compactSnapshotParser.ts +11 -10
- package/src/epochTracker.ts +34 -25
- package/src/fetchSnapshot.ts +57 -89
- package/src/odspDocumentService.ts +8 -5
- package/src/odspDocumentServiceFactoryCore.ts +7 -2
- package/src/odspDriverUrlResolver.ts +7 -1
- package/src/odspSummaryUploadManager.ts +7 -6
- package/src/packageVersion.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odspSummaryUploadManager.js","sourceRoot":"","sources":["../src/odspSummaryUploadManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Uint8ArrayToString, unreachableCase } from \"@fluidframework/common-utils\";\nimport { ISummaryContext } from \"@fluidframework/driver-definitions\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions\";\nimport { loggerToMonitoringContext, MonitoringContext, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspSummaryPayload,\n IWriteSummaryResponse,\n IOdspSummaryTree,\n IOdspSummaryTreeBaseEntry,\n OdspSummaryTreeEntry,\n OdspSummaryTreeValue,\n} from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils\";\n\n/* eslint-disable max-len */\n\n/**\n * This class manages a summary upload. When it receives a call to upload summary, it converts the summary tree into\n * a snapshot tree and then uploads that to the server.\n */\nexport class OdspSummaryUploadManager {\n // Last proposed handle of the uploaded app summary.\n private lastSummaryProposalHandle: string | undefined;\n private readonly mc: MonitoringContext;\n\n constructor(\n private readonly snapshotUrl: string,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n logger: ITelemetryLogger,\n private readonly epochTracker: EpochTracker,\n private readonly forceAccessTokenViaAuthorizationHeader: boolean,\n ) {\n this.mc = loggerToMonitoringContext(logger);\n }\n\n public async writeSummaryTree(tree: api.ISummaryTree, context: ISummaryContext) {\n // If the last proposed handle is not the proposed handle of the acked summary(could happen when the last summary get nacked),\n // then re-initialize the caches with the previous ones else just update the previous caches with the caches from acked summary.\n // Don't bother logging if lastSummaryProposalHandle hasn't been set before; only log on a positive mismatch.\n if (this.lastSummaryProposalHandle !== undefined &&\n this.lastSummaryProposalHandle !== context.proposalHandle) {\n this.mc.logger.sendTelemetryEvent({\n eventName: \"LastSummaryProposedHandleMismatch\",\n ackedSummaryProposedHandle: context.proposalHandle,\n lastSummaryProposalHandle: this.lastSummaryProposalHandle,\n });\n }\n const result = await this.writeSummaryTreeCore(context.ackHandle, context.referenceSequenceNumber, tree);\n const id = result ? result.id : undefined;\n if (!result || !id) {\n throw new Error(`Failed to write summary tree`);\n }\n this.lastSummaryProposalHandle = id;\n return id;\n }\n\n private async writeSummaryTreeCore(\n parentHandle: string | undefined,\n referenceSequenceNumber: number,\n tree: api.ISummaryTree,\n ): Promise<IWriteSummaryResponse> {\n const { snapshotTree, blobs } = await this.convertSummaryToSnapshotTree(\n parentHandle,\n tree,\n \".app\",\n \"\",\n );\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries!,\n message: \"app\",\n sequenceNumber: referenceSequenceNumber,\n // no ack handle implies this is initial summary after empty file creation.\n // send container payload so server will use it without a summary op\n type: parentHandle === undefined ? \"container\" : \"channel\",\n };\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"WriteSummaryTree\");\n\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/snapshot`,\n storageToken,\n this.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/json\";\n if (parentHandle) {\n headers[\"If-Match\"] = `fluid:containerid=${parentHandle}`;\n }\n\n const postBody = JSON.stringify(snapshot);\n\n return PerformanceEvent.timedExecAsync(this.mc.logger,\n {\n eventName: \"uploadSummary\",\n attempt: options.refresh ? 2 : 1,\n hasClaims: !!options.claims,\n hasTenantId: !!options.tenantId,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n blobs,\n size: postBody.length,\n referenceSequenceNumber,\n },\n async () => {\n const response = await this.epochTracker.fetchAndParseAsJSON<IWriteSummaryResponse>(\n url,\n {\n body: postBody,\n headers,\n method: \"POST\",\n },\n \"uploadSummary\");\n return response.content;\n });\n });\n }\n\n /**\n * Following are the goals of this function.\n * a.) Converts the summary tree to a snapshot/odsp tree to be uploaded. Always upload full snapshot tree.\n * @param parentHandle - Handle of the last uploaded summary or detach new summary.\n * @param tree - Summary Tree which will be converted to snapshot tree to be uploaded.\n * @param rootNodeName - Root node name of the summary tree.\n * @param path - Current path of node which is getting evaluated.\n * @param markUnreferencedNodes - True if we should mark unreferenced nodes.\n */\n private async convertSummaryToSnapshotTree(\n parentHandle: string | undefined,\n tree: api.ISummaryTree,\n rootNodeName: string,\n path: string = \"\",\n markUnreferencedNodes: boolean = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.MarkUnreferencedNodes\") ?? true,\n ) {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [] as OdspSummaryTreeEntry[],\n };\n\n let blobs = 0;\n const keys = Object.keys(tree.tree);\n for (const key of keys) {\n const summaryObject = tree.tree[key];\n\n let id: string | undefined;\n let value: OdspSummaryTreeValue | undefined;\n\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is\n // true (which is the only value it can have), the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n const currentPath = path === \"\" ? `${rootNodeName}/${key}` : `${path}/${key}`;\n switch (summaryObject.type) {\n case api.SummaryType.Tree: {\n const result = await this.convertSummaryToSnapshotTree(\n parentHandle,\n summaryObject,\n rootNodeName,\n currentPath);\n value = result.snapshotTree;\n unreferenced = markUnreferencedNodes ? summaryObject.unreferenced : undefined;\n blobs += result.blobs;\n break;\n }\n case api.SummaryType.Blob: {\n if (typeof summaryObject.content === \"string\") {\n value = {\n type: \"blob\",\n content: summaryObject.content,\n encoding: \"utf-8\",\n };\n } else {\n value = {\n type: \"blob\",\n content: Uint8ArrayToString(summaryObject.content, \"base64\"),\n encoding: \"base64\",\n };\n }\n blobs++;\n break;\n }\n case api.SummaryType.Handle: {\n if (!parentHandle) {\n throw Error(\"Parent summary does not exist to reference by handle.\");\n }\n let handlePath = summaryObject.handle;\n if (handlePath.length > 0 && !handlePath.startsWith(\"/\")) {\n handlePath = `/${handlePath}`;\n }\n const pathKey = `${rootNodeName}${handlePath}`;\n id = `${parentHandle}/${pathKey}`;\n break;\n }\n case api.SummaryType.Attachment: {\n id = summaryObject.id;\n break;\n }\n default: {\n unreachableCase(summaryObject, `Unknown type: ${(summaryObject as any).type}`);\n }\n }\n\n const baseEntry: IOdspSummaryTreeBaseEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n };\n\n let entry: OdspSummaryTreeEntry;\n\n if (value) {\n assert(id === undefined, 0x0ad /* \"Snapshot entry has both a tree value and a referenced id!\" */);\n entry = {\n value,\n ...baseEntry,\n unreferenced,\n };\n } else if (id) {\n entry = {\n ...baseEntry,\n id,\n };\n } else {\n throw new Error(`Invalid tree entry for ${summaryObject.type}`);\n }\n\n snapshotTree.entries!.push(entry);\n }\n\n return { snapshotTree, blobs };\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
|
1
|
+
{"version":3,"file":"odspSummaryUploadManager.js","sourceRoot":"","sources":["../src/odspSummaryUploadManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Uint8ArrayToString, unreachableCase } from \"@fluidframework/common-utils\";\nimport { ISummaryContext } from \"@fluidframework/driver-definitions\";\nimport { getGitType } from \"@fluidframework/protocol-base\";\nimport * as api from \"@fluidframework/protocol-definitions\";\nimport { InstrumentedStorageTokenFetcher } from \"@fluidframework/odsp-driver-definitions\";\nimport { loggerToMonitoringContext, MonitoringContext, PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport {\n IOdspSummaryPayload,\n IWriteSummaryResponse,\n IOdspSummaryTree,\n IOdspSummaryTreeBaseEntry,\n OdspSummaryTreeEntry,\n OdspSummaryTreeValue,\n} from \"./contracts\";\nimport { EpochTracker } from \"./epochTracker\";\nimport { getUrlAndHeadersWithAuth } from \"./getUrlAndHeadersWithAuth\";\nimport { getWithRetryForTokenRefresh } from \"./odspUtils\";\n\n/* eslint-disable max-len */\n\n/**\n * This class manages a summary upload. When it receives a call to upload summary, it converts the summary tree into\n * a snapshot tree and then uploads that to the server.\n */\nexport class OdspSummaryUploadManager {\n // Last proposed handle of the uploaded app summary.\n private lastSummaryProposalHandle: string | undefined;\n private readonly mc: MonitoringContext;\n\n constructor(\n private readonly snapshotUrl: string,\n private readonly getStorageToken: InstrumentedStorageTokenFetcher,\n logger: ITelemetryLogger,\n private readonly epochTracker: EpochTracker,\n private readonly forceAccessTokenViaAuthorizationHeader: boolean,\n ) {\n this.mc = loggerToMonitoringContext(logger);\n }\n\n public async writeSummaryTree(tree: api.ISummaryTree, context: ISummaryContext) {\n // If the last proposed handle is not the proposed handle of the acked summary(could happen when the last summary get nacked),\n // then re-initialize the caches with the previous ones else just update the previous caches with the caches from acked summary.\n // Don't bother logging if lastSummaryProposalHandle hasn't been set before; only log on a positive mismatch.\n if (this.lastSummaryProposalHandle !== undefined &&\n this.lastSummaryProposalHandle !== context.proposalHandle) {\n this.mc.logger.sendTelemetryEvent({\n eventName: \"LastSummaryProposedHandleMismatch\",\n ackedSummaryProposedHandle: context.proposalHandle,\n lastSummaryProposalHandle: this.lastSummaryProposalHandle,\n });\n }\n const result = await this.writeSummaryTreeCore(context.ackHandle, context.referenceSequenceNumber, tree);\n const id = result ? result.id : undefined;\n if (!result || !id) {\n throw new Error(`Failed to write summary tree`);\n }\n this.lastSummaryProposalHandle = id;\n return id;\n }\n\n private async writeSummaryTreeCore(\n parentHandle: string | undefined,\n referenceSequenceNumber: number,\n tree: api.ISummaryTree,\n ): Promise<IWriteSummaryResponse> {\n const enableContainerTypeSummaryUpload = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.EnableContainerTypeSummaryUpload\");\n const containsProtocolTree = enableContainerTypeSummaryUpload &&\n Object.keys(tree.tree).includes(\".protocol\");\n const { snapshotTree, blobs } = await this.convertSummaryToSnapshotTree(\n parentHandle,\n tree,\n \".app\",\n );\n const snapshot: IOdspSummaryPayload = {\n entries: snapshotTree.entries!,\n message: \"app\",\n sequenceNumber: referenceSequenceNumber,\n // no ack handle implies this is initial summary after empty file creation.\n // send container payload so server will use it without a summary op\n type: containsProtocolTree || parentHandle === undefined ? \"container\" : \"channel\",\n };\n\n return getWithRetryForTokenRefresh(async (options) => {\n const storageToken = await this.getStorageToken(options, \"WriteSummaryTree\");\n\n const { url, headers } = getUrlAndHeadersWithAuth(\n `${this.snapshotUrl}/snapshot`,\n storageToken,\n this.forceAccessTokenViaAuthorizationHeader,\n );\n headers[\"Content-Type\"] = \"application/json\";\n if (parentHandle) {\n headers[\"If-Match\"] = `fluid:containerid=${parentHandle}`;\n }\n\n const postBody = JSON.stringify(snapshot);\n\n return PerformanceEvent.timedExecAsync(this.mc.logger,\n {\n eventName: \"uploadSummary\",\n attempt: options.refresh ? 2 : 1,\n hasClaims: !!options.claims,\n hasTenantId: !!options.tenantId,\n headers: Object.keys(headers).length !== 0 ? true : undefined,\n blobs,\n size: postBody.length,\n referenceSequenceNumber,\n type: snapshot.type,\n enableContainerTypeSummaryUpload,\n },\n async () => {\n const response = await this.epochTracker.fetchAndParseAsJSON<IWriteSummaryResponse>(\n url,\n {\n body: postBody,\n headers,\n method: \"POST\",\n },\n \"uploadSummary\");\n return response.content;\n });\n });\n }\n\n /**\n * Following are the goals of this function.\n * a.) Converts the summary tree to a snapshot/odsp tree to be uploaded. Always upload full snapshot tree.\n * @param parentHandle - Handle of the last uploaded summary or detach new summary.\n * @param tree - Summary Tree which will be converted to snapshot tree to be uploaded.\n * @param rootNodeName - Root node name of the summary tree.\n * @param path - Current path of node which is getting evaluated.\n * @param markUnreferencedNodes - True if we should mark unreferenced nodes.\n */\n private async convertSummaryToSnapshotTree(\n parentHandle: string | undefined,\n tree: api.ISummaryTree,\n rootNodeName: string,\n markUnreferencedNodes: boolean = this.mc.config.getBoolean(\"Fluid.Driver.Odsp.MarkUnreferencedNodes\") ?? true,\n ) {\n const snapshotTree: IOdspSummaryTree = {\n type: \"tree\",\n entries: [] as OdspSummaryTreeEntry[],\n };\n\n let blobs = 0;\n const keys = Object.keys(tree.tree);\n for (const key of keys) {\n const summaryObject = tree.tree[key];\n\n let id: string | undefined;\n let value: OdspSummaryTreeValue | undefined;\n\n // Tracks if an entry is unreferenced. Currently, only tree entries can be marked as unreferenced. If the\n // property is not present, the tree entry is considered referenced. If the property is present and is\n // true (which is the only value it can have), the tree entry is considered unreferenced.\n let unreferenced: true | undefined;\n switch (summaryObject.type) {\n case api.SummaryType.Tree: {\n const result = await this.convertSummaryToSnapshotTree(\n parentHandle,\n summaryObject,\n rootNodeName);\n value = result.snapshotTree;\n unreferenced = markUnreferencedNodes ? summaryObject.unreferenced : undefined;\n blobs += result.blobs;\n break;\n }\n case api.SummaryType.Blob: {\n if (typeof summaryObject.content === \"string\") {\n value = {\n type: \"blob\",\n content: summaryObject.content,\n encoding: \"utf-8\",\n };\n } else {\n value = {\n type: \"blob\",\n content: Uint8ArrayToString(summaryObject.content, \"base64\"),\n encoding: \"base64\",\n };\n }\n blobs++;\n break;\n }\n case api.SummaryType.Handle: {\n if (!parentHandle) {\n throw Error(\"Parent summary does not exist to reference by handle.\");\n }\n let handlePath = summaryObject.handle;\n if (handlePath.length > 0 && !handlePath.startsWith(\"/\")) {\n handlePath = `/${handlePath}`;\n }\n const pathKey = `${rootNodeName}${handlePath}`;\n id = `${parentHandle}/${pathKey}`;\n break;\n }\n case api.SummaryType.Attachment: {\n id = summaryObject.id;\n break;\n }\n default: {\n unreachableCase(summaryObject, `Unknown type: ${(summaryObject as any).type}`);\n }\n }\n\n const baseEntry: IOdspSummaryTreeBaseEntry = {\n path: encodeURIComponent(key),\n type: getGitType(summaryObject),\n };\n\n let entry: OdspSummaryTreeEntry;\n\n if (value) {\n assert(id === undefined, 0x0ad /* \"Snapshot entry has both a tree value and a referenced id!\" */);\n entry = {\n value,\n ...baseEntry,\n unreferenced,\n };\n } else if (id) {\n entry = {\n ...baseEntry,\n id,\n };\n } else {\n throw new Error(`Invalid tree entry for ${summaryObject.type}`);\n }\n\n snapshotTree.entries!.push(entry);\n }\n\n return { snapshotTree, blobs };\n }\n}\n\n/* eslint-enable max-len */\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/odsp-driver";
|
|
8
|
-
export declare const pkgVersion = "0.58.
|
|
8
|
+
export declare const pkgVersion = "0.58.3000-61081";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,oBAAoB,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,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 = \"0.58.3000-61081\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/odsp-driver",
|
|
3
|
-
"version": "0.58.
|
|
3
|
+
"version": "0.58.3000-61081",
|
|
4
4
|
"description": "Socket storage implementation for SPO and ODC",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"lint:fix": "npm run eslint:fix",
|
|
33
33
|
"test": "npm run test:mocha",
|
|
34
34
|
"test:coverage": "nyc npm test -- --reporter xunit --reporter-option output=nyc/junit-report.xml",
|
|
35
|
-
"test:mocha": "mocha --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
|
|
35
|
+
"test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
|
|
36
36
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
37
37
|
"tsc": "tsc",
|
|
38
38
|
"tsfmt": "tsfmt --verify",
|
|
@@ -62,15 +62,15 @@
|
|
|
62
62
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
63
63
|
"@fluidframework/common-utils": "^0.32.1",
|
|
64
64
|
"@fluidframework/core-interfaces": "^0.42.0",
|
|
65
|
-
"@fluidframework/driver-base": "
|
|
66
|
-
"@fluidframework/driver-definitions": "^0.45.
|
|
67
|
-
"@fluidframework/driver-utils": "
|
|
65
|
+
"@fluidframework/driver-base": "0.58.3000-61081",
|
|
66
|
+
"@fluidframework/driver-definitions": "^0.45.2000-0",
|
|
67
|
+
"@fluidframework/driver-utils": "0.58.3000-61081",
|
|
68
68
|
"@fluidframework/gitresources": "^0.1035.1000",
|
|
69
|
-
"@fluidframework/odsp-doclib-utils": "
|
|
70
|
-
"@fluidframework/odsp-driver-definitions": "
|
|
69
|
+
"@fluidframework/odsp-doclib-utils": "0.58.3000-61081",
|
|
70
|
+
"@fluidframework/odsp-driver-definitions": "0.58.3000-61081",
|
|
71
71
|
"@fluidframework/protocol-base": "^0.1035.1000",
|
|
72
72
|
"@fluidframework/protocol-definitions": "^0.1027.1000",
|
|
73
|
-
"@fluidframework/telemetry-utils": "
|
|
73
|
+
"@fluidframework/telemetry-utils": "0.58.3000-61081",
|
|
74
74
|
"abort-controller": "^3.0.0",
|
|
75
75
|
"node-fetch": "^2.6.1",
|
|
76
76
|
"socket.io-client": "^4.4.1",
|
|
@@ -78,8 +78,9 @@
|
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@fluidframework/build-common": "^0.23.0",
|
|
81
|
-
"@fluidframework/eslint-config-fluid": "^0.27.
|
|
82
|
-
"@fluidframework/mocha-test-setup": "
|
|
81
|
+
"@fluidframework/eslint-config-fluid": "^0.27.2000-59622",
|
|
82
|
+
"@fluidframework/mocha-test-setup": "0.58.3000-61081",
|
|
83
|
+
"@fluidframework/odsp-driver-previous": "npm:@fluidframework/odsp-driver@0.58.2000",
|
|
83
84
|
"@microsoft/api-extractor": "^7.16.1",
|
|
84
85
|
"@rushstack/eslint-config": "^2.5.1",
|
|
85
86
|
"@types/mocha": "^8.2.2",
|
|
@@ -103,5 +104,9 @@
|
|
|
103
104
|
"sinon": "^7.4.2",
|
|
104
105
|
"typescript": "~4.1.3",
|
|
105
106
|
"typescript-formatter": "7.1.0"
|
|
107
|
+
},
|
|
108
|
+
"typeValidation": {
|
|
109
|
+
"version": "0.58.3000",
|
|
110
|
+
"broken": {}
|
|
106
111
|
}
|
|
107
112
|
}
|
|
@@ -14,10 +14,12 @@ import {
|
|
|
14
14
|
assertNumberInstance,
|
|
15
15
|
getAndValidateNodeProps,
|
|
16
16
|
NodeCore,
|
|
17
|
+
NodeTypes,
|
|
17
18
|
TreeBuilder,
|
|
18
19
|
} from "./zipItDataRepresentationUtils";
|
|
19
20
|
|
|
20
21
|
export const snapshotMinReadVersion = "1.0";
|
|
22
|
+
export const currentReadVersion = "1.0";
|
|
21
23
|
|
|
22
24
|
interface ISnapshotSection {
|
|
23
25
|
snapshotTree: ISnapshotTree,
|
|
@@ -28,7 +30,8 @@ interface ISnapshotSection {
|
|
|
28
30
|
* Recreates blobs section of the tree.
|
|
29
31
|
* @param node - tree node to read blob section from
|
|
30
32
|
*/
|
|
31
|
-
function readBlobSection(node:
|
|
33
|
+
function readBlobSection(node: NodeTypes) {
|
|
34
|
+
assertNodeCoreInstance(node, "TreeBlobs should be of type NodeCore");
|
|
32
35
|
const blobs: Map<string, ArrayBuffer> = new Map();
|
|
33
36
|
for (let count = 0; count < node.length; ++count) {
|
|
34
37
|
const blob = node.getNode(count);
|
|
@@ -44,7 +47,8 @@ function readBlobSection(node: NodeCore) {
|
|
|
44
47
|
* Recreates ops section of the tree.
|
|
45
48
|
* @param node - tree node to read ops section from
|
|
46
49
|
*/
|
|
47
|
-
function readOpsSection(node:
|
|
50
|
+
function readOpsSection(node: NodeTypes) {
|
|
51
|
+
assertNodeCoreInstance(node, "Deltas should be of type NodeCore");
|
|
48
52
|
const ops: ISequencedDocumentMessage[] = [];
|
|
49
53
|
const records = getAndValidateNodeProps(node, ["firstSequenceNumber", "deltas"]);
|
|
50
54
|
assertNumberInstance(records.firstSequenceNumber, "Seq number should be a number");
|
|
@@ -93,7 +97,8 @@ function readTreeSection(node: NodeCore) {
|
|
|
93
97
|
* Recreates snapshot tree out of tree representation.
|
|
94
98
|
* @param node - tree node to de-serialize from
|
|
95
99
|
*/
|
|
96
|
-
function readSnapshotSection(node:
|
|
100
|
+
function readSnapshotSection(node: NodeTypes): ISnapshotSection {
|
|
101
|
+
assertNodeCoreInstance(node, "Snapshot should be of type NodeCore");
|
|
97
102
|
const records = getAndValidateNodeProps(node,
|
|
98
103
|
["id", "sequenceNumber", "treeNodes"]);
|
|
99
104
|
|
|
@@ -120,7 +125,7 @@ export function parseCompactSnapshotResponse(buffer: ReadBuffer): ISnapshotConte
|
|
|
120
125
|
const root = builder.getNode(0);
|
|
121
126
|
|
|
122
127
|
const records = getAndValidateNodeProps(root,
|
|
123
|
-
["mrv", "cv", "snapshot", "blobs", "deltas"]);
|
|
128
|
+
["mrv", "cv", "snapshot", "blobs", "deltas"], false);
|
|
124
129
|
|
|
125
130
|
assertBlobCoreInstance(records.mrv, "minReadVersion should be of BlobCore type");
|
|
126
131
|
assertBlobCoreInstance(records.cv, "createVersion should be of BlobCore type");
|
|
@@ -128,14 +133,10 @@ export function parseCompactSnapshotResponse(buffer: ReadBuffer): ISnapshotConte
|
|
|
128
133
|
0x20f /* "Driver min read version should >= to server minReadVersion" */);
|
|
129
134
|
assert(records.cv.toString() >= snapshotMinReadVersion,
|
|
130
135
|
0x210 /* "Snapshot should be created with minReadVersion or above" */);
|
|
131
|
-
|
|
132
|
-
assertNodeCoreInstance(records.snapshot, "Snapshot should be of type NodeCore");
|
|
133
|
-
assertNodeCoreInstance(records.blobs, "TreeBlobs should be of type NodeCore");
|
|
134
|
-
assertNodeCoreInstance(records.deltas, "Deltas should be of type NodeCore");
|
|
135
|
-
|
|
136
|
+
assert(currentReadVersion === records.cv.toString(), "Create Version should be equal to currentReadVersion");
|
|
136
137
|
return {
|
|
137
138
|
...readSnapshotSection(records.snapshot),
|
|
138
139
|
blobs: readBlobSection(records.blobs),
|
|
139
|
-
ops: readOpsSection(records.deltas),
|
|
140
|
+
ops: records.deltas !== undefined ? readOpsSection(records.deltas) : [],
|
|
140
141
|
};
|
|
141
142
|
}
|
package/src/epochTracker.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "@fluidframework/odsp-driver-definitions";
|
|
19
19
|
import { DriverErrorType } from "@fluidframework/driver-definitions";
|
|
20
20
|
import { PerformanceEvent, isFluidError, normalizeError } from "@fluidframework/telemetry-utils";
|
|
21
|
-
import { fetchAndParseAsJSONHelper, fetchArray, getOdspResolvedUrl, IOdspResponse } from "./odspUtils";
|
|
21
|
+
import { fetchAndParseAsJSONHelper, fetchArray, fetchHelper, getOdspResolvedUrl, IOdspResponse } from "./odspUtils";
|
|
22
22
|
import {
|
|
23
23
|
IOdspCache,
|
|
24
24
|
INonPersistentCache,
|
|
@@ -166,6 +166,7 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
166
166
|
* @param fetchOptions - fetch options for request containing body, headers etc.
|
|
167
167
|
* @param fetchType - method for which fetch is called.
|
|
168
168
|
* @param addInBody - Pass True if caller wants to add epoch in post body.
|
|
169
|
+
* @param fetchReason - fetch reason to add to the request.
|
|
169
170
|
*/
|
|
170
171
|
public async fetchAndParseAsJSON<T>(
|
|
171
172
|
url: string,
|
|
@@ -174,12 +175,41 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
174
175
|
addInBody: boolean = false,
|
|
175
176
|
fetchReason?: string,
|
|
176
177
|
): Promise<IOdspResponse<T>> {
|
|
178
|
+
return this.fetchCore<T>(url, fetchOptions, fetchAndParseAsJSONHelper, fetchType, addInBody, fetchReason);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Api to fetch the response for given request and parse it as json.
|
|
183
|
+
* @param url - url of the request
|
|
184
|
+
* @param fetchOptions - fetch options for request containing body, headers etc.
|
|
185
|
+
* @param fetchType - method for which fetch is called.
|
|
186
|
+
* @param addInBody - Pass True if caller wants to add epoch in post body.
|
|
187
|
+
* @param fetchReason - fetch reason to add to the request.
|
|
188
|
+
*/
|
|
189
|
+
public async fetch(
|
|
190
|
+
url: string,
|
|
191
|
+
fetchOptions: RequestInit,
|
|
192
|
+
fetchType: FetchType,
|
|
193
|
+
addInBody: boolean = false,
|
|
194
|
+
fetchReason?: string,
|
|
195
|
+
) {
|
|
196
|
+
return this.fetchCore<Response>(url, fetchOptions, fetchHelper, fetchType, addInBody, fetchReason);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async fetchCore<T>(
|
|
200
|
+
url: string,
|
|
201
|
+
fetchOptions: {[index: string]: any},
|
|
202
|
+
fetcher: (url: string, fetchOptions: {[index: string]: any}) => Promise<IOdspResponse<T>>,
|
|
203
|
+
fetchType: FetchType,
|
|
204
|
+
addInBody: boolean = false,
|
|
205
|
+
fetchReason?: string,
|
|
206
|
+
) {
|
|
177
207
|
const clientCorrelationId = this.formatClientCorrelationId(fetchReason);
|
|
178
208
|
// Add epoch in fetch request.
|
|
179
209
|
this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);
|
|
180
210
|
let epochFromResponse: string | undefined;
|
|
181
211
|
return this.rateLimiter.schedule(
|
|
182
|
-
async () =>
|
|
212
|
+
async () => fetcher(url, fetchOptions),
|
|
183
213
|
).then((response) => {
|
|
184
214
|
epochFromResponse = response.headers.get("x-fluid-epoch");
|
|
185
215
|
this.validateEpochFromResponse(epochFromResponse, fetchType);
|
|
@@ -205,6 +235,7 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
205
235
|
* @param fetchOptions - fetch options for request containing body, headers etc.
|
|
206
236
|
* @param fetchType - method for which fetch is called.
|
|
207
237
|
* @param addInBody - Pass True if caller wants to add epoch in post body.
|
|
238
|
+
* @param fetchReason - fetch reason to add to the request.
|
|
208
239
|
*/
|
|
209
240
|
public async fetchArray(
|
|
210
241
|
url: string,
|
|
@@ -213,29 +244,7 @@ export class EpochTracker implements IPersistedFileCache {
|
|
|
213
244
|
addInBody: boolean = false,
|
|
214
245
|
fetchReason?: string,
|
|
215
246
|
) {
|
|
216
|
-
|
|
217
|
-
// Add epoch in fetch request.
|
|
218
|
-
this.addEpochInRequest(fetchOptions, addInBody, clientCorrelationId);
|
|
219
|
-
let epochFromResponse: string | undefined;
|
|
220
|
-
return this.rateLimiter.schedule(
|
|
221
|
-
async () => fetchArray(url, fetchOptions),
|
|
222
|
-
).then((response) => {
|
|
223
|
-
epochFromResponse = response.headers.get("x-fluid-epoch");
|
|
224
|
-
this.validateEpochFromResponse(epochFromResponse, fetchType);
|
|
225
|
-
response.propsToLog.XRequestStatsHeader = clientCorrelationId;
|
|
226
|
-
return response;
|
|
227
|
-
}).catch(async (error) => {
|
|
228
|
-
// Get the server epoch from error in case we don't have it as if undefined we won't be able
|
|
229
|
-
// to mark it as epoch error.
|
|
230
|
-
if (epochFromResponse === undefined) {
|
|
231
|
-
epochFromResponse = (error as IOdspError).serverEpoch;
|
|
232
|
-
}
|
|
233
|
-
await this.checkForEpochError(error, epochFromResponse, fetchType);
|
|
234
|
-
throw error;
|
|
235
|
-
}).catch((error) => {
|
|
236
|
-
const fluidError = normalizeError(error, { props: { XRequestStatsHeader: clientCorrelationId }});
|
|
237
|
-
throw fluidError;
|
|
238
|
-
});
|
|
247
|
+
return this.fetchCore<ArrayBuffer>(url, fetchOptions, fetchArray, fetchType, addInBody, fetchReason);
|
|
239
248
|
}
|
|
240
249
|
|
|
241
250
|
private addEpochInRequest(
|
package/src/fetchSnapshot.ts
CHANGED
|
@@ -22,14 +22,14 @@ import { getQueryString } from "./getQueryString";
|
|
|
22
22
|
import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth";
|
|
23
23
|
import {
|
|
24
24
|
fetchAndParseAsJSONHelper,
|
|
25
|
-
|
|
25
|
+
fetchHelper,
|
|
26
26
|
getWithRetryForTokenRefresh,
|
|
27
27
|
getWithRetryForTokenRefreshRepeat,
|
|
28
28
|
IOdspResponse,
|
|
29
29
|
ISnapshotContents,
|
|
30
30
|
} from "./odspUtils";
|
|
31
31
|
import { convertOdspSnapshotToSnapsohtTreeAndBlobs } from "./odspSnapshotParser";
|
|
32
|
-
import { parseCompactSnapshotResponse } from "./compactSnapshotParser";
|
|
32
|
+
import { currentReadVersion, parseCompactSnapshotResponse } from "./compactSnapshotParser";
|
|
33
33
|
import { ReadBuffer } from "./ReadBufferUtils";
|
|
34
34
|
import { EpochTracker } from "./epochTracker";
|
|
35
35
|
|
|
@@ -362,89 +362,6 @@ interface ISnapshotRequestAndResponseOptions {
|
|
|
362
362
|
requestHeaders: {[index: string]: any},
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
/**
|
|
366
|
-
* This function fetches the older snapshot format which is the json format(IOdspSnapshot).
|
|
367
|
-
* @param odspResolvedUrl - resolved odsp url.
|
|
368
|
-
* @param storageToken - token to do the auth for network request.
|
|
369
|
-
* @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
|
|
370
|
-
* @param controller - abort controller if caller needs to abort the network call.
|
|
371
|
-
* @param epochTracker - epoch tracker used to add/validate epoch in the network call.
|
|
372
|
-
* @returns fetched snapshot.
|
|
373
|
-
*/
|
|
374
|
-
async function fetchSnapshotContentsCoreV1(
|
|
375
|
-
odspResolvedUrl: IOdspResolvedUrl,
|
|
376
|
-
storageToken: string,
|
|
377
|
-
snapshotOptions: ISnapshotOptions | undefined,
|
|
378
|
-
controller?: AbortController,
|
|
379
|
-
epochTracker?: EpochTracker,
|
|
380
|
-
): Promise<ISnapshotRequestAndResponseOptions> {
|
|
381
|
-
const snapshotUrl = odspResolvedUrl.endpoints.snapshotStorageUrl;
|
|
382
|
-
const url = `${snapshotUrl}/trees/latest?ump=1`;
|
|
383
|
-
// The location of file can move on Spo in which case server returns 308(Permanent Redirect) error.
|
|
384
|
-
// Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
|
|
385
|
-
// This error thrown by server will contain the new redirect location. Look at the 404 error parsing
|
|
386
|
-
// for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
|
|
387
|
-
const header = { prefer: "manualredirect" };
|
|
388
|
-
const { body, headers } = getFormBodyAndHeaders(
|
|
389
|
-
odspResolvedUrl, storageToken, snapshotOptions, header);
|
|
390
|
-
headers.accept = "application/json";
|
|
391
|
-
const fetchOptions = {
|
|
392
|
-
body,
|
|
393
|
-
headers,
|
|
394
|
-
signal: controller?.signal,
|
|
395
|
-
method: "POST",
|
|
396
|
-
};
|
|
397
|
-
const response = await (epochTracker?.fetchAndParseAsJSON<IOdspSnapshot>(url, fetchOptions, "treesLatest", true) ??
|
|
398
|
-
fetchAndParseAsJSONHelper<IOdspSnapshot>(url, fetchOptions));
|
|
399
|
-
const snapshotContents: ISnapshotContents = convertOdspSnapshotToSnapsohtTreeAndBlobs(response.content);
|
|
400
|
-
const finalSnapshotContents: IOdspResponse<ISnapshotContents> = { ...response, content: snapshotContents };
|
|
401
|
-
return {
|
|
402
|
-
odspSnapshotResponse: finalSnapshotContents,
|
|
403
|
-
requestHeaders: headers,
|
|
404
|
-
requestUrl: url,
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* This function fetches the binary compact snapshot format. This is an experimental feature
|
|
410
|
-
* and is behind a feature flag.
|
|
411
|
-
* @param odspResolvedUrl - resolved odsp url.
|
|
412
|
-
* @param storageToken - token to do the auth for network request.
|
|
413
|
-
* @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
|
|
414
|
-
* @param controller - abort controller if caller needs to abort the network call.
|
|
415
|
-
* @param epochTracker - epoch tracker used to add/validate epoch in the network call.
|
|
416
|
-
* @returns fetched snapshot.
|
|
417
|
-
*/
|
|
418
|
-
async function fetchSnapshotContentsCoreV2(
|
|
419
|
-
odspResolvedUrl: IOdspResolvedUrl,
|
|
420
|
-
storageToken: string,
|
|
421
|
-
snapshotOptions: ISnapshotOptions | undefined,
|
|
422
|
-
controller?: AbortController,
|
|
423
|
-
epochTracker?: EpochTracker,
|
|
424
|
-
): Promise<ISnapshotRequestAndResponseOptions> {
|
|
425
|
-
const fullUrl = `${odspResolvedUrl.siteUrl}/_api/v2.1/drives/${odspResolvedUrl.driveId}/items/${
|
|
426
|
-
odspResolvedUrl.itemId}/opStream/attachments/latest/content?ump=1`;
|
|
427
|
-
|
|
428
|
-
const { body, headers } = getFormBodyAndHeaders(odspResolvedUrl, storageToken, snapshotOptions);
|
|
429
|
-
const fetchOptions = {
|
|
430
|
-
body,
|
|
431
|
-
headers,
|
|
432
|
-
signal: controller?.signal,
|
|
433
|
-
method: "POST",
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
const response = await (epochTracker?.fetchArray(fullUrl, fetchOptions, "treesLatest", true) ??
|
|
437
|
-
fetchArray(fullUrl, fetchOptions));
|
|
438
|
-
const snapshotContents: ISnapshotContents = parseCompactSnapshotResponse(
|
|
439
|
-
new ReadBuffer(new Uint8Array(response.content)));
|
|
440
|
-
const finalSnapshotContents: IOdspResponse<ISnapshotContents> = { ...response, content: snapshotContents };
|
|
441
|
-
return {
|
|
442
|
-
odspSnapshotResponse: finalSnapshotContents,
|
|
443
|
-
requestHeaders: headers,
|
|
444
|
-
requestUrl: fullUrl,
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
|
|
448
365
|
function getFormBodyAndHeaders(
|
|
449
366
|
odspResolvedUrl: IOdspResolvedUrl,
|
|
450
367
|
storageToken: string,
|
|
@@ -505,6 +422,17 @@ function countTreesInSnapshotTree(snapshotTree: ISnapshotTree): number {
|
|
|
505
422
|
return numTrees;
|
|
506
423
|
}
|
|
507
424
|
|
|
425
|
+
/**
|
|
426
|
+
* This function fetches the snapshot and parse it according to what is mentioned in response headers.
|
|
427
|
+
* @param odspResolvedUrl - resolved odsp url.
|
|
428
|
+
* @param storageToken - token to do the auth for network request.
|
|
429
|
+
* @param snapshotOptions - Options used to specify how and what to fetch in the snapshot.
|
|
430
|
+
* @param logger - logger
|
|
431
|
+
* @param fetchBinarySnapshotFormat - whether to fetch binary snapshot or not.
|
|
432
|
+
* @param controller - abort controller if caller needs to abort the network call.
|
|
433
|
+
* @param epochTracker - epoch tracker used to add/validate epoch in the network call.
|
|
434
|
+
* @returns fetched snapshot.
|
|
435
|
+
*/
|
|
508
436
|
export async function downloadSnapshot(
|
|
509
437
|
odspResolvedUrl: IOdspResolvedUrl,
|
|
510
438
|
storageToken: string,
|
|
@@ -520,13 +448,53 @@ export async function downloadSnapshot(
|
|
|
520
448
|
odspResolvedUrl.shareLinkInfo = { ...odspResolvedUrl.shareLinkInfo, sharingLinkToRedeem };
|
|
521
449
|
}
|
|
522
450
|
|
|
451
|
+
const snapshotUrl = odspResolvedUrl.endpoints.snapshotStorageUrl;
|
|
452
|
+
const url = `${snapshotUrl}/trees/latest?ump=1`;
|
|
453
|
+
// The location of file can move on Spo in which case server returns 308(Permanent Redirect) error.
|
|
454
|
+
// Adding below header will make VROOM API return 404 instead of 308 and browser can intercept it.
|
|
455
|
+
// This error thrown by server will contain the new redirect location. Look at the 404 error parsing
|
|
456
|
+
// for futher reference here: \packages\utils\odsp-doclib-utils\src\odspErrorUtils.ts
|
|
457
|
+
const header = {prefer: "manualredirect"};
|
|
458
|
+
const { body, headers } = getFormBodyAndHeaders(
|
|
459
|
+
odspResolvedUrl, storageToken, snapshotOptions, header);
|
|
460
|
+
const fetchOptions = {
|
|
461
|
+
body,
|
|
462
|
+
headers,
|
|
463
|
+
signal: controller?.signal,
|
|
464
|
+
method: "POST",
|
|
465
|
+
};
|
|
466
|
+
// For now we are keeping both json and ms-fluid values in accept header while fetching as we want to let
|
|
467
|
+
// the server decide what format it wants to send to the client as we roll it out slowly.
|
|
523
468
|
if (fetchBinarySnapshotFormat) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
469
|
+
headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
|
|
470
|
+
} else {
|
|
471
|
+
headers.accept = "application/json";
|
|
472
|
+
}
|
|
473
|
+
const response = await (epochTracker?.fetch(url, fetchOptions, "treesLatest", true) ??
|
|
474
|
+
fetchHelper(url, fetchOptions));
|
|
475
|
+
|
|
476
|
+
let finalSnapshotContents: IOdspResponse<ISnapshotContents>;
|
|
477
|
+
const contentType = response.headers.get("content-type");
|
|
478
|
+
if (contentType === "application/json") {
|
|
479
|
+
const text = await response.content.text();
|
|
480
|
+
const content: IOdspSnapshot = JSON.parse(text);
|
|
481
|
+
response.propsToLog.bodySize = text.length;
|
|
482
|
+
const snapshotContents: ISnapshotContents = convertOdspSnapshotToSnapsohtTreeAndBlobs(content);
|
|
483
|
+
finalSnapshotContents = { ...response, content: snapshotContents };
|
|
527
484
|
} else {
|
|
528
|
-
|
|
485
|
+
assert(contentType === "application/ms-fluid", "Content type should be application/ms-fluid");
|
|
486
|
+
const content = await response.content.arrayBuffer();
|
|
487
|
+
response.propsToLog.bodySize = content.byteLength;
|
|
488
|
+
const snapshotContents: ISnapshotContents = parseCompactSnapshotResponse(
|
|
489
|
+
new ReadBuffer(new Uint8Array(content)));
|
|
490
|
+
finalSnapshotContents = { ...response, content: snapshotContents };
|
|
529
491
|
}
|
|
492
|
+
response.propsToLog.contentType = contentType;
|
|
493
|
+
return {
|
|
494
|
+
odspSnapshotResponse: finalSnapshotContents,
|
|
495
|
+
requestHeaders: headers,
|
|
496
|
+
requestUrl: url,
|
|
497
|
+
};
|
|
530
498
|
}
|
|
531
499
|
|
|
532
500
|
function isRedeemSharingLinkError(odspResolvedUrl: IOdspResolvedUrl, error: any) {
|
|
@@ -81,6 +81,7 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
81
81
|
hostPolicy: HostStoragePolicy,
|
|
82
82
|
epochTracker: EpochTracker,
|
|
83
83
|
socketReferenceKeyPrefix?: string,
|
|
84
|
+
clientIsSummarizer?: boolean,
|
|
84
85
|
): Promise<IDocumentService> {
|
|
85
86
|
return new OdspDocumentService(
|
|
86
87
|
getOdspResolvedUrl(resolvedUrl),
|
|
@@ -92,6 +93,7 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
92
93
|
hostPolicy,
|
|
93
94
|
epochTracker,
|
|
94
95
|
socketReferenceKeyPrefix,
|
|
96
|
+
clientIsSummarizer,
|
|
95
97
|
);
|
|
96
98
|
}
|
|
97
99
|
|
|
@@ -131,6 +133,7 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
131
133
|
hostPolicy: HostStoragePolicy,
|
|
132
134
|
private readonly epochTracker: EpochTracker,
|
|
133
135
|
private readonly socketReferenceKeyPrefix?: string,
|
|
136
|
+
private readonly clientIsSummarizer?: boolean,
|
|
134
137
|
) {
|
|
135
138
|
this._policies = {
|
|
136
139
|
// load in storage-only mode if a file version is specified
|
|
@@ -150,7 +153,7 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
150
153
|
this.hostPolicy = hostPolicy;
|
|
151
154
|
this.hostPolicy.fetchBinarySnapshotFormat ??=
|
|
152
155
|
this.mc.config.getBoolean("Fluid.Driver.Odsp.binaryFormatSnapshot");
|
|
153
|
-
if (this.
|
|
156
|
+
if (this.clientIsSummarizer) {
|
|
154
157
|
this.hostPolicy = { ...this.hostPolicy, summarizerClient: true };
|
|
155
158
|
}
|
|
156
159
|
}
|
|
@@ -385,7 +388,7 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
385
388
|
};
|
|
386
389
|
|
|
387
390
|
const getResponseAndRefreshAfterDeltaMs = async () => {
|
|
388
|
-
|
|
391
|
+
const _response = await this.cache.sessionJoinCache.addOrGet(this.joinSessionKey, executeFetch);
|
|
389
392
|
// If the response does not contain refreshSessionDurationSeconds, then treat it as old flow and let the
|
|
390
393
|
// cache entry to be treated as expired after 1 hour.
|
|
391
394
|
_response.joinSessionResponse.refreshSessionDurationSeconds =
|
|
@@ -415,16 +418,16 @@ export class OdspDocumentService implements IDocumentService {
|
|
|
415
418
|
.catch((error) => {
|
|
416
419
|
this.mc.logger.sendErrorEvent({
|
|
417
420
|
eventName: "JoinSessionRefreshError",
|
|
418
|
-
|
|
421
|
+
details: JSON.stringify(props),
|
|
419
422
|
},
|
|
420
423
|
error,
|
|
421
424
|
);
|
|
422
425
|
});
|
|
423
426
|
} else {
|
|
424
427
|
// Logging just for informational purposes to help with debugging as this is a new feature.
|
|
425
|
-
this.mc.logger.
|
|
428
|
+
this.mc.logger.sendTelemetryEvent({
|
|
426
429
|
eventName: "JoinSessionRefreshNotScheduled",
|
|
427
|
-
|
|
430
|
+
details: JSON.stringify(props),
|
|
428
431
|
});
|
|
429
432
|
}
|
|
430
433
|
}
|
|
@@ -55,6 +55,7 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
|
|
|
55
55
|
createNewSummary: ISummaryTree | undefined,
|
|
56
56
|
createNewResolvedUrl: IResolvedUrl,
|
|
57
57
|
logger?: ITelemetryBaseLogger,
|
|
58
|
+
clientIsSummarizer?: boolean,
|
|
58
59
|
): Promise<IDocumentService> {
|
|
59
60
|
ensureFluidResolvedUrl(createNewResolvedUrl);
|
|
60
61
|
|
|
@@ -113,7 +114,8 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
|
|
|
113
114
|
this.hostPolicy.cacheCreateNewSummary ?? true,
|
|
114
115
|
!!this.hostPolicy.sessionOptions?.forceAccessTokenViaAuthorizationHeader,
|
|
115
116
|
);
|
|
116
|
-
const docService = this.createDocumentServiceCore(odspResolvedUrl, odspLogger,
|
|
117
|
+
const docService = this.createDocumentServiceCore(odspResolvedUrl, odspLogger,
|
|
118
|
+
cacheAndTracker, clientIsSummarizer);
|
|
117
119
|
event.end({
|
|
118
120
|
docId: odspResolvedUrl.hashedDocumentId,
|
|
119
121
|
});
|
|
@@ -147,14 +149,16 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
|
|
|
147
149
|
public async createDocumentService(
|
|
148
150
|
resolvedUrl: IResolvedUrl,
|
|
149
151
|
logger?: ITelemetryBaseLogger,
|
|
152
|
+
clientIsSummarizer?: boolean,
|
|
150
153
|
): Promise<IDocumentService> {
|
|
151
|
-
return this.createDocumentServiceCore(resolvedUrl, createOdspLogger(logger));
|
|
154
|
+
return this.createDocumentServiceCore(resolvedUrl, createOdspLogger(logger), undefined, clientIsSummarizer);
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
private async createDocumentServiceCore(
|
|
155
158
|
resolvedUrl: IResolvedUrl,
|
|
156
159
|
odspLogger: TelemetryLogger,
|
|
157
160
|
cacheAndTrackerArg?: ICacheAndTracker,
|
|
161
|
+
clientIsSummarizer?: boolean,
|
|
158
162
|
): Promise<IDocumentService> {
|
|
159
163
|
const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
|
|
160
164
|
const resolvedUrlData: IOdspUrlParts = {
|
|
@@ -194,6 +198,7 @@ export class OdspDocumentServiceFactoryCore implements IDocumentServiceFactory {
|
|
|
194
198
|
this.hostPolicy,
|
|
195
199
|
cacheAndTracker.epochTracker,
|
|
196
200
|
this.socketReferenceKeyPrefix,
|
|
201
|
+
clientIsSummarizer,
|
|
197
202
|
);
|
|
198
203
|
}
|
|
199
204
|
}
|